/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* ps -- print things about processes.
*/
#define _SYSCALL32
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <dirent.h>
#include <procfs.h>
#include <libelf.h>
#include <gelf.h>
#include <locale.h>
#include <wctype.h>
#include <stdarg.h>
#include <priv_utils.h>
#include <zone.h>
/* only one tty can be specified with SunOS ps */
struct psent {
char *psargs;
int found;
};
static int errflg;
static char *gettty();
static char *parg;
} *devl;
static struct tty {
char *tname;
static int ntty = 0;
static int pidwidth;
static void usage(); /* print usage message and quit */
static void getarg(void);
static int num(char *);
static int namencnt(char *, int, int);
static int pscompare(const void *, const void *);
static char *err_string(int);
int
{
int entsize;
int nent;
char *tmp;
char *p;
int c;
int i, found;
int pdlen;
/*
* This program needs the proc_owner privilege
*/
(char *)NULL);
/*
* calculate width of pid fields based on configured MAXPID
* (must be at least 5 to retain output format compatibility)
*/
pidwidth = 1;
while ((maxpid /= 10) > 0)
++pidwidth;
twidth = 80;
else
/* add the '-' for BSD compatibility */
if (argc > 1) {
}
}
}
switch (c) {
case 'g':
gflg++; /* include process group leaders */
break;
case 'c': /* display internal command name */
cflg++;
break;
case 'r': /* restrict output to running processes */
rflg++;
break;
case 'S': /* display time by process and all reaped children */
Sflg++;
break;
case 'x': /* process w/o controlling tty */
xflg++;
break;
case 'l': /* long listing */
lflg++;
break;
case 'u': /* user-oriented output */
uflg++;
break;
case 'U': /* update private database ups_data */
Uflg++;
break;
case 'w': /* increase display width */
if (twidth < 132)
twidth = 132;
else /* second w option */
break;
case 'v': /* display virtual memory format */
vflg++;
break;
case 'a':
/*
* display all processes except process group
* leaders and processes w/o controlling tty
*/
aflg++;
gflg++;
break;
case 'e':
/* Display environment along with aguments. */
eflg++;
break;
case 'n': /* Display numerical output */
nflg++;
break;
case 't': /* restrict output to named terminal */
tflg++;
gflg++;
xflg = 0;
do { /* only loop through once (NTTYS = 2) */
break;
getarg();
"ps: no memory\n");
exit(1);
}
p[0] = '\0';
(void) strcpy(p, "tty");
size -= 3;
}
xflg++;
else {
struct stat64 s;
}
ntty++;
} while (*p1);
break;
default: /* error on ? */
errflg++;
break;
}
if (errflg)
usage();
usage();
}
/*
* The -U option is obsolete. Attempts to use it cause ps to exit
* without printing anything.
*/
if (Uflg)
exit(0);
pflg++;
getarg();
"ps: %s is an invalid non-numeric argument for a process id\n", parg);
usage();
}
gflg++;
}
if (tflg)
/* allocate an initial guess for the number of processes */
entsize = 1024;
exit(1);
}
nent = 0; /* no active entries yet */
if (lflg) {
" F UID%*s%*s %%C PRI NI SZ RSS "
} else if (uflg) {
if (nflg)
" UID%*s %%CPU %%MEM SZ RSS "
"TT S START TIME COMMAND",
else
"USER %*s %%CPU %%MEM SZ RSS "
"TT S START TIME COMMAND",
} else if (vflg) {
"%*s TT S TIME SIZE RSS %%CPU %%MEM "
} else
exit(1);
}
/*
* Determine which processes to print info about by searching
* the /proc directory and looking at each process.
*/
procdir);
exit(1);
}
/* for each active process --- */
continue;
continue;
asfd = -1;
/* now we need the proc_owner privilege */
(void) __priv_bracket(PRIV_ON);
/* drop proc_owner privilege after open */
(void) __priv_bracket(PRIV_OFF);
}
/*
* Get the info structure for the process
*/
if (asfd > 0)
goto retry;
continue;
}
found = 0;
goto closeit;
/* Display only process from command line */
if (pflg) { /* pid in arg list */
found++;
else
goto closeit;
}
/*
* Omit "uninteresting" processes unless 'g' option.
*/
goto closeit;
/*
* Omit non-running processes for 'r' option
*/
if (rflg &&
goto closeit;
goto closeit;
/*
* Read the args for the -w and -ww cases
*/
if (asfd > 0) {
goto retry;
"ps: read() on %s: %s\n",
continue;
}
} else {
}
entsize *= 2;
exit(1);
}
}
== NULL) {
exit(1);
}
else {
== NULL) {
exit(1);
}
}
nent++;
if (asfd > 0)
}
/* revert to non-privileged user */
(void) __priv_relinquish();
for (i = 0; i < nent; i++) {
(void) printf("\n");
retcode = 0;
}
}
return (retcode);
}
static void
{
exit(1);
}
/*
* Read the process arguments from the process.
* This allows >PRARGSZ characters of arguments to be displayed but,
* unlike pr_psargs[], the process may have changed them.
*/
static int
{
int i;
#ifdef _LP64
#endif
goto out;
nextargoff = 0;
while (bsize > 0) {
#ifdef _LP64
if (is32) {
argvoff)) <= 0) {
break;
return (-1);
}
for (i = 0; i < NARG; i++)
} else
#endif
argvoff)) <= 0) {
break;
return (-1);
}
narg = 0;
}
break;
if (argoff != nextargoff &&
break;
return (-1);
}
*psa++ = ' ';
#ifdef _LP64
#else
#endif
}
psa--;
out:
*psa = '\0';
return (0);
}
/*
* Read environment variables from the process.
* Append them to psargs if there is room.
*/
static int
{
int len;
char *psa;
char *psainit;
int bsize;
int i;
#ifdef _LP64
#endif
return (0);
nextenvoff = 0;
while (bsize > 0) {
#ifdef _LP64
if (is32) {
envpoff)) <= 0) {
break;
return (-1);
}
for (i = 0; i < NARG; i++)
} else
#endif
envpoff)) <= 0) {
break;
return (-1);
}
nenv = 0;
}
break;
if (envoff != nextenvoff &&
break;
return (-1);
}
*psa++ = ' ';
#ifdef _LP64
#else
#endif
}
psa--;
*psa = '\0';
return (0);
}
/*
* 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.
*/
static void
getarg()
{
char *parga;
int c;
p1++;
*parga++ = c;
p1++;
}
*parga = '\0';
p1++;
}
static char *
{
int i;
}
return (NULL);
}
static char *
{
"ps: not enough memory for %d devices\n", maxdev);
exit(1);
}
}
}
/* Strip off /dev/ */
else {
;
if (i == leng)
else
}
}
/*
* gettty returns the user's tty number or ? if none.
*/
static char *
{
char *retval;
if (zid == -1)
return ("?");
return (retval);
}
/*
* Print percent from 16-bit binary fraction [0 .. 1]
* Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
*/
static void
{
}
/*
* Print info about the process.
*/
static int
{
char *cp;
char *tp;
char *psa;
long tm;
/*
* If process is zombie, call print routine and return.
*/
return (0);
else {
return (1);
}
}
/*
* 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;
return (0);
int match = 0;
/*
* Look for a name match
*/
match = 1;
break;
}
/*
* Look for same device under different names.
*/
}
if (!match) {
return (0);
}
}
if (lflg)
if (uflg) {
if (!nflg) {
/* USER */
else
/* UID */
} else {
}
} else if (lflg)
if (lflg)
if (lflg)
if (uflg) {
}
if (lflg) {
}
(void) printf(" 0");
else
(void) printf(" ?");
(void) printf(" 0");
else
(void) printf(" ?");
}
if (lflg) { /* WCHAN */
(void) printf(" ");
(void) printf(" %+8.8lx",
} else {
(void) printf(" ?");
}
}
else
if (!lflg)
if (lflg)
if (uflg)
/* time just for process */
if (Sflg) { /* calculate time for process and all reaped children */
>= 1000000000)
tm += 1;
}
if (vflg) {
(void) printf(" 0");
else
(void) printf(" ?");
(void) printf(" 0");
else
(void) printf(" ?");
}
if (cflg) { /* CMD */
return (1);
}
/*
* PRARGSZ == length of cmd arg string.
*/
i = PRARGSZ;
} else {
}
if (*cp == 0)
break;
return (1);
}
}
#if 0
/* dumps core on really long strings */
#else
(void) putchar(' ');
#endif
return (1);
}
/*
* Print starting time of process unless process started more than 24 hours
* ago, in which case the date is printed.
*/
static void
{
if (tim == 0L)
} else {
}
}
static void
{
long tm;
if (lflg)
if (uflg) {
else
} else if (lflg)
if (lflg)
if (lflg)
if (uflg) {
prtpct(0); /* %CPU */
prtpct(0); /* %MEM */
}
if (lflg) {
}
}
if (lflg)
if (uflg)
/* time just for process */
if (Sflg) { /* calculate time for process and all reaped children */
>= 1000000000)
tm += 1;
}
if (vflg) {
prtpct(0); /* %CPU */
prtpct(0); /* %MEM */
}
}
/*
* Returns true iff string is all numeric.
*/
static int
num(char *s)
{
int c;
if (s == NULL)
return (0);
c = *s;
do {
if (!isdigit(c))
return (0);
} while ((c = *++s) != '\0');
return (1);
}
/*
* Function to compute the number of printable bytes in a multibyte
* command string ("internationalization").
*/
static int
{
while (*cmd != '\0') {
return (8); /* default to use for illegal chars */
return (8);
break;
}
return (eucwcnt);
}
static int
{
int i;
if (uflg)
else if (vflg)
else
if (i == 0)
return (i);
}
static char *
{
return (str);
}