|
Home > Archive > Unix Programming > February 2005 > Retrieving Parent process ID of any arbitrary process.
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Retrieving Parent process ID of any arbitrary process.
|
|
| sreenidishc@gmail.com 2005-02-16, 5:57 pm |
| Does there exist any system call/library function to retrieve the
parent process id of any given arbitrary process from an unrelated
process in UNIX?
Currently I am doing the same with ps -p PID -o PPID. However -o option
does not work in HP-UX. Also, we would like to avoid using commands in
the code.
Otherwise, if there is no direct system call/library function
supporting this, could anybody suggest an elegant way to
programmatically access this information?
I searched FAQs for an answer to this question. If the question is
primitive for this group, I apologize.
Thanks in advance.
Sreenidish C
| |
| Michael Kerrisk 2005-02-16, 5:57 pm |
| On 16 Feb 2005 09:37:02 -0800, sreenidishc@gmail.com wrote:
Hello Sreenidish,
>Does there exist any system call/library function to retrieve the
>parent process id of any given arbitrary process from an unrelated
>process in UNIX?
There is no standard API to do this.
>Currently I am doing the same with ps -p PID -o PPID. However -o option
>does not work in HP-UX. Also, we would like to avoid using commands in
>the code.
>Otherwise, if there is no direct system call/library function
>supporting this, could anybody suggest an elegant way to
>programmatically access this information?
The usual way of doing this is what you are doing. An alternative on
some systems is to parse the contents of an appropriate
(implementation-specific) /proc file (e.g., /proc/PID/status on
Linux), but this is even less portable.
Cheers,
Michael
| |
| Dan Mercer 2005-02-16, 5:57 pm |
|
<sreenidishc@gmail.com> wrote in message news:1108575422.251209.314720@l41g2000cwc.googlegroups.com...
: Does there exist any system call/library function to retrieve the
: parent process id of any given arbitrary process from an unrelated
: process in UNIX?
: Currently I am doing the same with ps -p PID -o PPID. However -o option
: does not work in HP-UX. Also, we would like to avoid using commands in
: the code.
To get XPG4 functionality in HP-UX you must set UNIX95
$ UNIX95=1 ps -p PID -o PPID=
HP-UX has the pstat system functions. The following may be of some help.
Note, I haven't compiled it for over two years.
Dan Mercer
=========================== pstat.shar ===========================
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Dan Mercer <dam@limswks7> on Fri Jul 5 12:14:51 2002
#
# This archive contains:
# README pstat.c getusertable.c getproctable.c
# gettime.c pwinfo.h pstat.man makefile
#
LANG=""; export LANG
PATH=/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH; export PATH
EXIT_STATUS=0
echo x - README
cat >README <<'@EOF'
WARRANTY DISCLAIMER and LICENSE
This code is provided AS IS - no warranty specified or implied.
Use at you own risk, expecially if you decide to kill processes
as root with it. I personally have never screwed it up, but
that's me. You are free to use it for your own purposes, just don't
try to sell it back to me.
--
Dan Mercer
dmercer@mn.rr.com
@EOF
chmod 644 README
echo x - pstat.c
cat >pstat.c <<'@EOF'
/ ****************************************
***********************
*
* Copyright (C) 1992-2002, by Dan Mercer. All rights reserved.
*
* Program Name : $Source: /home/dam/News/pstat/RCS/pstat.c,v $
* Version : $Revision: 1.50 $
* Date Created : Tue Nov 15 15:37:12 CST 1994
* Author : Dan A. Mercer
* Last Modified : $Date: 2002/06/14 15:37:14 $
* Modified By : $Author: dam $
* Description : Interface to the pstat system calls
****************************************
***********************/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <signal.h>
#include <glob.h>
#include <pwd.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/pstat.h>
#include <sys/utsname.h>
#include <sys/param.h>
#define True (1==1)
#define False (1==0)
#define MXCLU "%s: Option error - -U and -u are mutually exclusive\n"
#define NOSIG "%s: -y option only valid with -k option\n"
#define NOTTY "%s: -k option not valid without tty or -y option\n"
#define NOGLOB "%s: -g option passed but no pattern supplied\n"
#define IORGOPT "%s: -g option & -i option are incompatible\n"
#define SORFOPT "%s: -s option & -f option are incompatible\n"
#define SORTOPT "%s: invalid -S option [cdgkpurstxzCDKPUXZ]\n"
#define UIDNUM "uid_list %s contains non-numeric entries\n"
#define BADUSERID "userid %s not found\n"
#define NUMCM "0123456789,"
#define ALLNUM "0123456789"
#define BADNUM "%s: invalid -%c option %s - must be numeric\n"
#define SIGMAX (sizeof sig1table/sizeof (int))
#define PSTAT_FORMAT "PSTAT_FORMAT"
#define DEF_FMT "%5p %S %C"
#define OPTCHRS ":dghioqrsyc:f:k:p:P:S:t:u:U:z:Z:"
#define SORTCHRS "cdgkpurstxzCDKPUXZ"
#define FMTCHRS "%dDkKxXzZpPgCcnrsStTuU0123456789"
#define SFMTCHRS "%uuuuuuuudddssnussussdssssssssss"
#define FMT_RE "^%([-]*[0-9]*[.]*[0-9]*[0-9cdgkprtuxzCDKPUXZ]|[%nsST])"
#define USERID_RE "%[-]*[0-9]*[.]*[0-9]*u"
#define ORDER_RE1 "^([mno]|matches|newer|older)="
#define FMTDT "%m/%d"
#define FMTTM "%H:%M"
#define FMTDTORTML 6
#define FMTDTTM "%D %T"
#define FMTDTTML 19
#define FMT_TM "%T"
#define FMT_TML 10
#define NOT_MODIFIER '!'
#define NOT_CMD (1<<0)
#define NOT_PID (1<<1)
#define NOT_PPID (1<<2)
#define NOT_UID (1<<3)
#define M24_HRS (24*60*60)
#define OLDER_THAN 1
#define NEWER_THAN -1
#define MATCHES 0
#ifndef MINROOTKILL
# define MINROOTKILL 200
#endif
char *argname;
char *sortfields;
char **userids;
extern time_t gettime();
struct pst_status *getproctable(/* int *countPointer, int *MaxProcPtr */);
char *ck_notflag(opt_ptr,flag,setting)
char *opt_ptr;
int *flag;
int setting;
{
if (NOT_MODIFIER == *opt_ptr)
{
*flag |= setting;
return opt_ptr + 1;
}
else
return opt_ptr;
}
void help(msg)
char *msg;
{
char *help_msg;
char *t; /* name of function */
int l; /* length of t */
FILE *pp;
char *lines_str;
char *pager;
int lines;
t = argname;
l = strlen(t);
pp = NULL;
help_msg = (!msg || !strlen(msg)) ? "" : msg;
#define PSTAT_MAINHELP_SZ 29
lines = (lines_str = getenv("LINES")) ? atoi(lines_str) : 24;
if (lines < PSTAT_MAINHELP_SZ)
{
pager = (pager = getenv("PAGER")) ? pager : "page";
if (NULL == (pp = popen(pager,"w")))
perror("Unable to open pager");
}
fprintf((pp) ? pp : stderr,
"%s\n"
"%s -[hdgioqrsy] [-c cmdlist] [-e timeval] [-f format] [-k sig]\n"
"%*s [-p pidlist] [-P ppidlist] [-u useridlist] [-U uidlist]\n"
"%*s [-S sortfields] [-z cpu] [-Z secs] [pattern]\n"
"Options:\n"
" -h this message.\n"
" -d show defunct processes.\n"
" -g use globbing on pattern.\n"
" -i ignore case on -c pattern matching.\n"
" -q quiet mode - return count of matches.\n"
" -o OR search criteria options instead of AND.\n"
" -r reverse order of sort.\n"
" -s output info as ksh arrays.\n"
" -y no prompt on kill.\n"
" -c cmdlist comma separated glob list of one or more cmds.\n"
" -f format used to control output format. (-f? for help)\n"
" -k signal kill using signal signal\n"
" -p pidlist comma separated list of one or more pids.\n"
" -P ppidlist comma separated list of one or more ppids.\n"
" -S sortfields sort using sortfields (-S? for help).\n"
" -u useridlist comma separated list of one or more userids.\n"
" -t time_expr match processes by time_expr. (-t? for help)\n"
" -U uidlist comma separated list of one or more uids.\n"
" -z cpu match processes exceeding cpu utilization.\n"
" -Z secs match processes exceeding secs cum time.\n"
" pattern an re or glob string to match against the\n"
" command string. (See -g option).\n"
" ! not modifier (e.g -p!2121)\n",
help_msg, t,l," ",l," ",t,l," ");
if (pp)
pclose(pp);
exit(0);
}
void helpformat()
{
FILE *pp;
char *lines_str;
char *pager;
int lines;
pp = NULL;
#define PSTAT_FMTHELP_SZ 25
lines = (lines_str = getenv("LINES")) ? atoi(lines_str) : 24;
if (lines < PSTAT_FMTHELP_SZ)
{
pager = (pager = getenv("PAGER")) ? pager : "page";
if (NULL == (pp = popen(pager,"w")))
perror("Unable to open pager");
}
fprintf((pp) ? pp : stderr,
"Formats:\n"
" %%[precision]0.. output command's argv[0...\n"
" %%[precision]p pid diplayed in integer precision\n"
" %%[precision]P ppid diplayed in integer precision\n"
" %%[precision]g process group id in integer precision\n"
" %%[precision]U uid diplayed in integer precision\n"
" %%[precision]C command string\n"
" %%[precision]c command name\n"
" %%n insert newline\n"
" %%[precision]r processor utilization for scheduling\n"
" %%s start time [MM/DD/YY hh:mm:ss]\n"
" %%S start time [MM/DD or hh:mm] - MM/DD used\n"
" if started more than 24 hrs ago\n"
" %%[precision]t cumulative time in seconds\n"
" %%T cumulative time in hh:mm:ss\n"
" %%[precision]u userid\n"
" %%[precision]d real pages used for data\n"
" %%[precision]x real pages used for text\n"
" %%[precision]k real pages used for stack\n"
" %%[precision]z real size\n"
" %%[precision]D virtual pages used for text\n"
" %%[precision]X virtual pages used for data\n"
" %%[precision]K virtual pages used for stack\n"
" %%[precision]Z virtual size\n"
);
if (pp)
pclose(pp);
exit(0);
}
void helpsort()
{
FILE *pp;
char *lines_str;
char *pager;
int lines;
pp = NULL;
#define PSTAT_SRTHELP_SZ 22
lines = (lines_str = getenv("LINES")) ? atoi(lines_str) : 24;
if (lines < PSTAT_SRTHELP_SZ)
{
pager = (pager = getenv("PAGER")) ? pager : "page";
if (NULL == (pp = popen(pager,"w")))
perror("Unable to open pager");
}
fprintf((pp) ? pp : stderr,
"Process information is sorted in the order the following\n"
"characters appear in the sortfield:\n"
" c sort alphabetically by command name\n"
" C sort alphabetically by command string\n"
" d sort numerically by real pages used for data\n"
" D sort numerically by virtual pages used for data\n"
" g sort numerically by process group id\n"
" k sort numerically by real pages used for stack\n"
" K sort numerically by virtual pages used for stack\n"
" p sort numerically by process id\n"
" P sort numerically by parent process id\n"
" r sort numerically by processor utilization\n"
" s sort numerically by start time\n"
" t sort numerically by cumulative time\n"
" u sort alphabetically by userid\n"
" U sort numerically by uid\n"
" x sort numerically by real pages used for text\n"
" X sort numerically by virtual pages used for text\n"
" z sort numerically by process real size\n"
" Z sort numerically by process virtual size\n"
);
if (pp)
pclose(pp);
exit(0);
}
void helptime(msg)
char *msg;
{
char *help_msg;
help_msg = (!msg || !strlen(msg)) ? "" : msg;
fprintf(stderr,
"%s"
"A time_expr expression is of the form modifier=timeval where\n"
"modifier is one of:\n\n"
" m[atches] match processes running on the day meeting\n"
" the time criteria\n"
" n[ewer] match processes starting since timeval\n"
" o[older] match processes starting before timeval\n\n"
"and where timeval can be an explicit date/time in\n"
"HH:MM:SS MM/DD/YY format or a special keyword or arithmetic\n"
"expression (see man pstat(1)):\n\n"
" now the current time\n"
" 1 week ago now - 1 week\n"
" today today at 00:00:00\n"
" yesterday yesterday at 00:00:00\n"
" yesterday 12 yesterday noon\n",
help_msg);
exit(0);
}
char *sec2dttm(seconds)
long seconds;
{
char *buf;
buf = calloc(1,FMTDTTML);
strftime(buf,FMTDTTML,FMTDTTM,localtime(
&seconds));
return buf;
}
char *sec2dtortm(seconds)
long seconds;
{
char *buf;
static long now=0;
long elapsed;
if (!now) time(&now);
elapsed = now - seconds;
buf = calloc(1,FMTDTORTML);
strftime(buf,
FMTDTORTML,
(elapsed >= M24_HRS) ? FMTDT : FMTTM,
localtime(&seconds));
return buf;
}
char *sec2tm(seconds)
long seconds;
{
char *buf;
buf = calloc(1,FMT_TML);
strftime(buf,FMT_TML,FMT_TM,gmtime(&seconds));
return buf;
}
void shellprint(ps,psct,maxproc,maxuserid)
struct pst_status **ps;
int psct;
int maxproc;
int maxuserid;
{
int i;
int pidl;
int uidl;
char *pidbuf,*p;
char *Ppidbuf,*P;
char *Pgidbuf,*G;
char *Uidbuf,*U;
char *useridbuf,*u;
char *cpu_buf,*r;
char *cmd_buf,*c;
char *Comm_buf,*C;
char *sbuf,*s;
char *tbuf,*t;
char *Tbuf,*T;
char *txtbuf,*x;
char *vtxtbuf,*X;
char *datbuf,*d;
char *vdatbuf,*D;
char *stkbuf,*k;
char *vstkbuf,*K;
char *szbuf,*z;
char *vszbuf,*Z;
char *timebuf;
struct passwd *pwd;
/* compute length of pid, ppid, and uid fields */
for (i=maxproc,pidl=1;i;i/=10,pidl++); pidl++;
for (i=maxuserid,uidl=1;i;i/=10,uidl++); uidl++;
pidbuf = p = (char *) calloc(1,(psct * pidl) + 1);
Ppidbuf = P = (char *) calloc(1,(psct * pidl) + 1);
Pgidbuf = G = (char *) calloc(1,(psct * pidl) + 1);
Uidbuf = U = (char *) calloc(1,(psct * uidl) + 1);
cpu_buf = r = (char *) calloc(1,(psct * 11) + 1);
cmd_buf = c = (char *) calloc(1,(psct * (PST_CLEN + 3)) + 1);
Comm_buf = C = (char *) calloc(1,(psct * (PST_UCOMMLEN + 1)) + 1);
useridbuf = u = (char *) calloc(1,(psct * UTSLEN) + 1);
sbuf = s = (char *) calloc(1,(psct * (FMTDTTML + 2)) + 1);
tbuf = t = (char *) calloc(1,(psct * 11) + 1);
Tbuf = T = (char *) calloc(1,(psct * FMT_TML) + 1);
txtbuf = x = (char *) calloc(1,(psct * 8) + 1);
vtxtbuf = X = (char *) calloc(1,(psct * 8) + 1);
datbuf = d = (char *) calloc(1,(psct * 8) + 1);
vdatbuf = D = (char *) calloc(1,(psct * 8) + 1);
stkbuf = k = (char *) calloc(1,(psct * 8) + 1);
vstkbuf = K = (char *) calloc(1,(psct * 8) + 1);
szbuf = z = (char *) calloc(1,(psct * 8) + 1);
vszbuf = Z = (char *) calloc(1,(psct * 8) + 1);
for (i=0;i<psct;i++)
{
p += sprintf(p," %d", ps[i]->pst_pid);
P += sprintf(P," %d", ps[i]->pst_ppid);
G += sprintf(G," %d", ps[i]->pst_pgrp);
U += sprintf(U," %d", ps[i]->pst_uid);
r += sprintf(r," %u", ps[i]->pst_cpu);
c += sprintf(c," '%s'",ps[i]->pst_cmd);
C += sprintf(C," %s", ps[i]->pst_ucomm);
x += sprintf(x," %u", ps[i]->pst_tsize);
X += sprintf(X," %u", ps[i]->pst_vtsize);
d += sprintf(d," %u", ps[i]->pst_dsize);
D += sprintf(D," %u", ps[i]->pst_vdsize);
k += sprintf(k," %u", ps[i]->pst_ssize);
K += sprintf(K," %u", ps[i]->pst_vssize);
z += sprintf(z," %u",
(ps[i]->pst_dsize + ps[i]->pst_ssize + ps[i]->pst_tsize));
Z += sprintf(Z," %u",
(ps[i]->pst_vdsize + ps[i]->pst_vssize + ps[i]->pst_vtsize));
t += sprintf(t," %u",ps[i]->pst_utime+ps[i]->pst_stime);
if (NULL == userids[ps[i]->pst_uid])
{
if (NULL == (pwd = getpwuid(ps[i]->pst_uid)))
{
userids[ps[i]->pst_uid] = calloc(1,16);
sprintf(userids[ps[i]->pst_uid],"%d",ps[i]->pst_uid);
}
else
{
userids[ps[i]->pst_uid] = strdup(pwd->pw_name);
}
}
u += sprintf(u," %s",userids[ps[i]->pst_uid]);
timebuf = sec2dttm(ps[i]->pst_start);
s += sprintf(s," '%s'",timebuf);
free(timebuf);
timebuf = sec2tm(ps[i]->pst_utime+ps[i]->pst_stime);
T += sprintf(T," %s",timebuf);
free(timebuf);
}
printf ("typeset -i PSCT=%d;\n", psct);
printf ("set -A PID%s;\n", pidbuf);
printf ("set -A PPID%s;\n", Ppidbuf);
printf ("set -A PGID%s;\n", Pgidbuf);
printf ("set -A UID%s;\n", Uidbuf);
printf ("set -A USERID%s;\n", useridbuf);
printf ("set -A CPU%s;\n", cpu_buf);
printf ("set -A START%s;\n", sbuf);
printf ("set -A SYSTIMES%s;\n", tbuf);
printf ("set -A SYSTIMEF%s;\n", Tbuf);
printf ("set -A CMDS%s;\n", cmd_buf);
printf ("set -A UCOMM%s;\n", Comm_buf);
printf ("set -A DSIZE%s;\n", datbuf);
printf ("set -A VDSIZE%s;\n", vdatbuf);
printf ("set -A SSIZE%s;\n", stkbuf);
printf ("set -A VSSIZE%s;\n", vstkbuf);
printf ("set -A TSIZE%s;\n", txtbuf);
printf ("set -A VTSIZE%s;\n", vtxtbuf);
printf ("set -A SZSIZE%s;\n", szbuf);
printf ("set -A VSZSIZE%s;\n", vszbuf);
}
int pid_sort(elem1,elem2)
void *elem1;
void *elem2;
{
int *p1,*p2;
p1 = elem1;
p2 = elem2;
return(*p1 - *p2);
}
int psSort(elem1,elem2)
void *elem1;
void *elem2;
{
struct pst_status *ps1;
struct pst_status *ps2;
struct passwd *pwd;
char *q;
int rc;
ps1 = *(struct pst_status **)elem1;
ps2 = *(struct pst_status **)elem2;
for (rc=0,q=sortfields;*q && (0==rc);q++)
{
switch (*q)
{
case 'c' :
rc = strncmp(ps1->pst_ucomm, ps2->pst_ucomm,MAXCOMLEN);
break;
case 'C' :
rc = strcmp(ps1->pst_cmd, ps2->pst_cmd);
break;
case 'd' :
rc = ps1->pst_dsize - ps2->pst_dsize;
break;
case 'D' :
rc = ps1->pst_vdsize - ps2->pst_vdsize;
break;
case 'g' :
rc = ps1->pst_pgrp - ps2->pst_pgrp;
break;
case 'k' :
rc = ps1->pst_ssize - ps2->pst_ssize;
break;
case 'K' :
rc = ps1->pst_vssize - ps2->pst_vssize;
break;
case 'p' :
rc = ps1->pst_pid - ps2->pst_pid;
break;
case 'r' :
rc = ps1->pst_cpu - ps2->pst_cpu;
break;
case 'u' :
if (NULL == userids[ps1->pst_uid])
{
if (NULL == (pwd = getpwuid(ps1->pst_uid)))
{
userids[ps1->pst_uid] = calloc(1,16);
sprintf(userids[ps1->pst_uid],"%d",ps1->pst_uid);
}
else
{
userids[ps1->pst_uid] = strdup(pwd->pw_name);
}
}
if (NULL == userids[ps2->pst_uid])
{
if (NULL == (pwd = getpwuid(ps2->pst_uid)))
{
userids[ps2->pst_uid] = calloc(1,16);
sprintf(userids[ps2->pst_uid],"%d",ps2->pst_uid);
}
else
{
userids[ps2->pst_uid] = strdup(pwd->pw_name);
}
}
rc = strcmp(userids[ps1->pst_uid],userids[ps2->pst_uid]);
break;
case 't' :
rc = (ps1->pst_stime + ps1->pst_utime) -
(ps2->pst_stime + ps2->pst_utime);
break;
case 's' :
rc = ps1->pst_start - ps2->pst_start;
break;
case 'P' :
rc = ps1->pst_ppid - ps2->pst_ppid;
break;
case 'U' :
rc = ps1->pst_uid - ps2->pst_uid;
break;
case 'x' :
rc = ps1->pst_tsize - ps2->pst_tsize;
break;
case 'X' :
rc = ps1->pst_vtsize - ps2->pst_vtsize;
break;
case 'z' :
rc = (ps1->pst_dsize + ps1->pst_ssize + ps1->pst_tsize) -
(ps2->pst_dsize + ps2->pst_ssize + ps2->pst_tsize);
break;
case 'Z' :
rc = (ps1->pst_vdsize + ps1->pst_vssize + ps1->pst_vtsize) -
(ps2->pst_vdsize + ps2->pst_vssize + ps2->pst_vtsize);
break;
}
}
return(rc);
}
int ok2kill(entry)
struct pst_status *entry;
{
int c;
printf("\n%5d %-14.14s %s\n Kill it? [y/n] ==> ",
entry->pst_pid, entry->pst_ucomm,entry->pst_cmd);
while (c = getchar())
{
switch (c)
{
case 'N' :
case 'n' :
while ('\n' != getchar());
case '\n' :
return 0;
break;
case 'Y' :
case 'y' :
while ('\n' != getchar());
return 1;
break;
default :
while ('\n' != getchar());
printf("\007 Kill it? [y/n] ==> ");
break;
}
}
}
void reset_tables(ps,marktablep,psctp)
struct pst_status **ps;
int **marktablep;
int *psctp;
{
int *m;
int i,j;
/* then rebuild ps and marktable */
for (i=0,j=0,m=*marktablep;i<*psctp;i++)
{
if (m[i])
{
if (j != i)
ps[j] = ps[i];
j++;
}
}
*psctp = j;
if (m) free((void *) m);
*marktablep = calloc(j,sizeof (int));
}
char **string_to_array(str,tokens,ct)
char *str;
char *tokens;
int *ct;
{
char **ar;
char **q;
char *tmp;
char i;
char *t,*p;
int arcount;
int recount;
if (NULL == (tmp = strdup(str)))
{
*ct = 0;
return NULL;
}
arcount = strlen(str)/2;
if (NULL == (ar = (char**) calloc(arcount,sizeof (char *))))
{
perror("string_to_array: Can't calloc array");
return NULL;
}
/* mind your p's and q's */
for (t=tmp,q=ar,*ct=0;p=strtok(t,tokens);t=N
ULL,q++,(*ct)++)
*q = strdup(p);
*q = NULL;
recount = *ct + 1;
if (arcount > recount)
ar = realloc(ar,recount * sizeof (char *));
free(tmp);
return(ar);
}
int psformat(format,entry)
char *format;
struct pst_status *entry;
{
static char *fmts[sizeof FMTCHRS + 1];
static char *vformat;
static char *fmtchrs;
static char *sfmtchrs;
static regex_t pregi;
static regex_t *preg = &pregi;
static regmatch_t pm;
struct passwd *pwd;
char rcbuf[256];
char *ptr, *vptr, *fptr, *mptr;
char *timebuf;
int diverting;
int periods;
int i,j;
int rc;
int end_prec;
int fmtx;
int argn;
int argct;
char **args;
if (!entry)
{
fmtchrs = strdup(FMTCHRS);
sfmtchrs = strdup(SFMTCHRS);
rc = regcomp(preg, FMT_RE, REG_EXTENDED);
/* verify and set up format */
vformat = calloc(1,strlen(format) + 1);
for (i=0;i<sizeof FMTCHRS + 1;i++)
fmts[i] = calloc(1,strlen(format) + 1);
for (ptr=format,vptr=vformat;*ptr;)
{
switch (*ptr)
{
case '%' :
*vptr++ = *ptr;
if (rc = regexec(preg,ptr,1,&pm,0))
{
regerror(rc,preg,rcbuf,sizeof rcbuf);
fprintf (stderr,
"Format error: pattern '%s' %s\n", ptr, rcbuf);
return -1;
}
end_prec = pm.rm_eo - 1;
fmtx = strchr(fmtchrs,*(ptr+end_prec)) - fmtchrs;
for (mptr=ptr,fptr=fmts[fmtx],i=0;i<end_prec;i++)
*fptr++ = *mptr++;
*fptr = *(sfmtchrs+fmtx);
*vptr++ = *(ptr+end_prec);
ptr += pm.rm_eo;
break;
default :
*vptr++ = *ptr++;
break;
}
}
}
else
{
for (vptr=vformat;*vptr;)
{
if ('%' == *vptr)
{
fmtx = strchr(fmtchrs,*(vptr+1)) - fmtchrs;
/* #define FMTCHRS "%dDkKxXpPgCcnrsStTuU0123456789" */
switch (*(vptr+1))
{
case '%' :
putchar('%');
break;
case 'n' :
putchar('\n');
break;
case '0' : case '1' : case '2' : case '3' : case '4' :
case '5' : case '6' : case '7' : case '8' : case '9' :
argn = *(vptr+1) - '0';
args = string_to_array(entry->pst_cmd," ",&argct);
if (argn < argct)
printf(fmts[fmtx],args[argn]);
else
printf(fmts[fmtx],"");
for (i=0;i<argct;i++)
free ((void *) args[i]);
free ((void *) args);
break;
case 'c' : /* command */
printf(fmts[fmtx],entry->pst_ucomm);
break;
case 'C' : /* command line */
if (PS_ZOMBIE == entry->pst_stat)
{
char tmpcmd[PST_CLEN + 4];
sprintf(tmpcmd, "[Z]%s",entry->pst_cmd);
printf(fmts[fmtx],tmpcmd);
}
else
printf(fmts[fmtx],entry->pst_cmd);
break;
case 'd' : /* real pages for data */
printf(fmts[fmtx],entry->pst_dsize);
break;
case 'D' : /* virtual pages for data */
printf(fmts[fmtx],entry->pst_vdsize);
break;
case 'g' : /* process group id */
printf(fmts[fmtx],entry->pst_pgrp);
break;
case 'k' : /* real pages for stack */
printf(fmts[fmtx],entry->pst_ssize);
break;
case 'K' : /* virtual pages for stack */
printf(fmts[fmtx],entry->pst_vssize);
break;
case 'p' : /* pid */
printf(fmts[fmtx],entry->pst_pid);
break;
case 'P' : /* parent pid */
printf(fmts[fmtx],entry->pst_ppid);
break;
case 'r' : /* cpu utilization */
printf(fmts[fmtx],entry->pst_cpu);
break;
case 's' : /* formatted start time */
timebuf = sec2dttm(entry->pst_start);
printf(fmts[fmtx],timebuf);
free(timebuf);
break;
case 'S' : /* formatted start time */
timebuf = sec2dtortm(entry->pst_start);
printf(fmts[fmtx],timebuf);
free(timebuf);
break;
case 't' : /* cum time in seconds */
printf(fmts[fmtx],entry->pst_stime + entry->pst_utime);
break;
case 'T' : /* formatted cum time */
timebuf = sec2tm(entry->pst_utime+entry->pst_stime);
printf(fmts[fmtx],timebuf);
free(timebuf);
break;
case 'u' : /* userid */
if (NULL == userids[entry->pst_uid])
{
if (NULL == (pwd = getpwuid(entry->pst_uid)))
{
userids[entry->pst_uid] = calloc(1,16);
sprintf(userids[entry->pst_uid],"%d",entry->pst_uid);
}
else
{
userids[entry->pst_uid] = strdup(pwd->pw_name);
}
}
printf(fmts[fmtx],userids[entry->pst_uid]);
break;
case 'U' : /* uid */
printf(fmts[fmtx],entry->pst_uid);
break;
case 'x' : /* real pages for text */
printf(fmts[fmtx],entry->pst_tsize);
break;
case 'X' : /* virtual pages for text */
printf(fmts[fmtx],entry->pst_vtsize);
break;
case 'z' : /* real size */
printf(fmts[fmtx],
(entry->pst_dsize + entry->pst_ssize + entry->pst_tsize)
);
break;
case 'Z' : /* virtual size */
printf(fmts[fmtx],
(entry->pst_vdsize + entry->pst_vssize + entry->pst_vtsize)
);
break;
default :
break;
}
vptr += 2;
}
else
putchar(*vptr++);
}
putchar('\n');
}
}
main (argc, argv)
int
argc;
char
**argv;
{
/*
*start of main procedure
*/
pid_t my_pid;
uid_t my_uid;
int opt;
extern char *optarg;
extern int optind;
extern int optopt;
char errmsg[256];
int totusers;
int maxuserid;
int *marktable;
struct pst_status *psblob;
struct pst_status **ps;
struct pst_status **rps;
int psct;
int maxproc;
struct tm *tmp;
struct tm *gdate_conv;
char **cmds;
int cmd_ct;
char **pid_list;
int pid_ct;
pid_t *pids;
char **Ppid_list;
int Ppid_ct;
pid_t *Ppids;
char **userid_list;
int userid_ct;
char **uid_list;
int uid_ct;
int *uids;
int i,j;
int ck_cpu;
int cpu_min;
int ck_time;
int tm_min;
int quiet;
int icase;
int orflag;
int yesflag;
int useglobbing;
int reverse;
int shellout;
int sig;
int cpu_base;
int tm_used;
int rc;
int notflag;
int timeflag;
int cols;
int findzombies;
time_t starttime;
time_t endtime;
char rcbuf[256];
char *format;
char *regex;
char *optionp;
char *columns;
char *timeval_string;
char def_fmt[80];
struct passwd *pwd;
static regex_t oregi;
static regex_t *oreg = &oregi;
static regex_t pregi;
static regex_t *preg = &pregi;
static regex_t uregi;
static regex_t *ureg = &uregi;
static char *sig1table[] = {
"sighello", "sighup", "sigint",
"sigquit", "sigill", "sigtrap",
"sigabrt", "sigemt", "sigfpe",
"sigkill", "sigbus", "sigsegv",
"sigsys", "sigpipe", "sigalrm",
"sigterm", "sigusr1", "sigusr2",
"sigchld", "sigpwr", "sigvtalrm",
"sigprof", "sigio", "sigwinch",
"sigstop", "sigtstp", "sigcont",
"sigttin", "sigttou", "sigurg",
"siglost" };
static char *sig2table[] = {
"hello", "hup", "int",
"quit", "ill", "trap",
"abrt", "emt", "fpe",
"kill", "bus", "segv",
"sys", "pipe", "alrm",
"term", "usr1", "usr2",
"chld", "pwr", "vtalrm",
"prof", "io", "winch",
"stop", "tstp", "cont",
"ttin", "ttou", "urg",
"lost" };
/* save executable name so it is globally available
*/
argname = strrchr(argv[0],'/');
argname = (argname) ? argname + 1 : argv[0];
quiet = False;
userid_ct = False;
uid_ct = False;
icase = False;
orflag = False;
yesflag = False;
useglobbing = False;
shellout = False;
reverse = False;
ck_cpu = False;
ck_time = False;
findzombies = False;
sig = -1;
notflag = 0;
maxuserid = 0;
starttime = 0;
endtime = 0;
while ((opt = getopt(argc, argv, OPTCHRS)) != EOF)
{
if ('-' == *optarg)
{
sprintf(errmsg,"%s: Option -%c requires an argument\n",
argname, optopt);
help(errmsg);
}
switch (opt)
{
case 'd' :
findzombies = True;
break;
case 'g' :
if (icase)
{
fprintf(stderr, IORGOPT,argname);
exit(1);
}
useglobbing = True;
break;
case 'h' :
help("");
break;
case 'i' :
if (useglobbing)
{
fprintf(stderr, IORGOPT,argname);
exit(1);
}
icase = REG_ICASE;
break;
case 'o' :
orflag = True;
break;
case 'q' :
quiet = True;
break;
case 'r' :
reverse = True;
break;
case 's' :
if (format)
{
fprintf(stderr, SORFOPT,argname);
exit(1);
}
shellout = True;
break;
case 'y' :
yesflag = True;
break;
case 'c' :
optionp = ck_notflag(optarg,¬flag,NOT_CMD);
cmds = string_to_array(optionp,",",&cmd_ct);
break;
case 'f' :
if (shellout)
{
fprintf(stderr, SORFOPT,argname);
exit(1);
}
if ('?' == *optarg)
helpformat();
format = strdup(optarg);
break;
case 'k' :
if (strlen(optarg) == strspn(optarg,ALLNUM))
{
sig = atoi(optarg);
if (sig >= SIGMAX)
{
fprintf (stderr,
"Signal %s exceeds limit %d\n",
optarg, SIGMAX - 1);
exit(1);
}
}
else
{
for (sig=0;sig<SIGMAX&&strcasecmp(optarg,sig1table[sig]);sig++);
if (sig == SIGMAX)
for (sig=0;sig<SIGMAX&&strcasecmp(optarg,sig2table[sig]);sig++);
if (sig == SIGMAX)
{
fprintf (stderr,"Signal %s could not be translated\n", optarg);
exit(1);
}
}
break;
case 'p' :
optionp = ck_notflag(optarg,¬flag,NOT_PID);
if (strlen(optionp) != strspn(optionp,NUMCM))
{
fprintf(stderr,
"pidlist %s contains non-numeric entries\n",optarg);
exit(1);
}
pid_list = string_to_array(optionp,",",&pid_ct);
/* convert pid_list to pids table */
if (pid_ct)
{
pids = calloc(pid_ct,sizeof (int));
for (i=0;i<pid_ct;i++)
pids[i] = atoi(pid_list[i]);
/* sort em */
qsort((void *) pids,pid_ct,sizeof (int),pid_sort);
}
break;
case 'P' :
optionp = ck_notflag(optarg,¬flag,NOT_PPID);
if (strlen(optionp) != strspn(optionp,NUMCM))
{
fprintf(stderr,
"Ppid_list %s contains non-numeric entries\n",optarg);
exit(1);
}
Ppid_list = string_to_array(optionp,",",&Ppid_ct);
/* convert Ppid_list to Ppids table */
if (Ppid_ct)
{
Ppids = calloc(Ppid_ct,sizeof (int));
for (i=0;i<Ppid_ct;i++)
Ppids[i] = atoi(Ppid_list[i]);
}
break;
case 'S' :
if ('?' == *optarg)
helpsort();
if (strlen(optarg) != strspn(optarg,SORTCHRS))
{
fprintf(stderr, SORTOPT, optarg);
exit(1);
}
sortfields = strdup(optarg);
break;
case 't' :
if ('?' == *optarg)
helptime("");
if ((rc = regcomp(oreg, ORDER_RE1, REG_EXTENDED)) != 0)
{
regerror(rc,oreg,rcbuf,sizeof rcbuf);
fprintf (stderr,"%s RE error: %s\n", argname, rcbuf);
exit(1);
}
if (regexec(oreg,optarg,0,NULL,0))
helptime("Missing time modifier\n");
if ((starttime = gettime(strchr(optarg,'=') + 1)) < 0)
helptime("Invalid DATE/TIME specificaton\n");
switch (*optarg)
{
case 'n' :
timeflag=NEWER_THAN;
break;
case 'm' :
timeflag=MATCHES;
break;
case 'o' :
timeflag=OLDER_THAN;
break;
}
break;
case 'u' :
if (uid_ct)
{
fprintf(stderr,MXCLU, argname);
exit(1);
}
optionp = ck_notflag(optarg,¬flag,NOT_UID);
userid_list = string_to_array(optionp,",",&userid_ct);
break;
case 'U' :
if (userid_ct)
{
fprintf(stderr,MXCLU, argname);
exit(1);
}
optionp = ck_notflag(optarg,¬flag,NOT_UID);
if (strlen(optionp) != strspn(optionp,NUMCM))
{
fprintf(stderr, UIDNUM, optarg);
exit(1);
}
uid_list = string_to_array(optionp,",",&uid_ct);
/* convert uid_list to uids table */
if (uid_ct)
{
uids = calloc(uid_ct,sizeof (int));
for (i=0;i<uid_ct;i++)
uids[i] = atoi(uid_list[i]);
}
break;
case 'z' :
if (strlen(optarg) == strspn(optarg,ALLNUM))
{
ck_cpu = True;
cpu_min = atoi(optarg);
}
else
{
fprintf(stderr, BADNUM, argname,opt,optarg);
exit(2);
}
break;
case 'Z' :
if (strlen(optarg) == strspn(optarg,ALLNUM))
{
ck_time = True;
tm_min = atoi(optarg);
}
else
{
fprintf(stderr, BADNUM, argname,opt,optarg);
exit(2);
}
break;
case ':' :
sprintf(errmsg,"%s: Option -%c requires an argument\n",
argname, optopt);
help(errmsg);
break;
case '?' :
sprintf(errmsg,"%s: Unrecognized option: -%c\n",
argname, optopt);
help(errmsg);
break;
}
}
switch(argc - optind)
{
case 0 :
if ((cmd_ct+pid_ct+Ppid_ct+userid_ct+uid_ct
) > 0)
{
regex = NULL;
break;
}
else if (useglobbing || icase)
{
fprintf(stderr, NOGLOB, argname);
exit(1);
break;
}
else
regex = strdup(".");
case 1 :
regex = strdup(argv[optind]);
if (!useglobbing)
{
if ((rc = regcomp(preg, regex, REG_EXTENDED|icase)) != 0)
{
regerror(rc,preg,rcbuf,sizeof rcbuf);
fprintf (stderr,"%s RE error: %s\n", argname, rcbuf);
exit(1);
}
}
break;
default :
fprintf(stderr,"%s: Argument error - only 1 regular expression "
"may be supplied\n", argname);
exit(1);
break;
}
my_uid = getuid();
if (yesflag)
{
if (-1 ==sig)
{
fprintf(stderr, NOSIG, argname);
exit(1);
}
}
else
{
if (sig > -1)
{
if (!(isatty(0) & isatty(1) & isatty(2)))
{
fprintf(stderr, NOTTY, argname);
exit(1);
}
}
}
/* set default format */
if (!(quiet | shellout) && (NULL == format))
{
if (NULL == (format = getenv(PSTAT_FORMAT)))
{
format = def_fmt;
cols = (columns = getenv("COLUMNS")) ? atoi(columns) : 80;
sprintf(format,"%%-8u %%5p %%S %%-.%dC", cols - 22);
}
}
/* pre compile output formats */
if (shellout || sig > -1);else
if (psformat(format,NULL) < 0) /* psformat will send errors */
exit(1);
/* get process table */
if (NULL == (psblob = getproctable(&psct,&maxproc)))
exit(1);
/*
* build and initialize tables
* build ps array from psblob because sorting pointers is faster
* than sorting structures - shuffling 4 bytes instead of 400
*/
ps = (struct pst_status **) calloc(psct,sizeof (struct pst_status *));
for (i=0;i<psct;i++)
{
ps[i] = &psblob[i];
maxuserid = (maxuserid > ps[i]->pst_uid) ? maxuserid : ps[i]->pst_uid;
}
marktable = (int *) calloc(psct,sizeof (int));
regcomp(ureg, USERID_RE, REG_EXTENDED);
if (shellout || !regexec(ureg,format,0,NULL,0) || userid_ct ||
(sortfields && strchr(sortfields,'u')))
{
/* build userids cross reference */
if (NULL == (userids = (char **) calloc(maxuserid+1,sizeof (char *))))
{
perror("Can't allocate userid table");
exit(2);
}
}
/* convert useridlist to uids table */
if (userid_ct)
{
struct _pw_table_ { int uid; char *pw_name; } *pw_table;
int maxuid;
maxuid = maxuserid;
uids = calloc(userid_ct,sizeof (int));
pw_table = (struct _pw_table_ *) calloc(userid_ct,
sizeof (struct _pw_table_));
for (uid_ct=0;uid_ct<userid_ct;uid_ct++)
{
if (NULL == (pwd = getpwnam(userid_list[uid_ct])))
{
fprintf(stderr,BADUSERID,userid_list[uid_ct]);
exit(2);
}
uids[uid_ct] = pwd->pw_uid;
maxuid = (pwd->pw_uid > maxuid) ? pwd->pw_uid : maxuid;
pw_table[uid_ct].pw_name = strdup(pwd->pw_name);
pw_table[uid_ct].uid = pwd->pw_uid;
}
if (maxuid > maxuserid)
{
maxuserid = maxuid;
userids = (char **) realloc(userids,(maxuserid+1)*sizeof (char *));
if (NULL == userids)
{
perror("Can't allocate userid table");
exit(2);
}
}
for (uid_ct=0;uid_ct<userid_ct;uid_ct++)
userids[pwd->pw_uid] = pw_table[uid_ct].pw_name;
free (pw_table);
}
/* Now we run through the process listing multiple times and mark
* matching files. If the orflag is set, we check all entries
* if not, we only check the file if the marktable is marked
* We start with pids because both tables are sorted by pid
*/
if (pid_ct)
{
for (i=0,j=0;i<pid_ct;i++)
{
for (;j < psct && (ps[j]->pst_pid < pids[i]);j++);
if (j == psct) /* since this is the smallest pid, none should match */
break;
if (ps[j]->pst_pid == pids[i])
marktable[j] = 1;
}
if (notflag & NOT_PID)
for (i=0;i<psct;i++)
marktable[i] ^= 1;
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (Ppid_ct)
{
/* while process is is unique, ppid is not */
for (i=0;i<Ppid_ct;i++)
{
for (j=0;j < psct;j++)
if (ps[j]->pst_ppid == Ppids[i]) /* match */
marktable[j] = 1;
}
if (notflag & NOT_PPID)
for (i=0;i<psct;i++)
marktable[i] ^= 1;
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (uid_ct)
{
/* while process is is unique, uid is not */
for (i=0;i<uid_ct;i++)
{
for (j=0;j < psct;j++)
if (ps[j]->pst_uid == uids[i]) /* match */
marktable[j] = 1;
}
if (notflag & NOT_UID)
for (i=0;i<psct;i++)
marktable[i] ^= 1;
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (findzombies)
{
for (i=0;i<psct;i++)
{
if (PS_ZOMBIE == ps[i]->pst_stat) /* match */
marktable[i] = 1;
}
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (ck_cpu)
{
for (i=0;i<psct;i++)
{
if (ps[i]->pst_cpu > cpu_min) /* match */
marktable[i] = 1;
}
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (ck_time)
{
for (i=0;i<psct;i++)
{
if ((ps[i]->pst_stime + ps[i]->pst_utime) > tm_min) /* match */
marktable[i] = 1;
}
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (starttime)
{
switch (timeflag)
{
/*
* default setup is correct for newer than
case NEWER_THAN :
break;
*/
case OLDER_THAN :
endtime = starttime;
starttime = 0;
break;
case MATCHES :
gdate_conv = localtime(&starttime);
gdate_conv->tm_sec = 0;
gdate_conv->tm_min = 0;
gdate_conv->tm_hour = 0;
starttime = mktime(gdate_conv);
gdate_conv->tm_sec = 59;
gdate_conv->tm_min = 59;
gdate_conv->tm_hour = 23;
endtime = mktime(gdate_conv);
break;
}
for (i=0;i<psct;i++)
{
if (starttime)
{
if (ps[i]->pst_start >= starttime)
{
if (endtime)
marktable[i] = (ps[i]->pst_start <= endtime) ? 1 : 0;
else
marktable[i] = 1;
}
else
marktable[i] = 0;
}
else
marktable[i] = (ps[i]->pst_start <= endtime) ? 1 : 0;
}
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (cmd_ct)
{
for (i=0;i<cmd_ct;i++)
{
for (j=0;j < psct;j++)
{
char ucomm[PST_UCOMMLEN];
strncpy(ucomm,cmds[i],MAXCOMLEN);
if (!fnmatch(ucomm,ps[j]->pst_ucomm,0))
marktable[j] = 1;
}
}
if (notflag & NOT_CMD)
for (i=0;i<psct;i++)
marktable[i] ^= 1;
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
if (regex)
{
for (i=0;i<psct;i++)
{
if ((useglobbing) ?
(!fnmatch(regex,ps[i]->pst_cmd,0)) :
(!regexec(preg,ps[i]->pst_cmd,0,NULL,0)))
marktable[i] = 1;
}
if (! orflag)
reset_tables(ps,&marktable,&psct);
}
/* strip out references to this process */
my_pid = getpid();
for (i=0;i<psct;i++)
{
if (my_pid == ps[i]->pst_pid)
marktable[i] = 0;
else if (!orflag)
marktable[i] = 1;
}
reset_tables(ps,&marktable,&psct);
if (quiet) exit (psct);
/* sort the data */
if (sortfields)
qsort((void **) ps,psct,sizeof (struct pst_status *),psSort);
if (reverse)
{
rps = (struct pst_status **) calloc(psct,sizeof (struct pst_status *));
for (i=0,j=psct-1;i<psct;i++,j--)
rps[i] = ps[j];
free ((void *) ps);
ps = rps;
}
/* select output - kill, shell or format */
/* Just add formatting */
if (sig > -1)
{
for (i=psct-1;i>=0;i--)
{
if (my_uid)
{
if (my_uid == ps[i]->pst_uid)
{
if (yesflag || ok2kill(ps[i]))
{
if (kill(ps[i]->pst_pid,sig))
perror("pstat kill");
}
}
}
else
{
/* root user */
if (ps[i]->pst_pid < MINROOTKILL)
{
fprintf(stderr,
"Can't kill process %d - less than MINROOTKILL of %d\n",
ps[i]->pst_pid,MINROOTKILL);
}
else if (yesflag || ok2kill(ps[i]))
{
if (kill(ps[i]->pst_pid,sig))
perror("pstat kill");
}
}
}
}
else if (shellout)
shellprint(ps,psct,maxproc,maxuserid);
else
{
for (i=0;i<psct;i++)
psformat(format, ps[i]);
}
exit(0);
}
@EOF
chmod 444 pstat.c
echo x - getusertable.c
cat >getusertable.c <<'@EOF'
/ ****************************************
***********************
*
* Copyright (C) 1992-2002, by Dan Mercer. All rights reserved.
*
* Program Name : $Source: /home/dam/News/pstat/RCS/getusertable.c,v $
* Version : $Revision: 1.5 $
* Date Created : 03-04-96
* Author : Dan A. Mercer
* Last Modified : $Date: 2002/06/14 15:06:59 $
* Modified By : $Author: dam $
*
* Description : build user database sorted by uid
****************************************
***********************/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <pwd.h>
#include "pwinfo.h"
#define U_TABLE_INC 100
int pw_sort(elem1,elem2)
void *elem1;
void *elem2;
{
PW_INFO *pw1;
PW_INFO *pw2;
pw1 = *((PW_INFO **)elem1);
pw2 = *((PW_INFO **)elem2);
return(pw1->uid - pw2->uid);
}
PW_INFO **getusertable(countPointer,MaxUserPtr)
int *countPointer;
int *MaxUserPtr;
{
PW_INFO **pw_array;
struct passwd *entry;
int pwct;
int arr_size;
int maxuid;
maxuid = 0;
for (pwct=arr_size=0,pw_array=NULL;entry=get
pwent();pwct++)
{
if (pwct >= arr_size)
{
if (NULL == (pw_array =
(PW_INFO **) realloc(pw_array,
(arr_size+=U_TABLE_INC) * sizeof (PW_INFO *))))
{
perror("Reallocing pw_array");
exit(1);
}
}
if (NULL == (pw_array[pwct] =
(PW_INFO *) calloc(1,sizeof (PW_INFO))))
{
perror("Callocing password entry");
exit(1);
}
pw_array[pwct]->uid = entry->pw_uid;
maxuid = (entry->pw_uid > maxuid) ? entry->pw_uid : maxuid;
pw_array[pwct]->name = strdup(entry->pw_name);
if (entry->pw_dir)
pw_array[pwct]->home = strdup(entry->pw_dir);
if (entry->pw_shell)
pw_array[pwct]->shell = strdup(entry->pw_shell);
if (entry->pw_gecos)
{
pw_array[pwct]->fname = strdup(entry->pw_gecos);
if (strtok(pw_array[pwct]->fname,","))
{
(pw_array[pwct]->location = strtok(NULL,",")) &&
(pw_array[pwct]->wphone = strtok(NULL,",")) &&
(pw_array[pwct]->hphone = strtok(NULL,","));
}
else
pw_array[pwct]->fname = NULL;
}
}
endpwent();
qsort((void *) pw_array,pwct,sizeof (PW_INFO *),pw_sort);
if (MaxUserPtr) *MaxUserPtr = maxuid;
if (countPointer) *countPointer = pwct;
return pw_array;
}
@EOF
chmod 444 getusertable.c
echo x - getproctable.c
cat >getproctable.c <<'@EOF'
/ ****************************************
***********************
*
* Copyright (C) 1992-2002, by Dan Mercer. All rights reserved.
*
* Program Name : $Source: /home/dam/News/pstat/RCS/getproctable.c,v $
* Version : $Revision: 1.3 $
* Date Created : 03-04-96
* Author : Dan A. Mercer
* Last Modified : $Date: 2002/06/14 15:07:23 $
* Modified By : $Author: dam $
*
* Description : use HP pstat routines to access process information
****************************************
***********************/
#include <sys/types.h>
#include <sys/pstat.h>
#include <stdio.h>
#include <malloc.h>
int ps_sort(elem1,elem2)
void *elem1;
void *elem2;
{
struct pst_status *ps1;
struct pst_status *ps2;
ps1 = elem1;
ps2 = elem2;
return(ps1->pst_pid - ps2->pst_pid);
}
struct pst_status *getproctable(countPointer,MaxProcPtr)
int *countPointer;
int *MaxProcPtr;
{
static struct pst_static pst_st_info;
struct pst_status *ps_array;
int psct;
if (pstat_getstatic(&pst_st_info,sizeof pst_st_info,1,0) < 0)
{
perror("pstat_getstatic failed!");
return (struct pst_status *) NULL;
}
ps_array = (struct pst_status *) calloc(pst_st_info.max_proc,
sizeof (struct pst_status));
psct = pstat_getproc(ps_array,
sizeof (struct pst_status),
pst_st_info.max_proc,
0);
qsort((void *) ps_array,psct,sizeof (struct pst_status),ps_sort);
if (MaxProcPtr) *MaxProcPtr = pst_st_info.max_proc;
if (countPointer) *countPointer = psct;
return ps_array;
}
@EOF
chmod 444 getproctable.c
echo x - gettime.c
cat >gettime.c <<'@EOF'
/ ****************************************
***********************
*
* Copyright (C) 1992-2002, by Dan Mercer. All rights reserved.
*
* Program Name : $Source: /home/dam/News/pstat/RCS/gettime.c,v $
* Version : $Revision: 1.5 $
* Date Created : Mon Jun 10 12:22:51 CDT 2002
* Author : Dan A. Mercer
* Last Modified : $Date: 2002/06/14 15:45:49 $
* Modified By : $Author: dam $
*
* Description : get time in EPOCH time given a string description
* : used by pstat application
* : Supported formats:
* : <number> <unit> [ago]
* : units:
* : sec[ond[s]|s]
* : min[ute[s]|s]
* : hour[s]|hr[s]
* : day[s]
* : week[s]
* : mo[n[t[h]]][s]
* : year[s]|yr[s]
* : [<today|yesterday|mm/dd/[cc]yy>] [HH:MM:SS]
* :
* : two digit year formula: 0-69, add 2000; 70-99, add 1900
* : only a 24 hour clock is supported. A month is assumed to
* : be an arbitrary 30 days.
****************************************
***********************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <malloc.h>
#include <regex.h>
#include <time.h>
char rcs_version[] = "$Revision: 1.5 $";
char rcs_date[] = "$Date: 2002/06/14 15:45:49 $";
void gt_settime(timestr,timeptr)
char *timestr;
struct tm *timeptr;
{
/* no attempt is made to insure correct time */
timeptr->tm_hour = atoi(strtok(timestr,":"));
timeptr->tm_min = atoi(strtok(NULL,":"));
timeptr->tm_sec = atoi(strtok(NULL,":"));
}
void gt_setdate(timestr,timeptr)
char *timestr;
struct tm *timeptr;
{
/* no attempt is made to insure correct date */
timeptr->tm_mon = atoi(strtok(timestr,"/")) - 1;
timeptr->tm_mday = atoi(strtok(NULL,"/"));
timeptr->tm_year = atoi(strtok(NULL,"/"));
if (timeptr->tm_year >= 1900)
timeptr->tm_year = timeptr->tm_year - 1900;
else if (timeptr->tm_year < 70)
timeptr->tm_year = timeptr->tm_year + 100;
}
time_t gettime(timestr)
char *timestr;
{
struct tm timebuf;
char **stack;
char **datestack;
char *ltimestr;
char *ts;
int i, tok_ct;
int measure, year;
time_t now;
if ((NULL == timestr) || (0 == strlen(timestr)))
ltimestr = strdup("none");
else
ltimestr = strdup(timestr);
stack = (char **) malloc(strlen(ltimestr) * sizeof (char *));
/*
* tokenize timestr
*/
for (i=0, ts=ltimestr;stack[i] = strtok(ts," ");i++,ts=NULL);
tok_ct = i;
/*
* initialize timebuf with current time
*/
now = time(NULL);
localtime_r(&now, &timebuf);
/*
* now process stack
* First, see if first arg is all numeric
*/
do {
if (strspn(stack[0],"0123456789") == strlen(stack[0]))
{
if (1 == tok_ct)
{
/*
* equivalent to today hour
*/
gt_settime(stack[0],&timebuf);
break;
}
measure = 0;
for (i=0;i<tok_ct;i++)
{
if (!strcmp(stack[i], "ago"))
break;
if (i%2)
{
if (!strncmp(stack[i],"year",4) || !strncmp(stack[i],"yr",2))
{
timebuf.tm_year -= measure;
now = mktime(&timebuf);
}
else if (!strncmp(stack[i],"mo",2))
now = mktime(&timebuf) - 30*60*60*24*7*measure;
else if (!strncmp(stack[i],"week",4))
now = mktime(&timebuf) - 60*60*24*7*measure;
else if (!strncmp(stack[i],"da",2))
now = mktime(&timebuf) - 60*60*24*measure;
else if (!strncmp(stack[i],"hour",4) || !strncmp(stack[i],"hr",2))
now = mktime(&timebuf) - 60*60*measure;
else if (!strncmp(stack[i],"mi",2))
now = mktime(&timebuf) - 60*measure;
else if (!strncmp(stack[i],"se",2))
now = mktime(&timebuf) - measure;
else
fprintf(stderr, "Rest of time expression ignored\n");
localtime_r(&now, &timebuf);
}
else
measure = atoi(stack[i]);
}
}
else if (strspn(stack[0],"0123456789/") == strlen(stack[0]))
{
gt_setdate(stack[0],&timebuf);
if (tok_ct > 1)
gt_settime(stack[1],&timebuf);
if (tok_ct > 2)
fprintf(stderr, "Rest of time expression ignored\n");
}
else if (strspn(stack[0],"0123456789:") == strlen(stack[0]))
{
gt_settime(stack[0],&timebuf);
if (tok_ct > 1)
fprintf(stderr, "Rest of time expression ignored\n");
}
else if (!strcmp(stack[0],"today"))
{
if (1 == tok_ct)
{
/* reset to last midnight */
gt_settime("0",&timebuf);
}
else
{
/* rest of expression must be HH:MM:SS - note that
* HH:MM and HH also work by default
*/
gt_settime(stack[1],&timebuf);
if (tok_ct > 2)
fprintf(stderr, "Rest of time expression ignored\n");
}
}
else if (!strcmp(stack[0],"yesterday"))
{
/* reset to yesterday at this time */
now -= 60*60*24;
localtime_r(&now, &timebuf);
if (1 == tok_ct)
gt_settime("0",&timebuf); /* reset to previous midnight */
else
{
/* rest of expression must be HH:MM:SS - note that
* HH:MM and HH also work by default
*/
gt_settime(stack[1],&timebuf);
if (tok_ct > 2)
fprintf(stderr, "Rest of time expression ignored\n");
}
}
else
{
fprintf(stderr, "Unknown time designator '%s'\n", stack[0]);
break;
}
} while(0);
free(ltimestr);
free(stack);
return mktime(&timebuf);
}
@EOF
chmod 444 gettime.c
echo x - pwinfo.h
cat >pwinfo.h <<'@EOF'
/ ****************************************
***********************
*
* Copyright (C) 1992-2002, by Dan Mercer. All rights reserved.
*
* Program Name : $Source: /home/dam/News/pstat/RCS/pwinfo.h,v $
* Version : $Revision: 1.1 $
* Date Created : 03-04-96
* Author : Dan A. Mercer
* Last Modified : $Date: 2002/06/14 14:53:15 $
* Modified By : $Author: dam $
*
* Description : common header for apps using getusertable
****************************************
***********************/
typedef struct _pw_info PW_INFO;
struct _pw_info {
int uid;
char *name;
char *home;
char *shell;
char *fname;
char *location;
char *wphone;
char *hphone;
};
@EOF
chmod 444 pwinfo.h
echo x - pstat.man
sed 's/^@//' >pstat.man <<'@EOF'
@.# comment
@.TH pstat 1
@.SH NAME
pstat - manipulate process status information
@.SH SYNOPSIS
@.TP 6
@.BR pstat " -[ghioqrsyzZ] [-c cmdlist] [-f format] [-k sig] [-p pidlist]"
@.sp 0
[-P ppidlist] [-u useridlist] [-U uidlist] [-S sortfields]
@.sp 0
[-z cpu] [-Z secs] [-t timespec] [pattern]
@.SH DESCRIPTION
pstat(1) is intended as the workhorse backend engine for frontend shell scripts.
@.B Options:
@.RS 3
@.TP 15
@.B -h
this message
@.sp -1
@.TP 15
@.B -g
@.RB "use globbing on pattern instead of " "regular expressions"
@.sp -1
@.TP 15
@.B -i
@.RB "ignore case on " "-c" " pattern matching."
@.sp -1
@.TP 15
@.B -q
quiet mode - just return count of matches in exit code
@.sp -1
@.TP 15
@.B -o
@.BR OR " search criteria options instead of " AND
@.sp -1
@.TP 15
@.B -r
reverse order of sort
@.sp -1
@.TP 15
@.B -s
@.RB "output info as " ksh " arrays."
@.sp -1
@.TP 15
@.B -y
@.RB "only valid with " "-k" " option - do not prompt user for permission
@.RB "to " kill .
@.sp -1
@.TP 15
@.B -z cpu
@.RB "match processes exceeding " CPU " utilization."
@.sp -1
@.TP 15
@.B -Z secs
@.RB "match processes exceeding " "secs CUM" " time."
@.sp -1
@.TP 15
@.B -t timespec
match processes whose starttime matches one of
@.B o[lder]=pattern m[atches]=pattern n[newer]=pattern
See
@.B SPECIFYING TIME VALUES
later.
@.sp -1
@.TP 15
@.B -c cmdlist
list of one or more commands (the basename(1) of the executable)
separated by commas. Cmd patterns may use the globbing chars
@.BR "'*'" " and " "'?'."
@.sp -1
@.TP 15
@.B -f format
@.RB "used to control output format (See " Formats: " Below)"
@.sp -1
@.TP 15
@.B -k signal
@.RB kill " using signal " signal ". If you don't own the process, the " kill
will fail silently. This option partially disabled for user root. See
@.B KILLING PROCESSES AS ROOT WITH PSTAT
below.
@.sp -1
@.TP 15
@.B -p pidlist
@.RB "list of one or more " "process ids" " separated by commas."
@.sp -1
@.TP 15
@.B -P ppidlist
@.RB "list of one or more " "parent process ids" " separated by commas."
@.sp -1
@.TP 15
@.B -S sortfields
sort matching process data according tosortfields which
consists of the letters
@.RB ' c "', '" C "',"
@.RB ' p "', '" P "',"
@.RB ' r "', '" s "',"
@.RB ' t "', '" u "' and "
@.RB ' U "'."
@.sp -1
@.TP 15
@.B -u useridlist
@.RB "list of one or more " userids " separated by commas."
@.sp -1
@.TP 15
@.B -U uidlist
@.RB "list of one or more " uids " separated by commas."
@.sp -1
@.TP 15
@.B pattern
a regular expression to match against the command string. If the -g option is
used globbing will be done instead.
@.bp
@.TP 15
@.B !
@.RB "not modifier - " "-p!2121,2123" " will exclude pids " 2121 " and " 2123
@.RB "and " "-c!dt*" " will exclude any " CDE " processes that begin with dt."
@.sp 2
@.RE
@.B Output Formats:
@.sp 0
The output formats are similar to printf(3) formats (and, in fact, are
internally converted to the appropriate printf(3) formats).
@.sp
@.RS 3
@.sp -1
@.TP 17
@.B %[precision]0..
@.RB "output commands' " "argv[0..."
@.sp -1
@.TP 17
@.B %[precision]p
@.BR pid " diplayed using integer precision."
@.sp -1
@.TP 17
@.B %[precision]P
@.BR ppid " diplayed using integer precision."
@.sp -1
@.TP 17
@.B %[precision]U
@.BR uid " diplayed using integer precision."
@.sp -1
@.TP 17
@.B %[precision]C
command string.
@.sp -1
@.TP 17
@.B %[precision]c
command name.
@.sp -1
@.TP 17
@.B %n
output newline.
@.sp -1
@.TP 17
@.B %[precision]r
processor utilization for scheduling.
@.sp -1
@.TP 17
@.B %s
start time [MM/DD/YY hh:mm:ss].
@.sp -1
@.TP 17
@.B %S
start time [MM/DD or hh:mm] - MM/DD used if started more than 24 hrs ago.
@.sp -1
@.TP 17
@.B %[precision]t
cumulative time in seconds.
@.sp -1
@.TP 17
@.B %T
cumulative time in hh:mm:ss.
@.sp -1
@.TP 17
@.B %[precision]u
userid.
@.RE
@.# .C monospace .B bold .I italic .SM smaller .[RIB][RIB] .P(new paragraph)
@.# .HP in Begin paragraph with hanging indent in
@.SH EXTERNAL INFLUENCES
@.TP 15
@.B PSTAT_FORMAT
if this environment variable is set and the
@.BR "-f" ", " "-k" " ,"
@.BR "-q" " and " "-s" " options"
are not specified, then the variable string is used for the output format.
@.RB "Otherwise, if no " "-f" " option is specified, a default
canned format that is not terribly informative is used.
@.SH RETURN VALUE
@.BR pstat " returns " 0 " on success, and " "non-zero" " on"
@.RB "error unless the " "-q" " option is specified;"
@.RB "in which case, it returns the number of " pids
that matched the description. Be aware that this is an abuse of the exit
code and can result in a false negative if the number of processes is
a modulus of
@.B 256.
If more than
@.B 256
processes are returned, the value
will be inaccurate.
@.SH SPECIFYING TIME PATTERNS
@.B pstat
Can display process based upon whether their start value is newer
than, older than or exactly matches a value provided by a time pattern.
time patterns can either be:
@.sp 0
@.IP "" 3
@.B mm/dd/yy HH:MM:SS
@.sp 1
@.RE
or
@.IP "" 3
@.B HH:MM:SS
which can be also expressed as
@.B HH:MM
or
@.B HH
@.sp 1
@.RE
or
@.IP "" 3
a formula involving an integer and a time unit and the optional
keyword
@.B "ago"
such as
@.B one day ago.
The units available are
@.B sec[ond][s], min[ute][s], h[ou]r[s],
@.B day[s], week[s], mo[nth][s],
and
@.B y[ea]r[s].
or
@.IP "" 3
a special day specifier and an optional time in
@.B HH:MM:SS
format. The special day specifiers are
@.BR today and yesterday.
For instance,
@.B today 12.
for noon today.
@.BR today " and " yesterday " start at " midnight.
@.SH KILLING PROCESSES AS ROOT WITH PSTAT
As a safety measure,
@.B pstat
will not kill any process below
@.B MINROOTKILL,
set by default to
@.B 200. Recompile to alter this value.
@.RE
@.SH MORE EXAMPLES
To show all processes run by the user excluding the shell
script process itself:
@.sp
@.RS 5
@.B echo """ PID PPID STIME COMMAND"""
@.sp 0
@.B echo """----- ----- ----- -------"""
@.sp 0
@.B pstat -f"%5p %5P %S %C"
@.B -p!$$ -U$(id -u)
@.RE
@.sp
@.RB "To show all the " ddterm " processes running:"
@.sp
@.RS 5
@.B pstat -f"%5p %2"
@.B -cddterm
@.RE
@.sp
To show the processes having the largest impact on the CPU (largest first)
@.sp
@.RS 5
@.B pstat -z0 -Sr -r
@.B -f '%5p %4r %C'
@.RE
@.SH KSH ARRAY OUTPUT
@.RB "When " pstat " is run with the " -s " option, it outputs"
@.RB "a series of " ksh " commands that will build arrays containing"
selected process information when those commands are run
@.RB "using the " eval " builtin " ksh " command:"
@.sp
@.RS 5
@.B eval $(pstat -s -ulims -clai)
@.sp
@.RE
The following environment variables are set:
@.RS 3
@.TP 10
@.B PSCT
an integer value set to the number of processes matching the
search description.
@.sp -1
@.TP 10
@.B PID
an array of process id's matching the search description.
@.sp -1
@.TP 10
@.B PPID
an array of parent process id's matching the search description.
@.sp -1
@.TP 10
@.B UID
an array of uid's matching the search description.
@.sp -1
@.TP 10
@.B USERID
an array of userid's matching the search description.
@.sp -1
@.TP 10
@.B CPU
an array of CPU utilization numbers matching the search description.
@.sp -1
@.TP 10
@.B START
an array of formatted start times matching the search description.
@.sp -1
@.TP 10
@.B SYSTIMES
an array of time used in seconds matching the search description.
@.sp -1
@.TP 10
@.B SYSTIMEF
an array of formatted time used matching the search description.
@.sp -1
@.TP 10
@.B UCOMM
an array of command names matching the search description.
@.RE
@EOF
chmod 644 pstat.man
echo x - makefile
sed 's/^@//' >makefile <<'@EOF'
CFLAGS = -g \
+DAportable \
-Wp,-H256000 \
-Wl,-a,archive \
-Wl,-E -l:libdld.sl
M = pstat.man
SHAR = pstat.shar
H = pwinfo.h
C = pstat.c getusertable.c getproctable.c gettime.c
O = $(C:.c=.o)
pstat : $O $H
$(CC) $(CFLAGS) -o $@ $O
clobber :
@rm -f pstat $O
shar : pstat.shar
man : pstat.1
pstat.shar : README $C $H $M makefile
shar README $C $H $M makefile > $@
@.man.1 :
@compress < $< > $@
@.SUFFIXES : .1 .man
@EOF
chmod 444 makefile
if [ $EXIT_STATUS -eq 1 ];then
exit 1
fi
exit 0
: Otherwise, if there is no direct system call/library function
: supporting this, could anybody suggest an elegant way to
: programmatically access this information?
: I searched FAQs for an answer to this question. If the question is
: primitive for this group, I apologize.
: Thanks in advance.
: Sreenidish C
:
| |
|
| u can save the process id in some shared memory or file..
this will b easy and not much cumborsome ..
|
|
|
|
|