/* ** 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: bsd-44.c,v 1.19 2005/04/06 23:49:34 forys Exp $"; #endif #define NO_MEXTERN #include "conf.h" #undef NO_MEXTERN /* * With FreeBSD 2.2 is required (again). */ #if (__FreeBSD__ >= 2) #include #if (__FreeBSD_version >= 220000) #include #endif #endif #include #include #include #include #include /* * 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", "VTALRM", "PROF", "WINCH", "INFO", "USR1", /* 25 - 30 */ "USR2" /* 31 */ #ifdef __NetBSD__ , "PWR" /* 32 */ #endif }; int NSig = NSIG - 1; #define SETCMD(dst,src,maxlen) { \ if (maxlen > 0) src[maxlen] = '\0'; \ dst = (dst = strrchr(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 *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 = (strstr(ProgName, "snice") == NULL); /* * 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 #include #if defined(BSD4_4) && (BSD < 199306) #include #include #define _ALLPROCFLAG KINFO_PROC_ALL #else #include #include #define _ALLPROCFLAG KERN_PROC_ALL #endif #ifndef P_WEXIT /* backward compatibility */ #define P_WEXIT SWEXIT #endif static char *pidmap[] = { "swapper", "init", "pagedaemon" }; static int pidmapsiz = sizeof(pidmap) / sizeof(pidmap[0]); #define PROC(kprocp) kprocp->kp_proc #define EPROC(kprocp) kprocp->kp_eproc /* * GetProc() * * Fill in and return a `struct ProcInfo' with information about the * next process. If no processes are left, return NULL. */ struct ProcInfo * GetProc() { static struct ProcInfo procinfo; static int nproc = -1; static struct kinfo_proc *aproc; static kvm_t *kd = NULL; #ifdef _POSIX2_LINE_MAX char errbuf[_POSIX2_LINE_MAX]; #else char errbuf[2048]; #endif /* * If this is our first time here, prepare to read procs from kernel. */ if (nproc == -1) { kd = kvm_openfiles((char *)NULL, (char *)NULL, (char *)NULL, O_RDONLY, errbuf); if (kd == NULL) { fprintf(stderr, "%s: %s\n", ProgName, errbuf); exit(EX_SERR); } if ((aproc=kvm_getprocs(kd, _ALLPROCFLAG, 0, &nproc)) == NULL) { fprintf(stderr, "%s: %s\n", ProgName, kvm_geterr(kd)); exit(EX_SERR); } } if (nproc == 0) { if (kd != NULL) { kvm_close(kd); kd = NULL; } return((struct ProcInfo *)NULL); } do { if (PROC(aproc).p_stat != 0) { /* * Make sure this isn't a "zombie" or "exiting" * process. If it is, fill in procinfo and return. */ procinfo.pi_flags = 0; procinfo.pi_pid = (pid_T) PROC(aproc).p_pid; procinfo.pi_uid = (uid_T) EPROC(aproc).e_ucred.cr_uid; if (PROC(aproc).p_stat == SZOMB) { /* zombie */ static char *zombie = ""; procinfo.pi_flags |= PI_ZOMBIE; procinfo.pi_cmd = zombie; } else if (PROC(aproc).p_flag & P_WEXIT) { /* exiting */ static char *exiting = ""; procinfo.pi_flags |= PI_SWEXIT; procinfo.pi_cmd = exiting; } if (procinfo.pi_flags) { nproc--; aproc++; return(&procinfo); } } } while (PROC(aproc).p_stat == 0); /* * We now have a process (`aproc'). * Fill in the rest of `procinfo'. */ if (EPROC(aproc).e_tdev != NODEV) { /* controlling tty */ procinfo.pi_flags |= PI_CTLTTY; procinfo.pi_tty = (tty_T) EPROC(aproc).e_tdev; } if (PROC(aproc).p_pid < pidmapsiz) { /* special */ procinfo.pi_cmd = pidmap[PROC(aproc).p_pid]; procinfo.pi_flags |= PI_ASKUSR; } else /* set path-stripped command name */ SETCMD(procinfo.pi_cmd, PROC(aproc).p_comm, MAXCOMLEN) nproc--; aproc++; return(&procinfo); }