procps 010114
This commit is contained in:
5
ps/.cvsignore.patch
Normal file
5
ps/.cvsignore.patch
Normal file
@@ -0,0 +1,5 @@
|
||||
diff -Naur procps-2.0.6/ps/.cvsignore procps-2.0.7/ps/.cvsignore
|
||||
--- procps-2.0.6/ps/.cvsignore Wed Dec 31 19:00:00 1969
|
||||
+++ procps-2.0.7/ps/.cvsignore Fri Jul 14 16:45:01 2000
|
||||
@@ -0,0 +1 @@
|
||||
+ps
|
481
ps/COPYING
Normal file
481
ps/COPYING
Normal file
@@ -0,0 +1,481 @@
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT 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 THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This 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.
|
||||
|
||||
This 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 this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
53
ps/HACKING
Normal file
53
ps/HACKING
Normal file
@@ -0,0 +1,53 @@
|
||||
Warning:
|
||||
|
||||
This code must corrctly handle lots of picky little details to meet
|
||||
the Unix98 standard while simultaneously being as compatible as
|
||||
possible with the original Linux ps. Don't "fix" something without
|
||||
considering the impact on all the special-case code. For example,
|
||||
the "tty" format _must_ use "TT" as the header, even though the SysV
|
||||
output formats _must_ use "TTY".
|
||||
|
||||
File overview:
|
||||
|
||||
display.c main(), debug code, iterates over processes
|
||||
escape.c Does stuff like \202 and < to command and environment.
|
||||
global.c Data + code to init it.
|
||||
help.c Help message.
|
||||
output.c Giant tables and lots of output functions.
|
||||
parser.c Initial command parsing.
|
||||
select.c want_this_proc() checks a process against flags & lists
|
||||
sortformat.c Parses sort & format specifier lists. Picks output format.
|
||||
stacktrace.c Debug code, not normally used.
|
||||
../proc/* Library used to gather data.
|
||||
regression Regression tests that ought to be run.
|
||||
common.h Lots of interesting stuff.
|
||||
Makefile Makefile
|
||||
p Script used to test ps when the library is not installed.
|
||||
utf Empty file used to test "ps ut?" unmangling behavior.
|
||||
ps.1 Man page.
|
||||
|
||||
Compiling:
|
||||
|
||||
Whatever you do, don't trust the Makefiles. They are severely broken.
|
||||
You can touch top.h and top won't be recompiled, or you can change
|
||||
library files and discover that the library and programs won't be
|
||||
recompiled.
|
||||
|
||||
Operation:
|
||||
|
||||
Unless the personality forces BSD parsing, parser.c tries to parse the
|
||||
command line as a mixed BSD+SysV+Gnu mess. On failure, BSD parsing is
|
||||
attempted. If BSD parsing fails _after_ SysV parsing has been attempted,
|
||||
the error message comes from the original SysV parse.
|
||||
|
||||
Control goes to sortformat.c, which must pick apart ambiguous options
|
||||
like "O". Failure can reset the whole program and set PER_FORCE_BSD,
|
||||
which means a second trip through parser.c and sortformat.c.
|
||||
|
||||
The choice of output format happens in sortformat.c. There is a switch()
|
||||
with all the valid format_flags combinations. The SysV and default
|
||||
options are NULL (unless overridden by personality), which causes a
|
||||
trip through SysV output format generation hackery. Note that the
|
||||
default format always goes through there, even if it is for BSD.
|
||||
Formats that came from the switch() (generally BSD, plus overrides)
|
||||
get mangled a bit to support various SysV output modifiers.
|
35
ps/Makefile
Executable file
35
ps/Makefile
Executable file
@@ -0,0 +1,35 @@
|
||||
all: ps
|
||||
|
||||
ps: escape.o global.o help.o select.o sortformat.o output.o parser.o display.o
|
||||
$(CC) -o ps escape.o global.o help.o select.o sortformat.o output.o parser.o display.o -L../proc -lproc
|
||||
|
||||
# This just adds the stacktrace code
|
||||
debug: escape.o global.o help.o select.o sortformat.o output.o parser.o display.o stacktrace.o
|
||||
$(CC) -o ps escape.o global.o help.o select.o sortformat.o output.o parser.o display.o stacktrace.o -L../proc -lproc -lefence
|
||||
|
||||
sortformat.o: sortformat.c common.h
|
||||
|
||||
global.o: global.c common.h
|
||||
|
||||
escape.o: escape.c
|
||||
|
||||
help.o: help.c
|
||||
|
||||
select.o: select.c common.h
|
||||
|
||||
output.o: output.c common.h
|
||||
|
||||
parser.o: parser.c common.h
|
||||
|
||||
display.o: display.c common.h
|
||||
|
||||
stacktrace.o: stacktrace.c
|
||||
|
||||
|
||||
install: ps
|
||||
install $(OWNERGROUP) --mode a=rx --strip ps $(BINDIR)/ps
|
||||
install $(OWNERGROUP) --mode a=r ps.1 $(MAN1DIR)/ps.1
|
||||
-rm -f $(DESTDIR)/var/catman/cat1/ps.1.gz $(DESTDIR)/var/man/cat1/ps.1.gz
|
||||
|
||||
clean:
|
||||
rm -f *.o DEADJOE *~ core ps gmon.out
|
28
ps/TRANSLATION
Normal file
28
ps/TRANSLATION
Normal file
@@ -0,0 +1,28 @@
|
||||
Initially I only want to translate the --help output and man page.
|
||||
Common error messages would be next on the list. I want to avoid
|
||||
run-time overhead and bloat.
|
||||
|
||||
Translations of the --help output should not be longer than 22 lines long.
|
||||
Feel free to leave out the less useful options to save space. (not even
|
||||
the English help text has all the options)
|
||||
|
||||
I think these are the most important options:
|
||||
|
||||
*** selection ***
|
||||
-C by command name list
|
||||
-G by real group ID list (supports names)
|
||||
-U by real user ID list (supports names)
|
||||
-u by effective user ID list (supports names)
|
||||
-e all processes
|
||||
-p by process ID list
|
||||
|
||||
*** output ***
|
||||
--no-heading No header line.
|
||||
-o,o user-defined output
|
||||
-j,j job control format
|
||||
-l,l long format
|
||||
-f full format
|
||||
s signal format
|
||||
u user-oriented format
|
||||
--forest ASCII art forest (process heirarchy)
|
||||
c show true command name
|
324
ps/common.h
Normal file
324
ps/common.h
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#ifndef PROCPS_PS_H
|
||||
#define PROCPS_PS_H
|
||||
|
||||
#include "../proc/readproc.h"
|
||||
#include <asm/page.h> /* looks safe for glibc, we need PAGE_SIZE */
|
||||
|
||||
#if 0
|
||||
#define trace(args...) printf(## args)
|
||||
#else
|
||||
#define trace(args...)
|
||||
#endif
|
||||
|
||||
|
||||
/***************** GENERAL DEFINE ********************/
|
||||
|
||||
|
||||
/* selection list */
|
||||
#define SEL_RUID 1
|
||||
#define SEL_EUID 2
|
||||
#define SEL_SUID 3
|
||||
#define SEL_FUID 4
|
||||
#define SEL_RGID 5
|
||||
#define SEL_EGID 6
|
||||
#define SEL_SGID 7
|
||||
#define SEL_FGID 8
|
||||
#define SEL_PGRP 9
|
||||
#define SEL_PID 10
|
||||
#define SEL_TTY 11
|
||||
#define SEL_SESS 12
|
||||
#define SEL_COMM 13
|
||||
|
||||
/* Since an enum could be smashed by a #define, it would be bad. */
|
||||
#define U98 0 /* Unix98 standard */ /* This must be 0 */
|
||||
#define XXX 1 /* Common extension */
|
||||
#define DEC 2 /* Digital Unix */
|
||||
#define AIX 3 /* AIX */
|
||||
#define SCO 4 /* SCO */
|
||||
#define LNX 5 /* Linux original :-) */
|
||||
#define BSD 6 /* FreeBSD and OpenBSD */
|
||||
#define SUN 7 /* SunOS 5 (Solaris) */
|
||||
#define HPU 8 /* HP-UX */
|
||||
#define SGI 9 /* Irix */
|
||||
#define SOE 10 /* IBM's S/390 OpenEdition */
|
||||
|
||||
/*
|
||||
* Must not overflow the output buffer:
|
||||
* 32 pages for env+cmd
|
||||
* 8 kB pages on the Alpha
|
||||
* 5 chars for "\001 "
|
||||
* plus some slack for other stuff
|
||||
* That is about 1.3 MB on the Alpha
|
||||
*
|
||||
* This isn't good enough for setuid. If anyone cares, mmap() over the
|
||||
* last page with something unwriteable.
|
||||
*/
|
||||
|
||||
/* maximum escape expansion is 6, for " */
|
||||
#define ESC_STRETCH 6
|
||||
/* output buffer size */
|
||||
#define OUTBUF_SIZE (32*PAGE_SIZE*ESC_STRETCH + 8*PAGE_SIZE)
|
||||
/* spaces used to right-justify things */
|
||||
#define SPACE_AMOUNT (int)(PAGE_SIZE)
|
||||
|
||||
/******************* PS DEFINE *******************/
|
||||
|
||||
/* personality control flags */
|
||||
#define PER_BROKEN_o 0x0001
|
||||
#define PER_BSD_h 0x0002
|
||||
#define PER_BSD_m 0x0004
|
||||
#define PER_CUMUL_MARKED 0x0008
|
||||
#define PER_FORCE_BSD 0x0010
|
||||
#define PER_GOOD_o 0x0020
|
||||
#define PER_OLD_m 0x0040
|
||||
#define PER_NO_DEFAULT_g 0x0080
|
||||
#define PER_ZAP_ADDR 0x0100
|
||||
#define PER_SANE_USER 0x0200
|
||||
#define PER_IRIX_l 0x0400
|
||||
|
||||
/* Simple selections by bit mask */
|
||||
#define SS_B_x 0x01
|
||||
#define SS_B_g 0x02
|
||||
#define SS_U_d 0x04
|
||||
#define SS_U_a 0x08
|
||||
#define SS_B_a 0x10
|
||||
|
||||
/* predefined format flags such as: -l -f l u s -j */
|
||||
#define FF_Uf 0x0001 /* -f */
|
||||
#define FF_Uj 0x0002 /* -j */
|
||||
#define FF_Ul 0x0004 /* -l */
|
||||
#define FF_Bj 0x0008 /* j */
|
||||
#define FF_Bl 0x0010 /* l */
|
||||
#define FF_Bs 0x0020 /* s */
|
||||
#define FF_Bu 0x0040 /* u */
|
||||
#define FF_Bv 0x0080 /* v */
|
||||
#define FF_LX 0x0100 /* X */
|
||||
#define FF_Lm 0x0200 /* m */ /* overloaded: threads, sort, format */
|
||||
|
||||
/* predefined format modifier flags such as: -l -f l u s -j */
|
||||
#define FM_c 0x0001 /* -c */
|
||||
#define FM_j 0x0002 /* -j */ /* only set when !sysv_j_format */
|
||||
#define FM_y 0x0004 /* -y */
|
||||
#define FM_L 0x0008 /* -L */
|
||||
#define FM_P 0x0010 /* -P */
|
||||
#define FM_M 0x0020 /* -M */
|
||||
#define FM_T 0x0040 /* -T */
|
||||
#define FM_F 0x0080 /* -F */ /* -F also sets the regular -f flags */
|
||||
|
||||
/* sorting & formatting */
|
||||
/* U,B,G is Unix,BSD,Gnu and then there is the option itself */
|
||||
#define SF_U_O 1
|
||||
#define SF_U_o 2
|
||||
#define SF_B_O 3
|
||||
#define SF_B_o 4
|
||||
#define SF_B_m 5 /* overloaded: threads, sort, format */
|
||||
#define SF_G_sort 6
|
||||
#define SF_G_format 7
|
||||
|
||||
/* headers */
|
||||
#define HEAD_SINGLE 0 /* default, must be 0 */
|
||||
#define HEAD_NONE 1
|
||||
#define HEAD_MULTI 2
|
||||
|
||||
|
||||
/********************** GENERAL TYPEDEF *******************/
|
||||
|
||||
/* Other fields that might be useful:
|
||||
*
|
||||
* char *name; user-defined column name (format specification)
|
||||
* int reverse; sorting in reverse (sort specification)
|
||||
*
|
||||
* name in place of u
|
||||
* reverse in place of n
|
||||
*/
|
||||
|
||||
typedef union sel_union {
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
dev_t tty;
|
||||
char cmd[8]; /* this is _not_ \0 terminated */
|
||||
} sel_union;
|
||||
|
||||
typedef struct selection_node {
|
||||
struct selection_node *next;
|
||||
sel_union *u; /* used if selection type has a list of values */
|
||||
int n; /* used if selection type has a list of values */
|
||||
int typecode;
|
||||
} selection_node;
|
||||
|
||||
typedef struct sort_node {
|
||||
struct sort_node *next;
|
||||
int (*sr)(const proc_t* P, const proc_t* Q); /* sort function */
|
||||
int reverse; /* can sort backwards */
|
||||
int typecode;
|
||||
} sort_node;
|
||||
|
||||
typedef struct format_node {
|
||||
struct format_node *next;
|
||||
char *name; /* user can override default name */
|
||||
int (*pr)(void); /* print function */
|
||||
/* int (* const sr)(const proc_t* P, const proc_t* Q); */ /* sort function */
|
||||
int width;
|
||||
int pad;
|
||||
int vendor; /* Vendor that invented this */
|
||||
int flags;
|
||||
int typecode;
|
||||
} format_node;
|
||||
|
||||
typedef struct format_struct {
|
||||
const char *spec; /* format specifier */
|
||||
const char *head; /* default header in the POSIX locale */
|
||||
int (* const pr)(void); /* print function */
|
||||
int (* const sr)(const proc_t* P, const proc_t* Q); /* sort function */
|
||||
const int width;
|
||||
const int pad; /* could be second width */
|
||||
const int vendor; /* Where does this come from? */
|
||||
const int flags;
|
||||
} format_struct;
|
||||
|
||||
/* though ps-specific, needed by general file */
|
||||
typedef struct macro_struct {
|
||||
const char *spec; /* format specifier */
|
||||
const char *head; /* default header in the POSIX locale */
|
||||
} macro_struct;
|
||||
|
||||
/**************** PS TYPEDEF ***********************/
|
||||
|
||||
typedef struct aix_struct {
|
||||
const int desc; /* 1-character format code */
|
||||
const char *spec; /* format specifier */
|
||||
const char *head; /* default header in the POSIX locale */
|
||||
} aix_struct;
|
||||
|
||||
typedef struct shortsort_struct {
|
||||
const int desc; /* 1-character format code */
|
||||
const char *spec; /* format specifier */
|
||||
} shortsort_struct;
|
||||
|
||||
/* Save these options for later: -o o -O O --format --sort */
|
||||
typedef struct sf_node {
|
||||
struct sf_node *next; /* next arg */
|
||||
format_node *f_cooked; /* convert each arg alone, then merge */
|
||||
sort_node *s_cooked; /* convert each arg alone, then merge */
|
||||
char *sf;
|
||||
int sf_code;
|
||||
} sf_node;
|
||||
|
||||
|
||||
/*********************** GENERAL GLOBALS *************************/
|
||||
|
||||
/* escape.c */
|
||||
extern int escape_strlist(char *dst, const char **src, size_t n);
|
||||
extern int escape_str(char *dst, const char *src, size_t n);
|
||||
extern int octal_escape_str(char *dst, const char *src, size_t n);
|
||||
extern int simple_escape_str(char *dst, const char *src, size_t n);
|
||||
|
||||
/********************* UNDECIDED GLOBALS **************/
|
||||
|
||||
/*
|
||||
* fputs(3) should (as in "good behavior") return the number of
|
||||
* characters written as it does on Digital Unix, AIX, Irix, and SunOS.
|
||||
* I'll assume glibc 2.1 has this extremely useful feature.
|
||||
*
|
||||
* Note: code ported from other systems will keep breaking until
|
||||
* the library is updated. You should patch the library itself if
|
||||
* at all possible. (for example, distributers who build libc from
|
||||
* source with automatic patching as part of the build process)
|
||||
*/
|
||||
|
||||
#if defined __GLIBC__ && ((__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) || __GLIBC__ > 2)
|
||||
#warning Hopefully fputs(3) has been modernized...
|
||||
#else
|
||||
#define EMULATE_FPUTS
|
||||
#define fputs something_to_avoid_libc_troubles
|
||||
static inline int fputs(const char *s, FILE *fp){
|
||||
return fwrite(s,1,strlen(s),fp);
|
||||
/* return fprintf(fp, "%s", s); */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* output.c */
|
||||
extern void show_one_proc(proc_t* p);
|
||||
extern void print_format_specifiers(void);
|
||||
extern const aix_struct *search_aix_array(const int findme);
|
||||
extern const shortsort_struct *search_shortsort_array(const int findme);
|
||||
extern const format_struct *search_format_array(const char *findme);
|
||||
extern const macro_struct *search_macro_array(const char *findme);
|
||||
extern void init_output(void);
|
||||
|
||||
/* global.c */
|
||||
extern void reset_global(void);
|
||||
|
||||
/* global.c */
|
||||
extern int all_processes;
|
||||
extern char *bsd_j_format;
|
||||
extern char *bsd_l_format;
|
||||
extern char *bsd_s_format;
|
||||
extern char *bsd_u_format;
|
||||
extern char *bsd_v_format;
|
||||
extern int bsd_c_option;
|
||||
extern int bsd_e_option;
|
||||
extern uid_t cached_euid;
|
||||
extern dev_t cached_tty;
|
||||
extern char forest_prefix[4 * 32*1024 + 100];
|
||||
extern int forest_type;
|
||||
extern unsigned format_flags; /* -l -f l u s -j... */
|
||||
extern format_node *format_list; /* digested formatting options */
|
||||
extern unsigned format_modifiers; /* -c -j -y -P -L... */
|
||||
extern int header_gap;
|
||||
extern int header_type; /* none, single, multi... */
|
||||
extern int include_dead_children;
|
||||
extern int lines_to_next_header;
|
||||
extern int max_line_width;
|
||||
extern const char *namelist_file;
|
||||
extern int negate_selection;
|
||||
extern unsigned personality;
|
||||
extern int prefer_bsd_defaults;
|
||||
extern int running_only;
|
||||
extern int screen_cols;
|
||||
extern int screen_rows;
|
||||
extern unsigned long seconds_since_boot;
|
||||
extern selection_node *selection_list;
|
||||
extern unsigned simple_select;
|
||||
extern sort_node *sort_list;
|
||||
extern char *sysv_f_format;
|
||||
extern char *sysv_fl_format;
|
||||
extern char *sysv_j_format;
|
||||
extern char *sysv_l_format;
|
||||
extern int unix_f_option;
|
||||
extern int user_is_number;
|
||||
extern int wchan_is_number;
|
||||
|
||||
/************************* PS GLOBALS *********************/
|
||||
|
||||
/* sortformat.c */
|
||||
extern int defer_sf_option(const char *arg, int source);
|
||||
extern const char *process_sf_options(int localbroken);
|
||||
extern void reset_sortformat(void);
|
||||
|
||||
/* select.c */
|
||||
extern int want_this_proc(proc_t *buf);
|
||||
extern const char *select_bits_setup(void);
|
||||
|
||||
/* help.c */
|
||||
extern const char *help_message;
|
||||
|
||||
/* global.c */
|
||||
extern void self_info(void);
|
||||
|
||||
/* parser.c */
|
||||
extern int arg_parse(int argc, char *argv[]);
|
||||
|
||||
#endif
|
398
ps/display.c
Normal file
398
ps/display.c
Normal file
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* username lookups */
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
/* major/minor number */
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include <signal.h> /* catch signals */
|
||||
|
||||
#include "common.h"
|
||||
#include "../proc/procps.h"
|
||||
#include "../proc/version.h"
|
||||
#include "../proc/readproc.h"
|
||||
#include "../proc/sysinfo.h"
|
||||
|
||||
#ifndef SIGCHLD
|
||||
#define SIGCHLD SIGCLD
|
||||
#endif
|
||||
|
||||
/* just reports a crash */
|
||||
static void signal_handler(int signo){
|
||||
if(signo==SIGPIPE) _exit(0); /* "ps | head" will cause this */
|
||||
/* fprintf() is not reentrant, but we _exit() anyway */
|
||||
fprintf(stderr,
|
||||
"\n\n"
|
||||
"Signal %d caught by ps (%s).\n"
|
||||
"Please send bug reports to <acahalan@cs.uml.edu>\n",
|
||||
signo,
|
||||
procps_version
|
||||
);
|
||||
_exit(signo+128);
|
||||
}
|
||||
|
||||
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
void init_stack_trace(char *prog_name);
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
void hex_dump(void *vp){
|
||||
char *charlist;
|
||||
int i = 0;
|
||||
int line = 45;
|
||||
char *cp = (char *)vp;
|
||||
|
||||
while(line--){
|
||||
printf("%8lx ", (unsigned long)cp);
|
||||
charlist = cp;
|
||||
cp += 16;
|
||||
for(i=0; i<16; i++){
|
||||
if((charlist[i]>31) && (charlist[i]<127)){
|
||||
printf("%c", charlist[i]);
|
||||
}else{
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
printf(" ");
|
||||
for(i=0; i<16; i++) printf(" %2x",(unsigned int)((unsigned char)(charlist[i])));
|
||||
printf("\n");
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_pid(char *s, int n, sel_union *data){
|
||||
printf("%s ", s);
|
||||
while(--n){
|
||||
printf("%d,", data[n].pid);
|
||||
}
|
||||
printf("%d\n", data[0].pid);
|
||||
}
|
||||
|
||||
static void show_uid(char *s, int n, sel_union *data){
|
||||
struct passwd *pw_data;
|
||||
printf("%s ", s);
|
||||
while(--n){
|
||||
pw_data = getpwuid(data[n].uid);
|
||||
if(pw_data) printf("%s,", pw_data->pw_name);
|
||||
else printf("%d,", data[n].uid);
|
||||
}
|
||||
pw_data = getpwuid(data[n].uid);
|
||||
if(pw_data) printf("%s\n", pw_data->pw_name);
|
||||
else printf("%d\n", data[n].uid);
|
||||
}
|
||||
|
||||
static void show_gid(char *s, int n, sel_union *data){
|
||||
struct group *gr_data;
|
||||
printf("%s ", s);
|
||||
while(--n){
|
||||
gr_data = getgrgid(data[n].gid);
|
||||
if(gr_data) printf("%s,", gr_data->gr_name);
|
||||
else printf("%d,", data[n].gid);
|
||||
}
|
||||
gr_data = getgrgid(data[n].gid);
|
||||
if(gr_data) printf("%s\n", gr_data->gr_name);
|
||||
else printf("%d\n", data[n].gid);
|
||||
}
|
||||
|
||||
static void show_tty(char *s, int n, sel_union *data){
|
||||
printf("%s ", s);
|
||||
while(--n){
|
||||
printf("%d:%d,", (int)major(data[n].tty), (int)minor(data[n].tty));
|
||||
}
|
||||
printf("%d:%d\n", (int)major(data[n].tty), (int)minor(data[n].tty));
|
||||
}
|
||||
|
||||
static void show_cmd(char *s, int n, sel_union *data){
|
||||
printf("%s ", s);
|
||||
while(--n){
|
||||
printf("%.8s,", data[n].cmd);
|
||||
}
|
||||
printf("%.8s\n", data[0].cmd);
|
||||
}
|
||||
|
||||
static void arg_show(void){
|
||||
selection_node *walk = selection_list;
|
||||
while(walk){
|
||||
switch(walk->typecode){
|
||||
case SEL_RUID: show_uid("RUID", walk->n, walk->u); break;
|
||||
case SEL_EUID: show_uid("EUID", walk->n, walk->u); break;
|
||||
case SEL_SUID: show_uid("SUID", walk->n, walk->u); break;
|
||||
case SEL_FUID: show_uid("FUID", walk->n, walk->u); break;
|
||||
case SEL_RGID: show_gid("RGID", walk->n, walk->u); break;
|
||||
case SEL_EGID: show_gid("EGID", walk->n, walk->u); break;
|
||||
case SEL_SGID: show_gid("SGID", walk->n, walk->u); break;
|
||||
case SEL_FGID: show_gid("FGID", walk->n, walk->u); break;
|
||||
case SEL_PGRP: show_pid("PGRP", walk->n, walk->u); break;
|
||||
case SEL_PID : show_pid("PID ", walk->n, walk->u); break;
|
||||
case SEL_TTY : show_tty("TTY ", walk->n, walk->u); break;
|
||||
case SEL_SESS: show_pid("SESS", walk->n, walk->u); break;
|
||||
case SEL_COMM: show_cmd("COMM", walk->n, walk->u); break;
|
||||
default: printf("Garbage typecode value!\n");
|
||||
}
|
||||
walk = walk->next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/***** check the header */
|
||||
/* Unix98: must not print empty header */
|
||||
static void check_headers(void){
|
||||
format_node *walk = format_list;
|
||||
int head_normal = 0;
|
||||
if(header_type==HEAD_MULTI){
|
||||
header_gap = screen_rows-1; /* true BSD */
|
||||
return;
|
||||
}
|
||||
if(header_type==HEAD_NONE){
|
||||
lines_to_next_header = -1; /* old Linux */
|
||||
return;
|
||||
}
|
||||
while(walk){
|
||||
if(!*(walk->name)){
|
||||
walk = walk->next;
|
||||
continue;
|
||||
}
|
||||
if(walk->pr){
|
||||
head_normal++;
|
||||
walk = walk->next;
|
||||
continue;
|
||||
}
|
||||
walk = walk->next;
|
||||
}
|
||||
if(!head_normal) lines_to_next_header = -1; /* how UNIX does --noheader */
|
||||
}
|
||||
|
||||
/***** fill in %CPU; not in libproc because of include_dead_children */
|
||||
static void fill_pcpu(proc_t *buf){
|
||||
unsigned long total_time;
|
||||
unsigned long pcpu = 0;
|
||||
unsigned long seconds;
|
||||
|
||||
total_time = buf->utime + buf->stime;
|
||||
if(include_dead_children) total_time += (buf->cutime + buf->cstime);
|
||||
seconds = (seconds_since_boot - ((unsigned long)buf->start_time) / Hertz);
|
||||
if(seconds) pcpu = (total_time * 1000ULL / Hertz) / seconds;
|
||||
buf->pcpu = (pcpu > 999) ? 999 : pcpu;
|
||||
}
|
||||
|
||||
/***** just display */
|
||||
static void simple_spew(void){
|
||||
proc_t buf;
|
||||
PROCTAB* ptp;
|
||||
ptp = openproc(PROC_FILLBUG);
|
||||
if(!ptp) {
|
||||
fprintf(stderr, "Error: can not access /proc.\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(&buf, '#', sizeof(proc_t));
|
||||
/* use "ps_" prefix to catch library mismatch */
|
||||
while(ps_readproc(ptp,&buf)){
|
||||
fill_pcpu(&buf);
|
||||
if(want_this_proc(&buf)) show_one_proc(&buf);
|
||||
/* if(buf.cmdline) free(buf.cmdline); */ /* these crash */
|
||||
/* if(buf.environ) free(buf.environ); */
|
||||
memset(&buf, '#', sizeof(proc_t));
|
||||
}
|
||||
closeproc(ptp);
|
||||
}
|
||||
|
||||
/***** forest output requires sorting by ppid; add start_time by default */
|
||||
static void prep_forest_sort(void){
|
||||
sort_node *tmp_list = sort_list;
|
||||
const format_struct *incoming;
|
||||
|
||||
if(!sort_list) { /* assume start time order */
|
||||
incoming = search_format_array("start_time");
|
||||
if(!incoming) fprintf(stderr, "Could not find start_time!\n");
|
||||
tmp_list = malloc(sizeof(sort_node));
|
||||
tmp_list->reverse = 0;
|
||||
tmp_list->typecode = '?'; /* what was this for? */
|
||||
tmp_list->sr = incoming->sr;
|
||||
tmp_list->next = sort_list;
|
||||
sort_list = tmp_list;
|
||||
}
|
||||
/* this is required for the forest option */
|
||||
incoming = search_format_array("ppid");
|
||||
if(!incoming) fprintf(stderr, "Could not find ppid!\n");
|
||||
tmp_list = malloc(sizeof(sort_node));
|
||||
tmp_list->reverse = 0;
|
||||
tmp_list->typecode = '?'; /* what was this for? */
|
||||
tmp_list->sr = incoming->sr;
|
||||
tmp_list->next = sort_list;
|
||||
sort_list = tmp_list;
|
||||
}
|
||||
|
||||
/* we rely on the POSIX requirement for zeroed memory */
|
||||
static proc_t *processes[32*1024];
|
||||
|
||||
/***** compare function for qsort */
|
||||
static int compare_two_procs(const void *a, const void *b){
|
||||
sort_node *tmp_list = sort_list;
|
||||
while(tmp_list){
|
||||
int result;
|
||||
result = (*tmp_list->sr)(*(const proc_t **)a, *(const proc_t **)b);
|
||||
if(result) return (tmp_list->reverse) ? -result : result;
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
return 0; /* no conclusion */
|
||||
}
|
||||
|
||||
/***** show pre-sorted array of process pointers */
|
||||
static void show_proc_array(int n){
|
||||
proc_t **p = processes;
|
||||
while(n--){
|
||||
show_one_proc(*p);
|
||||
/* if(p->cmdline) free(p->cmdline); */ /* this crashes */
|
||||
/* if(p->environ) free(p->environ); */ /* this crashes */
|
||||
/* memset(*p, '%', sizeof(proc_t)); */ /* debug */
|
||||
free(*p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/***** show tree */
|
||||
/* this needs some optimization work */
|
||||
#define ADOPTED(x) 1
|
||||
static void show_tree(const int self, const int n, const int level, const int have_sibling){
|
||||
int i = 0;
|
||||
if(level){
|
||||
/* add prefix of "+" or "L" */
|
||||
if(have_sibling) forest_prefix[level-1] = '+';
|
||||
else forest_prefix[level-1] = 'L';
|
||||
forest_prefix[level] = '\0';
|
||||
}
|
||||
show_one_proc(processes[self]); /* first show self */
|
||||
/* if(p->cmdline) free(p->cmdline); */ /* this crashes */
|
||||
/* if(p->environ) free(p->environ); */ /* this crashes */
|
||||
/* memset(*p, '%', sizeof(proc_t)); */ /* debug */
|
||||
for(;;){ /* look for children */
|
||||
if(i >= n) return; /* no children */
|
||||
if(processes[i]->ppid == processes[self]->pid) break;
|
||||
i++;
|
||||
}
|
||||
if(level){
|
||||
/* change our prefix to "|" or " " for the children */
|
||||
if(have_sibling) forest_prefix[level-1] = '|';
|
||||
else forest_prefix[level-1] = ' ';
|
||||
forest_prefix[level] = '\0';
|
||||
}
|
||||
for(;;){
|
||||
int self_pid;
|
||||
int more_children = 1;
|
||||
if(i >= n) break; /* over the edge */
|
||||
self_pid=processes[self]->pid;
|
||||
if(i+1 >= n)
|
||||
more_children = 0;
|
||||
else
|
||||
if(processes[i+1]->ppid != self_pid) more_children = 0;
|
||||
if(self_pid==1 && ADOPTED(processes[i]) && forest_type!='u')
|
||||
show_tree(i++, n, level, more_children);
|
||||
else
|
||||
show_tree(i++, n, level+1, more_children);
|
||||
if(!more_children) break;
|
||||
}
|
||||
/* chop prefix that children added -- do we need this? */
|
||||
forest_prefix[level] = '\0';
|
||||
}
|
||||
|
||||
/***** show forest */
|
||||
static void show_forest(const int n){
|
||||
int i = n;
|
||||
int j;
|
||||
while(i--){ /* cover whole array looking for trees */
|
||||
j = n;
|
||||
while(j--){ /* search for parent: if none, i is a tree! */
|
||||
if(processes[j]->pid == processes[i]->ppid) goto not_root;
|
||||
}
|
||||
show_tree(i,n,0,0);
|
||||
not_root:
|
||||
}
|
||||
/* don't free the array because it takes time and ps will exit anyway */
|
||||
}
|
||||
|
||||
/***** sorted or forest */
|
||||
static void fancy_spew(void){
|
||||
proc_t *retbuf;
|
||||
PROCTAB* ptp;
|
||||
int n = 0; /* number of processes & index into array */
|
||||
ptp = openproc(PROC_FILLBUG);
|
||||
if(!ptp) {
|
||||
fprintf(stderr, "Error: can not access /proc.\n");
|
||||
exit(1);
|
||||
}
|
||||
while((retbuf = ps_readproc(ptp,NULL))){
|
||||
fill_pcpu(retbuf);
|
||||
if(want_this_proc(retbuf)) processes[n++] = retbuf;
|
||||
else free(retbuf);
|
||||
}
|
||||
closeproc(ptp);
|
||||
if(!n) return; /* no processes */
|
||||
if(forest_type) prep_forest_sort();
|
||||
qsort(processes, n, sizeof(proc_t*), compare_two_procs);
|
||||
if(forest_type) show_forest(n);
|
||||
else show_proc_array(n);
|
||||
}
|
||||
|
||||
|
||||
/***** no comment */
|
||||
int main(int argc, char *argv[]){
|
||||
#ifdef DEBUG
|
||||
init_stack_trace(argv[0]);
|
||||
#else
|
||||
do {
|
||||
struct sigaction sa;
|
||||
int i = 32;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = signal_handler;
|
||||
sigfillset(&sa.sa_mask);
|
||||
while(i--) switch(i){
|
||||
default:
|
||||
sigaction(i,&sa,NULL);
|
||||
case 0:
|
||||
case SIGINT: /* ^C */
|
||||
case SIGQUIT: /* ^\ */
|
||||
case SIGPROF: /* profiling */
|
||||
case SIGKILL: /* can not catch */
|
||||
case SIGSTOP: /* can not catch */
|
||||
case SIGWINCH: /* don't care if window size changes */
|
||||
}
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
reset_global(); /* must be before parser */
|
||||
arg_parse(argc,argv);
|
||||
|
||||
/* arg_show(); */
|
||||
trace("screen is %ux%u\n",screen_cols,screen_rows);
|
||||
/* printf("sizeof(proc_t) is %d.\n", sizeof(proc_t)); */
|
||||
trace("======= ps output follows =======\n");
|
||||
|
||||
init_output(); /* must be between parser and output */
|
||||
check_headers();
|
||||
if (open_psdb(namelist_file)) wchan_is_number = 1;
|
||||
if(forest_type || sort_list) fancy_spew(); /* sort or forest */
|
||||
else simple_spew(); /* no sort, no forest */
|
||||
show_one_proc((proc_t *)-1); /* no output yet? */
|
||||
return 0;
|
||||
}
|
106
ps/escape.c
Normal file
106
ps/escape.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
|
||||
/* sanitize a string, without the nice BSD library function: */
|
||||
/* strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH) */
|
||||
int octal_escape_str(char *dst, const char *src, size_t n){
|
||||
unsigned char c;
|
||||
char d;
|
||||
size_t i;
|
||||
const char *codes =
|
||||
"Z------abtnvfr-------------e----"
|
||||
" *******************************" /* better: do not print any space */
|
||||
"****************************\\***"
|
||||
"*******************************-"
|
||||
"--------------------------------"
|
||||
"********************************"
|
||||
"********************************"
|
||||
"********************************";
|
||||
for(i=0; i<n;){
|
||||
c = (unsigned char) *(src++);
|
||||
d = codes[c];
|
||||
switch(d){
|
||||
case 'Z':
|
||||
goto leave;
|
||||
case '*':
|
||||
i++;
|
||||
*(dst++) = c;
|
||||
break;
|
||||
case '-':
|
||||
if(i+4 > n) goto leave;
|
||||
i += 4;
|
||||
*(dst++) = '\\';
|
||||
*(dst++) = "01234567"[c>>6];
|
||||
*(dst++) = "01234567"[(c>>3)&07];
|
||||
*(dst++) = "01234567"[c&07];
|
||||
break;
|
||||
default:
|
||||
if(i+2 > n) goto leave;
|
||||
i += 2;
|
||||
*(dst++) = '\\';
|
||||
*(dst++) = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
leave:
|
||||
*(dst++) = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/* sanitize a string via one-way mangle */
|
||||
int simple_escape_str(char *dst, const char *src, size_t n){
|
||||
unsigned char c;
|
||||
size_t i;
|
||||
const char *codes =
|
||||
"Z-------------------------------"
|
||||
"********************************"
|
||||
"********************************"
|
||||
"*******************************-"
|
||||
"--------------------------------"
|
||||
"********************************"
|
||||
"********************************"
|
||||
"********************************";
|
||||
for(i=0; i<n;){
|
||||
c = (unsigned char) *(src++);
|
||||
switch(codes[c]){
|
||||
case 'Z':
|
||||
goto leave;
|
||||
case '*':
|
||||
i++;
|
||||
*(dst++) = c;
|
||||
break;
|
||||
case '-':
|
||||
i++;
|
||||
*(dst++) = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
leave:
|
||||
*(dst++) = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/* escape a string as desired */
|
||||
int escape_str(char *dst, const char *src, size_t n){
|
||||
return simple_escape_str(dst, src, n);
|
||||
}
|
||||
|
||||
/* escape an argv or environment string array */
|
||||
int escape_strlist(char *dst, const char **src, size_t n){
|
||||
size_t i = 0;
|
||||
while(*src){
|
||||
i += simple_escape_str(dst+i, *src, n-i);
|
||||
if((n-i > 1) && (*(src+1))) dst[i++] = ' ';
|
||||
src++;
|
||||
}
|
||||
return i;
|
||||
}
|
422
ps/global.c
Normal file
422
ps/global.c
Normal file
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <string.h>
|
||||
|
||||
/*#undef __GLIBC_MINOR__
|
||||
#define __GLIBC_MINOR__ 1 */
|
||||
#include "common.h"
|
||||
/*#undef __GLIBC_MINOR__
|
||||
#define __GLIBC_MINOR__ 0 */
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include "../proc/version.h"
|
||||
#include "../proc/sysinfo.h"
|
||||
|
||||
|
||||
#ifndef __GNU_LIBRARY__
|
||||
#define __GNU_LIBRARY__ -1
|
||||
#endif
|
||||
#ifndef __GLIBC__
|
||||
#define __GLIBC__ -1
|
||||
#endif
|
||||
#ifndef __GLIBC_MINOR__
|
||||
#define __GLIBC_MINOR__ -1
|
||||
#endif
|
||||
|
||||
|
||||
static char *saved_personality_text = "You found a bug!";
|
||||
|
||||
int all_processes = -1;
|
||||
char *bsd_j_format = (char *)0xdeadbeef;
|
||||
char *bsd_l_format = (char *)0xdeadbeef;
|
||||
char *bsd_s_format = (char *)0xdeadbeef;
|
||||
char *bsd_u_format = (char *)0xdeadbeef;
|
||||
char *bsd_v_format = (char *)0xdeadbeef;
|
||||
int bsd_c_option = -1;
|
||||
int bsd_e_option = -1;
|
||||
uid_t cached_euid = -1;
|
||||
dev_t cached_tty = -1;
|
||||
char forest_prefix[4 * 32*1024 + 100];
|
||||
int forest_type = -1;
|
||||
unsigned format_flags = 0xffffffff; /* -l -f l u s -j... */
|
||||
format_node *format_list = (format_node *)0xdeadbeef; /* digested formatting options */
|
||||
unsigned format_modifiers = 0xffffffff; /* -c -j -y -P -L... */
|
||||
int header_gap = -1;
|
||||
int header_type = -1;
|
||||
int include_dead_children = -1;
|
||||
int lines_to_next_header = -1;
|
||||
const char *namelist_file = (const char *)0xdeadbeef;
|
||||
int negate_selection = -1;
|
||||
int running_only = -1;
|
||||
unsigned personality = 0xffffffff;
|
||||
int prefer_bsd_defaults = -1;
|
||||
int screen_cols = -1;
|
||||
int screen_rows = -1;
|
||||
unsigned long seconds_since_boot = -1;
|
||||
selection_node *selection_list = (selection_node *)0xdeadbeef;
|
||||
unsigned simple_select = 0xffffffff;
|
||||
sort_node *sort_list = (sort_node *)0xdeadbeef; /* ready-to-use sort list */
|
||||
char *sysv_f_format = (char *)0xdeadbeef;
|
||||
char *sysv_fl_format = (char *)0xdeadbeef;
|
||||
char *sysv_j_format = (char *)0xdeadbeef;
|
||||
char *sysv_l_format = (char *)0xdeadbeef;
|
||||
int unix_f_option = -1;
|
||||
int user_is_number = -1;
|
||||
int wchan_is_number = -1;
|
||||
|
||||
|
||||
static void reset_selection_list(void){
|
||||
selection_node *old;
|
||||
selection_node *walk = selection_list;
|
||||
if(selection_list == (selection_node *)0xdeadbeef){
|
||||
selection_list = NULL;
|
||||
return;
|
||||
}
|
||||
while(walk){
|
||||
old = walk;
|
||||
walk = old->next;
|
||||
free(old->u);
|
||||
free(old);
|
||||
}
|
||||
selection_list = NULL;
|
||||
}
|
||||
|
||||
/* The rules:
|
||||
* 1. Defaults are implementation-specific. (ioctl,termcap,guess)
|
||||
* 2. COLUMNS and LINES override the defaults. (standards compliance)
|
||||
* 3. Command line options override everything else.
|
||||
* 4. Actual output may be more if the above is too narrow.
|
||||
*/
|
||||
static void set_screen_size(void){
|
||||
struct winsize ws;
|
||||
char *columns; /* Unix98 environment variable */
|
||||
char *lines; /* Unix98 environment variable */
|
||||
if(ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0){
|
||||
screen_cols = ws.ws_col;
|
||||
screen_rows = ws.ws_row;
|
||||
}else{ /* TODO: ought to do tgetnum("co") and tgetnum("li") now */
|
||||
screen_cols = 80;
|
||||
screen_rows = 24;
|
||||
}
|
||||
if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;
|
||||
columns = getenv("COLUMNS");
|
||||
if(columns && *columns){
|
||||
long t;
|
||||
char *endptr;
|
||||
t = strtol(columns, &endptr, 0);
|
||||
if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_cols = (int)t;
|
||||
}
|
||||
lines = getenv("LINES");
|
||||
if(lines && *lines){
|
||||
long t;
|
||||
char *endptr;
|
||||
t = strtol(lines, &endptr, 0);
|
||||
if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_rows = (int)t;
|
||||
}
|
||||
if((screen_cols<9) || (screen_rows<2))
|
||||
fprintf(stderr,"Your %dx%d screen size is bogus. Expect trouble.\n",
|
||||
screen_cols, screen_rows
|
||||
);
|
||||
}
|
||||
|
||||
/**************** personality control **************/
|
||||
|
||||
typedef struct personality_table_struct {
|
||||
const char *name; /* personality name */
|
||||
const void *jump; /* See gcc extension info. :-) */
|
||||
} personality_table_struct;
|
||||
|
||||
static int compare_personality_table_structs(const void *a, const void *b){
|
||||
return strcasecmp(((personality_table_struct*)a)->name,((personality_table_struct*)b)->name);
|
||||
}
|
||||
|
||||
static const char *set_personality(void){
|
||||
char *s;
|
||||
size_t sl;
|
||||
char buf[16];
|
||||
personality_table_struct findme = { buf, NULL};
|
||||
personality_table_struct *found;
|
||||
static const personality_table_struct personality_table[] = {
|
||||
{"390", &&case_390},
|
||||
{"aix", &&case_aix},
|
||||
{"bsd", &&case_bsd},
|
||||
{"compaq", &&case_compaq},
|
||||
{"debian", &&case_debian},
|
||||
{"default", &&case_default},
|
||||
{"digital", &&case_digital},
|
||||
{"gnu", &&case_gnu},
|
||||
{"hp", &&case_hp},
|
||||
{"hpux", &&case_hpux},
|
||||
{"irix", &&case_irix},
|
||||
{"linux", &&case_linux},
|
||||
{"old", &&case_old},
|
||||
{"os390", &&case_os390},
|
||||
{"posix", &&case_posix},
|
||||
{"s390", &&case_s390},
|
||||
{"sco", &&case_sco},
|
||||
{"sgi", &&case_sgi},
|
||||
{"solaris2", &&case_solaris2},
|
||||
{"sunos4", &&case_sunos4},
|
||||
{"sysv", &&case_sysv},
|
||||
{"tru64", &&case_tru64},
|
||||
{"unix", &&case_unix},
|
||||
{"unix95", &&case_unix95},
|
||||
{"unix98", &&case_unix98},
|
||||
{"unknown", &&case_unknown}
|
||||
};
|
||||
const int personality_table_count = sizeof(personality_table)/sizeof(personality_table_struct);
|
||||
|
||||
personality = 0;
|
||||
prefer_bsd_defaults = 0;
|
||||
|
||||
bsd_j_format = "OL_j";
|
||||
bsd_l_format = "OL_l";
|
||||
bsd_s_format = "OL_s";
|
||||
bsd_u_format = "OL_u";
|
||||
bsd_v_format = "OL_v";
|
||||
|
||||
/* When these are NULL, the code does SysV output modifier logic */
|
||||
sysv_f_format = NULL;
|
||||
sysv_fl_format = NULL;
|
||||
sysv_j_format = NULL;
|
||||
sysv_l_format = NULL;
|
||||
|
||||
s = getenv("PS_PERSONALITY");
|
||||
if(!s || !*s) s = getenv("CMD_ENV");
|
||||
if(!s || !*s) s="unknown"; /* "Do The Right Thing[tm]" */
|
||||
if(getenv("I_WANT_A_BROKEN_PS")) s="old";
|
||||
sl = strlen(s);
|
||||
if(sl > 15) return "Environment specified an unknown personality.";
|
||||
strncpy(buf, s, sl);
|
||||
buf[sl] = '\0';
|
||||
saved_personality_text = strdup(buf);
|
||||
|
||||
found = bsearch(&findme, personality_table, personality_table_count,
|
||||
sizeof(personality_table_struct), compare_personality_table_structs
|
||||
);
|
||||
|
||||
if(!found) return "Environment specified an unknown personality.";
|
||||
|
||||
goto *(found->jump); /* See gcc extension info. :-) */
|
||||
|
||||
case_bsd:
|
||||
personality = PER_FORCE_BSD | PER_BSD_h | PER_BSD_m;
|
||||
prefer_bsd_defaults = 1;
|
||||
bsd_j_format = "FB_j";
|
||||
bsd_l_format = "FB_l";
|
||||
/* bsd_s_format not used */
|
||||
bsd_u_format = "FB_u";
|
||||
bsd_v_format = "FB_v";
|
||||
return NULL;
|
||||
|
||||
case_old:
|
||||
personality = PER_FORCE_BSD | PER_OLD_m;
|
||||
prefer_bsd_defaults = 1;
|
||||
return NULL;
|
||||
|
||||
case_debian: /* Toss this? They don't seem to care much. */
|
||||
case_gnu:
|
||||
personality = PER_GOOD_o | PER_CUMUL_MARKED | PER_OLD_m;
|
||||
prefer_bsd_defaults = 1;
|
||||
sysv_f_format = "RD_f";
|
||||
/* sysv_fl_format = "RD_fl"; */ /* Debian can't do this! */
|
||||
sysv_j_format = "RD_j";
|
||||
sysv_l_format = "RD_l";
|
||||
return NULL;
|
||||
|
||||
case_linux:
|
||||
personality = PER_GOOD_o | PER_ZAP_ADDR | PER_SANE_USER;
|
||||
return NULL;
|
||||
|
||||
case_default: /* use defaults for ps, ignoring other environment variables */
|
||||
return NULL;
|
||||
|
||||
case_unknown: /* defaults, but also check inferior environment variables */
|
||||
if(
|
||||
getenv("UNIX95") /* Irix */
|
||||
|| getenv("POSIXLY_CORRECT") /* most gnu stuff */
|
||||
|| (getenv("POSIX2") && !strcmp(getenv("POSIX2"), "on")) /* Unixware 7 */
|
||||
) personality = PER_BROKEN_o;
|
||||
return NULL;
|
||||
|
||||
case_aix:
|
||||
bsd_j_format = "FB_j";
|
||||
bsd_l_format = "FB_l";
|
||||
/* bsd_s_format not used */
|
||||
bsd_u_format = "FB_u";
|
||||
bsd_v_format = "FB_v";
|
||||
return NULL;
|
||||
|
||||
case_tru64:
|
||||
case_compaq:
|
||||
case_digital:
|
||||
personality = PER_GOOD_o | PER_BSD_h;
|
||||
prefer_bsd_defaults = 1;
|
||||
sysv_f_format = "F5FMT";
|
||||
sysv_fl_format = "FL5FMT";
|
||||
sysv_j_format = "JFMT";
|
||||
sysv_l_format = "L5FMT";
|
||||
bsd_j_format = "JFMT";
|
||||
bsd_l_format = "LFMT";
|
||||
bsd_s_format = "SFMT";
|
||||
bsd_u_format = "UFMT";
|
||||
bsd_v_format = "VFMT";
|
||||
return NULL;
|
||||
|
||||
case_sunos4:
|
||||
personality = PER_NO_DEFAULT_g;
|
||||
prefer_bsd_defaults = 1;
|
||||
bsd_j_format = "FB_j";
|
||||
bsd_l_format = "FB_l";
|
||||
/* bsd_s_format not used */
|
||||
bsd_u_format = "FB_u";
|
||||
bsd_v_format = "FB_v";
|
||||
return NULL;
|
||||
|
||||
case_irix:
|
||||
case_sgi:
|
||||
s = getenv("_XPG");
|
||||
if(s && s[0]>'0' && s[0]<='9') personality = PER_BROKEN_o;
|
||||
else personality = PER_IRIX_l;
|
||||
return NULL;
|
||||
|
||||
case_os390: /* IBM's OS/390 OpenEdition on the S/390 mainframe */
|
||||
case_s390:
|
||||
case_390:
|
||||
sysv_j_format = "J390"; /* don't know what -jl and -jf do */
|
||||
return NULL;
|
||||
|
||||
case_hp:
|
||||
case_hpux:
|
||||
case_posix:
|
||||
case_sco:
|
||||
case_solaris2:
|
||||
case_sysv:
|
||||
case_unix95:
|
||||
case_unix98:
|
||||
case_unix:
|
||||
personality = PER_BROKEN_o;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/************ Call this to reinitialize everything ***************/
|
||||
void reset_global(void){
|
||||
static proc_t p;
|
||||
reset_selection_list();
|
||||
look_up_our_self(&p);
|
||||
set_screen_size();
|
||||
set_personality();
|
||||
|
||||
all_processes = 0;
|
||||
bsd_c_option = 0;
|
||||
bsd_e_option = 0;
|
||||
cached_euid = geteuid();
|
||||
cached_tty = p.tty;
|
||||
/* forest_prefix must be all zero because of POSIX */
|
||||
forest_type = 0;
|
||||
format_flags = 0; /* -l -f l u s -j... */
|
||||
format_list = NULL; /* digested formatting options */
|
||||
format_modifiers = 0; /* -c -j -y -P -L... */
|
||||
header_gap = -1; /* send lines_to_next_header to -infinity */
|
||||
header_type = HEAD_SINGLE;
|
||||
include_dead_children = 0;
|
||||
lines_to_next_header = 1;
|
||||
namelist_file = NULL;
|
||||
negate_selection = 0;
|
||||
running_only = 0;
|
||||
seconds_since_boot = uptime(0,0);
|
||||
selection_list = NULL;
|
||||
simple_select = 0;
|
||||
sort_list = NULL;
|
||||
unix_f_option = 0;
|
||||
user_is_number = 0;
|
||||
wchan_is_number = 0;
|
||||
}
|
||||
|
||||
/*********** spew variables ***********/
|
||||
void self_info(void){
|
||||
#ifndef EMULATE_FPUTS
|
||||
int count;
|
||||
#endif
|
||||
fprintf(stderr,
|
||||
"BSD j %s\n"
|
||||
"BSD l %s\n"
|
||||
"BSD s %s\n"
|
||||
"BSD u %s\n"
|
||||
"BSD v %s\n"
|
||||
"SysV -f %s\n"
|
||||
"SysV -fl %s\n"
|
||||
"SysV -j %s\n"
|
||||
"SysV -l %s\n"
|
||||
"\n",
|
||||
bsd_j_format ? bsd_j_format : "(none)",
|
||||
bsd_l_format ? bsd_l_format : "(none)",
|
||||
bsd_s_format ? bsd_s_format : "(none)",
|
||||
bsd_u_format ? bsd_u_format : "(none)",
|
||||
bsd_v_format ? bsd_v_format : "(none)",
|
||||
sysv_f_format ? sysv_f_format : "(none)",
|
||||
sysv_fl_format ? sysv_fl_format : "(none)",
|
||||
sysv_j_format ? sysv_j_format : "(none)",
|
||||
sysv_l_format ? sysv_l_format : "(none)"
|
||||
);
|
||||
|
||||
display_version();
|
||||
fprintf(stderr, "Linux version %d.%d.%d\n",
|
||||
LINUX_VERSION_MAJOR(linux_version_code),
|
||||
LINUX_VERSION_MINOR(linux_version_code),
|
||||
LINUX_VERSION_PATCH(linux_version_code)
|
||||
);
|
||||
/* __libc_print_version(); */ /* how can we get the run-time version? */
|
||||
fprintf(stderr, "Compiled with: libc %d, internal version %d.%d\n\n",
|
||||
__GNU_LIBRARY__, __GLIBC__, __GLIBC_MINOR__
|
||||
);
|
||||
|
||||
#ifdef EMULATE_FPUTS
|
||||
fprintf(stderr, "libc assumed lame, using fprintf to emulate fputs.\n\n");
|
||||
#else
|
||||
fprintf(stderr, "fputs(\"");
|
||||
count = fputs("123456789", stderr);
|
||||
fprintf(stderr, "\", stderr) gives %d, which is %s.\n",
|
||||
count, count==9?"good":"BAD!\nAdjust ps/common.h or libc, then recompile"
|
||||
);
|
||||
if(count!=9){
|
||||
fprintf(stderr, "(procps includes a libc patch called glibc.patch)\n");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr,
|
||||
"header_gap=%d lines_to_next_header=%d\n"
|
||||
"screen_cols=%d screen_rows=%d\n"
|
||||
"\n",
|
||||
header_gap, lines_to_next_header,
|
||||
screen_cols, screen_rows
|
||||
);
|
||||
|
||||
/* open_psdb(namelist_file); */
|
||||
fprintf(stderr,
|
||||
"personality=0x%08x (from \"%s\")\n"
|
||||
"EUID=%d TTY=%d,%d Hertz=%ld\n"
|
||||
/* "namelist_file=\"%s\"\n" */
|
||||
,
|
||||
personality, saved_personality_text,
|
||||
cached_euid, (int)major(cached_tty), (int)minor(cached_tty), Hertz /* ,
|
||||
namelist_file?namelist_file:"<no System.map file>" */
|
||||
);
|
||||
}
|
49
ps/help.c
Normal file
49
ps/help.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights reserved.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The help message must not become longer, because it must fit
|
||||
* on an 80x24 screen _with_ the error message and command prompt.
|
||||
*/
|
||||
|
||||
|
||||
const char *help_message =
|
||||
"********* simple selection ********* ********* selection by list *********\n"
|
||||
"-A all processes -C by command name\n"
|
||||
"-N negate selection -G by real group ID (supports names)\n"
|
||||
"-a all w/ tty except session leaders -U by real user ID (supports names)\n"
|
||||
"-d all except session leaders -g by session leader OR by group name\n"
|
||||
"-e all processes -p by process ID\n"
|
||||
"T all processes on this terminal -s processes in the sessions given\n"
|
||||
"a all w/ tty, including other users -t by tty\n"
|
||||
"g all, even group leaders! -u by effective user ID (supports names)\n"
|
||||
"r only running processes U processes for specified users\n"
|
||||
"x processes w/o controlling ttys t by tty\n"
|
||||
"*********** output format ********** *********** long options ***********\n"
|
||||
"-o,o user-defined -f full --Group --User --pid --cols\n"
|
||||
"-j,j job control s signal --group --user --sid --rows\n"
|
||||
"-O,O preloaded -o v virtual memory --cumulative --format --deselect\n"
|
||||
"-l,l long u user-oriented --sort --tty --forest --version\n"
|
||||
" X registers --heading --no-heading\n"
|
||||
" ********* misc options *********\n"
|
||||
"-V,V show version L list format codes f ASCII art forest\n"
|
||||
"-m,m show threads S children in sum -y change -l format\n"
|
||||
"-n,N set namelist file c true command name n numeric WCHAN,UID\n"
|
||||
"-w,w wide output e show environment -H process heirarchy\n"
|
||||
;
|
||||
|
||||
|
||||
|
||||
/* Missing:
|
||||
*
|
||||
* -c -L -P -M --info
|
||||
*
|
||||
*/
|
35
ps/it
Normal file
35
ps/it
Normal file
@@ -0,0 +1,35 @@
|
||||
From ddainese@dsi.unive.it Sun Apr 18 14:12:27 1999
|
||||
|
||||
here is a first translation of the text:
|
||||
---------------------------------------------------------------------
|
||||
const char *help_message =
|
||||
"****** seleziona i processi ******* * seleziona una lista specificando: *\n"
|
||||
"-A tutti -C il nome del comando\n"
|
||||
"-N nega la selezione -G il real group ID (supporta i nomi)\n"
|
||||
"-a con tty, tranne i session leader -U il real user ID (supporta i nomi)\n"
|
||||
"-d tutti, tranne i session leader -g il session leader OPPURE il gruppo\n"
|
||||
"-e tutti -p l'ID del processo\n"
|
||||
"T su questo terminale -s la sessione\n"
|
||||
"a con tty, di tutti gli utenti -t il tty\n"
|
||||
"g tutti, anche i leader di gruppo -u l'effective user ID (supporta i nomi)\n"
|
||||
"r in stato running U una lista di utenti\n"
|
||||
"x senza tty t il tty\n"
|
||||
"******** formato dell'output ****** ********** opzioni lunghe **********\n"
|
||||
"-o,o definito dall'utente --Group --User --pid --cols\n"
|
||||
"-j,j job s segnali --group --user --sid --rows\n"
|
||||
"-O,O -o preimpostato v memoria virtuale --cumulative --format --deselect\n"
|
||||
"-l,l lungo u utenti --sort --tty --forest --version\n"
|
||||
"-f completo X registri --heading --no-heading\n"
|
||||
" ******** opzioni varie *********\n"
|
||||
"-V,V versione L codici di formato f foresta di ASCII\n"
|
||||
"-m,m vista ad albero S figli in sum -y cambia il formato -l\n"
|
||||
"-n,N namelist file c nome reale del comando n WCHAN,UID numerici\n"
|
||||
"-w,w output ampio e mostra l'environment -H gerarchia dei processi\n"
|
||||
;
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Unfortunately it isn't really understandable for a newbie, because
|
||||
there is too little space for a good translation; to make it more
|
||||
meaningful, I would need about an entire line for every option, thus
|
||||
if you really want the help text stays under 22 lines, it must
|
||||
contains only 22 options. What do you think about it?
|
1608
ps/output.c
Normal file
1608
ps/output.c
Normal file
File diff suppressed because it is too large
Load Diff
6
ps/p
Executable file
6
ps/p
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Wow, using $* causes great pain with: ps "pid,user pcpu,pmem"
|
||||
# The "$@" won't break that into 2 arguments.
|
||||
#
|
||||
LD_PRELOAD=../proc/libproc.so exec ./ps "$@"
|
1123
ps/parser.c
Normal file
1123
ps/parser.c
Normal file
File diff suppressed because it is too large
Load Diff
521
ps/ps.1
Normal file
521
ps/ps.1
Normal file
@@ -0,0 +1,521 @@
|
||||
.\" Man page for ps.
|
||||
.\" Quick hack conversion by Albert Cahalan, 1998.
|
||||
.\" Licensed under version 2 of the Gnu General Public License.
|
||||
.\"
|
||||
.\" This man page is a horrid hack because *roff sucks.
|
||||
.\" The whole system is way obsolete. The internal header
|
||||
.\" stuff must die, and will when I figure out how to kill it.
|
||||
.\" I've already killed the wasteful left margin and screwy
|
||||
.\" old perfect justification. Gross! You'd think someone
|
||||
.\" invented this crap in 1973. Oh yeah, they did. Sorry.
|
||||
.\"
|
||||
.TH PS 1 "July 5, 1998" "Linux" "Linux User's Manual"
|
||||
.SH \fRNAME\fR
|
||||
ps \- report process status
|
||||
.ad r
|
||||
.na
|
||||
.ss 12 0
|
||||
.in 0
|
||||
.nh
|
||||
.nf
|
||||
|
||||
SYNOPSIS
|
||||
ps [options]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
ps gives a snapshot of the current processes. If you want
|
||||
a repetitive update of this status, use top. This man
|
||||
page documents the /proc-based version of ps, or tries to.
|
||||
|
||||
|
||||
COMMAND-LINE OPTIONS
|
||||
|
||||
This version of ps accepts several kinds of options.
|
||||
|
||||
Unix options may be grouped and must be preceeded by a dash.
|
||||
BSD options may be grouped and must not be used with a dash.
|
||||
Gnu long options are preceeded by two dashes.
|
||||
|
||||
Options of different types may be freely mixed.
|
||||
|
||||
Set the I_WANT_A_BROKEN_PS environment variable to force BSD syntax even
|
||||
when options are preceeded by a dash. The PS_PERSONALITY environment
|
||||
variable (described below) provides more detailed control of ps behavior.
|
||||
|
||||
SIMPLE PROCESS SELECTION
|
||||
-A select all processes
|
||||
-N negate selection
|
||||
-a select all with a tty except session leaders
|
||||
-d select all, but omit session leaders
|
||||
-e select all processes
|
||||
T select all processes on this terminal
|
||||
a select all processes on a terminal, including those of other users
|
||||
g really all, even group leaders (does nothing w/o SunOS settings)
|
||||
r restrict output to running processes
|
||||
x select processes without controlling ttys
|
||||
--deselect negate selection
|
||||
|
||||
PROCESS SELECTION BY LIST
|
||||
-C select by command name
|
||||
-G select by RGID (supports names)
|
||||
-U select by RUID (supports names)
|
||||
-g select by session leader OR by group name
|
||||
-p select by PID
|
||||
-s select processes belonging to the sessions given
|
||||
-t select by tty
|
||||
-u select by effective user ID (supports names)
|
||||
U select processes for specified users
|
||||
p select by process ID
|
||||
t select by tty
|
||||
--Group select by real group name or ID
|
||||
--User select by real user name or ID
|
||||
--group select by effective group name or ID
|
||||
--pid select by process ID
|
||||
--sid select by session ID
|
||||
--tty select by terminal
|
||||
--user select by effective user name or ID
|
||||
-123 implied --sid
|
||||
123 implied --pid
|
||||
|
||||
OUTPUT FORMAT CONTROL
|
||||
-O is preloaded "-o"
|
||||
-c different scheduler info for -l option
|
||||
-f does full listing
|
||||
-j jobs format
|
||||
-l long format
|
||||
-o user-defined format
|
||||
-y do not show flags; show rss in place of addr
|
||||
O is preloaded "o" (overloaded)
|
||||
X old Linux i386 register format
|
||||
j job control format
|
||||
l display long format
|
||||
o specify user-defined format
|
||||
s display signal format
|
||||
u display user-oriented format
|
||||
v display virtual memory format
|
||||
--format user-defined format
|
||||
|
||||
OUTPUT MODIFIERS
|
||||
-H show process hierarchy (forest)
|
||||
-m show threads
|
||||
-n set namelist file
|
||||
-w wide output
|
||||
C use raw CPU time for %CPU instead of decaying average
|
||||
N specify namelist file
|
||||
O sorting order (overloaded)
|
||||
S include some dead child process data (as a sum with the parent)
|
||||
c true command name
|
||||
e show environment after the command
|
||||
f ASCII-art process hierarchy (forest)
|
||||
h no header (or, one header per screen in the BSD personality)
|
||||
m all threads
|
||||
n numeric output for WCHAN and USER
|
||||
w wide output
|
||||
--cols set screen width
|
||||
--columns set screen width
|
||||
--cumulative include some dead child process data (as a sum with the parent)
|
||||
--forest ASCII art process tree
|
||||
--headers repeat header lines, one per page of output
|
||||
--no-headers print no header line at all
|
||||
--lines set screen height
|
||||
--rows set screen height
|
||||
--sort specify sorting order
|
||||
--width set screen width
|
||||
|
||||
INFORMATION
|
||||
-V print version
|
||||
L list all format specifiers
|
||||
V show version info
|
||||
--help print help message
|
||||
--info print debugging info
|
||||
--version print version
|
||||
|
||||
OBSOLETE
|
||||
A increases the argument space (DecUnix)
|
||||
M use alternate core (try -n or N instead)
|
||||
W get swap info from ... not /dev/drum (try -n or N instead)
|
||||
k use /vmcore as c-dumpfile (try -n or N instead)
|
||||
|
||||
|
||||
|
||||
NOTES
|
||||
|
||||
The "-g" option can select by session leader OR by group name.
|
||||
Selection by session leader is specified by many standards,
|
||||
but selection by group is the logical behavior that several other
|
||||
operating systems use. This ps will select by session leader when
|
||||
the list is completely numeric (as sessions are). Group ID numbers
|
||||
will work only when some group names are also specified.
|
||||
|
||||
The "m" option should not be used. Use "-m" or "-o" with a list.
|
||||
("m" displays memory info, shows threads, or sorts by memory use)
|
||||
|
||||
The "h" option is problematic. Standard BSD ps uses the option to
|
||||
print a header on each page of output, but older Linux ps uses the option
|
||||
to totally disable the header. This version of ps follows the Linux
|
||||
usage of not printing the header unless the BSD personality has been
|
||||
selected, in which case it prints a header on each page of output.
|
||||
Regardless of the current personality, you can use the long options
|
||||
--headers and --no-headers to enable printing headers each page and
|
||||
disable headers entirely, respectively.
|
||||
|
||||
Terminals (ttys, or screens for text output) can be specified in several
|
||||
forms: /dev/ttyS1, ttyS1, S1. Obsolete "ps t" (your own terminal) and
|
||||
"ps t?" (processes without a terminal) syntax is supported, but modern
|
||||
options ("T", "-t" with list, "x", "t" with list) should be used instead.
|
||||
|
||||
The BSD "O" option can act like "-O" (user-defined output format with
|
||||
some common fields predefined) or can be used to specify sort order.
|
||||
Heuristics are used to determine the behavior of this option. To ensure
|
||||
that the desired behavior is obtained, specify the other option (sorting
|
||||
or formatting) in some other way.
|
||||
|
||||
For sorting, BSD "O" option syntax is O[+|-]k1[,[+|-]k2[,...]]
|
||||
Order the process listing according to the multilevel sort specified by
|
||||
the sequence of short keys from SORT KEYS, k1, k2, ... The `+' is quite
|
||||
optional, merely re-iterating the default direction on a key. `-' reverses
|
||||
direction only on the key it precedes. The O option must be the last option
|
||||
in a single command argument, but specifications in successive arguments are
|
||||
catenated.
|
||||
|
||||
Gnu sorting syntax is --sortX[+|-]key[,[+|-]key[,...]]
|
||||
Choose a multi-letter key from the SORT KEYS section. X may be any
|
||||
convenient separator character. To be GNU-ish use `='. The `+' is really
|
||||
optional since default direction is increasing numerical or lexicographic
|
||||
order. For example, ps jax --sort=uid,-ppid,+pid
|
||||
|
||||
This ps works by reading the virtual files in /proc. This ps does not
|
||||
need to be suid kmem or have any privileges to run. Do not give this ps
|
||||
any special permissions.
|
||||
|
||||
This ps needs access to a namelist file for proper WCHAN display.
|
||||
The namelist file must match the current Linux kernel exactly for
|
||||
correct output.
|
||||
|
||||
To produce the WCHAN field, ps needs to read the System.map file created
|
||||
when the kernel is compiled. The search path is:
|
||||
|
||||
$PS_SYSTEM_MAP
|
||||
/boot/System.map-`uname -r`
|
||||
/boot/System.map
|
||||
/lib/modules/`uname -r`/System.map
|
||||
/usr/src/linux/System.map
|
||||
|
||||
The member used_math of task_struct is not shown, since crt0.s checks
|
||||
to see if math is present. This causes the math flag to be set for all
|
||||
processes, and so it is worthless. (Somebody fix libc or the kernel please)
|
||||
|
||||
Programs swapped out to disk will be shown without command line arguments,
|
||||
and unless the c option is given, in brackets.
|
||||
|
||||
%CPU shows the cputime/realtime percentage. It will not add up to 100%
|
||||
unless you are lucky. It is time used divided by the time the process has
|
||||
been running.
|
||||
|
||||
The SIZE and RSS fields don't count the page tables and the task_struct of a
|
||||
proc; this is at least 12k of memory that is always resident. SIZE is the
|
||||
virtual size of the proc (code+data+stack).
|
||||
|
||||
Processes marked <defunct> are dead processes (so-called "zombies") that
|
||||
remain because their parent has not destroyed them properly. These processes
|
||||
will be destroyed by init(8) if the parent process exits.
|
||||
|
||||
|
||||
PROCESS FLAGS
|
||||
|
||||
ALIGNWARN 001 print alignment warning msgs
|
||||
STARTING 002 being created
|
||||
EXITING 004 getting shut down
|
||||
PTRACED 010 set if ptrace (0) has been called
|
||||
TRACESYS 020 tracing system calls
|
||||
FORKNOEXEC 040 forked but didn't exec
|
||||
SUPERPRIV 100 used super-user privileges
|
||||
DUMPCORE 200 dumped core
|
||||
SIGNALED 400 killed by a signal
|
||||
|
||||
|
||||
PROCESS STATE CODES
|
||||
|
||||
D uninterruptible sleep (usually IO)
|
||||
R runnable (on run queue)
|
||||
S sleeping
|
||||
T traced or stopped
|
||||
Z a defunct ("zombie") process
|
||||
|
||||
For BSD formats and when the "stat" keyword is used, additional
|
||||
letters may be displayed:
|
||||
|
||||
W has no resident pages
|
||||
< high-priority process
|
||||
N low-priority task
|
||||
L has pages locked into memory (for real-time and custom IO)
|
||||
|
||||
|
||||
SORT KEYS
|
||||
|
||||
Note that the values used in sorting are the internal values ps uses and not
|
||||
the `cooked' values used in some of the output format fields. Pipe ps
|
||||
output into the sort(1) command if you want to sort the cooked values.
|
||||
|
||||
KEY LONG DESCRIPTION
|
||||
c cmd simple name of executable
|
||||
C cmdline full command line
|
||||
f flags flags as in long format F field
|
||||
g pgrp process group ID
|
||||
G tpgid controlling tty process group ID
|
||||
j cutime cumulative user time
|
||||
J cstime cumulative system time
|
||||
k utime user time
|
||||
K stime system time
|
||||
m min_flt number of minor page faults
|
||||
M maj_flt number of major page faults
|
||||
n cmin_flt cumulative minor page faults
|
||||
N cmaj_flt cumulative major page faults
|
||||
o session session ID
|
||||
p pid process ID
|
||||
P ppid parent process ID
|
||||
r rss resident set size
|
||||
R resident resident pages
|
||||
s size memory size in kilobytes
|
||||
S share amount of shared pages
|
||||
t tty the minor device number of tty
|
||||
T start_time time process was started
|
||||
U uid user ID number
|
||||
u user user name
|
||||
v vsize total VM size in kB
|
||||
y priority kernel scheduling priority
|
||||
|
||||
|
||||
AIX FORMAT DESCRIPTORS
|
||||
|
||||
This ps supports AIX format descriptors, which work somewhat like the
|
||||
formatting codes of printf(1) and printf(3). For example, the normal
|
||||
default output can be produced with this: ps -eo "%p %y %x %c"
|
||||
|
||||
CODE NORMAL HEADER
|
||||
%C pcpu %CPU
|
||||
%G group GROUP
|
||||
%P ppid PPID
|
||||
%U user USER
|
||||
%a args COMMAND
|
||||
%c comm COMMAND
|
||||
%g rgroup RGROUP
|
||||
%n nice NI
|
||||
%p pid PID
|
||||
%r pgid PGID
|
||||
%t etime ELAPSED
|
||||
%u ruser RUSER
|
||||
%x time TIME
|
||||
%y tty TTY
|
||||
%z vsz VSZ
|
||||
|
||||
|
||||
STANDARD FORMAT SPECIFIERS
|
||||
|
||||
These may be used to control both output format and sorting.
|
||||
For example: ps -eo pid,user,args --sort user
|
||||
|
||||
CODE HEADER
|
||||
%cpu %CPU
|
||||
%mem %MEM
|
||||
alarm ALARM
|
||||
args COMMAND
|
||||
blocked BLOCKED
|
||||
bsdstart START
|
||||
bsdtime TIME
|
||||
c C
|
||||
caught CAUGHT
|
||||
cmd CMD
|
||||
comm COMMAND
|
||||
command COMMAND
|
||||
cputime TIME
|
||||
drs DRS
|
||||
dsiz DSIZ
|
||||
egid EGID
|
||||
egroup EGROUP
|
||||
eip EIP
|
||||
esp ESP
|
||||
etime ELAPSED
|
||||
euid EUID
|
||||
euser EUSER
|
||||
f F
|
||||
fgid FGID
|
||||
fgroup FGROUP
|
||||
flag F
|
||||
flags F
|
||||
fname COMMAND
|
||||
fsgid FSGID
|
||||
fsgroup FSGROUP
|
||||
fsuid FSUID
|
||||
fsuser FSUSER
|
||||
fuid FUID
|
||||
fuser FUSER
|
||||
gid GID
|
||||
group GROUP
|
||||
ignored IGNORED
|
||||
intpri PRI
|
||||
lim LIM
|
||||
longtname TTY
|
||||
lstart STARTED
|
||||
m_drs DRS
|
||||
m_trs TRS
|
||||
maj_flt MAJFL
|
||||
majflt MAJFLT
|
||||
min_flt MINFL
|
||||
minflt MINFLT
|
||||
ni NI
|
||||
nice NI
|
||||
nwchan WCHAN
|
||||
opri PRI
|
||||
pagein PAGEIN
|
||||
pcpu %CPU
|
||||
pending PENDING
|
||||
pgid PGID
|
||||
pgrp PGRP
|
||||
pid PID
|
||||
pmem %MEM
|
||||
ppid PPID
|
||||
pri PRI
|
||||
priority PRI
|
||||
rgid RGID
|
||||
rgroup RGROUP
|
||||
rss RSS
|
||||
rssize RSS
|
||||
rsz RSZ
|
||||
ruid RUID
|
||||
ruser RUSER
|
||||
s S
|
||||
sess SESS
|
||||
session SESS
|
||||
sgi_p P
|
||||
sgi_rss RSS
|
||||
sgid SGID
|
||||
sgroup SGROUP
|
||||
sid SID
|
||||
sig PENDING
|
||||
sig_block BLOCKED
|
||||
sig_catch CATCHED
|
||||
sig_ignore IGNORED
|
||||
sig_pend SIGNAL
|
||||
sigcatch CAUGHT
|
||||
sigignore IGNORED
|
||||
sigmask BLOCKED
|
||||
stackp STACKP
|
||||
start STARTED
|
||||
start_stack STACKP
|
||||
start_time START
|
||||
stat STAT
|
||||
state S
|
||||
stime STIME
|
||||
suid SUID
|
||||
suser SUSER
|
||||
svgid SVGID
|
||||
svgroup SVGROUP
|
||||
svuid SVUID
|
||||
svuser SVUSER
|
||||
sz SZ
|
||||
time TIME
|
||||
timeout TMOUT
|
||||
tmout TMOUT
|
||||
tname TTY
|
||||
tpgid TPGID
|
||||
trs TRS
|
||||
trss TRSS
|
||||
tsiz TSIZ
|
||||
tt TT
|
||||
tty TT
|
||||
tty4 TTY
|
||||
tty8 TTY
|
||||
ucmd CMD
|
||||
ucomm COMMAND
|
||||
uid UID
|
||||
uid_hack UID
|
||||
uname USER
|
||||
user USER
|
||||
vsize VSZ
|
||||
vsz VSZ
|
||||
wchan WCHAN
|
||||
|
||||
|
||||
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
The following environment variables could affect ps:
|
||||
COLUMNS Override default display width.
|
||||
LINES Override default display height.
|
||||
PS_PERSONALITY Set to one of posix,old,linux,bsd,sun,digital...
|
||||
CMD_ENV Set to one of posix,old,linux,bsd,sun,digital...
|
||||
I_WANT_A_BROKEN_PS Force obsolete command line interpretation.
|
||||
LC_TIME Date format.
|
||||
PS_COLORS Not currently supported.
|
||||
PS_FORMAT Default output format override.
|
||||
PS_SYSMAP Default namelist (System.map) location.
|
||||
PS_SYSTEM_MAP Default namelist (System.map) location.
|
||||
POSIXLY_CORRECT Don't find excuses to ignore bad "features".
|
||||
UNIX95 Don't find excuses to ignore bad "features".
|
||||
_XPG Cancel CMD_ENV=irix non-standard behavior.
|
||||
|
||||
In general, it is a bad idea to set these variables. The one exception
|
||||
is CMD_ENV or PS_PERSONALITY, which could be set to Linux for normal
|
||||
systems. Without that setting, ps follows the useless and bad parts
|
||||
of the Unix98 standard.
|
||||
|
||||
|
||||
PERSONALITY
|
||||
390 like the S/390 OpenEdition ps
|
||||
aix like AIX ps
|
||||
bsd like FreeBSD ps (totally non-standard)
|
||||
compaq like Digital Unix ps
|
||||
debian like the old Debian ps
|
||||
digital like Digital Unix ps
|
||||
gnu like the old Debian ps
|
||||
hp like HP-UX ps
|
||||
hpux like HP-UX ps
|
||||
irix like Irix ps
|
||||
linux ***** RECOMMENDED *****
|
||||
old like the original Linux ps (totally non-standard)
|
||||
posix standard
|
||||
sco like SCO ps
|
||||
sgi like Irix ps
|
||||
sun like SunOS 4 ps (totally non-standard)
|
||||
sunos like SunOS 4 ps (totally non-standard)
|
||||
sysv standard
|
||||
unix standard
|
||||
unix95 standard
|
||||
unix98 standard
|
||||
|
||||
|
||||
EXAMPLES
|
||||
To see every process on the system using standard syntax:
|
||||
ps -e
|
||||
To see every process on the system using BSD syntax:
|
||||
ps ax
|
||||
To see every process except those running as root (real & effective ID)
|
||||
ps -U root -u root -N
|
||||
To see every process with a user-defined format:
|
||||
ps -eo pid,tt,user,fname,tmout,f,wchan
|
||||
Odd display with AIX field descriptors:
|
||||
ps -o "%u : %U : %p : %a"
|
||||
Print only the process IDs of syslogd:
|
||||
ps -C syslogd -o pid=
|
||||
|
||||
SEE ALSO
|
||||
top(1) pstree(1) proc(5)
|
||||
|
||||
STANDARDS
|
||||
This ps conforms to version 2 of the Single Unix Specification.
|
||||
|
||||
AUTHOR
|
||||
ps was originally written by Branko Lankester <lankeste@fwi.uva.nl>. Michael
|
||||
K. Johnson <johnsonm@redhat.com> re-wrote it significantly to use the proc
|
||||
filesystem, changing a few things in the process. Michael Shields
|
||||
<mjshield@nyx.cs.du.edu> added the pid-list feature. Charles Blake
|
||||
<cblake@bbn.com> added multi-level sorting, the dirent-style library, the
|
||||
device name-to-number mmaped database, the approximate binary search
|
||||
directly on System.map, and many code and documentation cleanups. David
|
||||
Mossberger-Tang wrote the generic BFD support for psupdate. Albert Cahalan
|
||||
<acahalan@cs.uml.edu> rewrote ps for full Unix98 and BSD support, along with
|
||||
some ugly hacks for obsolete and foreign syntax.
|
||||
|
||||
Please send bug reports to <acahalan@cs.uml.edu>
|
26
ps/regression
Normal file
26
ps/regression
Normal file
@@ -0,0 +1,26 @@
|
||||
-u 500 -o pid,ppid,fname,comm,args # right margin trouble
|
||||
-u 500 -o pid,ppid,fname,comm,args,wchan,wchan,wchan,wchan,wchan,nice,wchan
|
||||
-u 500 -o pid,pid,pid,pid,user,user,user,args # had trouble
|
||||
-u 500 -o user,user,user,pid,pid,pid,pid,args # no trouble!
|
||||
|
||||
Test with each type of field (RIGHT,LEFT,UNLIMITED...) hanging off the
|
||||
edge of the screen and each type of field to the left of the one that
|
||||
hangs off the edge.
|
||||
|
||||
Test "ps ef" as _both_ normal user and root. Especially after su!
|
||||
|
||||
On a 108-col screen, try "ps alx" and "ps alx | cat"
|
||||
|
||||
These ought to be the same:
|
||||
CMD_ENV=old ps -m
|
||||
CMD_ENV=old ps m
|
||||
|
||||
These ought to be the same:
|
||||
CMD_ENV=old ps -X
|
||||
CMD_ENV=old ps X
|
||||
ps X
|
||||
ps -X # needs to be a non-SysV option
|
||||
|
||||
This should fail:
|
||||
ps x -x
|
||||
|
146
ps/select.c
Normal file
146
ps/select.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "../proc/readproc.h"
|
||||
#include "../proc/procps.h"
|
||||
|
||||
#define session_leader(p) ((p)->session == (p)->pid)
|
||||
#define process_group_leader(p) ((p)->pgid == (p)->pid)
|
||||
#define without_a_tty(p) ((unsigned short)((p)->tty) == (unsigned short)-1)
|
||||
#define some_other_user(p) ((p)->euid != cached_euid)
|
||||
#define running(p) (((p)->state=='R')||((p)->state=='D'))
|
||||
#define has_our_euid(p) ((unsigned short)((p)->euid) == (unsigned short)cached_euid)
|
||||
#define on_our_tty(p) ((unsigned short)((p)->tty) == (unsigned short)cached_tty)
|
||||
|
||||
static unsigned long select_bits = 0;
|
||||
|
||||
/***** prepare select_bits for use */
|
||||
const char *select_bits_setup(void){
|
||||
int switch_val = 0;
|
||||
/* don't want a 'g' screwing up simple_select */
|
||||
if(!simple_select && !prefer_bsd_defaults){
|
||||
select_bits = 0xaa00; /* the STANDARD selection */
|
||||
return NULL;
|
||||
}
|
||||
/* For every BSD but SunOS, the 'g' option is a NOP. (enabled by default) */
|
||||
if( !(personality & PER_NO_DEFAULT_g) && !(simple_select&(SS_U_a|SS_U_d)) )
|
||||
switch_val = simple_select|SS_B_g;
|
||||
else
|
||||
switch_val = simple_select;
|
||||
switch(switch_val){
|
||||
/* UNIX options */
|
||||
case SS_U_a | SS_U_d: select_bits = 0x3f3f; break; /* 3333 or 3f3f */
|
||||
case SS_U_a: select_bits = 0x0303; break; /* 0303 or 0f0f */
|
||||
case SS_U_d: select_bits = 0x3333; break;
|
||||
/* SunOS 4 only (others have 'g' enabled all the time) */
|
||||
case 0: select_bits = 0x0202; break;
|
||||
case SS_B_a: select_bits = 0x0303; break;
|
||||
case SS_B_x : select_bits = 0x2222; break;
|
||||
case SS_B_x | SS_B_a: select_bits = 0x3333; break;
|
||||
/* General BSD options */
|
||||
case SS_B_g : select_bits = 0x0a0a; break;
|
||||
case SS_B_g | SS_B_a: select_bits = 0x0f0f; break;
|
||||
case SS_B_g | SS_B_x : select_bits = 0xaaaa; break;
|
||||
case SS_B_g | SS_B_x | SS_B_a: /* convert to -e instead of using 0xffff */
|
||||
all_processes = 1;
|
||||
simple_select = 0;
|
||||
break;
|
||||
default:
|
||||
return "Process selection options conflict.";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***** selected by simple option? */
|
||||
static int table_accept(proc_t *buf){
|
||||
unsigned proc_index;
|
||||
proc_index = (has_our_euid(buf) <<0)
|
||||
| (session_leader(buf) <<1)
|
||||
| (without_a_tty(buf) <<2)
|
||||
| (on_our_tty(buf) <<3);
|
||||
return (select_bits & (1<<proc_index));
|
||||
}
|
||||
|
||||
/***** selected by some kind of list? */
|
||||
static int proc_was_listed(proc_t *buf){
|
||||
selection_node *sn = selection_list;
|
||||
int i;
|
||||
if(!sn) return 0;
|
||||
while(sn){
|
||||
switch(sn->typecode){
|
||||
default:
|
||||
printf("Internal error in ps! Please report this bug.\n");
|
||||
|
||||
#define return_if_match(foo,bar) \
|
||||
i=sn->n; while(i--) \
|
||||
if((unsigned short )(buf->foo) == (unsigned short)(*(sn->u+i)).bar) \
|
||||
return 1
|
||||
|
||||
break; case SEL_RUID: return_if_match(ruid,uid);
|
||||
break; case SEL_EUID: return_if_match(euid,uid);
|
||||
break; case SEL_SUID: return_if_match(suid,uid);
|
||||
break; case SEL_FUID: return_if_match(fuid,uid);
|
||||
|
||||
break; case SEL_RGID: return_if_match(rgid,gid);
|
||||
break; case SEL_EGID: return_if_match(egid,gid);
|
||||
break; case SEL_SGID: return_if_match(sgid,gid);
|
||||
break; case SEL_FGID: return_if_match(fgid,gid);
|
||||
|
||||
break; case SEL_PGRP: return_if_match(pgrp,pid);
|
||||
break; case SEL_PID : return_if_match(pid,pid);
|
||||
break; case SEL_TTY : return_if_match(tty,tty);
|
||||
break; case SEL_SESS: return_if_match(session,pid);
|
||||
|
||||
/* TODO Should use a long long cast for performance */
|
||||
break; case SEL_COMM: i=sn->n; while(i--)
|
||||
if(!strncmp( buf->cmd, (*(sn->u+i)).cmd, 8 )) return 1;
|
||||
|
||||
|
||||
|
||||
#undef return_if_match
|
||||
|
||||
}
|
||||
sn = sn->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***** This must satisfy Unix98 and as much BSD as possible */
|
||||
int want_this_proc(proc_t *buf){
|
||||
int accepted_proc = 1; /* assume success */
|
||||
/* elsewhere, convert T to list, U sets x implicitly */
|
||||
|
||||
/* handle -e -A */
|
||||
if(all_processes) goto finish;
|
||||
|
||||
/* use table for -a a d g x */
|
||||
if((simple_select || !selection_list))
|
||||
if(table_accept(buf)) goto finish;
|
||||
|
||||
/* search lists */
|
||||
if(proc_was_listed(buf)) goto finish;
|
||||
|
||||
/* fail, fall through to loose ends */
|
||||
accepted_proc = 0;
|
||||
|
||||
/* do r N */
|
||||
finish:
|
||||
if(running_only && !running(buf)) accepted_proc = 0;
|
||||
if(negate_selection) return !accepted_proc;
|
||||
return accepted_proc;
|
||||
}
|
875
ps/sortformat.c
Normal file
875
ps/sortformat.c
Normal file
@@ -0,0 +1,875 @@
|
||||
/*
|
||||
* Copyright 1998 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* username lookups */
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "../proc/readproc.h"
|
||||
#include "common.h"
|
||||
|
||||
static sf_node *sf_list = NULL; /* deferred sorting and formatting */
|
||||
static int broken; /* use gross Unix98 parsing? */
|
||||
static int have_gnu_sort = 0; /* if true, "O" must be format */
|
||||
static int already_parsed_sort = 0; /* redundantly set in & out of fn */
|
||||
static int already_parsed_format = 0;
|
||||
|
||||
|
||||
#define parse_sort_opt <-- arrgh! do not use this -->
|
||||
#define gnusort_parse <-- arrgh! do not use this -->
|
||||
|
||||
|
||||
/**************** Parse single format specifier *******************/
|
||||
static format_node *do_one_spec(const char *spec, const char *override){
|
||||
const format_struct *fs;
|
||||
const macro_struct *ms;
|
||||
|
||||
fs = search_format_array(spec);
|
||||
if(fs){
|
||||
int w1, w2;
|
||||
format_node *thisnode;
|
||||
thisnode = malloc(sizeof(format_node));
|
||||
w1 = fs->width;
|
||||
if(override){
|
||||
w2 = strlen(override);
|
||||
thisnode->width = (w1>w2)?w1:w2;
|
||||
thisnode->name = malloc(strlen(override)+1);
|
||||
strcpy(thisnode->name, override);
|
||||
}else{
|
||||
thisnode->width = w1;
|
||||
thisnode->name = malloc(strlen(fs->head)+1);
|
||||
strcpy(thisnode->name, fs->head);
|
||||
}
|
||||
thisnode->pr = fs->pr;
|
||||
thisnode->pad = fs->pad;
|
||||
thisnode->vendor = fs->vendor;
|
||||
thisnode->flags = fs->flags;
|
||||
thisnode->next = NULL;
|
||||
return thisnode;
|
||||
}
|
||||
|
||||
/* That failed, so try it as a macro. */
|
||||
ms = search_macro_array(spec);
|
||||
if(ms){
|
||||
format_node *list = NULL;
|
||||
format_node *newnode;
|
||||
const char *walk;
|
||||
int dist;
|
||||
char buf[16]; /* trust strings will be short (from above, not user) */
|
||||
walk = ms->head;
|
||||
while(*walk){
|
||||
dist = strcspn(walk, ", ");
|
||||
strncpy(buf,walk,dist);
|
||||
buf[dist] = '\0';
|
||||
newnode = do_one_spec(buf,override); /* call self, assume success */
|
||||
newnode->next = list;
|
||||
list = newnode;
|
||||
walk += dist;
|
||||
if(*walk) walk++;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return NULL; /* bad, spec not found */
|
||||
}
|
||||
|
||||
|
||||
/************ must wrap user format in default *************/
|
||||
static void O_wrap(sf_node *sfn, int otype){
|
||||
format_node *fnode;
|
||||
format_node *endp;
|
||||
char *trailer;
|
||||
|
||||
trailer = (otype=='b') ? "END_BSD" : "END_SYS5" ;
|
||||
|
||||
fnode = do_one_spec("pid",NULL);
|
||||
if(!fnode)fprintf(stderr,"Seriously crashing. Goodbye cruel world.\n");
|
||||
endp = sfn->f_cooked; while(endp->next) endp = endp->next; /* find end */
|
||||
endp->next = fnode;
|
||||
|
||||
fnode = do_one_spec(trailer,NULL);
|
||||
if(!fnode)fprintf(stderr,"Seriously crashing. Goodbye cruel world.\n");
|
||||
endp = fnode; while(endp->next) endp = endp->next; /* find end */
|
||||
endp->next = sfn->f_cooked;
|
||||
sfn->f_cooked = fnode;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Used to parse option AIX field descriptors.
|
||||
* Put each completed format_node onto the list starting at ->f_cooked
|
||||
*/
|
||||
static const char *aix_format_parse(sf_node *sfn){
|
||||
char *buf; /* temp copy of arg to hack on */
|
||||
char *walk;
|
||||
int items;
|
||||
|
||||
/*** sanity check and count items ***/
|
||||
items = 0;
|
||||
walk = sfn->sf;
|
||||
/* state machine */ {
|
||||
int c;
|
||||
initial:
|
||||
c = *walk++;
|
||||
if(c=='%') goto get_desc;
|
||||
if(!c) goto looks_ok;
|
||||
/* get_text: */
|
||||
items++;
|
||||
get_more_text:
|
||||
c = *walk++;
|
||||
if(c=='%') goto get_desc;
|
||||
if(c) goto get_more_text;
|
||||
goto looks_ok;
|
||||
get_desc:
|
||||
items++;
|
||||
c = *walk++;
|
||||
if(c) goto initial;
|
||||
return "Improper AIX field descriptor.";
|
||||
looks_ok:
|
||||
}
|
||||
|
||||
/*** sanity check passed ***/
|
||||
buf = malloc(strlen(sfn->sf)+1);
|
||||
strcpy(buf, sfn->sf);
|
||||
walk = sfn->sf;
|
||||
|
||||
while(items--){
|
||||
format_node *fnode; /* newly allocated */
|
||||
format_node *endp; /* for list manipulation */
|
||||
|
||||
if(*walk == '%'){
|
||||
const aix_struct *aix;
|
||||
walk++;
|
||||
if(*walk == '%') goto double_percent;
|
||||
aix = search_aix_array(*walk);
|
||||
walk++;
|
||||
if(!aix){
|
||||
free(buf);
|
||||
return "Unknown AIX field descriptor.";
|
||||
}
|
||||
fnode = do_one_spec(aix->spec, aix->head);
|
||||
if(!fnode){
|
||||
free(buf);
|
||||
return "AIX field descriptor processing bug.";
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
len = strcspn(walk, "%");
|
||||
memcpy(buf,walk,len);
|
||||
if(0){
|
||||
double_percent:
|
||||
len = 1;
|
||||
buf[0] = '%';
|
||||
}
|
||||
buf[len] = '\0';
|
||||
walk += len;
|
||||
fnode = malloc(sizeof(format_node));
|
||||
fnode->width = len;
|
||||
fnode->name = malloc(len+1);
|
||||
strcpy(fnode->name, buf);
|
||||
fnode->pr = NULL; /* checked for */
|
||||
fnode->pad = 0;
|
||||
fnode->vendor = AIX;
|
||||
fnode->flags = 0;
|
||||
fnode->next = NULL;
|
||||
}
|
||||
|
||||
endp = fnode; while(endp->next) endp = endp->next; /* find end */
|
||||
endp->next = sfn->f_cooked;
|
||||
sfn->f_cooked = fnode;
|
||||
}
|
||||
free(buf);
|
||||
already_parsed_format = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Used to parse option O lists. Option O is shared between
|
||||
* sorting and formatting. Users may expect one or the other.
|
||||
* The "broken" flag enables a really bad Unix98 misfeature.
|
||||
* Put each completed format_node onto the list starting at ->f_cooked
|
||||
*/
|
||||
static const char *format_parse(sf_node *sfn){
|
||||
char *buf; /* temp copy of arg to hack on */
|
||||
char *sep_loc; /* separator location: " \t,\n" */
|
||||
char *walk;
|
||||
const char *err; /* error code that could or did happen */
|
||||
format_node *fnode;
|
||||
int items;
|
||||
int need_item;
|
||||
static char errbuf[80]; /* for variable-text error message */
|
||||
|
||||
/*** prepare to operate ***/
|
||||
buf = malloc(strlen(sfn->sf)+1);
|
||||
strcpy(buf, sfn->sf);
|
||||
|
||||
/*** sanity check and count items ***/
|
||||
need_item = 1; /* true */
|
||||
items = 0;
|
||||
walk = buf;
|
||||
do{
|
||||
switch(*walk){
|
||||
case ' ': case ',': case '\t': case '\n': case '\0':
|
||||
/* Linux extension: allow \t and \n as delimiters */
|
||||
if(need_item){
|
||||
free(buf);
|
||||
goto improper;
|
||||
}
|
||||
need_item=1;
|
||||
break;
|
||||
case '=':
|
||||
if(broken) goto out;
|
||||
/* fall through */
|
||||
default:
|
||||
if(need_item) items++;
|
||||
need_item=0;
|
||||
}
|
||||
} while (*++walk);
|
||||
out:
|
||||
if(!items){
|
||||
free(buf);
|
||||
goto empty;
|
||||
}
|
||||
#ifdef STRICT_LIST
|
||||
if(need_item){ /* can't have trailing deliminator */
|
||||
free(buf);
|
||||
goto improper;
|
||||
}
|
||||
#else
|
||||
if(need_item){ /* allow 1 trailing deliminator */
|
||||
*--walk='\0'; /* remove the trailing deliminator */
|
||||
}
|
||||
#endif
|
||||
/*** actually parse the list ***/
|
||||
walk = buf;
|
||||
while(items--){
|
||||
format_node *endp;
|
||||
char *equal_loc;
|
||||
sep_loc = strpbrk(walk," ,\t\n");
|
||||
/* if items left, then sep_loc is not in header override */
|
||||
if(items && sep_loc) *sep_loc = '\0';
|
||||
equal_loc = strpbrk(walk,"=");
|
||||
if(equal_loc){ /* if header override */
|
||||
*equal_loc = '\0';
|
||||
equal_loc++;
|
||||
}
|
||||
fnode = do_one_spec(walk,equal_loc);
|
||||
if(!fnode){
|
||||
if(!*errbuf){ /* if didn't already create an error string */
|
||||
snprintf(
|
||||
errbuf,
|
||||
sizeof(errbuf),
|
||||
"Unknown user-defined format specifier \"%s\".",
|
||||
walk
|
||||
);
|
||||
}
|
||||
free(buf);
|
||||
goto unknown;
|
||||
}
|
||||
endp = fnode; while(endp->next) endp = endp->next; /* find end */
|
||||
endp->next = sfn->f_cooked;
|
||||
sfn->f_cooked = fnode;
|
||||
walk = sep_loc + 1; /* point to next item, if any */
|
||||
}
|
||||
free(buf);
|
||||
already_parsed_format = 1;
|
||||
return NULL;
|
||||
|
||||
/* errors may cause a retry looking for AIX format codes */
|
||||
if(0) unknown: err=errbuf;
|
||||
if(0) empty: err="Empty format list.";
|
||||
if(0) improper: err="Improper format list.";
|
||||
if(strchr(sfn->sf,'%')) err = aix_format_parse(sfn);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**************** Parse single sort specifier *******************/
|
||||
static sort_node *do_one_sort_spec(const char *spec){
|
||||
const format_struct *fs;
|
||||
int reverse = 0;
|
||||
if(*spec == '-'){
|
||||
reverse = 1;
|
||||
spec++;
|
||||
}
|
||||
fs = search_format_array(spec);
|
||||
if(fs){
|
||||
sort_node *thisnode;
|
||||
thisnode = malloc(sizeof(format_node));
|
||||
thisnode->sr = fs->sr;
|
||||
thisnode->reverse = reverse;
|
||||
thisnode->next = NULL;
|
||||
return thisnode;
|
||||
}
|
||||
return NULL; /* bad, spec not found */
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* Used to parse long sorting options.
|
||||
* Put each completed sort_node onto the list starting at ->s_cooked
|
||||
*/
|
||||
static const char *long_sort_parse(sf_node *sfn){
|
||||
char *buf; /* temp copy of arg to hack on */
|
||||
char *sep_loc; /* separator location: " \t,\n" */
|
||||
char *walk;
|
||||
const char *err; /* error code that could or did happen */
|
||||
sort_node *snode;
|
||||
int items;
|
||||
int need_item;
|
||||
|
||||
/*** prepare to operate ***/
|
||||
buf = malloc(strlen(sfn->sf)+1);
|
||||
strcpy(buf, sfn->sf);
|
||||
|
||||
/*** sanity check and count items ***/
|
||||
need_item = 1; /* true */
|
||||
items = 0;
|
||||
walk = buf;
|
||||
err = "Improper sort specifier list.";
|
||||
do{
|
||||
switch(*walk){
|
||||
case ' ': case ',': case '\t': case '\n': case '\0':
|
||||
if(need_item){
|
||||
free(buf);
|
||||
return "Improper sort list";
|
||||
}
|
||||
need_item=1;
|
||||
break;
|
||||
default:
|
||||
if(need_item) items++;
|
||||
need_item=0;
|
||||
}
|
||||
} while (*++walk);
|
||||
if(!items){
|
||||
free(buf);
|
||||
return "Empty sort list.";
|
||||
}
|
||||
#ifdef STRICT_LIST
|
||||
if(need_item){ /* can't have trailing deliminator */
|
||||
free(buf);
|
||||
return "Improper sort list.";
|
||||
}
|
||||
#else
|
||||
if(need_item){ /* allow 1 trailing deliminator */
|
||||
*--walk='\0'; /* remove the trailing deliminator */
|
||||
}
|
||||
#endif
|
||||
/*** actually parse the list ***/
|
||||
walk = buf;
|
||||
while(items--){
|
||||
sort_node *endp;
|
||||
sep_loc = strpbrk(walk," ,\t\n");
|
||||
if(sep_loc) *sep_loc = '\0';
|
||||
snode = do_one_sort_spec(walk);
|
||||
if(!snode){
|
||||
free(buf);
|
||||
return "Unknown sort specifier.";
|
||||
}
|
||||
endp = snode; while(endp->next) endp = endp->next; /* find end */
|
||||
endp->next = sfn->s_cooked;
|
||||
sfn->s_cooked = snode;
|
||||
walk = sep_loc + 1; /* point to next item, if any */
|
||||
}
|
||||
free(buf);
|
||||
already_parsed_sort = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************ pre-parse short sorting option *************/
|
||||
/* Errors _must_ be detected so that the "O" option can try to
|
||||
* reparse as formatting codes.
|
||||
*/
|
||||
static const char *verify_short_sort(const char *arg){
|
||||
const char *all = "CGJKMNPRSTUcfgjkmnoprstuvy+-";
|
||||
char checkoff[256];
|
||||
int i;
|
||||
const char *walk;
|
||||
int tmp;
|
||||
if(strspn(arg,all) != strlen(arg)) return "Bad sorting code.";
|
||||
for(i=256; i--;) checkoff[i] = 0;
|
||||
walk = arg;
|
||||
for(;;){
|
||||
tmp = *walk;
|
||||
switch(tmp){
|
||||
case '\0':
|
||||
return NULL; /* looks good */
|
||||
case '+':
|
||||
case '-':
|
||||
tmp = *(walk+1);
|
||||
if(!tmp || tmp=='+' || tmp=='-') return "Bad sorting code.";
|
||||
break;
|
||||
case 'P':
|
||||
if(forest_type) return "PPID sort and forest output conflict.";
|
||||
/* fall through */
|
||||
default:
|
||||
if(checkoff[tmp]) return "Bad sorting code."; /* repeated */
|
||||
/* ought to check against already accepted sort options */
|
||||
checkoff[tmp] = 1;
|
||||
break;
|
||||
}
|
||||
walk++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************ parse short sorting option *************/
|
||||
static const char *short_sort_parse(sf_node *sfn){
|
||||
int direction = 0;
|
||||
const char *walk;
|
||||
int tmp;
|
||||
sort_node *snode;
|
||||
sort_node *endp;
|
||||
const struct shortsort_struct *ss;
|
||||
walk = sfn->sf;
|
||||
for(;;){
|
||||
tmp = *walk;
|
||||
switch(tmp){
|
||||
case '\0':
|
||||
already_parsed_sort = 1;
|
||||
return NULL;
|
||||
case '+':
|
||||
direction = 0;
|
||||
break;
|
||||
case '-':
|
||||
direction = 1;
|
||||
break;
|
||||
default:
|
||||
ss = search_shortsort_array(tmp);
|
||||
if(!ss) return "Unknown sort specifier.";
|
||||
snode = do_one_sort_spec(ss->spec);
|
||||
if(!snode) return "Unknown sort specifier.";
|
||||
snode->reverse = direction;
|
||||
endp = snode; while(endp->next) endp = endp->next; /* find end */
|
||||
endp->next = sfn->s_cooked;
|
||||
sfn->s_cooked = snode;
|
||||
direction = 0;
|
||||
break;
|
||||
}
|
||||
walk++;
|
||||
}
|
||||
}
|
||||
|
||||
/******************* high-level below here *********************/
|
||||
|
||||
|
||||
/*
|
||||
* Used to parse option O lists. Option O is shared between
|
||||
* sorting and formatting. Users may expect one or the other.
|
||||
* The "broken" flag enables a really bad Unix98 misfeature.
|
||||
* Recursion is to preserve original order.
|
||||
*/
|
||||
static const char *parse_O_option(sf_node *sfn){
|
||||
const char *err; /* error code that could or did happen */
|
||||
|
||||
if(sfn->next){
|
||||
err = parse_O_option(sfn->next);
|
||||
if(err) return err;
|
||||
}
|
||||
|
||||
switch(sfn->sf_code){
|
||||
case SF_B_o: case SF_G_format: case SF_U_o: /*** format ***/
|
||||
err = format_parse(sfn);
|
||||
if(!err) already_parsed_format = 1;
|
||||
break;
|
||||
case SF_U_O: /*** format ***/
|
||||
/* Can have -l -f f u... set already_parsed_format like DEC does */
|
||||
if(already_parsed_format) return "option -O can not follow other format options.";
|
||||
err = format_parse(sfn);
|
||||
if(err) return err;
|
||||
already_parsed_format = 1;
|
||||
O_wrap(sfn,'u'); /* must wrap user format in default */
|
||||
break;
|
||||
case SF_B_O: /*** both ***/
|
||||
if(have_gnu_sort || already_parsed_sort) err = "Multiple sort options.";
|
||||
else err = verify_short_sort(sfn->sf);
|
||||
if(!err){ /* success as sorting code */
|
||||
short_sort_parse(sfn);
|
||||
already_parsed_sort = 1;
|
||||
return NULL;
|
||||
}
|
||||
if(already_parsed_format){
|
||||
err = "option O is neither first format nor sort order.";
|
||||
break;
|
||||
}
|
||||
if(!format_parse(sfn)){ /* if success as format code */
|
||||
already_parsed_format = 1;
|
||||
O_wrap(sfn,'b'); /* must wrap user format in default */
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case SF_G_sort: case SF_B_m: /*** sort ***/
|
||||
if(already_parsed_sort) err = "Multiple sort options.";
|
||||
else err = long_sort_parse(sfn);
|
||||
already_parsed_sort = 1;
|
||||
break;
|
||||
default: /*** junk ***/
|
||||
return "Bug: parse_O_option got weirdness!";
|
||||
}
|
||||
return err; /* could be NULL */
|
||||
}
|
||||
|
||||
|
||||
/************ Main parser calls this to save lists for later **********/
|
||||
/* store data for later and return 1 if arg looks non-standard */
|
||||
int defer_sf_option(const char *arg, int source){
|
||||
sf_node *sfn;
|
||||
char buf[16];
|
||||
int dist;
|
||||
const format_struct *fs;
|
||||
int need_item = 1;
|
||||
|
||||
sfn = malloc(sizeof(sf_node));
|
||||
sfn->sf = malloc(strlen(arg)+1);
|
||||
strcpy(sfn->sf, arg);
|
||||
sfn->sf_code = source;
|
||||
sfn->s_cooked = NULL;
|
||||
sfn->f_cooked = NULL;
|
||||
sfn->next = sf_list;
|
||||
sf_list = sfn;
|
||||
|
||||
if(source == SF_G_sort) have_gnu_sort = 1;
|
||||
|
||||
/* Now try to find an excuse to ignore broken Unix98 parsing. */
|
||||
if(source != SF_U_o) return 1; /* Wonderful! Already non-Unix98. */
|
||||
do{
|
||||
switch(*arg){
|
||||
case ' ': case ',': case '\0': /* no \t\n\r support in Unix98 */
|
||||
if(need_item) return 1; /* something wrong */
|
||||
need_item=1;
|
||||
break;
|
||||
case '=':
|
||||
if(need_item) return 1; /* something wrong */
|
||||
return 0; /* broken Unix98 parsing is required */
|
||||
default:
|
||||
if(!need_item) break;
|
||||
need_item=0;
|
||||
dist = strcspn(arg,", =");
|
||||
if(dist>15) return 1; /* something wrong, sort maybe? */
|
||||
strncpy(buf,arg,dist); /* no '\0' on end */
|
||||
buf[dist] = '\0'; /* fix that problem */
|
||||
fs = search_format_array(buf);
|
||||
if(!fs) return 1; /* invalid spec, macro or sort maybe? */
|
||||
if(fs->vendor) return 1; /* Wonderful! Legal non-Unix98 spec. */
|
||||
}
|
||||
} while (*++arg);
|
||||
|
||||
return 0; /* boring, Unix98 is no change */
|
||||
}
|
||||
|
||||
/***** Since ps is not long-lived, the memory leak can be ignored. ******/
|
||||
void reset_sortformat(void){
|
||||
sf_list = NULL; /* deferred sorting and formatting */
|
||||
format_list = NULL; /* digested formatting options */
|
||||
sort_list = NULL; /* digested sorting options (redundant?) */
|
||||
have_gnu_sort = 0;
|
||||
already_parsed_sort = 0;
|
||||
already_parsed_format = 0;
|
||||
}
|
||||
|
||||
|
||||
/***** Search format_list for findme, then insert putme after findme. ****/
|
||||
static int fmt_add_after(const char *findme, format_node *putme){
|
||||
format_node *walk;
|
||||
if(!strcmp(format_list->name, findme)){
|
||||
putme->next = format_list->next;
|
||||
format_list->next = putme;
|
||||
return 1; /* success */
|
||||
}
|
||||
walk = format_list;
|
||||
while(walk->next){
|
||||
if(!strcmp(walk->next->name, findme)){
|
||||
putme->next = walk->next->next;
|
||||
walk->next->next = putme;
|
||||
return 1; /* success */
|
||||
}
|
||||
walk = walk->next;
|
||||
}
|
||||
return 0; /* fail */
|
||||
}
|
||||
|
||||
/******* Search format_list for findme, then delete it. ********/
|
||||
static int fmt_delete(const char *findme){
|
||||
format_node *walk;
|
||||
format_node *old;
|
||||
if(!strcmp(format_list->name, findme)){
|
||||
old = format_list;
|
||||
format_list = format_list->next;
|
||||
free(old);
|
||||
return 1; /* success */
|
||||
}
|
||||
walk = format_list;
|
||||
while(walk->next){
|
||||
if(!strcmp(walk->next->name, findme)){
|
||||
old = walk->next;
|
||||
walk->next = walk->next->next;
|
||||
free(old);
|
||||
return 1; /* success */
|
||||
}
|
||||
walk = walk->next;
|
||||
}
|
||||
return 0; /* fail */
|
||||
}
|
||||
|
||||
|
||||
/************ Build a SysV format backwards. ***********/
|
||||
#define PUSH(foo) (fn=do_one_spec(foo, NULL), fn->next=format_list, format_list=fn)
|
||||
static const char *generate_sysv_list(void){
|
||||
format_node *fn;
|
||||
if((format_modifiers & FM_y) && !(format_flags & FF_Ul))
|
||||
return "Modifier -y without format -l makes no sense.";
|
||||
if(prefer_bsd_defaults){
|
||||
if(format_flags) PUSH("cmd");
|
||||
else PUSH("args");
|
||||
PUSH("bsdtime");
|
||||
if(!(format_flags & FF_Ul)) PUSH("stat");
|
||||
}else{
|
||||
if(format_flags & FF_Uf) PUSH("cmd");
|
||||
else PUSH("ucmd");
|
||||
PUSH("time");
|
||||
}
|
||||
PUSH("tname"); /* Unix98 says "TTY" here, yet "tty" produces "TT". */
|
||||
if(format_flags & FF_Uf) PUSH("stime");
|
||||
/* avoid duplicate columns from -FP and -Fly */
|
||||
if(format_modifiers & FM_F){
|
||||
/* if -FP take the Sun-style column instead (sorry about "sgi_p") */
|
||||
if(!(format_modifiers & FM_P)) PUSH("psr"); /* should be ENG */
|
||||
/* if -Fly take the ADDR-replacement RSS instead */
|
||||
if(!( (format_flags & FF_Ul) && (format_modifiers & FM_y) )) PUSH("rss");
|
||||
}
|
||||
if(format_flags & FF_Ul){
|
||||
PUSH("wchan");
|
||||
}
|
||||
/* since FM_y adds RSS anyway, don't do this hack when that is true */
|
||||
if( (format_flags & FF_Ul) && !(format_modifiers & FM_y) ){
|
||||
if(personality & PER_IRIX_l){ /* add "rss" then ':' here */
|
||||
PUSH("sgi_rss");
|
||||
fn = malloc(sizeof(format_node));
|
||||
fn->width = 1;
|
||||
fn->name = malloc(2);
|
||||
strcpy(fn->name, ":");
|
||||
fn->pr = NULL; /* checked for */
|
||||
fn->pad = 0;
|
||||
fn->vendor = AIX; /* yes, for SGI weirdness */
|
||||
fn->flags = 0;
|
||||
fn->next = format_list;
|
||||
format_list=fn;
|
||||
}
|
||||
}
|
||||
if((format_modifiers & FM_F) || (format_flags & FF_Ul)){
|
||||
PUSH("sz");
|
||||
}
|
||||
if(format_flags & FF_Ul){
|
||||
if(format_modifiers & FM_y) PUSH("rss");
|
||||
else if(personality & (PER_ZAP_ADDR|PER_IRIX_l)) PUSH("sgi_p");
|
||||
else PUSH("addr_1");
|
||||
}
|
||||
if(format_modifiers & FM_c){
|
||||
PUSH("pri"); PUSH("class");
|
||||
}else if(format_flags & FF_Ul){
|
||||
PUSH("ni"); PUSH("opri");
|
||||
}
|
||||
if((format_modifiers & FM_L) && (format_flags & FF_Uf)) PUSH("nlwp");
|
||||
if( (format_flags & (FF_Uf|FF_Ul)) && !(format_modifiers & FM_c) ) PUSH("c");
|
||||
if(format_modifiers & FM_P) PUSH("psr");
|
||||
if(format_modifiers & FM_L) PUSH("lwp");
|
||||
if(format_modifiers & FM_j){
|
||||
PUSH("sid");
|
||||
PUSH("pgid");
|
||||
}
|
||||
if(format_flags & (FF_Uf|FF_Ul)) PUSH("ppid");
|
||||
if(format_modifiers & FM_T) PUSH("spid");
|
||||
PUSH("pid");
|
||||
if(format_flags & FF_Uf){
|
||||
if(personality & PER_SANE_USER) PUSH("user");
|
||||
else PUSH("uid_hack");
|
||||
}else if(format_flags & FF_Ul){
|
||||
PUSH("uid");
|
||||
}
|
||||
if(format_flags & FF_Ul){
|
||||
PUSH("s");
|
||||
if(!(format_modifiers & FM_y)) PUSH("f");
|
||||
}
|
||||
if(format_modifiers & FM_M){
|
||||
PUSH("label"); /* Mandatory Access Control */
|
||||
}
|
||||
format_modifiers = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Used to parse option O lists. Option O is shared between
|
||||
* sorting and formatting. Users may expect one or the other.
|
||||
* The "broken" flag enables a really bad Unix98 misfeature.
|
||||
*/
|
||||
const char *process_sf_options(int localbroken){
|
||||
const char *err;
|
||||
sf_node *sf_walk;
|
||||
int option_source; /* true if user-defined */
|
||||
if(personality & PER_BROKEN_o) localbroken = 1;
|
||||
if(personality & PER_GOOD_o) localbroken = 0;
|
||||
broken = localbroken;
|
||||
if(sf_list){
|
||||
err = parse_O_option(sf_list);
|
||||
if(err) return err;
|
||||
}
|
||||
|
||||
if(format_list) printf("Bug: must reset the list first!\n");
|
||||
|
||||
/* merge formatting info of sf_list into format_list here */
|
||||
sf_walk = sf_list;
|
||||
while(sf_walk){
|
||||
format_node *fmt_walk;
|
||||
fmt_walk = sf_walk->f_cooked;
|
||||
sf_walk->f_cooked = NULL;
|
||||
while(fmt_walk){ /* put any nodes onto format_list in opposite way */
|
||||
format_node *travler;
|
||||
travler = fmt_walk;
|
||||
fmt_walk = fmt_walk->next;
|
||||
travler->next = format_list;
|
||||
format_list = travler;
|
||||
}
|
||||
sf_walk = sf_walk->next;
|
||||
}
|
||||
|
||||
/* merge sorting info of sf_list into sort_list here */
|
||||
sf_walk = sf_list;
|
||||
while(sf_walk){
|
||||
sort_node *srt_walk;
|
||||
srt_walk = sf_walk->s_cooked;
|
||||
sf_walk->s_cooked = NULL;
|
||||
while(srt_walk){ /* put any nodes onto sort_list in opposite way */
|
||||
sort_node *travler;
|
||||
travler = srt_walk;
|
||||
srt_walk = srt_walk->next;
|
||||
travler->next = sort_list;
|
||||
sort_list = travler;
|
||||
}
|
||||
sf_walk = sf_walk->next;
|
||||
}
|
||||
|
||||
if(format_list){
|
||||
if(format_flags) return "Conflicting format options.";
|
||||
option_source = 1;
|
||||
}else{
|
||||
format_node *fmt_walk;
|
||||
format_node *fn;
|
||||
const char *spec;
|
||||
switch(format_flags){
|
||||
|
||||
default: return "Conflicting format options.";
|
||||
|
||||
/* These can be NULL, which enables SysV list generation code. */
|
||||
case 0: spec=NULL; break;
|
||||
case FF_Uf | FF_Ul: spec=sysv_fl_format; break;
|
||||
case FF_Uf: spec=sysv_f_format; break;
|
||||
case FF_Ul: spec=sysv_l_format; break;
|
||||
|
||||
/* These are NOT REACHED for normal -j processing. */
|
||||
case FF_Uj: spec=sysv_j_format; break; /* Debian & Digital */
|
||||
case FF_Uj | FF_Ul: spec="RD_lj"; break; /* Debian */
|
||||
case FF_Uj | FF_Uf: spec="RD_fj"; break; /* Debian */
|
||||
|
||||
/* These are true BSD options. */
|
||||
case FF_Bj: spec=bsd_j_format; break;
|
||||
case FF_Bl: spec=bsd_l_format; break;
|
||||
case FF_Bs: spec=bsd_s_format; break;
|
||||
case FF_Bu: spec=bsd_u_format; break;
|
||||
case FF_Bv: spec=bsd_v_format; break;
|
||||
|
||||
/* These are old Linux options. Option m is overloaded. */
|
||||
case FF_LX: spec="OL_X"; break;
|
||||
case FF_Lm: spec="OL_m"; break;
|
||||
|
||||
} /* end switch(format_flags) */
|
||||
|
||||
option_source = 0;
|
||||
if(!format_flags && !format_modifiers){ /* was default */
|
||||
char *tmp;
|
||||
tmp = getenv("PS_FORMAT"); /* user override kills default */
|
||||
if(tmp && *tmp){
|
||||
spec = tmp;
|
||||
option_source = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(spec){
|
||||
fn = do_one_spec(spec, NULL); /* use override "" for no headers */
|
||||
fmt_walk = fn;
|
||||
while(fmt_walk){ /* put any nodes onto format_list in opposite way */
|
||||
format_node *travler;
|
||||
travler = fmt_walk;
|
||||
fmt_walk = fmt_walk->next;
|
||||
travler->next = format_list;
|
||||
format_list = travler;
|
||||
}
|
||||
}else{
|
||||
err = generate_sysv_list();
|
||||
if(err) return err;
|
||||
option_source = 3;
|
||||
}
|
||||
}
|
||||
if(format_modifiers){ /* generate_sysv_list() may have cleared some bits */
|
||||
format_node *fn;
|
||||
if(option_source) return "Can't use output modifiers with user-defined output";
|
||||
if(format_modifiers & FM_j){
|
||||
fn = do_one_spec("pgid", NULL);
|
||||
if(!fmt_add_after("PPID", fn)) if(!fmt_add_after("PID", fn))
|
||||
return "Internal error, no PID or PPID for -j option.";
|
||||
fn = do_one_spec("sid", NULL);
|
||||
if(!fmt_add_after("PGID", fn)) return "Lost my PGID!";
|
||||
}
|
||||
if(format_modifiers & FM_y){
|
||||
/* TODO: check for failure to do something, and complain if so */
|
||||
fmt_delete("F");
|
||||
fn = do_one_spec("rss", NULL);
|
||||
if(fmt_add_after("ADDR", fn)) fmt_delete("ADDR");
|
||||
}
|
||||
if(format_modifiers & FM_c){
|
||||
fmt_delete("%CPU"); fmt_delete("CPU"); fmt_delete("CP"); fmt_delete("C");
|
||||
fmt_delete("NI");
|
||||
fn = do_one_spec("class", NULL);
|
||||
if(!fmt_add_after("PRI", fn))
|
||||
return "Internal error, no PRI for -c option.";
|
||||
fmt_delete("PRI"); /* we want a different one */
|
||||
fn = do_one_spec("pri", NULL);
|
||||
if(!fmt_add_after("CLS", fn)) return "Lost my CLS!";
|
||||
}
|
||||
}
|
||||
if(!option_source){ /* OK to really muck with stuff */
|
||||
format_node *fn;
|
||||
/* Do personality-specific translations not covered by format_flags.
|
||||
* Generally, these only get hit when personality overrides unix output.
|
||||
* That (mostly?) means the Digital and Debian personalities.
|
||||
*/
|
||||
if((personality & PER_ZAP_ADDR) && (format_flags & FF_Ul)){
|
||||
fn = do_one_spec("sgi_p", NULL);
|
||||
if(fmt_add_after("ADDR", fn)) fmt_delete("ADDR");
|
||||
}
|
||||
if((personality & PER_SANE_USER) && (format_flags & FF_Uf)){
|
||||
fn = do_one_spec("user", NULL);
|
||||
if(fmt_add_after("UID", fn)) fmt_delete("UID");
|
||||
}
|
||||
}
|
||||
|
||||
/* Could scan for duplicates (format and sort) here. Digital does. */
|
||||
return NULL;
|
||||
}
|
||||
|
165
ps/stacktrace.c
Normal file
165
ps/stacktrace.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Gnu debugger stack trace code provided by Peter Mattis
|
||||
* <petm@CSUA.Berkeley.EDU> on Thu, 2 Nov 1995
|
||||
*
|
||||
* Modified for easy use by Albert Cahalan.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define INTERACTIVE 0
|
||||
#define STACK_TRACE 1
|
||||
|
||||
char *stored_prog_name = "You forgot to set \"program\"";
|
||||
static int stack_trace_done;
|
||||
|
||||
/***********/
|
||||
static void debug_stop(char **args){
|
||||
execvp (args[0], args);
|
||||
perror ("exec failed");
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
/***********/
|
||||
static void stack_trace_sigchld(int signum){
|
||||
stack_trace_done = 1;
|
||||
}
|
||||
|
||||
/************/
|
||||
static void stack_trace(char **args){
|
||||
pid_t pid;
|
||||
int in_fd[2];
|
||||
int out_fd[2];
|
||||
fd_set fdset;
|
||||
fd_set readset;
|
||||
struct timeval tv;
|
||||
int sel, index, state;
|
||||
char buffer[256];
|
||||
char c;
|
||||
|
||||
stack_trace_done = 0;
|
||||
signal(SIGCHLD, stack_trace_sigchld);
|
||||
|
||||
if((pipe (in_fd) == -1) || (pipe (out_fd) == -1)){
|
||||
perror ("could open pipe");
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
pid = fork ();
|
||||
if (pid == 0){
|
||||
close (0); dup (in_fd[0]); /* set the stdin to the in pipe */
|
||||
close (1); dup (out_fd[1]); /* set the stdout to the out pipe */
|
||||
close (2); dup (out_fd[1]); /* set the stderr to the out pipe */
|
||||
execvp (args[0], args); /* exec gdb */
|
||||
perror ("exec failed");
|
||||
_exit (0);
|
||||
} else {
|
||||
if(pid == (pid_t) -1){
|
||||
perror ("could not fork");
|
||||
_exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
FD_ZERO (&fdset);
|
||||
FD_SET (out_fd[0], &fdset);
|
||||
|
||||
write (in_fd[1], "backtrace\n", 10);
|
||||
write (in_fd[1], "p x = 0\n", 8);
|
||||
write (in_fd[1], "quit\n", 5);
|
||||
|
||||
index = 0;
|
||||
state = 0;
|
||||
|
||||
for(;;){
|
||||
readset = fdset;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
|
||||
if (sel == -1) break;
|
||||
|
||||
if((sel > 0) && (FD_ISSET (out_fd[0], &readset))){
|
||||
if(read (out_fd[0], &c, 1)){
|
||||
switch(state){
|
||||
case 0:
|
||||
if(c == '#'){
|
||||
state = 1;
|
||||
index = 0;
|
||||
buffer[index++] = c;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
buffer[index++] = c;
|
||||
if((c == '\n') || (c == '\r')){
|
||||
buffer[index] = 0;
|
||||
fprintf (stderr, "%s", buffer);
|
||||
state = 0;
|
||||
index = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(stack_trace_done) break;
|
||||
}
|
||||
|
||||
close (in_fd[0]);
|
||||
close (in_fd[1]);
|
||||
close (out_fd[0]);
|
||||
close (out_fd[1]);
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
/************/
|
||||
void debug(int method, char *prog_name){
|
||||
pid_t pid;
|
||||
char buf[16];
|
||||
char *args[4] = { "gdb", NULL, NULL, NULL };
|
||||
int x;
|
||||
|
||||
snprintf (buf, 99, "%d", getpid ());
|
||||
|
||||
args[1] = prog_name;
|
||||
args[2] = buf;
|
||||
|
||||
pid = fork ();
|
||||
if(pid == 0){
|
||||
switch (method){
|
||||
case INTERACTIVE:
|
||||
fprintf (stderr, "debug_stop\n");
|
||||
debug_stop(args);
|
||||
break;
|
||||
case STACK_TRACE:
|
||||
fprintf (stderr, "stack_trace\n");
|
||||
stack_trace(args);
|
||||
break;
|
||||
}
|
||||
_exit(0);
|
||||
} else if(pid == (pid_t) -1){
|
||||
perror ("could not fork");
|
||||
return;
|
||||
}
|
||||
|
||||
x = 1;
|
||||
while(x); /* wait for debugger? */
|
||||
}
|
||||
|
||||
/************/
|
||||
static void stack_trace_sigsegv(int signum){
|
||||
debug(STACK_TRACE, stored_prog_name);
|
||||
}
|
||||
|
||||
/************/
|
||||
void init_stack_trace(char *prog_name){
|
||||
stored_prog_name = prog_name;
|
||||
signal(SIGSEGV, stack_trace_sigsegv);
|
||||
}
|
Reference in New Issue
Block a user