/*
** Copyright (c) 1986, 1994, 1996, 2000, 2002, 2006
** Jeff Forys (jeffware@marjum.com). All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that: (1) Redistributions of
** source code must retain the above copyright notice, this list of
** conditions and the following disclaimer, (2) Redistributions in
** binary form must reproduce the above copyright notice, this list
** of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution, (3) All
** advertising materials mentioning features or use of this software
** must display the following acknowledgment: ``This product includes
** software developed by Jeff Forys (jeffware@marjum.com).'', (4)
** The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
** WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char rcsid[] = "$Id: aix-3.c,v 1.10 2006/10/09 01:58:11 forys Exp $";
#endif
#define NO_MEXTERN
#include "conf.h"
#undef NO_MEXTERN
#include <sys/user.h>
#include <sys/proc.h>
#include <stdio.h>
/*
* For AIX 3 and AIX 4, #define the SKILL_AIX34 macro.
* For AIX 5 (and beyond), this file should compile correctly.
*/
#ifdef SKILL_AIX34
#define SKILL_P_STRUCT struct procinfo
#define SKILL_P_STATE(p) (p)->pi_stat
#define SKILL_P_FLAGS(p) (p)->pi_flag
#define SKILL_PU_TTYP(p,u) (u)->ui_ttyp
#define SKILL_PU_TTYD(p,u) (u)->ui_ttyd
#define SKILL_PU_COMM(p,u) (u)->ui_comm
#define SKILL_NOTTY (-1)
#else
#define SKILL_P_STRUCT struct procentry64
#define SKILL_P_STATE(p) (p)->pi_state
#define SKILL_P_FLAGS(p) (p)->pi_flags
#define SKILL_PU_TTYP(p,u) (p)->pi_ttyp
#define SKILL_PU_TTYD(p,u) (p)->pi_ttyd
#define SKILL_PU_COMM(p,u) (p)->pi_comm
#define SKILL_NOTTY (0)
#include <stdlib.h>
#endif
/*
* Define SigNames, NSig, and TtyDevDir here; they are used by other
* routines and must be global. Everyone seems to have their own
* idea as to what NSIG should be. Here, `NSig' is the number of
* signals available, not counting zero.
*/
char *SigMap[] = { "0",
"HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", /* 1 - 6 */
"EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */
"PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */
"CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */
"XFSZ", "26", "MSG", "WINCH", "PWR", "USR1", /* 25 - 30 */
"USR2", "PROF", "DANGER", "VTALRM", "MIGRATE", "PRE", /* 31 - 36 */
"37", "38", "39", "40", "41", "42", /* 37 - 42 */
"43", "44", "45", "46", "47", "48", /* 43 - 48 */
"49", "50", "51", "52", "53", "54", /* 49 - 54 */
#ifdef SKILL_AIX34
"55", "56", "57", "58", "59", "GRANT", /* 55 - 60 */
#else
"55", "56", "57", "58", "CPUFAIL", "GRANT", /* 55 - 60 */
#endif
"RETRACT", "SOUND", "SAK", "64", /* 61 - 64 */
};
int NSig = NSIG;
#define SETCMD(dst,src,maxlen) { \
extern char *rindex(); \
if (maxlen > 0) src[maxlen] = '\0'; \
dst = (dst = rindex(src, '/')) ? ++dst: src; \
}
static char *TtyDevDir = "/dev";
int Skill; /* set 1 if running `skill', 0 if `snice' */
int PrioMin, PrioMax; /* min and max process priorities */
int SigPri; /* signal to send or priority to set */
pid_T MyPid; /* pid of this process */
uid_T MyUid; /* uid of this process */
char *ProgName; /* program name */
/*
* This is the machine-dependent initialization routine.
*
* - The following global variables must be initialized:
* MyPid, MyUid, ProgName, Skill, PrioMin, PrioMax, SigPri
* - The working directory will be changed to that which contains the
* tty devices (`TtyDevDir'); this makes argument parsing go faster.
* - If possible, this routine should raise the priority of this process.
*/
void
MdepInit(pname)
char *pname;
{
extern char *rindex(), *SysErr();
MyPid = (pid_T) getpid();
MyUid = (uid_T) getuid();
SETCMD(ProgName, pname, 0)
/*
* If we are running as root, raise our priority to better
* catch runaway processes.
*/
if (MyUid == ROOTUID)
(void) setpriority(PRIO_PROCESS, MyPid, PRIO_MIN);
/*
* Determine what we are doing to processes we find. We will
* either send them a signal (skill), or renice them (snice).
*/
Skill = (strcmp(ProgName, "snice") != 0);
/*
* chdir to `TtyDevDir' to speed up tty argument parsing.
*/
if (chdir(TtyDevDir) < 0) {
fprintf(stderr, "%s: chdir(%s): %s\n", ProgName, TtyDevDir,
SysErr());
exit(EX_SERR);
}
/*
* Set up minimum and maximum process priorities.
* Initialize SigPri to either default signal (`skill') or
* default priority (`snice').
*/
PrioMin = PRIO_MIN;
PrioMax = PRIO_MAX;
SigPri = Skill? SIGTERM: 4;
}
/*
* Carry out an action on a particular process. If this is `skill',
* then send the process a signal, otherwise this is `snice' so change
* it's priority.
*
* If 0 is returned, the operation was successful, otherwise -1 is
* returned and `errno' set.
*/
int
MdepAction(pid)
pid_T pid;
{
if (Skill)
return(kill((int)pid, SigPri));
else
return(setpriority(PRIO_PROCESS, (int)pid, SigPri));
}
#ifdef SKILL_AIX34
/* disable regular expresions: regex(3) availability unknown */
NULL_REGEX_FUNCS
#else
/* OS supports POSIX-style regular expressions */
#include <regex.h>
REAL_REGEX_FUNCS
#endif
/*
* Now, set up everything we need to write a GetProc() routine.
*
* IMPORTANT NOTE TO PEOPLE SNARFING THIS CODE:
*
* The AIX getproc() and getuser() routines are unsupported (not to
* mention, undocumented). They are liable to be changed, or replaced
* in future versions of AIX. Please include this comment in any
* code that uses these routines. Thanks.
*
* With that said, here's a brief (incomplete) description of each:
*
* #include <procinfo.h>
*
* struct procinfo pinfo[N];
* getproc(pinfo, N, sizeof(struct procinfo))
* RETURN: number of procs read (must be all), or -1 on error.
* [If N is too small, -1 is returned with errno == ENOSPC]
*
* struct userinfo uinfo;
* struct procinfo *aproc;
* getuser(aproc, sizeof(struct procinfo), &uinfo, sizeof(uinfo))
* RETURN: 0 on success, -1 on error.
*/
#include <sys/var.h>
#include <sys/sysconfig.h>
#include <sys/errno.h>
#include <procinfo.h>
extern off_t lseek();
#define NPROCS 1024 /* size of `procs' struct (if too small, use calloc) */
/*
* GetProc()
*
* Fill in and return a `struct ProcInfo' with information about the
* next process. If no processes are left, return NULL.
*
* Fflag support:
* If Fflag is set we will try to avoid reading in the user struct.
* We can do this only if Iflag, TtyIndx, and CmdIndx are zero.
*/
struct ProcInfo *
GetProc()
{
extern int errno;
extern char *SysErr();
static SKILL_P_STRUCT pinfo[NPROCS], *procsp;
register SKILL_P_STRUCT *aproc;
static struct ProcInfo procinfo;
static int thisproc = 0;
static int initialized = 0;
static int needuser = 1; /* Fflag support */
#ifdef SKILL_AIX34
register struct userinfo *auser;
#else
pid_t procsidx;
#endif
/*
* Read in all the processes at once, into a large block of memory;
* if `pinfo' is big enough, we'll use that, o/w we will calloc()
* what we need. Either way, `procsp' will point to the next proc.
*
* The first time thisproc == 0, we do the `procsp' initialization.
* The second time thisproc == 0, we are finished and return NULL.
* The following `while' is for sanity; it could be an `if'.
*/
while (thisproc == 0) {
char *errstr = "%s: %s: %s\n";
register u_int nprocs, maxnprocs, pisize;
if (initialized)
return((struct ProcInfo *)NULL);
pisize = sizeof(SKILL_P_STRUCT);
#ifdef SKILL_AIX34
if ((thisproc = getproc(pinfo, (u_int)NPROCS, pisize)) < 0)
#else
procsidx = 0;
if (((thisproc = getprocs64(pinfo, pisize, NULL, 0,
&procsidx, (u_int)NPROCS)) < 0) ||
thisproc == NPROCS)
#endif
{
/*
* We apparently have more then NPROCS processes
* running on this machine. Ideally, one should
* raise NPROCS if they run into this problem.
* However, we'll quietly deal with it by grabbing
* a sufficiently large block of memory.
*
* N.B. `nprocs' is temporarily used to hold `errno'
* across the call to sysconfig(), after which, it
* will assume it's real duty.
*/
struct var v;
nprocs = errno;
if (sysconfig(SYS_GETPARMS, &v, sizeof(struct var)) < 0)
maxnprocs = 1024 * 1024; /* very big */
else
maxnprocs = v.v_proc;
errno = nprocs;
nprocs = NPROCS;
while (nprocs <= maxnprocs) {
nprocs <<= 1;
if ((procsp = (SKILL_P_STRUCT *)
calloc(nprocs, pisize)) == NULL) {
fprintf(stderr, errstr, ProgName,
"getproc", "out of memory");
exit(EX_SERR);
}
errno = 0;
#ifdef SKILL_AIX34
thisproc = getproc(procsp, nprocs, pisize);
#else
procsidx = 0;
thisproc = getprocs64(procsp, pisize, NULL, 0,
&procsidx, nprocs);
#endif
if (thisproc < 0 && errno != ENOSPC) {
fprintf(stderr, errstr, ProgName,
"getproc", SysErr());
exit(EX_SERR);
} else if (thisproc < nprocs)
break;
free((void *)procsp);
}
if (nprocs > maxnprocs) {
fprintf(stderr, errstr, ProgName,
"GetProc", "maxnproc exceeded");
exit(EX_SERR);
}
} else
procsp = pinfo;
/*
* We run a little faster without reading in the user struct;
* the price is incomplete information for errors (no cmd).
*/
if (Fflag && Iflag == 0 && TtyIndx == 0 && CmdIndx == 0)
needuser = 0;
initialized = 1;
}
/*
* Trudge thru `procsp'. Decrement `thisproc' as we go.
*/
do {
aproc = procsp++;
thisproc--;
if (SKILL_P_STATE(aproc) != SNONE) {
/*
* Make sure this isn't a "zombie" or "exiting"
* process. If it is, we have all the information
* we need; fill in procinfo and return.
*/
procinfo.pi_flags = 0;
procinfo.pi_pid = (pid_T) aproc->pi_pid;
procinfo.pi_uid = (uid_T) aproc->pi_uid;
if (SKILL_P_STATE(aproc) == SZOMB) { /* zombie */
static char *zombie = "<defunct>";
procinfo.pi_flags |= PI_ZOMBIE;
procinfo.pi_cmd = zombie;
} else if (SKILL_P_FLAGS(aproc) & SEXIT) {
static char *exiting = "<exiting>";
procinfo.pi_flags |= PI_SWEXIT;
procinfo.pi_cmd = exiting;
} else if (!needuser) {
static char *fflagcmd = "<-f>";
procinfo.pi_cmd = fflagcmd;
}
if (procinfo.pi_flags || !needuser)
return(&procinfo);
#ifdef SKILL_AIX34
else {
static struct userinfo uinfo;
if (getuser(aproc, sizeof(SKILL_P_STRUCT),
&uinfo,sizeof(struct userinfo)) < 0)
auser = NULL;
else
auser = &uinfo;
}
#endif
}
}
#ifdef SKILL_AIX34
while (SKILL_P_STATE(aproc) == SNONE || auser == NULL);
#else
while (SKILL_P_STATE(aproc) == SNONE);
#endif
/*
* We now have a process (`aproc').
* Fill in the rest of `procinfo'.
*/
if (SKILL_PU_TTYP(aproc,auser) != SKILL_NOTTY) { /* controlling tty */
procinfo.pi_flags |= PI_CTLTTY;
procinfo.pi_tty = (tty_T) SKILL_PU_TTYD(aproc,auser);
} else {
procinfo.pi_tty = (tty_T)-2;
}
/* set path-stripped command name */
SETCMD(procinfo.pi_cmd, SKILL_PU_COMM(aproc,auser), MAXCOMLEN)
return(&procinfo);
}
syntax highlighted by Code2HTML, v. 0.9.1