From 8d43959e0f7cce0a92b399ee0657e5acae3a5b65 Mon Sep 17 00:00:00 2001 From: Sehong Na Date: Sat, 31 May 2014 12:53:17 +0900 Subject: [PATCH 1/1] Initialize Tizen 2.3 --- 00.README.FIRST | 47 + 00.README.FIRST_4.82 | 29 + 00CREDITS | 512 +++ 00DCACHE | 745 ++++ 00DIALECTS | 6 + 00DIST | 4430 +++++++++++++++++++++ 00FAQ | 7923 +++++++++++++++++++++++++++++++++++++ 00LSOF-L | 100 + 00MANIFEST | 386 ++ 00PORTING | 1790 +++++++++ 00QUICKSTART | 1008 +++++ 00README | 1535 +++++++ 00TEST | 1000 +++++ 00XCONFIG | 665 ++++ AFSConfig | 346 ++ Configure | 5453 +++++++++++++++++++++++++ Customize | 1151 ++++++ Inventory | 204 + LICENSE.lsof | 25 + README.lsof_4.82 | 128 + arg.c | 2428 ++++++++++++ dialects/linux/Makefile | 157 + dialects/linux/Mksrc | 25 + dialects/linux/dfile.c | 64 + dialects/linux/dlsof.h | 172 + dialects/linux/dmnt.c | 586 +++ dialects/linux/dnode.c | 538 +++ dialects/linux/dproc.c | 1381 +++++++ dialects/linux/dproto.h | 51 + dialects/linux/dsock.c | 2792 +++++++++++++ dialects/linux/dstore.c | 107 + dialects/linux/machine.h | 630 +++ lib/Makefile.skel | 62 + lib/ckkv.c | 93 + lib/cvfs.c | 110 + lib/dvch.c | 1413 +++++++ lib/fino.c | 148 + lib/isfn.c | 418 ++ lib/lkud.c | 207 + lib/pdvn.c | 182 + lib/prfp.c | 212 + lib/ptti.c | 1370 +++++++ lib/rdev.c | 524 +++ lib/regex.c | 6328 +++++++++++++++++++++++++++++ lib/rmnt.c | 243 ++ lib/rnam.c | 669 ++++ lib/rnch.c | 811 ++++ lib/rnmh.c | 743 ++++ lib/snpf.c | 749 ++++ lsof.8 | 4307 ++++++++++++++++++++ lsof.h | 955 +++++ lsof.man | 3828 ++++++++++++++++++ lsof_fields.h | 176 + main.c | 1678 ++++++++ misc.c | 1648 ++++++++ node.c | 258 ++ packaging/lsof.changes | 13 + packaging/lsof.spec | 56 + packaging/lsof_4.81-threads.patch | 129 + print.c | 2752 +++++++++++++ proc.c | 1187 ++++++ proto.h | 284 ++ regex.h | 617 +++ scripts/00MANIFEST | 58 + scripts/00README | 55 + scripts/big_brother.perl5 | 210 + scripts/count_pf.perl | 68 + scripts/count_pf.perl5 | 94 + scripts/identd.perl5 | 131 + scripts/idrlogin.perl | 201 + scripts/idrlogin.perl5 | 197 + scripts/list_NULf.perl5 | 161 + scripts/list_fields.awk | 198 + scripts/list_fields.perl | 156 + scripts/shared.perl5 | 409 ++ scripts/sort_res.perl5 | 135 + scripts/watch_a_file.perl | 94 + scripts/xusers.awk | 137 + store.c | 414 ++ tests/00README | 102 + tests/Add2TestDB | 83 + tests/CkTestDB | 136 + tests/LTbasic.c | 445 +++ tests/LTbigf.c | 767 ++++ tests/LTdnlc.c | 426 ++ tests/LTlib.c | 1104 ++++++ tests/LTlock.c | 769 ++++ tests/LTnfs.c | 531 +++ tests/LTnlink.c | 556 +++ tests/LTsock.c | 877 ++++ tests/LTszoff.c | 509 +++ tests/LTunix.c | 364 ++ tests/LsofTest.h | 360 ++ tests/Makefile | 159 + tests/TestDB | 120 + usage.c | 916 +++++ util.c | 73 + version | 1 + 98 files changed, 79600 insertions(+) create mode 100644 00.README.FIRST create mode 100644 00.README.FIRST_4.82 create mode 100644 00CREDITS create mode 100644 00DCACHE create mode 100644 00DIALECTS create mode 100644 00DIST create mode 100644 00FAQ create mode 100644 00LSOF-L create mode 100644 00MANIFEST create mode 100644 00PORTING create mode 100644 00QUICKSTART create mode 100644 00README create mode 100644 00TEST create mode 100644 00XCONFIG create mode 100755 AFSConfig create mode 100755 Configure create mode 100755 Customize create mode 100755 Inventory create mode 100644 LICENSE.lsof create mode 100644 README.lsof_4.82 create mode 100644 arg.c create mode 100644 dialects/linux/Makefile create mode 100755 dialects/linux/Mksrc create mode 100644 dialects/linux/dfile.c create mode 100644 dialects/linux/dlsof.h create mode 100644 dialects/linux/dmnt.c create mode 100644 dialects/linux/dnode.c create mode 100644 dialects/linux/dproc.c create mode 100644 dialects/linux/dproto.h create mode 100644 dialects/linux/dsock.c create mode 100644 dialects/linux/dstore.c create mode 100644 dialects/linux/machine.h create mode 100644 lib/Makefile.skel create mode 100644 lib/ckkv.c create mode 100644 lib/cvfs.c create mode 100644 lib/dvch.c create mode 100644 lib/fino.c create mode 100644 lib/isfn.c create mode 100644 lib/lkud.c create mode 100644 lib/pdvn.c create mode 100644 lib/prfp.c create mode 100644 lib/ptti.c create mode 100644 lib/rdev.c create mode 100644 lib/regex.c create mode 100644 lib/rmnt.c create mode 100644 lib/rnam.c create mode 100644 lib/rnch.c create mode 100644 lib/rnmh.c create mode 100644 lib/snpf.c create mode 100644 lsof.8 create mode 100644 lsof.h create mode 100644 lsof.man create mode 100644 lsof_fields.h create mode 100644 main.c create mode 100644 misc.c create mode 100644 node.c create mode 100644 packaging/lsof.changes create mode 100644 packaging/lsof.spec create mode 100644 packaging/lsof_4.81-threads.patch create mode 100644 print.c create mode 100644 proc.c create mode 100644 proto.h create mode 100644 regex.h create mode 100644 scripts/00MANIFEST create mode 100644 scripts/00README create mode 100755 scripts/big_brother.perl5 create mode 100755 scripts/count_pf.perl create mode 100755 scripts/count_pf.perl5 create mode 100755 scripts/identd.perl5 create mode 100755 scripts/idrlogin.perl create mode 100755 scripts/idrlogin.perl5 create mode 100755 scripts/list_NULf.perl5 create mode 100644 scripts/list_fields.awk create mode 100755 scripts/list_fields.perl create mode 100755 scripts/shared.perl5 create mode 100755 scripts/sort_res.perl5 create mode 100755 scripts/watch_a_file.perl create mode 100755 scripts/xusers.awk create mode 100644 store.c create mode 100644 tests/00README create mode 100755 tests/Add2TestDB create mode 100755 tests/CkTestDB create mode 100644 tests/LTbasic.c create mode 100644 tests/LTbigf.c create mode 100644 tests/LTdnlc.c create mode 100644 tests/LTlib.c create mode 100644 tests/LTlock.c create mode 100644 tests/LTnfs.c create mode 100644 tests/LTnlink.c create mode 100644 tests/LTsock.c create mode 100644 tests/LTszoff.c create mode 100644 tests/LTunix.c create mode 100644 tests/LsofTest.h create mode 100644 tests/Makefile create mode 100644 tests/TestDB create mode 100644 usage.c create mode 100644 util.c create mode 100644 version diff --git a/00.README.FIRST b/00.README.FIRST new file mode 100644 index 0000000..17c8d70 --- /dev/null +++ b/00.README.FIRST @@ -0,0 +1,47 @@ +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. + +* 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 +April 19, 2002 diff --git a/00.README.FIRST_4.82 b/00.README.FIRST_4.82 new file mode 100644 index 0000000..731c4be --- /dev/null +++ b/00.README.FIRST_4.82 @@ -0,0 +1,29 @@ +A tour of the lsof_4.82 distribution: + + 00.README.FIRST_4.82 is this file. + + README.lsof_4.82 contains distribution and security information. + + RELEASE.SUMMARY_4.82 contains a summary of the lsof 4.82 + distribution. + + lsof_4.82_src.tar is the lsof 4.82 source tar archive. + + lsof_4.82_src.tar.sig is a detached GPG certificate for + lsof_4.82_src.tar. + +I suggest you follow these steps: + +1. Read 00.README.FIRST_4.82. + +2. Read README.lsof_4.82 and follow its instructions to verify + the authenticity of lsof_4.82_src.tar. + +3. Unpack lsof_4.82_src.tar -- use `tar xf lsof_4.82_src.tar`. + That will produce an lsof_4.82_src sub-directory. + +4. Change to the lsof_4.82_src sub-directory and read its + 00.README.FIRST file. + +Vic Abell +Wed Mar 25 15:26:14 EDT 2009 diff --git a/00CREDITS b/00CREDITS new file mode 100644 index 0000000..2403983 --- /dev/null +++ b/00CREDITS @@ -0,0 +1,512 @@ + + 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 + Marc Auslander + Tigran Aivazian + Jos Backus + David Bacon + Alexis Ballier + Scott Ballew + Ade Barkah + Alon Bar-Lev + Anthony Baxter + John Beacom + Bruce Beare + M. Jay Beck + Bill Behr + Michael Beirne + Marc Bejarano + Andrew Bell + Steve Bellenot + Robert Benites + 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 + Pierfrancesco Caci + Bill Campbell + David Capshaw + John Caruso + Jon Champlin + Kris Chandrasekhar + Albert Chin-A-Young + Bernt Christandl + Marc Christensen + Hans Petter Christiansen + Tom Christiansen + Yves Christophe + Richard Chycoski + A. Channing Clark + 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 + Will Day + Frederic Delanoy + Mike Depot + Steve Dibbell + Hugh Dickins + David DiGiacomo + Casper Dik + John DiMarco + Don Draper + 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 + 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 + Harvey Garner + Carson Gaspar + Stuart D. Gathman + Brian L. Gentry + Dave Gilbert + Steve Ginsberg + Edwin Groothuis + Jin Guojun + Kurt Gollhardt + Roman Gollent + Steve Gonczi + Julian Gordon + Marcin Gozdalik + Henry Grebler + Richard Green + Chaskiel Grundman + Armin Gruner + David Gutierrez + Robert Hall + Garner Halloran + Adam Hammer + Charles Hannum + Vlad Harchev + Craig Harmer + Michael Haro + Peter Harvey + Steinar Haug + Sheldon Hearn + John Heasley + Wolfgang Hecht + Janet Hempstead + Michael Hennecke + Randolph J. Herber + Andrew Hill + Kurt Hillig + Steven Hinkle + Paul Hite + Billy Ho + 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 + 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 + 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 + 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 + Alex Podlecki + Lutz Poetschulat, + John Polstra + Scott Presnell + Mark Price + Philippe-Andre Prindeville + David Putz + Tom Qin + 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 + Ingimar Robertson + Sylvain Robitaille + Larry Rogers + Malgorzata Roos + Larry Rosenman + Stephan Rossi + Kevin Ruderman + Wolfgang Rupprecht + Pavol Rusnak + Conrad J. Sabatier + Klaus Saggerer + Chris Schanzle + Igor Schein + Horst Scheuermann + 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 + 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 + Sushila Subramanian + Jan Ole Suhr + Mike Sullivan + Patrick D. Sullivan + Peter Svensson + Chris Sylvain + 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 + Dan Trinkle + 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 + Eric Williams + Steve Williams + Steve Wilson + Erich Wimmer + Wally Winzer, Jr. + Patrick Wolfe + Stephen Woods + James Woodward + Scott Worley + Joshua Wright + Sailu Yallapragada + Donna Yobs + Ron Young + Blair Zajac + Karel Zak + Donald Zoch + Malcom Zung + and Waldemar Zurowski + +If I have omitted a contributor's name, the fault is wholly mine, +and I apologize for the error. + + +Vic Abell +March 25, 2009 diff --git a/00DCACHE b/00DCACHE new file mode 100644 index 0000000..5d17c0f --- /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 (Mac OS X 10.5) + 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 [67].x for x86-based systems + FreeBSD 5.x and [67].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 +March 25, 2009 diff --git a/00DIALECTS b/00DIALECTS new file mode 100644 index 0000000..7f9b968 --- /dev/null +++ b/00DIALECTS @@ -0,0 +1,6 @@ + AIX 5.3 + Apple Darwin 9 (Mac OS X 10.5) + FreeBSD 4.9 for x86-based systems + FreeBSD 7.[012] and 8.0 for AMD64-based systems + Linux 2.1.72 and above for x86-based systems + Solaris 9 and 10 diff --git a/00DIST b/00DIST new file mode 100644 index 0000000..156bbe9 --- /dev/null +++ b/00DIST @@ -0,0 +1,4430 @@ + + Notes for the distribution of lsof version 4 + +******************************************************************** +| The latest release of lsof is always available via anonymous ftp | +| from lsof.itap.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 + 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 + + +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: + + AIX 5.3 + Apple Darwin 9 (Mac OS X 10.5) + FreeBSD 4.9 for x86-based systems + FreeBSD 7.[012] and 8.0 for AMD64-based systems + Linux 2.1.72 and above for x86-based systems + Solaris 9 and 10 + +(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 Rosenmann + 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. + +Vic Abell +March 25, 2009 diff --git a/00FAQ b/00FAQ new file mode 100644 index 0000000..6cf790a --- /dev/null +++ b/00FAQ @@ -0,0 +1,7923 @@ + + 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 +March 25, 2009 +______________________________________________________________________ + +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? + +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.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.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? + +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.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? + +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 ZFS probblems +17.27.1 Why does Configure ask for the location of ZFS header files? +17.27.2 Why do -h and -v output warn about possibly inaccurate ZFS + structure definitions? +17.27.3 Why don't the Open Solaris ZFS header files provide correct + ZFS kernel structure definitions? + +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 September 3, 2003 these sites appeared to mirror lsof: + + ftp://ftp.cerias.purdue.edu/pub/tools/unix/sysutils/lsof + ftp://ftp.tau.ac.il/pub/unix/admin + ftp://ftp.cert.dfn.de/pub/tools/admin/lsof + ftp://ftp.fu-berlin.de/pub/unix/tools/lsof + ftp://gd.tuwien.ac.at/utils/admin-tools/lsof + ftp://sunsite.ualberta.ca/pub/Mirror/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/ + + +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 for x86-based systems + FreeBSD 7.[012] and 8.0 for AMD64-based systems + Linux 2.1.72 and above for x86-based systems + Solaris 9 and 10 + + 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. 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.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 has been specified, or if the dialect doesn't support + the displaying of file offset (position). + + 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.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. + + +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.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. If they aren't, then the KVM library + or lsof may be using kernel structure definitions that + don't match the booted kernel. + + 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. + + +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 depts, 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/ipx (needs kernel patch) + /proc/net/raw + /proc/net/raw6 + /proc/net/tcp + /proc/net/tcp6 + /proc/net/udp + /proc/net/udp6 + /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. + + 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 ZFS probblems + +17.27.1 Why does Configure ask for the location of ZFS header files? + + To provide ZFS support when lsof is compiled it needs to have + access to the definitions of ZFS structures used by the kernel. + Those definitions are contained in header files that Sun does + not distribute with Solaris 10. + + When the Configure script detects the system might support ZFS + by finding the header file, it checks for the + required ZFS kernel structure definition header files. When + they are not found, it asks if ZFS support should be included + and if so, with what definitions. + + Two sources can be declared for definitions: 1) lsof's internal + ones; or 2) the necessary header files at some location other + than /usr/include/sys. + + The necessary header files are: + + dmu.h zfs_acl.h zfs_debug.h zfs_rlock.h zil.h + spa.h zfs_context.h zfs_dir.h zfs_vfsops.h zio.h + txg.h zfs_ctldir.h zfs_ioctl.h zfs_znode.h zio_impl.h + + The necessary header files might have been obtained, for + example, from the http://src.opensolaris.org Open Solaris + source site. However, the Open Solaris header files might not + be adequate -- see the answer to the "Why don't the Open + Solaris ZFS header files provide correct ZFS kernel structure + definitions?' question for information on why the Open Solaris + ZFS header files might not provide correct ZFS kernel structure + definitions. + + The supplied header file path must point to a directory that + contains a sys/ subdirectory where the matching header files + are located -- e.g., if the supplied path is /tmp/zfs, then + /tmp/zfs/sys must contain the necessary header files. + + See the answer to the "Why do -h and -v output warn about + possibly inaccurate ZFS kernel structure definitions?" question + for information on the risks associated with using lsof's + internal definitions. + +17.27.2 Why do -h and -v output warn about possibly inaccurate ZFS + kernel structure definitions? + + When lsof is configured to use its internal ZFS kernel + structure definitions, there is the chance that the definitions + may be out of date. Hence, an lsof built with them may report + incorrect device numbers, file sizes, node numbers and link + counts. + + Please contact me via e-mail at for work-around + suggestions. Make sure "lsof" appears in the "Subject:" line so + my e-mail filter won't classify your letter as Spam. + +17.27.3 Why don't the Open Solaris ZFS header files provide correct + ZFS kernel structure definitions? + + The Open Solaris ZFS header files may not provide correct ZFS + kernel definitions. An lsof built with them may report + incorrect device numbers, file sizes, node numbers and link + counts. + + The definitions may be incorrect because the Open Solaris + header files are not synchronized with any particular Solaris + 10 release. Consequently they might contain modifications to + the structures not in the structure definitions used to build + the running kernel. It may be that only Sun has header files + that match the kernel structures of the running Solaris 10 + kernel. + + Please contact me via e-mail at for work-around + suggestions. Make sure "lsof" appears in the "Subject:" line so + my e-mail filter won't classify your letter as Spam. + + +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..7a58df6 --- /dev/null +++ b/00LSOF-L @@ -0,0 +1,100 @@ + + 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 rcac.purdue.edu. + + +Subscribing +=========== + +You may subscribe to the lsof-l mailing list by sending e-mail to: + + lsof-l-subscribe@rcac.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 rcac.purdue.edu GNU Mailman server is +available by sending e-mail to lsof-l-request@rcac.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.rcac.purdue.edu/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@rcac.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 Me Via E-Mail +================================= + +DON'T SEND BUG REPORTS TO lsof-l. Send them directly to me via e-mail +at . Make sure lsof appears in the "Subject:" line and +make sure you first read the "Bug Reports" section of the 00README file +of the lsof distribution. + + +Unsubscribing +============= + +You can unsubscribe from lsof-l by sending e-mail to: + + lsof-l-unsubscribe@rcac.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.rcac.purdue.edu/listinfo/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 +May 8, 2008 diff --git a/00MANIFEST b/00MANIFEST new file mode 100644 index 0000000..24f67e9 --- /dev/null +++ b/00MANIFEST @@ -0,0 +1,386 @@ +.: +00.README.FIRST +00CREDITS +00DCACHE +00DIALECTS +00DIST +00FAQ +00LSOF-L +00MANIFEST +00PORTING +00QUICKSTART +00README +00TEST +00XCONFIG +AFSConfig* +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 +get-hdr-loc.sh* +machine.h +solaris_kaddr_filters +zfs/ + +./dialects/sun/zfs: +sys/ +zfs_vnops.c + +./dialects/sun/zfs/sys: +dmu.h +spa.h +txg.h +zfs_acl.h +zfs_context.h +zfs_ctldir.h +zfs_debug.h +zfs_dir.h +zfs_ioctl.h +zfs_rlock.h +zfs_vfsops.h +zfs_znode.h +zil.h +zio.h +zio_impl.h + +./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..bd9b9a6 --- /dev/null +++ b/00PORTING @@ -0,0 +1,1790 @@ + + 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, + HASF_VNODE, HASKQUEUE, HASPRIVFILETYPE, + HASPSXSHM and HASPSXSEM 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_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_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. + + 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.) + + 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. + + 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. + + HAS_JFS2 The AIX >= 5.0 dialect has jfs2 support. + + HASFSTRUCT indicates the dialect has a file structure + the listing of whose element values can be + enabled with +f[cfn]. FSV_DEFAULT defines + the default listing values. + + HASFSTYPE enables/disables the use of the file system's + stat(2) st_fstype member. + + If the HASFSTYPE value is 1, st_fstype is + treated as a character array; 2, it is + treated as an integer. + + See also the RMNT_EXPDEV and RMNT_FSTYPE + documentation in lib/rmnt.c + + HASGETBOOTFILE indicates the NetBSD or OpenBSD dialect has + a getbootfile() function. + + HASGNODE enables/disables readgnode() in node.c. + + 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. + + 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. + + 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_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_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. + + 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. + + 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. + + 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. + + 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. + + 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(). + + 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., ). + + 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 + . + + 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. + + 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. + + HAS_ZFS indicates the dialect has support for the ZFS file + system. + + HASXOPT_VALUE defines the default binary value for the X option + in store.c. + + 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(). + + 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. + + 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 +March 25, 2009 diff --git a/00QUICKSTART b/00QUICKSTART new file mode 100644 index 0000000..3b7db86 --- /dev/null +++ b/00QUICKSTART @@ -0,0 +1,1008 @@ + + 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 + ... + + +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 +March 27, 2006 diff --git a/00README b/00README new file mode 100644 index 0000000..bf041b8 --- /dev/null +++ b/00README @@ -0,0 +1,1535 @@ + + 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. + +All pre-compiled binaries on lsof.itap.purdue.edu and mirrored from +it were constructed without the HASSECURITY definition. + +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. + +I do support binaries I built, obtained ONLY from lsof.itap.purdue.edu. +Before reporting a problem with a lsof.itap.purdue.edu binary, please +verify the correctness of the signatures found in its associated +CHECKSUMS file. + +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. + +David O'Brien 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. + +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/binaries +and + 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 and [67].x + /dev/kmem-based 11.00 + 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 +April 24, 2007 diff --git a/00TEST b/00TEST new file mode 100644 index 0000000..ca4479e --- /dev/null +++ b/00TEST @@ -0,0 +1,1000 @@ + + 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_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. + +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. + 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 + 7.0 Alpha, gcc + 7.0 Amd64, gcc + 7.1 Amd64, gcc + 8.0 Amd64, gcc + 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.) + 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 + 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 +March 25, 2009 diff --git a/00XCONFIG b/00XCONFIG new file mode 100644 index 0000000..6aaebb0 --- /dev/null +++ b/00XCONFIG @@ -0,0 +1,665 @@ + + 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_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 the standard header files. You may + need to specify it if you want Configure to test + header files in a tree different from /usr/include, + and you want to compile lsof from the header files + in that different tree. + +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_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_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 + 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_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_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 + +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 +April 15, 2008 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/Configure b/Configure new file mode 100755 index 0000000..5d22835 --- /dev/null +++ b/Configure @@ -0,0 +1,5453 @@ +#!/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.157 2009/03/25 19:23:55 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_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_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_LINUX_INCL temporary variable for holding path to Linux +# include files +# $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_PL patch level +# $LSOF_RANLIB randomizing command for the lsof library +# $LSOF_SCRIPT_CALL Customize and Inventory scripts call status +# $LSOF_SPMKF Special Makefile name +# $LSOF_TGT canonical target abbreviation (shortest) +# $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_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_CFGF="" +LSOF_CFGL="" +LSOF_CINFO="" +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_LINUX_INCL="" +LSOF_PL="" +LSOF_RANLIB="ranlib \${LIB}" +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" +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 "make -f $LSOF_MKFC clean" + make -f $LSOF_MKFC clean + else + if test -r ${LSOF_LIB}/${LSOF_LIBMKF} # { + then + echo "(cd ${LSOF_LIB}; make -f ${LSOF_LIBMKF} clean)" + (cd ${LSOF_LIB}; make -f ${LSOF_LIBMKF} clean) + else + if test -r ${LSOF_LIB}/${LSOF_LIBMKF}.skel # { + then + echo "(cd ${LSOF_LIB}; make -f ${LSOF_LIBMKF}.skel clean)" + (cd ${LSOF_LIB}; make -f ${LSOF_LIBMKF}.skel clean) + fi # } + fi # } + fi # } + if test -r ${LSOF_TSTSUBD}/Makefile # { + then + echo "(cd ${LSOF_TSTSUBD}; make spotless)" + (cd ${LSOF_TSTSUBD}; 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 version.h vnode_if.h + echo "rm -rf AFSHeaders AFSVersion 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 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. + + LSOF_RANLIB="@echo \\\\\\\\c" # AIX make doesn't like a null ${RANLIB}. + 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.*) # a coming version of Mac OS? + LSOF_VERS=1000 + ;; + *) + echo Unknown Darwin release: `uname -r` + echo Assuming Darwin 9.0 + LSOF_VERS=900 + ;; + 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) + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + LSOF_TMP1="" + LSOF_UNSUP="" + LSOF_TSTBIGF=" " # enable LTbigf test + ;; + 1000) + 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="-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="-Olimit 1024" + LSOF_TMP1="/sys" + ;; + 30000) + LSOF_CFGF="-Olimit 1024" + LSOF_TMP1="/sys" + LSOF_TMP2=-DUSELOCALREADDIR + ;; + 30200) + LSOF_CFGF="-Olimit 1024" + LSOF_TMP1="/sys" + LSOF_TMP2=-DUSELOCALREADDIR + ;; + 40000) + LSOF_TMP1="/usr/sys" + ;; + 50000|50100) + 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="-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*) + LSOF_VERS=7000 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 7.0" + ;; + 8*) + LSOF_TSTBIGF=" " + LSOF_VERS=8000 + ;; + *) + echo Unknown FreeBSD release: `uname -r` + echo Assuming FreeBSD 2.x + LSOF_CFGL="-lkvm" + LSOF_VERS=2000 + LSOF_N_UNIXV=`/usr/sbin/sysctl -n kern.bootfile` + if test "X$LSOF_N_UNIXV" = "X" # { + then + LSOF_N_UNIXV="/kernel" + fi # } + ;; + esac # } + fi # } + + # Clear LSOF_UNSUP message for supported versions of FreeBSD. + + case $LSOF_VERS in # { + 4090|7000|7010|7020|8000) + LSOF_UNSUP="" + ;; + esac # } + + # Get system CFLAGS from FREEBSD_MAKE_CONF (default=/etc/make.conf). + + if test "X$FREEBSD_MAKE_CONF" = "X" # { + then + FREEBSD_MAKE_CONF="/etc/make.conf" + fi # } + if test -r $FREEBSD_MAKE_CONF # { + then + LSOF_CFGF=`echo "all:\n.include " | make -f- -VCFLAGS` + LSOF_TMP=1 + while test $LSOF_TMP -eq 1 # { + do + echo $LSOF_CFGF | grep -q -e '-O' + if test $? -eq 0 # { + then + if test "X$LSOF_DEBUG" = "X" + then # { + LSOF_DEBUG=`echo $LSOF_CFGF | sed 's/.*\(-O[^ $]*\).*/\1/'` + fi # } + LSOF_CFGF=`echo $LSOF_CFGF | sed 's/\(.*\)-O[^ $]*\(.*\)/\1 \2/' | sed 's/^ *//g' | sed 's/ */ /g' | sed 's/ *$//'` + else + LSOF_TMP=0 + fi # } + LSOF_FBSD_ZFS_CFGF="$LSOF_CFGF" + done # } + 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 # } + + # Do FreeBSD version-specific stuff. + + case $LSOF_VERS in # { + 1000) + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + 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="-lkvm" + ;; + 2020) + 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="-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 # } + ;; + 4000|4010|4020|4030|4040|4050|4060|4070|4080|4090|4100|4110|5000|5010|5020|5030|5040|5050|6000|6010|6020|6030|6040|7000|7010|7020|8000) + 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="-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." + exit 1 + fi # } + fi # } + fi # } + fi # } + + # Do FreeBSD 5.2 and higher version-specific stuff. + + 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}/ufs/ufs/inode.h # { + then + grep -q i_din2 ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_UFS1_2" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/conf.h # { + then + grep -q "^#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 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" + 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 # } + fi # } + fi # } + fi # } + ;; + *) + echo "Unknown FreeBSD release: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + 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 # } + LSOF_DIALECT_DIR=freebsd + ;; + +# Configure for HP-UX and HP-UX gcc. + + hpux|hpuxgcc) + LSOF_CFGL="" + LSOF_RANLIB="" + 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="-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 # } + LSOF_DIALECT_DIR="" + 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="-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 $LSOF_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 + $LSOF_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 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 # } + 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="-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="-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="-w" + LSOF_DEBUG="-pedantic -O" + else + LSOF_CFGL="" + fi # } + 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="-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="-lkvm" + LSOF_DIALECT_DIR=n+obsd + ;; + +# Configure for SCO OpenServer. + + osr|osrgcc|sco|scogcc) + LSOF_RANLIB="" + + 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) + LSOF_RANLIB="" + 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 + echo "WARNING: no cc in ${SOLARIS_CCDIR}; using cc without path." + LSOF_CC=cc + 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" + ;; + *) + 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) + 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="-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) + 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 # } + fi # } + + # Do tests specific to Solaris 10 and above. + + if test $LSOF_VERS -ge 100000 # { + then + if test -r ${LSOF_INCLUDE}/inet/ipclassifier.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_IPCLASSIFIER_H" + 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 # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/zone.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASZONES" + fi # } + + # Check for Solaris 10 or higher ZFS. + + if test -r ${LSOF_INCLUDE}/sys/fs/zfs.h # { + then + + # Check for required ZFS kernel header files. + + LSOF_TMP1="dmu.h zfs_acl.h zfs_debug.h zfs_rlock.h zil.h spa.h zfs_context.h zfs_dir.h zfs_vfsops.h zio.h txg.h zfs_ctldir.h zfs_ioctl.h zfs_znode.h zio_impl.h" + LSOF_TMP2="" + for i in $LSOF_TMP1 # { + do + if test ! -r ${LSOF_INCLUDE}/sys/$i # { + then + if test "X$LSOF_TMP2" = "X" # { + then + LSOF_TMP2=$i + else + LSOF_TMP2="$LSOF_TMP2 $i" + fi # } + fi # } + done # } + if test "X$LSOF_TMP2" = "X" # { + then + LSOF_TMP4="${LSOF_INCLUDE}/sys" + LSOF_TMP5=0 + else + LSOF_TMP3=`pwd`/dialects/sun/get-hdr-loc.sh + if test ! -x $LSOF_TMP3 # { + then + echo "FATAL: can't execute: $LSOF_TMP3" + rm -f $LSOF_HLP + exit 1 + fi # } + LSOF_TMP4=`$LSOF_TMP3 $LSOF_TMP2` + LSOF_TMP5=$? + fi #} + if test $LSOF_TMP5 -eq 0 # { + then + + # ZFS support has been requested. + + if test "X$LSOF_TMP4" = "X" # { + then + + # Use of lsof interal ZFS structure definitions has been + # requested. + + LSOF_CFGF="$LSOF_CFGF -DHAS_ZFS=1" + else + + # Use of ZFS header files at the returned location has + # been requested. + + LSOF_CFGF="$LSOF_CFGF -DHAS_ZFS=2" + if test "X$LSOF_TMP4" != "X${LSOF_INCLUDE}/sys" # { + then + + # Add the returned location unless it is ${LSOF_INCLUDE}/sys. + + LSOF_CFGF="$LSOF_CFGF -I$LSOF_TMP4" + fi # } + fi # } + + # Identify the ZFS version. + + LSOF_TMP1=0 + if test -x /usr/sbin/zpool # { + then + LSOF_TMP2=`/usr/sbin/zpool upgrade -v|grep -i running|grep -i zfs` + if test "X$LSOF_TMP2" != "X" # { + then + LSOF_TMP3=`echo $LSOF_TMP2 | sed 's/^.* \([0-9][0-9]*\)\.$/\1/'` + if test "X$LSOF_TMP3" != "X" # { + then + LSOF_TMP1=$LSOF_TMP3 + fi # } + fi # } + fi # } + LSOF_CFGF="$LSOF_CFGF -DZFS_VERS=$LSOF_TMP1" + else + + # The get-hdr-loc.sh script returned a non-zero exit value. + # If there was a message on STDOUT, an error was detected. + # if there was no message, ZFS support is not required. + + if test "X$LSOF_TMP4" != "X" # { + then + echo "$LSOF_TMP3 detected the error: $LSOF_TMP4" + rm -f $LSOF_HLP + exit 1 + fi # } + fi # } + fi # } + ;; + *) + echo "Unsupported Solaris version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + LSOF_CFGF="-Dsolaris=$LSOF_VERS $LSOF_CFGF" + + # 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 + + # 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="-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" + LSOF_RANLIB="" + 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="-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="-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="-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_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" >> ${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 warning, as appropriate. + +if test "X$LSOF_UNSUP" != "X" # { +then + echo "$LSOF_UNSUP" +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/LICENSE.lsof b/LICENSE.lsof new file mode 100644 index 0000000..9bfa12c --- /dev/null +++ b/LICENSE.lsof @@ -0,0 +1,25 @@ +/* + * 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. + */ diff --git a/README.lsof_4.82 b/README.lsof_4.82 new file mode 100644 index 0000000..2aa2e48 --- /dev/null +++ b/README.lsof_4.82 @@ -0,0 +1,128 @@ + + Information About This Lsof Distribution + + +What You Have +============= + +If you got this far without being confused, then you are probably +familiar with the construction of the lsof distribution or you have +read RELEASE.SUMMARY_4.82. If either is the case, please skip to +the Inventory section. If you haven't read RELEASE.SUMMARY_4.82, +I suggest you do it now, because it explains how the lsof distribution +is constructed and other useful things about lsof, including a +summary of changes for the past few lsof revisions. + +Even though you may have thought you were getting lsof.tar.bz2, +lsof.tar.gz or lsof.tar.Z with ftp, you really got lsof_4.82.tar.bz2, +lsof_4.82.tar.gz or lsof_4.82.tar.Z. That's because the triplet of +lsof.tar.* files are symbolic links to their longer-named counterparts. + +The bzip2'd, gzip'd or compressed tar files with lsof_, followed by a +number, are wrapper archives, designed to package the lsof source +archive, this file, other documentation files, and a GPG authentication +certificate together. + +The number, 4.82, is the lsof revision number. When you bunzip2'd, +gunzip'd or uncompressed lsof_4.82.tar.* and used tar to unpack +lsof_4.82.tar, you got: 00.README.FIRST_4.82, describing the contents +of lsof_4.82; README.lsof_4.82; lsof_4.82_src.tar; and +lsof_4.82_src.tar.sig. All are identified with the revision number. +You're reading README.lsof_4.82. lsof_4.82_src.tar.sig is a GPG +certificate that authenticates the lsof source archive, +lsof_4.82_src.tar. + +After you read the Inventory and Security sections, and hopefully +after you check the GPG certificate, unpack the lsof_4.82_src.tar +source archive and you will get a sub-directory, named lsof_4.82_src, +that contains the lsof 4.82 source distribution. + + +Inventory +========= + +Once you have unpacked lsof_4.82_src.tar.tar, you can check +lsof_4.82_src for completeness by changing to that sub-directory +and running the Inventory script. The lsof_4.82_src/Configure +script runs the Inventory script, too. The Configure script also +calls a customization script, called Customize. You can direct +Configure to avoid calling Inventory and Customize with the -n +option. + +See the Distribution Contents section of the 00DIST file and The +Inventory Script section of the 00README file for more information +on the contents of the lsof distribution, and the Configure, +Customize and Inventory scripts. The 00DIST and 00README files +will be found in the lsof_4.82_src sub-directory you just created. + + +Security +======== + +The md5 checksum for lsof_4.82_src.tar is: + + MD5 (lsof_4.82_src.tar) = 91efe55e2d5d06292556fb454d42c800 + +A good source for an MD5 checksum computation tool is the OpenSSL +project whose work may be found at: + + www.openssl.org + +You can use the openssl "dgst" operator to compute an MD5 checksum -- +e.g., + + $ openssl dgst -md5 lsof_4.82_src + +The old-style sum(1) checksum for lsof_4.82_src.tar (Please read +the next paragraph if you don't get this value.) is: + + 11381 8606 lsof_4.82/lsof_4.82_src.tar + +If your dialect's sum(1) program defaults to the new style algorithm +(e.g., Solaris), you may have to use its -r option (or use the +Solaris /usr/ucb/sum). If your Unix dialect doesn't have a sum(1) +program (e.g., FreeBSD, or NetBSD), use its cksum(1) program with +the -o1 option to get an old-style checksum. You may also need to +ignore the block count, depending on the block size used on your +your system (i.e., 512 or 1,024). The sum(1) that produced the +above checksum considers block size to be 512; in contrast the BSD +cksum(1) programs' -o1 option considers block size to be 1,024. + +lsof_4.82_src.tar.sig is a GPG certificate file, using my public +key. My key may be available on some public key servers under the +names: + + Victor A. Abell + or + Victor A. Abell + +You will also find it at: + + ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/Victor_A_Abell.gpg + +Get my key and install it in your public key ring. + +Once my key is installed, use this command to check the certificate +of lsof_4.82_src.tar: + + gpg --verify lsof_4.82_src.tar.sig lsof_4.82_src.tar + +If the certificate check isn't good, lsof_4.82_src.tar is suspect. +Report the problem to me via e-mail at . + +If you don't have GPG, you can compare the md5 checksum of +lsof_4.82_src.tar to the value listed in this file. However, that +is a less reliable authentication method, since it can't detect +changes to both lsof_4.82_src.tar and the md5 checksum value listed +in this tile. + +Other Security +============== + +Signature information for the distribution file that contains +this file may be found in the CHECKSUMS file that is located +where the distribution file was found. + + +Victor A. Abell +Wed Mar 25 15:26:12 EDT 2009 diff --git a/arg.c b/arg.c new file mode 100644 index 0000000..fe3834a --- /dev/null +++ b/arg.c @@ -0,0 +1,2428 @@ +/* + * 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.49 2009/03/25 19:20:30 abe Exp $"; +#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 { + mp = mmp[mx++]; + 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); +} + + +/* + * 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/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..276cd35 --- /dev/null +++ b/dialects/linux/dfile.c @@ -0,0 +1,64 @@ +/* + * 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.7 2002/02/26 15:20:15 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * 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..e0861ce --- /dev/null +++ b/dialects/linux/dlsof.h @@ -0,0 +1,172 @@ +/* + * 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.18 2008/10/21 16:17:21 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) +#include +# else /* !defined(GLIBCV) */ +#include +# endif /* defined(GLIBCV) */ + +#include +#include + +#if defined(HASSELINUX) +#include +#endif /* defined(HASSELINUX) */ + +#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 (mounted on) */ + char *fsname; /* file system + * (symbolic links unresolved) */ + char *fsnmres; /* file system + * (symbolic links resolved) */ + dev_t dev; /* directory st_dev */ + dev_t rdev; /* directory st_rdev */ + INODETYPE inode; /* directory st_ino */ + mode_t mode; /* directory st_mode */ + 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 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..8eda2c2 --- /dev/null +++ b/dialects/linux/dmnt.c @@ -0,0 +1,586 @@ +/* + * 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.17 2008/04/15 13:32:26 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, 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; /* directory name */ + dev_t dev; /* device number */ + int ln; /* line on which defined */ + struct mntsup *next; /* next entry */ +} mntsup_t; +#endif /* defined(HASMNTSUP) */ + + +/* + * Local static definitions + */ + +static 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, s, ss) + char *dn; /* mount point directory name */ + struct stat *s; /* stat(2) buffer receptor */ + int *ss; /* stat(2) status result -- i.e., SB_* + * values */ +{ + static int err = 0; + int h; + mntsup_t *mp, *mpn; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + + if (err) + return(0); + if (!MSHash) { + + /* + * No mount supplement hash buckets have been allocated, so read the + * mount supplement file and create hash buckets for its entries. + */ + char buf[(MAXPATHLEN*2) + 1], *dp, path[(MAXPATHLEN*2) + 1]; + dev_t dev; + FILE *fs; + int ln = 0; + size_t sz; + + if ((MntSup != 2) || !MntSupP) + return(0); + if (!is_readable(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 (!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->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 biuckets for the supplied directory path. + */ + if (err) + return(0); + h = hash_mnt(dn); + for (mp = MSHash[h]; mp; mp = mp->next) { + if (!strcmp(dn, mp->dn)) { + memset((void *)s, 0, sizeof(struct stat)); + s->st_dev = mp->dev; + *ss |= SB_DEV; + return(1); + } + } + return(0); +} + + +/* + * hash_mnt() - hash mount point + */ + +static int +hash_mnt(dn) + char *dn; /* mount point directory name */ +{ + register int i, h; + size_t l; + + if (!(l = strlen(dn))) + return(0); + if (l == 1) + return((int)*dn & (HASHMNT - 1)); + for (i = h = 0; i < (int)(l - 1); i++) { + h ^= ((int)dn[i] * (int)dn[i+1]) << ((i*3)%13); + } + return(h & (HASHMNT - 1)); +} +#endif /* defined(HASMNTSUP) */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char buf[MAXPATHLEN], *cp, **fp; + char *dn = (char *)NULL; + int ds; + char *fp0 = (char *)NULL; + char *fp1 = (char *)NULL; + 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; + /* + * Ignore an entry with a colon in the device name, followed by + * "(pid*" -- it's probably an automounter entry. + * + * Ignore autofs, pipefs, and sockfs entries. + */ + if ((cp = strchr(fp0, ':')) && !strncasecmp(++cp, "(pid", 4)) + continue; + if (!strcasecmp(fp[2], "autofs") || !strcasecmp(fp[2], "pipefs") + || !strcasecmp(fp[2], "sockfs")) + continue; + /* + * Interpolate a possible symbolic directory link. + */ + if (dn) + (void) free((FREE_P *)dn); + dn = fp1; + fp1 = (char *)NULL; + 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; + /* + * Detect an NFS mount point. + */ + if (!(nfs = strcasecmp(fp[2], "nfs")) && !HasNFS) + HasNFS = 1; + /* + * Stat() the directory. + */ + if (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"); + } + +#if defined(HASMNTSUP) + if ((MntSup == 2) && MntSupP) { + ds = 0; + if (!getmntdev(dn, &sb, &ds) || !(ds & SB_DEV)) + continue; + (void) fprintf(stderr, + " assuming dev=%#lx from %s\n", + (long)sb.st_dev, MntSupP); + } else + continue; +#else /* !defined(HASMNTSUP) */ + continue; +#endif /* defined(HASMNTSUP) */ + + } else + ds = SB_ALL; + /* + * Allocate and fill a local mount structure. + */ + 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->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) + (void) printf("%s %#lx\n", mp->dir, (long)mp->dev); +#endif /* defined(HASMNTSUP) */ + + /* + * Interpolate a possible file system (mounted-on) device name link. + */ + dn = fp0; + fp0 = (char *)NULL; + mp->fsname = dn; + ln = Readlink(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mp->fsnmres = ln; + mp->fs_mode = sb.st_mode; + 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..6d56a6f --- /dev/null +++ b/dialects/linux/dnode.c @@ -0,0 +1,538 @@ +/* + * 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.20 2009/03/25 19:22:39 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define OFFSET_MAX ((off_t)0x7fffffff) /* this is defined in + * .../src/fs/locks.c and not + * in a header file */ +#define PIDBUCKS 64 /* PID hash buckets */ +#define HASHPID(pid) (((int)((pid * 31415) >> 3)) & (PIDBUCKS - 1)) + + +/* + * Local structure definitions + */ + +struct llock { + int pid; + dev_t dev; + INODETYPE inode; + char type; + struct llock *next; +}; + + +/* + * Local definitions + */ + +struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static void check_lock,(void)); + + +/* + * check_lock() - check lock for file *Lf, process *Lp + */ + +static void +check_lock() +{ + int h; + struct llock *lp; + + h = HASHPID(Lp->pid); + for (lp = LckH[h]; lp; lp = lp->next) { + if (Lp->pid == lp->pid + && Lf->dev == lp->dev + && Lf->inode == lp->inode) + { + Lf->lock = lp->type; + return; + } + } +} + + +/* + * get_fields() - separate a line into fields + */ + +int +get_fields(ln, sep, fr, eb, en) + char *ln; /* input line */ + char *sep; /* separator list */ + char ***fr; /* field pointer return address */ + int *eb; /* indexes of fields where blank or an + * entry from the separator list may be + * embedded and are not separators + * (may be NULL) */ + int en; /* number of entries in eb[] (may be + * zero) */ +{ + char *bp, *cp, *sp; + int i, j, n; + MALLOC_S len; + static char **fp = (char **)NULL; + static int nfpa = 0; + + for (cp = ln, n = 0; cp && *cp;) { + for (bp = cp; *bp && (*bp == ' ' || *bp == '\t'); bp++); + ; + if (!*bp || *bp == '\n') + break; + for (cp = bp; *cp; cp++) { + if (*cp == '\n') { + *cp = '\0'; + break; + } + if (*cp == '\t') /* TAB is always a separator */ + break; + if (*cp == ' ') { + + /* + * See if this field may have an embedded space. + */ + if (!eb || !en) + break; + else { + for (i = j = 0; i < en; i++) { + if (eb[i] == n) { + j = 1; + break; + } + } + if (!j) + break; + } + } + if (sep) { + + /* + * See if the character is in the separator list. + */ + for (sp = sep; *sp; sp++) { + if (*sp == *cp) + break; + } + if (*sp) { + + /* + * See if this field may have an embedded separator. + */ + if (!eb || !en) + break; + else { + for (i = j = 0; i < en; i++) { + if (eb[i] == n) { + j = 1; + break; + } + } + if (!j) + break; + } + } + } + } + if (*cp) + *cp++ = '\0'; + if (n >= nfpa) { + nfpa += 32; + len = (MALLOC_S)(nfpa * sizeof(char *)); + if (fp) + fp = (char **)realloc((MALLOC_P *)fp, len); + else + fp = (char **)malloc(len); + if (!fp) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for field pointers.\n", + Pn, 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, 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, s, ss, l, ls) + char *p; /* node's readlink() path */ + 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: + Ntype = N_BLK; + break; + case S_IFCHR: + Ntype = N_CHR; + break; + case S_IFIFO: + Ntype = N_FIFO; + break; + case S_IFSOCK: + process_proc_sock(p, s, ss, l, ls); + return; + } + } + if (Selinet) + return; +/* + * Save the device. If it is an NFS device, change the node type to N_NFS. + */ + if (ss & SB_DEV) { + Lf->dev = s->st_dev; + Lf->dev_def = 1; + } + if ((Ntype == N_CHR || Ntype == N_BLK)) { + if (ss & SB_RDEV) { + Lf->rdev = s->st_rdev; + Lf->rdev_def = 1; + } + } + if (Ntype == N_REGLR && (HasNFS == 2)) { + for (mp = readmnt(); mp; mp = mp->next) { + if ((mp->ty == N_NFS) + && (mp->ds & SB_DEV) && (Lf->dev == mp->dev) + ) { + Ntype = N_NFS; + break; + } + } + } +/* + * Save the inode number. + */ + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } +/* + * Check for a lock. + */ + if (Lf->dev_def && (Lf->inp_ty == 1)) + (void) check_lock(); +/* + * Save the file size. + */ + switch (Ntype) { + case N_BLK: + case N_CHR: + case N_FIFO: + if (!Fsize && l && (ls & SB_SIZE) && OffType) { + Lf->off = (SZOFFTYPE)l->st_size; + Lf->off_def = 1; + } + break; + default: + if (Foffset) { + if (l && (ls & SB_SIZE) && OffType) { + Lf->off = (SZOFFTYPE)l->st_size; + Lf->off_def = 1; + } + } else if (!Foffset || Fsize) { + if (ss & SB_SIZE) { + Lf->sz = (SZOFFTYPE)s->st_size; + Lf->sz_def = 1; + } + } + } +/* + * Record the link count. + */ + if (Fnlink && (ss & SB_NLINK)) { + Lf->nlink = (long)s->st_nlink; + Lf->nlink_def = 1; + if (Nlink && (Lf->nlink < Nlink)) + Lf->sf |= SELNLINK; + } +/* + * Format the type name. + */ + if (ss & SB_MODE) { + switch (type) { + case S_IFBLK: + tn = "BLK"; + break; + case S_IFCHR: + tn = "CHR"; + break; + case S_IFDIR: + tn = "DIR"; + break; + case S_IFIFO: + tn = "FIFO"; + break; + case S_IFREG: + tn = "REG"; + break; + case S_IFLNK: + tn = "LINK"; + break; + case S_ISVTX: + tn = "VTXT"; + break; + default: + (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); + Lf->ntype = Ntype; +/* + * Record an NFS file selection. + */ + if (Ntype == N_NFS && Fnfs) + Lf->sf |= SELNFS; +/* + * Test for specified file. + */ + if (Sfile + && is_file_named((char *)NULL, + ((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..d1424f3 --- /dev/null +++ b/dialects/linux/dproc.c @@ -0,0 +1,1381 @@ +/* + * 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.22 2008/10/21 16:17:21 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define FDINFO_FLAGS 1 /* fdinfo flags available */ +#define FDINFO_POS 2 /* fdinfo position available */ +#define FDINFO_ALL (FDINFO_FLAGS | FDINFO_POS) +#define LSTAT_TEST_FILE "/" +#define LSTAT_TEST_SEEK 1 + +#if !defined(ULLONG_MAX) +#define ULLONG_MAX 18446744073709551615ULL +#endif /* !defined(ULLONG_MAX) */ + + +/* + * Local structures + */ + +struct l_fdinfo { + int flags; /* flags: line value */ + off_t pos; /* pos: line value */ +}; + + +/* + * Local variables + */ + +static short Cckreg; /* conditional status of regular file + * checking: + * 0 = unconditionally check + * 1 = conditionally check */ +static short Ckscko; /* socket file only checking status: + * 0 = none + * 1 = check only socket files */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int get_fdinfo,(char *p, struct l_fdinfo *fi)); +_PROTOTYPE(static int getlinksrc,(char *ln, char *src, int srcl)); +_PROTOTYPE(static int nm2id,(char *nm, int *id, int *idl)); +_PROTOTYPE(static int read_id_stat,(int ty, char *p, int id, char **cmd, + int *ppid, int *pgid)); +_PROTOTYPE(static void process_proc_map,(char *p, struct stat *s, int ss)); +_PROTOTYPE(static int process_id,(char *idp, int idpl, char *cmd, UID_ARG uid, + int pid, int ppid, int pgid)); +_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) */ + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + char *cmd; + struct dirent *dp; + struct stat sb; + int lwp, n, nl, pgid, pid, ppid, rv, tx; + static char *lwppath = (char *)NULL; + static int lwppathl = 0; + 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; + static char *taskpath = (char *)NULL; + static int taskpathl = 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, 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, 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; + /* + * Process the PID's process information. + */ + (void) make_proc_path(pidpath, n, &path, &pathl, "stat"); + rv = read_id_stat(0, path, pid, &cmd, &ppid, &pgid); + if (rv == 1) + continue; + else if (rv == 0) { + (void) process_id(pidpath, n, cmd, uid, pid, ppid, pgid); + continue; + } + /* + * The process is a zombie. Check for a non-zombie task. + */ + (void) make_proc_path(pidpath, n, &taskpath, &taskpathl, "task"); + tx = n + 4; + if ((ts = opendir(taskpath))) { + + /* + * Process the PID's tasks (lightweight processes.) Record the + * open files of the first one whose LWP ID does not match the PID + * and which is not a itself a zombie. + */ + while ((dp = readdir(ts))) { + + /* + * Get the LWP ID. Skip the task if its LWP ID matches the + * process PID. + */ + if (nm2id(dp->d_name, &lwp, &nl)) + continue; + if (lwp == pid) + continue; + /* + * Check the LWP state. + */ + if (read_id_stat(1, path, lwp, &cmd, &ppid, &pgid)) + continue; + /* + * Attempt to record the LWP. + */ + if ((tx + 1 + nl + 1) > lwppathl) { + lwppathl = tx + 1 + n + 1 + 64; + if (lwppath) + lwppath = (char *)realloc((MALLOC_P *)lwppath, + lwppathl); + else + lwppath = (char *)malloc((MALLOC_S)lwppathl); + if (!lwppath) { + (void) fprintf(stderr, + "%s: can't allocate %d task bytes", Pn, + lwppathl); + (void) fprintf(stderr, + " for \"%s/%s/\"\n", taskpath, dp->d_name); + Exit(1); + } + } + (void) snpf(lwppath, lwppathl, "%s/%s/", taskpath, + dp->d_name); + if (!process_id(lwppath, (tx + 1 + nl+ 1), cmd, uid, pid, + ppid, pgid)) + { + break; + } + } + (void) closedir(ts); + } + } +} + + +/* + * get_fdinfo() - get values from /proc/fdinfo/FD + */ + +static int +get_fdinfo(p, fi) + char *p; /* path to fdinfo file */ + struct l_fdinfo *fi; /* pointer to local fdinfo values + * return structure */ +{ + char buf[MAXPATHLEN + 1], *ep, **fp; + FILE *fs; + int rv = 0; + unsigned long ul; + unsigned long long ull; +/* + * Signal no values returned (0) if no fdinfo pointer was provided or if the + * fdinfo path can't be opened. + */ + if (!fi) + return(0); + if (!p || !*p || !(fs = fopen(p, "r"))) + return(0); +/* + * Read the fdinfo file. + */ + while (fgets(buf, sizeof(buf), fs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 2) + continue; + if (!fp[0] || !*fp[0] || !fp[1] || !*fp[1]) + continue; + if (!strcmp(fp[0], "flags:")) { + + /* + * Process a "flags:" line. + */ + ep = (char *)NULL; + if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + fi->flags = (unsigned int)ul; + if ((rv |= FDINFO_FLAGS) == FDINFO_ALL) + break; + } else if (!strcmp(fp[0], "pos:")) { + + /* + * Process a "pos:" line. + */ + ep = (char *)NULL; + if ((ull = strtoull(fp[1], &ep, 0)) == ULLONG_MAX + || !ep || *ep) + continue; + fi->pos = (off_t)ull; + if ((rv |= FDINFO_POS) == FDINFO_ALL) + break; + } + } + fclose(fs); +/* + * Signal via the return value what information was obtained. (0 == none) + */ + return(rv); +} + + +/* + * getlinksrc() - get the source path name for the /proc//fd/ link + */ + + +static int +getlinksrc(ln, src, srcl) + char *ln; /* link path */ + char *src; /* link source path return address */ + int srcl; /* length of src[] */ +{ + char *cp; + int ll; + + 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); + } + 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, &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, 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); +} + + +/* + * 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) + 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 av; + static char *dpath = (char *)NULL; + static int dpathl = 0; + short 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 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; + 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) + || is_cmd_excl(cmd, &pss, &sf)) + return(1); + if (Cckreg) { + + /* + * If conditional checking of regular files is enabled, enable + * socket file only checking, based on the process' selection + * status. + */ + Ckscko = (sf & SELPROC) ? 0 : 1; + } + alloc_lproc(pid, pgid, ppid, uid, cmd, (int)pss, (int)sf); + Plf = (struct lfile *)NULL; +/* + * Process the ID's current working directory info. + */ + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "cwd"); + alloc_lfile(CWD, -1); + if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + if (!Fwarn) { + (void) memset((void *)&sb, 0, sizeof(sb)); + lnk = ss = 0; + (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + pn = 1; + } else + pn = 0; + } else { + lnk = pn = 1; + 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, + &sb, ss, + (struct stat *)NULL, 0); + if (Lf->sf) + link_lfile(); + } + } +/* + * Process the ID's root directory info. + */ + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "root"); + alloc_lfile(RTD, -1); + if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + if (!Fwarn) { + (void) memset((void *)&sb, 0, sizeof(sb)); + lnk = ss = 0; + (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + pn = 1; + } else + pn = 0; + } else { + lnk = pn = 1; + 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, + &sb, ss, + (struct stat *)NULL, 0); + if (Lf->sf) + link_lfile(); + } + } +/* + * Process the ID's execution info. + */ + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "exe"); + alloc_lfile("txt", -1); + if (getlinksrc(path, pbuf, sizeof(pbuf)) < 1) { + (void) memset((void *)&sb, 0, sizeof(sb)); + lnk = ss = 0; + if (!Fwarn) { + if ((errno != ENOENT) || uid) { + (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + pn = 1; + } else + pn = 0; + } else { + lnk = pn = 1; + 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, + &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)) < 1) { + (void) memset((void *)&sb, 0, sizeof(sb)); + lnk = ss = 0; + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + pn = 1; + } else + pn = 0; + } else { + lnk = 1; + if (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) { + if (oty) { + (void) make_proc_path(ipath, j, &pathi, &pathil, + fp->d_name); + if ((av = get_fdinfo(pathi, &fi)) & FDINFO_POS) { + ls |= SB_SIZE; + lsb.st_size = fi.pos; + } else + ls &= ~SB_SIZE; + +#if !defined(HASNOFSFLAGS) + if ((av & FDINFO_FLAGS) && (Fsv & FSV_FG)) { + Lf->ffg = (long)fi.flags; + Lf->fsv |= FSV_FG; + } +# endif /* !defined(HASNOFSFLAGS) */ + + } + process_proc_node(lnk ? pbuf : path, + &sb, ss, &lsb, ls); + 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, 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; + 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, 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. + */ + alloc_lfile("mem", -1); + if (HasNFS) { + sv = statsafely(fp[6], &sb); + } else + sv = stat(fp[6], &sb); + if (sv) { + en = errno; + /* + * Applying stat(2) to the file failed, so manufacture a partial + * stat(2) reply from the process' maps file entry. + * + * If the file has been deleted, reset its type to "DEL"; otherwise + * generate a stat() error name addition. + */ + (void) memset((void *)&sb, 0, sizeof(sb)); + sb.st_dev = dev; + sb.st_ino = (ino_t)inode; + sb.st_mode = S_IFREG; + mss = SB_DEV | SB_INO | SB_MODE; + if (ds) + alloc_lfile("DEL", -1); + else { + (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", + strerror(en)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } else if ((sb.st_dev != dev) || ((INODETYPE)sb.st_ino != inode)) { + + /* + * The stat(2) device and inode numbers don't match those obtained + * from the process' maps file. + * + * If the file has been deleted, reset its type to "DEL"; otherwise + * generate inconsistency name additions. + * + * Manufacture a partial stat(2) reply from the maps file + * information. + */ + if (ds) + alloc_lfile("DEL", -1); + else if (!Fwarn) { + char *sep; + + if (sb.st_dev != dev) { + (void) snpf(nmabuf, sizeof(nmabuf), + "(path dev=%d,%d%s", + GET_MAJ_DEV(sb.st_dev), GET_MIN_DEV(sb.st_dev), + ((INODETYPE)sb.st_ino == inode) ? ")" : ","); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + sep = ""; + } else + sep = "(path "; + if ((INODETYPE)sb.st_ino != inode) { + (void) snpf(fmtbuf, sizeof(fmtbuf), "%%sinode=%s)", + InodeFmt_d); + (void) snpf(nmabuf, sizeof(nmabuf), fmtbuf, + sep, (INODETYPE)sb.st_ino); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } + (void) memset((void *)&sb, 0, sizeof(sb)); + sb.st_dev = dev; + sb.st_ino = (ino_t)inode; + sb.st_mode = S_IFREG; + mss = SB_DEV | SB_INO | SB_MODE; + } else + mss = SB_ALL; + /* + * Record the file's information. + */ + process_proc_node(fp[6], &sb, mss, (struct stat *)NULL, 0); + if (Lf->sf) + link_lfile(); + } + (void) fclose(ms); +} + + +/* + * read_id_stat() - read ID (PID or LWP ID) status + * + * return: -1 == ID is a zombie + * 0 == ID OK + * 1 == ID unavailable + */ + +static int +read_id_stat(ty, p, id, cmd, ppid, pgid) + int ty; /* type: 0 == PID, 1 == LWP */ + char *p; /* path to status file */ + int id; /* ID: PID or LWP */ + char **cmd; /* malloc'd command name */ + int *ppid; /* returned parent PID for PID type */ + int *pgid; /* returned process group ID for PID + * type */ +{ + char buf[MAXPATHLEN], *cp, *cp1, **fp; + static char *cbf = (char *)NULL; + static MALLOC_S cbfa = 0; + FILE *fs; + MALLOC_S len; + int nf; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Open the stat file path, assign a page size buffer to its stream, + * and read the file's first line. + */ + if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return(1); + cp = fgets(buf, sizeof(buf), fs); + (void) fclose(fs); + if (!cp) + return(1); +/* + * Separate the line into fields on white space separators. Expect five fields + * for a PID type and three for an LWP type. + */ + if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) + < (ty ? 5 : 3)) + { + return(1); + } +/* + * Convert the first field to an integer; its conversion must match the + * ID argument. + */ + if (!fp[0] || (atoi(fp[0]) != id)) + return(1); +/* + * Get the command name from the second field. Strip a starting '(' and + * an ending ')'. Allocate space to hold the result and return the space + * pointer. + */ + if (!(cp = fp[1])) + return(1); + if (cp && *cp == '(') + cp++; + if ((cp1 = strrchr(cp, ')'))) + *cp1 = '\0'; + if ((len = strlen(cp) + 1) > cbfa) { + cbfa = len; + if (cbf) + cbf = (char *)realloc((MALLOC_P *)cbf, cbfa); + else + cbf = (char *)malloc(cbfa); + if (!cbf) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for command \"%s\"\n", + Pn, cbfa, cp); + Exit(1); + } + } + (void) snpf(cbf, len, "%s", cp); + *cmd = cbf; +/* + * If the type is PID, convert and return parent process (fourth field) + * and process group (fifth field) IDs. + */ + if (!ty) { + if (fp[3] && *fp[3]) + *ppid = atoi(fp[3]); + else + return(1); + if (fp[4] && *fp[4]) + *pgid = atoi(fp[4]); + else + return(1); + } +/* + * Check the state in the third field. If it is 'Z', return that indication. + */ + return((fp[2] && !strcmp(fp[2], "Z")) ? -1 : 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 s safe + * stat() on each trimmed result. Stop when a safe stat() succeeds or doesn't + * fail because of EACCES or EPERM. + */ + for (cp = strrchr(cb, '/'); cp && (cp != cb);) { + *cp = '\0'; + if (!statsafely(cb, &sb)) { + st = 1; + break; + } + ensv = errno; + if ((ensv != EACCES) && (ensv != EPERM)) + break; + cp = strrchr(cb, '/'); + } +/* + * If a stat() on a trimmed result succeeded, form partial results containing + * only the device and raw device numbers. + */ + memset((void *)s, 0, sizeof(struct stat)); + if (st) { + errno = 0; + s->st_dev = sb.st_dev; + s->st_rdev = sb.st_rdev; + *ss = SB_DEV | SB_RDEV; + return(0); + } + errno = ensv; + *ss = 0; + return(1); +} diff --git a/dialects/linux/dproto.h b/dialects/linux/dproto.h new file mode 100644 index 0000000..0b86a8a --- /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.7 2008/04/15 13:32:26 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,(char *p, 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, struct stat *s, int ss, struct stat *l, int ls)); +_PROTOTYPE(extern void process_proc_sock,(char *p, 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..52d8ad8 --- /dev/null +++ b/dialects/linux/dsock.c @@ -0,0 +1,2792 @@ +/* + * 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.34 2009/03/25 19:22:39 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define INOBUCKS 128 /* inode hash bucket count -- must be + * a power of two */ +#define INOHASH(ino) ((int)((ino * 31415) >> 3) & (INOBUCKS - 1)) +#define TCPUDPHASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp_bucks - 1)) +#define TCPUDP6HASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp6_bucks - 1)) + + +/* + * Local structures + */ + +struct ax25sin { /* AX25 socket information */ + char *da; /* destination address */ + char *dev_ch; /* device characters */ + char *sa; /* source address */ + INODETYPE inode; + unsigned long sq, rq; /* send and receive queue values */ + unsigned char sqs, rqs; /* send and receive queue states */ + int state; + struct ax25sin *next; +}; + +struct 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 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 tcp_udp { /* IPv4 TCP and UDP socket + * information */ + INODETYPE inode; + unsigned long faddr, laddr; /* foreign & local IPv6 addresses */ + int fport, lport; /* foreign & local ports */ + unsigned long txq, rxq; /* transmit & receive queue values */ + int proto; /* 0 = TCP, 1 = UDP, 2 = UDPLITE */ + int state; /* protocol state */ + struct tcp_udp *next; +}; + +#if defined(HASIPv6) +struct tcp_udp6 { /* IPv6 TCP and UDP socket + * information */ + INODETYPE inode; + struct in6_addr faddr, laddr; /* foreign and local IPv6 addresses */ + int fport, lport; /* foreign & local ports */ + unsigned long txq, rxq; /* transmit & receive queue values */ + int proto; /* 0 = TCP, 1 = UDP, 2 = UDPLITE */ + int state; /* protocol state */ + struct tcp_udp6 *next; +}; +#endif /* defined(HASIPv6) */ + +struct uxsin { /* UNIX socket information */ + INODETYPE inode; + char *pcb; + char *path; + unsigned char sb_def; + dev_t sb_dev; + INODETYPE sb_ino; + dev_t sb_rdev; + struct uxsin *next; +}; + + +/* + * Local static values + */ + +static char *AX25path = (char *)NULL; /* path to AX25 /proc information */ +static struct ax25sin **AX25sin = (struct ax25sin **)NULL; + /* AX25 socket info, hashed by inode */ +static char *ax25st[] = { + "LISTENING", /* 0 */ + "SABM SENT", /* 1 */ + "DISC SENT", /* 2 */ + "ESTABLISHED", /* 3 */ + "RECOVERY" /* 4 */ +}; +#define NAX25ST (sizeof(ax25st) / sizeof(char *)) +static char *Ipxpath = (char *)NULL; /* path to IPX /proc information */ +static struct ipxsin **Ipxsin = (struct ipxsin **)NULL; + /* IPX socket info, hashed by inode */ +static struct packin **Packin = (struct packin **)NULL; + /* packet info, hashed by inode */ +static char *Packpath = (char *)NULL; /* path to packer /proc information */ +struct packpr { /* packet protocol conversions */ + int pr; /* protocol number */ + char *nm; /* protocol name */ +} static Packpr[] = { + +#if defined(ETH_P_LOOP) + { ETH_P_LOOP, "LOOP" }, +#endif /* defined(ETH_P_LOOP) */ + +#if defined(ETH_P_PUP) + { ETH_P_PUP, "PUP" }, +#endif /* defined(ETH_P_PUP) */ + +#if defined(ETH_P_PUPAT) + { ETH_P_PUPAT, "PUPAT" }, +#endif /* defined(ETH_P_PUPAT) */ + +#if defined(ETH_P_IP) + { ETH_P_IP, "IP" }, +#endif /* defined(ETH_P_IP) */ + +#if defined(ETH_P_X25) + { ETH_P_X25, "X25" }, +#endif /* defined(ETH_P_X25) */ + +#if defined(ETH_P_ARP) + { ETH_P_ARP, "ARP" }, +#endif /* defined(ETH_P_ARP) */ + +#if defined(ETH_P_BPQ) + { ETH_P_BPQ, "BPQ" }, +#endif /* defined(ETH_P_BPQ) */ + +#if defined(ETH_P_IEEEPUP) + { ETH_P_IEEEPUP, "I3EPUP" }, +#endif /* defined(ETH_P_IEEEPUP) */ + +#if defined(ETH_P_IEEEPUPAT) + { ETH_P_IEEEPUPAT, "I3EPUPA" }, +#endif /* defined(ETH_P_IEEEPUPAT) */ + +#if defined(ETH_P_DEC) + { ETH_P_DEC, "DEC" }, +#endif /* defined(ETH_P_DEC) */ + +#if defined(ETH_P_DNA_DL) + { ETH_P_DNA_DL, "DNA_DL" }, +#endif /* defined(ETH_P_DNA_DL) */ + +#if defined(ETH_P_DNA_RC) + { ETH_P_DNA_RC, "DNA_RC" }, +#endif /* defined(ETH_P_DNA_RC) */ + +#if defined(ETH_P_DNA_RT) + { ETH_P_DNA_RT, "DNA_RT" }, +#endif /* defined(ETH_P_DNA_RT) */ + +#if defined(ETH_P_LAT) + { ETH_P_LAT, "LAT" }, +#endif /* defined(ETH_P_LAT) */ + +#if defined(ETH_P_DIAG) + { ETH_P_DIAG, "DIAG" }, +#endif /* defined(ETH_P_DIAG) */ + +#if defined(ETH_P_CUST) + { ETH_P_CUST, "CUST" }, +#endif /* defined(ETH_P_CUST) */ + +#if defined(ETH_P_SCA) + { ETH_P_SCA, "SCA" }, +#endif /* defined(ETH_P_SCA) */ + +#if defined(ETH_P_RARP) + { ETH_P_RARP, "RARP" }, +#endif /* defined(ETH_P_RARP) */ + +#if defined(ETH_P_ATALK) + { ETH_P_ATALK, "ATALK" }, +#endif /* defined(ETH_P_ATALK) */ + +#if defined(ETH_P_AARP) + { ETH_P_AARP, "AARP" }, +#endif /* defined(ETH_P_AARP) */ + +#if defined(ETH_P_8021Q) + { ETH_P_8021Q, "8021Q" }, +#endif /* defined(ETH_P_8021Q) */ + +#if defined(ETH_P_IPX) + { ETH_P_IPX, "IPX" }, +#endif /* defined(ETH_P_IPX) */ + +#if defined(ETH_P_IPV6) + { ETH_P_IPV6, "IPV6" }, +#endif /* defined(ETH_P_IPV6) */ + +#if defined(ETH_P_SLOW) + { ETH_P_SLOW, "SLOW" }, +#endif /* defined(ETH_P_SLOW) */ + +#if defined(ETH_P_WCCP) + { ETH_P_WCCP, "WCCP" }, +#endif /* defined(ETH_P_WCCP) */ + +#if defined(ETH_P_PPP_DISC) + { ETH_P_PPP_DISC, "PPP_DIS" }, +#endif /* defined(ETH_P_PPP_DISC) */ + +#if defined(ETH_P_PPP_SES) + { ETH_P_PPP_SES, "PPP_SES" }, +#endif /* defined(ETH_P_PPP_SES) */ + +#if defined(ETH_P_MPLS_UC) + { ETH_P_MPLS_UC, "MPLS_UC" }, +#endif /* defined(ETH_P_MPLS_UC) */ + +#if defined(ETH_P_MPLS_MC) + { ETH_P_MPLS_MC, "MPLS_MC" }, +#endif /* defined(ETH_P_MPLS_MC) */ + +#if defined(ETH_P_ATMMPOA) + { ETH_P_ATMMPOA, "ATMMPOA" }, +#endif /* defined(ETH_P_ATMMPOA) */ + +#if defined(ETH_P_MPLS_MC) + { ETH_P_MPLS_MC, "MPLS_MC" }, +#endif /* defined(ETH_P_MPLS_MC) */ + +#if defined(ETH_P_ATMFATE) + { ETH_P_ATMFATE, "ATMFATE" }, +#endif /* defined(ETH_P_ATMFATE) */ + +#if defined(ETH_P_AOE) + { ETH_P_AOE, "AOE" }, +#endif /* defined(ETH_P_AOE) */ + +#if defined(ETH_P_TIPC) + { ETH_P_TIPC, "TIPC" }, +#endif /* defined(ETH_P_TIPC) */ + +#if defined(ETH_P_802_3) + { ETH_P_802_3, "802.3" }, +#endif /* defined(ETH_P_802_3) */ + +#if defined(ETH_P_AX25) + { ETH_P_AX25, "AX25" }, +#endif /* defined(ETH_P_AX25) */ + +#if defined(ETH_P_ALL) + { ETH_P_ALL, "ALL" }, +#endif /* defined(ETH_P_ALL) */ + +#if defined(ETH_P_802_2) + { ETH_P_802_2, "802.2" }, +#endif /* defined(ETH_P_802_2) */ + +#if defined(ETH_P_SNAP) + { ETH_P_SNAP, "SNAP" }, +#endif /* defined(ETH_P_SNAP) */ + +#if defined(ETH_P_DDCMP) + { ETH_P_DDCMP, "DDCMP" }, +#endif /* defined(ETH_P_DDCMP) */ + +#if defined(ETH_P_WAN_PPP) + { ETH_P_WAN_PPP, "WAN_PPP" }, +#endif /* defined(ETH_P_WAN_PPP) */ + +#if defined(ETH_P_PPP_MP) + { ETH_P_PPP_MP, "PPP MP" }, +#endif /* defined(ETH_P_PPP_MP) */ + +#if defined(ETH_P_LOCALTALK) + { ETH_P_LOCALTALK, "LCLTALK" }, +#endif /* defined(ETH_P_LOCALTALK) */ + +#if defined(ETH_P_PPPTALK) + { ETH_P_PPPTALK, "PPPTALK" }, +#endif /* defined(ETH_P_PPPTALK) */ + +#if defined(ETH_P_TR_802_2) + { ETH_P_TR_802_2, "802.2" }, +#endif /* defined(ETH_P_TR_802_2) */ + +#if defined(ETH_P_MOBITEX) + { ETH_P_MOBITEX, "MOBITEX" }, +#endif /* defined(ETH_P_MOBITEX) */ + +#if defined(ETH_P_CONTROL) + { ETH_P_CONTROL, "CONTROL" }, +#endif /* defined(ETH_P_CONTROL) */ + +#if defined(ETH_P_IRDA) + { ETH_P_IRDA, "IRDA" }, +#endif /* defined(ETH_P_IRDA) */ + +#if defined(ETH_P_ECONET) + { ETH_P_ECONET, "ECONET" }, +#endif /* defined(ETH_P_ECONET) */ + +#if defined(ETH_P_HDLC) + { ETH_P_HDLC, "HDLC" }, +#endif /* defined(ETH_P_HDLC) */ + +#if defined(ETH_P_ARCNET) + { ETH_P_ARCNET, "ARCNET" }, +#endif /* defined(ETH_P_ARCNET) */ + +}; +#define NPACKPR (sizeof(Packpr) / sizeof(struct packpr)) +struct packty { /* packet socket type conversions */ + int ty; /* type number */ + char *nm; /* type name */ +} static Packty[] = { + +#if defined(SOCK_STREAM) + { SOCK_STREAM, "STREAM" }, +#endif /* defined(SOCK_STREAM) */ + +#if defined(SOCK_DGRAM) + { SOCK_DGRAM, "DGRAM" }, +#endif /* defined(SOCK_DGRAM) */ + +#if defined(SOCK_RAW) + { SOCK_RAW, "RAW" }, +#endif /* defined(SOCK_RAW) */ + +#if defined(SOCK_RDM) + { SOCK_RDM, "RDM" }, +#endif /* defined(SOCK_RDM) */ + +#if defined(SOCK_SEQPACKET) + { SOCK_SEQPACKET, "SEQPACKET" }, +#endif /* defined(SOCK_SEQPACKET) */ + +#if defined(SOCK_PACKET) + { SOCK_PACKET, "PACKET" }, +#endif /* defined(SOCK_PACKET) */ +}; +#define NPACKTY (sizeof(Packty) / sizeof(struct packty)) +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 *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 *UDP6LITEpath = (char *)NULL; + /* path to IPv6 UDPLITE /proc + * information */ +#endif /* defined(HASIPv6) */ + +static char *UDPpath = (char *)NULL; /* path to UDP /proc information */ +static char *UDPLITEpath = (char *)NULL; + /* path to UDPLITE /proc information */ +static char *UNIXpath = (char *)NULL; /* path to UNIX /proc information */ +static struct uxsin **Uxsin = (struct uxsin **)NULL; + /* UNIX socket info, hashed by inode */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct ax25sin *check_ax25,(INODETYPE i)); +_PROTOTYPE(static struct ipxsin *check_ipx,(INODETYPE i)); +_PROTOTYPE(static struct packin *check_pack,(INODETYPE i)); +_PROTOTYPE(static struct rawsin *check_raw,(INODETYPE i)); +_PROTOTYPE(static struct tcp_udp *check_tcpudp,(INODETYPE i, char **p)); +_PROTOTYPE(static struct uxsin *check_unix,(INODETYPE i)); +_PROTOTYPE(static void get_ax25,(char *p)); +_PROTOTYPE(static void get_ipx,(char *p)); +_PROTOTYPE(static void get_pack,(char *p)); +_PROTOTYPE(static void get_raw,(char *p)); +_PROTOTYPE(static void get_tcpudp,(char *p, int pr, int clr)); +_PROTOTYPE(static void get_unix,(char *p)); +_PROTOTYPE(static void print_ax25info,(struct ax25sin *ap)); +_PROTOTYPE(static void print_ipxinfo,(struct ipxsin *ip)); + +#if defined(HASIPv6) +_PROTOTYPE(static struct rawsin *check_raw6,(INODETYPE i)); +_PROTOTYPE(static struct tcp_udp6 *check_tcpudp6,(INODETYPE i, char **p)); +_PROTOTYPE(static void get_raw6,(char *p)); +_PROTOTYPE(static void get_tcpudp6,(char *p, int pr, int clr)); +_PROTOTYPE(static int net6a2in6,(char *as, struct in6_addr *ad)); +#endif /* defined(HASIPv6) */ + + +/* + * build_IPstates() -- build the TCP and UDP state tables + */ + +void +build_IPstates() +{ + if (!TcpSt) { + (void) enter_IPstate("TCP", "ESTABLISHED", TCP_ESTABLISHED); + (void) enter_IPstate("TCP", "SYN_SENT", TCP_SYN_SENT); + (void) enter_IPstate("TCP", "SYN_RECV", TCP_SYN_RECV); + (void) enter_IPstate("TCP", "FIN_WAIT1", TCP_FIN_WAIT1); + (void) enter_IPstate("TCP", "FIN_WAIT2", TCP_FIN_WAIT2); + (void) enter_IPstate("TCP", "TIME_WAIT", TCP_TIME_WAIT); + (void) enter_IPstate("TCP", "CLOSE", TCP_CLOSE); + (void) enter_IPstate("TCP", "CLOSE_WAIT", TCP_CLOSE_WAIT); + (void) enter_IPstate("TCP", "LAST_ACK", TCP_LAST_ACK); + (void) enter_IPstate("TCP", "LISTEN", TCP_LISTEN); + (void) enter_IPstate("TCP", "CLOSING", TCP_CLOSING); + (void) enter_IPstate("TCP", "CLOSED", 0); + (void) enter_IPstate("TCP", (char *)NULL, 0); + } +} + + +/* + * check_ax25() - check for AX25 socket file + */ + +static struct ax25sin * +check_ax25(i) + INODETYPE i; /* socket file's inode number */ +{ + struct ax25sin *ap; + int h; + + h = INOHASH(i); + for (ap = AX25sin[h]; ap; ap = ap->next) { + if (i == ap->inode) + return(ap); + } + return((struct ax25sin *)NULL); +} + + +/* + * check_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_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_tcpudp() - check for IPv4 TCP or UDP socket file + */ + +static struct tcp_udp * +check_tcpudp(i, p) + INODETYPE i; /* socket file's inode number */ + char **p; /* protocol return */ +{ + int h; + struct tcp_udp *tp; + + h = TCPUDPHASH(i); + for (tp = TcpUdp[h]; tp; tp = tp->next) { + if (i == tp->inode) { + switch (tp->proto) { + case 0: + *p = "TCP"; + break; + case 1: + *p = "UDP"; + break; + case 2: + *p = "UDPLITE"; + break; + default: + *p = "unknown"; + } + return(tp); + } + } + return((struct tcp_udp *)NULL); +} + + +#if defined(HASIPv6) +/* + * check_raw6() - check for raw IPv6 socket file + */ + +static struct rawsin * +check_raw6(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct rawsin *rp; + + h = INOHASH(i); + for (rp = Rawsin6[h]; rp; rp = rp->next) { + if (i == rp->inode) + return(rp); + } + return((struct rawsin *)NULL); +} + + +/* + * check_tcpudp6() - check for IPv6 TCP or UDP socket file + */ + +static struct tcp_udp6 * +check_tcpudp6(i, p) + INODETYPE i; /* socket file's inode number */ + char **p; /* protocol return */ +{ + int h; + struct tcp_udp6 *tp6; + + h = TCPUDP6HASH(i); + for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) { + if (i == tp6->inode) { + switch (tp6->proto) { + case 0: + *p = "TCP"; + break; + case 1: + *p = "UDP"; + break; + case 2: + *p = "UDPLITE"; + break; + default: + *p = "unknown"; + } + return(tp6); + } + } + return((struct tcp_udp6 *)NULL); +} +#endif /* defined(HASIPv6) */ + + +/* + * check_unix() - check for UNIX domain socket + */ + +static struct uxsin * +check_unix(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct uxsin *up; + + h = INOHASH(i); + for (up = Uxsin[h]; up; up = up->next) { + if (i == up->inode) + return(up); + } + return((struct uxsin *)NULL); +} + + +/* + * get_ax25() - get /proc/net/ax25 info + */ + +static void +get_ax25(p) + char *p; /* /proc/net/ipx path */ +{ + struct ax25sin *ap, *np; + FILE *as; + char buf[MAXPATHLEN], *da, *dev_ch, *ep, **fp, *sa; + int h, nf; + INODETYPE inode; + unsigned long rq, sq, state; + MALLOC_S len; + unsigned char rqs, sqs; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Do second time cleanup or first time setup. + */ + if (AX25sin) { + for (h = 0; h < INOBUCKS; h++) { + for (ap = AX25sin[h]; ap; ap = np) { + np = ap->next; + if (ap->da) + (void) free((FREE_P *)ap->da); + if (ap->dev_ch) + (void) free((FREE_P *)ap->dev_ch); + if (ap->sa) + (void) free((FREE_P *)ap->sa); + (void) free((FREE_P *)ap); + } + AX25sin[h] = (struct ax25sin *)NULL; + } + } else { + AX25sin = (struct ax25sin **)calloc(INOBUCKS, + sizeof(struct ax25sin *)); + if (!AX25sin) { + (void) fprintf(stderr, + "%s: can't allocate %d AX25 hash pointer bytes\n", + Pn, 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/next/ac25 has no title line, a very poor deficiency in its + * implementation. + * + * The ax25_get_info() function in kern mnodule .../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, 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, 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, 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, sizeof(struct ax25sin)); + Exit(1); + } + ap->da = da; + ap->dev_ch = dev_ch; + ap->inode = inode; + ap->rq = rq; + ap->rqs = rqs; + ap->sa = sa; + ap->sq = sq; + ap->sqs = sqs; + ap->state = (int)state; + ap->next = AX25sin[h]; + AX25sin[h] = ap; + } + (void) fclose(as); +} + + +/* + * get_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, 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, 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, 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, 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_pack() - get /proc/net/packet info + */ + +static void +get_pack(p) + char *p; /* /proc/net/raw path */ +{ + char buf[MAXPATHLEN], *ep, **fp; + int h, lc, 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, 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; + lc = 0; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 9) + continue; + lc++; + if (lc == 1) { + + /* + * 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; + } + 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, 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, 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, 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, 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, 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, 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_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, sizeof(struct tcp_udp)); + Exit(1); + } + tp->inode = inode; + tp->faddr = faddr; + tp->fport = (int)(fport & 0xffff); + tp->laddr = laddr; + tp->lport = (int)(lport & 0xffff); + tp->txq = txq; + tp->rxq = rxq; + tp->proto = pr; + tp->state = (int)state; + tp->next = TcpUdp[h]; + TcpUdp[h] = tp; + } + (void) fclose(fs); +} + + +#if defined(HASIPv6) +/* + * get_raw6() - get /proc/net/raw6 info + */ + +static void +get_raw6(p) + char *p; /* /proc/net/raw path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp; + int h; + INODETYPE inode; + int nf = 12; + struct rawsin *np, *rp; + MALLOC_S lal, ral, spl; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + FILE *xs; +/* + * Do second time cleanup or first time setup. + */ + if (Rawsin6) { + for (h = 0; h < INOBUCKS; h++) { + for (rp = Rawsin6[h]; rp; rp = np) { + np = rp->next; + if (rp->la) + (void) free((FREE_P *)rp->la); + if (rp->ra) + (void) free((FREE_P *)rp->ra); + (void) free((FREE_P *)rp); + } + Rawsin6[h] = (struct rawsin *)NULL; + } + } else { + Rawsin6 = (struct rawsin **)calloc(INOBUCKS, + sizeof(struct rawsin *)); + if (!Rawsin6) { + (void) fprintf(stderr, + "%s: can't allocate %d raw6 hash pointer bytes\n", + Pn, 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, 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, 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, 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, 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, sizeof(struct tcp_udp6)); + Exit(1); + } + tp6->inode = inode; + tp6->faddr = faddr; + tp6->fport = (int)(fport & 0xffff); + tp6->laddr = laddr; + tp6->lport = (int)(lport & 0xffff); + tp6->txq = txq; + tp6->rxq = rxq; + tp6->proto = pr; + tp6->state = (int)state; + tp6->next = TcpUdp6[h]; + TcpUdp6[h] = tp6; + } + (void) fclose(fs); +} +#endif /* defined(HASIPv6) */ + + +/* + * get_unix() - get UNIX net info + */ + +static void +get_unix(p) + char *p; /* /proc/net/unix path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *path, *pcb; + int fl = 1; + int h, nf; + INODETYPE inode; + MALLOC_S len; + struct uxsin *np, *up; + FILE *us; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Do second time cleanup or first time setup. + */ + if (Uxsin) { + for (h = 0; h < INOBUCKS; h++) { + for (up = Uxsin[h]; up; up = np) { + np = up->next; + if (up->path) + (void) free((FREE_P *)up->path); + if (up->pcb) + (void) free((FREE_P *)up->pcb); + (void) free((FREE_P *)up); + } + Uxsin[h] = (struct uxsin *)NULL; + } + } else { + Uxsin = (struct uxsin **)calloc(INOBUCKS, sizeof(struct uxsin *)); + if (!Uxsin) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for Unix socket info\n", + Pn, INOBUCKS * sizeof(struct uxsin *)); + } + } +/* + * Open the /proc/net/unix file, assign a page size buffer to the stream, + * read the file's contents, and add them to the Uxsin hash buckets. + */ + if (!(us = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, us)) { + if ((nf = get_fields(buf, ":", &fp, (int *)NULL, 0)) < 7) + continue; + if (fl) { + + /* + * Check the first line for header words. + */ + if (!fp[0] || strcmp(fp[0], "Num") + || !fp[1] || strcmp(fp[1], "RefCount") + || !fp[2] || strcmp(fp[2], "Protocol") + || !fp[3] || strcmp(fp[3], "Flags") + || !fp[4] || strcmp(fp[4], "Type") + || !fp[5] || strcmp(fp[5], "St") + || !fp[6] || strcmp(fp[6], "Inode") + || nf < 8 + || !fp[7] || strcmp(fp[7], "Path")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + fl = 0; + continue; + } + /* + * Assemble PCB address, inode number, and path name. If this + * inode is already represented in Uxsin, skip it. + */ + ep = (char *)NULL; + if (!fp[6] || !*fp[6] + || (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + h = INOHASH(inode); + for (up = Uxsin[h]; up; up = up->next) { + if (inode == up->inode) + break; + } + if (up) + continue; + if (!fp[0] || !*fp[0]) + pcb = (char *)NULL; + else { + len = strlen(fp[0]) + 2; + if (!(pcb = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for UNIX PCB: %s\n", + Pn, len + 1, fp[0]); + Exit(1); + } + (void) snpf(pcb, len + 1, "0x%s", fp[0]); + } + if (nf >= 8 + && fp[7] && *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, len + 1, fp[7]); + Exit(1); + } + (void) snpf(path, len + 1, "%s", fp[7]); + } else + path = (char *)NULL; + /* + * Allocate and fill a Unix socket info structure; link it to its + * hash bucket. + */ + if (!(up = (struct uxsin *)malloc(sizeof(struct uxsin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for uxsin struct\n", + Pn, sizeof(struct uxsin)); + Exit(1); + } + up->inode = inode; + up->pcb = pcb; + up->sb_def = 0; + if ((up->path = path) && (*path == '/')) { + + /* + * If an absolute path (i.e., one that begins with a '/') exists + * for the line, attempt to stat(2) it and save the device and + * node numbers reported in the stat buffer. + */ + struct stat sb; + int sr; + + if (HasNFS) + sr = statsafely(path, &sb); + else + sr = stat(path, &sb); + if (sr && ((sb.st_mode & S_IFMT) == S_IFSOCK)) { + up->sb_def = 1; + up->sb_dev = sb.st_dev; + up->sb_ino = (INODETYPE)sb.st_ino; + up->sb_rdev = sb.st_rdev; + } + } + up->next = Uxsin[h]; + Uxsin[h] = up; + } + (void) fclose(us); +} + + +#if defined(HASIPv6) +/* + * net6a2in6() - convert ASCII IPv6 address in /proc/net/{tcp,udp} form to + * an in6_addr + */ + +static int +net6a2in6(as, ad) + char *as; /* address source */ + struct in6_addr *ad; /* address destination */ +{ + char buf[9], *ep; + int i; + size_t len; +/* + * Assemble four uint32_t's from 4 X 8 hex digits into s6_addr32[]. + */ + for (i = 0, len = strlen(as); + (i < 4) && (len >= 8); + as += 8, i++, len -= 8) + { + (void) strncpy(buf, as, 8); + buf[8] = '\0'; + ep = (char *)NULL; + if ((ad->s6_addr32[i] = (uint32_t)strtoul(buf, &ep, 16)) + == (uint32_t)UINT32_MAX || !ep || *ep) + break; + } + return((*as || (i != 4) || len) ? 1 : 0); +} +#endif /* defined(HASIPv6) */ + + +/* + * 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, 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, 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, s, ss, l, lss) + char *p; /* node's readlink() path */ + 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, dev_ch[32], *path; + unsigned char *fa, *la; + struct in_addr fs, ls; + struct ipxsin *ip; + int i, len, nl; + struct packin *pp; + char *pr; + struct rawsin *rp; + struct tcp_udp *tp; + struct uxsin *up; + +#if defined(HASIPv6) + int af; + struct tcp_udp6 *tp6; +#endif /* defined(HASIPv6) */ + +/* + * Enter offset, if possible. + */ + if (Foffset || !Fsize) { + if (l && (lss & SB_SIZE) && OffType) { + Lf->off = (SZOFFTYPE)l->st_size; + Lf->off_def = 1; + } + } +/* + * Check for socket's inode presence in the protocol info caches. + */ + if (AX25path) { + (void) get_ax25(AX25path); + (void) free((FREE_P *)AX25path); + AX25path = (char *)NULL; + } + if ((ss & SB_INO) + && (ap = check_ax25((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to an AX25 /proc record. + * + * Set the type to "ax25"; save the device name; save the inode number; + * save the destination and source addresses; save the send and receive + * queue sizes; and save the connection state. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "ax25"); + if (ap->dev_ch) + (void) enter_dev_ch(ap->dev_ch); + Lf->inode = ap->inode; + Lf->inp_ty = 1; + print_ax25info(ap); + return; + } + if (Ipxpath) { + (void) get_ipx(Ipxpath); + (void) free((FREE_P *)Ipxpath); + Ipxpath = (char *)NULL; + } + if ((ss & SB_INO) + && (ip = check_ipx((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to an IPX /proc record. + * + * Set the type to "ipx"; enter the inode and device numbers; store + * the addresses, queue sizes, and state in the NAME column. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "ipx"); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + if (ss & SB_DEV) { + Lf->dev = s->st_dev; + Lf->dev_def = 1; + } + cp = Namech; + nl = Namechl; + *cp = '\0'; + if (ip->la && nl) { + + /* + * Store the local IPX address. + */ + len = strlen(ip->la); + if (len > nl) + len = nl; + (void) strncpy(cp, ip->la, len); + cp += len; + *cp = '\0'; + nl -= len; + } + if (ip->ra && nl) { + + /* + * Store the remote IPX address, prefixed with "->". + */ + if (nl > 2) { + (void) snpf(cp, nl, "->"); + cp += 2; + nl -= 2; + } + if (nl) { + (void) snpf(cp, nl, "%s", ip->ra); + cp += len; + nl -= len; + } + } + (void) print_ipxinfo(ip); + if (Namech[0]) + enter_nm(Namech); + return; + } + if (Rawpath) { + (void) get_raw(Rawpath); + (void) free((FREE_P *)Rawpath); + Rawpath = (char *)NULL; + } + if ((ss & SB_INO) + && (rp = check_raw((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to a raw /proc record. + * + * Set the type to "raw"; enter the inode number; store the local + * address, remote address, and state in the NAME column. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "raw"); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + cp = Namech; + nl = Namechl - 2; + *cp = '\0'; + if (rp->la && rp->lal) { + + /* + * Store the local raw address. + */ + if (nl > rp->lal) { + (void) snpf(cp, nl, "%s", rp->la); + cp += rp->lal; + *cp = '\0'; + nl -= rp->lal; + } + } + if (rp->ra && rp->ral) { + + /* + * Store the remote raw address, prefixed with "->". + */ + if (nl > (rp->ral + 2)) { + (void) snpf(cp, nl, "->%s", rp->ra); + cp += (rp->ral + 2); + 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 (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"); + for (i = 0; i < NPACKTY; i++) { + if (Packty[i].ty == pp->ty) { + (void) snpf(Namech, Namechl, "type=SOCK_%s", + Packty[i].nm); + break; + } + } + for (i = 0; i < NPACKPR; i++) { + if (Packpr[i].pr == pp->pr) + break; + } + cp = (i < NPACKPR) ? Packpr[i].nm : "unknown"; + (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, cp); + Lf->inp_ty = 2; + if (ss & SB_INO) { + (void) snpf(dev_ch, sizeof(dev_ch), InodeFmt_d, + (INODETYPE)s->st_ino); + enter_dev_ch(dev_ch); + } + if (Namech[0]) + enter_nm(Namech); + return; + } + if (UNIXpath) { + (void) get_unix(UNIXpath); + (void) free((FREE_P *)UNIXpath); + UNIXpath = (char *)NULL; + } + if ((ss & SB_INO) + && (up = check_unix((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to a UNIX /proc record. + * + * Set the type to "unix"; enter the PCB address in the DEVICE column; + * enter the inode number; and save the optional path. + */ + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + if (up->pcb) + enter_dev_ch(up->pcb); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + path = up->path ? up->path : p; + (void) enter_nm(path); + if (Sfile) { + + /* + * See if this UNIX domain socket was specified as a search + * argument. + * + * Search first by device and node numbers, if that is possible; + * then search by name. + */ + unsigned char f = 0; /* file-found flag */ + + if (up->sb_def) { + + /* + * If the UNIX socket information includes stat(2) results, do + * a device and node number search. + * + * Note: that requires the saving, temporary modification and + * restoration of some *Lf values. + */ + unsigned char sv_dev_def; /* saved dev_def */ + unsigned char sv_inp_ty; /* saved inp_ty */ + unsigned char sv_rdev_def; /* saved rdev_def */ + dev_t sv_dev; /* saved dev */ + INODETYPE sv_inode; /* saved inode */ + dev_t sv_rdev; /* saved rdev */ + + sv_dev_def = Lf->dev_def; + sv_dev = Lf->dev; + sv_inode = Lf->inode; + sv_inp_ty = Lf->inp_ty; + sv_rdev_def = Lf->rdev_def; + sv_rdev = Lf->rdev; + Lf->dev_def = Lf->inp_ty = Lf->rdev_def = 1; + Lf->dev = up->sb_dev; + Lf->inode = up->sb_ino; + Lf->rdev = up->sb_rdev; + if (is_file_named((char *)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(path, + ((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 (UDP6LITEpath) { + if (!Fxopt) + (void) get_tcpudp6(UDP6LITEpath, 2, 0); + (void) free((FREE_P *)UDP6LITEpath); + UDP6LITEpath = (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(dev_ch, sizeof(dev_ch), InodeFmt_d, + (INODETYPE)s->st_ino); + enter_dev_ch(dev_ch); + } + 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(dev_ch, sizeof(dev_ch), InodeFmt_d, + (INODETYPE)s->st_ino); + enter_dev_ch(dev_ch); + } + 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; + } +/* + * 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; + } + enter_nm(Fxopt ? "can't identify protocol (-X specified)" + : "can't identify protocol"); +} + + +/* + * set_net_paths() - set /proc/net paths + */ + +void +set_net_paths(p, pl) + char *p; /* path to /proc/net/ */ + int pl; /* strlen(p) */ +{ + int pathl; + + pathl = 0; + (void) make_proc_path(p, pl, &AX25path, &pathl, "ax25"); + pathl = 0; + (void) make_proc_path(p, pl, &Ipxpath, &pathl, "ipx"); + pathl = 0; + (void) make_proc_path(p, pl, &Packpath, &pathl, "packet"); + pathl = 0; + (void) make_proc_path(p, pl, &Rawpath, &pathl, "raw"); + 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, &UDP6LITEpath, &pathl, "udp6lite"); +#endif /* defined(HASIPv6) */ + + pathl = 0; + (void) make_proc_path(p, pl, &UNIXpath, &pathl, "unix"); +} diff --git a/dialects/linux/dstore.c b/dialects/linux/dstore.c new file mode 100644 index 0000000..730b3b3 --- /dev/null +++ b/dialects/linux/dstore.c @@ -0,0 +1,107 @@ +/* + * 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.3 2008/04/15 13:32:26 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) + { (long)O_LARGEFILE, 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..f3cb150 --- /dev/null +++ b/dialects/linux/machine.h @@ -0,0 +1,630 @@ +/* + * 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.33 2008/10/21 16:17:21 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 */ + + +/* + * HASFSINO is defined for those dialects that have the file system + * inode element, fs_ino, in the lfile structure definition in lsof.h. + */ + +/* #define HASFSINO 1 */ + + +/* + * HASFSTRUCT is defined if the dialect has a file structure. + * + * FSV_DEFAULT defines the default set of file structure values to list. + * It defaults to zero (0), but may be made up of a combination of the + * FSV_* symbols from lsof.h. + * + * HASNOFSADDR -- has no file structure address + * HASNOFSFLAGS -- has no file structure flags + * HASNOFSCOUNT -- has no file structure count + * HASNOFSNADDR -- has no file structure node address + */ + +#define HASFSTRUCT 1 +/* #define FSV_DEFAULT FSV_? | FSV_? | FSV_? */ +#define HASNOFSADDR 1 /* has no file structure address */ +/* #define HASNOFSFLAGS 1 has no file structure flags */ +#define HASNOFSCOUNT 1 /* has no file structure count */ +#define HASNOFSNADDR 1 /* has no file structure node address */ + + +/* + * HASGNODE is defined for those dialects that have gnodes. + */ + +/* #define HASGNODE 1 */ + + +/* + * HASHSNODE is defined for those dialects that have High Sierra nodes. + */ + +/* #define HASHSNODE 1 */ + + +/* + * HASINODE is defined for those dialects that have inodes and wish to + * use readinode() from node.c. + */ + +/* #define HASINODE 1 */ + + +/* + * HASINTSIGNAL is defined for those dialects whose signal function returns + * an int. + */ + +/* #define HASINTSIGNAL 1 */ + + +/* + * HASKERNIDCK is defined for those dialects that support the comparison of + * the build to running kernel identity. + */ + +/* #define HASKERNIDCK 1 */ + + +/* + * HASKOPT is defined for those dialects that support the -k option of + * reading the kernel's name list from an optional file. + */ + +/* #define HASKOPT 1 */ + + +/* + * HASLFILEADD is defined for those dialects that need additional elements + * in struct lfile. The HASLFILEADD definition is a macro that defines + * them. If any of the additional elements need to be preset in the + * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined + * to do that. + * + * If any additional elements need to be cleared in alloc_lfile() or in the + * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to + * do that. Note that CLRLFILEADD takes one argument, the pointer to the + * lfile struct. The CLRLFILEADD macro is expected to expand to statements + * that are complete -- i.e., have terminating semi-colons -- so the macro is + * called without a terminating semicolon by proc.c. + * + * The HASXOPT definition may be used to select the conditions under which + * private lfile elements are used. + */ + +/* #define HASLFILEADD int ... */ +/* #define CLRLFILEADD(lf) (lf)->... = (type)NULL; */ +/* #define SETLFILEADD Lf->... */ + + +/* + * HASLWP is defined for dialects that have LWP support inside processes. + */ + +#define HASLWP 1 + + +/* + * HASMNTSTAT indicates the dialect supports the mount stat(2) result option + * in its l_vfs and mounts structures. + */ + +/* #define HASMNTSTAT 1 */ + + +/* + * HASMNTSUP is defined for those dialects that support the mount supplement + * option. + */ + +#define HASMNTSUP 1 + + +/* + * HASMOPT is defined for those dialects that support the reading of + * kernel memory from an alternate file. + */ + +/* #define HASMOPT 1 */ + + +/* + * HASNCACHE is defined for those dialects that have a kernel name cache + * that lsof can search. A value of 1 directs printname() to prefix the + * cache value with the file system directory name; 2, avoid the prefix. + * + * NCACHELDPFX is a set of C commands to execute before calling ncache_load(). + * + * NCACHELDSFX is a set of C commands to execute after calling ncache_load(). + */ + +/* #define HASNCACHE 1 */ +/* #define NCACHELDPFX ??? */ +/* #define NCACHELDSFX ??? */ + + +/* + * HASNLIST is defined for those dialects that use nlist() to acccess + * kernel symbols. + */ + +/* #define HASNLIST 1 */ + + +/* + * HASPIPEFN is defined for those dialects that have a special function to + * process DTYPE_PIPE file structure entries. Its value is the name of the + * function. + * + * NOTE: don't forget to define a prototype for this function in dproto.h. + */ + +/* #define HASPIPEFN process_pipe? */ + + +/* + * HASPIPENODE is defined for those dialects that have pipe nodes. + */ + +/* #define HASPIPENODE 1 */ + + +/* + * HASPMAPENABLED is defined when the reporting of portmapper registration + * info is enabled by default. + */ + +/* #define HASPMAPENABLED 1 */ + + +/* + * HASPPID is defined for those dialects that support identification of + * the parent process IDentifier (PPID) of a process. + */ + +#define HASPPID 1 + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +/* #define HASPRINTDEV print_dev? */ +/* #define HASPRINTINO print_ino? */ +/* #define HASPRINTNM print_nm? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 */ + + +/* + * 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..876758a --- /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 $"; +# 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..2f8d841 --- /dev/null +++ b/lib/prfp.c @@ -0,0 +1,212 @@ +/* + * 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.14 2008/10/21 16:12:36 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_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 (f.f_type || f.f_ops) { + (void) snpf(Namech, Namechl, + "%s file struct, ty=%#x, 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.8 b/lsof.8 new file mode 100644 index 0000000..609b24e --- /dev/null +++ b/lsof.8 @@ -0,0 +1,4307 @@ +.ds VN 4.82 +.TH LSOF 8 Revision-\*(VN +.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" +] [ +.B +|\-f [cfgGn] +] [ +.BI \-F " [f]" +] [ +.BI \-g " [s]" +] [ +.BI \-i " [i]" +] [ +.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 + AIX 5.3 + Apple Darwin 9 (Mac OS X 10.5) + FreeBSD 4.9 for x86-based systems + FreeBSD 7.[012] and 8.0 for AMD64-based systems + Linux 2.1.72 and above for x86-based systems + Solaris 9 and 10 +.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 +This option causes list selection options to be ANDed, as described +above. +.TP \w'names'u+4 +.BI \-A " A" +This option 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 +This option 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" +This option 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" +This option 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 +This option 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" +This option causes +.I lsof +to search for all open instances of directory +.I s +and the files and directories it contains at its top level. +This option 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" +This option 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" +This option 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" +This option 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 +.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" +This option 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]" +This option 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]" +This option 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 +[\fI46\fP][\fIprotocol\fP][@\fIhostname\fP\||\|\fIhostaddr\fP][:\fIservice\fP\||\|\fIport\fP] +.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" +This option specifies a kernel name list file, +.IR k , +in place of /vmunix, /mach, etc. +This option is not available under AIX on the IBM RISC/System 6000. +.TP \w'names'u+4 +.B \-l +This option 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]" +This option 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" +This option 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. +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. +.IP +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. +.TP \w'names'u+4 +.B \-n +This option 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 +This option selects the listing of NFS files. +.TP \w'names'u+4 +.BI \-o +This option 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" +This option 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. +This option 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 +This option 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" +This option 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 +This option 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]]" +This option 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 +This option 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 +When 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 +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]" +This option 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]" +This option 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 +This option 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). +This option selects the +.B \-w +option. +.TP \w'names'u+4 +.BI \-u " s" +This option 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 +This option selects the listing of UNIX domain socket files. +.TP \w'names'u+4 +.B \-v +This option 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 +This option 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 +.B \-x " [fl]" +This option 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. +This option 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 +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 ``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. +.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, 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 + F file structure address (0x) + G file flaGs (0x; names if \fB+fg\fP follows) + i file's inode number + k link count + l file's lock status + L process login name + m marker between repeated output + n file name, comment, Internet address + N node identifier (ox + o file's offset (decimal) + p process ID (always selected) + g process group ID + 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 [67].x for x86-based systems + FreeBSD 5.x and [67].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] 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/lsof.h b/lsof.h new file mode 100644 index 0000000..48b373e --- /dev/null +++ b/lsof.h @@ -0,0 +1,955 @@ +/* + * 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.62 2009/03/25 19:20:38 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) */ +}; + + +/* + * 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 */ +# else /* !defined(HASUTMPX) */ +static struct utmp dummy_utmp; /* to get login name length */ +# endif /* defined(HASUTMPX) */ +#define LOGINML sizeof(dummy_utmp.ut_name) + /* login name length */ +# 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_AUSX 3 /* Auspex LFS node */ +#define N_AUTO 4 /* automount node */ +#define N_BLK 5 /* block device node */ +#define N_CACHE 6 /* cached file system node */ +#define N_CDFS 7 /* CD-ROM node */ +#define N_CFS 8 /* CFS node */ +#define N_CHR 9 /* character device node */ +#define N_COM 10 /* streams common device node */ +#define N_CTFSADIR 11 /* Solaris CTFS adir node */ +#define N_CTFSBUND 12 /* Solaris CTFS bundle node */ +#define N_CTFSCDIR 13 /* Solaris CTFS cdir node */ +#define N_CTFSCTL 14 /* Solaris CTFS ctl node */ +#define N_CTFSEVT 15 /* Solaris CTFS events node */ +#define N_CTFSLATE 16 /* Solaris CTFS latest node */ +#define N_CTFSROOT 17 /* Solaris CTFS root node */ +#define N_CTFSSTAT 18 /* Solaris CTFS status node */ +#define N_CTFSSYM 19 /* Solaris CTFS symbolic node */ +#define N_CTFSTDIR 20 /* Solaris CTFS type node */ +#define N_CTFSTMPL 21 /* Solaris CTFS template node */ +#define N_DEV 22 /* DEV FS node */ +#define N_DOOR 23 /* DOOR node */ +#define N_FD 24 /* FD node */ +#define N_FIFO 25 /* FIFO node */ +#define N_HSFS 26 /* High Sierra node */ +#define N_KERN 27 /* BSD /kern node */ +#define N_LOFS 28 /* loopback node */ +#define N_MNT 29 /* mount file system device node */ +#define N_MPC 30 /* multiplexed device node */ +#define N_MVFS 31 /* multi-volume file system node (?) */ +#define N_NFS 32 /* NFS node */ +#define N_NFS4 33 /* NFS version 4 node */ +#define N_NM 34 /* named file system node */ +#define N_OBJF 35 /* objfs file system node */ +#define N_PCFS 36 /* PC file system node */ +#define N_PIPE 37 /* pipe device node */ +#define N_PORT 38 /* port node */ +#define N_PROC 39 /* /proc node */ +#define N_PSEU 49 /* pseudofs node */ +#define N_SAMFS 41 /* Solaris SAM-FS */ +#define N_SANFS 42 /* AIX SANFS */ +#define N_SHARED 43 /* Solaris sharedfs */ +#define N_SOCK 44 /* sock_vnodeops node */ +#define N_SPEC 45 /* spec_vnodeops node */ +#define N_STREAM 46 /* stream node */ +#define N_TMP 47 /* tmpfs node */ +#define N_UFS 48 /* UNIX file system node */ +#define N_VXFS 49 /* Veritas file system node */ +#define N_XFS 50 /* XFS node */ +#define N_ZFS 51 /* 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 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 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 SELALL (SELCMD|SELCNTX|SELFD|SELNA|SELNET|SELNM|SELNFS|SELPID|SELUID|SELUNX|SELZONE) +#define SELPROC (SELCMD|SELCNTX|SELPGID|SELPID|SELUID|SELZONE) + /* 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) */ + +# 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) + */ + +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) */ + +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 Fport; +extern int FportMap; +extern int Fpgid; +extern int Fppid; +extern int Fsize; +extern int Fsv; +extern int FsvByf; +extern int FsvFlagX; +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 char *InodeFmt_d; +extern char *InodeFmt_x; + +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 */ + 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]; + short 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 */ + int pid; /* process ID */ + 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 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 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 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.man b/lsof.man new file mode 100644 index 0000000..a46c24e --- /dev/null +++ b/lsof.man @@ -0,0 +1,3828 @@ + + + +Maintenance Procedures LSOF(8) + + + +NAME + lsof - list open files + +SYNOPSIS + lsof [ -?abChlnNOPRtUvVX ] [ -A A ] [ -c c ] [ +c c ] [ +|-d + d ] [ +|-D D ] [ +|-f [cfgGn] ] [ -F [f] ] [ -g [s] ] [ -i + [i] ] [ -k k ] [ +|-L [l] ] [ +|-m m ] [ +|-M ] [ -o [o] ] [ + -p s ] [ +|-r [t[m]] ] [ -s [p:s] ] [ -S [t] ] [ -T [t] + ] [ -u s ] [ +|-w ] [ -x [fl] ] [ -z [z] ] [ -Z [Z] ] [ -- ] + [names] + +DESCRIPTION + Lsof revision 4.82 lists on its standard output file infor- + mation about files opened by processes for the following + UNIX dialects: + + AIX 5.3 + Apple Darwin 9 (Mac OS X 10.5) + FreeBSD 4.9 for x86-based systems + FreeBSD 7.[012] and 8.0 for AMD64-based systems + Linux 2.1.72 and above for x86-based systems + Solaris 9 and 10 + + (See the DISTRIBUTION section of this manual page for infor- + mation on how to obtain the latest lsof revision.) + + An open file may be a regular file, a directory, a block + special file, a character special file, an executing text + reference, a library, a stream or a network file (Internet + socket, NFS file or UNIX domain socket.) A specific file or + all the files in a file system may be selected by path. + + Instead of a formatted display, lsof will produce output + that can be parsed by other programs. See the -F, option + description, and the OUTPUT FOR OTHER PROGRAMS section for + more information. + + In addition to producing a single output list, lsof will run + in repeat mode. In repeat mode it will produce output, + delay, then repeat the output operation until stopped with + an interrupt or quit signal. See the +|-r [t[m]] + option description for more information. + +OPTIONS + In the absence of any options, lsof lists all open files + belonging to all active processes. + + If any list request option is specified, other list requests + must be specifically requested - e.g., if -U is specified + for the listing of UNIX socket files, NFS files won't be + listed unless -N is also specified; or if a user list is + specified with the -u option, UNIX domain socket files, + + + +SunOS 5.9 Last change: Revision-4.82 1 + + + + + + +Maintenance Procedures LSOF(8) + + + + belonging to users not in the list, won't be listed unless + the -U option is also specified. + + Normally list options that are specifically stated are ORed + - i.e., specifying the -i option without an address and the + -ufoo option produces a listing of all network files OR + files belonging to processes owned by user ``foo''. The + exceptions are: + + 1) the `^' (negated) login name or user ID (UID), specified + with the -u option; + + 2) the `^' (negated) process ID (PID), specified with the -p + option; + + 3) the `^' (negated) process group ID (PGID), specified with + the -g option; + + 4) the `^' (negated) command, specified with the -c option; + + 5) the (`^') negated TCP or UDP protocol state names, speci- + fied with the -s [p:s] option. + + Since they represent exclusions, they are applied without + ORing or ANDing and take effect before any other selection + criteria are applied. + + The -a option may be used to AND the selections. For exam- + ple, specifying -a, -U, and -ufoo produces a listing of only + UNIX socket files that belong to processes owned by user + ``foo''. + + Caution: the -a option causes all list selection options to + be ANDed; it can't be used to cause ANDing of selected pairs + of selection options by placing it between them, even though + its placement there is acceptable. Wherever -a is placed, + it causes the ANDing of all selection options. + + 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 -i@aaa.bbb, + -i@ccc.ddd, -a, and -ufff,ggg will select the listing of + files that belong to either login ``fff'' OR ``ggg'' AND + have network connections to either host aaa.bbb OR ccc.ddd. + + Options may be grouped together following a single prefix -- + e.g., the option set ``-a -b -C'' may be stated as -abC. + However, since values are optional following +|-f, -F, -g, + -i, +|-L, -o, +|-r, -s, -S, -T, -x and -z. when you have no + values for them be careful that the following character + + + +SunOS 5.9 Last change: Revision-4.82 2 + + + + + + +Maintenance Procedures LSOF(8) + + + + isn't ambiguous. For example, -Fn might represent the -F + and -n options, or it might represent the n field identifier + character following the -F option. When ambiguity is possi- + ble, start a new option with a `-' character - e.g., ``-F + -n''. If the next option is a file name, follow the possi- + bly ambiguous option with ``--'' - e.g., ``-F -- name''. + + Either the `+' or the `-' prefix may be applied to a group + of options. Options that don't take on separate meanings + for each prefix - e.g., -i - may be grouped under either + prefix. Thus, for example, ``+M -i'' may be stated as + ``+Mi'' and the group means the same as the separate + options. Be careful of prefix grouping when one or more + options in the group does take on separate meanings under + different prefixes - e.g., +|-M; ``-iM'' is not the same + request as ``-i +M''. When in doubt, use separate options + with appropriate prefixes. + + -? -h These two equivalent options select a usage (help) + output list. Lsof displays a shortened form of + this output when it detects an error in the options + supplied to it, after it has displayed messages + explaining each error. (Escape the `?' character + as your shell requires.) + + -a This option causes list selection options to be + ANDed, as described above. + + -A A This option is available on systems configured for + AFS whose AFS kernel code is implemented via + dynamic modules. It allows the lsof user to + specify A as an alternate name list file where the + kernel addresses of the dynamic modules might be + found. See the lsof FAQ (The FAQ section gives its + location.) for more information about dynamic + modules, their symbols, and how they affect lsof. + + -b This option causes lsof to avoid kernel functions + that might block - lstat(2), readlink(2), and + stat(2). + + See the BLOCKS AND TIMEOUTS and AVOIDING KERNEL + BLOCKS sections for information on using this + option. + + -c c This option selects the listing of files for + processes executing the command that begins with + the characters of c. Multiple commands may be + specified, using multiple -c options. They are + joined in a single ORed set before participating in + AND option selection. + + + + +SunOS 5.9 Last change: Revision-4.82 3 + + + + + + +Maintenance Procedures LSOF(8) + + + + If c begins with a `^', then the following charac- + ters specify a command name whose processes are to + be ignored (excluded.) + + If c begins and ends with a slash ('/'), the char- + acters 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: + + + b the regular expression is a basic one. + i ignore the case of letters. + x the regular expression is an extended one + (default). + + See the lsof FAQ (The FAQ section gives its loca- + tion.) for more information on basic and extended + regular expressions. + + The simple command specification is tested first. + If that test fails, the command regular expression + is applied. If the simple command test succeeds, + the command regular expression test isn't made. + This may result in ``no command found for regex:'' + messages when lsof's -V option is specified. + + +c w This option defines the maximum number of initial + characters of the name, supplied by the UNIX + dialect, of the UNIX command associated with a pro- + cess to be printed in the COMMAND column. (The + lsof default is nine.) + + Note that many UNIX dialects do not supply all com- + mand name characters to lsof in the files and + structures from which lsof obtains command name. + Often dialects limit the number of characters sup- + plied in those sources. For example, Linux 2.4.27 + and Solaris 9 both limit command name length to 16 + characters. + + If w is zero ('0'), all command characters supplied + to lsof by the UNIX dialect will be printed. + + If w is less than the length of the column title, + ``COMMAND'', it will be raised to that length. + + -C This option disables the reporting of any path name + components from the kernel's name cache. See the + KERNEL NAME CACHE section for more information. + + + + +SunOS 5.9 Last change: Revision-4.82 4 + + + + + + +Maintenance Procedures LSOF(8) + + + + +d s This option causes lsof to search for all open + instances of directory s and the files and direc- + tories it contains at its top level. This option + does NOT descend the directory tree, rooted at s. + The +D D option may be used to request a + full-descent directory tree search, rooted at + directory D. + + Processing of the +d option does not follow sym- + bolic links within s unless the -x or -x l option + is also specified. Nor does it search for open + files on file system mount points on subdirectories + of s unless the -x or -x f option is also speci- + fied. + + Note: the authority of the user of this option lim- + its it to searching for files that the user has + permission to examine with the system stat(2) func- + tion. + + -d s This option 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 s - e.g., ``cwd,1,3'', + ``^6,^2''. (There should be no spaces in the set.) + + The list is an exclusion list if all entries of the + set begin with `^'. It is an inclusion list if no + entry begins with `^'. Mixed lists are not permit- + ted. + + 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 descrip- + tors 0 through 7. + + Multiple file descriptor numbers are joined in a + single ORed set before participating in AND option + selection. + + When there are exclusion and inclusion members in + the set, lsof reports them as errors and exits with + a non-zero return code. + + See the description of File Descriptor (FD) output + values in the OUTPUT section for more information + on file descriptor names. + + +D D This option causes lsof to search for all open + + + +SunOS 5.9 Last change: Revision-4.82 5 + + + + + + +Maintenance Procedures LSOF(8) + + + + instances of directory D and all the files and + directories it contains to its complete depth. + + Processing of the +D option does not follow sym- + bolic links within D unless the -x or -x l option + is also specified. Nor does it search for open + files on file system mount points on subdirectories + of D unless the -x or -x f option is also speci- + fied. + + Note: the authority of the user of this option lim- + its it to searching for files that the user has + permission to examine with the system stat(2) func- + tion. + + Further note: lsof may process this option slowly + and require a large amount of dynamic memory to do + it. This is because it must descend the entire + directory tree, rooted at D, calling stat(2) for + each file and directory, building a list of all the + files it finds, and searching that list for a match + with every open file. When directory D is large, + these steps can take a long time, so use this + option prudently. + + -D D This option directs lsof's use of the device cache + file. The use of this option is sometimes res- + tricted. See the DEVICE CACHE FILE section and the + sections that follow it for more information on + this option. + + -D must be followed by a function letter; the func- + tion letter may optionally be followed by a path + name. Lsof recognizes these function letters: + + + ? - report device cache file paths + b - build the device cache file + i - ignore the device cache file + r - read the device cache file + u - read and update the device cache file + + The b, r, and u functions, accompanied by a path + name, are sometimes restricted. When these func- + tions are restricted, they will not appear in the + description of the -D option that accompanies -h or + -? option output. See the DEVICE CACHE FILE sec- + tion and the sections that follow it for more + information on these functions and when they're + restricted. + + The ? function reports the read-only and write + + + +SunOS 5.9 Last change: Revision-4.82 6 + + + + + + +Maintenance Procedures LSOF(8) + + + + paths that lsof can use for the device cache file, + the names of any environment variables whose values + lsof will examine when forming the device cache + file path, and the format for the personal device + cache file path. (Escape the `?' character as your + shell requires.) + + When available, the b, r, and u functions may be + followed by the device cache file's path. The + standard default is .lsof_hostname in the home + directory of the real user ID that executes lsof, + but this could have been changed when lsof was con- + figured and compiled. (The output of the -h and -? + options show the current default prefix - e.g., + ``.lsof''.) The suffix, hostname, is the first + component of the host's name returned by gethost- + name(2). + + When available, the b function directs lsof to + build a new device cache file at the default or + specified path. + + The i function directs lsof to ignore the default + device cache file and obtain its information about + devices via direct calls to the kernel. + + The r function directs lsof to read the device + cache at the default or specified path, but + prevents it from creating a new device cache file + when none exists or the existing one is improperly + structured. The r function, when specified without + a path name, prevents lsof from updating an + incorrect or outdated device cache file, or creat- + ing a new one in its place. The r function is + always available when it is specified without a + path name argument; it may be restricted by the + permissions of the lsof process. + + When available, the u function directs lsof to read + the device cache file at the default or specified + path, if possible, and to rebuild it, if necessary. + This is the default device cache file function when + no -D option has been specified. + + +|-f [cfgGn] + f by itself clarifies how path name arguments are + to be interpreted. When followed by c, f, g, G, or + n in any combination it specifies that the listing + of kernel file structure information is to be + enabled (`+') or inhibited (`-'). + + Normally a path name argument is taken to be a file + + + +SunOS 5.9 Last change: Revision-4.82 7 + + + + + + +Maintenance Procedures LSOF(8) + + + + system name if it matches a mounted-on directory + name reported by mount(8), or if it represents a + block device, named in the mount output and associ- + ated with a mounted directory name. When +f is + specified, all path name arguments will be taken to + be file system names, and lsof will complain if any + are not. This can be useful, for example, when the + file system name (mounted-on device) isn't a block + device. This happens for some CD-ROM file systems. + + When -f is specified by itself, all path name argu- + ments will be taken to be simple files. Thus, for + example, the ``-f -- /'' arguments direct lsof to + search for open files with a `/' path name, not all + open files in the `/' (root) file system. + + Be careful to make sure +f and -f are properly ter- + minated 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 +f and -f as in these examples. + + + $ lsof +f -- /file/system/name + $ lsof -f -- /file/name + + The listing of information from kernel file struc- + tures, requested with the +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 f + is a plus sign (`+'), these characters request file + structure information: + + + c file structure use count (not Linux) + f file structure address (not Linux) + g file flag abbreviations (Linux 2.6.22 and up) + G file flags in hexadecimal (Linux 2.6.22 and up) + n file structure node address (not Linux) + + When the prefix is minus (`-') the same characters + disable the listing of the indicated values. + + File structure addresses, use counts, flags, and + node addresses may be used to detect more readily + identical files inherited by child processes and + identical files in use by different processes. + Lsof column output can be sorted by output columns + holding the values and listed to identify identical + file use, or lsof field output can be parsed by an + AWK or Perl post-filter script, or by a C program. + + + +SunOS 5.9 Last change: Revision-4.82 8 + + + + + + +Maintenance Procedures LSOF(8) + + + + -F f This option specifies a character list, f, that + selects the fields to be output for processing by + another program, and the character that terminates + each output field. Each field to be output is + specified with a single character in f. The field + terminator defaults to NL, but may be changed to + NUL (000). See the OUTPUT FOR OTHER PROGRAMS sec- + tion for a description of the field identification + characters and the field output process. + + When the field selection character list is empty, + all standard fields are selected (except the raw + device field, security context and zone field for + compatibility reasons) and the NL field terminator + is used. + + When the field selection character list contains + only a zero (`0'), all fields are selected (except + the raw device field for compatibility reasons) and + the NUL terminator character is used. + + Other combinations of fields and their associated + field terminator character must be set with expli- + cit entries in f, as described in the OUTPUT FOR + OTHER PROGRAMS section. + + When a field selection character identifies an item + lsof does not normally list - e.g., PPID, selected + with -R - specification of the field character - + e.g., ``-FR'' - also selects the listing of the + item. + + When the field selection character list contains + the single character `?', lsof will display a help + list of the field identification characters. + (Escape the `?' character as your shell requires.) + + -g [s] This option excludes or selects the listing of + files for the processes whose optional process + group IDentification (PGID) numbers are in the + comma-separated set s - e.g., ``123'' or + ``123,^456''. (There should be no spaces in the + set.) + + PGID numbers that begin with `^' (negation) + represent exclusions. + + 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. + + + +SunOS 5.9 Last change: Revision-4.82 9 + + + + + + +Maintenance Procedures LSOF(8) + + + + The -g option also enables the output display of + PGID numbers. When specified without a PGID set + that's all it does. + + -i [i] This option selects the listing of files any of + whose Internet address matches the address speci- + fied in i. If no address is specified, this option + selects the listing of all Internet and x.25 + (HP-UX) network files. + + If -i4 or -i6 is specified with no following + address, only files of the indicated IP version, + IPv4 or IPv6, are displayed. (An IPv6 specifica- + tion may be used only if the dialects supports + IPv6, as indicated by ``[46]'' and ``IPv[46]'' in + lsof's -h or -? output.) Sequentially specifying + -i4, followed by -i6 is the same as specifying -i, + and vice-versa. Specifying -i4, or -i6 after -i is + the same as specifying -i4 or -i6 by itself. + + Multiple addresses (up to a limit of 100) may be + specified with multiple -i options. (A port number + or service name range is counted as one address.) + They are joined in a single ORed set before parti- + cipating in AND option selection. + + An Internet address is specified in the form (Items + in square brackets are optional.): + + [46][protocol][@hostname|hostaddr][:service|port] + + where: + 46 specifies the IP version, IPv4 or IPv6 + that applies to the following address. + '6' may be be specified only if the UNIX + dialect supports IPv6. If neither '4' nor + '6' is specified, the following address + applies to all IP versions. + protocol is a protocol name - TCP, UDP + hostname is an Internet host name. Unless a + specific IP version is specified, open + network files associated with host names + of all versions will be selected. + hostaddr is a numeric Internet IPv4 address in + dot form; or an IPv6 numeric address in + colon form, enclosed in brackets, if the + UNIX dialect supports IPv6. When an IP + version is selected, only its numeric + addresses may be specified. + service is an /etc/services name - e.g., smtp - + or a list of them. + port is a port number, or a list of them. + + + +SunOS 5.9 Last change: Revision-4.82 10 + + + + + + +Maintenance Procedures LSOF(8) + + + + IPv6 options may be used only if the UNIX dialect + supports IPv6. To see if the dialect supports + IPv6, run lsof and specify the -h or -? (help) + option. If the displayed description of the -i + option contains ``[46]'' and ``IPv[46]'', IPv6 is + supported. + + IPv4 host names and addresses may not be specified + if network file selection is limited to IPv6 with + -i 6. IPv6 host names and addresses may not be + specified if network file selection is limited to + IPv4 with -i 4. When an open IPv4 network file's + address is mapped in an IPv6 address, the open + file's type will be IPv6, not IPv4, and its display + will be selected by '6', not '4'. + + At least one address component - 4, 6, protocol, + ,IR hostname , hostaddr, or service - must be sup- + plied. The `@' character, leading the host specif- + ication, is always required; as is the `:', leading + the port specification. Specify either hostname or + hostaddr. Specify either service name list or port + number list. If a service name list is specified, + the protocol may also need to be specified if the + TCP, UDP and UDPLITE port numbers for the service + name are different. Use any case - lower or upper + - for protocol. + + Service names and port numbers may be combined in a + list whose entries are separated by commas and + whose numeric range entries are separated by minus + signs. There may be no embedded spaces, and all + service names must belong to the specified proto- + col. Since service names may contain embedded + minus signs, the starting entry of a range can't be + a service name; it can be a port number, however. + + Here are some sample addresses: + + -i6 - IPv6 only + TCP:25 - TCP and port 25 + @1.2.3.4 - Internet IPv4 host address 1.2.3.4 + @[3ffe:1ebc::1]:1234 - Internet IPv6 host address + 3ffe:1ebc::1, port 1234 + UDP:who - UDP who service port + TCP@lsof.itap:513 - TCP, port 513 and host name lsof.itap + tcp@foo:1-10,smtp,99 - TCP, ports 1 through 10, + service name smtp, port 99, host name foo + tcp@bar:1-smtp - TCP, ports 1 through smtp, host bar + :time - either TCP, UDP or UDPLITE time service port + + -k k This option specifies a kernel name list file, k, + + + +SunOS 5.9 Last change: Revision-4.82 11 + + + + + + +Maintenance Procedures LSOF(8) + + + + in place of /vmunix, /mach, etc. This option is + not available under AIX on the IBM RISC/System + 6000. + + -l This option inhibits the conversion of user ID + numbers to login names. It is also useful when + login name lookup is working improperly or slowly. + + +|-L [l] This option enables (`+') or disables (`-') the + listing of file link counts, where they are avail- + able - e.g., they aren't available for sockets, or + most FIFOs and pipes. + + When +L is specified without a following number, + all link counts will be listed. When -L is speci- + fied (the default), no link counts will be listed. + + When +L is followed by a number, only files having + a link count less than that number will be listed. + (No number may follow -L.) A specification of the + form ``+L1'' will select open files that have been + unlinked. A specification of the form + ``+aL1 '' will select unlinked open + files on the specified file system. + + For other link count comparisons, use field output + (-F) and a post-processing script or program. + + +|-m m This option specifies an alternate kernel memory + file or activates mount table supplement process- + ing. + + The option form -m m specifies a kernel memory + file, m, in place of /dev/kmem or /dev/mem - e.g., + a crash dump file. + + The option form +m requests that a mount supplement + file be written to the standard output file. All + other options are silently ignored. + + There will be a line in the mount supplement file + for each mounted file system, containing the + mounted file system directory, followed by a single + space, followed by the device number in hexadecimal + "0x" format - e.g., + + + / 0x801 + + Lsof can use the mount supplement file to get dev- + ice numbers for file systems when it can't get them + via stat(2) or lstat(2). + + + +SunOS 5.9 Last change: Revision-4.82 12 + + + + + + +Maintenance Procedures LSOF(8) + + + + The option form +m m identifies m as a mount sup- + plement file. + + Note: the +m and +m m options are not available for + all supported dialects. Check the output of lsof's + -h or -? options to see if the +m and +m m options + are available. + + +|-M Enables (+) or disables (-) the reporting of port- + mapper registrations for local TCP, UDP and UDPLITE + ports. The default reporting mode is set by the + lsof builder with the HASPMAPENABLED #define in the + dialect's machine.h header file; lsof is distri- + buted with the HASPMAPENABLED #define deactivated, + so portmapper reporting is disabled by default and + must be requested with +M. Specifying lsof's -h or + -? option will report the default mode. Disabling + portmapper registration when it is already disabled + or enabling it when already enabled is acceptable. + + When portmapper registration reporting is enabled, + lsof displays the portmapper registration (if any) + for local TCP, UDP or UDPLITE ports in square + brackets 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. + + When portmapper registration reporting is enabled, + lsof may run a little more slowly or even become + blocked when access to the portmapper becomes cong- + ested or stopped. Reverse the reporting mode to + determine if portmapper registration reporting is + slowing or blocking lsof. + + For purposes of portmapper registration reporting + 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 lsof ignore some foreign ports + on machines with multiple interfaces when the + foreign Internet address is on a different inter- + face from the local one. + + See the lsof FAQ (The FAQ section gives its + + + +SunOS 5.9 Last change: Revision-4.82 13 + + + + + + +Maintenance Procedures LSOF(8) + + + + location.) for further discussion of portmapper + registration reporting issues. + + -n This option inhibits the conversion of network + numbers to host names for network files. Inhibit- + ing conversion may make lsof run faster. It is + also useful when host name lookup is not working + properly. + + -N This option selects the listing of NFS files. + + -o This option directs lsof to display file offset at + all times. It causes the SIZE/OFF output column + title to be changed to OFFSET. Note: on some UNIX + dialects lsof can't obtain accurate or consistent + file offset information from its kernel data + sources, sometimes just for particular kinds of + files (e.g., socket files.) Consult the lsof FAQ + (The FAQ section gives its location.) for more + information. + + The -o and -s options are mutually exclusive; they + can't both be specified. When neither is speci- + fied, lsof displays whatever value - size or offset + - is appropriate and available for the type of the + file. + + -o o This option defines the number of decimal digits + (o) to be printed after the ``0t'' for a file + offset before the form is switched to ``0x...''. + An o value of zero (unlimited) directs lsof to use + the ``0t'' form for all offset output. + + This option does NOT direct lsof to display offset + at all times; specify -o (without a trailing + number) to do that. This option only specifies the + number of digits after ``0t'' in either mixed size + and offset or offset-only output. Thus, for exam- + ple, to direct lsof to display offset at all times + with a decimal digit count of 10, use: + + + -o -o 10 + or + -oo10 + + The default number of digits allowed after ``0t'' + is normally 8, but may have been changed by the + lsof builder. Consult the description of the -o o + option in the output of the -h or -? option to + determine the default that is in effect. + + + + +SunOS 5.9 Last change: Revision-4.82 14 + + + + + + +Maintenance Procedures LSOF(8) + + + + -O This option directs lsof to bypass the strategy it + uses to avoid being blocked by some kernel opera- + tions - i.e., doing them in forked child processes. + See the BLOCKS AND TIMEOUTS and AVOIDING KERNEL + BLOCKS sections for more information on kernel + operations that may block lsof. + + While use of this option will reduce lsof startup + overhead, it may also cause lsof to hang when the + kernel doesn't respond to a function. Use this + option cautiously. + + -p s This option excludes or selects the listing of + files for the processes whose optional process + IDentification (PID) numbers are in the + comma-separated set s - e.g., ``123'' or + ``123,^456''. (There should be no spaces in the + set.) + + PID numbers that begin with `^' (negation) + represent exclusions. + + Multiple process ID numbers are joined in a single + ORed set before participating in AND option selec- + tion. However, PID exclusions are applied without + ORing or ANDing and take effect before other selec- + tion criteria are applied. + + -P This option inhibits the conversion of port numbers + to port names for network files. Inhibiting the + conversion may make lsof run a little faster. It + is also useful when port name lookup is not working + properly. + + +|-r [t[m]] + This option puts lsof in repeat mode. There lsof + lists open files as selected by other options, + delays t seconds (default fifteen), then repeats + the listing, delaying and listing repetitively + until stopped by a condition defined by the prefix + to the option. + + If the prefix is a `-', repeat mode is endless. + Lsof must be terminated with an interrupt or quit + signal. + + If the prefix is `+', repeat mode will end the + first cycle no open files are listed - and of + course when lsof is stopped with an interrupt or + quit signal. When repeat mode ends because no + files are listed, the process exit code will be + zero if any open files were ever listed; one, if + + + +SunOS 5.9 Last change: Revision-4.82 15 + + + + + + +Maintenance Procedures LSOF(8) + + + + none were ever listed. + + Lsof marks the end of each listing: if field out- + put is in progress (the -F, option has been speci- + fied), the default marker is `m'; otherwise the + default marker is ``========''. The marker is fol- + lowed by a NL character. + + The optional "m" argument specifies a format + for the marker line. The characters follow- + ing `m' are interpreted as a format specification + to the strftime(3) function, when both it and the + localtime(3) function are available in the + dialect's C library. Consult the strftime(3) docu- + mentation for what may appear in its format specif- + ication. Note that when field output is requested + with the -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. + + Repeat mode reduces lsof startup overhead, so it is + more efficient to use this mode than to call lsof + repetitively from a shell script, for example. + + To use repeat mode most efficiently, accompany +|-r + with specification of other lsof selection options, + so the amount of kernel memory access lsof does + will be kept to a minimum. Options that filter at + the process level - e.g., -c, -g, -p, -u - are the + most efficient selectors. + + Repeat mode is useful when coupled with field out- + put (see the -F, option description) and a + supervising awk or Perl script, or a C program. + + -R This option directs lsof to list the Parent Process + IDentification number in the PPID column. + + -s [p:s] s alone directs lsof to display file size at all + times. It causes the SIZE/OFF output column title + to be changed to SIZE. If the file does not have a + size, nothing is displayed. + + When followed by a protocol name (p), either TCP or + UDP, a colon (`:') and a comma-separated protocol + state name list, the option causes open TCP and UDP + files to be excluded if their state name(s) are in + the list (s) preceded by a `^'; or included if + their name(s) are not preceded by a `^'. + + + + +SunOS 5.9 Last change: Revision-4.82 16 + + + + + + +Maintenance Procedures LSOF(8) + + + + When an inclusion list is defined, only network + files with state names in the list will be present + in the lsof output. Thus, specifying one state + name means that only network files with that lone + state name will be listed. + + Case is unimportant in the protocol or state names, + but there may be no spaces and the colon (`:') + separating the protocol name (p) and the state name + list (s) is required. + + If only TCP and UDP files are to be listed, as con- + trolled by the specified exclusions and inclusions, + the -i option must be specified, too. If only a + single protocol's files are to be listed, add its + name as an argument to the -i option. + + For example, to list only network files with TCP + state LISTEN, use: + + + -iTCP -sTCP:LISTEN + + Or, for example, to list network files with all UDP + states except Idle, use: + + + -iUDP -sUDP:Idle + + State names vary with UNIX dialects, so it's not + possible to provide a complete list. Some common + TCP state names are: CLOSED, IDLE, BOUND, LISTEN, + ESTABLISHED, SYN_SENT, SYN_RCDV, ESTABLISHED, + CLOSE_WAIT, FIN_WAIT1, CLOSING, LAST_ACK, + FIN_WAIT_2, and TIME_WAIT. Two common UDP state + names are Unbound and Idle. + + See the lsof FAQ (The FAQ section gives its loca- + tion.) for more information on how to use protocol + state exclusion and inclusion, including examples. + + The -o (without a following decimal digit count) + and -s option (without a following protocol and + state name list) are mutually exclusive; they can't + both be specified. When neither is specified, lsof + displays whatever value - size or offset - is + appropriate and available for the type of file. + + Since some types of files don't have true sizes - + sockets, FIFOs, pipes, etc. - lsof displays for + their sizes the content amounts in their associated + kernel buffers, if possible. + + + +SunOS 5.9 Last change: Revision-4.82 17 + + + + + + +Maintenance Procedures LSOF(8) + + + + -S [t] This option specifies an optional time-out seconds + value for kernel functions - lstat(2), readlink(2), + and stat(2) - that might otherwise deadlock. The + minimum for t is two; the default, fifteen; when no + value is specified, the default is used. + + See the BLOCKS AND TIMEOUTS section for more infor- + mation. + + -T [t] This option controls the reporting of some TCP/TPI + information, also reported by netstat(1), following + the network addresses. In normal output the infor- + mation appears in parentheses, each item except TCP + or TPI state name identified by a keyword, followed + by `=', separated from others by a single space: + + + + QR= + QS= + SO= + SS= + TF= + WR= + WW= + + Not all values are reported for all UNIX dialects. + Items values (when available) are reported after + the item name and '='. + + When the field output mode is in effect (See OUTPUT + FOR OTHER PROGRAMS.) each item appears as a field + with a `T' leading character. + + -T with no following key characters disables + TCP/TPI information reporting. + + -T with following characters selects the reporting + of specific TCP/TPI information: + + + f selects reporting of socket options, + states and values, and TCP flags and + values. + q selects queue length reporting. + s selects connection state reporting. + w selects window size reporting. + + Not all selections are enabled for some UNIX + dialects. State may be selected for all dialects + and is reported by default. The -h or -? help out- + put for the -T option will show what selections may + + + +SunOS 5.9 Last change: Revision-4.82 18 + + + + + + +Maintenance Procedures LSOF(8) + + + + be used with the UNIX dialect. + + When -T is used to select information - i.e., it is + followed by one or more selection characters - the + displaying of state is disabled by default, and it + must be explicitly selected again in the characters + following -T. (In effect, then, the default is + equivalent to -Ts.) For example, if queue lengths + and state are desired, use -Tqs. + + Socket options, socket states, some socket values, + TCP flags and one TCP value may be reported (when + available in the UNIX dialect) in the form of the + names that commonly appear after SO_, so_, SS_, + TCP_ and TF_ in the dialect's header files - most + often , and + . Consult those header files + for the meaning of the flags, options, states and + values. + + ``SO='' precedes socket options and values; + ``SS='', socket states; and ``TF='', TCP flags and + values. + + If a flag or option has a value, the value will + follow an '=' and the name -- e.g., + ``SO=LINGER=5'', ``SO=QLIM=5'', ``TF=MSS=512''. + The following seven values may be reported: + + + Name + Reported Description (Common Symbol) + + KEEPALIVE keep alive time (SO_KEEPALIVE) + LINGER linger time (SO_LINGER) + MSS maximum segment size (TCP_MAXSEG) + PQLEN partial listen queue connections + QLEN established listen queue connections + QLIM established listen queue limit + RCVBUF receive buffer length (SO_RCVBUF) + SNDBUF send buffer length (SO_SNDBUF) + + Details on what socket options and values, socket + states, and TCP flags and values may be displayed + for particular UNIX 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 lsof FAQ (The FAQ sec- + tion gives its location.) + + + + +SunOS 5.9 Last change: Revision-4.82 19 + + + + + + +Maintenance Procedures LSOF(8) + + + + -t This option specifies that lsof should produce + terse output with process identifiers only and no + header - e.g., so that the output may be piped to + kill(1). This option selects the -w option. + + -u s This option selects the listing of files for the + user whose login names or user ID numbers are in + the comma-separated set s - e.g., ``abe'', or + ``548,root''. (There should be no spaces in the + set.) + + Multiple login names or user ID numbers are joined + in a single ORed set before participating in AND + option selection. + + If a login name or user ID is preceded by a `^', it + becomes a negation - i.e., files of processes owned + by the login name or user ID will never be listed. + A negated login name or user ID selection is nei- + ther 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 lsof to exclude the listing + of files belonging to root processes, specify + ``-u^root'' or ``-u^0''. + + -U This option selects the listing of UNIX domain + socket files. + + -v This option selects the listing of lsof version + information, including: revision number; when the + lsof binary was constructed; who constructed the + binary and where; the name of the compiler used to + construct the lsof binary; the version number of + the compiler when readily available; the compiler + and loader flags used to construct the lsof binary; + and system information, typically the output of + uname's -a option. + + -V This option directs lsof to indicate the items it + was asked to list and failed to find - command + names, file names, Internet addresses or files, + login names, NFS files, PIDs, PGIDs, and UIDs. + + When other options are ANDed to search options, or + compile-time options restrict the listing of some + files, lsof may not report that it failed to find a + search item when an ANDed option or compile-time + option prevents the listing of the open file con- + taining the located search item. + + For example, ``lsof -V -iTCP@foobar -a -d 999'' may + + + +SunOS 5.9 Last change: Revision-4.82 20 + + + + + + +Maintenance Procedures LSOF(8) + + + + 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 list- + ing of open files. + + +|-w Enables (+) or disables (-) the suppression of + warning messages. + + The lsof builder may choose to have warning mes- + sages disabled or enabled by default. The default + warning message state is indicated in the output of + the -h or -? option. Disabling warning messages + when they are already disabled or enabling them + when already enabled is acceptable. + + The -t option selects the -w option. + + -x [fl] This option may accompany the +d and +D options to + direct their processing to cross over symbolic + links and|or file system mount points encountered + when scanning the directory (+d) or directory tree + (+D). + + If -x is specified by itself without a following + parameter, cross-over processing of both symbolic + links and file system mount points is enabled. + Note that when -x is specified without a parameter, + the next argument must begin with '-' or '+'. + + The optional 'f' parameter enables file system + mount point cross-over processing; 'l', symbolic + link cross-over processing. + + The -x option may not be supplied without also sup- + plying a +d or +D option. + + -X This is a dialect-specific option. + + AIX: + This IBM AIX RISC/System 6000 option requests the + reporting of executed text file and shared library + references. + + WARNING: because this option uses the kernel + readx() function, its use on a busy AIX system + might cause an application process to hang so com- + pletely 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 possi- + bility it could happen. + + + +SunOS 5.9 Last change: Revision-4.82 21 + + + + + + +Maintenance Procedures LSOF(8) + + + + By default use of readx() is disabled. On AIX 5L + and above lsof may need setuid-root permission to + perform the actions this option requests. + + The lsof builder may specify that the -X option be + restricted to processes whose real UID is root. If + that has been done, the -X option will not appear + in the -h or -? help output unless the real UID of + the lsof process is root. The default lsof distri- + bution allows any UID to specify -X, so by default + it will appear in the help output. + + When AIX readx() use is disabled, lsof may not be + able to 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. + + The readx() function, used by 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 lsof, + asking the kernel to search the directory - e.g., + by using open(2) - can cause dir_search() to loop + forever, thus hanging the application process. + + Consult the lsof FAQ (The FAQ section gives its + location.) and the 00README file of the lsof dis- + tribution for a more complete description of the + Stale Segment ID bug, its APAR, and methods for + defining readx() use when compiling lsof. + + Linux: + This Linux option requests that lsof skip the + reporting of information on all open TCP, UDP and + UDPLITE IPv4 and IPv6 files. + + 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 /proc/net/tcp* and /proc/net/udp* files + would take lsof a long time, and whose reporting is + not of interest. + + Use this option with care and only when you are + sure that the information you want lsof to display + isn't associated with open TCP, UDP or UDPLITE + socket files. + + + + +SunOS 5.9 Last change: Revision-4.82 22 + + + + + + +Maintenance Procedures LSOF(8) + + + + Solaris 10 and above: + This Solaris 10 and above option requests the + reporting of cached paths for files that have been + deleted - i.e., removed with rm(1) or unlink(2). + + The cached path is followed by the string + `` (deleted)'' to indicate that the path by which + the file was opened has been deleted. + + Because intervening changes made to the path - + i.e., renames with mv(1) or rename(2) - are not + recorded in the cached path, what lsof reports is + only the path by which the file was opened, not its + possibly different final path. + + -z [z] specifies how Solaris 10 and higher zone informa- + tion is to be handled. + + Without a following argument - e.g., NO z - the + option specifies that zone names are to be listed + in the ZONE output column. + + The -z option may be followed by a zone name, z. + That causes lsof to list only open files for + processes in that zone. Multiple -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 con- + ditions specified by other options and arguments. + + -Z [Z] specifies how SELinux security contexts are to be + handled. This option and 'Z' field output charac- + ter support are inhibited when SELinux is disabled + in the running Linux kernel. See OUTPUT FOR OTHER + PROGRAMS for more information on the 'Z' field out- + put character. + + Without a following argument - e.g., NO Z - the + option specifies that security contexts are to be + listed in the SECURITY-CONTEXT output column. + + The -Z option may be followed by a wildcard secu- + rity context name, Z. That causes lsof to list + only open files for processes in that security con- + text. Multiple -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 condi- + tions specified by other options and arguments. + Note that Z can be A:B:C or *:B:C or A:B:* or *:*:C + to match against the A:B:C context. + + + + +SunOS 5.9 Last change: Revision-4.82 23 + + + + + + +Maintenance Procedures LSOF(8) + + + + -- The double minus sign option is a marker that sig- + nals 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 signi- + fied by the presence of a minus sign in the follow- + ing option and before the start of the file names. + + names These are path names of specific files to list. + Symbolic links are resolved before use. The first + name may be separated from the preceding options + with the ``--'' option. + + If a name is the mounted-on directory of a file + system or the device of the file system, lsof will + list all the files open on the file system. To be + considered a file system, the name must match a + mounted-on directory name in mount(8) output, or + match the name of a block device associated with a + mounted-on directory name. The +|-f option may be + used to force lsof to consider a name a file system + identifier (+f) or a simple file (-f). + + If name is a path to a directory that is not the + mounted-on directory name of a file system, it is + treated just as a 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 lsof look for open files inside a + directory name, use the +d s and +D D options. + + If a name is the base name of a family of multi- + plexed files - e. g, AIX's /dev/pt[cs] - lsof will + list all the associated multiplexed files on the + device that are open - e.g., /dev/pt[cs]/1, + /dev/pt[cs]/2, etc. + + If a name is a UNIX domain socket name, lsof will + usually search for it by the characters of the name + alone - exactly as it is specified and is recorded + in the kernel socket structure. (See the next + paragraph for an exception to that rule for Linux.) + Specifying a relative path - e.g., ./file - in + place of the file's absolute path - e.g., /tmp/file + - won't work because lsof must match the characters + you specify with what it finds in the kernel UNIX + domain socket structures. + + If a name is a Linux UNIX domain socket name, in + one case lsof is able to search for it by its dev- + ice and inode number, allowing name to be a + + + +SunOS 5.9 Last change: Revision-4.82 24 + + + + + + +Maintenance Procedures LSOF(8) + + + + relative path. The case requires that the absolute + path -- i.e., one beginning with a slash ('/') be + used by the process that created the socket, and + hence be stored in the /proc/net/unix file; and it + requires that lsof be able to obtain the device and + node numbers of both the absolute path in + /proc/net/unix and name via successful stat(2) sys- + tem calls. When those conditions are met, lsof + will be able to search for the UNIX domain socket + when some path to it is is specified in name. + Thus, for example, if the path is /dev/log, and an + lsof search is initiated when the working directory + is /dev, then name could be ./log. + + If a name is none of the above, lsof will list any + open files whose device and inode match that of the + specified path name. + + If you have also specified the -b option, the only + names you may safely specify are file systems for + which your mount table supplies alternate device + numbers. See the AVOIDING KERNEL BLOCKS and ALTER- + NATE DEVICE NUMBERS sections for more information. + + Multiple file names are joined in a single ORed set + before participating in AND option selection. + +AFS + Lsof supports the recognition of AFS files for these + dialects (and AFS versions): + + AIX 4.1.4 (AFS 3.4a) + HP-UX 9.0.5 (AFS 3.4a) + Linux 1.2.13 (AFS 3.3) + Solaris 2.[56] (AFS 3.4a) + + It may recognize AFS files on other versions of these + dialects, but has not been tested there. Depending on how + AFS is implemented, lsof may recognize AFS files in other + dialects, or may have difficulties recognizing AFS files in + the supported dialects. + + Lsof may have trouble identifying all aspects of AFS files + in supported dialects when AFS kernel support is implemented + via dynamic modules whose addresses do not appear in the + kernel's variable name list. In that case, lsof may have to + guess at the identity of AFS files, and might not be able to + obtain volume information from the kernel that is needed for + calculating AFS volume node numbers. When lsof can't com- + pute volume node numbers, it reports blank in the NODE + column. + + + + +SunOS 5.9 Last change: Revision-4.82 25 + + + + + + +Maintenance Procedures LSOF(8) + + + + The -A A option is available in some dialect implementations + of lsof for specifying the name list file where dynamic + module kernel addresses may be found. When this option is + available, it will be listed in the lsof help output, + presented in response to the -h or -? + + See the lsof FAQ (The FAQ section gives its location.) for + more information about dynamic modules, their symbols, and + how they affect lsof options. + + Because AFS path lookups don't seem to participate in the + kernel's name cache operations, lsof can't identify path + name components for AFS files. + +SECURITY + Lsof has three features that may cause security concerns. + First, its default compilation mode allows anyone to list + all open files with it. Second, by default it creates a + user-readable and user-writable device cache file in the + home directory of the real user ID that executes lsof. (The + list-all-open-files and device cache features may be dis- + abled when lsof is compiled.) Third, its -k and -m options + name alternate kernel name list or memory files. + + Restricting the listing of all open files is controlled by + the compile-time HASSECURITY and HASNOSOCKSECURITY options. + When HASSECURITY is defined, lsof will allow only the root + user to list all open files. The non-root user may list + only open files of processes with the same user IDentifica- + tion number as the real user ID number of the lsof process + (the one that its user logged on with). + + However, if HASSECURITY and HASNOSOCKSECURITY are both + defined, anyone may list open socket files, provided they + are selected with the -i option. + + When HASSECURITY is not defined, anyone may list all open + files. + + Help output, presented in response to the -h or -? option, + gives the status of the HASSECURITY and HASNOSOCKSECURITY + definitions. + + See the Security section of the 00README file of the lsof + distribution for information on building lsof with the + HASSECURITY and HASNOSOCKSECURITY options enabled. + + Creation and use of a user-readable and user-writable device + cache file is controlled by the compile-time HASDCACHE + option. See the DEVICE CACHE FILE section and the sections + that follow it for details on how its path is formed. For + security considerations it is important to note that in the + + + +SunOS 5.9 Last change: Revision-4.82 26 + + + + + + +Maintenance Procedures LSOF(8) + + + + default lsof distribution, if the real user ID under which + lsof is executed is root, the device cache file will be + written in root's home directory - e.g., / or /root. When + HASDCACHE is not defined, lsof does not write or attempt to + read a device cache file. + + When HASDCACHE is defined, the lsof help output, presented + in response to the -h, -D?, or -? options, will provide dev- + ice cache file handling information. When HASDCACHE is not + defined, the -h or -? output will have no -D option descrip- + tion. + + Before you decide to disable the device cache file feature - + enabling it improves the performance of lsof by reducing the + startup overhead of examining all the nodes in /dev (or + /devices) - read the discussion of it in the 00DCACHE file + of the lsof distribution and the lsof FAQ (The FAQ section + gives its location.) + + WHEN IN DOUBT, YOU CAN TEMPORARILY DISABLE THE USE OF THE + DEVICE CACHE FILE WITH THE -Di OPTION. + + When lsof user declares alternate kernel name list or memory + files with the -k and -m options, lsof checks the user's + authority to read them with access(2). This is intended to + prevent whatever special power lsof's modes might confer on + it from letting it read files not normally accessible via + the authority of the real user ID. + +OUTPUT + This section describes the information lsof lists for each + open file. See the OUTPUT FOR OTHER PROGRAMS section for + additional information on output that can be processed by + another program. + + Lsof only outputs printable (declared so by isprint(3)) 8 + bit characters. Non-printable characters are printed in one + of three forms: the C ``\[bfrnt]'' form; the control char- + acter `^' form (e.g., ``^@''); or hexadecimal leading ``\x'' + form (e.g., ``\xab''). Space is non-printable in the COM- + MAND column (``\x20'') and printable elsewhere. + + For some dialects - if HASSETLOCALE is defined in the + dialect's machine.h header file - lsof will print the + extended 8 bit characters of a language locale. The lsof + process must be supplied a language locale environment vari- + able (e.g., LANG) whose value represents a known language + locale in which the extended characters are considered + printable by isprint(3). Otherwise lsof considers the + extended characters non-printable and prints them according + to its rules for non-printable characters, stated above. + Consult your dialect's setlocale(3) man page for the names + + + +SunOS 5.9 Last change: Revision-4.82 27 + + + + + + +Maintenance Procedures LSOF(8) + + + + of other environment variables that may be used in place of + LANG - e.g., LC_ALL, LC_CTYPE, etc. + + Lsof's language locale support for a dialect also covers + wide 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 lsof pro- + cess. Wide characters are printable under those conditions + if iswprint(3) reports them to be. If HASSETLOCALE, + HASWIDECHAR and a suitable language locale aren't defined, + or if iswprint(3) reports wide characters that aren't print- + able, lsof considers the wide characters non-printable and + prints each of their 8 bits according to its rules for + non-printable characters, stated above. + + Consult the answers to the "Language locale support" ques- + tions in the lsof FAQ (The FAQ section gives its location.) + for more information. + + 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 predeces- + sor by at least one space. + + COMMAND contains the first nine characters of the name of + the UNIX command associated with the process. If + a non-zero w value is specified to the +c w + option, the column contains the first w charac- + ters of the name of the UNIX command associated + with the process up to the limit of characters + supplied to lsof by the UNIX dialect. (See the + description of the +c w command or the lsof FAQ + for more information. The FAQ section gives its + location.) + + If w is less than the length of the column title, + ``COMMAND'', it will be raised to that length. + + If a zero w value is specified to the +c w + option, the column contains all the characters of + the name of the UNIX command associated with the + process. + + All command name characters maintained by the + kernel in its structures are displayed in field + output when the command name descriptor (`c') is + specified. See the OUTPUT FOR OTHER COMMANDS + section for information on selecting field output + and the associated command name descriptor. + + PID is the Process IDentification number of the + + + +SunOS 5.9 Last change: Revision-4.82 28 + + + + + + +Maintenance Procedures LSOF(8) + + + + process. + + ZONE is the Solaris 10 and higher zone name. This + column must be selected with the -z option. + + SECURITY-CONTEXT + is the SELinux security context. This column + must be selected with the -Z option. Note that + the -Z option is inhibited when SELinux is dis- + abled in the running Linux kernel. + + PPID is the Parent Process IDentification number of + the process. It is only displayed when the -R + option has been specified. + + PGID is the process group IDentification number asso- + ciated with the process. It is only displayed + when the -g option has been specified. + + USER is the user ID number or login name of the user + to whom the process belongs, usually the same as + reported by ps(1). However, on Linux USER is the + user ID number or login that owns the directory + in /proc where lsof finds information about the + process. Usually that is the same value reported + by ps(1), but may differ when the process has + changed its effective user ID. (See the -l + option description for information on when a user + ID number or login name is displayed.) + + FD is the File Descriptor number of the file or: + + + cwd current working directory; + Lnn library references (AIX); + err FD information error (see NAME column); + jld jail directory (FreeBSD); + ltx shared library text (code and data); + Mxx hex memory-mapped type number xx. + m86 DOS Merge mapped file; + mem memory-mapped file; + mmap memory-mapped device; + pd parent directory; + rtd root directory; + tr kernel trace file (OpenBSD); + txt program text (code and data); + v86 VP/ix mapped file; + + FD is followed by one of these characters, + describing the mode under which the file is open: + + r for read access; + + + +SunOS 5.9 Last change: Revision-4.82 29 + + + + + + +Maintenance Procedures LSOF(8) + + + + w for write access; + u for read and write access; + space if mode unknown and no lock + character follows; + `-' if mode unknown and lock + character follows. + + The mode character is followed by one of these + lock characters, describing the type of lock + applied to the file: + + N for a Solaris NFS lock of unknown type; + r for read lock on part of the file; + R for a read lock on the entire file; + w for a write lock on part of the file; + W for a write lock on the entire file; + u for a read and write lock of any length; + U for a lock of unknown type; + x for an SCO OpenServer Xenix lock on part + of the file; + X for an SCO OpenServer Xenix lock on the + entire file; + space if there is no lock. + + See the LOCKS section for more information on the + lock information character. + + The FD column contents constitutes a single field + for parsing in post-processing scripts. + + TYPE is the type of the node associated with the file + - e.g., GDIR, GREG, VDIR, VREG, etc. + + or ``IPv4'' for an IPv4 socket; + + or ``IPv6'' for an open IPv6 network file - even + if its address is IPv4, mapped in an IPv6 + address; + + or ``ax25'' for a Linux AX.25 socket; + + or ``inet'' for an Internet domain socket; + + or ``lla'' for a HP-UX link level access file; + + or ``rte'' for an AF_ROUTE socket; + + or ``sock'' for a socket of unknown domain; + + or ``unix'' for a UNIX domain socket; + + or ``x.25'' for an HP-UX x.25 socket; + + + +SunOS 5.9 Last change: Revision-4.82 30 + + + + + + +Maintenance Procedures LSOF(8) + + + + or ``BLK'' for a block special file; + + or ``CHR'' for a character special file; + + or ``DEL'' for a Linux map file that has been + deleted; + + or ``DIR'' for a directory; + + or ``DOOR'' for a VDOOR file; + + or ``FIFO'' for a FIFO special file; + + or ``KQUEUE'' for a BSD style kernel event queue + file; + + or ``LINK'' for a symbolic link file; + + or ``MPB'' for a multiplexed block file; + + or ``MPC'' for a multiplexed character file; + + or ``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; + + or ``PAS'' for a /proc/as file; + + or ``PAXV'' for a /proc/auxv file; + + or ``PCRE'' for a /proc/cred file; + + or ``PCTL'' for a /proc control file; + + or ``PCUR'' for the current /proc process; + + or ``PCWD'' for a /proc current working direc- + tory; + + or ``PDIR'' for a /proc directory; + + or ``PETY'' for a /proc executable type (etype); + + or ``PFD'' for a /proc file descriptor; + + or ``PFDR'' for a /proc file descriptor direc- + tory; + + or ``PFIL'' for an executable /proc file; + + or ``PFPR'' for a /proc FP register set; + + + +SunOS 5.9 Last change: Revision-4.82 31 + + + + + + +Maintenance Procedures LSOF(8) + + + + or ``PGD'' for a /proc/pagedata file; + + or ``PGID'' for a /proc group notifier file; + + or ``PIPE'' for pipes; + + or ``PLC'' for a /proc/lwpctl file; + + or ``PLDR'' for a /proc/lpw directory; + + or ``PLDT'' for a /proc/ldt file; + + or ``PLPI'' for a /proc/lpsinfo file; + + or ``PLST'' for a /proc/lstatus file; + + or ``PLU'' for a /proc/lusage file; + + or ``PLWG'' for a /proc/gwindows file; + + or ``PLWI'' for a /proc/lwpsinfo file; + + or ``PLWS'' for a /proc/lwpstatus file; + + or ``PLWU'' for a /proc/lwpusage file; + + or ``PLWX'' for a /proc/xregs file' + + or ``PMAP'' for a /proc map file (map); + + or ``PMEM'' for a /proc memory image file; + + or ``PNTF'' for a /proc process notifier file; + + or ``POBJ'' for a /proc/object file; + + or ``PODR'' for a /proc/object directory; + + or ``POLP'' for an old format /proc light weight + process file; + + or ``POPF'' for an old format /proc PID file; + + or ``POPG'' for an old format /proc page data + file; + + or ``PORT'' for a SYSV named pipe; + + or ``PREG'' for a /proc register file; + + or ``PRMP'' for a /proc/rmap file; + + + + +SunOS 5.9 Last change: Revision-4.82 32 + + + + + + +Maintenance Procedures LSOF(8) + + + + or ``PRTD'' for a /proc root directory; + + or ``PSGA'' for a /proc/sigact file; + + or ``PSIN'' for a /proc/psinfo file; + + or ``PSTA'' for a /proc status file; + + or ``PSXSEM'' for a POSIX semaphore file; + + or ``PSXSHM'' for a POSIX shared memory file; + + or ``PUSG'' for a /proc/usage file; + + or ``PW'' for a /proc/watch file; + + or ``PXMP'' for a /proc/xmap file; + + or ``REG'' for a regular file; + + or ``SMT'' for a shared memory transport file; + + or ``STSO'' for a stream socket; + + or ``UNNM'' for an unnamed type file; + + or ``XNAM'' for an OpenServer Xenix special file + of unknown type; + + or ``XSEM'' for an OpenServer Xenix semaphore + file; + + or ``XSD'' for an OpenServer Xenix shared data + file; + + or the four type number octets if the correspond- + ing name isn't known. + + FILE-ADDR contains the kernel file structure address when f + has been specified to +f; + + FCT contains the file reference count from the kernel + file structure when c has been specified to +f; + + FILE-FLAG when g or G has been specified to +f, this field + contains the contents of the f_flag[s] member of + the kernel file structure and the kernel's + per-process open file flags (if available); `G' + causes them to be displayed in hexadecimal; `g', + as short-hand names; two lists may be displayed + with entries separated by commas, the lists + separated by a semicolon (`;'); the first list + + + +SunOS 5.9 Last change: Revision-4.82 33 + + + + + + +Maintenance Procedures LSOF(8) + + + + may contain short-hand names for f_flag[s] values + from the following table: + + + AIO asynchronous I/O (e.g., FAIO) + AP append + ASYN asynchronous I/O (e.g., FASYNC) + BAS block, test, and set in use + BKIU block if in use + BL use block offsets + BSK block seek + CA copy avoid + CIO concurrent I/O + CLON clone + CLRD CL read + CR create + DF defer + DFI defer IND + DFLU data flush + DIR direct + DLY delay + DOCL do clone + DSYN data-only integrity + DTY must be a directory + EVO event only + EX open for exec + EXCL exclusive open + FSYN synchronous writes + GCDF defer during unp_gc() (AIX) + GCMK mark during unp_gc() (AIX) + GTTY accessed via /dev/tty + HUP HUP in progress + KERN kernel + KIOC kernel-issued ioctl + LCK has lock + LG large file + MBLK stream message block + MK mark + MNT mount + MSYN multiplex synchronization + NATM don't update atime + NB non-blocking I/O + NBDR no BDRM check + NBIO SYSV non-blocking I/O + NBF n-buffering in effect + NC no cache + ND no delay + NDSY no data synchronization + NET network + NFLK don't follow links + NMFS NM file system + NOTO disable background stop + + + +SunOS 5.9 Last change: Revision-4.82 34 + + + + + + +Maintenance Procedures LSOF(8) + + + + 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 + + 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; + + the second list (after the semicolon) may contain + short-hand names for kernel per-process open file + flags from this table: + + + 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 + + + +SunOS 5.9 Last change: Revision-4.82 35 + + + + + + +Maintenance Procedures LSOF(8) + + + + RSVW reserved wait + SHMT UF_FSHMAT set (AIX) + USE in use (multi-threaded) + + 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 occasion- + ally a concatenation of device and node number) + when n has been specified to +f; + + DEVICE contains the device numbers, separated by commas, + for a character special, block special, regular, + directory or NFS file; + + or ``memory'' for a memory file system node under + Tru64 UNIX; + + or the address of the private data area of a + Solaris socket stream; + + or a kernel reference address that identifies the + file (The kernel reference address may be used + for FIFO's, for example.); + + or the base address or device name of a Linux + AX.25 socket device. + + Usually only the lower thirty two bits of Tru64 + UNIX kernel addresses are displayed. + + SIZE, SIZE/OFF, or OFFSET + is the size of the file or the file offset in + bytes. A value is displayed in this column only + if it is available. Lsof displays whatever value + - size or offset - is appropriate for the type of + the file and the version of lsof. + + On some UNIX dialects lsof can't obtain accurate + or consistent file offset information from its + kernel data sources, sometimes just for particu- + lar kinds of files (e.g., socket files.) In + other cases, files don't have true sizes - e.g., + sockets, FIFOs, pipes - so lsof displays for + their sizes the content amounts it finds in their + kernel buffer descriptors (e.g., socket buffer + size counts or TCP/IP window sizes.) Consult the + lsof FAQ (The FAQ section gives its location.) + for more information. + + The file size is displayed in decimal; the offset + is normally displayed in decimal with a leading + ``0t'' if it contains 8 digits or less; in + + + +SunOS 5.9 Last change: Revision-4.82 36 + + + + + + +Maintenance Procedures LSOF(8) + + + + hexadecimal with a leading ``0x'' if it is longer + than 8 digits. (Consult the -o o option descrip- + tion for information on when 8 might default to + some other value.) + + Thus the leading ``0t'' and ``0x'' identify an + offset when the column may contain both a size + and an offset (i.e., its title is SIZE/OFF). + + If the -o option is specified, lsof always + displays the file offset (or nothing if no offset + is available) and labels the column OFFSET. The + offset always begins with ``0t'' or ``0x'' as + described above. + + The lsof user can control the switch from ``0t'' + to ``0x'' with the -o o option. Consult its + description for more information. + + If the -s option is specified, lsof always + displays the file size (or nothing if no size is + available) and labels the column SIZE. The -o + and -s options are mutually exclusive; they can't + both be specified. + + For files that don't have a fixed size - e.g., + don't reside on a disk device - lsof will display + appropriate information about the current size or + position of the file if it is available in the + kernel structures that define the file. + + NLINK contains the file link count when +L has been + specified; + + NODE is the node number of a local file; + + or the inode number of an NFS file in the server + host; + + or the Internet protocol type - e. g, ``TCP''; + + or ``STR'' for a stream; + + or ``CCITT'' for an HP-UX x.25 socket; + + or the IRQ or inode number of a Linux AX.25 + socket device. + + NAME is the name of the mount point and file system on + which the file resides; + + or the name of a file specified in the names + + + +SunOS 5.9 Last change: Revision-4.82 37 + + + + + + +Maintenance Procedures LSOF(8) + + + + option (after any symbolic links have been + resolved); + + or the name of a character special or block spe- + cial device; + + or the local and remote Internet addresses of a + network file; the local host name or IP number is + followed by a colon (':'), the port, ``->'', and + the two-part remote address; IP addresses may be + reported as numbers or names, depending on the + +|-M, -n, and -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 destina- + tion; 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 netstat(1) + reports; see the -T option description or the + description of the TCP/TPI field in OUTPUT FOR + OTHER PROGRAMS for more information on state, + queue size, and window size; + + 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; + + or the local and remote mount point names of an + NFS file; + + or ``STR'', followed by the stream name; + + or a stream character device name, followed by + ``->'' and the stream name or a list of stream + module names, separated by ``->''; + + or ``STR:'' followed by the SCO OpenServer stream + device and module names, separated by ``->''; + + or system directory name, `` -- '', and as many + components of the path name as lsof can find in + the kernel's name cache for selected dialects + (See the KERNEL NAME CACHE section for more + information.); + + + + +SunOS 5.9 Last change: Revision-4.82 38 + + + + + + +Maintenance Procedures LSOF(8) + + + + or ``PIPE->'', followed by a Solaris kernel pipe + destination address; + + or ``COMMON:'', followed by the vnode device + information structure's device name, for a + Solaris common vnode; + + or the address family, followed by a slash (`/'), + followed by fourteen comma-separated bytes of a + non-Internet raw socket address; + + or the HP-UX x.25 local address, followed by the + virtual connection number (if any), followed by + the remote address (if any); + + or ``(dead)'' for disassociated Tru64 UNIX files + - typically terminal files that have been flagged + with the TIOCNOTTY ioctl and closed by daemons; + + or ``rd='' and ``wr='' for the + values of the read and write offsets of a FIFO; + + or ``clone n:/dev/event'' for SCO OpenServer file + clones of the /dev/event device, where n is the + minor device number of the file; + + or ``(socketpair: n)'' for a Solaris 2.6, 8, 9 + or 10 UNIX domain socket, created by the + socketpair(3N) network function; + + or ``no PCB'' for socket files that do not have a + protocol block associated with them, optionally + followed by ``, CANTSENDMORE'' if sending on the + socket has been disabled, or ``, CANTRCVMORE'' if + receiving on the socket has been disabled (e.g., + by the shutdown(2) function); + + or the local and remote addresses of a Linux IPX + socket file in the form :[:], + followed in parentheses by the transmit and + receive queue sizes, and the connection state; + + or ``dgram'' or ``stream'' for the type UnixWare + 7.1.1 and above in-kernel UNIX domain sockets, + followed by a colon (':') and the local path name + when available, followed by ``->'' and the remote + path name or kernel socket address in hexadecimal + when available. + + For dialects that support a ``namefs'' file system, allowing + one file to be attached to another with fattach(3C), lsof + will add ``(FA:)'' to the + + + +SunOS 5.9 Last change: Revision-4.82 39 + + + + + + +Maintenance Procedures LSOF(8) + + + + 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. + + Lsof may add two parenthetical notes to the NAME column for + open Solaris 10 files: ``(?)'' if lsof considers the path + name of questionable accuracy; and ``(deleted)'' if the -X + option has been specified and lsof detects the open file's + path name has been deleted. Consult the lsof FAQ (The FAQ + section gives its location.) for more information on these + NAME column additions. + +LOCKS + Lsof can't adequately report the wide variety of UNIX + dialect file locks in a single character. What it reports + in a single character is a compromise between the informa- + tion it finds in the kernel and the limitations of the + reporting format. + + Moreover, when a process holds several byte level locks on a + file, lsof only reports the status of the first lock it + encounters. If it is a byte level lock, then the lock char- + acter will be reported in lower case - i.e., `r', `w', or + `x' - rather than the upper case equivalent reported for a + full file lock. + + Generally 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. + + Lsof has trouble reporting locks for some UNIX dialects. + Consult the BUGS section of this manual page or the lsof FAQ + (The FAQ section gives its location.) for more information. + +OUTPUT FOR OTHER PROGRAMS + When the -F option is specified, lsof produces output that + is suitable for processing by another program - e.g, an awk + or Perl script, or a C program. + + Each unit of information is output in a field that is iden- + tified 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. + + + +SunOS 5.9 Last change: Revision-4.82 40 + + + + + + +Maintenance Procedures LSOF(8) + + + + 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, and + the user ID (UID) number or login name. + + 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. + + When the NUL (000) field terminator has been selected with + the 0 (zero) field identifier character, lsof ends each pro- + cess and file set with a NL (012) character. + + Lsof always produces one field, the PID (`p') field. All + other fields may be declared optionally in the field iden- + tifier character list that follows the -F option. When a + field selection character identifies an item lsof does not + normally list - e.g., PPID, selected with -R - specification + of the field character - e.g., ``-FR'' - also selects the + listing of the item. + + It is entirely possible to select a set of fields that can- + not easily be parsed - e.g., if the field descriptor field + is not selected, it may be difficult to identify file sets. + To help you avoid this difficulty, lsof supports the -F + option; it selects the output of all fields with NL termina- + tors (the -F0 option pair selects the output of all fields + with NUL terminators). For compatibility reasons neither -F + nor -F0 select the raw device field. + + These are the fields that lsof will produce. The single + character listed first is the field identifier. + + a file access mode + c process command name (all characters from proc or + user structure) + C file structure share count + d file's device character code + D file's major/minor device number (0x) + f file descriptor + F file structure address (0x) + G file flaGs (0x; names if +fg follows) + i file's inode number + k link count + l file's lock status + + + +SunOS 5.9 Last change: Revision-4.82 41 + + + + + + +Maintenance Procedures LSOF(8) + + + + L process login name + m marker between repeated output + n file name, comment, Internet address + N node identifier (ox + o file's offset (decimal) + p process ID (always selected) + g process group ID + 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 -h or -? help output for the + -T option will show what TCP/TPI reporting can be + requested.) + u process user ID + z Solaris 10 and higher zone name + Z SELinux security context (inhibited when SELinux is disabled) + 0 use NUL field terminator character in place of NL + 1-9 dialect-specific field identifiers (The output + of -F? identifies the information to be found + in dialect-specific fields.) + + You can get on-line help information on these characters and + their descriptions by specifying the -F? option pair. + (Escape the `?' character as your shell requires.) Addi- + tional information on field content can be found in the OUT- + PUT section. + + As an example, ``-F pcfn'' will select the process ID (`p'), + command name (`c'), file descriptor (`f') and file name + (`n') fields with an NL field terminator character; ``-F + pcfn0'' selects the same output with a NUL (000) field ter- + minator character. + + Lsof doesn't produce all fields for every process or file + set, only those that are available. Some fields are mutu- + ally 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 + + + +SunOS 5.9 Last change: Revision-4.82 42 + + + + + + +Maintenance Procedures LSOF(8) + + + + or the other member of these mutually exclusive sets will + appear in field output, but not both. + + Normally lsof ends each field with a NL (012) character. + The 0 (zero) field identifier character may be specified to + change the field terminator character to a NUL (000). A NUL + terminator may be easier to process with xargs (1), for + example, or with programs whose quoting mechanisms may not + easily cope with the range of characters in the field out- + put. When the NUL field terminator is in use, lsof ends + each process and file set with a NL (012). + + Three aids to producing programs that can process lsof field + output are included in the lsof distribution. The first is + a C header file, lsof_fields.h, that contains symbols for + the field identification characters, indexes for storing + them in a table, and explanation strings that may be com- + piled into programs. Lsof uses this header file. + + The second aid is a set of sample scripts that process field + output, written in awk, Perl 4, and Perl 5. They're located + in the scripts subdirectory of the lsof distribution. + + The third aid is the C library used for the lsof test suite. + The test suite is written in C and uses field output to + validate the correct operation of lsof. The library can be + found in the tests/LTlib.c file of the lsof distribution. + The library uses the first aid, the lsof_fields.h header + file. + +BLOCKS AND TIMEOUTS + Lsof can be blocked by some kernel functions that it uses - + lstat(2), readlink(2), and stat(2). These functions are + stalled in the kernel, for example, when the hosts where + mounted NFS file systems reside become inaccessible. + + Lsof attempts to break these blocks with timers and child + processes, but the techniques are not wholly reliable. When + lsof does manage to break a block, it will report the break + with an error message. The messages may be suppressed with + the -t and -w options. + + The default timeout value may be displayed with the -h or -? + option, and it may be changed with the -S [t] option. The + minimum for t is two seconds, but you should avoid small + values, since slow system responsiveness can cause short + timeouts to expire unexpectedly and perhaps stop lsof before + it can produce any output. + + When lsof has to break a block during its access of mounted + file system information, it normally continues, although + with less information available to display about open files. + + + +SunOS 5.9 Last change: Revision-4.82 43 + + + + + + +Maintenance Procedures LSOF(8) + + + + 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 -O option. While this will + allow lsof to start up with less overhead, it exposes lsof + completely to the kernel situations that might block it. + Use this option cautiously. + +AVOIDING KERNEL BLOCKS + You can use the -b option to tell lsof to avoid using kernel + functions that would block. Some cautions apply. + + First, using this option usually requires that your system + supply alternate device numbers in place of the device + numbers that lsof would normally obtain with the lstat(2) + and stat(2) kernel functions. See the ALTERNATE DEVICE + NUMBERS section for more information on alternate device + numbers. + + Second, you can't specify names for lsof to locate unless + they're file system names. This is because lsof needs to + know the device and inode numbers of files listed with names + in the lsof options, and the -b option prevents lsof from + obtaining them. Moreover, since lsof only has device + numbers for the file systems that have alternates, its abil- + ity to locate files on file systems depends completely on + the availability and accuracy of the alternates. If no + alternates are available, or if they're incorrect, lsof + won't be able to locate files on the named file systems. + + Third, if the names of your file system directories that + lsof obtains from your system's mount table are symbolic + links, lsof won't be able to resolve the links. This is + because the -b option causes lsof to avoid the kernel + readlink(2) function it uses to resolve symbolic links. + + Finally, using the -b option causes lsof to issue warning + messages when it needs to use the kernel functions that the + -b option directs it to avoid. You can suppress these mes- + sages by specifying the -w option, but if you do, you won't + see the alternate device numbers reported in the warning + messages. + +ALTERNATE DEVICE NUMBERS + On some dialects, when lsof has to break a block because it + can't get information about a mounted file system via the + lstat(2) and stat(2) kernel functions, or because you speci- + fied the -b option, 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, + lsof will report the device number it obtained. (You can + suppress the report by specifying the -w option.) + + + + +SunOS 5.9 Last change: Revision-4.82 44 + + + + + + +Maintenance Procedures LSOF(8) + + + + You can assist this process if your mount table is supported + with an /etc/mtab or /etc/mnttab file that contains an + options field by adding a ``dev=xxxx'' field for mount + points that do not have one in their 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. + + You may also be able to supply device numbers using the +m + and +m m options, provided they are supported by your + dialect. Check the output of lsof's -h or -? options to see + if the +m and +m m options are available. + + The ``xxxx'' portion of the field is the hexadecimal value + of the file system's device number. (Consult the st_dev + field of the output of the lstat(2) and stat(2) functions + for the appropriate values for your file systems.) Here's + an example from a Sun Solaris 2.6 /etc/mnttab for a file + system remotely mounted via NFS: + + nfs ignore,noquota,dev=2a40001 + + There's an advantage to having ``dev=xxxx'' entries in your + mount table file, especially for file systems that are + mounted from remote NFS servers. When a remote server + crashes and you want to identify its users by running lsof + on one of its clients, lsof probably won't be able to get + output from the lstat(2) and stat(2) functions for the file + system. If it can obtain the file system's device number + from the mount table, it will be able to display the files + open on the crashed NFS server. + + Some dialects that do not use an ASCII /etc/mtab or + /etc/mnttab file for the mount table may still provide an + alternative device number in their internal mount tables. + This includes AIX, Apple Darwin, FreeBSD, NetBSD, OpenBSD, + and Tru64 UNIX. Lsof knows how to obtain the alternative + device number for these dialects and uses it when its + attempt to lstat(2) or stat(2) the file system is blocked. + + If you're not sure your dialect supplies alternate device + numbers for file systems from its mount table, use this lsof + incantation to see if it reports any alternate device + numbers: + + lsof -b + + Look for standard error file warning messages that begin + ``assuming "dev=xxxx" from ...''. + +KERNEL NAME CACHE + + + + +SunOS 5.9 Last change: Revision-4.82 45 + + + + + + +Maintenance Procedures LSOF(8) + + + + Lsof is able to examine the kernel's name cache or use other + kernel facilities (e.g., the ADVFS 4.x tag_to_path() func- + tion 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.) + + Lsof reports the complete paths it finds in the NAME column. + If lsof can't report all components in a path, it reports in + the NAME column the file system name, followed by a space, + two `-' characters, another space, and the name components + it has located, separated by the `/' character. + + When lsof is run in repeat mode - i.e., with the -r option + specified - the extent to which it can report path name com- + ponents 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. + + Lsof's use of the kernel name cache to identify the paths of + files can lead it to report incorrect components under some + circumstances. This can happen when the kernel name cache + uses device and node number as a key (e.g., SCO OpenServer) + and a key on a rapidly changing file system is reused. If + the UNIX dialect's kernel doesn't purge the name cache entry + for a file when it is unlinked, lsof may find a reference to + the wrong entry in the cache. The lsof FAQ (The FAQ section + gives its location.) has more information on this situa- + tion. + + Lsof can report path name components for these dialects: + + FreeBSD + HP-UX + Linux + NetBSD + NEXTSTEP + OpenBSD + OPENSTEP + SCO OpenServer + SCO|Caldera UnixWare + Solaris + Tru64 UNIX + + Lsof can't report path name components for these dialects: + + AIX + + If you want to know why lsof can't report path name com- + ponents for some dialects, see the lsof FAQ (The FAQ section + + + +SunOS 5.9 Last change: Revision-4.82 46 + + + + + + +Maintenance Procedures LSOF(8) + + + + gives its location.) + +DEVICE CACHE FILE + Examining all members of the /dev (or /devices) node tree + with stat(2) functions can be time consuming. What's more, + the information that lsof needs - device number, inode + number, and path - rarely changes. + + Consequently, lsof normally maintains an ASCII text file of + cached /dev (or /devices) information (exception: the + /proc-based Linux lsof where it's not needed.) The local + system administrator who builds lsof can control the way the + device cache file path is formed, selecting from these + options: + + Path from the -D option; + Path from an environment variable; + System-wide path; + Personal path (the default); + Personal path, modified by an environment variable. + + Consult the output of the -h, -D? , or -? help options for + the current state of device cache support. The help output + lists the default read-mode device cache file path that is + in effect for the current invocation of lsof. The -D? + option output lists the read-only and write device cache + file paths, the names of any applicable environment vari- + ables, and the personal device cache path format. + + Lsof can detect that the current device cache file has been + 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 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. + + The path from which a lsof process may attempt to read a + device cache file may not be the same as the path to which + it can legitimately write. Thus when lsof senses that it + needs to update the device cache file, it may choose a dif- + ferent path for writing it from the path from which it read + an incorrect or outdated version. + + If available, the -Dr option will inhibit the writing of a + new device cache file. (It's always available when speci- + fied without a path name argument.) + + When a new device is added to the system, the device cache + file may need to be recreated. Since lsof compares the + mtime of the device cache file with the mtime and ctime of + + + +SunOS 5.9 Last change: Revision-4.82 47 + + + + + + +Maintenance Procedures LSOF(8) + + + + the /dev (or /devices) directory, it usually detects that a + new device has been added; in that case lsof issues a warn- + ing message and attempts to rebuild the device cache file. + + Whenever lsof writes a device cache file, it sets its owner- + ship to the real UID of the executing process, and its per- + mission modes to 0600, this restricting its reading and + writing to the file's owner. + +LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS + Two permissions of the lsof executable affect its ability to + access device cache files. The permissions are set by the + local system administrator when lsof is installed. + + The first and rarer permission is setuid-root. It comes + into effect when lsof is executed; its effective UID is then + root, while its real (i.e., that of the logged-on user) UID + is not. The lsof distribution recommends that versions for + these dialects run setuid-root. + + HP-UX 11.11 and 11.23 + Linux + + The second and more common permission is setgid. It comes + into effect when the effective group IDentification number + (GID) of the lsof process is set to one that can access ker- + nel memory devices - e.g., ``kmem'', ``sys'', or ``system''. + + An lsof process that has setgid permission usually + surrenders the permission after it has accessed the kernel + memory devices. When it does that, lsof can allow more + liberal device cache path formations. The lsof distribution + recommends that versions for these dialects run setgid and + be allowed to surrender setgid permission. + + AIX 5.[12] and 5.3-ML1 + Apple Darwin 7.x Power Macintosh systems + FreeBSD 4.x, 4.1x, 5.x and [67].x for x86-based systems + FreeBSD 5.x and [67].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] 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 + + + + + +SunOS 5.9 Last change: Revision-4.82 48 + + + + + + +Maintenance Procedures LSOF(8) + + + + (Note: lsof for AIX 5L and above needs setuid-root permis- + sion if its -X option is used.) + + 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. + + Linux + +DEVICE CACHE FILE PATH FROM THE -D OPTION + The -D option provides limited means for specifying the dev- + ice cache file path. Its ? function will report the + read-only and write device cache file paths that lsof will + use. + + When the -D b, r, and u functions are available, you can use + them to request that the cache file be built in a specific + location (b[path]); read but not rebuilt (r[path]); or read + and rebuilt (u[path]). The b, r, and u functions are res- + tricted under some conditions. They are restricted when the + lsof process is setuid-root. The path specified with the r + function is always read-only, even when it is available. + + The b, r, and u functions are also restricted when the lsof + process runs setgid and lsof doesn't surrender the setgid + permission. (See the LSOF PERMISSIONS THAT AFFECT DEVICE + CACHE FILE ACCESS section for a list of implementations that + normally don't surrender their setgid permission.) + + A further -D function, i (for ignore), is always available. + + When available, the b function tells lsof to read device + information from the kernel with the stat(2) function and + build a device cache file at the indicated path. + + When available, the r function tells lsof to read the device + cache file, but not update it. When a path argument accom- + panies -Dr, it names the device cache file path. The r + function is always available when it is specified without a + path name argument. If lsof is not running setuid-root and + surrenders its setgid permission, a path name argument may + accompany the r function. + + When available, the u function tells lsof to attempt to read + and use the device cache file. If it can't read the file, + or if it finds the contents of the file incorrect or out- + dated, it will read information from the kernel, and attempt + to write an updated version of the device cache file, but + only to a path it considers legitimate for the lsof process + effective and real UIDs. + + + + + +SunOS 5.9 Last change: Revision-4.82 49 + + + + + + +Maintenance Procedures LSOF(8) + + + +DEVICE CACHE PATH FROM AN ENVIRONMENT VARIABLE + Lsof's second choice for the device cache file is the con- + tents of the LSOFDEVCACHE environment variable. It avoids + this choice if the lsof process is setuid-root, or the real + UID of the process is root. + + A further restriction applies to a device cache file path + taken from the LSOFDEVCACHE environment variable: lsof will + not write a device cache file to the path if the lsof pro- + cess doesn't surrender its setgid permission. (See the LSOF + PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS section for + information on implementations that don't surrender their + setgid permission.) + + The local system administrator can disable the use of the + LSOFDEVCACHE environment variable or change its name when + building lsof. Consult the output of -D? for the environ- + ment variable's name. + +SYSTEM-WIDE DEVICE CACHE PATH + The local system administrator may choose to have a + system-wide device cache file when building lsof. That file + will generally be constructed by a special system adminis- + tration procedure when the system is booted or when the con- + tents of /dev or /devices) changes. If defined, it is + lsof's third device cache file path choice. + + You can tell that a system-wide device cache file is in + effect for your local installation by examining the lsof + help option output - i.e., the output from the -h or -? + option. + + Lsof will never write to the system-wide device cache file + path by default. It must be explicitly named with a -D + function in a root-owned procedure. Once the file has been + written, the procedure must change its permission modes to + 0644 (owner-read and owner-write, group-read, and + other-read). + +PERSONAL DEVICE CACHE PATH (DEFAULT) + The default device cache file path of the lsof distribution + is one recorded in the home directory of the real UID that + executes lsof. Added to the home directory is a second path + component of the form .lsof_hostname. + + This is lsof's fourth device cache file path choice, and is + usually the default. If a system-wide device cache file + path was defined when lsof was built, this fourth choice + will be applied when lsof can't find the system-wide device + cache file. This is the only time lsof uses two paths when + reading the device cache file. + + + + +SunOS 5.9 Last change: Revision-4.82 50 + + + + + + +Maintenance Procedures LSOF(8) + + + + The hostname part of the second component is the base name + of the executing host, as returned by gethostname(2). The + base name is defined to be the characters preceding the + first `.' in the gethostname(2) output, or all the gethost- + name(2) output if it contains no `.'. + + The device cache file belongs to the user ID and is readable + and writable by the user ID alone - i.e., its modes are + 0600. Each distinct real user ID on a given host that exe- + cutes lsof has a distinct device cache file. The hostname + part of the path distinguishes device cache files in an + NFS-mounted home directory into which device cache files are + written from several different hosts. + + The personal device cache file path formed by this method + represents a device cache file that lsof will attempt to + read, and will attempt to write should it not exist or + should its contents be incorrect or outdated. + + The -Dr option without a path name argument will inhibit the + writing of a new device cache file. + + The -D? option will list the format specification for con- + structing the personal device cache file. The conversions + used in the format specification are described in the + 00DCACHE file of the lsof distribution. + +MODIFIED PERSONAL DEVICE CACHE PATH + If this option is defined by the local system administrator + when lsof is built, the LSOFPERSDCPATH environment variable + contents may be used to add a component of the personal dev- + ice cache file path. + + 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 specifi- + cation of the dialect's machine.h header file. (It's placed + right after the home directory in the default lsof distribu- + tion.) + + 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: + + /Homes/abe/LSOF/.lsof_vic + + The LSOFPERSDCPATH environment variable is ignored when the + lsof process is setuid-root or when the real UID of the pro- + cess is root. + + + + +SunOS 5.9 Last change: Revision-4.82 51 + + + + + + +Maintenance Procedures LSOF(8) + + + + Lsof will not write to a modified personal device cache file + path if the lsof process doesn't surrender setgid permis- + sion. (See the LSOF PERMISSIONS THAT AFFECT DEVICE CACHE + FILE ACCESS section for a list of implementations that nor- + mally don't surrender their setgid permission.) + + If, for example, you want to create a sub-directory of per- + sonal device cache file paths by using the LSOFPERSDCPATH + environment variable to name it, and lsof doesn't surrender + its setgid permission, you will have to allow lsof to create + device cache files at the standard personal path and move + them to your subdirectory with shell commands. + + The local system administrator may: disable this option when + lsof is built; change the name of the environment variable + from LSOFPERSDCPATH to something else; change the HASPERSDC + format to include the personal path component in another + place; or exclude the personal path component entirely. + Consult the output of the -D? option for the environment + variable's name and the HASPERSDC format specification. + +DIAGNOSTICS + Errors are identified with messages on the standard error + file. + + Lsof returns a one (1) if any error was detected, including + the failure to locate command names, file names, Internet + addresses or files, login names, NFS files, PIDs, PGIDs, or + UIDs it was asked to list. If the -V option is specified, + lsof will indicate the search items it failed to list. + + 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. + + When lsof cannot open access to /dev (or /devices) or one of + its subdirectories, or get information on a file in them + with stat(2), it issues a warning message and continues. + That lsof will issue warning messages about inaccessible + files in /dev (or /devices) is indicated in its help output + - requested with the -h or >B -? options - with the mes- + sage: + + Inaccessible /dev warnings are enabled. + + The warning message may be suppressed with the -w option. + It may also have been suppressed by the system administrator + when lsof was compiled by the setting of the WARNDEVACCESS + definition. In this case, the output from the help options + will include the message: + + + + + +SunOS 5.9 Last change: Revision-4.82 52 + + + + + + +Maintenance Procedures LSOF(8) + + + + Inaccessible /dev warnings are disabled. + + Inaccessible device warning messages usually disappear after + lsof has created a working device cache file. + +EXAMPLES + For a more extensive set of examples, documented more fully, + see the 00QUICKSTART file of the lsof distribution. + + To list all open files, use: + + lsof + + To list all open Internet, x.25 (HP-UX), and UNIX domain + files, use: + + lsof -i -U + + To list all open IPv4 network files in use by the process + whose PID is 1234, use: + + lsof -i 4 -a -p 1234 + + Presuming the UNIX dialect supports IPv6, to list only open + IPv6 network files, use: + + lsof -i 6 + + To list all files using any protocol on ports 513, 514, or + 515 of host wonderland.cc.purdue.edu, use: + + lsof -i @wonderland.cc.purdue.edu:513-515 + + To list all files using any protocol on any port of + mace.cc.purdue.edu (cc.purdue.edu is the default domain), + use: + + lsof -i @mace + + To list all open files for login name ``abe'', or user ID + 1234, or process 456, or process 123, or process 789, use: + + lsof -p 456,123,789 -u 1234,abe + + To list all open files on device /dev/hd4, use: + + lsof /dev/hd4 + + To find the process that has /u/abe/foo open, use: + + lsof /u/abe/foo + + + + +SunOS 5.9 Last change: Revision-4.82 53 + + + + + + +Maintenance Procedures LSOF(8) + + + + To send a SIGHUP to the processes that have /u/abe/bar open, + use: + + kill -HUP `lsof -t /u/abe/bar` + + To find any open file, including an open UNIX domain socket + file, with the name /dev/log, use: + + lsof /dev/log + + To find processes with open files on the NFS file system + named /nfs/mount/point whose server is inaccessible, and + presuming your mount table supplies the device number for + /nfs/mount/point, use: + + lsof -b /nfs/mount/point + + To do the preceding search with warning messages suppressed, + use: + + lsof -bw /nfs/mount/point + + To ignore the device cache file, use: + + lsof -Di + + To obtain PID and command name field output for each pro- + cess, file descriptor, file device number, and file inode + number for each file of each process, use: + + lsof -FpcfDi + + To list the files at descriptors 1 and 3 of every process + running the lsof command for login ID ``abe'' every 10 + seconds, use: + + lsof -c lsof -a -d 1 -d 3 -u abe -r10 + + To list the current working directory of processes running a + command that is exactly four characters long and has an 'o' + or 'O' in character three, use this regular expression form + of the -c c option: + + lsof -c /^..o.$/i -a -d cwd + + To find an IP version 4 socket file by its associated + numeric dot-form address, use: + + lsof -i@128.210.15.17 + + To find an IP version 6 socket file (when the UNIX dialect + supports IPv6) by its associated numeric colon-form address, + + + +SunOS 5.9 Last change: Revision-4.82 54 + + + + + + +Maintenance Procedures LSOF(8) + + + + use: + + lsof -i@[0:1:2:3:4:5:6:7] + + To find an IP version 6 socket file (when the UNIX dialect + supports IPv6) by an associated numeric colon-form address + that has a run of zeroes in it - e.g., the loop-back address + - use: + + lsof -i@[::1] + + To obtain a repeat mode marker line that contains the + current time, use: + + lsof -rm====%T==== + + To add spaces to the previous marker line, use: + + lsof -r "m==== %T ====" + +BUGS + Since lsof reads kernel memory in its search for open files, + rapid changes in kernel memory may produce unpredictable + results. + + When a file has multiple record locks, the lock status char- + acter (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. + + Lsof can't search for files with restrictive access permis- + sions by name unless it is installed with root set-UID per- + mission. Otherwise it is limited to searching for files to + which its user or its set-GID group (if any) has access per- + mission. + + The display of the destination address of a raw socket + (e.g., for ping) depends on the UNIX operating system. Some + dialects store the destination address in the raw socket's + protocol control block, some do not. + + Lsof can't always represent Solaris device numbers in the + same way that ls(1) does. For example, the major and minor + device numbers that the lstat(2) and stat(2) functions + report for the directory on which CD-ROM files are mounted + (typically /cdrom) are not the same as the ones that it + reports for the device on which CD-ROM files are mounted + (typically /dev/sr0). (Lsof reports the directory numbers.) + + The support for /proc file systems is available only for BSD + and Tru64 UNIX dialects, Linux, and dialects derived from + + + +SunOS 5.9 Last change: Revision-4.82 55 + + + + + + +Maintenance Procedures LSOF(8) + + + + SYSV R4 - e.g., FreeBSD, NetBSD, OpenBSD, Solaris, UnixWare. + + Some /proc file items - device number, inode number, and + file size - are unavailable in some dialects. Searching for + files in a /proc file system may require that the full path + name be specified. + + No text (txt) file descriptors are displayed for Linux + processes. All entries for files other than the current + working directory, the root directory, and numerical file + descriptors are labeled mem descriptors. + + Lsof can't search for Tru64 UNIX named pipes by name, + because their kernel implementation of lstat(2) returns an + improper device number for a named pipe. + + Lsof can't report fully or correctly on HP-UX 9.01, 10.20, + and 11.00 locks because of insufficient access to kernel + data or errors in the kernel data. See the lsof FAQ (The + FAQ section gives its location.) for details. + + The AIX SMT file type is a fabrication. It's made up for + file structures whose type (15) isn't defined in the AIX + /usr/include/sys/file.h header file. One way to create such + file structures is to run X clients with the DISPLAY vari- + able set to ``:0.0''. + + The +|-f[cfgGn] option is not supported under /proc-based + Linux lsof, because it doesn't read kernel structures from + kernel memory. + +ENVIRONMENT + Lsof may access these environment variables. + + LANG defines a language locale. See setlo- + cale(3) for the names of other variables + that can be used in place of LANG - e.g., + LC_ALL, LC_TYPE, etc. + + LSOFDEVCACHE defines the path to a device cache file. + See the DEVICE CACHE PATH FROM AN ENVIRON- + MENT VARIABLE section for more informa- + tion. + + LSOFPERSDCPATH defines the middle component of a modified + personal device cache file path. See the + MODIFIED PERSONAL DEVICE CACHE PATH sec- + tion for more information. + +FAQ + Frequently-asked questions and their answers (an FAQ) are + available in the 00FAQ file of the lsof distribution. + + + +SunOS 5.9 Last change: Revision-4.82 56 + + + + + + +Maintenance Procedures LSOF(8) + + + + That file is also available via anonymous ftp from + lsof.itap.purdue.edu at pub/tools/unix/lsofFAQ. The URL is: + + ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ + +FILES + /dev/kmem kernel virtual memory device + + /dev/mem physical memory device + + /dev/swap system paging device + + .lsof_hostname lsof's device cache file (The suffix, + hostname, is the first component of the + host's name returned by gethostname(2).) + +AUTHORS + Lsof was written by Victor A. Abell of Pur- + due University. Many others have contributed to lsof. + They're listed in the 00CREDITS file of the lsof distribu- + tion. + +DISTRIBUTION + The latest distribution of lsof is available via anonymous + ftp from the host lsof.itap.purdue.edu. You'll find the + lsof distribution in the pub/tools/unix/lsof directory. + + You can also use this URL: + + ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof + + Lsof is also mirrored elsewhere. When you access + lsof.itap.purdue.edu and change to its pub/tools/unix/lsof + directory, you'll be given a list of some mirror sites. The + pub/tools/unix/lsof directory also contains a more complete + list in its mirrors file. Use mirrors with caution - not + all mirrors always have the latest lsof revision. + + Some pre-compiled Lsof executables are available on + 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 + pub/tools/unix/lsof/binaries subdirectories and in the 00* + files of the distribution. + + More information on the lsof distribution can be found in + its README.lsof_ file. If you intend to get the + lsof distribution and build it, please read + README.lsof_ and the other 00* files of the distri- + bution before sending questions to the author. + + + + +SunOS 5.9 Last change: Revision-4.82 57 + + + + + + +Maintenance Procedures LSOF(8) + + + +SEE ALSO + Not all the following manual pages may exist in every UNIX + dialect to which lsof has been ported. + + access(2), awk(1), crash(1), fattach(3C), ff(1), fstat(8), + fuser(1), gethostname(2), isprint(3), kill(1), localtime(3), + lstat(2), modload(8), mount(8), netstat(1), ofiles(8L), + perl(1), ps(1), readlink(2), setlocale(3), stat(2), + strftime(3), time(2), uname(1). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +SunOS 5.9 Last change: Revision-4.82 58 + + + diff --git a/lsof_fields.h b/lsof_fields.h new file mode 100644 index 0000000..d40aafc --- /dev/null +++ b/lsof_fields.h @@ -0,0 +1,176 @@ +/* + * lsof_field.h - 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.11 2006/09/15 18:53:21 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" + +#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_LOCK 'l' +#define LSOF_FIX_LOCK 10 +#define LSOF_FNM_LOCK "lock: r/R = read; w/W = write; u = read/write" + +#define LSOF_FID_LOGIN 'L' +#define LSOF_FIX_LOGIN 11 +#define LSOF_FNM_LOGIN "login name" + +#define LSOF_FID_MARK 'm' +#define LSOF_FIX_MARK 12 +#define LSOF_FNM_MARK "marker between repeated output" + +#define LSOF_FID_NAME 'n' +#define LSOF_FIX_NAME 13 +#define LSOF_FNM_NAME "comment, name, Internet addresses" + +#define LSOF_FID_NI 'N' +#define LSOF_FIX_NI 14 +#define LSOF_FNM_NI "file struct node ID as 0x" + +#define LSOF_FID_OFFSET 'o' +#define LSOF_FIX_OFFSET 15 +#define LSOF_FNM_OFFSET "file offset as 0t or 0x" + +#define LSOF_FID_PID 'p' +#define LSOF_FIX_PID 16 +#define LSOF_FNM_PID "process ID (PID)" + +#define LSOF_FID_PGID 'g' +#define LSOF_FIX_PGID 17 +#define LSOF_FNM_PGID "process group ID (PGID)" + +#define LSOF_FID_PROTO 'P' +#define LSOF_FIX_PROTO 18 +#define LSOF_FNM_PROTO "protocol name" + +#define LSOF_FID_RDEV 'r' +#define LSOF_FIX_RDEV 19 +#define LSOF_FNM_RDEV "raw device number as 0x" + +#define LSOF_FID_PPID 'R' +#define LSOF_FIX_PPID 20 +#define LSOF_FNM_PPID "paRent PID" + +#define LSOF_FID_SIZE 's' +#define LSOF_FIX_SIZE 21 +#define LSOF_FNM_SIZE "file size" + +#define LSOF_FID_STREAM 'S' +#define LSOF_FIX_STREAM 22 +#define LSOF_FNM_STREAM "stream module and device names" + +#define LSOF_FID_TYPE 't' +#define LSOF_FIX_TYPE 23 +#define LSOF_FNM_TYPE "file type" + +#define LSOF_FID_TCPTPI 'T' +#define LSOF_FIX_TCPTPI 24 +#define LSOF_FNM_TCPTPI "TCP/TPI info" + +#define LSOF_FID_UID 'u' +#define LSOF_FIX_UID 25 +#define LSOF_FNM_UID "user ID (UID)" + +#define LSOF_FID_ZONE 'z' +#define LSOF_FIX_ZONE 26 +#define LSOF_FNM_ZONE "zone name" + +#define LSOF_FID_CNTX 'Z' +#define LSOF_FIX_CNTX 27 +#define LSOF_FNM_CNTX "security context" + +#define LSOF_FID_TERM '0' +#define LSOF_FIX_TERM 28 +#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..be58704 --- /dev/null +++ b/main.c @@ -0,0 +1,1678 @@ +/* + * 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.53 2008/10/21 16:21:41 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; +#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 all file descriptors above 2. + * + * 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. + */ + for (i = 3, n = GET_MAX_FD(); i < n; 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:D:d:%sf:F:g:hi:%slL:%sMnNo: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(HASKOPT) + "k:", +#else /* !defined(HASKOPT) */ + "", +#endif /* defined(HASKOPT) */ + +#if defined(HASMOPT) || defined(HASMNTSUP) + "m:", +#else /* !defined(HASMOPT) && !defined(HASMNTSUP) */ + "", +#endif /* defined(HASMOPT) || defined(HASMNTSUP) */ + +#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 = 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; + 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(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(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) */ + + if (FieldSel[i].id == LSOF_FID_RDEV) + continue; /* for compatibility */ + 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(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 (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) */ + + 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) */ + + case 'M': + FportMap = (GOp == '+') ? 1 : 0; + break; + 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; + } + } +/* + * 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 (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; + Selall = 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) */ + + /* + * 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 (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(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..3c1c32b --- /dev/null +++ b/misc.c @@ -0,0 +1,1648 @@ +/* + * 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.26 2008/10/21 16:21:41 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HASWIDECHAR) && defined(WIDECHARINCL) +#include WIDECHARINCL +#endif /* defined(HASWIDECHAR) && defined(WIDECHARINCL) */ + + +/* + * 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) */ + +_PROTOTYPE(static char *safepup,(unsigned int c, int *cl)); + + +/* + * 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 fd, nd, r_al, r_rbln; + char r_arg[MAXPATHLEN+1], r_rbuf[MAXPATHLEN+1]; + int (*r_fn)(); + /* + * Close all open file descriptors except Pipes[0] and + * Pipes[3]. + */ + for (fd = 0, nd = GET_MAX_FD(); fd < nd; 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; + } + /* + * 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) + */ + +static char * +safepup(c, cl) + unsigned int c; /* unprintable (i.e., !isprint()) + * character */ + 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 { + (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 == c) { + if (*sp < 0x20 || (unsigned char)*sp == 0xff) + 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 (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 (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/packaging/lsof.changes b/packaging/lsof.changes new file mode 100644 index 0000000..77e7b14 --- /dev/null +++ b/packaging/lsof.changes @@ -0,0 +1,13 @@ +* Wed Jun 08 2011 Anas Nashif - 4.82 +- Repackage docs + +* Mon Jan 11 2010 Passion Zhao - 4.82 +- Update to 4.82 + +* Sat Feb 07 2009 Anas Nashif 4.81 +- Update to 4.81 + +* Tue Sep 09 2008 Anas Nashif 4.78 +- initial checkin into moblin +- remove selinux support + diff --git a/packaging/lsof.spec b/packaging/lsof.spec new file mode 100644 index 0000000..d932f54 --- /dev/null +++ b/packaging/lsof.spec @@ -0,0 +1,56 @@ +# +# Please submit bugfixes or comments via http://bugs.meego.com/ +# + +Name: lsof +Version: 4.82 +Release: 1 +License: BSD-style +Summary: A utility which lists open files on a Linux/UNIX system +Group: Development/Debuggers + +Url: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof +# lsof contains licensed code that we cannot ship. Therefore we use +# upstream2downstream.sh script to remove the code before shipping it. +# +# The script you can found in CVS or download from: +# http://cvs.fedoraproject.org/viewcvs/rpms/lsof/devel/upstream2downstream.sh +# +%define lsofrh lsof_4.82-rh +Source0: %{lsofrh}.tar.bz2 + +# 184338 - allow lsof access nptl threads +Patch1: lsof_4.81-threads.patch + +%description +Lsof 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. + +%prep +%setup -q -n %{lsofrh} +%patch1 -p1 + +%build +LSOF_VSTR=2.6.16 LINUX_BASE=/proc ./Configure -n linux + +make DEBUG="%{optflags}" %{?_smp_mflags} + +%install +mkdir -p %{buildroot}%{_sbindir} +install -p -m 0755 lsof %{buildroot}%{_prefix}/sbin +mkdir -p %{buildroot}%{_mandir}/man8 +install -p lsof.8 %{buildroot}%{_mandir}/man8/ +mkdir -p %{buildroot}/usr/share/license +cp LICENSE.lsof %{buildroot}/usr/share/license/%{name} + +%clean +rm -rf %{buildroot} + +%docs_package + +%files +%defattr(644,root,root,755) +%attr(0755,root,root) %{_sbindir}/lsof +/usr/share/license/%{name} + diff --git a/packaging/lsof_4.81-threads.patch b/packaging/lsof_4.81-threads.patch new file mode 100644 index 0000000..399819f --- /dev/null +++ b/packaging/lsof_4.81-threads.patch @@ -0,0 +1,129 @@ +diff -up lsof_4.81-rh/dialects/linux/dproc.c.kzak lsof_4.81-rh/dialects/linux/dproc.c +--- lsof_4.81-rh/dialects/linux/dproc.c.kzak 2008-10-21 18:17:25.000000000 +0200 ++++ lsof_4.81-rh/dialects/linux/dproc.c 2008-12-02 10:54:54.000000000 +0100 +@@ -89,7 +89,8 @@ _PROTOTYPE(static void process_proc_map, + _PROTOTYPE(static int process_id,(char *idp, int idpl, char *cmd, UID_ARG uid, + int pid, int ppid, int pgid)); + _PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss)); +- ++_PROTOTYPE(static int get_other_thread,(int pid, char **tid)); ++ + + #if defined(HASSELINUX) + _PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx)); +@@ -159,6 +160,7 @@ gather_proc_info() + struct dirent *dp; + struct stat sb; + int lwp, n, nl, pgid, pid, ppid, rv, tx; ++ char *tid = NULL; + static char *lwppath = (char *)NULL; + static int lwppathl = 0; + static char *path = (char *)NULL; +@@ -252,6 +254,13 @@ gather_proc_info() + while ((dp = readdir(ps))) { + if (nm2id(dp->d_name, &pid, &n)) + continue; ++ ++ tid = NULL; ++ if (get_other_thread(pid, &tid) < 0) ++ continue; ++ if (tid) ++ n += sizeof("task/") + strlen(tid); ++ + /* + * Build path to PID's directory. + */ +@@ -265,7 +274,14 @@ gather_proc_info() + Exit(1); + } + } +- (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name); ++ if (tid) { ++ /* /proc/ is useless (zombie), we have to use /proc//task/ ++ * where is still running thread ++ */ ++ (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/task/%s/", dp->d_name, tid); ++ free(tid); ++ } else ++ (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name); + n += (pidx + 1); + /* + * Process the PID's stat info. +@@ -1007,6 +1023,64 @@ process_id(idp, idpl, cmd, uid, pid, ppi + return(0); + } + ++/* fill tid if the initial thread is zombie, ++ * but other thread still alive ++ * ++ * returns -1=error, 0=nothing, 1=ok ++ */ ++static int ++get_other_thread(pid, tid) ++ int pid; ++ char **tid; ++{ ++ char path[MAXPATHLEN]; ++ DIR *tdp; ++ struct dirent *td; ++ char pstate; ++ FILE *f; ++ int _pid; ++ int re = 0, x; ++ ++ snpf(path, sizeof(path), "%s/%d/stat", PROCFS, pid); ++ if (!(f = fopen(path, "r"))) ++ return -1; ++ x = fscanf(f, "%d %*s %c", &_pid, &pstate); ++ fclose(f); ++ if (x!=2) ++ return -1; ++ if (_pid != pid) ++ return -1; /* corrupted /proc? */ ++ if (pstate!='Z') ++ return 0; /* ignore normal proceses */ ++ ++ snpf(path, sizeof(path), "%s/%d/task", PROCFS, pid); ++ ++ /* open /proc//task */ ++ if (!(tdp = opendir(path))) ++ return 0; /* kernel < 2.6.x */ ++ ++ /* look for first alive thread */ ++ while ((td = readdir(tdp))) { ++ if (strcmp(td->d_name, ".")==0 || strcmp(td->d_name, "..")==0) ++ continue; ++ ++ /* /proc//task//stat */ ++ snpf(path, sizeof(path), "%s/%d/task/%s/stat", PROCFS, pid, td->d_name); ++ if (!(f = fopen(path, "r"))) ++ continue; ++ x = fscanf(f, "%*d %*s %c", &pstate); ++ fclose(f); ++ if (x!=1) ++ continue; ++ if (pstate!='Z') { ++ re = 1; ++ *tid = strdup(td->d_name); ++ break; ++ } ++ } ++ closedir(tdp); ++ return re; ++} + + /* + * process_proc_map() - process the memory map of a process +@@ -1250,12 +1324,6 @@ read_id_stat(ty, p, id, cmd, ppid, pgid) + return(1); + } + /* +- * Convert the first field to an integer; its conversion must match the +- * ID argument. +- */ +- if (!fp[0] || (atoi(fp[0]) != id)) +- return(1); +-/* + * Get the command name from the second field. Strip a starting '(' and + * an ending ')'. Allocate space to hold the result and return the space + * pointer. diff --git a/print.c b/print.c new file mode 100644 index 0000000..645397b --- /dev/null +++ b/print.c @@ -0,0 +1,2752 @@ +/* + * 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.50 2008/10/21 16:21:41 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; +}; + + +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 + */ +#define HASHPORT(p) (((((int)(p)) * 31415) >> 3) & (PORTHASHBUCKETS - 1)) + + +_PROTOTYPE(static void fill_portmap,(void)); +_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)); +_PROTOTYPE(static void update_portmap,(struct porttab *pt, char *pn)); + + +/* + * 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); +} + + +/* + * 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); +} + + +/* + * 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]) { + nh = FportMap ? 4 : 2; + 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 we're looking up program names for portmapped ports, make sure the + * portmap table has been loaded. + */ + if (FportMap && !pm) { + (void) fill_portmap(); + pm++; + } +/* + * 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 (!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); + } + } + 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(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(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 || FportMap) { + + /* + * 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 ((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; + } + } + 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); + 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(1); + return; + } + 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; +} + + +/* + * 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; +} diff --git a/proc.c b/proc.c new file mode 100644 index 0000000..9dc1b0e --- /dev/null +++ b/proc.c @@ -0,0 +1,1187 @@ +/* + * 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.45 2009/03/25 19:20:44 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int is_file_sel,(struct lproc *lp, struct lfile *lf)); + + +/* + * 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(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; + 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); + 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) && !Selall) { + 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; + } +} + + +/* + * 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? + */ + +static 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 (Selall) + return(1); + if (Fand && ((lf->sf & Selflags) != Selflags)) + return(0); + return(1); +} + + +/* + * is_proc_excl() - is process excluded? + */ + +int +is_proc_excl(pid, pgid, uid, pss, sf) + 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 */ +{ + 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 (Selall) { + *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); + } +/* + * When neither the process group ID, nor the PID, nor the UID is selected: + * + * If list option ANDing of process group IDs, PIDs or UIDs 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))) ? 1 : 0); +/* + * When the process group ID, PID, or UID is selected and the process group + * ID, PID, or UID list option has been specified: + * + * If list option ANDing has been specified, and the correct + * combination of process group ID, PID, and UID is selected, reply that + * the process is not 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)) { + if (Fand) + return(((Selflags & (SELPGID|SELPID|SELUID)) != *sf) ? 1 : 0); + return(0); + } +/* + * Finally, when neither the process group ID, nor the PID, nor the UID is + * selected, and no process group ID, PID or UID 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; + 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; + Lf = (struct lfile *)NULL; +} + + +#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) { + + /* + * 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(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 dialects-specific formatted + * output. + */ + if (!Ffield) { + print_file(); + continue; + } + /* + * Print selected fields. + */ + lc = st = 0; + if (FieldSel[LSOF_FIX_FD].st) { + for (cp = Lf->fd; *cp == ' '; cp++) + ; + if (*cp) { + (void) printf("%c%s%c", LSOF_FID_FD, cp, Terminator); + lc++; + } + } + 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/proto.h b/proto.h new file mode 100644 index 0000000..b0a74bb --- /dev/null +++ b/proto.h @@ -0,0 +1,284 @@ +/* + * 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.34 2008/10/21 16:21:41 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)); +_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)); +_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_nw_addr,(unsigned char *ia, int p, int af)); +_PROTOTYPE(extern int is_proc_excl,(int pid, int pgid, UID_ARG uid, short *pss, short *sf)); +_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 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..b9e2fc1 --- /dev/null +++ b/store.c @@ -0,0 +1,414 @@ +/* + * 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.38 2008/10/21 16:21:41 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Global storage definitions + */ + +#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 */ + +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 Fcntx = 0; /* -Z option status */ +int FdColW; /* FD column width */ +int Ffilesys = 0; /* -f option status: + * 0 = paths may be file systems + * 1 = paths are just files + * 2 = paths must be file systems */ + +#if defined(HASNCACHE) +int Fncache = 1; /* -C option status */ +int NcacheReload = 1; /* 1 == call ncache_load() */ +#endif /* defined(HASNCACHE) */ + +int Ffield = 0; /* -f and -F status */ +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(HASPMAPENABLED) +int FportMap = 1; /* +|-M option status */ +#else /* !defined(HASPMAPENABLED) */ +int FportMap = 0; /* +|-M option status */ +#endif /* defined(HASPMAPENABLED) */ + +int Fpgid = 0; /* -g option status */ +int Fppid = 0; /* -R option status */ +int Fsize = 0; /* -s option status */ +int FcColW; /* FCT column width */ +int FgColW; /* FILE-FLAG column width */ +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 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, 0, LSOF_FNM_FD, NULL, 0 }, /* 5 */ + { LSOF_FID_FA, 0, LSOF_FNM_FA, &Fsv, FSV_FA }, /* 6 */ + { LSOF_FID_FG, 0, LSOF_FNM_FG, &Fsv, FSV_FG }, /* 7 */ + { LSOF_FID_INODE, 0, LSOF_FNM_INODE, NULL, 0 }, /* 8 */ + { LSOF_FID_NLINK, 0, LSOF_FNM_NLINK, &Fnlink, 1 }, /* 9 */ + { LSOF_FID_LOCK, 0, LSOF_FNM_LOCK, NULL, 0 }, /* 10 */ + { LSOF_FID_LOGIN, 0, LSOF_FNM_LOGIN, NULL, 0 }, /* 11 */ + { LSOF_FID_MARK, 1, LSOF_FNM_MARK, NULL, 0 }, /* 12 */ + { LSOF_FID_NAME, 0, LSOF_FNM_NAME, NULL, 0 }, /* 13 */ + { LSOF_FID_NI, 0, LSOF_FNM_NI, &Fsv, FSV_NI }, /* 14 */ + { LSOF_FID_OFFSET, 0, LSOF_FNM_OFFSET, NULL, 0 }, /* 15 */ + { LSOF_FID_PID, 1, LSOF_FNM_PID, NULL, 0 }, /* 16 */ + { LSOF_FID_PGID, 0, LSOF_FNM_PGID, &Fpgid, 1 }, /* 17 */ + { LSOF_FID_PROTO, 0, LSOF_FNM_PROTO, NULL, 0 }, /* 18 */ + { LSOF_FID_RDEV, 0, LSOF_FNM_RDEV, NULL, 0 }, /* 19 */ + { LSOF_FID_PPID, 0, LSOF_FNM_PPID, &Fppid, 1 }, /* 20 */ + { LSOF_FID_SIZE, 0, LSOF_FNM_SIZE, NULL, 0 }, /* 21 */ + { LSOF_FID_STREAM, 0, LSOF_FNM_STREAM, NULL, 0 }, /* 22 */ + { LSOF_FID_TYPE, 0, LSOF_FNM_TYPE, NULL, 0 }, /* 23 */ + { LSOF_FID_TCPTPI, 0, LSOF_FNM_TCPTPI, &Ftcptpi, TCPTPI_ALL }, /* 24 */ + { LSOF_FID_UID, 0, LSOF_FNM_UID, NULL, 0 }, /* 25 */ + { LSOF_FID_ZONE, 0, LSOF_FNM_ZONE, &Fzone, 1 }, /* 26 */ + { LSOF_FID_CNTX, 0, LSOF_FNM_CNTX, &Fcntx, 1 }, /* 27 */ + { LSOF_FID_TERM, 0, LSOF_FNM_TERM, NULL, 0 }, /* 28 */ + +#if defined(HASFIELDAP1) + { '1', 0, HASFIELDAP1, NULL, 0 }, /* TERM+1 */ +#endif /* defined(HASFIELDAP1) */ + +#if defined(HASFIELDAP2) + { '2', 0, HASFIELDAP2, NULL, 0 }, /* TERM+2 */ +#endif /* defined(HASFIELDAP2) */ + +#if defined(HASFIELDAP3) + { '3', 0, HASFIELDAP3, NULL, 0 }, /* TERM+3 */ +#endif /* defined(HASFIELDAP3) */ + +#if defined(HASFIELDAP4) + { '4', 0, HASFIELDAP4, NULL, 0 }, /* TERM+4 */ +#endif /* defined(HASFIELDAP4) */ + +#if defined(HASFIELDAP5) + { '5', 0, HASFIELDAP5, NULL, 0 }, /* TERM+5 */ +#endif /* defined(HASFIELDAP5) */ + +#if defined(HASFIELDAP6) + { '6', 0, HASFIELDAP6, NULL, 0 }, /* TERM+6 */ +#endif /* defined(HASFIELDAP6) */ + +#if defined(HASFIELDAP7) + { '7', 0, HASFIELDAP7, NULL, 0 }, /* TERM+7 */ +#endif /* defined(HASFIELDAP7) */ + +#if defined(HASFIELDAP8) + { '8', 0, HASFIELDAP8, NULL, 0 }, /* TERM+8 */ +#endif /* defined(HASFIELDAP8) */ + +#if defined(HASFIELDAP9) + { '9', 0, HASFIELDAP9, NULL, 0 }, /* TERM+9 */ +#endif /* defined(HASFIELDAP9) */ + + { ' ', 0, NULL, NULL, 0 } +}; + +int Hdr = 0; /* header print status */ +char *InodeFmt_d = (char *) NULL; + /* INODETYPE decimal printf specification */ +char *InodeFmt_x = (char *) NULL; + /* INODETYPE hexadecimal printf specification */ +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 */ +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 = 1; /* all processes are selected (default) */ +int Selflags = 0; /* selection flags -- see SEL* in lsof.h */ +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 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 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..48603f9 --- /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.2 2002/04/19 11:53:37 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 `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..954fd66 --- /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.2 2002/04/19 11:54:00 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 data base line. + +new="" +for i in `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..be15af1 --- /dev/null +++ b/tests/LTlib.c @@ -0,0 +1,1104 @@ +/* + * 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_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..35aac12 --- /dev/null +++ b/tests/LTnlink.c @@ -0,0 +1,556 @@ +/* + * 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", 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) { + (void) unlink(Path); + 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..16c1025 --- /dev/null +++ b/tests/LTsock.c @@ -0,0 +1,877 @@ +/* + * 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_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..e1d149c --- /dev/null +++ b/tests/LsofTest.h @@ -0,0 +1,360 @@ +/* + * 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.12 2008/07/05 16:21:07 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 +#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..89dae5b --- /dev/null +++ b/tests/TestDB @@ -0,0 +1,120 @@ +# 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.33 2009/03/25 19:15:29 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_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=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=8000 +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 +_FILE_OFFSET_BITS=64 LT_BIGF LT_CC LT_DIAL_linux LT_VERS=26022 +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_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..84353a0 --- /dev/null +++ b/usage.c @@ -0,0 +1,916 @@ +/* + * 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.28 2008/10/21 16:21:41 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%s%stUvV%s]", + +#if defined(HASNCACHE) + "C", +#else /* !defined(HASNCACHE) */ + "", +#endif /* defined(HASNCACHE) */ + +#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]", + +#if defined(HASDCACHE) + "|-" +#else /* !defined(HASDCACHE) */ + "" +#endif /* defined(HASDCACHE) */ + + ); + + (void) fprintf(stderr, + " [+|-f%s%s%s%s%s%s]\n [-F [f]] [-g [s]] [-i [i]]", + +#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) */ + + (void) fprintf(stderr, + " [+|-M] [-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"); + (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 /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]"); +#else /* !defined(HASZONES) */ +# if defined(HASSELINUX) + (void) fprintf(stderr, + (buf[0]) ? " %s\n" : " %-25.25s", "-Z Z context [Z]"); +# endif /* defined(HASSELINUX) */ +#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[%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) */ + + (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 [%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_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"); + +#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..252e2b9 --- /dev/null +++ b/version @@ -0,0 +1 @@ +.ds VN 4.82 -- 2.7.4