/* ** 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. ** ** NetBSD/KERN_PROC2 support by Simon Burge (simonb@NetBSD.ORG) */ #ifndef lint static char rcsid[] = "$Id: nbsd-44.c,v 1.10 2005/04/06 23:49:35 forys Exp $"; #endif #define NO_MEXTERN #include "conf.h" #undef NO_MEXTERN #include #include #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[NSIG]; /* dynamically filled in by MdepInit() */ 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 */ int CmdLen; /* commands are unique to this many bytes */ pid_T MyPid; /* pid of this process */ uid_T MyUid; /* uid of this process */ char *ProgName; /* program name */ static const char *nomemmsg = "%s: %s: out of memory (wanted %u bytes)\n"; /* * 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(); const char * const *signam, *scp; size_t siz; char *cp; int i; 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; CmdLen = MAXCOMLEN; /* * Determine total space for signal names (or numbers) and NULs, * allocate memory, then copy signals with pointers in SigMap[]. */ for (i = siz = 0, signam = sys_signame; i < NSIG; i++, signam++) siz += (signam != NULL && strchr(*signam, ' ') == NULL)? strlen(*signam): 10; /* names or numbers */ siz += NSIG; /* NUL terminators */ if ((cp = malloc(siz)) == NULL) { fprintf(stderr, nomemmsg, ProgName, "MdepInit", siz); exit(EX_SERR); } for (i = 0, signam = sys_signame; i < NSIG; i++, signam++) { SigMap[i] = cp; if (signam != NULL && strchr(*signam, ' ') == NULL) { for (scp = *signam; *scp != '\0'; scp++) *cp++ = islower(*scp)? toupper(*scp): *scp; *cp++ = '\0'; } else cp += sprintf(cp, "%u", i) + 1; } } /* * 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)); } /* OS supports POSIX-style regular expressions */ #include REAL_REGEX_FUNCS /* * Now, set up everything we need to write a GetProc() routine. */ #include #include static char *pidmap[] = { "swapper", "init" #ifdef NeXTBSD , "mach_init" #else , "pagedaemon" #ifdef __FreeBSD__ #if (__FreeBSD__ > 3) , "vmdaemon", "bufdaemon", "syncer", "vnlru" #else , "vmdaemon", "update" #endif #endif #ifdef __NetBSD_Version__ #if (__NetBSD_Version__ >= 105000000) , "reaper", "ioflush" #endif #endif #endif /* !NeXTBSD */ }; static int pidmapsiz = sizeof(pidmap) / sizeof(pidmap[0]); #ifdef __FreeBSD__ #if (__FreeBSD__ > 4) #define _PROC_COMM(p) (p)->ki_comm #define _PROC_FLAG(p) (p)->ki_flag #define _PROC_PID(p) (p)->ki_pid #define _PROC_STAT(p) (p)->ki_stat #define _PROC_TDEV(p) (p)->ki_tdev #define _PROC_UID(p) (p)->ki_uid #endif #endif /* __FreeBSD__ */ #if defined(__NetBSD_Version__) && defined(KERN_PROC2) #define _SYSCTL_ARG KERN_PROC2 #define _SYSCTL_NMIB 6 #define _SYSCTL_PROC kinfo_proc2 #define _SYSCTL_MIBINIT(m) \ m[0] = CTL_KERN; \ m[1] = KERN_PROC2; \ m[2] = KERN_PROC_ALL; \ m[3] = 0; \ m[4] = sizeof(struct _SYSCTL_PROC); \ m[5] = 0 #define _SYSCTL_MIBPROC(m,sz) \ m[5] = (sz) / sizeof(struct _SYSCTL_PROC) #define _PROC_COMM(p) (p)->p_comm #define _PROC_FLAG(p) (p)->p_flag #define _PROC_PID(p) (p)->p_pid #define _PROC_STAT(p) (p)->p_stat #define _PROC_TDEV(p) (p)->p_tdev #define _PROC_UID(p) (p)->p_uid #endif /* __NetBSD_Version__ && KERN_PROC2 */ #ifndef _PROC_TDEV /* PROC defaults */ #define _PROC_COMM(p) (p)->kp_proc.p_comm #define _PROC_FLAG(p) (p)->kp_proc.p_flag #define _PROC_PID(p) (p)->kp_proc.p_pid #define _PROC_STAT(p) (p)->kp_proc.p_stat #define _PROC_TDEV(p) (p)->kp_eproc.e_tdev #define _PROC_UID(p) (p)->kp_eproc.e_ucred.cr_uid #endif #ifndef _SYSCTL_MIBINIT /* SYSCTL defaults */ #define _SYSCTL_ARG KERN_PROC #define _SYSCTL_NMIB 3 #define _SYSCTL_PROC kinfo_proc #define _SYSCTL_MIBINIT(m) \ m[0] = CTL_KERN; \ m[1] = KERN_PROC; \ m[2] = KERN_PROC_ALL #define _SYSCTL_MIBPROC(m,sz) #endif /* * 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 _SYSCTL_PROC *aproc; /* * If this is our first time here, prepare to read procs from kernel. */ if (nproc == -1) { int mib[_SYSCTL_NMIB]; size_t size = 0; _SYSCTL_MIBINIT(mib); if (sysctl(mib, _SYSCTL_NMIB, NULL, &size, NULL, 0) < 0) { fprintf(stderr, "%s: sysctl proctab size: %s\n", ProgName, strerror(errno)); exit(EX_SERR); } size += (size / 8); if ((aproc = malloc(size)) == NULL) { fprintf(stderr, nomemmsg, ProgName, "GetProc", size); exit(EX_SERR); } _SYSCTL_MIBPROC(mib,size); if (sysctl(mib, _SYSCTL_NMIB, aproc, &size, NULL, 0) < 0) { fprintf(stderr, "%s: sysctl proctab: %s\n", ProgName, strerror(errno)); exit(EX_SERR); } if (size % sizeof *aproc != 0) { fprintf(stderr, "%s: proc size mismatch, recompile libkvm\n", ProgName); exit(EX_SERR); } nproc = size / sizeof(struct _SYSCTL_PROC); } if (nproc == 0) return((struct ProcInfo *)NULL); do { if (_PROC_STAT(aproc) != 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_PID(aproc); procinfo.pi_uid = (uid_T) _PROC_UID(aproc); if (_PROC_STAT(aproc) == SZOMB) { /* zombie */ static char *zombie = ""; procinfo.pi_flags |= PI_ZOMBIE; procinfo.pi_cmd = zombie; } else if (_PROC_FLAG(aproc) & 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_STAT(aproc) == 0); /* * We now have a process (`aproc'). * Fill in the rest of `procinfo'. */ if (_PROC_TDEV(aproc) != NODEV) { /* controlling tty */ procinfo.pi_flags |= PI_CTLTTY; procinfo.pi_tty = (tty_T) _PROC_TDEV(aproc); } #ifdef __FreeBSD__ # if (__FreeBSD__ > 4) if (_PROC_PID(aproc) < 100) /* special */ procinfo.pi_flags |= PI_ASKUSR; # else if (_PROC_PID(aproc) < pidmapsiz) { /* special */ procinfo.pi_cmd = pidmap[_PROC_PID(aproc)]; procinfo.pi_flags |= PI_ASKUSR; } else /* set path-stripped command name */ # endif #else if (_PROC_PID(aproc) < pidmapsiz) { /* special */ procinfo.pi_cmd = pidmap[_PROC_PID(aproc)]; procinfo.pi_flags |= PI_ASKUSR; } else /* set path-stripped command name */ #endif SETCMD(procinfo.pi_cmd, _PROC_COMM(aproc), MAXCOMLEN) nproc--; aproc++; return(&procinfo); }