2218 lines
50 KiB
C
2218 lines
50 KiB
C
/* :set ts=4 */
|
|
|
|
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
|
|
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
|
|
/* UNIX System Laboratories, Inc. */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "$Revision: 1.88 $"
|
|
|
|
/***************************************************************************
|
|
* Command: ps
|
|
*
|
|
* Displays all sorts of useful information about a process.
|
|
*
|
|
* SGI changes:
|
|
* 1) Removed all the security junk.
|
|
* 2) Removed DIRSIZ and replaced it with MAXNAMLEN
|
|
* 3) Put in the notinteresting() routine to cut search time
|
|
* 4) Removed remote file system support (MAYBE)
|
|
* 5) Ignore syscon and systty entirely, they are always links
|
|
* to some other device
|
|
* 6) Redid all output with format strings
|
|
*
|
|
***************************************************************************/
|
|
|
|
/* Overall scheme:
|
|
main() Process the args setting appropriate flags and saving
|
|
away pids etc for later matching.
|
|
Build the line out format fEntry[].
|
|
Loop over entries in /proc using PIOCPSINFO.
|
|
Select the interesting procs and pass them to prcom().
|
|
FillFormat() Builds a string of field names based on the flags.
|
|
FormatSpecifier()
|
|
Takes either the FillFormat() string or the -o string
|
|
and creates the fEntry data.
|
|
prcom() Prints out info{} formatted according to fEntry[].
|
|
info{} Saves the current process entry's state.
|
|
fEntry[] Describes the line format as formatted fields.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <ustat.h>
|
|
#include <ftw.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <wchar.h>
|
|
#include <dirent.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/fault.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/syssgi.h>
|
|
#include <sys/time.h>
|
|
#include <sys/procfs.h>
|
|
#include <paths.h>
|
|
#include <locale.h>
|
|
#include <fmtmsg.h>
|
|
#include <stdarg.h>
|
|
#include <sgi_nl.h>
|
|
#include <msgs/uxsgicore.h>
|
|
#include <sys/mac.h>
|
|
#include <sys/capability.h>
|
|
#include <grp.h>
|
|
#include <getopt.h>
|
|
|
|
#ifdef UNS
|
|
extern int _getpwent_no_shadow;
|
|
#endif
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#define NTTYS 20 /* max ttys that can be specified with the -t option */
|
|
#define SIZ 30 /* max processes that can be specified with -p and -g */
|
|
#define ARGSIZ 256 /* size of buffer which holds args for -t, -p & -u */
|
|
|
|
#ifndef MAXLOGIN
|
|
#define MAXLOGIN 14 /* max number of char in userid */
|
|
#endif
|
|
|
|
|
|
/* format specifiers */
|
|
#define PS_RUSER 0 /* real user ID */
|
|
#define PS_USER 1 /* effective user ID */
|
|
#define PS_RGROUP 2 /* real group ID */
|
|
#define PS_GROUP 3 /* effective group ID */
|
|
#define PS_PID 4 /* pid */
|
|
#define PS_PPID 5 /* parent pid */
|
|
#define PS_PGID 6 /* process group id */
|
|
#define PS_PCPU 7 /* ratio of CPU time */
|
|
#define PS_VSZ 8 /* size of process */
|
|
#define PS_NICE 9 /* priority */
|
|
#define PS_ETIME 10 /* elapsed time */
|
|
#define PS_TIME 11 /* CPU time */
|
|
#define PS_TTY 12 /* controlling terminal */
|
|
#define PS_COMM 13 /* command */
|
|
#define PS_ARGS 14 /* command arguments */
|
|
#define PS_STIME 15 /* start time */
|
|
#define PS_FLAG 16 /* flags associated with the process */
|
|
#define PS_STATE 17 /* state of the process */
|
|
#define PS_WCHAN 18 /* wchan address process is waiting on */
|
|
#define PS_WNAME 19 /* wchan name process is waiting on */
|
|
#define PS_UTIL 20 /* processor utilisation */
|
|
#define PS_UID 21 /* user id */
|
|
#define PS_OPRI 22 /* old priority */
|
|
#define PS_PROC 23 /* processor */
|
|
#define PS_SZ 24 /* size in blocks */
|
|
#define PS_RSS 25 /* resident size */
|
|
#define PS_OTIME 26 /* old time display */
|
|
#define PS_PRI 27 /* priority */
|
|
#define PS_CLASS 28 /* class */
|
|
#define PS_SID 29 /* sid */
|
|
#define PS_BLANK 30 /* place a space */
|
|
#define PS_ADDR 31 /* address of the process */
|
|
#define PS_LABEL 32 /* label of the process */
|
|
#define PS_CELL 33 /* cell id of the process */
|
|
#define FORMAT_ENTRIES 34
|
|
|
|
struct format {
|
|
short len; /* format length */
|
|
char spec; /* format specifier */
|
|
char d; /* delimitor */
|
|
};
|
|
|
|
int fcount = 0;
|
|
|
|
#define FORMAT_MAX 50 /* maximum format entries */
|
|
struct format fEntry[FORMAT_MAX];
|
|
|
|
|
|
#define LEFT_ADJUST 0
|
|
#define RIGHT_ADJUST 1
|
|
|
|
struct formatname_s {
|
|
char *name; /* format name */
|
|
int namelen;
|
|
int adjust; /* left or right justified */
|
|
char spec;
|
|
char *def; /* default format name */
|
|
int minlen;
|
|
} fname[FORMAT_ENTRIES] = {
|
|
{ "ruser", 5, RIGHT_ADJUST, PS_RUSER, "RUSER", 8 },
|
|
{ "user", 4, RIGHT_ADJUST, PS_USER, "USER", 8 },
|
|
{ "rgroup", 6, RIGHT_ADJUST, PS_RGROUP, "RGROUP", 8 },
|
|
{ "group", 5, RIGHT_ADJUST, PS_GROUP, "GROUP", 8 },
|
|
{ "pid", 3, RIGHT_ADJUST, PS_PID, "PID", 10 },
|
|
{ "ppid", 4, RIGHT_ADJUST, PS_PPID, "PPID", 10 },
|
|
{ "pgid", 4, RIGHT_ADJUST, PS_PGID, "PGID", 10 },
|
|
{ "pcpu", 4, RIGHT_ADJUST, PS_PCPU, "%CPU", 4 },
|
|
{ "vsz", 3, LEFT_ADJUST, PS_VSZ, "VSZ", 6 },
|
|
{ "nice", 4, RIGHT_ADJUST, PS_NICE, "NI", 2 },
|
|
{ "etime", 5, RIGHT_ADJUST, PS_ETIME, "ELAPSED", 11 },
|
|
{ "time", 4, RIGHT_ADJUST, PS_TIME, "TIME", 11 },
|
|
{ "tty", 3, LEFT_ADJUST, PS_TTY, "TTY", 6 },
|
|
{ "comm", 4, LEFT_ADJUST, PS_COMM, "COMMAND", 9 },
|
|
{ "args", 4, LEFT_ADJUST, PS_ARGS, "COMMAND", 35 },
|
|
{ "stime", 5, RIGHT_ADJUST, PS_STIME, "STIME", 8 },
|
|
{ "flag", 4, RIGHT_ADJUST, PS_FLAG, "F", 3 },
|
|
{ "state", 5, LEFT_ADJUST, PS_STATE, "S", 1 },
|
|
{ "wchan", 5, RIGHT_ADJUST, PS_WCHAN, "WCHAN", 8 },
|
|
{ "wname", 5, RIGHT_ADJUST, PS_WNAME, "WCHAN", 8 },
|
|
{ "util", 4, RIGHT_ADJUST, PS_UTIL, "C", 2 },
|
|
{ "cell", 4, RIGHT_ADJUST, PS_CELL, "CELL", 4 },
|
|
{ "uid", 3, RIGHT_ADJUST, PS_UID, "UID", 5 },
|
|
{ "opri", 4, RIGHT_ADJUST, PS_OPRI, "PRI", 3 },
|
|
{ "cpu", 3, RIGHT_ADJUST, PS_PROC, "P", 2 },
|
|
{ "sz", 2, RIGHT_ADJUST, PS_SZ, "SZ", 5 },
|
|
{ "rss", 3, LEFT_ADJUST, PS_RSS, "RSS", 5 },
|
|
{ "otime", 5, RIGHT_ADJUST, PS_OTIME, "TIME", 5 },
|
|
{ "pri", 3, RIGHT_ADJUST, PS_PRI, "PRI", 3 },
|
|
{ "class", 5, RIGHT_ADJUST, PS_CLASS, "CLS", 4 },
|
|
{ "sid", 3, RIGHT_ADJUST, PS_SID, "SID", 10 },
|
|
{ "blank", 5, RIGHT_ADJUST, PS_BLANK, "", 0 },
|
|
{ "addr", 4, RIGHT_ADJUST, PS_ADDR, "ADDR", 8 },
|
|
{ "label", 5, LEFT_ADJUST, PS_LABEL, "LABEL", 22},
|
|
};
|
|
|
|
|
|
/* Structure for storing user info */
|
|
struct udata {
|
|
uid_t uid; /* numeric user id */
|
|
char name[MAXLOGIN]; /* login name, may not be null terminated */
|
|
};
|
|
|
|
/* udata and devl granularity for structure allocation */
|
|
#define UDQ 50
|
|
|
|
/* Pointer to user data */
|
|
struct udata *ud;
|
|
int nud = 0; /* number of valid ud structures */
|
|
int maxud = 0; /* number of ud's allocated */
|
|
|
|
struct udata uid_tbl[SIZ]; /* table to store selected uid's */
|
|
int nut = 0; /* counter for uid_tbl */
|
|
struct udata Uid_tbl[SIZ]; /* table to store selected uid's */
|
|
int nUt = 0; /* counter for uid_tbl */
|
|
|
|
char label[512];
|
|
|
|
struct prpsinfo info; /* process information structure from /proc */
|
|
struct prcred cred; /* process credentials structure from /proc */
|
|
int trix_mac; /* true if kernel has MAC configured */
|
|
|
|
int retcode = 1; /* exit value - any success clears this flag */
|
|
|
|
int lflg = 0;
|
|
int eflg = 0;
|
|
int uflg = 0;
|
|
int Uflg = 0;
|
|
int aflg = 0;
|
|
int dflg = 0;
|
|
int pflg = 0;
|
|
int fflg = 0;
|
|
int cflg = 0;
|
|
int jflg = 0;
|
|
int gflg = 0;
|
|
int Gflg = 0;
|
|
int sflg = 0;
|
|
int tflg = 0;
|
|
int Mflg = 0;
|
|
int oflg = 0;
|
|
int xflg = 0;
|
|
int Xflg = 0;
|
|
int Tflg = 0;
|
|
int noflg = 0;
|
|
#ifdef _SHAREII
|
|
int yflg;
|
|
#endif /* _SHAREII */
|
|
int euid;
|
|
|
|
int xpg = 0;
|
|
|
|
int pgSize;
|
|
time_t tim;
|
|
|
|
int errflg;
|
|
char argbuf[ARGSIZ];
|
|
char *parg;
|
|
char *p1; /* points to successive option arguments */
|
|
static char stdbuf[BUFSIZ+8];
|
|
cell_t cellid;
|
|
|
|
/*
|
|
* /tmp/.ps_data/ps_data stores information for quick access by ps
|
|
* and whodo. To avoid synchronization problems when
|
|
* reading and writing this file, a temporary file is
|
|
* created at the level of /tmp/.ps_data, ownership and group set to known
|
|
* ids, information stored in the temp file, and finally
|
|
* the temp file is renamed to /tmp/.ps_data/ps_data. Note also that
|
|
* update of ps_data depends on /etc/passwd, /unix and /dev.
|
|
* The files are kept in /tmp/.ps_data instead of /tmp, because /tmp
|
|
* has the sticky bit set. This keeps the ps program from being able
|
|
* to remove and rename files in /tmp without being setuid root. So,
|
|
* we created a subdirectory that is writable by root,sys for ps to
|
|
* work in.
|
|
*
|
|
*/
|
|
|
|
int ndev; /* number of devices */
|
|
int maxdev; /* number of devl structures allocated */
|
|
|
|
|
|
struct devl { /* device list */
|
|
char dname[MAXNAMLEN]; /* device name */
|
|
dev_t dev; /* device number */
|
|
} *devl;
|
|
|
|
char *tty[NTTYS]; /* for t option */
|
|
int ntty = 0;
|
|
pid_t pid[SIZ]; /* for p option */
|
|
int npid = 0;
|
|
pid_t grpid[SIZ]; /* for g option */
|
|
int ngrpid = 0;
|
|
pid_t Grpid[SIZ]; /* for G option */
|
|
int nGrpid = 0;
|
|
pid_t sessid[SIZ]; /* for s option */
|
|
int nsessid = 0;
|
|
pid_t Cellids[SIZ]; /* for X option */
|
|
int nCellids = 0;
|
|
|
|
static void usage(void); /* print usage message and quit */
|
|
static void uconv(void);
|
|
void uconv_all(struct udata *uid_tbl, int *nut);
|
|
void getdev(void), getarg(void);
|
|
int gdev(const char *, const struct stat *, int,struct FTW *);
|
|
void FormatSpecifier(char *), FillFormat(void);
|
|
void getpasswd(void);
|
|
void wrdata(void);
|
|
void pswrite(int fd, char *bp, unsigned bs);
|
|
void prstime(timespec_t st, int len);
|
|
void prformattime(time_t tm, int len);
|
|
|
|
char cmd_label[] = "UX:ps";
|
|
|
|
/*
|
|
* error handling
|
|
*/
|
|
static void
|
|
err_nomem()
|
|
{
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_outofmem, "Out of memory"));
|
|
}
|
|
|
|
static void
|
|
err_opt_c(s, c)
|
|
char *s;
|
|
int c;
|
|
{
|
|
char *pstr= s;
|
|
|
|
/* check the size of message text, message system functions
|
|
* don't handle arbitrary sizes, use PATH_MAX for limit.
|
|
*/
|
|
if (strlen(s) >= PATH_MAX) {
|
|
*(pstr+PATH_MAX) = '\0';
|
|
}
|
|
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_invpopt,
|
|
"%s is an invalid non-numeric argument for -%c"),
|
|
s, c);
|
|
}
|
|
|
|
static void
|
|
err_tty()
|
|
{
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_notty, "can't find controlling terminal"));
|
|
}
|
|
|
|
/*
|
|
* usage message
|
|
*/
|
|
static void
|
|
usage(void)
|
|
{
|
|
#ifdef _SHAREII
|
|
_sgi_nl_usage(SGINL_USAGE, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_usage3, "ps [ -edalfcjyxM ] [ -t termlist ] [ -u uidlist ] [ -o format ]"));
|
|
#else
|
|
_sgi_nl_usage(SGINL_USAGE, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_usage3, "ps [ -edalfcjxM ] [ -t termlist ] [ -u uidlist ] [ -o format ]"));
|
|
#endif /* _SHAREII */
|
|
_sgi_nl_usage(SGINL_USAGESPC, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_usage4, " [ -U userlist ] [ -G grplist ] [ -p proclist ] [ -g grplist ]"));
|
|
_sgi_nl_usage(SGINL_USAGESPC, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_usage4, " [ -s sidlist ] [ -X celllist ]"));
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Procedure: main
|
|
*
|
|
*/
|
|
main(int argc, char **argv)
|
|
{
|
|
register char **ttyp = tty;
|
|
char *name;
|
|
char *p;
|
|
int c;
|
|
uid_t puid; /* puid: process user id */
|
|
uid_t rpuid; /* rpuid: process real user id */
|
|
uid_t pgid; /* pgid: process real group id */
|
|
pid_t ppid; /* ppid: parent process id */
|
|
pid_t ppgrp; /* ppgrp: process group leader id */
|
|
pid_t psid; /* psid: session id */
|
|
int i, found;
|
|
struct ustat ustatb;
|
|
struct stat statb;
|
|
dev_t procdev;
|
|
int pgerrflg = 0; /* err flg: non-numeric arg w/p & g options */
|
|
unsigned size;
|
|
DIR *dirp;
|
|
struct dirent *dentp;
|
|
char pname[100];
|
|
int pdlen;
|
|
char *cp;
|
|
cap_t ocap;
|
|
cap_value_t cap_mac_read = CAP_MAC_READ;
|
|
#ifdef UNS
|
|
_getpwent_no_shadow = 1;
|
|
#endif
|
|
euid = geteuid();
|
|
|
|
/*
|
|
* intnl support
|
|
*/
|
|
(void)setlocale(LC_ALL, "");
|
|
(void)setcat("uxsgicore");
|
|
(void)setlabel(cmd_label);
|
|
|
|
/* set page size variable */
|
|
pgSize = getpagesize();
|
|
|
|
/* get the current time */
|
|
tim = time((time_t *) 0);
|
|
|
|
/* check to see if we need to be XPG compliant */
|
|
if (p = getenv("_XPG")) {
|
|
xpg = atoi(p);
|
|
}
|
|
|
|
label[0] = '\0';
|
|
trix_mac = (sysconf(_SC_MAC) == 1);
|
|
(void) setvbuf(stdout, stdbuf, _IOFBF, sizeof(stdbuf));
|
|
#ifdef _SHAREII
|
|
while ((c = getopt(argc, argv, "jlfcweadxAMyTt:p:g:u:n:s:o:G:U:X:")) != EOF)
|
|
#else /* _SHAREII */
|
|
while ((c = getopt(argc, argv, "jlfcweadxAMTt:p:g:u:n:s:o:G:U:X:")) != EOF)
|
|
#endif /* _SHAREII */
|
|
switch (c) {
|
|
case 'l': /* long listing */
|
|
lflg++;
|
|
break;
|
|
case 'f': /* full listing */
|
|
fflg++;
|
|
break;
|
|
case 'j':
|
|
jflg++;
|
|
break;
|
|
case 'T':
|
|
Tflg++;
|
|
break;
|
|
case 'x': /* display the cell id */
|
|
/* verify that the kernel supports the syssgi option */
|
|
if (syssgi(SGI_CELL, SGI_CELL_PID_TO_CELLID, 0,
|
|
&cellid) == -1) {
|
|
fprintf(stderr,
|
|
"Operating system version does not support -x option\n");
|
|
exit(1);
|
|
}
|
|
xflg++;
|
|
break;
|
|
case 'X': /* cell ids */
|
|
/* verify that the kernel supports the syssgi option */
|
|
if (syssgi(SGI_CELL, SGI_CELL_PID_TO_CELLID, 0,
|
|
&cellid) == -1) {
|
|
fprintf(stderr,
|
|
"Operating system version does not support -X option\n");
|
|
exit(1);
|
|
}
|
|
Xflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
if (nCellids >= SIZ)
|
|
break;
|
|
getarg();
|
|
if (!num(parg)) {
|
|
pgerrflg++;
|
|
err_opt_c(parg, 'X');
|
|
}
|
|
Cellids[nCellids++] = (pid_t) atol(parg);
|
|
} while (*p1);
|
|
break;
|
|
case 'c':
|
|
/*
|
|
* Format output to reflect scheduler changes:
|
|
* high numbers for high priorities and don't
|
|
* print nice or p_cpu values. 'c' option only
|
|
* effective when used with 'l' or 'f' options.
|
|
*/
|
|
cflg++;
|
|
break;
|
|
case 'e': /* list for every process */
|
|
case 'A':
|
|
eflg++;
|
|
tflg = uflg = Uflg = pflg = Gflg = gflg = sflg = 0;
|
|
Xflg = 0;
|
|
break;
|
|
case 'a':
|
|
/*
|
|
* Same as 'e' except no process group leaders
|
|
* and no non-terminal processes.
|
|
*/
|
|
aflg++;
|
|
break;
|
|
case 'd': /* same as e except no proc grp leaders */
|
|
dflg++;
|
|
break;
|
|
case 'n': /* no longer needed; retain as no-op */
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_noopt, "-n option ignored"));
|
|
break;
|
|
case 'M': /* print MAC labels */
|
|
if (trix_mac)
|
|
Mflg++;
|
|
break;
|
|
#ifdef _SHAREII
|
|
case 'y': /* print processes attached to lnode "uid" */
|
|
yflg++;
|
|
break;
|
|
#endif /* _SHAREII */
|
|
case 't': /* terminals */
|
|
#define TSZ 30
|
|
tflg++;
|
|
p1 = optarg;
|
|
do {
|
|
parg = argbuf;
|
|
if (ntty >= NTTYS)
|
|
break;
|
|
getarg();
|
|
if ((p = (char *)malloc(TSZ)) == NULL) {
|
|
err_nomem();
|
|
exit(1);
|
|
}
|
|
size = TSZ;
|
|
if (isdigit(*parg)) {
|
|
(void) strcpy(p, "tty");
|
|
size -= 3;
|
|
} else
|
|
*p = '\0';
|
|
(void) strncat(p, parg, (int)size);
|
|
*ttyp++ = p;
|
|
ntty++;
|
|
} while (*p1);
|
|
break;
|
|
case 'p': /* proc ids */
|
|
pflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
if (npid >= SIZ)
|
|
break;
|
|
getarg();
|
|
if (!num(parg)) {
|
|
pgerrflg++;
|
|
err_opt_c(parg, 'p');
|
|
}
|
|
pid[npid++] = (pid_t)atol(parg);
|
|
} while (*p1);
|
|
break;
|
|
case 's': /* session */
|
|
sflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
if (nsessid >= SIZ)
|
|
break;
|
|
getarg();
|
|
if (!num(parg)) {
|
|
pgerrflg++;
|
|
err_opt_c(parg, 's');
|
|
}
|
|
sessid[nsessid++] = (pid_t)atol(parg);
|
|
} while (*p1);
|
|
break;
|
|
case 'g': /* proc group */
|
|
gflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
if (ngrpid >= SIZ)
|
|
break;
|
|
getarg();
|
|
if (!num(parg)) {
|
|
pgerrflg++;
|
|
err_opt_c(parg, 'g');
|
|
}
|
|
grpid[ngrpid++] = (pid_t)atol(parg);
|
|
} while (*p1);
|
|
break;
|
|
case 'G': /* proc real group */
|
|
Gflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
if (nGrpid >= SIZ)
|
|
break;
|
|
getarg();
|
|
if (!num(parg)) {
|
|
pgerrflg++;
|
|
err_opt_c(parg, 'G');
|
|
}
|
|
Grpid[nGrpid++] = (pid_t)atol(parg);
|
|
} while (*p1);
|
|
break;
|
|
case 'u': /* user name or number */
|
|
uflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
getarg();
|
|
if (nut < SIZ)
|
|
(void) strncpy(uid_tbl[nut++].name,
|
|
parg, MAXLOGIN);
|
|
} while (*p1);
|
|
break;
|
|
case 'U': /* real user name or number */
|
|
Uflg++;
|
|
p1 = optarg;
|
|
parg = argbuf;
|
|
do {
|
|
getarg();
|
|
if (nUt < SIZ)
|
|
(void) strncpy(Uid_tbl[nUt++].name,
|
|
parg, MAXLOGIN);
|
|
} while (*p1);
|
|
break;
|
|
case 'o': /* format instruction */
|
|
oflg++;
|
|
FormatSpecifier(optarg);
|
|
break;
|
|
default: /* error on ? */
|
|
errflg++;
|
|
break;
|
|
}
|
|
if (trix_mac) {
|
|
char *labelstate;
|
|
|
|
/* If env variable is on then show security labels */
|
|
labelstate = getenv("LABELFLAG");
|
|
if (labelstate && strcasecmp(labelstate,"on") == 0)
|
|
Mflg++;
|
|
}
|
|
if (errflg || (optind < argc) || pgerrflg)
|
|
usage();
|
|
|
|
if (tflg)
|
|
*ttyp = 0;
|
|
|
|
if (stat(_PATH_PROCFSPI, &statb) < 0) {
|
|
perror(_PATH_PROCFSPI);
|
|
exit(1);
|
|
}
|
|
procdev = statb.st_dev;
|
|
if (stat("/", &statb) < 0) {
|
|
perror("/");
|
|
exit(1);
|
|
}
|
|
if ((procdev == statb.st_dev) || (ustat(procdev, &ustatb) < 0)) {
|
|
fprintf(stderr, "%s is not mounted\n", _PATH_PROCFSPI);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* If an appropriate option has not been specified, use the
|
|
* current terminal as the default.
|
|
*/
|
|
if (!(aflg || eflg || dflg || uflg || tflg || pflg || gflg || sflg ||
|
|
Gflg || Uflg || Xflg)) {
|
|
name = NULL;
|
|
for (i = 2; i >= 0; i--)
|
|
if (isatty(i)) {
|
|
name = ttyname(i);
|
|
break;
|
|
}
|
|
if (name == NULL) {
|
|
err_tty();
|
|
exit(1);
|
|
}
|
|
*ttyp++ = name + 5;
|
|
*ttyp = 0;
|
|
ntty++;
|
|
tflg++;
|
|
noflg++;
|
|
}
|
|
if (eflg) {
|
|
tflg = uflg = Uflg = pflg = sflg = gflg = Gflg = 0;
|
|
aflg = dflg = Xflg = 0;
|
|
}
|
|
if (aflg || dflg)
|
|
tflg = 0;
|
|
|
|
if (!readata()) { /* get data from psfile */
|
|
getdev();
|
|
#ifndef UNS
|
|
getpasswd();
|
|
#endif
|
|
wrdata();
|
|
}
|
|
|
|
uconv();
|
|
|
|
if (!oflg)
|
|
FillFormat();
|
|
|
|
/*
|
|
* Get rid of trailing blanks at the end of the label line.
|
|
*/
|
|
cp = (label + (strlen(label) - 1)); /* point to last char b4 '\0' */
|
|
while (*cp && (label < cp) && (*cp == ' '))
|
|
cp--;
|
|
|
|
*(cp + 1) = '\0';
|
|
|
|
/* display header */
|
|
{
|
|
/* if the header is blank, dont print anything */
|
|
int i, len = strlen(label);
|
|
for (i = 0; i < len; i++)
|
|
if (label[i] != ' ')
|
|
break;
|
|
if (i < len)
|
|
printf("%s\n", label);
|
|
}
|
|
|
|
/*
|
|
* Determine which processes to print info about by searching
|
|
* the /proc/pinfo directory and looking at each process.
|
|
*/
|
|
if ((dirp = opendir(_PATH_PROCFSPI)) == NULL) {
|
|
(void) fprintf(stderr,"Cannot open /proc/pinfo directory :%s\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
(void) sprintf(pname, "%s%c", _PATH_PROCFSPI, '/');
|
|
pdlen = strlen(pname);
|
|
|
|
/* for each active process --- */
|
|
ocap = cap_acquire(1, &cap_mac_read);
|
|
while (dentp = readdir(dirp)) {
|
|
int procfd; /* fd for /proc/pinfo/nnnnn */
|
|
char *plblstring; /* process label string */
|
|
int mt;
|
|
|
|
if (dentp->d_name[0] == '.') /* skip . and .. */
|
|
continue;
|
|
|
|
plblstring = NULL;
|
|
(void) strcpy(pname + pdlen, dentp->d_name);
|
|
if (Mflg) {
|
|
mac_t pl; /* pname's MAC label */
|
|
|
|
/*
|
|
* If you don't have privilege to get
|
|
* pname's label, then you don't have
|
|
* privilege to see the process.
|
|
*/
|
|
pl = mac_get_file (pname);
|
|
if (pl == NULL)
|
|
continue;
|
|
plblstring = mac_to_text(pl, (size_t *) NULL);
|
|
mac_free(pl);
|
|
if (plblstring == NULL)
|
|
continue;
|
|
}
|
|
retry:
|
|
if ((procfd = open(pname, O_RDONLY)) == -1) {
|
|
mac_free(plblstring);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Get the info structure for the process and close quickly.
|
|
*/
|
|
if (ioctl(procfd, PIOCPSINFO, (char *) &info) == -1) {
|
|
int saverr = errno;
|
|
|
|
(void) close(procfd);
|
|
if (saverr == EACCES) {
|
|
mac_free(plblstring);
|
|
continue;
|
|
}
|
|
if (saverr == EAGAIN)
|
|
goto retry;
|
|
if (saverr != ENOENT)
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_nopsinfo,
|
|
"PIOCPSINFO on %s: %s"),
|
|
pname, strerror(saverr));
|
|
mac_free(plblstring);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* read in the process creds
|
|
*/
|
|
if (ioctl(procfd, PIOCCRED, (char *) &cred) == -1) {
|
|
int saverr = errno;
|
|
|
|
(void) close(procfd);
|
|
if (saverr == EACCES) {
|
|
mac_free(plblstring);
|
|
continue;
|
|
}
|
|
if (saverr == EAGAIN)
|
|
goto retry;
|
|
if (saverr != ENOENT)
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_nopsinfo,
|
|
"PIOCCRED on %s: %s"),
|
|
pname, strerror(saverr));
|
|
mac_free(plblstring);
|
|
continue;
|
|
}
|
|
|
|
if (!(mt = (info.pr_thds > 1 && Tflg)))
|
|
(void) close(procfd);
|
|
|
|
if (info.pr_state == 0) { /* can't happen? */
|
|
goto next_proc;
|
|
}
|
|
found = 0;
|
|
#ifdef _SHAREII
|
|
if (yflg)
|
|
puid = info.pr_shareuid;
|
|
else
|
|
puid = cred.pr_euid;
|
|
#else /* _SHAREII */
|
|
puid = cred.pr_euid;
|
|
#endif /* _SHAREII */
|
|
rpuid = info.pr_uid;
|
|
ppid = info.pr_pid;
|
|
pgid = info.pr_gid;
|
|
ppgrp = info.pr_pgrp;
|
|
psid = info.pr_sid;
|
|
|
|
/*
|
|
* Omit process group leaders for 'a' and 'd' options.
|
|
*/
|
|
if ((ppid == psid) && (dflg || aflg)) {
|
|
goto next_proc;
|
|
}
|
|
if (eflg || dflg)
|
|
found++;
|
|
else if (pflg && search(pid, npid, ppid))
|
|
found++;
|
|
else if (uflg && ufind(puid,1))
|
|
found++; /* puid in u option arg list */
|
|
else if (Uflg && ufind(rpuid,0))
|
|
found++; /* puid in U option arg list */
|
|
else if (gflg && search(grpid, ngrpid, ppgrp))
|
|
found++; /* grpid in g option arg list */
|
|
else if (Gflg && search(Grpid, nGrpid, pgid))
|
|
found++; /* grpid in G option arg list */
|
|
else if (sflg && search(sessid, nsessid, psid))
|
|
found++; /* sessid in s option arg list */
|
|
else if (Xflg) {
|
|
(void) syssgi(SGI_CELL, SGI_CELL_PID_TO_CELLID,
|
|
info.pr_pid, &cellid);
|
|
if (search(Cellids, nCellids, (pid_t) cellid))
|
|
found++;
|
|
}
|
|
|
|
if (!found && !tflg && !aflg ) {
|
|
goto next_proc;
|
|
}
|
|
|
|
if (xflg && !Xflg) {
|
|
/* make the syssgi call to set the cell id */
|
|
(void) syssgi(SGI_CELL, SGI_CELL_PID_TO_CELLID,
|
|
info.pr_pid, &cellid);
|
|
}
|
|
|
|
if (!mt) {
|
|
if (prcom(puid, found, plblstring)) {
|
|
printf("\n");
|
|
retcode = 0;
|
|
}
|
|
} else {
|
|
prthreadctl_t ptc;
|
|
|
|
ptc.pt_tid = 0;
|
|
ptc.pt_flags = PTFD_GEQ | PTFS_ALL;
|
|
ptc.pt_cmd = PIOCPSINFO;
|
|
ptc.pt_data = (caddr_t)&info;
|
|
|
|
if (ioctl(procfd, PIOCTHREAD, &ptc) < 0
|
|
|| !prcom(puid, found, plblstring))
|
|
goto next_proc;
|
|
retcode = 0;
|
|
ptc.pt_flags = PTFD_GTR | PTFS_ALL;
|
|
for (;;) {
|
|
printf("\n");
|
|
if (ioctl(procfd, PIOCTHREAD, &ptc) < 0
|
|
|| !prcom(puid, found, plblstring))
|
|
break;
|
|
}
|
|
}
|
|
next_proc:
|
|
if (mt) (void)close(procfd);
|
|
mac_free(plblstring);
|
|
}
|
|
cap_surrender(ocap);
|
|
|
|
(void) closedir(dirp);
|
|
(void) fflush(stdout);
|
|
exit(xpg ? 0 : retcode);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/*
|
|
* Procedure: readata
|
|
*
|
|
* Notes:
|
|
* readata reads in the open devices (terminals) and stores
|
|
* info in the devl structure.
|
|
*/
|
|
|
|
static char psdir[] = "/tmp/.ps_data";
|
|
static char psfile[] = "/tmp/.ps_data/.ps_data";
|
|
static char pstmpfile[] = "/tmp/.ps_data/.ps_XXXXXX";
|
|
|
|
int readata()
|
|
{
|
|
struct stat sbuf1, sbuf2;
|
|
int fd;
|
|
|
|
fd = open(psfile, O_RDONLY);
|
|
|
|
if(fd == -1) /* Restore privs before returning error.*/
|
|
return(0);
|
|
|
|
if (fstat(fd, &sbuf1) < 0
|
|
|| sbuf1.st_size == 0
|
|
|| stat(_PATH_DEV, &sbuf2) == -1
|
|
|| sbuf1.st_mtime <= sbuf2.st_mtime
|
|
|| sbuf1.st_mtime <= sbuf2.st_ctime
|
|
|| stat("/unix", &sbuf2) == -1
|
|
|| sbuf1.st_mtime <= sbuf2.st_mtime
|
|
|| sbuf1.st_mtime <= sbuf2.st_ctime
|
|
|| stat(_PATH_PASSWD, &sbuf2) == -1
|
|
|| sbuf1.st_mtime <= sbuf2.st_mtime
|
|
|| sbuf1.st_mtime <= sbuf2.st_ctime) {
|
|
(void) close(fd);
|
|
return 0;
|
|
}
|
|
|
|
/* Read /dev data from psfile. */
|
|
if (psread(fd, (char *) &ndev, sizeof(ndev)) == 0) {
|
|
(void) close(fd);
|
|
return 0;
|
|
}
|
|
|
|
if ((devl = (struct devl *)malloc(ndev * sizeof(*devl))) == NULL) {
|
|
err_nomem();
|
|
exit(1);
|
|
}
|
|
if (psread(fd, (char *)devl, ndev * sizeof(*devl)) == 0) {
|
|
(void) close(fd);
|
|
return 0;
|
|
}
|
|
|
|
#ifndef UNS
|
|
/* Read /etc/passwd data from psfile. */
|
|
if (psread(fd, (char *) &nud, sizeof(nud)) == 0) {
|
|
(void) close(fd);
|
|
return 0;
|
|
}
|
|
if ((ud = (struct udata *)malloc(nud * sizeof(*ud))) == NULL) {
|
|
err_nomem();
|
|
exit(1);
|
|
}
|
|
if (psread(fd, (char *)ud, nud * sizeof(*ud)) == 0) {
|
|
(void) close(fd);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
(void) close(fd);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Procedure: getdev
|
|
*
|
|
* Notes: getdev() uses ftw() to pass pathnames under /dev to gdev()
|
|
* along with a status buffer.
|
|
*/
|
|
|
|
void getdev(void)
|
|
{
|
|
int rcode;
|
|
|
|
ndev = 0;
|
|
rcode = nftw(_PATH_DEV, gdev, 100, FTW_PHYS);
|
|
|
|
switch(rcode) {
|
|
|
|
case 0: return; /* successful return, devl populated */
|
|
|
|
case 1:
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_ftwproblem, "ftw() encountered problem: %s"), strerror(errno));
|
|
exit(1);
|
|
case -1:
|
|
_sgi_nl_error(SGINL_SYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_ftwfailed, "ftw() failed: %s"), strerror(errno));
|
|
exit(1);
|
|
default:
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_ftwret, "ftw() unexpected return, rcode=%d: %s"), rcode, strerror(errno));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Procedure: notinteresting
|
|
*
|
|
* Filters out directory names which don't normally contain
|
|
* tty-like devices by comparing the initial path to a table
|
|
* of known "uninteresting" strings. Returns 1 if the string is
|
|
* deemed uninteresting, 0 otherwise.
|
|
*/
|
|
|
|
char *excl[] = {
|
|
"/dev/dsk",
|
|
"/dev/rdsk",
|
|
"/dev/mt",
|
|
"/dev/rmt",
|
|
"/dev/gro",
|
|
"/dev/grin",
|
|
"/dev/annex",
|
|
"/dev/hl",
|
|
"/dev/fd",
|
|
"/dev/scsi",
|
|
"/dev/hdsp",
|
|
"/dev/vme",
|
|
"/dev/input",
|
|
"/dev/syscon",
|
|
"/dev/systty",
|
|
"/dev/tape",
|
|
"/dev/xbmon",
|
|
0
|
|
};
|
|
|
|
notinteresting(s)
|
|
char *s;
|
|
{
|
|
register char **pref;
|
|
|
|
for (pref = &excl[0]; *pref; pref++) {
|
|
if (strncmp(s, *pref, strlen(*pref)) == 0)
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Procedure: gdev
|
|
*
|
|
* gdev() puts device names and ID into the devl structure for character
|
|
* special files in /dev. The "/dev/" string is stripped from the name
|
|
* and if the resulting pathname exceeds MAXNAMLEN in length then the highest
|
|
* level directory names are stripped until the pathname is MAXNAMLEN or less.
|
|
* For efficiency purposes, we disregard directories which we know will never
|
|
* have tty-like files in them.
|
|
*/
|
|
|
|
int gdev(const char *objptr, const struct stat *objstatp,
|
|
int numb,struct FTW *f)
|
|
{
|
|
register int i;
|
|
int leng, start;
|
|
static struct devl ldevl[2];
|
|
static int lndev, consflg;
|
|
struct stat *statp,link_stat;
|
|
|
|
statp = (struct stat *)objstatp;
|
|
switch (numb) {
|
|
case FTW_SL:
|
|
/* Try to get the inode information of the file which
|
|
* this symbolic link references.
|
|
*/
|
|
if (stat(objptr,&link_stat))
|
|
return(0);
|
|
statp = &link_stat;
|
|
case FTW_F:
|
|
if ((statp->st_mode & S_IFMT) == S_IFCHR) {
|
|
/* Cut search path */
|
|
if (notinteresting(objptr))
|
|
return(0);
|
|
|
|
/* Get more and be ready for syscon & systty. */
|
|
while (ndev + lndev >= maxdev) {
|
|
maxdev += UDQ;
|
|
devl = (struct devl *) ((devl == NULL) ?
|
|
malloc(sizeof(struct devl ) * maxdev) :
|
|
realloc(devl, sizeof(struct devl ) * maxdev));
|
|
if (devl == NULL) {
|
|
err_nomem();
|
|
exit(1);
|
|
}
|
|
}
|
|
#ifndef sgi
|
|
/*
|
|
* Save systty & syscon entries if the console
|
|
* entry hasn't been seen.
|
|
*/
|
|
if (!consflg
|
|
&& (strcmp("/dev/systty", objptr) == 0
|
|
|| strcmp("/dev/syscon", objptr) == 0)) {
|
|
(void) strncpy(ldevl[lndev].dname,
|
|
&objptr[5], MAXNAMLEN);
|
|
ldevl[lndev].dev = statp->st_rdev;
|
|
lndev++;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
leng = strlen(objptr);
|
|
/* Strip off /dev/ */
|
|
if (leng < MAXNAMLEN + 4)
|
|
(void) strcpy(devl[ndev].dname, &objptr[5]);
|
|
else {
|
|
start = leng - MAXNAMLEN - 1;
|
|
|
|
for (i = start; i < leng && (objptr[i] != '/');
|
|
i++)
|
|
;
|
|
if (i == leng )
|
|
(void) strncpy(devl[ndev].dname,
|
|
&objptr[start], MAXNAMLEN);
|
|
else
|
|
(void) strncpy(devl[ndev].dname,
|
|
&objptr[i+1], MAXNAMLEN);
|
|
}
|
|
devl[ndev].dev = statp->st_rdev;
|
|
ndev++;
|
|
#ifndef sgi
|
|
/*
|
|
* Put systty & syscon entries in devl when console
|
|
* is found.
|
|
*/
|
|
if (strcmp("/dev/console", objptr) == 0) {
|
|
consflg++;
|
|
for (i = 0; i < lndev; i++) {
|
|
(void) strncpy(devl[ndev].dname,
|
|
ldevl[i].dname, MAXNAMLEN);
|
|
devl[ndev].dev = ldevl[i].dev;
|
|
ndev++;
|
|
}
|
|
lndev = 0;
|
|
}
|
|
#endif
|
|
}
|
|
return 0;
|
|
|
|
case FTW_D:
|
|
if (notinteresting(objptr))
|
|
f->quit = FTW_PRUNE;
|
|
case FTW_DNR:
|
|
case FTW_NS:
|
|
case FTW_DP:
|
|
case FTW_SLN:
|
|
return 0;
|
|
|
|
default:
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_gdeverr, "gdev() error, %d, encountered"), numb);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Procedure: getpasswd
|
|
*
|
|
* Get the passwd file data into the ud structure.
|
|
*/
|
|
|
|
void
|
|
getpasswd(void)
|
|
{
|
|
struct passwd *pw;
|
|
|
|
ud = NULL;
|
|
nud = 0;
|
|
maxud = 0;
|
|
|
|
while ((pw = getpwent()) != NULL) {
|
|
while (nud >= maxud) {
|
|
maxud += UDQ;
|
|
ud = (struct udata *) ((ud == NULL) ?
|
|
malloc(sizeof(struct udata ) * maxud) :
|
|
realloc(ud, sizeof(struct udata ) * maxud));
|
|
if (ud == NULL) {
|
|
err_nomem();
|
|
exit(1);
|
|
}
|
|
}
|
|
/*
|
|
* Copy fields from pw file structure to udata.
|
|
*/
|
|
ud[nud].uid = pw->pw_uid;
|
|
(void) strncpy(ud[nud].name, pw->pw_name, MAXLOGIN);
|
|
nud++;
|
|
}
|
|
endpwent();
|
|
}
|
|
|
|
/*
|
|
* Procedure: wrdata
|
|
*
|
|
* Restrictions:
|
|
strerror: None
|
|
mktemp: None
|
|
open(2): None
|
|
chown(2): None
|
|
rename(2): None
|
|
unlink(2): None
|
|
*/
|
|
void
|
|
wrdata(void)
|
|
{
|
|
int fd;
|
|
struct stat statbuf;
|
|
cap_t ocap;
|
|
cap_value_t cap_chown = CAP_CHOWN;
|
|
|
|
(void) umask(02);
|
|
|
|
if (mktemp(pstmpfile) == (char *)NULL ||
|
|
pstmpfile[0] == '\0') {
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_opnwr, "open() for write failed"));
|
|
_sgi_nl_error(SGINL_SYSERR, cmd_label, "%s", psfile);
|
|
_sgi_ffmtmsg(stderr, 0, cmd_label, MM_FIX,
|
|
gettxt(_SGI_DMMX_ps_notifySU, "Please notify your System Administrator"));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Make sure that the /tmp/.ps_data directory exists.
|
|
*/
|
|
if (stat(psdir, &statbuf) != 0) {
|
|
if (errno == ENOENT) {
|
|
/*
|
|
* Make the directory writable by only
|
|
* user root and group sys. This allows
|
|
* the ps to muck with the directory entries
|
|
* since it is setgid sys, but it keeps
|
|
* others away.
|
|
*/
|
|
if (mkdir(psdir, 0775) != 0) {
|
|
return;
|
|
}
|
|
ocap = cap_acquire(1, &cap_chown);
|
|
if (chown(psdir, 0, 0) != 0) {
|
|
cap_surrender(ocap);
|
|
return;
|
|
}
|
|
cap_surrender(ocap);
|
|
} else {
|
|
return;
|
|
}
|
|
} else if (!(S_ISDIR(statbuf.st_mode))) {
|
|
/*
|
|
* If the name is in use but it is not a directory,
|
|
* then it is probably a left over .ps_data file from
|
|
* when we used to keep it directly in /tmp. Try to
|
|
* remove it and create the directory in its place.
|
|
* Make sure to get the owner and group permissions
|
|
* on the directory right as described above.
|
|
*/
|
|
if (remove(psdir) != 0) {
|
|
return;
|
|
}
|
|
if (mkdir(psdir, 0775) != 0) {
|
|
return;
|
|
}
|
|
ocap = cap_acquire(1, &cap_chown);
|
|
if (chown(psdir, 0, 0) != 0) {
|
|
cap_surrender(ocap);
|
|
return;
|
|
}
|
|
cap_surrender(ocap);
|
|
}
|
|
|
|
if ((fd = open(pstmpfile, O_WRONLY|O_CREAT, 0664)) == -1) {
|
|
/* only privileged user can write ps_data file */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Make owner root, group sys.
|
|
* This is for compatibility.
|
|
*/
|
|
ocap = cap_acquire(1, &cap_chown);
|
|
(void)chown(pstmpfile, (uid_t)0, (gid_t)0);
|
|
cap_surrender(ocap);
|
|
|
|
/* write /dev data */
|
|
pswrite(fd, (char *) &ndev, sizeof(ndev));
|
|
pswrite(fd, (char *)devl, ndev * sizeof(*devl));
|
|
|
|
#ifndef UNS
|
|
/* write /etc/passwd data */
|
|
pswrite(fd, (char *) &nud, sizeof(nud));
|
|
pswrite(fd, (char *)ud, nud * sizeof(*ud));
|
|
#endif
|
|
|
|
(void) close(fd);
|
|
if (rename(pstmpfile, psfile) == -1) {
|
|
_sgi_nl_error(SGINL_SYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_rename, "rename() failed"));
|
|
_sgi_ffmtmsg(stderr, 0, cmd_label, MM_FIX,
|
|
gettxt(_SGI_DMMX_ps_notifySU, "Please notify your System Administrator"));
|
|
(void)unlink(pstmpfile);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* getarg() finds the next argument in list and copies arg into argbuf.
|
|
* p1 first pts to arg passed back from getopt routine. p1 is then
|
|
* bumped to next character that is not a comma or blank -- p1 NULL
|
|
* indicates end of list.
|
|
*/
|
|
|
|
void getarg(void)
|
|
{
|
|
char *parga;
|
|
parga = argbuf;
|
|
|
|
while(*p1 && *p1 != ',' && *p1 != ' ' && *p1 != '\t' && parga < (argbuf + ARGSIZ - 1))
|
|
*parga++ = *p1++;
|
|
*parga = '\0';
|
|
|
|
while( *p1 && ( *p1 == ',' || *p1 == ' ' || *p1 == '\t') )
|
|
p1++;
|
|
}
|
|
|
|
/*
|
|
* gettty returns the user's tty number or ? if none.
|
|
*/
|
|
char *gettty(ip)
|
|
register int *ip; /* where the search left off last time */
|
|
{
|
|
register int i;
|
|
|
|
if (info.pr_ttydev != PRNODEV && *ip >= 0) {
|
|
for (i = *ip; i < ndev; i++) {
|
|
if (devl[i].dev == info.pr_ttydev) {
|
|
*ip = i + 1;
|
|
return devl[i].dname;
|
|
}
|
|
}
|
|
}
|
|
*ip = -1;
|
|
return "?";
|
|
}
|
|
|
|
/*
|
|
* Procedure: prcom
|
|
*
|
|
* Restrictions:
|
|
lvlout: MACREAD
|
|
lvlproc: none
|
|
*
|
|
* Notes:
|
|
* Print info about the process.
|
|
*/
|
|
prcom(puid, found, plblstring)
|
|
uid_t puid;
|
|
int found;
|
|
char *plblstring;
|
|
{
|
|
register char *cp;
|
|
register char *tp;
|
|
long tm;
|
|
int i, wcnt, length;
|
|
wchar_t wchar;
|
|
register char **ttyp, *str;
|
|
int j;
|
|
char buf[64];
|
|
struct group *gr;
|
|
#ifdef UNS
|
|
struct passwd *pw;
|
|
#endif
|
|
|
|
if (info.pr_zomb && tflg && !found)
|
|
return 0;
|
|
|
|
#if NEVER
|
|
/*
|
|
* SIDL - intermediate state in process creation
|
|
* psinfo may not be consistent (skip it for now) -XXX
|
|
*/
|
|
if (info.pr_state==SIDL)
|
|
return(1);
|
|
#endif
|
|
|
|
/*
|
|
* Get current terminal. If none ("?") and 'a' is set, don't print
|
|
* info. If 't' is set, check if term is in list of desired terminals
|
|
* and print it if it is.
|
|
*/
|
|
i = 0;
|
|
tp = gettty(&i);
|
|
if (aflg && *tp == '?')
|
|
return 0;
|
|
if (tflg && !found) {
|
|
int match = 0;
|
|
|
|
/*
|
|
* Look for same device under different names.
|
|
*/
|
|
while (i >= 0 && !match) {
|
|
for (ttyp = tty; (str = *ttyp) != 0 && !match; ttyp++)
|
|
if (strcmp(tp, str) == 0)
|
|
match = 1;
|
|
if (!match)
|
|
tp = gettty(&i);
|
|
}
|
|
if (!match)
|
|
return 0;
|
|
/*
|
|
* if -t was not specified (we're checking for terminal
|
|
* by default) require an effective uid match
|
|
*/
|
|
if (noflg && puid != euid)
|
|
return 0;
|
|
}
|
|
|
|
for ( j = 0; j < fcount; j++ ) {
|
|
|
|
/* for each format entry, display */
|
|
switch (fEntry[j].spec) {
|
|
case PS_RUSER:
|
|
#ifdef UNS
|
|
pw = getpwuid(cred.pr_ruid);
|
|
if (pw) {
|
|
printf("%*.*s ", fEntry[j].len,
|
|
fEntry[j].len, pw->pw_name);
|
|
} else {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cred.pr_ruid);
|
|
}
|
|
#else
|
|
if ((i = getunam(cred.pr_ruid)) >= 0)
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len,
|
|
ud[i].name);
|
|
else {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cred.pr_ruid);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case PS_USER:
|
|
#ifdef UNS
|
|
#ifdef _SHAREII
|
|
if (yflg)
|
|
pw = getpwuid(puid);
|
|
else
|
|
pw = getpwuid(cred.pr_euid);
|
|
#else /* _SHAREII */
|
|
pw = getpwuid(cred.pr_euid);
|
|
#endif /* _SHAREII */
|
|
if (pw) {
|
|
printf("%*.*s ", fEntry[j].len,
|
|
fEntry[j].len, pw->pw_name);
|
|
} else {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cred.pr_ruid);
|
|
}
|
|
#else
|
|
#ifdef _SHAREII
|
|
if (yflg)
|
|
i = getunam(puid);
|
|
else
|
|
i = getunam(cred.pr_euid);
|
|
#else /* _SHAREII */
|
|
i = getunam(cred.pr_euid);
|
|
#endif /* _SHAREII */
|
|
if (i >= 0)
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len,
|
|
ud[i].name);
|
|
else {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cred.pr_euid);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case PS_RGROUP:
|
|
if (gr = getgrgid(cred.pr_rgid))
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len,
|
|
gr->gr_name);
|
|
else {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cred.pr_rgid);
|
|
}
|
|
break;
|
|
|
|
case PS_GROUP:
|
|
if (gr = getgrgid(cred.pr_egid))
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len,
|
|
gr->gr_name);
|
|
else {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cred.pr_egid);
|
|
}
|
|
break;
|
|
|
|
case PS_PID:
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, info.pr_pid);
|
|
break;
|
|
|
|
case PS_PPID:
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, info.pr_ppid);
|
|
break;
|
|
|
|
case PS_PGID:
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, info.pr_pgrp);
|
|
break;
|
|
|
|
case PS_PCPU:
|
|
/* ok, ok, this is a hack job but the stats
|
|
* are not available in the kernel and at this point
|
|
* having ps wait a certain about of time to
|
|
* determine them isn't a good idea. */
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, 0);
|
|
break;
|
|
|
|
case PS_VSZ:
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, info.pr_size * pgSize / 1024);
|
|
break;
|
|
|
|
case PS_NICE:
|
|
if (info.pr_zomb) {
|
|
sprintf(buf, "%%-%ds ", fEntry[j].len);
|
|
printf(buf, "-");
|
|
break;
|
|
}
|
|
if (strcmp(info.pr_clname, "TS") == 0) {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, info.pr_nice);
|
|
}
|
|
#ifdef _SHAREII
|
|
else if (strcmp(info.pr_clname, "SHR") == 0) {
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, info.pr_nice);
|
|
}
|
|
#endif /* _SHAREII */
|
|
else if (strcmp(info.pr_clname, "WL") == 0) {
|
|
sprintf(buf, "%%%d.%ds ", fEntry[j].len, fEntry[j].len);
|
|
printf(buf, info.pr_clname);
|
|
} else if (strcmp(info.pr_clname, "B") == 0) {
|
|
sprintf(buf, "%%%d.%ds ", fEntry[j].len, fEntry[j].len);
|
|
printf(buf, info.pr_clname);
|
|
} else if (strcmp(info.pr_clname, "BC") == 0) {
|
|
sprintf(buf, "%%%d.%ds ", fEntry[j].len, fEntry[j].len);
|
|
printf(buf, info.pr_clname);
|
|
} else {
|
|
sprintf(buf, "%%%d.%ds ", fEntry[j].len, fEntry[j].len);
|
|
printf(buf, info.pr_clname);
|
|
}
|
|
break;
|
|
|
|
case PS_ETIME:
|
|
if (info.pr_zomb) {
|
|
sprintf(buf, "%%-%ds ", fEntry[j].len);
|
|
printf(buf, "-");
|
|
break;
|
|
}
|
|
if ((tm = tim - info.pr_start.tv_sec) < 0)
|
|
tm = 0L;
|
|
prformattime(tm,fEntry[j].len);
|
|
break;
|
|
|
|
case PS_TIME:
|
|
tm = info.pr_time.tv_sec;
|
|
if (info.pr_time.tv_nsec > 500000000)
|
|
tm++;
|
|
prformattime(tm,fEntry[j].len);
|
|
break;
|
|
|
|
case PS_TTY:
|
|
sprintf(buf, "%%-%ds ", fEntry[j].len);
|
|
if (info.pr_zomb)
|
|
printf(buf, "-");
|
|
else
|
|
printf(buf, tp);
|
|
break;
|
|
|
|
case PS_COMM:
|
|
if (info.pr_zomb) {
|
|
printf("%.*s ", fEntry[j].len, "<defunct>");
|
|
break;
|
|
}
|
|
|
|
/* if not last, make sure to fill in spaces, if it
|
|
* is last, don't fill in spaces */
|
|
wcnt = namencnt(info.pr_fname, 16, fEntry[j].len);
|
|
if ((j + 1) < fcount)
|
|
printf("%-*.*s ", fEntry[j].len, wcnt, info.pr_fname);
|
|
else
|
|
printf("%.*s ", wcnt, info.pr_fname);
|
|
break;
|
|
|
|
case PS_ARGS:
|
|
if (info.pr_zomb) {
|
|
printf("%.*s ", fEntry[j].len, "<defunct>");
|
|
break;
|
|
}
|
|
for (cp = info.pr_psargs; cp < &info.pr_psargs[PRARGSZ]; ) {
|
|
if (*cp == 0)
|
|
break;
|
|
length = mbtowc(&wchar, cp, MB_LEN_MAX);
|
|
if (length < 0 || !iswprint(wchar)) {
|
|
sprintf(buf, " [ %.8s ]", info.pr_fname);
|
|
printf("%.*s ", fEntry[j].len, buf);
|
|
wcnt = 8;
|
|
return 1;
|
|
}
|
|
cp += length;
|
|
}
|
|
|
|
/* if not last, make sure to fill in spaces, if it
|
|
* is last, don't fill in spaces */
|
|
if ((j + 1) < fcount) {
|
|
wcnt = namencnt(info.pr_psargs, PRARGSZ,
|
|
lflg ? fEntry[j].len : PRARGSZ);
|
|
printf("%-*.*s ", (lflg ? fEntry[j].len : PRARGSZ),
|
|
wcnt, info.pr_psargs);
|
|
} else {
|
|
wcnt = namencnt(info.pr_psargs, PRARGSZ, lflg ?
|
|
fEntry[j].len : PRARGSZ);
|
|
printf("%.*s", wcnt, info.pr_psargs);
|
|
}
|
|
break;
|
|
|
|
case PS_STIME:
|
|
if (info.pr_zomb)
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len, "-");
|
|
else
|
|
prstime(info.pr_start,fEntry[j].len);
|
|
break;
|
|
|
|
case PS_FLAG:
|
|
sprintf(buf, "%%%dx ", fEntry[j].len);
|
|
printf(buf, info.pr_flag & PR_FLAG_MASK);
|
|
break;
|
|
|
|
case PS_STATE:
|
|
i = 1;
|
|
while (i < fEntry[j].len)
|
|
printf(" "), i++;
|
|
printf("%c ", info.pr_sname);
|
|
break;
|
|
|
|
case PS_WCHAN:
|
|
if (info.pr_wchan && !info.pr_zomb) {
|
|
printf("%*x ", fEntry[j].len,
|
|
info.pr_wchan);
|
|
} else {
|
|
i = 1;
|
|
while (i < fEntry[j].len)
|
|
putchar(' '), i++;
|
|
printf("- ");
|
|
}
|
|
break;
|
|
|
|
case PS_WNAME:
|
|
if (info.pr_wchan && !info.pr_zomb) {
|
|
if (info.pr_wname[0])
|
|
printf("%*.*s ",
|
|
fEntry[j].len, fEntry[j].len,
|
|
info.pr_wname);
|
|
else
|
|
printf("%*x ", fEntry[j].len,
|
|
info.pr_wchan);
|
|
} else {
|
|
i = 1;
|
|
while (i < fEntry[j].len)
|
|
putchar(' '), i++;
|
|
printf("- ");
|
|
}
|
|
break;
|
|
|
|
case PS_UTIL:
|
|
sprintf(buf, "%%%dd ", fEntry[j].len);
|
|
printf(buf, info.pr_cpu & 0377);
|
|
break;
|
|
|
|
case PS_CELL:
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, cellid);
|
|
break;
|
|
|
|
case PS_UID:
|
|
sprintf(buf, "%%%dld ", fEntry[j].len);
|
|
printf(buf, puid);
|
|
break;
|
|
|
|
case PS_ADDR:
|
|
sprintf(buf, "%%%dlx ", fEntry[j].len);
|
|
printf(buf, info.pr_addr);
|
|
break;
|
|
|
|
case PS_OPRI:
|
|
if (strcmp(info.pr_clname, "WL") == 0) {
|
|
sprintf(buf, " w ");
|
|
printf (buf, info.pr_oldpri);
|
|
} else if (strcmp(info.pr_clname, "B") == 0) {
|
|
sprintf(buf, " b ");
|
|
printf (buf, info.pr_oldpri);
|
|
} else if (strcmp(info.pr_clname, "BC") == 0) {
|
|
sprintf(buf, " bc ");
|
|
printf (buf, info.pr_oldpri);
|
|
} else {
|
|
sprintf(buf, "%%%dd ", fEntry[j].len);
|
|
printf(buf, info.pr_oldpri);
|
|
}
|
|
break;
|
|
|
|
case PS_PROC:
|
|
if (info.pr_zomb) {
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len, "-");
|
|
break;
|
|
}
|
|
if ((int)info.pr_sonproc < 0) {
|
|
i = 1;
|
|
while (i < fEntry[j].len)
|
|
putchar(' '), i++;
|
|
printf("* ");
|
|
} else {
|
|
sprintf(buf, "%%%dd ", fEntry[j].len);
|
|
printf(buf, info.pr_sonproc);
|
|
}
|
|
break;
|
|
|
|
case PS_SZ:
|
|
if (info.pr_zomb) {
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len, "-");
|
|
break;
|
|
}
|
|
sprintf(buf, "%%%dd%c", fEntry[j].len, fEntry[j].d);
|
|
printf(buf, info.pr_size);
|
|
break;
|
|
|
|
case PS_RSS:
|
|
if (info.pr_zomb) {
|
|
printf("%-*.*s ", fEntry[j].len, fEntry[j].len, "-");
|
|
break;
|
|
}
|
|
sprintf(buf, "%%-%dd%c", fEntry[j].len, fEntry[j].d);
|
|
printf(buf, info.pr_rssize);
|
|
break;
|
|
|
|
case PS_OTIME:
|
|
i = fEntry[j].len - 5;
|
|
while (i)
|
|
putchar(' '), i--;
|
|
tm = info.pr_time.tv_sec;
|
|
if (info.pr_time.tv_nsec > 500000000)
|
|
tm++;
|
|
printf("%2ld:%.2ld ", tm / 60, tm % 60);
|
|
break;
|
|
|
|
case PS_CLASS:
|
|
printf("%*.*s ", fEntry[j].len, fEntry[j].len,
|
|
(info.pr_zomb ? "-" : info.pr_clname));
|
|
break;
|
|
|
|
case PS_PRI:
|
|
if (strcmp(info.pr_clname, "WL") == 0)
|
|
printf(" w ");
|
|
else {
|
|
sprintf(buf, "%%%dd ", fEntry[j].len);
|
|
printf(buf, info.pr_pri);
|
|
}
|
|
break;
|
|
|
|
case PS_SID:
|
|
sprintf(buf, "%%%dd ", fEntry[j].len);
|
|
printf(buf, info.pr_sid);
|
|
break;
|
|
|
|
case PS_BLANK:
|
|
putchar(' ');
|
|
break;
|
|
case PS_LABEL:
|
|
sprintf(buf, "%%-%ds ", fEntry[j].len);
|
|
printf(buf, plblstring);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Returns 1 if arg is found in array arr, of length num; 0 otherwise.
|
|
*/
|
|
int search(pid_t arr[], register int number, register pid_t arg)
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; i < number; i++)
|
|
if (arg == arr[i])
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Procedure: uconv
|
|
*
|
|
*/
|
|
void
|
|
uconv(void) {
|
|
uconv_all(uid_tbl, &nut);
|
|
uconv_all(Uid_tbl, &nUt);
|
|
}
|
|
|
|
#ifdef UNS
|
|
void
|
|
uconv_all(struct udata *uid_tbl, int *nut)
|
|
{
|
|
struct passwd *pw;
|
|
uid_t pwuid;
|
|
int i, j;
|
|
|
|
for (i = 0; i < *nut; i++) {
|
|
pw = getpwnam(uid_tbl[i].name);
|
|
if (! pw && isdigit(*uid_tbl[i].name)) {
|
|
pwuid = (uid_t)atol(uid_tbl[i].name);
|
|
pw = getpwuid(pwuid);
|
|
}
|
|
if (pw) {
|
|
uid_tbl[i].uid = pw->pw_uid;
|
|
(void) strncpy(uid_tbl[i].name, pw->pw_name,
|
|
MAXLOGIN);
|
|
} else {
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_unknuser, "unknown user %s"),
|
|
uid_tbl[i].name);
|
|
for (j = i + 1; j < *nut; j++) {
|
|
(void) strncpy(uid_tbl[j-1].name,
|
|
uid_tbl[j].name, MAXLOGIN);
|
|
}
|
|
*nut -= 1;
|
|
if (*nut <= 0)
|
|
exit(1);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
}
|
|
#else
|
|
void
|
|
uconv_all(struct udata *uid_tbl, int *nut)
|
|
{
|
|
uid_t pwuid;
|
|
int found, i, j;
|
|
|
|
/*
|
|
* Search name array for oarg.
|
|
*/
|
|
for (i = 0; i < *nut; i++) {
|
|
found = -1;
|
|
for (j = 0; j < nud; j++) {
|
|
if (strncmp(uid_tbl[i].name, ud[j].name,
|
|
MAXLOGIN) == 0) {
|
|
found = j;
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* If not found and oarg is numeric, search number array.
|
|
*/
|
|
if (found < 0
|
|
&& uid_tbl[i].name[0] >= '0'
|
|
&& uid_tbl[i].name[0] <= '9') {
|
|
pwuid = (uid_t)atol(uid_tbl[i].name);
|
|
for (j = 0; j < nud; j++) {
|
|
if (pwuid == ud[j].uid) {
|
|
found = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If found, enter found index into tbl array.
|
|
*/
|
|
if (found != -1) {
|
|
uid_tbl[i].uid = ud[found].uid;
|
|
(void) strncpy(uid_tbl[i].name, ud[found].name,
|
|
MAXLOGIN);
|
|
} else {
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_unknuser, "unknown user %s"),
|
|
uid_tbl[i].name);
|
|
for (j = i + 1; j < *nut; j++) {
|
|
(void) strncpy(uid_tbl[j-1].name,
|
|
uid_tbl[j].name, MAXLOGIN);
|
|
}
|
|
*nut -= 1;
|
|
if (*nut <= 0)
|
|
exit(1);
|
|
i--;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* For full command listing (-f flag) print user name instead of number.
|
|
* Search table of userid numbers and if puid is found, return the
|
|
* corresponding name. Otherwise search /etc/passwd.
|
|
*/
|
|
int getunam(puid)
|
|
register uid_t puid;
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; i < nud; i++)
|
|
if (ud[i].uid == puid)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Return 1 if puid is in table, otherwise 0.
|
|
*/
|
|
int ufind(puid,flag)
|
|
register uid_t puid;
|
|
{
|
|
register int i;
|
|
int count = (flag ? nut : nUt);
|
|
|
|
for (i = 0; i < count; i++)
|
|
if (flag && uid_tbl[i].uid == puid)
|
|
return 1;
|
|
else if (!flag && Uid_tbl[i].uid == puid)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Procedure: psread
|
|
*
|
|
* Restrictions:
|
|
read(2): None
|
|
unlink(2): None
|
|
* Notes:
|
|
* Special read; unlinks psfile on read error.
|
|
*/
|
|
int psread(fd, bp, bs)
|
|
int fd;
|
|
char *bp;
|
|
unsigned int bs;
|
|
{
|
|
int rbs;
|
|
|
|
if ((rbs = read(fd, bp, bs)) != bs) {
|
|
(void) unlink(psfile);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Procedure: pswrite
|
|
*
|
|
* Restrictions:
|
|
write(2): None
|
|
unlink(2): None
|
|
* Notes:
|
|
* Special write; unlinks pstmpfile on write error.
|
|
*/
|
|
void
|
|
pswrite(fd, bp, bs)
|
|
int fd;
|
|
char *bp;
|
|
unsigned bs;
|
|
{
|
|
int wbs;
|
|
|
|
if ((wbs = write(fd, bp, bs)) != bs) {
|
|
_sgi_nl_error(SGINL_NOSYSERR, cmd_label,
|
|
gettxt(_SGI_DMMX_ps_pswriteerr,
|
|
"pswrite() error on write, wbs=%d, bs=%d"),
|
|
wbs, bs);
|
|
(void) unlink(pstmpfile);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Procedure: prstime
|
|
*
|
|
* Restrictions:
|
|
* cftime: MACREAD opens /usr/lib/locale/<language>/LC_TIME
|
|
* which should be at SYS_PUBLIC
|
|
* gettxt: None
|
|
* printf: None
|
|
* Notes:
|
|
* Print starting time of process unless process started more than 24 hours
|
|
* ago, in which case the date is printed.
|
|
*/
|
|
void
|
|
prstime(timespec_t st, int len)
|
|
{
|
|
char sttim[26];
|
|
time_t starttime;
|
|
|
|
starttime = st.tv_sec;
|
|
if (st.tv_nsec > 500000000)
|
|
starttime++;
|
|
|
|
if (tim - starttime > 24*60*60) {
|
|
cftime(sttim, gettxt(":724","%b %d"), &starttime);
|
|
sttim[8] = '\0';
|
|
} else {
|
|
cftime(sttim, gettxt(":725","%H:%M:%S"), &starttime);
|
|
sttim[8] = '\0';
|
|
}
|
|
printf("%*.*s ", len, len, sttim);
|
|
}
|
|
|
|
|
|
void
|
|
prformattime(time_t tm, int len)
|
|
{
|
|
char buf[24];
|
|
long l,m;
|
|
|
|
l = tm % (24*60*60);
|
|
m = l % (60*60);
|
|
if (tm > 24*60*60)
|
|
sprintf(buf, "%2ld-%.2ld:%.2ld:%.2ld", tm / (24*60*60), l / (60*60),
|
|
m / 60, m % 60 );
|
|
else if (tm > 60*60)
|
|
sprintf(buf, " %2ld:%.2ld:%.2ld", l / (60*60), m / 60, m % 60 );
|
|
else
|
|
sprintf(buf, " %2ld:%.2ld", m / 60, m % 60);
|
|
|
|
printf("%*.*s ", len, len, buf);
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns true iff string is all numeric.
|
|
*/
|
|
int num(s)
|
|
register char *s;
|
|
{
|
|
register int c;
|
|
|
|
if (s == NULL)
|
|
return 0;
|
|
c = *s;
|
|
do {
|
|
if (!isdigit(c))
|
|
return 0;
|
|
} while (c = *++s);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Function to compute the number of printable bytes in a multibyte
|
|
* command string ("internationalization").
|
|
*/
|
|
int namencnt(cmd, eucsize, scrsize)
|
|
register char *cmd;
|
|
int eucsize;
|
|
int scrsize;
|
|
{
|
|
register int eucwcnt = 0, scrwcnt = 0;
|
|
register int neucsz, nscrsz;
|
|
wchar_t wchar;
|
|
|
|
while (*cmd != '\0') {
|
|
if ((neucsz = mbtowc(&wchar, cmd, MB_LEN_MAX)) < 0)
|
|
return 8; /* default to use for illegal chars */
|
|
if ((nscrsz = wcwidth(wchar)) == 0)
|
|
return 8;
|
|
if (eucwcnt + neucsz > eucsize || scrwcnt + nscrsz > scrsize)
|
|
break;
|
|
eucwcnt += neucsz;
|
|
scrwcnt += nscrsz;
|
|
cmd += neucsz;
|
|
}
|
|
return eucwcnt;
|
|
}
|
|
|
|
|
|
/*
|
|
* Interpret format command line and output appropriate header
|
|
*/
|
|
void
|
|
FormatSpecifier(char *str)
|
|
{
|
|
|
|
int i = 0, found, len, l, j;
|
|
char id, buf[32], delimit;
|
|
char *rstr = str;
|
|
|
|
while (str && str[i]) {
|
|
found = 0;
|
|
|
|
/* if there are white spaces skip them */
|
|
while (str[i] == ' ')
|
|
i++;
|
|
|
|
for (j = 0; j < FORMAT_ENTRIES && str[i]; j++)
|
|
if (!strncmp(fname[j].name, &str[i], fname[j].namelen)) {
|
|
found++;
|
|
i += fname[j].namelen;
|
|
id = fname[j].spec;
|
|
|
|
/* override the default name */
|
|
if (str[i] == '=') {
|
|
i++;
|
|
len = 0;
|
|
|
|
/* look for delimitor */
|
|
while (str[i+len] != ',' && str[i+len] != '\0')
|
|
len++;
|
|
|
|
/* is it long enough */
|
|
l = len < fname[j].minlen ? fname[j].minlen : len;
|
|
|
|
/* create format string to fit requirements */
|
|
sprintf(buf, "%%s%%%s%d.%ds ",
|
|
(fname[j].adjust == LEFT_ADJUST ? "-" : ""), l, len);
|
|
|
|
sprintf(label, buf, label, &str[i]);
|
|
i += len;
|
|
len = l;
|
|
delimit = ' ';
|
|
} else {
|
|
len = fname[j].minlen;
|
|
sprintf(buf, "%%s%%%s%d.%ds",
|
|
(fname[j].adjust == LEFT_ADJUST ? "-" : ""), len, len);
|
|
sprintf(label, buf, label, fname[j].def);
|
|
if (str[i] == ':')
|
|
strcat(label, ":"), i++, delimit = ':';
|
|
else
|
|
strcat(label, " "), delimit = ' ';
|
|
}
|
|
|
|
/* add entry */
|
|
if (fcount == FORMAT_MAX)
|
|
return;
|
|
fEntry[fcount].spec = id;
|
|
fEntry[fcount].len = len;
|
|
fEntry[fcount].d = delimit;
|
|
fcount++;
|
|
|
|
/* if delimitor, go on to next */
|
|
if (str[i] == ',')
|
|
i++;
|
|
|
|
if (id == PS_LABEL && trix_mac)
|
|
Mflg++;
|
|
|
|
break;
|
|
}
|
|
if (!found) {
|
|
err_opt_c(rstr, 'o');
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FillFormat(void)
|
|
{
|
|
char format[512];
|
|
|
|
format[0] = '\0';
|
|
if (Mflg)
|
|
strcat(format, "label,");
|
|
if (!lflg && !fflg)
|
|
strcat(format, "blank,");
|
|
else if (lflg)
|
|
strcat(format, "flag,state,");
|
|
if (fflg)
|
|
strcat(format, "user=UID,");
|
|
else if (lflg)
|
|
strcat(format, "uid,");
|
|
strcat(format, "pid,");
|
|
if (lflg || fflg)
|
|
strcat(format, "ppid,");
|
|
if (jflg)
|
|
strcat(format, "pgid,sid,");
|
|
if (xflg || Xflg)
|
|
strcat(format, "cell,");
|
|
if (cflg)
|
|
strcat(format, "class,pri,");
|
|
else if (lflg || fflg) {
|
|
if (!cflg)
|
|
strcat(format, "util,");
|
|
if (lflg)
|
|
strcat(format, "opri,nice,");
|
|
}
|
|
if (lflg) {
|
|
if (xpg)
|
|
strcat(format, "addr,sz,wname,");
|
|
else
|
|
strcat(format, "cpu,sz:rss,wname,");
|
|
}
|
|
if (fflg)
|
|
strcat(format, "stime,tty,otime,args=CMD");
|
|
else
|
|
strcat(format, "tty,otime,comm=CMD");
|
|
|
|
FormatSpecifier(format);
|
|
}
|