logo       


[SSI] openssi/procps/ps .cvsignore,NONE,1.1.3.1.2.1 COPYING,NONE,1.1.3.1.2.: msg#00200

Subject: [SSI] openssi/procps/ps .cvsignore,NONE,1.1.3.1.2.1 COPYING,NONE,1.1.3.1.2.1 HACKING,NONE,1.1.3.1.2.1 Makefile,NONE,1.1.3.1.2.1 common.h,NONE,1.1.3.1.2.1 display.c,NONE,1.1.3.1.2.1 escape.c,NONE,1.1.3.1.2.1 global.c,NONE,1.1.3.1.2.1 help.c,NONE,1.1.3.1.2.1 output.c,NONE,1.1.3.1.2.1 parser.c,NONE,1.1.3.1.2.1 ps.1,NONE,1.1.3.1.2.1 regression,NONE,1.1.3.1.2.1 select.c,NONE,1.1.3.1.2.1 sortformat.c,NONE,1.1.3.1.2.1 stacktrace.c,NONE,1.1.3.1.2.1
Update of /cvsroot/ssic-linux/openssi/procps/ps
In directory sc8-pr-cvs1:/tmp/cvs-serv17067/ps

Added Files:
      Tag: OPENSSI-RH
        .cvsignore COPYING HACKING Makefile common.h display.c 
        escape.c global.c help.c output.c parser.c ps.1 regression 
        select.c sortformat.c stacktrace.c 
Log Message:
Commit RedHat psproc 2.0.11-6 to OPENSSI-RH branch.


--- NEW FILE: .cvsignore ---
ps

--- NEW FILE: COPYING ---
                  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!

--- NEW FILE: HACKING ---
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 &lt; 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.

--- NEW FILE: Makefile ---
all: ps

ps: escape.o global.o help.o select.o sortformat.o output.o parser.o display.o
        $(CC) $(LDFLAGS) -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) $(LDFLAGS) -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) --strip ps $(BINDIR)/ps
        install $(OWNERGROUP) --mode a=r ps.1 $(MAN1DIR)/ps.1
        # The following does no harm and on older systems might help
        -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

--- NEW FILE: common.h ---
/*
 * 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 */

/*
 * 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 &quot; */
#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_SUN_MUTATE_a  0x0080
#define PER_ZAP_ADDR      0x0100
#define PER_SANE_USER     0x0200
#define PER_IRIX_l        0x0400

/* Simple selections by bit mask
 * Warning: these bit positions are hard-coded into the table in
 * table_accept(), so do not change them.
 */
#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 */

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

/* Justification control for flags field. */
#define JUST_MASK 0x0f
     /* AIXHACK   0 */
#define USER      1             /* left if text, right if numeric */
#define LEFT      2
#define RIGHT     3
#define UNLIMITED 4
#define WCHAN     5             /* left if text, right if numeric */
#define SIGNAL    6             /* right in 9, or 16 if screen_cols>107 */

#define CUMUL     16            /* mark cumulative (Summed) headers with 'C' */
                                  
/********************** 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 readproc_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;
        const int readproc_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);
extern int html_escape_str(char *dst, const char *src, size_t n);

/********************* UNDECIDED GLOBALS **************/

/* compare.c */
extern void reset_sort_options(void);
extern int mult_lvl_cmp(void *a, void *b);
extern int node_mult_lvl_cmp(void *a, void *b);
extern void dump_keys(void);
extern const char *parse_sort_opt(const char *opt);
extern const char *parse_long_sort(const char *opt);

/* 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 pid_t cached_pid;
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 show_threads;
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;
extern int running_only;
extern int screen_cols;
extern int screen_rows;
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 use_aix_codes;
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 *usage_message;
extern const char *help_message;

/* global.c */
extern void self_info(void);

/* parser.c */
extern int arg_parse(int argc, char *argv[]);

/* output.c */
extern unsigned long seconds_since_boot;

#endif

--- NEW FILE: display.c ---
/*
 * 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

static int need_wchan;

/* 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 <procps-list@xxxxxxxxxx>\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->flags & JUST_MASK) == WCHAN)
                        need_wchan = 1;
                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; readproc() doesn't do it because it needs the uptime */
static void
fill_pcpu(proc_t * buf)
{
        unsigned long total_time;
        unsigned long pcpu = 0;
        unsigned long group_pcpu = 0;
        unsigned long seconds;

        if (buf == NULL)
                return;         /* Just in case */
        total_time = buf->utime + buf->stime;
        if (include_dead_children)
                total_time += (buf->cutime + buf->cstime);
        seconds = seconds_since_boot - buf->start_time / Hertz;
        if (seconds)
                pcpu = ((long long) total_time * 1000 / Hertz) / seconds;
        buf->pcpu = (pcpu > 999) ? 999 : pcpu;


        total_time = buf->group_utime + buf->group_stime;
        if (include_dead_children)
                total_time += (buf->group_cutime + buf->group_cstime);
        if (seconds)
                group_pcpu = ((long long) total_time * 1000 / Hertz) / seconds;
        buf->group_pcpu = (group_pcpu > 999) ? 999 : group_pcpu;
}

static int
get_readproc_flags(void)
{
        format_node *walk;
        int flags;

        flags = 0;
        walk = format_list;
        while (walk) {
                flags |= walk->readproc_flags;
                walk = walk->next;
        }
        if (!show_threads)
                flags |= PROC_SKIPTHREADS;
        return flags;
}


/***** just display */
static void
simple_spew(void)
{
        proc_t buf;
        PROCTAB *ptp;
        ptp = openproc(get_readproc_flags());
        memset(&buf, '#', sizeof (proc_t));
        /* use "ps_" prefix to catch library mismatch */
        while (ps_readproc(ptp, &buf)) {
                /* hex_dump(&buf); */
                fill_pcpu(&buf);        /* fill in %CPU */
                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 */
}

/*
 * thread_group - are these two processes in the same thread group?
 */
static int
thread_group(proc_t * parent, proc_t * child)
{
        int i;

        if (parent->vm_rss != child->vm_rss)
                return 0;
        if (parent->vm_size != child->vm_size)
                return 0;
        if (parent->cmdline == NULL || child->cmdline == NULL)
                return 0;
        for (i = 0; parent->cmdline[i] != NULL && child->cmdline[i] != NULL;
             i++) {
                if (strcmp(parent->cmdline[i], child->cmdline[i]) != 0)
                        return 0;
        }
        if (parent->cmdline[i] != NULL || child->cmdline[i] != NULL)
                return 0;

        /*
         * the processes share executable name, allocated VM size, RSS size and
         * are parent-child - they must be threads!
         */
        return 1;
}

/*
 * flag_threads - flag processes that are in the same thread group.
 */
static void
flag_threads(int pid)
{
        unsigned int *pid_array;
        int max = 1, parent, i, is_ntpl_thread;

        for (i = 0; i < pid; i++) {
                if (processes[i]->pid > max)
                        max = processes[i]->pid;
                if (processes[i]->ppid > max)
                        max = processes[i]->ppid;
        }
        pid_array = malloc(sizeof (unsigned int) * (max + 1));
        if (!pid_array)
                return;
        memset(pid_array, 0, sizeof (unsigned int) * (max + 1));

        for (i = 0; i < pid; i++)
                pid_array[processes[i]->pid] = i + 1;

        for (i = 0; i < pid; i++) {
                is_ntpl_thread = processes[i]->tgid != 0 && processes[i]->tgid 
!= processes[i]->pid;
                processes[i]->thread = is_ntpl_thread;
                        
                if (!is_ntpl_thread) {
                        /* Check for old-style LinuxThread or clone() threads: 
*/
                        if (processes[i]->ppid <= 1
                            || pid_array[processes[i]->ppid] == 0)
                                continue;
                        parent = pid_array[processes[i]->ppid] - 1;
                        if (thread_group(processes[parent], processes[i]))
                                processes[i]->thread = 1;
                }
        }

        /*
         * yield the master thread the CPU times from the child threads
         */
        for (i = 0; i < pid; i++) {
                if (processes[i]->thread &&
                    (processes[i]->tgid == 0 ||
                     processes[i]->tgid == processes[i]->pid)) {
                        /* Non NTPL thread, need to manually compute thread 
stuff */
                        parent = i;
                        do {
                                parent = pid_array[processes[parent]->ppid] - 1;
                        } while (processes[parent]->thread);
                        
                        processes[parent]->group_cstime += 
processes[i]->group_cstime;
                        processes[parent]->group_cutime += 
processes[i]->group_cutime;
                        processes[parent]->group_stime += 
processes[i]->group_stime;
                        processes[parent]->group_utime += 
processes[i]->group_utime;
                        processes[parent]->group_pcpu += 
processes[i]->group_pcpu;
                        
                        /*
                         * prevent a possible overflow due to bad accounting
                         */
                        if (processes[parent]->group_pcpu > 999)
                                processes[parent]->group_pcpu = 999;
                } 
        }

        /* Move threadgroup cpu info counters to normal ones, since
         * we're not showing subthreads
         */
        for (i = 0; i < pid; i++) {
                if (!processes[i]->thread) {
                        processes[i]->cstime = processes[i]->group_cstime;
                        processes[i]->cutime = processes[i]->group_cutime;
                        processes[i]->stime = processes[i]->group_stime;
                        processes[i]->utime = processes[i]->group_utime;
                        processes[i]->pcpu = processes[i]->group_pcpu;
                }
        }
        
        free(pid_array);
}

/***** show pre-sorted array of process pointers */
static void
show_proc_array(int n)
{
        proc_t **p = processes;
        while (n--) {
                if (show_threads || !(*p)->thread)
                        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 */
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';
        }
        if (show_threads || !processes[self]->thread)
                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 more_children = 1;
                if (i >= n)
                        break;  /* over the edge */
                if (i + 1 >= n)
                        more_children = 0;
                else if (processes[i + 1]->ppid != processes[self]->pid)
                        more_children = 0;
                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(get_readproc_flags());
        while ((retbuf = ps_readproc(ptp, NULL))) {
                fill_pcpu(retbuf);      /* fill in %CPU */
                if (want_this_proc(retbuf))
                        processes[n++] = retbuf;
                else
                        free(retbuf);
        }
        closeproc(ptp);
        if (!n)
                return;         /* no processes */

        if (!show_threads)
                flag_threads(n);

        if (forest_type)
                prep_forest_sort();
        if (sort_list)
                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[])
{
        if (getuid() != geteuid()) {
                fprintf(stderr,
                        "This /bin/ps is not secure for setuid operation.\n");
                exit(1);
        }
        if (getgid() != getegid()) {
                fprintf(stderr,
                        "This /bin/ps is not secure for setgid operation.\n");
                exit(1);
        }
#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 */
#ifndef DEBUG
                        case SIGSEGV:   /* I want core dumps to debug if I 
don't get a backtrace */
#endif
                        case SIGWINCH:; /* we aren't going to change output 
line length later... */
                        }
        } 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 (!need_wchan || open_psdb(namelist_file))
                wchan_is_number = 1;
        if (forest_type || sort_list || !show_threads)
                fancy_spew();   /* sort or forest */
        else
                simple_spew();  /* no sort, no forest */
        show_one_proc((proc_t *) - 1);  /* no output yet? */
        return 0;
}

--- NEW FILE: escape.c ---
/*
 * 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;
}

/* sanitize a string for HTML */
int
html_escape_str(char *dst, const char *src, size_t n)
{
        unsigned char c;
        size_t i;
        const char *codes =
            "Z-------------------------------"
            "**q***&*********************<*>*"
            "********************************"
            "*******************************-"
            "--------------------------------"
            "********************************"
            "********************************"
            "********************************";
        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;
                case '&':
                        if (i + 5 > n)
                                goto leave;
                        i += 5;
                        *(dst++) = '&';
                        *(dst++) = 'a';
                        *(dst++) = 'm';
                        *(dst++) = 'p';
                        *(dst++) = ';';
                        break;
                case '<':
                        if (i + 4 > n)
                                goto leave;
                        i += 4;
                        *(dst++) = '&';
                        *(dst++) = 'l';
                        *(dst++) = 't';
                        *(dst++) = ';';
                        break;
                case '>':
                        if (i + 4 > n)
                                goto leave;
                        i += 4;
                        *(dst++) = '&';
                        *(dst++) = 'g';
                        *(dst++) = 't';
                        *(dst++) = ';';
                        break;
                case 'q':
                        if (i + 6 > n)
                                goto leave;
                        i += 6;
                        *(dst++) = '&';
                        *(dst++) = 'q';
                        *(dst++) = 'u';
                        *(dst++) = 'o';
                        *(dst++) = 't';
                        *(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;
}

--- NEW FILE: global.c ---
/*
 * 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>
#include <sys/stat.h>
#include <limits.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;
pid_t cached_pid = -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 show_threads = -1;
int include_dead_children = -1;
int lines_to_next_header = -1;
int max_line_width = 666;
const char *namelist_file = (const char *) 0xdeadbeef;
int negate_selection = -1;
int running_only = -1;
unsigned personality = 0xffffffff;
int prefer_bsd = -1;
int screen_cols = -1;
int screen_rows = -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 use_aix_codes = -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;
}

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 {
                struct stat sb;
                fstat(1, &sb);
                if (!S_ISFIFO(sb.st_mode)) {
                        /* TODO: ought to do tgetnum("co") and tgetnum("li") 
now */
                        screen_cols = 80;
                        screen_rows = 24;
                } else {
                        screen_cols = 80 * 4;   /* arbitrary */
                        screen_rows = 24;
                }
        }
        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[] = {
                {"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},
                {"posix", &&case_posix},
                {"sco", &&case_sco},
                {"sgi", &&case_sgi},
                {"solaris2", &&case_solaris2},
                {"sunos4", &&case_sunos4},
                {"sysv", &&case_sysv},
                {"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 = 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.  :-)   */
        /* FIXME: change to enum's and switch statement */

      case_bsd:
        personality = PER_FORCE_BSD | PER_BSD_h | PER_BSD_m;
        prefer_bsd = 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 = 1;
        return NULL;

      case_debian:              /* Toss this? They don't seem to care much. */
      case_gnu:
        personality = PER_GOOD_o | PER_CUMUL_MARKED;
        prefer_bsd = 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_compaq:
      case_digital:
        personality = PER_GOOD_o | PER_BSD_h;
        prefer_bsd = 1;         /* TODO check this */
        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_SUN_MUTATE_a;
        prefer_bsd = 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_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_pid = getpid();
        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;
        show_threads = 0;
        include_dead_children = 0;
        lines_to_next_header = 1;
        max_line_width = 80;
        namelist_file = NULL;
        negate_selection = 0;
        running_only = 0;
        selection_list = NULL;
        simple_select = 0;
        sort_list = NULL;
        unix_f_option = 0;
        use_aix_codes = 0;
        user_is_number = 0;
        wchan_is_number = 0;
}

/*********** spew variables ***********/
void
self_info(void)
{
        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__);

        fprintf(stderr,
                "header_gap=%d lines_to_next_header=%d max_line_width=%d\n"
                "screen_cols=%d screen_rows=%d\n"
                "\n",
                header_gap, lines_to_next_header, max_line_width,
                screen_cols, screen_rows);

/*  open_psdb(namelist_file); */
        fprintf(stderr,
                "personality=0x%08x (from \"%s\")\n"
                "EUID=%d TTY=%d,%d Hertz=%Lu\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>"  */
            );
}

--- NEW FILE: help.c ---
/*
 * 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 *usage_message =
    "usage: ps -[Unix98 options]\n"
    "       ps [BSD-style options]\n"
    "       ps --[GNU-style long options]\n"
    "       ps --help for a command summary\n";

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 --html --nul -M --info
 *
 */

--- NEW FILE: output.c ---
/*
 * Copyright 1999 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.
 */

/*
 * This file is really gross, and I know it. I looked into several
 * alternate ways to deal with the mess, and they were all ugly.
 *
 * FreeBSD has a fancy hack using offsets into a struct -- that
 * saves code but it is _really_ gross. See the PO macro below.
 *
[...1739 lines suppressed...]
        case 16384:
                page_shift = 14;
                break;
        case 8192:
                page_shift = 13;
                break;
        default:
                fprintf(stderr, "Unknown page size! (assume 4096)\n");
        case 4096:
                page_shift = 12;
                break;
        case 2048:
                page_shift = 11;
                break;
        case 1024:
                page_shift = 10;
                break;
        }
        check_header_width();
}

--- NEW FILE: parser.c ---
/*
 * 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.
 */

/* Ought to have debug print stuff like this:
 * #define Print(fmt, args...) printf("Debug: " fmt, ## args)
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

[...1294 lines suppressed...]

#if 0
        /* I promised people that this would go away with the new version... */
        if (!(personality & PER_FORCE_BSD))
                fprintf(stderr, "Bad syntax, perhaps a bogus '-'?\n");
#endif

        choose_dimensions();
        return 0;

      total_failure:
        reset_parser();
        if (personality & PER_FORCE_BSD)
                fprintf(stderr, "ps: error: %s\n", err2);
        else
                fprintf(stderr, "ps: error: %s\n", err);
        fputs(usage_message, stderr);
        exit(1);
        /* return 1; *//* useless */
}

--- NEW FILE: ps.1 ---
,\" t
.\" (The preceding line is a note to broken versions of man to tell
.\" them to pre-process this man page with tbl)
.\" Man page for ps.
.\" Licensed under version 2 of the GNU General Public License.
.\" Modified by Michael K. Johnson from a gross plain-text hack
.\" by Albert Cahalan of Michael's original version.
.\"
.TH PS 1 "March 11, 1999" "Linux" "Linux User's Manual"
.SH NAME
ps \- report process status
.SH SYNOPSIS
ps [\fIoptions\fP]

.SH 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.

.SH "COMMAND-LINE OPTIONS"

This version of ps accepts several kinds of options.
.br
.RS
Unix98 options may be grouped and must be preceeded by a dash.
.br
BSD options may be grouped and must not be used with a dash.
.br
GNU long options are preceeded by two dashes.
.RE
.br
Options of different types may be freely mixed.

Set the \f(CWI_WANT_A_BROKEN_PS\fR environment variable to force BSD
syntax even when options are preceeded by a dash. The \f(CWPS_PERSONALITY\fR
environment variable (described below) provides more detailed control of
ps behavior.

.SS "SIMPLE PROCESS SELECTION"
.TS
lB lB
lfCW l.
Switch  Description
.TH
-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       T{
select all processes on a terminal, including those of other users
T}
g       T{
really all, even group leaders (does nothing w/o SunOS settings)
T}
r       restrict output to running processes
x       select processes without controlling ttys
--deselect      negate selection
.TE

.SS "PROCESS SELECTION BY LIST"
.TS
lB lB
lfCW l.
Switch  Description
.TH
-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
.TE

.SS "OUTPUT FORMAT CONTROL"
.TS
lB lB
lfCW l.
Switch  Description
.TH
-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
.TE

.SS "OUTPUT MODIFIERS"
.TS
lB lB
lfCW l.
Switch  Description
.TH
-H      show process hierarchy (forest)
-m      show all 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       T{
include some dead child process data (as a sum with the parent)
T}
c       true command name
e       show environment after the command
f       ASCII-art process hierarchy (forest)
h       T{
do not print header lines (repeat header lines in BSD personality)
T}
m       all threads
n       numeric output for WCHAN and USER
w       wide output
--cols  set screen width
--columns       set screen width
--cumulative    T{
include some dead child process data (as a sum with the parent)
T}
--forest        ASCII art process tree
--html  HTML escaped output
--headers       repeat header lines
--no-headers    print no header line at all
--lines set screen height
--nul   unjustified output with NULs
--null  unjustified output with NULs
--rows  set screen height
--sort  specify sorting order
--width set screen width
--zero  unjustified output with NULs
.TE

.SS INFORMATION
.TS
lB lB
lfCW l.
Switch  Description
.TH
-V      print version
L       list all format specifiers
V       show version info
--help  print help message
--info  print debugging info
--version       print version
.TE

.SS OBSOLETE
.TS
lB lB
lfCW l.
Switch  Description
.TH
A       increase 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)
.TE

.SH 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 of 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:
.RS
$PS_SYSTEM_MAP
.br
/boot/System.map-`uname -r`
.br
/boot/System.map
.br
/lib/modules/`uname -r`/System.map
.br
/usr/src/linux/System.map
.br
/System.map
.RE
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.

.SS "PROCESS FLAGS"
.TS
lfCW lfCW l.
FORKNOEXEC      1       forked but didn't exec
SUPERPRIV       2       used super-user privileges
DUMPCORE        4       dumped core
.TE

.SS "PROCESS STATE CODES"
.TS
lfCW l.
D       uninterruptible sleep (usually IO)
R       runnable (on run queue)
S       sleeping
T       traced or stopped
Z       a defunct ("zombie") process
.TE

For BSD formats and when the "stat" keyword is used, additional
letters may be displayed:
.TS
lfCW l.
W       has no resident pages
<       high-priority process
N       low-priority task
L       has pages locked into memory (for real-time and custom IO)
.TE

.SS "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.

.TS
lB lB lB
lfCW lfCW l.
KEY     LONG    DESCRIPTION
.TH
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 bytes
y       priority        kernel scheduling priority
.TE

.SS "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"

.TS
lB lB lB
lfCW lfCW l.
CODE    NORMAL  HEADER
.TH
%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
.TE

.SS "STANDARD FORMAT SPECIFIERS"

These may be used to control both output format and sorting.
.br
For example:  ps -eo pid,user,args --sort user

.TS
lB lB
lfCW lfCW.
CODE    HEADER
.TH
%cpu    %CPU
%mem    %MEM
alarm   ALARM
args    COMMAND
blocked BLOCKED
bsdstart        START
bsdtime TIME
c       C
caught  CAUGHT
cp      CP
cpu     CPU
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
policy  POL
ppid    PPID
pri     PRI
rgid    RGID
rgroup  RGROUP
rss     RSS
rssize  RSS
rsz     RSZ
rtprio  RTPRIO
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
ucomm   COMMAND
uid     UID     
uid_hack        UID
uname   USER    
user    USER    
vsize   VSZ     
vsz     VSZ     
wchan   WCHAN   
.TE

.SS "ENVIRONMENT VARIABLES"

The following environment variables could affect ps:
.TS
lfCW l.
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_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
.TE

In general, it is a bad idea to set these variables. The two exceptions
are CMD_ENV (or PS_PERSONALITY), to set the desired default personality,
and POSIXLY_CORRECT (or UNIX95), which should be set for Unix98 standard
compliance.

.TS
lfCW lb
lfCW l.
PS_PERSONALITY  Description
.TH
\fInone\fP      "Do the right thing"
aix     like AIX ps
bsd     like FreeBSD ps
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   deviate from Unix98 for convenience only
old     like the original Linux ps
posix   standard
sco     like SCO ps
sgi     like Irix ps
sun     like SunOS 4 ps
sunos   like SunOS 4 ps
sysv    standard
unix    standard
unix95  standard
unix98  standard
.TE

.SH EXAMPLES

To see every process on the system using standard syntax:
.RS
ps -e
.RE
To see every process on the system using BSD syntax:
.RS
ps ax
.RE
To see every process except those running as root (real & effective ID)
.RS
ps -U root -u root -N
.RE
To see every process with a user-defined format:
.RS
ps -eo pid,tt,user,fname,tmout,f,wchan
.RE
Odd display with AIX field descriptors:
.RS
ps -o "%u : %U : %p : %a"
.RE
Print only the process IDs of syslogd:
.RS
ps -C syslogd -o pid=
.RE

.SH "SEE ALSO"
top(1) pstree(1) proc(5)

.SH STANDARDS
This ps can be set to conform to version 2 of the Single Unix Specification.

.SH AUTHOR
ps was originally written by Branko Lankester <lankeste@xxxxxxxxxx>.
.br
Michael K. Johnson <johnsonm@xxxxxxxxxx> re-wrote it significantly to
use the proc filesystem, changing a few things in the process.
.br
Michael Shields <shields@xxxxxxxx> added the pid-list feature.
.br
Charles Blake <cblake@xxxxxxx> 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.
.br
David Mosberger-Tang wrote the generic BFD support for psupdate.
.br
Albert Cahalan <acahalan@xxxxxxxxxx> rewrote ps for full Unix98 and
BSD support, along with some ugly hacks for obsolete and foreign syntax.

Michael K. Johnson <johnsonm@xxxxxxxxxx> is the current maintainer.

Please send bug reports to <procps-list@xxxxxxxxxx>

--- NEW FILE: regression ---
-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


--- NEW FILE: select.c ---
/*
 * 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)
{
        if (!simple_select) {   /* don't want a 'g' added to this (or do we?) */
                select_bits = 0xaa00;
                return NULL;
        }
        /* For everybody but Sun, the 'g' option is a NOP */
        if (!(personality & PER_SUN_MUTATE_a)
            && !(simple_select & (SS_U_a | SS_U_d)))
                simple_select |= SS_B_g;
        switch (simple_select) {
        case SS_U_a | SS_U_d:
        case SS_B_x | SS_B_a:
        case SS_U_d:
                select_bits = 0x3333;
                break;
        case SS_U_a:
                select_bits = 0x0303;
                break;
        case SS_B_a:
                select_bits = 0x3300;
                break;
        case SS_B_x:
                select_bits = 0x2222;
                break;
        case SS_B_g:
                select_bits = 0xaa00;
                break;
        case SS_B_g | SS_B_a:
                select_bits = 0x0f00;
                break;
        case SS_B_g | SS_B_x:
                select_bits = 0xaaaa;
                break;
        case SS_B_g | SS_B_x | SS_B_a:
                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));
}

#if 0
/***** selected by simple option? */
static int
table_accept(proc_t * buf)
{
        unsigned proc_index;
#ifdef ACT_LIKE_SUNOS4
        static unsigned table[] = {
                0xfffffff0, 0xfffffff0, 0xccccccc0, 0xccccccc0, /* process has 
some other tty */
                0xfafafaf0, 0xfafafafa, 0xc8c8c8c0, 0xc8c8c8c8, /* no tty, ps 
itself has one */
                0xfffffff0, 0xffffffff, 0xccccccc0, 0xcccccccc, /* process has 
same tty as ps */
                0xfafafaf0, 0xfafafafa, 0xc8c8c8c0, 0xc8c8c8c8  /* nobody has a 
tty */
        };
#else
        static unsigned table[] = {
                0xfffffff0, 0xfffffff0, 0xffffccc0, 0xffffccc0, /* process has 
some other tty */
                0xfafafaf0, 0xfafafafa, 0xfafac8c0, 0xfafac8c8, /* no tty, ps 
itself has one */
                0xfffffff0, 0xffffffff, 0xffffccc0, 0xffffcccc, /* process has 
same tty as ps */
                0xfafafaf0, 0xfafafafa, 0xfafac8c0, 0xfafac8c8  /* nobody has a 
tty */
        };
#endif
        proc_index = (has_our_euid(buf) << 0)
            | (session_leader(buf) << 1)
            | (without_a_tty(buf) << 2)
            | (on_our_tty(buf) << 3);
/*
  printf("0x%08x 0x%08x 0x%08x %-8.8s\n",
         table[proc_index],
         (1<<simple_select),
         table[proc_index] & (1<<simple_select),
         buf->cmd);
*/
        return (table[proc_index] & (1 << simple_select));
}
#endif

/***** 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;
}

--- NEW FILE: sortformat.c ---
/*
 * 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>
[...974 lines suppressed...]
                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, 1);
                        if (fmt_add_after("ADDR", fn))
                                fmt_delete("ADDR");
                }
                if ((personality & PER_SANE_USER) && (format_flags & FF_Uf)) {
                        fn = do_one_spec("user", NULL, 1);
                        if (fmt_add_after("UID", fn))
                                fmt_delete("UID");
                }
        }

        /* Could scan for duplicates (format and sort) here. Digital does. */
        return NULL;
}

--- NEW FILE: stacktrace.c ---
/*
 * Gnu debugger stack trace code provided by Peter Mattis
 * <petm@xxxxxxxxxxxxxxxxx> 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;

        sprintf(buf, "%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);
}




-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn


Ruby Jobs
Java Jobs
Jobs in California
more...
what
job title, keywords
where
city, state, zip
jobs by