Commit 8f1a8857 authored by Timothy Stack's avatar Timothy Stack

Import the auto-nice-daemon on Oct 25, 2004

parent 478f5241
Changelog for Auto Nice Daemon
------------------------------
Changes in 1.2.1
- take into account not only usr but also sys time (Linux only; other
Unixes already did this)
Changes in 1.2.0
- more robust signal handling/config reload
- startup script fixed for Tru64 killall
- proper daemon mode
- improved 64bit hardness
- verbosity handling now in and_printf()
- additional criterion: parent process (parent=.../ancestor=...)
(thanks to Dr. Hans Ekkehard Plesser, NLH, for idea and testing)
- additional criterion: minimum user/group id
(again thanks to Dr. Hans Ekkehard Plesser)
Changes in 1.0.9
- fix broken zombie fix (Linux only)
- fix ultra-long running (248+ days) processes (thanks to Marcelo
Matus, UA)
- clean up signed/unsigned time vars
- compiled for AMD Opteron
Changes in 1.0.8
- leave zombies alone (Linux only)
Changes in 1.0.7
- port to FreeBSD (thanks to a guy who calls himself quake2)
- version and date are now compiled in
- make doc target to bump version number in man pages
Changes in 1.0.6
- stop overwriting existing configuration when make install
- small docs improvement (command name and regexes)
- changed misleading log message (seemingly negative nice level)
- added gtop to default config file
- fix LICENSE (still GPL, but the file was truncated)
- port to IRIX, IRIX64 and SunOS (thanks to Dan Stromberg, UCI)
Changes in 1.0.5
- fix format string vulnerability (please UPDATE!)
(thanks to INTEXXIA.com)
Changes in 1.0.4
- makefile improvements, esp. for Debian (thanks to Andras Bali
and Mikael Andersson)
- include LICENSE
Changes in 1.0.3
- bug fix Linux/AXP: jiffies to seconds fixed (thanks to Markus
Lischka, TUM)
- in config files, "on" hostname is now an extended regex
(thanks to Markus Lischka, TUM)
- new commandline switch -s for output to stdout
- documentation updates
Changes in 1.0.2
- minor documentation updates
- improved default configuration
- distribution-independend spec file for source rpms (thanks to
Terje Rosten for his help)
- improved build process to support distribution-independend
spec file
- fix logging: in -x mode (default), log via syslog; in -t mode (test),
log to ./debug.and
- added chkconfig hook in SysV init script
Changes in 1.0.1
- fix status check in SysV init script
Changes in 1.0.0
- first official release
This diff is collapsed.
#
# Makefile for auto nice daemon
#
# 1999-2004 Patrick Schemitz <schemitz@users.sourceforge.net>
# http://and.sourceforge.net/
#
#######################################################################
# Edit here to adapt to your system! #
#######################################################################
#
# Init script.
# (and.init.debian for Debian GNU/Linux or and.init for others;
# leave empty for BSD!)
#
INITSCRIPT=and.init
#
# Target directories. Examples for common configurations are
# given below.
#
PREFIX=/usr/local
INSTALL_ETC=$(PREFIX)/etc
INSTALL_INITD=/etc/init.d
INSTALL_SBIN=$(PREFIX)/sbin
INSTALL_MAN=$(PREFIX)/man
# typical OpenBSD or FreeBSD configuration
#PREFIX=/usr/local
#INSTALL_ETC=/etc
#INSTALL_INITD=
#INSTALL_SBIN=$(PREFIX)/sbin
#INSTALL_MAN=$(PREFIX)/man
# typical Debian or SuSE 7.x configuration
#PREFIX=/usr
#INSTALL_ETC=/etc
#INSTALL_INITD=/etc/init.d
#INSTALL_SBIN=$(PREFIX)/sbin
#INSTALL_MAN=$(PREFIX)/share/man
# typical SuSE 6.x configuration
#PREFIX=/usr
#INSTALL_ETC=/etc
#INSTALL_INITD=/sbin/init.d
#INSTALL_SBIN=$(PREFIX)/sbin
#INSTALL_MAN=$(PREFIX)/man
# typical Redhat / Mandrake configuration
#PREFIX=/usr
#INSTALL_ETC=/etc
#INSTALL_INITD=/etc/rc.d/init.d
#INSTALL_SBIN=$(PREFIX)/sbin
#INSTALL_MAN=$(PREFIX)/share/man
# typical OSF/1 / Digital UNIX 4 configuration
#PREFIX=/usr/local
#INSTALL_ETC=/etc
#INSTALL_INITD=/sbin/init.d
#INSTALL_SBIN=$(PREFIX)/sbin
#INSTALL_MAN=$(PREFIX)/man
#
# Install program
#
INSTALL=install
#######################################################################
# Stop editing here! #
#######################################################################
default: and $(INITSCRIPT) doc
#
# Version and date
#
VERSION=1.2.1
DATE="09 Sep 2004"
#
# Man pages
#
MANPAGES=and.8 and.conf.5 and.priorities.5
#
# Determine architecture from uname(1)
#
ARCH=$(shell uname)
#
# Architecture-dependent settings: ANSI C compiler and linker
#
ifeq (${ARCH},Linux)
CC = gcc -ansi -pedantic -Wall -g
LD = gcc
LIBS =
else
ifeq (${ARCH},OSF1)
CC = cc -ansi
LD = cc
LIBS =
else
ifeq (${ARCH},OpenBSD)
CC = gcc
LD = gcc
LIBS = -lkvm
else
ifeq (${ARCH},FreeBSD)
CC = gcc -Wall
LD = gcc
LIBS = -lkvm
else
ifeq (${ARCH},SunOS)
CC = cc -D__SunOS__
LD = cc
else
ifeq (${ARCH},IRIX)
CC = cc
LD = cc
else
ifeq (${ARCH},IRIX64)
CC = cc
LD = cc
else
# unsupported architecture
CC = false
LD = false
LIBS =
endif
endif
endif
endif
endif
endif
endif
#
# Build the auto-nice daemon.
#
and: and.o and-$(ARCH).o
$(LD) and.o and-$(ARCH).o -o and $(LIBS)
#
# Independent part: configuration management, priority database.
#
and.o: and.c and.h
$(CC) -DDEFAULT_INTERVAL=60 -DDEFAULT_NICE=0 \
-DDEFAULT_CONFIG_FILE=\"$(INSTALL_ETC)/and.conf\" \
-DDEFAULT_DATABASE_FILE=\"$(INSTALL_ETC)/and.priorities\" \
-DAND_VERSION=\"$(VERSION)\" -DAND_DATE=\"$(DATE)\" -c and.c
#
# Unix variant specific stuff
#
and-Linux.o: and.h and-Linux.c
$(CC) -c and-Linux.c
and-OpenBSD.o: and.h and-OpenBSD.c
$(CC) -c and-OpenBSD.c
and-FreeBSD.o: and.h and-OpenBSD.c
$(CC) -c and-OpenBSD.c -o and-FreeBSD.o
and-OSF1.o: and.h and-OSF1.c
$(CC) -c and-OSF1.c
and-IRIX.o: and.h and-OSF1.c
$(CC) -c and-OSF1.c -o and-IRIX.o
and-IRIX64.o: and.h and-OSF1.c
$(CC) -c and-OSF1.c -o and-IRIX64.o
and-SunOS.o: and.h and-OSF1.c
$(CC) -c and-OSF1.c -o and-SunOS.o
#
# Create script for SysV init
#
and.init: and.startup
sed s:INSTALL_SBIN:$(INSTALL_SBIN):g < and.startup > and.init
chmod +x and.init
#
# Man pages
#
doc: $(MANPAGES)
and.8: and.8.man
cat $< | \
sed s/__VERSION__/$(VERSION)/g | \
sed s/__DATE__/$(DATE)/g > $@
and.conf.5: and.conf.5.man
cat $< | \
sed s/__VERSION__/$(VERSION)/g | \
sed s/__DATE__/$(DATE)/g > $@
and.priorities.5: and.priorities.5.man
cat $< | \
sed s/__VERSION__/$(VERSION)/g | \
sed s/__DATE__/$(DATE)/g > $@
#
# Install and under $(PREFIX)/bin etc.
#
install: and $(INITSCRIPT)
strip and
#-mkdir $(PREFIX)
-mkdir -p $(DESTDIR)$(INSTALL_SBIN)
-mkdir -p $(DESTDIR)$(INSTALL_ETC)
-mkdir -p $(DESTDIR)$(INSTALL_INITD)
-mkdir -p $(DESTDIR)$(INSTALL_MAN)/man5
-mkdir -p $(DESTDIR)$(INSTALL_MAN)/man8
$(INSTALL) -m 0755 and $(DESTDIR)$(INSTALL_SBIN)
test -e $(DESTDIR)$(INSTALL_ETC)/and.conf || \
$(INSTALL) -m 0644 and.conf $(DESTDIR)$(INSTALL_ETC)
test -e $(DESTDIR)$(INSTALL_ETC)/and.priorities || \
$(INSTALL) -m 0644 and.priorities $(DESTDIR)$(INSTALL_ETC)
ifneq (${INITSCRIPT},)
ifneq (${INSTALL_INITD},)
@echo "Installing SysV script in $(DESTDIR)$(INSTALL_INITD)"
$(INSTALL) -m 0755 $(INITSCRIPT) $(DESTDIR)$(INSTALL_INITD)/and
else
@echo "Installing SysV script in $(DESTDIR)$(INSTALL_SBIN)"
$(INSTALL) -m 0755 $(INITSCRIPT) $(DESTDIR)$(INSTALL_SBIN)
@echo "Installing SysV init.d finder in $(DESTDIR)$(INSTALL_SBIN)"
$(INSTALL) -m 0755 and-find-init.d $(DESTDIR)$(INSTALL_SBIN)
endif
endif
$(INSTALL) -m 0644 and.8 $(DESTDIR)$(INSTALL_MAN)/man8
$(INSTALL) -m 0644 and.conf.5 $(DESTDIR)$(INSTALL_MAN)/man5
$(INSTALL) -m 0644 and.priorities.5 $(DESTDIR)$(INSTALL_MAN)/man5
simpleinstall: and and.init
strip and
mkdir -p $(DESTDIR)$(INSTALL_SBIN) $(DESTDIR)$(INSTALL_ETC)
mkdir -p $(DESTDIR)$(INSTALL_INITD)
mkdir -p $(DESTDIR)$(INSTALL_MAN)/man5 $(DESTDIR)$(INSTALL_MAN)/man8
cp and $(DESTDIR)$(INSTALL_SBIN)
test -e $(DESTDIR)$(INSTALL_ETC)/and.conf || \
cp and.conf $(DESTDIR)$(INSTALL_ETC)
test -e $(DESTDIR)$(INSTALL_ETC)/and.priorities || \
cp and.priorities $(DESTDIR)$(INSTALL_ETC)
ifneq (${INITSCRIPT},) # on SysV only
cp $(INITSCRIPT) $(DESTDIR)$(INSTALL_INITD)/and
endif
cp and.8 $(DESTDIR)$(INSTALL_MAN)/man8
cp and.conf.5 $(DESTDIR)$(INSTALL_MAN)/man5
cp and.priorities.5 $(DESTDIR)$(INSTALL_MAN)/man5
uninstall:
rm -f $(DESTDIR)$(INSTALL_SBIN)/and
rm -f $(DESTDIR)$(INSTALL_INITD)/and
rm -f $(DESTDIR)$(INSTALL_ETC)/and.conf
rm -f $(DESTDIR)$(INSTALL_ETC)/and.priorities
rm -f $(DESTDIR)$(INSTALL_MAN)/man8/and.8
rm -f $(DESTDIR)$(INSTALL_MAN)/man5/and.conf.5
rm -f $(DESTDIR)$(INSTALL_MAN)/man5/and.priorities.5
#
# Clean up generated files.
#
clean:
rm -f *.o and and.init $(MANPAGES)
distclean: clean
find . -name \*~ -exec rm \{\} \;
README for the Auto Nice Daemon, AND
------------------------------------
The auto nice daemon will renice or even kill jobs according to a priority
database, after they take up too much CPU time. (You define what "too much"
actually means.) Refer to the man pages, and(8), and.conf(5), and
and.priorities(5), for details and instructions, and check the home page,
http://and.sourceforge.net/.
Platforms:
Digital UNIX 4.0, 5.1
FreeBSD 4.x
IRIX and IRIX64
Linux 2.2.x and 2.4.x
OpenBSD 2.7+
Solaris 5.6
Requires:
GNU make
ANSI C Compiler
Documentation and Download:
http://and.sourceforge.net/
Author:
Patrick Schemitz <schemitz@users.sourceforge.net>
Credits:
SRPM spec file help by Terje Rosten <terjeros@phys.ntnu.no>
Linux/AXP jiffies to seconds fix by Markus Lischka
<Markus_Lischka@physik.tu-muenchen.de>
Debian package, Debian init script, Debian Makefile patches
by Andras Bali <bali@debian.org>
Debian Makefile patch by Mikael Andersson <mikan@mikan.net>
The guys at INTEXXIA, http://www.intexxia.com, noticed a
format string vulnerability and provided me with a patch.
Pauli K. Borodulin <boro@fixel.net> pointed out that overwriting
existing config files when doing make install was rude. He is
right.
Janet Casey <jcasey@gnu.org> noticed and reported that the LICENSE
file was truncated.
Dan Stromberg <strombrg@nis.acs.uci.edu> pointed out that
the Digital UNIX version, and-OSF1.c, works virtually unchanged
on IRIX, IRIX64 and Solaris (SunOS).
"Quake2" <quake2@vladimir.eso.nu> pointed out that
the OpenBSD version works virtually unchanged on FreeBSD.
Marcelo Matus <mmatus@dinha.acms.arizona.edu> sent a patch for
problems with very long running processes (alread longer than 248
days when auto nice daemon is started), and other issues.
Dr. Hans Ekkehard Plesser <hans.ekkehard.plesser@nlh.no> came up with
the idea of also examining a process' parent, as well as with the
minuid and mingid configuration options.
Both xavier@rootshell.be and Jerome Warnier <jwarnier@beeznest.net>
noticed that the Linux version accounted for usr time only; Xavier
also provided a (one-line) fix. (Solaris, IRIX, and Tru 64 already
did this.)
Installation:
Edit the Makefile, which is well documented. (g)make. (g)make install.
(make simpleinstall if you don't have install(1) (which you really
should). Edit the configuration files, /etc/and.conf and
/etc/and.priorities. Start /usr/local/sbin/and. You must run it as
root if you want it to renice or kill any jobs but your own; on all
platforms but Linux, not even dummy mode will work for mortal users.
That's due to the way process information is accessible under these
Unices. (Linux is more generous here, which can be seen as both an
advantage and a security flaw. I'm not conclusive on this topic.)
Last updated:
This document was last updated 2004/03/06 by Patrick Schemitz
<schemitz@users.sourceforge.net>
/*
AND auto nice daemon - renice programs according to their CPU usage.
Copyright (C) 1999-2003 Patrick Schemitz <schemitz@users.sourceforge.net>
http://and.sourceforge.net/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
#include <syslog.h>
#include <sys/stat.h>
#include <signal.h>
#include <asm/param.h> /* kernel interrupt frequency: HZ */
#include "and.h"
/*
AND -- auto-nice daemon/Linux version.
Linux-specific AND version. Makes excessive use of the Linux
/proc filesystem and is not portable.
1999-2003 Patrick Schemitz, <schemitz@users.sourceforge.net>
http://and.sourceforge.net/
*/
static DIR *linux_procdir = 0;
static struct and_procent linux_proc;
int linux_readproc (char *fn)
{
/* Scan /proc/<pid>/stat file. Format described in proc(5).
l1: pid comm state ppid
l2: pgrp session tty tpgid
l3: flags minflt cminflt majflt cmajflt
l4: utime stime cutime cstime
l5: counter priority
*/
FILE* f;
int i;
long li;
long unsigned u, ujf, sjf;
char state;
char buffer [1024];
if (!(f = fopen(fn,"rt"))) return 0;
fscanf(f,"%d %1023s %c %d",&(linux_proc.pid),buffer,&state,&(linux_proc.ppid));
fscanf(f,"%d %d %d %d",&i,&i,&i,&i);
fscanf(f,"%lu %lu %lu %lu %lu",&u,&u,&u,&u,&u);
fscanf(f,"%lu %lu %ld %ld",&ujf,&sjf,&li,&li);
fscanf(f,"%ld %d",&li,&(linux_proc.nice));
i = feof(f);
fclose(f);
if (i) return 0;
if (state == 'Z') return 0; /* ignore zombies */
ujf += sjf; /* take into account both usr and sys time */
ujf /= HZ; /* convert jiffies to seconds */
linux_proc.utime = ujf > INT_MAX ? INT_MAX: (int) ujf;
buffer[strlen(buffer)-1] = 0; /* remove () around command name */
strncpy(linux_proc.command,&buffer[1],1023);
linux_proc.command[1023] = 0;
and_printf(3, "Linux: process %s pid: %d ppid: %d\n",
linux_proc.command, linux_proc.pid, linux_proc.ppid);
return 1;
}
struct and_procent *linux_getnext ()
{
char name [1024];
struct dirent *entry;
struct stat dirstat;
if (!linux_procdir) return NULL;
while ((entry = readdir(linux_procdir)) != NULL) { /* omit . .. apm bus... */
if (isdigit(entry->d_name[0])) break;
}
if (!entry) return NULL;
snprintf(name, 1024, "/proc/%s/stat",entry->d_name);
/* stat() file to get uid/gid */
if (stat(name,&dirstat)) return linux_getnext();
/* read the job's stat "file" to get command, nice level, etc */
if (!linux_readproc(name)) return linux_getnext();
linux_proc.uid = dirstat.st_uid;
linux_proc.gid = dirstat.st_gid;
return &linux_proc;
}
struct and_procent *linux_getfirst ()
{
if (linux_procdir) {
rewinddir(linux_procdir);
} else {
linux_procdir = opendir("/proc");
if (!linux_procdir) {
and_printf(0,"cannot open /proc, aborting.\n");
abort();
}
}
return linux_getnext();
}
int main (int argc, char** argv)
{
and_setprocreader(&linux_getfirst,&linux_getnext);
return and_main(argc,argv);
}
/*
AND auto nice daemon - renice programs according to their CPU usage.
Copyright (C) 1999-2001 Patrick Schemitz <schemitz@users.sourceforge.net>
http://and.sourceforge.net/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <sys/procfs.h>
#include <sys/times.h>
#include <sys/file.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <signal.h>
#include <math.h>
#include <sys/stat.h>
#include "and.h"
/*
AND -- auto-nice daemon/Digital UNIX(OSF/1) version.
OSF/1-specific AND version. Makes reasonable use of the OSF/1
/proc filesystem and seems to be more portable than I thought.
Also works for Solaris (SunOS 5) and IRIX/IRIX64. (Thanks to
Dan Stromberg for telling me.)
2000, 2001 Patrick Schemitz, <schemitz@users.sourceforge.net>
http://and.sourceforge.net/
*/
static DIR *digitalunix_procdir = 0;
static struct and_procent digitalunix_proc;
int digitalunix_readproc (char *fn)
{
prpsinfo_t ps;
double cputime;
int res, fd;
if ((fd = open(fn, O_RDONLY)) < 0) return 0;
res = ioctl(fd, PIOCPSINFO, &ps);
close(fd);
if (res < 0) return 0;
digitalunix_proc.uid = ps.pr_uid;
digitalunix_proc.gid = ps.pr_gid;
digitalunix_proc.ppid = ps.pr_ppid;
strncpy(digitalunix_proc.command,ps.pr_fname,1022);
digitalunix_proc.command[1023] = 0;
cputime = (double)ps.pr_time.tv_sec + (double)ps.pr_time.tv_nsec / 1.0E9;
digitalunix_proc.utime = (int)cputime;
digitalunix_proc.pid = ps.pr_pid;
digitalunix_proc.nice = getpriority(PRIO_PROCESS, ps.pr_pid);
/*
printf("%5i %-20s %5i %3i\n", digitalunix_proc.pid,
digitalunix_proc.command, digitalunix_proc.utime,
digitalunix_proc.nice);
*/
and_printf(3, "OSF/1: process: %s pid: %d ppid: %d\n",
digitalunix_proc.command,
digitalunix_proc.pid,
digitalunix_proc.ppid);
return 1;
}
struct and_procent *digitalunix_getnext ()
{
char name [1024];
struct dirent* entry;
struct stat dirstat;
if (!digitalunix_procdir) return NULL;
while ((entry = readdir(digitalunix_procdir)) != NULL) {
if (!isdigit(entry->d_name[0])) continue;
sprintf(name,"/proc/%s",entry->d_name);
if (access(name, R_OK) < 0) {
and_printf(0,"read access denied: /proc/%s\n",entry->d_name);
continue;
}
break;
}
if (!entry) return NULL;
if (!digitalunix_readproc(name)) return NULL;
return &digitalunix_proc;
}
struct and_procent *digitalunix_getfirst ()
{
if (digitalunix_procdir) {
rewinddir(digitalunix_procdir);
} else {
digitalunix_procdir = opendir("/proc");
if (!digitalunix_procdir) {
and_printf(0,"/proc: cannot open /proc. Aborting.\n");
abort();
}
}
return digitalunix_getnext();
}
int main (int argc, char** argv)
{
and_setprocreader(&digitalunix_getfirst,&digitalunix_getnext);
return and_main(argc,argv);
}
/*
AND auto nice daemon - renice programs according to their CPU usage.
Copyright (C) 1999-2001 Patrick Schemitz <schemitz@users.sourceforge.net>
http://and.sourceforge.net/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <kvm.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/resourcevar.h>
#ifdef __FreeBSD__
#include <sys/user.h>
#endif