/*
** Copyright (c) 1986, 1994, 1996, 2000, 2002
** 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: umax-42.c,v 1.8 2005/04/06 23:49:35 forys Exp $";
#endif
#define NO_MEXTERN
#include "conf.h"
#undef NO_MEXTERN
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#define CRIT_PID 1 /* Query kills for pids .LE. this number */
/*
* 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", "IOT", /* 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", "VTALRM", "PROF", "28", "29", "30", /* 25 - 30 */
"31", "32", /* 31 - 32 */
};
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));
}
/* disable regular expresions: regex(3) availability unknown */
NULL_REGEX_FUNCS
/*
* Now, set up everything we need to write a GetProc() routine.
*/
#include <sys/statistics.h>
#include <sys/procstats.h>
extern off_t lseek();
#ifndef SZOMB
#define SZOMB 0x08
#endif
/*
* 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 stat'ing ttys for dev_t's.
* We can do this only if TtyIndx is zero.
*/
struct ProcInfo *
GetProc()
{
extern int errno;
extern char *SysErr();
static struct stat_descr pdesc;
static struct proc_config pconf;
static struct proc_detail *procsp;
static struct ProcInfo procinfo;
register struct proc_detail *aproc;
static int thisproc = 0;
static int initialized = 0;
static int needtty = 1; /* Fflag support */
/*
* 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) {
extern char *calloc();
char *errstr = "%s: %s: %s\n";
if (initialized)
return((struct ProcInfo *)NULL);
pdesc.sd_next = NULL;
pdesc.sd_subsys = SUBSYS_PROC;
pdesc.sd_type = PROCTYPE_CONFIG;
pdesc.sd_options = NULL;
pdesc.sd_objid = NULL;
pdesc.sd_addr = (char *)&pconf;
pdesc.sd_size = sizeof(struct proc_config);
if (inq_stats(1, &pdesc) < 0) {
fprintf(stderr, errstr, ProgName, "inq_stats(CONFIG)",
SysErr());
exit(EX_SERR);
}
thisproc = pconf.pc_nprocs;
if ((procsp = (struct proc_detail *) calloc((unsigned)thisproc,
sizeof(struct proc_detail))) == NULL) {
fprintf(stderr, errstr, ProgName, "GetProc",
"out of memory");
exit(EX_SERR);
}
pdesc.sd_next = NULL;
pdesc.sd_subsys = SUBSYS_PROC;
pdesc.sd_type = PROCTYPE_DETAIL;
pdesc.sd_options = PROC_DETAIL_ALL|PROC_DETAIL_ALLPROC;
pdesc.sd_objid = NULL;
pdesc.sd_addr = (char *)procsp;
pdesc.sd_size = thisproc * sizeof(struct proc_detail);
if (inq_stats(1, &pdesc) < 0) {
fprintf(stderr, errstr, ProgName, "inq_stats(DETAIL)",
SysErr());
exit(EX_SERR);
}
thisproc = pdesc.sd_sizeused / sizeof (struct proc_detail);
/*
* We can avoid a stat() syscall if we dont need dev_t's.
*/
if (Fflag && TtyIndx == 0)
needtty = 0;
initialized = 1;
}
/*
* Trudge thru `procsp'. Decrement `thisproc' as we go.
*/
aproc = procsp++;
thisproc--;
/*
* Make sure this isn't a "zombie" process. If it is, we are
* finished; fill in procinfo and return.
*/
procinfo.pi_flags = 0;
procinfo.pi_pid = (pid_T) aproc->pd_pid;
procinfo.pi_uid = (uid_T) aproc->pd_uid;
if (aproc->pd_flag & SZOMB) { /* zombie */
static char *zombie = "<defunct>";
procinfo.pi_flags |= PI_ZOMBIE;
procinfo.pi_cmd = zombie;
}
if (procinfo.pi_flags)
return(&procinfo);
/*
* Fill in the rest of `procinfo'.
*/
if (aproc->pd_pid <= CRIT_PID) /* special */
procinfo.pi_flags |= PI_ASKUSR;
/* set path-stripped command name */
SETCMD(procinfo.pi_cmd, aproc->pd_command, 12)
/*
* Encore gives us a character string representing the device.
* We want the actual device major/minor!
*/
if (needtty && *aproc->pd_device != '?') {
static struct stat st;
if (stat(aproc->pd_device, &st) >= 0 &&
(st.st_mode & S_IFMT) == S_IFCHR) {
procinfo.pi_flags |= PI_CTLTTY;
procinfo.pi_tty = (tty_T) st.st_rdev;
}
}
return(&procinfo);
}
syntax highlighted by Code2HTML, v. 0.9.1