Index: extern.h =================================================================== RCS file: /cvsroot/basesrc/bin/ps/extern.h,v retrieving revision 1.19 diff -p -u -r1.19 extern.h --- extern.h 2000/06/07 04:57:59 1.19 +++ extern.h 2000/06/11 17:47:08 @@ -43,7 +43,7 @@ struct varent; extern double ccpu; extern int eval, fscale, mempages, nlistread, rawcpu; extern int sumrusage, termwidth, totwidth; -extern int needenv, needcomm, commandonly, dontuseprocfs, use_procfs; +extern int needenv, commandonly, dontuseprocfs, use_procfs, sysv; extern uid_t myuid; extern kvm_t *kd; extern VAR var[]; @@ -54,10 +54,12 @@ void command __P((struct kinfo_proc2 *, void cputime __P((struct kinfo_proc2 *, VARENT *, int)); int donlist __P((void)); int donlist_sysctl __P((void)); +void etime __P((struct kinfo_proc2 *, VARENT *, int)); void fmt_puts __P((char *, int *)); void fmt_putc __P((int, int *)); double getpcpu __P((struct kinfo_proc2 *)); double getpmem __P((struct kinfo_proc2 *)); +void gname __P((struct kinfo_proc2 *, VARENT *, int)); void logname __P((struct kinfo_proc2 *, VARENT *, int)); void longtname __P((struct kinfo_proc2 *, VARENT *, int)); void lstarted __P((struct kinfo_proc2 *, VARENT *, int)); @@ -75,11 +77,14 @@ struct kinfo_proc2 *getkinfo_procfs __P((int, int, int *)); char **procfs_getargv __P((const struct kinfo_proc2 *, int)); void pvar __P((struct kinfo_proc2 *, VARENT *, int)); +void rgname __P((struct kinfo_proc2 *, VARENT *, int)); void rssize __P((struct kinfo_proc2 *, VARENT *, int)); void runame __P((struct kinfo_proc2 *, VARENT *, int)); void showkey __P((void)); +void size __P((struct kinfo_proc2 *, VARENT *, int)); void started __P((struct kinfo_proc2 *, VARENT *, int)); void state __P((struct kinfo_proc2 *, VARENT *, int)); +void sysv_state __P((struct kinfo_proc2 *, VARENT *, int)); void tdev __P((struct kinfo_proc2 *, VARENT *, int)); void tname __P((struct kinfo_proc2 *, VARENT *, int)); void tsize __P((struct kinfo_proc2 *, VARENT *, int)); Index: keyword.c =================================================================== RCS file: /cvsroot/basesrc/bin/ps/keyword.c,v retrieving revision 1.25 diff -p -u -r1.25 keyword.c --- keyword.c 2000/06/07 04:57:59 1.25 +++ keyword.c 2000/06/11 17:47:08 @@ -88,13 +88,19 @@ VAR var[] = { {"%mem", "%MEM", NULL, 0, pmem}, {"acflag", "ACFLG", NULL, 0, pvar, 0, POFF(p_acflag), USHORT, "x"}, {"acflg", "", "acflag"}, + {"addr", "ADDR", NULL, 0, pvar, 0, POFF(p_paddr), KPTR, "x"}, + {"args", "COMMAND", NULL, LJUST, command}, {"blocked", "", "sigmask"}, + {"c", "C", NULL, 0, pvar, 0, POFF(p_estcpu), UINT, "d"}, {"caught", "", "sigcatch"}, - {"command", "COMMAND", NULL, COMM|LJUST, command}, + {"comm", "COMMAND", NULL, COMM|LJUST, command}, + {"command", "COMMAND", NULL, LJUST, command}, {"cpu", "CPU", NULL, 0, pvar, 0, POFF(p_estcpu), UINT, "d"}, {"cputime", "", "time"}, + {"etime", "ELAPSED", NULL, 0, etime}, {"f", "F", NULL, 0, pvar, 0, POFF(p_flag), INT, "x"}, {"flags", "", "f"}, + {"group", "GROUP", NULL, LJUST, gname}, {"holdcnt", "HOLDCNT", NULL, 0, pvar, 0, POFF(p_holdcnt), INT, "d"}, {"ignored", "", "sigignore"}, {"inblk", "INBLK", NULL, 0, pvar, 0, POFF(p_uru_inblock), ULONG, "d"}, @@ -138,11 +144,13 @@ VAR var[] = { GID("rgid", "RGID", pvar, POFF(p_rgid)), /* XXX */ {"rlink", "RLINK", NULL, 0, pvar, 0, POFF(p_back), KPTR, "x"}, + {"rgroup", "RGROUP", NULL, LJUST, rgname}, {"rss", "RSS", NULL, 0, p_rssize}, {"rssize", "", "rsz"}, {"rsz", "RSZ", NULL, 0, rssize}, UID("ruid", "RUID", pvar, POFF(p_ruid)), {"ruser", "RUSER", NULL, LJUST, runame}, + {"s", "S", NULL, 0, sysv_state}, {"sess", "SESS", NULL, 0, pvar, 0, POFF(p_sess), KPTR24, "x"}, PID("sid", "SID", pvar, POFF(p_sid)), {"sig", "PENDING", @@ -159,6 +167,7 @@ VAR var[] = { {"state", "STAT", NULL, LJUST, state}, GID("svgid", "SVGID", pvar, POFF(p_gid)), UID("svuid", "SVUID", pvar, POFF(p_uid)), + {"sz", "SZ", NULL, 0, size}, {"tdev", "TDEV", NULL, 0, tdev}, {"time", "TIME", NULL, 0, cputime}, PID("tpgid", "TGPID", pvar, POFF(p_tpgid)), Index: print.c =================================================================== RCS file: /cvsroot/basesrc/bin/ps/print.c,v retrieving revision 1.55 diff -p -u -r1.55 print.c --- print.c 2000/06/08 13:30:40 1.55 +++ print.c 2000/06/11 17:47:08 @@ -111,6 +111,8 @@ static void doubleprintorsetwidth __P(( static void intprintorsetwidth __P((VAR *, int, int)); static void strprintorsetwidth __P((VAR *, const char *, int)); +static time_t now; + #define min(a,b) ((a) <= (b) ? (a) : (b)) #define max(a,b) ((a) >= (b) ? (a) : (b)) @@ -279,6 +281,12 @@ command(ki, ve, mode) left = v->width; } else left = -1; + + if (sysv && P_ZOMBIE(ki)) { + fmt_puts("", &left); + return; + } + if (needenv && kd) { argv = kvm_getenvv2(kd, ki, termwidth); if ((p = argv) != NULL) { @@ -289,33 +297,34 @@ command(ki, ve, mode) } } } - if (needcomm) { - name = ki->p_comm; - if (!commandonly) { - argv = NULL; - if (!use_procfs) - argv = kvm_getargv2(kd, ki, termwidth); - else - argv = procfs_getargv(ki, termwidth); - if ((p = argv) != NULL) { - while (*p) { - fmt_puts(*p, &left); - p++; - fmt_putc(' ', &left); - } - } - if (titlecmp(name, argv)) { - fmt_putc('(', &left); - fmt_puts(name, &left); - fmt_putc(')', &left); - } - if (use_procfs && argv) { - free(argv[0]); - free(argv); + + name = ki->p_comm; + if (!commandonly) { + argv = NULL; + if (!use_procfs) + argv = kvm_getargv2(kd, ki, termwidth); + else + argv = procfs_getargv(ki, termwidth); + if ((p = argv) != NULL) { + while (*p) { + fmt_puts(*p, &left); + if (v->flag & COMM) + break; + p++; + fmt_putc(' ', &left); } - } else { + } + if (titlecmp(name, argv)) { + fmt_putc('(', &left); fmt_puts(name, &left); + fmt_putc(')', &left); } + if (use_procfs && argv) { + free(argv[0]); + free(argv); + } + } else { + fmt_puts(name, &left); } if (ve->next && left > 0) printf("%*s", left, ""); @@ -414,6 +423,49 @@ state(k, ve, mode) } void +sysv_state(k, ve, mode) + struct kinfo_proc2 *k; + VARENT *ve; + int mode; +{ + int ch; + VAR *v; + + if (mode == WIDTHMODE) + /* The header width is the same the max column width */ + return; + + v = ve->var; + switch (k->p_stat) { + case SSTOP: + ch = 'T'; + break; + + case SSLEEP: + ch = 'S'; + break; + + case SRUN: + case SIDL: + ch = 'R'; + break; + + case SONPROC: + ch = 'O'; + break; + + case SZOMB: + case SDEAD: + ch = 'Z'; + break; + + default: + ch = '?'; + } + putchar(ch); +} + +void pnice(k, ve, mode) struct kinfo_proc2 *k; VARENT *ve; @@ -462,6 +514,30 @@ runame(k, ve, mode) } void +gname(k, ve, mode) + struct kinfo_proc2 *k; + VARENT *ve; + int mode; +{ + VAR *v; + + v = ve->var; + strprintorsetwidth(v, user_from_uid(k->p_gid, 0), mode); +} + +void +rgname(k, ve, mode) + struct kinfo_proc2 *k; + VARENT *ve; + int mode; +{ + VAR *v; + + v = ve->var; + strprintorsetwidth(v, user_from_uid(k->p_rgid, 0), mode); +} + +void tdev(k, ve, mode) struct kinfo_proc2 *k; VARENT *ve; @@ -559,10 +635,9 @@ started(k, ve, mode) int mode; { VAR *v; - static time_t now; time_t startt; struct tm *tp; - char buf[100], *cp; + char buf[50], *cp; /* * XXX: The maximum width of this field is the same as the header @@ -606,7 +681,7 @@ lstarted(k, ve, mode) { VAR *v; time_t startt; - char buf[100]; + char buf[10]; v = ve->var; if (!k->p_uvalid) { @@ -622,13 +697,65 @@ lstarted(k, ve, mode) /* assume all times are the same length */ if (mode != WIDTHMODE || v->width == 0) { - (void)strftime(buf, sizeof(buf) -1, "%c", + (void)strftime(buf, sizeof(buf) - 1, "%c", localtime(&startt)); strprintorsetwidth(v, buf, mode); } } void +etime(k, ve, mode) + struct kinfo_proc2 *k; + VARENT *ve; + int mode; +{ + VAR *v; + char buf[16]; + int fmtlen; + long d, h, m, s; + + v = ve->var; + if (!k->p_uvalid) { + /* + * Minimum width is less than header - we don't + * need to check it every time. + */ + if (mode == PRINTMODE) + (void)printf("%*s", v->width, "-"); + return; + } + + if (!now) + (void)time(&now); + + s = now - k->p_ustart_sec; + m = s / SECSPERMIN; + s %= SECSPERMIN; + h = m / MINSPERHOUR; + m %= MINSPERHOUR; + d = h / HOURSPERDAY; + h %= HOURSPERDAY; + + if (mode == WIDTHMODE) { + if (d == 0) { + fmtlen = 8; + } else { + fmtlen = (int)log10((double)d) + 1 + 9; + } + if (fmtlen > v->width) + v->width = fmtlen; + } else { + if (d == 0) + snprintf(buf, sizeof(buf), "%02ld:%02ld:%02ld", + h, m, s); + else + snprintf(buf, sizeof(buf), "%ld-%02ld:%02ld:%02ld", + d, h, m, s); + strprintorsetwidth(v, buf, mode); + } +} + +void wchan(k, ve, mode) struct kinfo_proc2 *k; VARENT *ve; @@ -655,6 +782,18 @@ wchan(k, ve, mode) if (mode == PRINTMODE) (void)printf("%-*s", v->width, "-"); } +} + +void +size(k, ve, mode) + struct kinfo_proc2 *k; + VARENT *ve; + int mode; +{ + VAR *v; + + v = ve->var; + intprintorsetwidth(v, k->p_vm_rssize, mode); } #define pgtok(a) (((a)*getpagesize())/1024) Index: ps.c =================================================================== RCS file: /cvsroot/basesrc/bin/ps/ps.c,v retrieving revision 1.40 diff -p -u -r1.40 ps.c --- ps.c 2000/06/08 13:30:40 1.40 +++ ps.c 2000/06/11 17:47:08 @@ -112,11 +112,13 @@ __RCSID("$NetBSD: ps.c,v 1.40 2000/06/08 * ARGOPTS must contain all option characters that take arguments * (except for 't'!) - it is used in kludge_oldps_options() */ -#define GETOPTSTR "acCeghjKLlM:mN:O:o:p:rSTt:U:uvW:wx" +#define GETOPTSTR "acCefghjKlLmM:N:o:O:p:rSt:TuU:vwW:x" #define ARGOPTS "MNOopUW" +#define SYSVGETOPTSTR "aAdefg:G:jln:o:p:st:u:U:y" + struct kinfo_proc2 *kinfo; -struct varent *vhead, *vtail; +struct varent *vhead; int eval; /* exit value */ int rawcpu; /* -C */ @@ -125,7 +127,7 @@ int dontuseprocfs; /* -K */ int termwidth; /* width of screen (0 == infinity) */ int totwidth; /* calculated width of requested variables */ -int needcomm, needenv, commandonly, use_procfs; +int needenv, commandonly, use_procfs, sysv; uid_t myuid; enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; @@ -134,10 +136,10 @@ static struct kinfo_proc2 *getkinfo_kvm __P((kvm_t *, int, int, int *)); static char *kludge_oldps_options __P((char *)); static int pscomp __P((const void *, const void *)); -static void scanvars __P((void)); static void usage __P((void)); int main __P((int, char *[])); +/* BSD formats */ char dfmt[] = "pid tt state time command"; char jfmt[] = "user pid ppid pgid sess jobc state tt time command"; char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command"; @@ -146,6 +148,586 @@ char o2[] = "tt state time command"; char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command"; char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command"; +/* System V / SUSv2 formats. Ugh, there must be a better way... */ +char sysv_fmt[] = "pid tt time command"; +char sysv_jfmt[] = "pid pgid sid tt time command"; + +char sysv_ffmt[] = "user pid ppid " /*c*/ " start tt time command"; +char sysv_fjfmt[] = "user pid ppid pgid sid " /*c*/ " start tt time command"; + +char sysv_flfmt[] = "f s user pid ppid c pri ni addr sz wchan start tty time command"; +char sysv_flyfmt[] = "s user pid ppid c pri ni rss sz wchan start tty time command"; +char sysv_fljfmt[] = "f s user pid ppid pgid sid c pri ni addr sz wchan start tty time command"; +char sysv_fljyfmt[] = "s user pid ppid pgid sid c pri ni rss sz wchan start tty time command"; + +char sysv_lfmt[] = "f s uid pid ppid c pri ni addr sz wchan tty time command"; +char sysv_lyfmt[] = "s uid pid ppid c pri ni rss sz wchan tty time command"; +char sysv_ljfmt[] = "f s uid pid ppid pgid sid c pri ni addr sz wchan tty time command"; +char sysv_ljyfmt[] = "s uid pid ppid pgid sid c pri ni rss sz wchan tty time command"; + + +/* HPUX: + def: "pid tty time comm" + -f "user pid ppid cpu stime tty time args" + -l "flags state uid pid ppid cpu intpri nice addr sz wchan tty time comm" + -fl "flags state user pid ppid cpu intpri nice addr sz wchan stime tty time args" + -c remove "cpu nice", replace "intpri" with "cls pri" + -j add "pgid sid" after "ppid" (or "pid" if no "ppid") + -P add "prmid" (for -l) or "prmgrp" (for -f or -fl) after "pid" + -H Shows the process hierarchy. Each process is displayed + under its parent, and the contents of the args or comm + column for that process is indented from that of its + parent. Note that this option is expensive in both + memory and speed. + + The column names and their meanings are given below. Except where + noted, the default heading for each column is the uppercase form of + the column name. + + addr The memory address of the process, if resident; + otherwise, the disk address. + + args The command line given when the process was + created. This column should be the last one + specified, if it is desired. Only a subset of the + command line is saved by the kernel; as much of + the command line will be displayed as is + available. The output in this column may contain + spaces. The default heading for this column is + COMMAND if -o is specified and CMD otherwise. + + cls Process scheduling class, see rtsched(1). + + comm The command name. The output in this column may + contain spaces. The default heading for this + column is COMMAND if -o is specified and CMD + otherwise. + + cpu Processor utilization for scheduling. The default + heading for this column is C. + + etime Elapsed time of the process. The default heading + for this column is ELAPSED. + + flags Flags (octal and additive) associated with the + process: + + 0 Swapped + 1 In core + 2 System process + 4 Locked in core (e.g., for physical I/O) + 10 Being traced by another process + 20 Another tracing flag + + The default heading for this column is F. + + intpri The priority of the process as it is stored + internally by the kernel. This column is provided + for backward compatibility and its use is not + encouraged. + + gid The group ID number of the effective process + owner. + + group The group name of the effective process owner. + + nice Nice value; used in priority computation (see + nice(1)). The default heading for this column is + NI. + + pcpu The percentage of CPU time used by this process + during the last scheduling interval. The default + heading for this column is %CPU. + + pgid The process group ID number of the process group + to which this process belongs. + + pid The process ID number of the process. + + ppid The process ID number of the parent process. + + pri The priority of the process. The meaning of the + value depends on the process scheduling class; see + cls, above, and rtsched(1). + + prmid The PRM process resource group ID number. + + prmgrp The PRM process resource group name. + + rgid The group ID number of the real process owner. + + rgroup The group name of the real process owner. + + ruid The user ID number of the real process owner. + + ruser The login name of the real process owner. + + sid The session ID number of the session to which this + process belongs. + + state The state of the process: + + 0 Nonexistent + S Sleeping + W Waiting + R Running + I Intermediate + Z Terminated + T Stopped + X Growing + + The default heading for this column is S. + + stime Starting time of the process. If the elapsed time + is greater than 24 hours, the starting date is + displayed instead. + + sz The size in physical pages of the core image of + the process, including text, data, and stack + space. Physical page size is defined by + _SC_PAGE_SIZE in the header file (see + sysconf(2) and unistd(5)). + + time The cumulative execution time for the process. + + tty The controlling terminal for the process. The + default heading for this column is TT if -o is + specified and TTY otherwise. + + uid The user ID number of the effective process owner. + + user The login name of the effective process owner. + + vsz The size in kilobytes (1024 byte units) of the + core image of the process. See column sz, above. + + wchan The event for which the process is waiting or + sleeping; if there is none, a hyphen (-) is + displayed. +*/ + +/* SUS (plus solaris options on first column) + +NAME + + ps - report process status + +SYNOPSIS + + ps [-aA] [-defl] [-G grouplist] [-o format] ... [-p proclist] + [-t termlist] [-U userlist] [-g grouplist] [-n namelist] + [-u userlist] + +DESCRIPTION + + The ps utility writes information about processes. You must have appropriate + privileges to get information about the specified processes. + + By default, ps selects all processes that have the same effective user ID as the + current user, and the same controlling terminal as the terminal from which the + command is invoked. + + On some systems, especially multi-level secure systems, ps may be severely + restricted and may produce information only about child processes owned by the + user. For additional information concerning functionality of the ps utility + under these conditions, contact your System Administrator. + + Things can change while ps is running; the snapshot it gives is only true for an + instant, and may not be accurate by the time it is displayed. + +OPTIONS + + This utility supports the utility syntax guidelines described in the + xbdutsyntax(5) reference page. + + With the exception of the -f, -l, and -o options, all of the options shown for + ps are used to select processes. If any of these options are specified, the + default list of processes is ignored, and ps selects the processes that satisfy + any of the selection-criteria options. + + Systems that conform to the Single UNIX Specification support the following + options: + +* -A + Writes information about all processes. +* -a + Writes information about all processes associated with terminals. Some + systems that conform to the Single UNIX Specification, Version 2 may omit + session leaders from this list. +-c Print information in a format that reflects scheduler properties as described + in priocntl(1). The -c option affects the output of the -f and -l options, as + described below. +* -d + Writes information about all processes (except session leaders). +* -e + Writes information about all processes (equivalent to -A). +* -f + Generates a full listing. + + Under the -f option, ps tries to determine the command name and arguments + given when the process was created, by examining memory or the swap area. + Failing this, ps writes the command name, as it would appear without the + -f option, in square brackets ( []). + +* -G grouplist + Writes information about processes for which the real group ID numbers are + given in grouplist. The grouplist must be a single argument in the form of + a blank- or comma-separated list. +* -g grouplist + Writes information about processes for which the session leaders are given + in grouplist. The grouplist must be a single argument in the form of a + blank- or comma-separated list. +-j Print session ID and process group ID. +* -l + (the letter "ell") Generates a long listing. +-L Print information about each light weight process (lwp) in each selected process. + (See below.) +* -n namelist + Specifies the name of an alternative system namelist file, in place of the + default. The default name and the format of a namelist file may vary among + systems that conform to the Single UNIX Specification, Version 2. +* -o format + Writes information according to the format specification given in format. + Multiple -o options can be specified; the format specification is + interpreted as the space-character-separated concatenation of all the + format option-arguments. For additional information, see Format + Specifications subsection of ps(1). +* -p proclist + Writes information about processes for which the process ID numbers are + given in proclist. The proclist must be a single argument in the form of a + blank- or comma-separated list. +-P Print the number of the processor to which the process or lwp is bound, if any, + under an additional column header, PSR. +-s sidlist + List information on all session leaders whose IDs appear in sidlist. +* -t termlist + Writes information about processes associated with the list of terminal + identifiers given in termlist. The termlist must be a single argument in + the form of a blank- or comma-separated list. Terminal identifiers must be + given in one of two forms: + Device's file name (for example, tty04). + If the device's file name starts with tty, just the identifier + following those characters (for example, 04 if the device name is + tty04). +* -U userlist + Writes information about processes for which the real user ID numbers or + login names are given in userlist. The userlist must be a single argument + in the form of a blank- or comma-separated list. +* -u userlist + Writes information about processes for which the user ID numbers or login + names are given in userlist. The userlist must be a single argument in the + form of a blank- or comma-separated list. In the listing, the numerical + user ID is written unless the -f option is used, in which case the login + name is written. +-y Under a long listing (-l), omit the obsolete F and ADDR columns and include an + RSS column to report the resident set size of the process. Under the -y option, + both RSS and SZ (see below) will be reported in units of kilobytes instead of + pages. + + +EXTENDED DESCRIPTION + + If a signal is received during execution of this utility, the action of the + utility follows the guidelines described in the xcuutildef(5) reference page. + + If an error condition occurs, the effects of using this utility may vary among + systems that conform to the Single UNIX Specification. For more information, see + the xcuutildef(5) reference page. + + The following sections contain additional information for the ps utility: + + Default Output Format subsection of ps(1) + Format Specifications subsection of ps(1) + + Default Output Format + + When the -o option is not specified, the standard output format is as follows. + The column headings and descriptions of the columns in a ps listing are shown in + the following table. The precise meanings of these fields may vary among systems + that conform to the Single UNIX Specification, Version 2. + + The words "full" or "long" in the "Type of Listing" column indicate the option + (-f or -l, respectively) that causes the corresponding heading to appear; "all" + means that the heading always appears. These two options determine only what + information is displayed for a process; they do not determine which processes + are listed. + + Column Head + Type of Listing + Description + F + Long + Flags (octal and additive) associated with the process. + S + Long + The state of the process. +O Process is running on a processor. +S Sleeping: process is waiting for an event to complete. +R Runnable: process is on run queue. +Z Zombie state: process terminated and parent not waiting. +T Process is stopped, either by a job control signal or because it is being traced. + UID + Full, long + The user ID number of the process owner. The login name is printed under the + -f option. + PID + All + The process ID of the process. It is possible to kill a process if this ID is known +. + PPID + Full, long + The process ID of the parent process. + C + Full, long + Processor utilization for scheduling. + PRI + Long + The priority of the process; higher numbers mean lower priority. + NI + Long + Nice value; used in priority computation. + ADDR + Long + The address of the process. + SZ + Long + The size in blocks of the core image of the process. + WCHAN + Long + The event for which the process is waiting or sleeping; if blank, the process is + running. + STIME + Full + Starting time of the process. + TTY + All + The controlling terminal for the process. + TIME + All + The cumulative execution time for the process. + CMD + All + The command name. The full command name and its arguments are written + under the -f option. +The following two additional columns are printed when the -j option is specified: +PGID The process ID of the process group leader. +SID The process ID of the session leader. + +The following two additional columns are printed when the -L option is specified: +LWP The lwp ID of the lwp being reported. +NLWP The number of lwps in the process (if -f is also specified). + + A process is marked defunct if it has exited and has a parent, but has not yet + been waited for by the parent (to release any remaining system resources, + including its process ID). + + Format Specifications + + The format specification supplied with the -o option must be a list of names + presented as a single argument, blank-separated (if the argument is quoted) or + comma-separated. For each name, ps produces a default header. The default header + can be overridden by appending an = (equal sign) and the new text of the header. + The rest of the characters in the argument are used as the header text. + + The fields specified are written in the order specified on the command line, and + are arranged in columns in the output. The field widths are selected by the + system to be at least as wide as the header text (either the default header or a + new header supplied with the format). + + If the header text is null (for example, -o user=), the field width is at least as + wide as the default header text. If all header text fields are null, no header + line is written. + + If the field width is too narrow to display a textual ID (such as a user ID or + group ID), the system may use a numeric version. Normally, the system ensures + that field widths are large enough for proper display of the fields; but if a + large number of fields is selected, fields might be displayed using the minimum + widths, to fit the information for each process on one line. One way to ensure + adequate width for textual IDs is to override the default header for a field, + making it larger than most or all user or group names. + + The following names are recognized in the POSIX locale: + + ruser + Real user ID of the process. The displayed ID is the textual user ID, if + it can be obtained and the field width permits; otherwise, the ID is a + decimal representation. + user + Effective user ID of the process. The displayed ID is the textual user ID, + if it can be obtained and the field width permits; otherwise, the ID is a + decimal representation. + rgroup + Real group ID of the process. The displayed ID is the textual group ID, if + it can be obtained and the field width permits; otherwise, the ID is a + decimal representation. + group + Effective group ID of the process. The displayed ID is the textual group + ID, if it can be obtained and the field width permits; otherwise, the ID + is a decimal representation. + pid + Decimal value of the process ID. + ppid + Decimal value of the parent process ID. + pgid + Decimal value of the process group ID. + pcpu + Ratio of the CPU time used recently to the CPU time available in the same + period, expressed as a percentage. The meaning of "recently" in this + context may vary among systems that conform to the Single UNIX + Specification, Version 2. The manner in which the available CPU time is + determined may also vary. + vsz + Size of the process in virtual memory (in kilobytes, expressed as a + decimal integer). + nice + Decimal value of the system scheduling priority of the process. For more + information about system scheduling priorities, see the nice(1) reference + page. + etime + In the POSIX locale, the elapsed time since the process was started, in + the following format, where dd represents the number of days, hh the + number of hours, mm the number of minutes, and ss the number of seconds: + + + [[dd-]hh:]mm:ss + + The dd field is a decimal integer. The hh, mm, and ss fields are two-digit + decimal integers, padded on the left with zeros. + + time + In the POSIX locale, the cumulative CPU time of the process in the + following format: + + + [dd-]hh:mm:ss + + The dd field is a decimal integer. The hh, mm, and ss fields are two-digit + decimal integers, padded on the left with zeros. + + tty + Name of the controlling terminal of the process (if any), in the same + format used by the who utility. + comm + Name of the command being executed (argv[0] value), expressed as a string. + args + Command with all its arguments, expressed as a string. + + The local system may truncate this value to the field width to fit the ps + display. On some systems that conform to the Single UNIX Specification, + Version 2, further truncation may occur. On some systems, a string + displayed by ps may be represented as a version of the argument list that + was passed to the command when it started; on other systems, the displayed + string may be a version of the arguments as modified by the application. + An application should not expect the output of ps to show modifications + the application made to an argument list. + +The following names are recognized in the Solaris implementation: +f Flags (hexadecimal and additive) associated with the process. +s The state of the process. +c Processor utilization for scheduling (obsolete). +uid The effective user ID number of the process as a decimal integer. +ruid The real user ID number of the process as a decimal integer. +gid The effective group ID number of the process as a decimal integer. +rgid The real group ID number of the process as a decimal integer. +sid The process ID of the session leader. +class The scheduling class of the process. +pri The priority of the process. Higher numbers mean higher priority. +opri The obsolete priority of the process. Lower numbers mean higher priority. +lwp The decimal value of the lwp ID. Requesting this formatting option causes + one line to be printed for eachlwp in the process. +nlwp The number of lwps in the process. +psr The number of the processor to which the process or lwp is bound. +addr The memory address of the process. +osz The total size of the process in virtual memory, in pages. +wchan The address of an event for which the process is sleeping (if -, the process + is running). +stime The starting time or date of the process, printed with no blanks. +rss The resident set size of the process, in kilobytes. +pmem The ratio of the process's resident set size to the physical memory on the + machine, expressed as a percentage. +fname The first 8 bytes of the base name of the process's executable file. + + Some fields may not be meaningful on all systems that conform to the Single UNIX + Specification, Version 2. In such a case, ps displays a hyphen ( -) in place of + the field value. + + Of the standard fields, only the comm and args fields can contain blank + characters; all other fields cannot. + + The following table specifies the default header to be used in the POSIX locale + corresponding to each format specifier. + + Format Specifier Default Header + args COMMAND + ppid PPID + comm COMMAND + rgroup RGROUP + etime ELAPSED + ruser RUSER + group GROUP + time TIME + nice NI + tty TT + pcpu %CPU + user USER + pgid PGID + vsz VSZ + pid PID + + +EXIT STATUS + + This utility returns the following exit values: + + 0 + Successful completion. + >0 + An error occurred. + +EXAMPLES + + Example 1: Listing the Currently Running Processes + + The following command displays a full listing of every process running at the + time the command is issued: + + ps -e -f + + Example 2: Listing the Running Processes of a Particular User + + The following command displays a full listing of every process running at the + time the command is issued. It only displays processes owned by james ( james need + not be the same as the requesting user). + + ps -f -u james + + Example 3: Specifying Multiple Headers + + There is no special quoting mechanism for header text; the header text is + treated as the rest of the argument to the -o option. If multiple header changes + are needed, multiple -o options can be used, as in the following command: + + ps -o "user=User Name" -o pid=Process\ ID + + As shown in this example, a space can be imbedded in the header text either by + quoting the entire argument to the -o option (as in -o "user=User Name") or by + escaping the space character (as in -o pid=Process\ ID). + +ENVIRONMENT VARIABLES + + The environ(5) reference page provides general information about the following + standard environment variables, which can affect the operation of this utility: + COLUMNS, LANG, LC_ALL, LC_CTYPE, LC_MESSAGES, LC_TIME, and NLSPATH. + +SEE ALSO + + kill(1), nice(1), renice(1), who(1), environ(5), xbdutsyntax(5), xcuutildef(5) + + + The Single UNIX. Documentation, version 2. Copyright ) 1998 The Open Group. + +*/ + kvm_t *kd; int @@ -156,7 +738,7 @@ main(argc, argv) struct varent *vent; struct winsize ws; int ch, flag, i, fmt, lineno, nentries; - int prtheader, wflag, what, xflg, mode; + int prtheader, widthflag, what, noctty, nosl, mode; char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX]; char *ttname; @@ -167,164 +749,322 @@ main(argc, argv) termwidth = 79; else termwidth = ws.ws_col - 1; + + /* Allow for multiple -B/-X options at the beginning. */ + while (argc > 1 && + (strcmp(argv[1], "-B") == 0 || strcmp(argv[1], "-X") == 0)) { + if (strcmp(argv[1], "-B") == 0) + sysv = 0; + else + sysv = 1; + argc--; + argv++; + } - if (argc > 1) + if (!sysv && argc > 1) argv[1] = kludge_oldps_options(argv[1]); - fmt = prtheader = wflag = xflg = 0; + fmt = prtheader = widthflag = noctty = nosl = 0; what = KERN_PROC_UID; flag = myuid = getuid(); memf = nlistf = swapf = NULL; mode = PRINTMODE; - while ((ch = getopt(argc, argv, GETOPTSTR)) != -1) - switch((char)ch) { - case 'a': - what = KERN_PROC_ALL; - flag = 0; - break; - case 'c': - commandonly = 1; - break; - case 'e': /* XXX set ufmt */ - needenv = 1; - break; - case 'C': - rawcpu = 1; - break; - case 'g': - break; /* no-op */ - case 'h': - prtheader = ws.ws_row > 5 ? ws.ws_row : 22; - break; - case 'j': - parsefmt(jfmt); - fmt = 1; - jfmt[0] = '\0'; - break; - case 'K': - dontuseprocfs=1; - break; - case 'L': - showkey(); - exit(0); - /* NOTREACHED */ - case 'l': - parsefmt(lfmt); - fmt = 1; - lfmt[0] = '\0'; - break; - case 'M': - memf = optarg; - dontuseprocfs = 1; - break; - case 'm': - sortby = SORTMEM; - break; - case 'N': - nlistf = optarg; - break; - case 'O': - parsefmt(o1); - parsefmt(optarg); - parsefmt(o2); - o1[0] = o2[0] = '\0'; - fmt = 1; - break; - case 'o': - parsefmt(optarg); - fmt = 1; - break; - case 'p': - what = KERN_PROC_PID; - flag = atol(optarg); - xflg = 1; - break; - case 'r': - sortby = SORTCPU; - break; - case 'S': - sumrusage = 1; - break; - case 'T': - if ((ttname = ttyname(STDIN_FILENO)) == NULL) - errx(1, "stdin: not a terminal"); - goto tty; - case 't': - ttname = optarg; - tty: { - struct stat sb; - char *ttypath, pathbuf[MAXPATHLEN]; - - flag = 0; - if (strcmp(ttname, "?") == 0) - flag = KERN_PROC_TTY_NODEV; - else if (strcmp(ttname, "-") == 0) - flag = KERN_PROC_TTY_REVOKE; - else if (strcmp(ttname, "co") == 0) - ttypath = _PATH_CONSOLE; - else if (*ttname != '/') - (void)snprintf(ttypath = pathbuf, - sizeof(pathbuf), "%s%s", _PATH_TTY, ttname); - else - ttypath = ttname; - what = KERN_PROC_TTY; - if (flag == 0) { - if (stat(ttypath, &sb) == -1) - err(1, "%s", ttypath); - if (!S_ISCHR(sb.st_mode)) - errx(1, "%s: not a terminal", ttypath); - flag = sb.st_rdev; + if (sysv) { + int fflag, jflag, lflag, yflag; + + fflag = jflag = lflag = yflag = 0; + while ((ch = getopt(argc, argv, SYSVGETOPTSTR)) != -1) + switch((char)ch) { + case 'a': + what = KERN_PROC_ALL; + flag = 0; + break; + case 'A': + case 'e': + what = KERN_PROC_ALL; + flag = 0; + noctty = 1; + break; +#if 0 + case 'C': /* HPUX XPG4 */ + /* parse process name list */ + break; +#endif + case 'd': + what = KERN_PROC_ALL; + flag = 0; + nosl = noctty = 1; + break; + /* case 'e': - above with 'A' */ + case 'f': + fflag++; + break; + case 'g': + case 'p': + case 's': + /* XXX: parse list, not single id */ + switch (ch) { + case 'g': +#if 0 + what = KERN_PROC_PGID; + break; +#else + errx(1, "-g not supported yet"); +#endif + case 'p': + what = KERN_PROC_PID; + break; + case 's': +#if 0 + what = KERN_PROC_SID; + break; +#else + errx(1, "-s not supported yet"); +#endif + } + flag = atol(optarg); + noctty = 1; + break; + case 'G': + case 'u': /* effective uid/username */ + case 'U': /* real uid/username */ + /* XXX: parse list, not single username */ + if (*optarg != '\0') { + struct passwd *pw; + char *ep; + + switch (ch) { + case 'G': +#if 0 + what = KERN_PROC_RGID; + break; +#else + errx(1, "-G not supported yet"); +#endif + case 'u': + what = KERN_PROC_UID; + break; + case 'U': + what = KERN_PROC_RUID; + break; + } + pw = getpwnam(optarg); + if (pw == NULL) { + errno = 0; + flag = strtoul(optarg, &ep, 10); + if (errno) + err(1, "%s", optarg); + if (*ep != '\0') + errx(1, "%s: illegal user name", + optarg); + } else + flag = pw->pw_uid; + } + break; + case 'j': + jflag++; + break; + case 'l': + lflag++; + break; + case 'n': + nlistf = optarg; + break; + case 'o': + parsefmt(optarg); + fmt = 1; + break; + /* case 'p': - above with 'g' */ + /* case 's': - above with 'g' */ + case 't': + /* XXX: parse tty list */ + break; + /* case 'u': - above with 'G' */ + /* case 'U': - above with 'G' */ + case 'y': + yflag++; + break; + default: + usage(); } - break; - } - case 'U': - if (*optarg != '\0') { - struct passwd *pw; - char *ep; - - what = KERN_PROC_UID; - pw = getpwnam(optarg); - if (pw == NULL) { - errno = 0; - flag = strtoul(optarg, &ep, 10); - if (errno) - err(1, "%s", optarg); - if (*ep != '\0') - errx(1, "%s: illegal user name", - optarg); - } else - flag = pw->pw_uid; + if (fmt == 0) { + if (fflag && lflag) { + parsefmt(yflag ? + (jflag ? sysv_fljyfmt : sysv_flyfmt) : + (jflag ? sysv_fljfmt : sysv_flfmt)); + } else if (fflag) { + parsefmt(jflag ? sysv_fjfmt : sysv_ffmt); + } else if (lflag) { + parsefmt(yflag ? + (jflag ? sysv_ljyfmt : sysv_lyfmt) : + (jflag ? sysv_ljfmt : sysv_lfmt)); + } else { + parsefmt(jflag ? sysv_jfmt : sysv_fmt); } - break; - case 'u': - parsefmt(ufmt); - sortby = SORTCPU; - fmt = 1; - ufmt[0] = '\0'; - break; - case 'v': - parsefmt(vfmt); - sortby = SORTMEM; - fmt = 1; - vfmt[0] = '\0'; - break; - case 'W': - swapf = optarg; - break; - case 'w': - if (wflag) - termwidth = UNLIMITED; - else if (termwidth < 131) - termwidth = 131; - wflag++; - break; - case 'x': - xflg = 1; - break; - case '?': - default: - usage(); } + if (!fflag) + commandonly = 1; + } else { + while ((ch = getopt(argc, argv, GETOPTSTR)) != -1) + switch((char)ch) { + case 'a': + what = KERN_PROC_ALL; + flag = 0; + break; + case 'c': + commandonly = 1; + break; + case 'C': + rawcpu = 1; + break; + case 'e': /* XXX set ufmt */ + needenv = 1; + break; + case 'f': /* sysv -ef compatibility */ + what = KERN_PROC_ALL; + flag = 0; + noctty = 1; + needenv = 0; /* XXX! */ + parsefmt(sysv_ffmt); + fmt = 1; + sysv_ffmt[0] = '\0'; + break; + case 'g': + break; /* no-op */ + case 'h': + prtheader = ws.ws_row > 5 ? ws.ws_row : 22; + break; + case 'j': + parsefmt(jfmt); + fmt = 1; + jfmt[0] = '\0'; + break; + case 'K': + dontuseprocfs=1; + break; + case 'l': + parsefmt(lfmt); + fmt = 1; + lfmt[0] = '\0'; + break; + case 'L': + showkey(); + exit(0); + /* NOTREACHED */ + case 'm': + sortby = SORTMEM; + break; + case 'M': + memf = optarg; + dontuseprocfs = 1; + break; + case 'N': + nlistf = optarg; + break; + case 'o': + parsefmt(optarg); + fmt = 1; + break; + case 'O': + parsefmt(o1); + parsefmt(optarg); + parsefmt(o2); + o1[0] = o2[0] = '\0'; + fmt = 1; + break; + case 'p': + what = KERN_PROC_PID; + flag = atol(optarg); + noctty = 1; + break; + case 'r': + sortby = SORTCPU; + break; + case 'S': + sumrusage = 1; + break; + case 't': + ttname = optarg; + tty: { + struct stat sb; + char *ttypath, pathbuf[MAXPATHLEN]; + + flag = 0; + if (strcmp(ttname, "?") == 0) + flag = KERN_PROC_TTY_NODEV; + else if (strcmp(ttname, "-") == 0) + flag = KERN_PROC_TTY_REVOKE; + else if (strcmp(ttname, "co") == 0) + ttypath = _PATH_CONSOLE; + else if (*ttname != '/') + (void)snprintf(ttypath = pathbuf, + sizeof(pathbuf), "%s%s", _PATH_TTY, ttname); + else + ttypath = ttname; + what = KERN_PROC_TTY; + if (flag == 0) { + if (stat(ttypath, &sb) == -1) + err(1, "%s", ttypath); + if (!S_ISCHR(sb.st_mode)) + errx(1, "%s: not a terminal", ttypath); + flag = sb.st_rdev; + } + break; + } + case 'T': + if ((ttname = ttyname(STDIN_FILENO)) == NULL) + errx(1, "stdin: not a terminal"); + goto tty; + case 'u': + parsefmt(ufmt); + sortby = SORTCPU; + fmt = 1; + ufmt[0] = '\0'; + break; + case 'U': + if (*optarg != '\0') { + struct passwd *pw; + char *ep; + + what = KERN_PROC_UID; + pw = getpwnam(optarg); + if (pw == NULL) { + errno = 0; + flag = strtoul(optarg, &ep, 10); + if (errno) + err(1, "%s", optarg); + if (*ep != '\0') + errx(1, "%s: illegal user name", + optarg); + } else + flag = pw->pw_uid; + } + break; + case 'v': + parsefmt(vfmt); + sortby = SORTMEM; + fmt = 1; + vfmt[0] = '\0'; + break; + case 'w': + if (widthflag) + termwidth = UNLIMITED; + else if (termwidth < 131) + termwidth = 131; + widthflag++; + break; + case 'W': + swapf = optarg; + break; + case 'x': + noctty = 1; + break; + default: + usage(); + } + if (!fmt) + parsefmt(dfmt); + } argc -= optind; argv += optind; @@ -355,14 +1095,6 @@ main(argc, argv) } } - if (!fmt) - parsefmt(dfmt); - - /* - * scan requested variables, noting what structures are needed. - */ - scanvars(); - /* * select procs */ @@ -406,7 +1138,7 @@ main(argc, argv) for (i = 0; i < nentries; i++) { struct kinfo_proc2 *ki = &kinfo[i]; - if (xflg == 0 && (ki->p_tdev == NODEV || + if (noctty == 0 && (ki->p_tdev == NODEV || (ki->p_flag & P_CONTROLT) == 0)) continue; for (vent = vhead; vent; vent = vent->next) @@ -425,9 +1157,11 @@ main(argc, argv) for (i = lineno = 0; i < nentries; i++) { struct kinfo_proc2 *ki = &kinfo[i]; - if (xflg == 0 && (ki->p_tdev == NODEV || + if (noctty == 0 && (ki->p_tdev == NODEV || (ki->p_flag & P_CONTROLT ) == 0)) continue; + if (nosl && (ki->p_pid == ki->p_sid)) + continue; for (vent = vhead; vent; vent = vent->next) { (vent->var->oproc)(ki, vent, mode); if (vent->next != NULL) @@ -451,19 +1185,6 @@ getkinfo_kvm(kd, what, flag, nentriesp) { return (kvm_getproc2(kd, what, flag, sizeof(struct kinfo_proc2), nentriesp)); -} - -static void -scanvars() -{ - struct varent *vent; - VAR *v; - - for (vent = vhead; vent; vent = vent->next) { - v = vent->var; - if (v->flag & COMM) - needcomm = 1; - } } static int Index: ps.h =================================================================== RCS file: /cvsroot/basesrc/bin/ps/ps.h,v retrieving revision 1.17 diff -p -u -r1.17 ps.h --- ps.h 2000/06/07 04:58:02 1.17 +++ ps.h 2000/06/11 17:47:08 @@ -55,7 +55,7 @@ typedef struct var { char *name; /* name(s) of variable */ char *header; /* default header */ char *alias; /* aliases */ -#define COMM 0x01 /* needs exec arguments and environment (XXX) */ +#define COMM 0x01 /* command only, not args */ #define LJUST 0x02 /* left adjust on output (trailing blanks) */ #define INF127 0x04 /* 127 = infinity: if > 127, print 127. */ u_int flag;