diff --git a/sensors/and/CHANGELOG b/sensors/and/CHANGELOG new file mode 100644 index 0000000000000000000000000000000000000000..4d448c866a65c9c97c7dac762f5e74230607c8f5 --- /dev/null +++ b/sensors/and/CHANGELOG @@ -0,0 +1,74 @@ +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 diff --git a/sensors/and/LICENSE b/sensors/and/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..5b6e7c66c276e7610d4a73c70ec1a1f7c1003259 --- /dev/null +++ b/sensors/and/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/sensors/and/Makefile b/sensors/and/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5bf4f78052c8f66514f1fc46620b61ecda814564 --- /dev/null +++ b/sensors/and/Makefile @@ -0,0 +1,279 @@ +# +# 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 \{\} \; diff --git a/sensors/and/README b/sensors/and/README new file mode 100644 index 0000000000000000000000000000000000000000..6efbe68412c131e3ea9ed9e411974cb75f2d48e0 --- /dev/null +++ b/sensors/and/README @@ -0,0 +1,90 @@ +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> diff --git a/sensors/and/and-Linux.c b/sensors/and/and-Linux.c new file mode 100644 index 0000000000000000000000000000000000000000..25657afa81915471879af6d844ef838b44526a81 --- /dev/null +++ b/sensors/and/and-Linux.c @@ -0,0 +1,135 @@ +/* + + 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); +} diff --git a/sensors/and/and-OSF1.c b/sensors/and/and-OSF1.c new file mode 100644 index 0000000000000000000000000000000000000000..558c098b806506e23d9042042cde785975f82488 --- /dev/null +++ b/sensors/and/and-OSF1.c @@ -0,0 +1,139 @@ +/* + + 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); +} diff --git a/sensors/and/and-OpenBSD.c b/sensors/and/and-OpenBSD.c new file mode 100644 index 0000000000000000000000000000000000000000..fb4565041a5e6022a3174a66b21d5f22ae66fc9c --- /dev/null +++ b/sensors/and/and-OpenBSD.c @@ -0,0 +1,142 @@ +/* + + 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 + + +#include "and.h" + + +/* + + AND -- auto-nice daemon/OpenBSD version. + + OpenBSD-specific AND version. Makes excessive use of the OpenBSD + kernel memory interface, kvm, but also works for FreeBSD. + + 2000, 2002 Patrick Schemitz, <schemitz@users.sourceforge.net> + http://and.sourceforge.net/ + +*/ + + +static kvm_t *openbsd_kvm = NULL; +static struct kinfo_proc *openbsd_pt = NULL; +static int openbsd_nproc = 0; +static int openbsd_next = 0; +static long openbsd_hz = -1; + + +static struct and_procent openbsd_proc; + + +static int openbsd_init () +{ + struct nlist nlst [] = { + { "_hz" }, + { 0 } + }; + kvm_nlist(openbsd_kvm,nlst); + if (nlst[0].n_type == 0) { + and_printf(0,"KVM: nlist failed. Aborting.\n"); + abort(); + } + if (kvm_read(openbsd_kvm,nlst[0].n_value,(char*)(&openbsd_hz), + sizeof(openbsd_hz)) != sizeof(openbsd_hz)) { + and_printf(0,"KVM: hz symbol empty. Aborting.\n"); + abort(); + } + return 1; +} + + +struct and_procent *openbsd_getnext () +{ + if (!openbsd_pt) { + and_printf(0,"KVM: no process table (late detection). Aborting.\n"); + abort(); + } + if (openbsd_next >= openbsd_nproc) return NULL; + strncpy(openbsd_proc.command,openbsd_pt[openbsd_next].kp_proc.p_comm,1023); + openbsd_proc.command[1023] = 0; + openbsd_proc.pid = openbsd_pt[openbsd_next].kp_proc.p_pid; + openbsd_proc.ppid = openbsd_pt[openbsd_next].kp_proc.p_ppid; /* FIXME that correct? */ + openbsd_proc.nice = openbsd_pt[openbsd_next].kp_proc.p_nice-20; + openbsd_proc.uid = openbsd_pt[openbsd_next].kp_eproc.e_pcred.p_ruid; + openbsd_proc.gid = openbsd_pt[openbsd_next].kp_eproc.e_pcred.p_rgid; + /* Adapted from top(1) port, as found in the misc@openbsd.org archive */ + openbsd_proc.utime = (openbsd_pt[openbsd_next].kp_proc.p_uticks + + openbsd_pt[openbsd_next].kp_proc.p_sticks + + openbsd_pt[openbsd_next].kp_proc.p_iticks) + / openbsd_hz; + /* + printf("%-20s %5i %3i %i\n",openbsd_proc.command,openbsd_proc.pid, + openbsd_proc.nice,openbsd_proc.utime); + */ + and_printf(3, "OpenBSD: process %s pid: %d ppid: %d\n", + openbsd_proc.command, openbsd_proc.pid, openbsd_proc.ppid); + openbsd_next++; + return &openbsd_proc; +} + + +struct and_procent *openbsd_getfirst () +{ + char errmsg [_POSIX2_LINE_MAX]; + if (!openbsd_kvm) { + openbsd_kvm = kvm_openfiles(NULL,NULL,NULL,O_RDONLY,errmsg); + if (!openbsd_kvm) { + and_printf(0,"KVM: cannot open (\"%s\"). Aborting.\n",errmsg); + abort(); + } + openbsd_init(); + } + openbsd_pt = kvm_getprocs(openbsd_kvm,KERN_PROC_ALL,0,&openbsd_nproc); + if (!openbsd_pt) { + and_printf(0,"KVM: cannot retrieve process table. Aborting.\n"); + abort(); + } + openbsd_next = 0; + return openbsd_getnext(); +} + + +int main (int argc, char** argv) +{ + and_setprocreader(&openbsd_getfirst,&openbsd_getnext); + return and_main(argc,argv); +} diff --git a/sensors/and/and.8.man b/sensors/and/and.8.man new file mode 100644 index 0000000000000000000000000000000000000000..418177615b87bc6677b6bcacaff5a6d2bdeba392 --- /dev/null +++ b/sensors/and/and.8.man @@ -0,0 +1,146 @@ +.TH AND 8 "__DATE__" "Unix" "Administrator's Tools" + +.SH "NAME" +and \- auto nice daemon + +.SH "SYNOPSIS" +.B and +.RB [ \-htvsx ] +.RB [ \-i +.IR interval ] +.RB [ \-c +.IR /path/to/and.conf ] +.RB [ \-d +.IR /path/to/and.priorities ] + + +.SH "VERSION" +This manual page documents +.B and +version __VERSION__. + +.SH "DESCRIPTION" +The auto nice daemon activates itself in certain intervals and renices and +even kills jobs according to their priority and CPU usage. + +Renice levels and kill signals can be defined in terms of users, groups, +and commands. Wildcards can be specified for any of these. In addition, +commands can be specified using POSIX regular expressions. To allow for +network-wide configuration and priority files, a mechanism for hostname-based +evaluation is provided, again supporting regular expressions for specifying +host names. + +Jobs owned by root are left alone. Jobs are never increased in their priority. + +Here are some real-world examples: + +A certain user is notorious for wasting CPU with next-to-irrelevant jobs. +One line is sufficient to renice all of his jobs to about 19. +This is a typical situation for a LART (Luser's Attitude Readjustment Tool) +like +.B and. + +A CPU server is dedicated to a certain group, but others may also use +it when it's idle. Just define default nice levels of e.g. 18 and a lower +nice level for the privilegued group, say nice level 12. + +A certain web browser who shall remain unnamed tends to go berserk once +in a while. You can configure +.B and +to kill -9 it after e.g. 20 CPU minutes. + + +.SH "COMMAND\-LINE OPTIONS" + +.TP 0.5i +.B \-c /path/to/and.conf +Specifies the configuration file. If this flag is omitted, +.I /etc/and.conf +is used instead. + +.TP 0.5i +.B \-d /path/to/and.priorities +Specifies the priority database file. If this flag is omitted, +.I /etc/and.priorities +is used instead. + +.TP 0.5i +.B \-h +Produces a short help text. + +.TP 0.5i +.B \-i interval +Sets the interval between nice level checks. This flag overrides the +interval specified in the configuration file, if any. The default interval of +.I 60 +seconds is used if neither -i nor an interval directive in the configuration +file is given. + +.TP 0.5i +.B \-s +Log to stdout. Without this switch, logging goes to syslog (normal +operations) or +.I ./debug.and +(test mode). Useful for debugging config files. + +.TP 0.5i +.B \-t +Run in test mode only, i.e. don't really renice or kill anything. +In this mode, logging goes into +.I ./debug.and +instead of syslog. + +.TP 0.5i +.B \-v +Increase verbosity. For maximum verbosity, this flag can be specified +multiple times. Be warned that this will blow up your log files, so +you should use it in test mode only. + +.TP 0.5i +.B \-x +Run in full operational mode, i.e. really renice or kill things. +This is the default. + +.SH "SIGNALS" + +On +.B kill -HUP +the auto nice daemon will reload its configuration file and priority +database. + + +.SH "FILES" + +.TP 0.5i +.B /etc/and.conf +General configuration file. Stores default nice level, default interval, +the "time zones" and the database lookup affinity. + +.TP 0.5i +.B /etc/and.priorities +The priority database (in plain text). Contains the (user, group, command, +nicelevels) tuples. + +.TP 0.5i +Both files have their own manual pages. + +.TP 0.5i +.B ./debug.and +Contains logging and status information for debugging purposes. +Used in test mode only. + +.SH "SEE ALSO" +.BR and.conf (5), +.BR and.priorities (5), +.BR kill (1), +.BR regex (7), +.BR renice (8) + + +.SH "INTERNET" +.B http://and.sourceforge.net/ + + +.SH "AUTHOR" +The auto nice daemon and this manual page were written by +Patrick Schemitz <schemitz@users.sourceforge.net> diff --git a/sensors/and/and.c b/sensors/and/and.c new file mode 100644 index 0000000000000000000000000000000000000000..54933b785a251e4148478874a070872f9317f115 --- /dev/null +++ b/sensors/and/and.c @@ -0,0 +1,993 @@ +/* + + AND auto nice daemon - renice programs according to their CPU usage. + Copyright (C) 1999-2004 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 + +*/ + +/************************************************************************ + * * + * and.c -- AND library for platform-independent code. * + * * + * Automatically renice jobs when they use too much CPU time. * + * * + * 1999-2004 Patrick Schemitz <schemitz@users.sourceforge.net> * + * http://and.sourceforge.net/ * + * * + ***********************************************************************/ + +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <pwd.h> +#include <grp.h> +#include <syslog.h> +#include <time.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/types.h> +#include <signal.h> +#include <regex.h> +#include <values.h> + +#define DEBUG 0 + +/* OpenBSD getopt() is in unistd.h; Linux and Digital UNIX have getopt.h */ +#if !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__svr4__) && !defined(__SunOS__) +#include <getopt.h> +#endif + +/* GNU C library forgets to declare this one: */ +#ifdef __GNUC__ +int vsnprintf (char *str, size_t n, const char *format, va_list ap); +#define HAVE_VSNPRINTF +#endif + +#include "and.h" + + + +#ifndef DEFAULT_NICE +#define DEFAULT_NICE 0 +#endif + +#ifndef LOG_PERROR +#define LOG_PERROR 0 +#endif + +#ifndef DEFAULT_INTERVAL +#define DEFAULT_INTERVAL 60 +#endif + +#ifndef DEFAULT_CONFIG_FILE +#define DEFAULT_CONFIG_FILE "/etc/and.conf" +#endif + +#ifndef DEFAULT_DATABASE_FILE +#define DEFAULT_DATABASE_FILE "/etc/and.priorities" +#endif + +#ifndef AND_VERSION +#define AND_VERSION "1.0.7 or above (not compiled in)" +#endif + +#ifndef AND_DATE +#define AND_DATE "27 Jan 2002 or later (not compiled in)" +#endif + + +#define bool char +#define false (0) +#define true (!false) + + +/* Maximum entries in priority database. You may change this, + if you have a really large priority database. However, you + shouldn't make too large databases since the get_priority() + function takes too long otherwise. */ + +#define PRI_MAXENTRIES 100 + + +/* Indices for the weight array when resolving a user/group/command/parent + tuple to get the correct priority database entry. These are + constants. Never ever change them! Change the affinity in the + config file instead. */ + +enum { + PRI_U, PRI_G, PRI_C, PRI_P, PRI_N +}; + + +/* Priority database entry record. Consists of the user ID, the + group ID, the command (string and compiled regexp), the parent + (string and compiled regexp), and three nice levels. */ + +#define PARENT_ONLY 0 +#define PARENT_AND_ANCHESTORS 1 + +#define PARENT_ONLY_KEYWORD "parent=" +#define PARENT_AND_ANCHESTORS_KEYWORD "ancestor=" + +struct priority_db_entry { + int uid; + int gid; + char command_str [128]; + regex_t *command; + char parent_str [128]; + regex_t *parent; + int parentmode; + int nl [3]; +}; + + +/* Global variables for priority database (db), configuration (conf), + and other arguments (args). */ + +struct{ + int n; + struct priority_db_entry entry [PRI_MAXENTRIES]; +} and_db; + + + +/* AND configuration data. Some of this is compiled in; for some things + there are command-line options, and some is read from and.conf */ + +struct { + char hostname [512]; + int test; + char *program; + char *config_file; + char *database_file; + int verbose; + int to_stdout; + int nice_default; + bool lock_interval; + unsigned interval; + unsigned time_mark [3]; + char affinity [5]; + int weight [PRI_N]; + int min_uid; + int min_gid; +} and_config; + + + +/* Initialise configuration parameters. Some are later over- + ridden by command-line arguments and and.conf. */ + +void set_defaults (int argc, char **argv) +{ + and_config.test = 0; + and_config.verbose = 0; + and_config.to_stdout = 0; + and_config.program = argv[0]; + and_config.lock_interval = false; + and_config.interval = DEFAULT_INTERVAL; + and_config.config_file = DEFAULT_CONFIG_FILE; + and_config.database_file = DEFAULT_DATABASE_FILE; + and_config.nice_default = DEFAULT_NICE; + and_config.min_uid = 0; + and_config.min_gid = 0; + gethostname(and_config.hostname,511); + and_config.hostname[511] = 0; +} + + + +/* Log AND messages (to ./debug.and if in test mode, syslog() otherwise). + If available, uses non-ANSI function vsnprintf() to avoid possible + buffer overflow. */ + +void and_printf (int required_verbosity, char *fmt, ...) +{ + va_list args; + static int syslog_open = 0; + static FILE *out = NULL; + char buffer [2048]; + time_t t; + va_start(args,fmt); + if (and_config.verbose >= required_verbosity) + { + if (and_config.test) { + /* in test mode, create log file; use stderr on failure */ + if (!and_config.to_stdout && !out) { + out = fopen("./debug.and","wt"); + if (!out) { + out = stderr; + } + } + /* write time stamp to ./debug.and */ + t = time(NULL); + strncpy(buffer,ctime(&t),2047); + buffer[strlen(buffer)-1] = ' '; + if (and_config.to_stdout) + fputs(buffer,stdout); + else + fputs(buffer,out); + } + /* build actual log message */ +#ifdef HAVE_VSNPRINTF + vsnprintf(buffer,2048,fmt,args); +#else + vsprintf(buffer,fmt,args); /* ... and hope for the best :( */ + buffer[2047] = 0; +#endif + if (and_config.to_stdout) { + fputs(buffer,stdout); + fflush(stdout); + } else { + if (and_config.test) { + /* log to ./debug.and in test mode */ + fputs(buffer,out); + fflush(out); + } else { + /* write to syslog if in full operations */ + if (!syslog_open) { + openlog(and_config.program,LOG_PERROR|LOG_PID,LOG_DAEMON); + syslog_open = 1; + } + syslog(LOG_WARNING,"%s",buffer); + } + } + } + va_end(args); +} + + +/* Print priority database. */ + +void print_priorities () +{ + int i; + and_printf(0,"Priority database:\n"); + and_printf(0,"UID: GID: Command Parent: NLs:\n"); + for (i=0; i<and_db.n; i++) { + and_printf(0,"%5i %5i %-20s %-20s %-13s %2i,%2i,%2i\n", + and_db.entry[i].uid, and_db.entry[i].gid, + and_db.entry[i].command_str, + and_db.entry[i].parent_str, + (and_db.entry[i].parentmode == PARENT_ONLY ? "(parent)" : "(ancestors)"), + and_db.entry[i].nl[0], + and_db.entry[i].nl[1], and_db.entry[i].nl[2]); + } + and_printf(0,"%i entries.\n\n",and_db.n); +} + + +/* Print configuration parameters. */ + +void print_config () +{ + and_printf(0,"Configuration parameters:\n" + "host name: %s\n" + "operational mode: %s\n" + "verbosity: %2i\n" + "default nicelevel: %2i\n" + "interval [sec]: %3u\n" + "level 0 from [sec]: %3u\n" + "level 1 from [sec]: %3u\n" + "level 2 from [sec]: %3u\n" + "minimum uid: %i\n" + "minimum gid: %i\n" + "affinity: %s\n" + " U: %i\n" + " G: %i\n" + " C: %i\n" + " P: %i\n\n", + and_config.hostname, + (and_config.test?"just checkin'":"I'm serious."), + and_config.verbose, + and_config.nice_default, and_config.interval, + and_config.time_mark[0], and_config.time_mark[1], + and_config.time_mark[2], + and_config.min_uid, and_config.min_gid, + and_config.affinity, + and_config.weight[PRI_U], and_config.weight[PRI_G], + and_config.weight[PRI_C], and_config.weight[PRI_P]); +} + + +/* Parse one line of the priority database */ + +void read_priorities () +{ + FILE *priority; + int bad_count, line_count; + char buffer [1024]; + /* entry field */ + int uid; + char uid_s [1024]; + int gid; + char gid_s [1024]; + char command [1024]; + int parentmode; + char parent [1024]; + char parent_s [1024]; + int nl0, nl1, nl2; + /* auxillary structs */ + struct passwd *lookup_p; + struct group *lookup_g; + int error; + char error_msg [1024]; + int i, entry; + int linelen; + regex_t *rex; + bool section_matches = true; + + if ((priority = fopen(and_config.database_file,"rt")) == 0) { + and_printf(0,"Priority database %s not found. Aborting.\n", + and_config.database_file); + abort(); + } + and_printf(0,"Priority database is: %s\n", and_config.database_file); + /* Read file line by line */ + line_count = bad_count = 0; + and_db.n = 0; + while (!feof(priority)) { + memset(buffer,0,1024); + if (fgets(buffer,1022,priority) == 0) break; + line_count++; + /* Intercept empty lines, comments, and overflows */ + linelen = strlen(buffer); + if (linelen == 0) { + continue; + } + if (buffer[0] == 10 || buffer[0] == 13 || buffer[0] == '#') { + continue; + } + if (linelen > 1022) { + and_printf(0,"Priority database line %i too long: %s\n", + line_count, buffer); + bad_count++; + continue; + } + /* Handle host-specific parts */ + if ((buffer[0] == 'o') && (buffer[1] == 'n') && (buffer[2] == ' ')) { + while (buffer[strlen(buffer)-1] < 32) { + buffer[strlen(buffer)-1] = 0; + } + rex = (regex_t*)malloc(sizeof(regex_t)); + regcomp(rex,&buffer[3],REG_NOSUB|REG_EXTENDED); + section_matches = (regexec(rex,and_config.hostname,0,0,0) == 0); + and_printf(0,"Priority database line %i: section for host(s) %s will be %s.\n", + line_count, &buffer[3], (section_matches?"read":"skipped")); + regfree(rex); + continue; + } + if (!section_matches) { + continue; + } + i = sscanf(buffer, "%s %s %s %s %i %i %i", + uid_s, gid_s, command, parent_s, &nl0, &nl1, &nl2); + if (i != 7) { + and_printf(0,"Priority database line %i is invalid: %s\n", + line_count, buffer); + bad_count++; + continue; + } + /* Identify UID */ + if (strcmp(uid_s,"*") == 0) { + uid = -1; + } else if ((lookup_p = getpwnam(uid_s)) != 0) { + uid = lookup_p->pw_uid; + } else if ((i = atoi(uid_s)) > 0) { + uid = i; + } else { + and_printf(0,"Priority database line %i with invalid UID: %s\n", + line_count, uid_s); + bad_count++; + continue; + } + /* Identify GID */ + if (strcmp(gid_s,"*") == 0) { + gid = -1; + } else if ((lookup_g = getgrnam(gid_s)) != 0) { + gid = lookup_g->gr_gid; + } else if ((i = atoi(gid_s)) > 0) { + gid = i; + } else { + and_printf(0,"Priority database line %i with invalid GID: %s\n", + line_count, gid_s); + bad_count++; + continue; + } + /* figure parent mode */ + if (strcmp(parent_s,"*") == 0) { + strcpy(parent,"*"); + parentmode = PARENT_ONLY; + } else if (strncmp(parent_s,PARENT_ONLY_KEYWORD, + strlen(PARENT_ONLY_KEYWORD)) == 0) { + strcpy(parent,&parent_s[strlen(PARENT_ONLY_KEYWORD)]); + parentmode = PARENT_ONLY; + } else if (strncmp(parent_s,PARENT_AND_ANCHESTORS_KEYWORD, + strlen(PARENT_AND_ANCHESTORS_KEYWORD)) == 0) { + strcpy(parent,&parent_s[strlen(PARENT_AND_ANCHESTORS_KEYWORD)]); + parentmode = PARENT_AND_ANCHESTORS; + } else { + and_printf(0,"Priority database line %i with bad parent keyword: %s\n", + line_count, parent_s); + bad_count++; + continue; + } + /* Find entry in database */ + entry = and_db.n; + for (i=0; i<and_db.n; ++i) { + if (and_db.entry[i].uid == uid && and_db.entry[i].gid == gid + && strcmp(and_db.entry[i].command_str,command) == 0 + && strcmp(and_db.entry[i].parent_str,parent) == 0) { + entry = i; + break; + } + } + /* If not recycling an entry (i.e. overwriting the priorities), + rebuild the regular expression */ + if (!and_db.entry[entry].command) { + and_db.entry[entry].uid = uid; + and_db.entry[entry].gid = gid; + and_db.entry[entry].command = (regex_t*)malloc(sizeof(regex_t)); + error = regcomp(and_db.entry[entry].command,command,REG_NOSUB); + if (error) { + regerror(error,and_db.entry[entry].command,error_msg,1023); + regfree(and_db.entry[entry].command); + free(and_db.entry[entry].command); + and_db.entry[entry].command = NULL; + and_printf(0,"Priority database line %i with bad command regexp %s (%s)\n", + line_count, command, error_msg); + bad_count++; + continue; + } + strncpy(and_db.entry[entry].command_str,command,127); + and_db.entry[entry].command_str[127] = 0; + and_db.entry[entry].parent = (regex_t*)malloc(sizeof(regex_t)); + error = regcomp(and_db.entry[entry].parent,parent,REG_NOSUB); + if (error) { + regerror(error,and_db.entry[entry].parent,error_msg,1023); + regfree(and_db.entry[entry].parent); + free(and_db.entry[entry].parent); + and_db.entry[entry].parent = NULL; + and_printf(0,"Priority database line %i with bad parent regexp %s (%s)\n", + line_count, parent, error_msg); + bad_count++; + continue; + } + strncpy(and_db.entry[entry].parent_str,parent,127); + and_db.entry[entry].parent_str[127] = 0; + and_db.entry[entry].parentmode = parentmode; + } + and_db.entry[entry].nl[0] = nl0; + and_db.entry[entry].nl[1] = nl1; + and_db.entry[entry].nl[2] = nl2; + if (entry == and_db.n) { + and_db.n++; + } + } + /* cleanup */ + fclose(priority); + if (and_config.verbose > 1) { + print_priorities(); + } + if (bad_count) { + and_printf(0,"Priority database contains %i bad lines. Aborting.\n", + bad_count); + abort(); + } +} + + +void read_config () +{ + FILE *f; + int i, val, bad, bad_f, line, u, g, c, p; + unsigned uval; + char buffer [1024]; + char param [1024]; + char value [1024]; + regex_t *rex; + bool section_matches = true; + if ((f = fopen(and_config.config_file,"rt")) == 0) { + and_printf(0,"Configuration file %s not found. Aborting.\n", + and_config.config_file); + abort(); + } + and_printf(0,"Configuration file is: %s\n", and_config.config_file); + /* Set defaults */ + strcpy(and_config.affinity,"ugcp"); + and_config.weight[PRI_U] = 8; + and_config.weight[PRI_G] = 4; + and_config.weight[PRI_C] = 2; + and_config.weight[PRI_P] = 1; + and_config.time_mark[0] = 120; /* 2 min */ + and_config.time_mark[1] = 1200; /* 20 min */ + and_config.time_mark[2] = 3600; /* 60 min */ + /* Read file line by line */ + line = 0; + bad = 0; + fgets(buffer,1023,f); + while (!feof(f)) { + ++line; + if (buffer[0] == 10 || buffer[0] == 13 || buffer[0] == '#') { + memset(buffer,0,1024); + if (fgets(buffer,1022,f) == 0) break; + continue; + } + if ((buffer[0] == 'o') && (buffer[1] == 'n') && (buffer[2] == ' ')) { + while (buffer[strlen(buffer)-1] < 32) { + buffer[strlen(buffer)-1] = 0; + } + rex = (regex_t*)malloc(sizeof(regex_t)); + regcomp(rex,&buffer[3],REG_NOSUB|REG_EXTENDED); + section_matches = (regexec(rex,and_config.hostname,0,0,0) == 0); + and_printf(0,"Configuration file line %i: section for host(s) %s will be %s.\n", + line, &buffer[3], (section_matches?"read":"skipped")); + regfree(rex); + buffer[0] = '#'; /* trigger read next line */ + continue; + } + if (!section_matches) { + buffer[0] = '#'; /* trigger read next line */ + continue; + } + if (sscanf(buffer,"%s %s",param,value) != 2) { + ++bad; + and_printf(0,"Configuration file line %i is invalid: %s\n", + line, buffer); + memset(buffer,0,1024); + if (fgets(buffer,1022,f) == 0) break; + continue; + } + if (sscanf(value,"%i",&val) != 1) val = -1; + if (sscanf(value,"%u",&uval) != 1) uval = UINT_MAX; + if (strcmp(param,"defaultnice")==0) { + if (val > -1) /* Prohibits a default is kill policy */ + and_config.nice_default = val; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for defaultnice: %s.\n", + line, value); + } + } else if (strcmp(param,"interval")==0) { + if (and_config.lock_interval) { + and_printf(0,"Configuration file line %i: interval locked by -i command-line option.\n", + line); + } else { + if (uval < UINT_MAX) + and_config.interval = uval; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for interval: %s.\n", + line, value); + } + } + } else if (strcmp(param,"minuid")==0) { + if (uval < UINT_MAX) + and_config.min_uid = uval; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for minuid: %s.\n", + line, value); + } + } else if (strcmp(param,"mingid")==0) { + if (uval < UINT_MAX) + and_config.min_gid = uval; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for mingid: %s.\n", + line, value); + } + } else if (strcmp(param,"lv1time")==0) { + if (uval < UINT_MAX) + and_config.time_mark[0] = uval; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for lv1time: %s.\n", + line, value); + } + } else if (strcmp(param,"lv2time")==0) { + if (uval < UINT_MAX) + and_config.time_mark[1] = uval; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for lv2time: %s.\n", + line, value); + } + } else if (strcmp(param,"lv3time")==0) { + if (uval < UINT_MAX) + and_config.time_mark[2] = uval; + else { + ++bad; + and_printf(0,"Configuration file line %i has invalid value for lv3time: %s.\n", + line, value); + } + } else if (strcmp(param,"affinity")==0) { + bad_f = -1; + u = g = c = p = 0; + if (strlen(value) != 4) { + and_printf(0,"Configuration file line %i has invalid affinity: %s.\n", + line, value); + ++bad; + } else { + for (i=0; i<4; i++) { + switch(value[3-i]) { + case 'u': + if (!u) u = and_config.weight[PRI_U] = 1 << i; + else bad_f = i; + break; + case 'g': + if (!g) g = and_config.weight[PRI_G] = 1 << i; + else bad_f = i; + break; + case 'c': + if (!c) c = and_config.weight[PRI_C] = 1 << i; + else bad_f = i; + break; + case 'p': + if (!p) p = and_config.weight[PRI_P] = 1 << i; + else bad_f = i; + break; + default: + bad_f = 3-i; + } + } + if (bad_f > -1) { + and_printf(0,"Configuration file line %i has invalid affinity: %s[%i]=%c.\n", + line, value, bad_f, value[bad_f]); + ++bad; + } else { + strncpy(and_config.affinity,value,4); + and_config.affinity[4] = 0; + } + } + } else { + ++bad; + and_printf(0,"Configuration file line %i has invalid parameter: %s.\n", + line, param); + } + memset(buffer,0,1024); + if (fgets(buffer,1022,f) == 0) break; + } + /* Cleanup, exit on errors. */ + fclose(f); + if (and_config.verbose > 1) print_config(); + if (bad) { + and_printf(0,"Configuration file contains %i bad lines. Aborting.\n", + bad); + abort(); + } +} + + +/* Compute new nice level for given command/uid/gid/utime */ + +int and_getnice (int uid, int gid, char *command, struct and_procent *parent, unsigned cpu_seconds) +{ + int i, level, entry, exact = -1, last; + struct and_procent *par; + int exactness [PRI_MAXENTRIES]; + if (!command) { + and_printf(0,"Process without command string encountered. Aborting.\n"); + abort(); + } + if (uid == 0) { + and_printf(3,"root is untouchable: %s\n", command); + return 0; + } + if (uid < and_config.min_uid) { + and_printf(3,"uid %i is untouchable: %s\n", uid, command); + return 0; + } + if (gid < and_config.min_gid) { + and_printf(3,"gid %i is untouchable: %s\n", gid, command); + return 0; + } + + /* Strategy: each priority database accumulates accuracy points + for every aspect: user, group, command, parent. An exact hit is + worth the configured weight of the aspect (1, 2, 4, 8); a joker + is worth 0; and a miss is with -MAXINT, effectively eliminating + the entry (veto). At the end, the highest rated entry is + used to determine the new nice level. */ + for (i=0; i<and_db.n; i++) { + /* user id */ + if (uid == and_db.entry[i].uid) { + exactness[i] = and_config.weight[PRI_U]; + } else if (and_db.entry[i].uid == -1) { + exactness[i] = 0; + } else { + exactness[i] = -MAXINT; + } + /* group id */ + if (gid == and_db.entry[i].gid) { + exactness[i] += and_config.weight[PRI_G]; + } else if (and_db.entry[i].gid == -1) { + exactness[i] += 0; + } else { + exactness[i] = -MAXINT; + } + /* command */ + if (command!=NULL && regexec(and_db.entry[i].command,command,0,0,0) == 0) { + exactness[i] += and_config.weight[PRI_C]; + } else if (strcmp(and_db.entry[i].command_str,"*") == 0) { + exactness[i] += 0; + } else { + exactness[i] = -MAXINT; + } + /* parent */ + par = parent; + while (par != NULL) + { + last = (and_db.entry[i].parentmode == PARENT_ONLY || + par->parent == NULL); + if (regexec(and_db.entry[i].parent,par->command,0,0,0) == 0) { + exactness[i] += and_config.weight[PRI_P]; + break; + } else if (last && strcmp(and_db.entry[i].parent_str,"*") == 0) { + exactness[i] += 0; + break; + } else if (last) { + exactness[i] = -MAXINT; + break; + } + par = par->parent; + } + } + entry = 0; + exact = -1; + for (i=0; i<and_db.n; i++) { + if (exactness[i] >= exact) { + /* >exact -> first entry wins, >=exact -> last entry wins */ + entry = i; + exact = exactness[i]; + } + } + if (exact < 0) { + and_printf(2,"no match for uid=%i gid=%i cmd=%s\n par=%s\n", + uid, gid, command, (parent!=NULL?parent->command:"(orphan)")); + return and_config.nice_default; + } + level = 2; + while (level >= 0 && and_config.time_mark[level] > cpu_seconds) { + --level; + } + and_printf(2,"command=%s (%i,%i,%s) hit on entry=%i, exactness=%i, level=%i.\n", + command, uid, gid, (parent!=NULL?parent->command:"(orphan)"), + entry, exact, level); + return (level >= 0 ? and_db.entry[entry].nl[level] : 0); +} + + + +/********************************************************************** + + **********************************************************************/ + + + +static struct and_procent *(*and_getfirst)() = NULL; +static struct and_procent *(*and_getnext)() = NULL; + + +void and_setprocreader (struct and_procent *(*getfirst)(), + struct and_procent *(*getnext)()) +{ + and_getfirst = getfirst; + and_getnext = getnext; +} + + +struct and_procent* and_find_proc (struct and_procent *head, int ppid) +{ + struct and_procent *current = head; + while (current != NULL) + { + if (current->pid == ppid) + return current; + current = current->next; + } + and_printf(1,"no parent for ppid: %d\n", ppid); + return NULL; +} + + +void and_loop () +{ + struct and_procent *head, *current, *new, *proc; + int newnice; + int njobs = 0; + assert(and_getfirst != NULL); + assert(and_getnext != NULL); + head = NULL; + current = NULL; + proc = and_getfirst(); + while (proc != NULL) { + new = (struct and_procent*)malloc(sizeof(struct and_procent)); + memcpy(new,proc,sizeof(struct and_procent)); + new->next = NULL; + if (current != NULL) { + current->next = new; + } else { + head = new; + } + current = new; + proc = and_getnext(); + } + current = head; + while (current != NULL) { + if (current->pid != current->ppid) + current->parent = and_find_proc(head,current->ppid); + else + current->parent = NULL; + and_printf(2, "process %s parent : %s\n", current->command, + (current->parent != NULL ? current->parent->command : "(none)")); + current = current->next; + } + current = head; + while (current != NULL) { + njobs++; + newnice = and_getnice(current->uid,current->gid,current->command, + current->parent,current->utime); + if (current->uid != 0) { + if (newnice) { + if (newnice > 0) { + if (newnice > current->nice) { + if (and_config.test) + and_printf(0,"would renice to %i: %i (%s)\n",newnice,current->pid, + current->command); + else { + and_printf(1,"renice to %i: %i (%s)\n",newnice,current->pid, + current->command); + setpriority(PRIO_PROCESS,current->pid,newnice); + } + } + } else { + if (and_config.test) + and_printf(0,"would kill %i %i (%s)\n",newnice,current->pid, + current->command); + else { + and_printf(1,"kill %i %i (%s)\n",newnice,current->pid, + current->command); + kill(current->pid,-newnice); + } + } + } + } + current = current->next; + } + current = head; + while (current != NULL) { + proc = current; + current = current->next; + free(proc); + } +} + + +void and_getopt (int argc, char** argv) +{ +#define OPTIONS "c:d:i:vstxh" + int opt, value; + opt = getopt(argc,argv,OPTIONS); + while (opt != -1) { + switch(opt) { + case 'c': + and_config.config_file = (char*)malloc(strlen(optarg)+1); + assert(and_config.config_file); + strcpy(and_config.config_file,optarg); + break; + case 'd': + and_config.database_file = (char*)malloc(strlen(optarg)+1); + assert(and_config.database_file); + strcpy(and_config.database_file,optarg); + break; + case 'i': + value = atoi(optarg); + if (value > 0) { + and_config.lock_interval = true; + and_config.interval = value; + } else { + fprintf(stderr,"%s: illegal interval: %s\n",argv[0],optarg); + exit(1); + } + break; + case 's': + and_config.to_stdout = 1; + break; + case 'v': + ++and_config.verbose; + break; + case 't': + and_config.test = 1; + break; + case 'x': + and_config.test = 0; + break; + case 'h': + printf("auto nice daemon version %s (%s)\n" + "%s [-v] [-s] [-t] [-x] [-c configfile] [-d databasefile] [-i interval]\n" + "-v: verbosity -v, -vv, -vvv etc\n" + "-s: log to stdout (default is syslog, or debug.and)\n" + "-x: really execute renices and kills (default)\n" + "-t: test configuration (don't really renice)\n" + "-i interval: loop interval in seconds (default %i)\n" + "-c configfile: specify config file (default %s)\n" + "-d databasefile: specify priority database file (default %s)\n" + ,AND_VERSION,AND_DATE,argv[0], + DEFAULT_INTERVAL, DEFAULT_CONFIG_FILE, DEFAULT_DATABASE_FILE); + exit(1); + default: + fprintf(stderr,"Try %s -h for help.\n", argv[0]); + exit(1); + } + opt = getopt(argc,argv,OPTIONS); + } +#undef OPTIONS +} + + +static int g_reload_conf; + + +void and_trigger_readconf (int sig) +{ + g_reload_conf = (sig == SIGHUP); +} + + +void and_readconf () +{ + and_printf(0,"Re-reading configuration and priority database...\n"); + read_config(); + read_priorities(); + g_reload_conf = 0; +} + + +void and_worker () +{ + read_config(); + read_priorities(); + signal(SIGHUP,and_trigger_readconf); + and_printf(0,"AND ready.\n"); + g_reload_conf = 0; + while (1) { + if (g_reload_conf) { + and_readconf(); + } + and_loop(); + sleep(and_config.interval); + } +} + + +int and_main (int argc, char** argv) +{ + set_defaults(argc,argv); + and_getopt(argc,argv); + if (and_config.test) { + and_worker(); + } else { + if (fork() == 0) and_worker(); + } + return 0; +} + diff --git a/sensors/and/and.conf b/sensors/and/and.conf new file mode 100644 index 0000000000000000000000000000000000000000..e8e38e61e8133e9e6e0372dd2402287bb1c3964b --- /dev/null +++ b/sensors/and/and.conf @@ -0,0 +1,61 @@ +# +# Sample configuration file for the auto nice daemon, /etc/and.conf +# +# Comments must have the # in the *first* column! +# +# Read and.conf(5) for details. +# +# 1999, 2000, 2004 Patrick Schemitz, schemitz@users.sourceforge.net +# + +# +# Nice level for jobs that are not in and.priorities. +# 0 = do not renice. +# +defaultnice 0 + +# +# Time interval between renice cycles, in seconds. Default is +# 60 seconds. +# +interval 60 + +# +# Ranges for the nice levels. Jobs with less than lv1time seconds +# CPU time are not reniced; jobs between lv1time and lv2time seconds +# are reniced to the first level in an.priorities; jobs between +# lv2time and lv3time seconds to the second level; jobs with more +# than lv3time seconds are reniced to the third level. +# +lv1time 120 +lv2time 1200 +lv3time 3600 + +# +# Hosts molasses, snail, and snore are pretty slow, so be gentle when +# renicing, since a CPU minute isn't really very much computations here. +# +#on (molasses|snail|snore) +#lv1time 300 +#lv2time 1800 +#lv3time 3600 +#on .* + +# +# Strategy for picking the right priority entry for a user/group/job +# triple. The strategy is a permutation of "cgu", "c"ommand, "g"roup, +# "u"ser. The order specifies the affinity of the priority lookup +# method. "cug" means an exact match of the command has priority +# over an exact match of the user or group. See the documentation +# for more details. +# +affinity cpug + +# +# Minimum user/group id to be even considered for renicing. Processes +# with lower user/group id are ignored. This does not affect root +# (user id 0), which is never, ever reniced. +# +minuid 1 +mingid 1 + diff --git a/sensors/and/and.conf.5.man b/sensors/and/and.conf.5.man new file mode 100644 index 0000000000000000000000000000000000000000..ac575734888f8cf4751c7786651fe2d6af6b2c9a --- /dev/null +++ b/sensors/and/and.conf.5.man @@ -0,0 +1,241 @@ +.TH AND.CONF 5 "__DATE__" "Unix" "File Formats" + +.SH "NAME" +/etc/and.conf \- general configuration parameters for the +auto nice daemon. + + +.SH "VERSION" +This manual page documents and.conf for +.B and +version __VERSION__. + + +.SH "DESCRIPTION" +This is the general configuration file for +.B and. +It stores settings like the default nice level, the renice intervals, +the three stages of renicing, and the affinity of the priority database, +i.e. the weight of (user, group, command) when resolving nice levels +from the database. These settings are described below. + +Comments start with a # in the +.B first column. +Empty lines are ignored. Unlike with other configuration files, lines +.B cannot be concatenated +with a backslash. Furthermore, this file is +.B case sensitive. + +.B and +allows for host-specific sections in the configuration file. These work +as lines of the form +.I on somehost +and work as follows: the parser determines if the host name (as returned +by gethostname) matches the extended regular expression that follows the +.I on +keyword. If it does, it just keeps processing the file as if nothing had +happened. If it does not match, however, everything up to the next +.I on +keyword is skipped. So if you want to end a host-specific section, you +must write +.I on .* +(which matches all hosts) to switch back to normal. + +Don't forget to +.B kill -HUP +the auto nice daemon to enable the changes. + + +.SH "SETTINGS" + +.TP 0.5i +.B defaultnice +The default nice level. A number between 0 and 19. Jobs for which no +entry can be found in +.I /etc/and.priorities +are reniced to this level, regardless of the CPU time they've used +so far. If you prefer to renice unknown jobs gradually, you can do +so by supplying three asterisks as (user, group, command) tuple in +.I /etc/and.priorities. +The default nice level is +.I 0 + +.TP 0.5i +.B interval +The default interval between nice checks of the auto nice daemon, +in seconds. This value can be overridden by the +.I -i +command-line option of +.B and. +The default interval is +.I 60 +seconds. + +.TP 0.5i +.B lv1time +.TP 0.5i +.B lv2time +.TP 0.5i +.B lv3time +Ranges for the nice levels. Jobs with less than lv1time seconds +CPU time are not reniced; jobs between lv1time and lv2time seconds +are reniced to the first level in an.priorities; jobs between +lv2time and lv3time seconds to the second level; jobs with more +than lv3time seconds are reniced to the third level. +Defaults are +.I 120 +, +.I 1200 +, and +.I 3600 +seconds. + +.TP 0.5i +.B minuid, mingid +Minimum user id and group id to be considered for renicing. +Processes whose user id is below +.I minuid +are left alone, as are processes with a group id of below +.I mingid. +(Note that even if you set minuid to zero, root processes are +left alone.) + +.TP 0.5i +.B affinity +Strategy for picking the right priority entry for a user/group/job +triple. The strategy is a permutation of "cgu", "c"ommand, "g"roup, +"u"ser. The order specifies the affinity of the priority lookup +method. Suppose you have an entry for all jobs of user +.I foo, +another entry for all jobs of group +.I bar, +and yet another entry for the command +.I baz. +Furthermore suppose user +.I foo +(who happens to belong to group +.I bar +) starts a job named +.I baz +-- which entry should be chosen? This is what the affinity setting +means, for example "cug" means an exact match of the command has priority +over both an exact match of the user and the group. The default affinity is +"cug", which is probably sensible for most cases, since it's the job +which takes up CPU time, not the user or group ID. + + +.SH "EXAMPLES" + +.TP 0.5i +.B Default Configuration +# This is the default configuration: +.br +default 0 +.br +interval 60 +.br +lv1time 300 +.br +lv2time 1800 +.br +lv3time 3600 +.br +affinity cug +.br +minuid 0 +.br +mingid 0 +.br + +.TP 0.5i +.B Default Configuration, with terminals +# Normal default configuration for all +.br +default 0 +.br +interval 60 +.br +lv1time 300 +.br +lv2time 1800 +.br +lv3time 3600 +.br +# Hosts foo, bar, baz are terminals and must +.br +# be more responsive, so earlier renice. +.br +on (foo|bar) +.br +lv1time 120 +.br +lv2time 600 +.br +lv3time 1200 +.br +on .* +.br +# This is for all hosts again +.br +affinity cug +.br + +.TP 0.5i +.B Group-specific Hosts +.br +default 0 +.br +interval 60 +.br +lv1time 300 +.br +lv2time 1800 +.br +lv3time 3600 +.br +# Normal affinity for all hosts. +.br +affinity cug +.br +# Hosts bar, baz belong to group foo, which +.br +# is privilegued on these hosts, so override +.br +# affinity. (Note regexp!) +.br +on ba[rz] +.br +affinity guc +.br +on .* +.br +minuid 500 +.br +mingid 100 +.br + + +.SH "FILES" + +.TP 0.5i +.B /etc/and.conf +General configuration file. Stores default nice level, default interval, +the "time zones" and the database lookup affinity. This is what this +manual page is about. + + +.SH "SEE ALSO" +.BR and (8), +.BR and.priorities (5), +.BR kill (1), +.BR regex (7), +.BR renice (8) + + +.SH "INTERNET" +.B http://and.sourceforge.net/ + + +.SH "AUTHOR" +The auto nice daemon and this manual page were written by +Patrick Schemitz <schemitz@users.sourceforge.net> diff --git a/sensors/and/and.h b/sensors/and/and.h new file mode 100644 index 0000000000000000000000000000000000000000..7b1108f462cb0bb9db385eadae7101f2dc85b8ce --- /dev/null +++ b/sensors/and/and.h @@ -0,0 +1,93 @@ +/* + + AND auto nice daemon - renice programs according to their CPU usage. + Copyright (C) 1999-2004 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 + +*/ + +#ifndef AND_H +#define AND_H + + +/************************************************************************ + * * + * and.h -- AND library for platform-independent code. * + * * + * 1999, 2004 Patrick Schemitz <schemitz@users.sourceforge.net> * + * http://and.sourceforge.net/ * + * * + ***********************************************************************/ + + +/* + * and_procent -- process entry. + * + * AND-relevant information on a process. + */ +struct and_procent { + /* to be filled by and-$OS.c: */ + int pid; + int ppid; + int uid; + int gid; + int nice; + unsigned utime; + char command [1024]; + /* to be filled by and.c: */ + struct and_procent *parent; + struct and_procent *next; +}; + + +/* + * and_printf() - log message. + * + * Logs a message (in printf() format), either to stderr, or to syslog(), + * depending on AND operational mode. In test mode (and -t), stderr is + * used; syslog() otherwise. Use this to report any O/S-specific problems. + * Log is suppressed if the current verbosity level is below the required + * one. + */ +void and_printf (int required_verbosity, char *fmt, ...); + + +/* + * and_setprocreader() -- set O/S specific handler for reading processes. + * + * getfirst and getnext are two functions returning a pointer to an + * and_procent, or NULL if no more processes are available. The implementation + * of these two functions are O/S specific. For Linux, reading through the + * /proc filesystem is most suitable. See and-linux.c for a sample + * implementation. + * + * Note: it is getfirst's task to also clean up any remainders of former + * calls to getfirst and getnext, such as open DIR*. + */ +void and_setprocreader (struct and_procent *(*getfirst)(), + struct and_procent *(*getnext)()); + + +/* + * and_main() -- start the AND. + * + * Takes over control. Call this after setting the and_procreader(). + */ +int and_main (int argc, char** argv); + + +#endif diff --git a/sensors/and/and.init.debian b/sensors/and/and.init.debian new file mode 100644 index 0000000000000000000000000000000000000000..c09deee5ff411fd2894201f39ea674bedea08713 --- /dev/null +++ b/sensors/and/and.init.debian @@ -0,0 +1,55 @@ +#! /bin/sh +# +# and Launch auto nice daemon +# +# Written by Miquel van Smoorenburg <miquels@cistron.nl>. +# Modified for Debian GNU/Linux by Ian Murdock <imurdock@gnu.ai.mit.edu>. +# Modified for and by Andras Bali <bali@debian.org> +# + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/and +NAME=and +DESC="auto nice daemon" + +test -f $DAEMON || exit 0 + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --background --nicelevel -19 \ + --make-pidfile --pidfile /var/run/$NAME.pid \ + --exec $DAEMON >/dev/null 2>&1 + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON && rm -f /var/run/$NAME.pid + echo "$NAME." + ;; + reload|force-reload) + echo "Reloading $DESC configuration files." + start-stop-daemon --stop --signal 1 --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON >/dev/null 2>&1 + ;; + restart) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON && rm -f /var/run/$NAME.pid + sleep 1 + start-stop-daemon --start --quiet --background --nicelevel -19 \ + --make-pidfile --pidfile /var/run/$NAME.pid \ + --exec $DAEMON >/dev/null 2>&1 + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/sensors/and/and.priorities b/sensors/and/and.priorities new file mode 100644 index 0000000000000000000000000000000000000000..7724e84d29f5554d83091e2a12800e9eaf6fad26 --- /dev/null +++ b/sensors/and/and.priorities @@ -0,0 +1,108 @@ +# +# Sample priority database for the auto-nice daemon, /etc/and.priorities +# +# Comments must have the # in the _first_ column! +# +# File format: +# user group job parent nice1 nice2 nice3 +# - user: user name or user id or * for all +# - group: group name or group id or * for all +# - job: executable (without path; may be a regexp) or * for all +# - parent: keyword "parent=" or "ancestor=" followed by the +# executable (without path; may be a regexp), or * for all +# - nice1, nice2, nice3: nice levels for CPU usage ranges. +# +# At least one of user or group must be an asterisk *. +# +# After /etc/and.conf:lv1time seconds matching jobs are niced to nice1, +# after /etc/and.conf:lv2time to nice2 and after /etc/and.conf:lv3time +# to nice3. +# +# Read and.priorities(5) for details. +# +# 1999, 2000, 2004 Patrick Schemitz, schemitz@users.sourceforge.net +# + +# +# Philosophy: +# +# Hold down notorious troublemakers (Netscape, colourful screensavers, ...) +# and leave other jobs alone. (Within reason, that is.) +# Note that a perceptive user might rename his jobs' executables to +# obtain higher privilegue. So the values must be sensible to that. +# For instance, noone with his mind right would rename his computation- +# intensive job to "gcc" to avoid renicing after two minutes, since +# gcc is reniced to 19 after just another 18 minutes... +# + +# +# Default entry -- moderate renicing, priority always above screen savers. +# +* * * * 4 8 12 + +# +# Jobs started by the Grid master process always run on 10. If someone +# else besides User grid starts a (fake, presumably) Grid master, kill it +# at once: it's a fraud! The real Grid master, of course, is left alone. +# +#* * * ancestor=grid_nanny 10 10 10 +#* * grid_nanny * -9 -9 -9 +#grid * grid_nanny * 0 0 0 + +# +# Jobs of the local user are treated more nicely. The local user is +# identified by the fact that her programs are started by the login +# screen, kdm or xdm in this case. +# +* * * ancestor=[xk]dm 2 2 2 + +# +# The hosts bar and baz are reserved for the foo group, so +# prefer them over other groups. +# +#on (bar|baz) +#* foo * * 4 8 12 +#* * * * 12 16 18 +#on .* + +# +# Our special friend, user dau, tends to thresh machines with long- +# running unniced jobs... we do not appreciate this behaviour. A little +# punishment might be in order. +# +#dau * * * 12 16 18 + +# +# Netscape -- more than 20 minutes probably means it's running berserk, +# so we just kill it off. +# +* * .*netscape.* * 2 -9 -9 + +# +# Compilers -- don't renice them the first 20 minutes, but then... +# After an hour of compilation for one single source file, there +# *is* something wrong. +# ld and make shouldn't use more than 2 minutes themselves, so we +# just leave them to the default. +# +* * gcc * 0 19 -9 +* * g++ * 0 19 -9 +* * g77 * 0 19 -9 +* * cc1 * 0 19 -9 + +# +# Screen savers -- low priority from the beginning, but enough to log in. +# KDE screen savers all end with .kss. +# +* * xlock.* * 15 15 15 +* * .*\.kss * 15 15 15 + +# +# System monitors -- don't monitor the system useless. +# +* * .*top * 15 15 15 +* * .*xosview.* * 15 15 15 +* * .*xps * 15 15 15 +* * .*qps * 15 15 15 +* * .*ktop * 15 15 15 +* * .*gtop * 15 15 15 diff --git a/sensors/and/and.priorities.5.man b/sensors/and/and.priorities.5.man new file mode 100644 index 0000000000000000000000000000000000000000..c3fd799e23b67d66ea394da356cf68e33b286f93 --- /dev/null +++ b/sensors/and/and.priorities.5.man @@ -0,0 +1,209 @@ +.TH AND.PRIORITIES 5 "__DATE__" "Unix" "File Formats" + +.SH "NAME" +/etc/and.priorities \- priority database for the auto nice daemon. + + +.SH "VERSION" +This manual page documents and.priorities for +.B and +version __VERSION__. + + +.SH "DESCRIPTION" +This is the priority database file for +.B and. +It stores (user, group, command, parent, nicelevels) tuples (hereafter called +entries) to determine the new nice level (or the kill signal, for that +matter) when a job reaches one of the time limits defined in +.I /etc/and.conf. +(See lv1time, lv2time, and lv3time on the and.conf manual page for +details.) See the +.B affinity +setting in +.I /etc/and.conf +for how ambiguities between the fields (user, group, command, parent) +are dealt with when searching the database to determine the new nice +level for a job. +Note that if more than one entry matches with the same accuracy (e.g. +with a parent= entry and an ancestor= entry), the +.B last entry wins! + +Comments start with a # in the +.B first column. +Empty lines are ignored. Unlike with other configuration files, lines +.B cannot be concatenated +with a backslash. Furthermore, this file is +.B case sensitive. + +.B and +allows for host-specific sections in the configuration file. These work +as lines of the form +.I on somehost +and work as follows: the parser determines if the host name (as returned +by gethostname) matches the extended regular expression that follows the +.I on +keyword. If it does, it just keeps processing the file as if nothing had +happened. If it does not match, however, everything up to the next +.I on +keyword is skipped. So if you want to end a host-specific section, you +must write +.I on .* +(which matches all hosts) to switch back to normal. + +Don't forget to +.B kill -HUP +the auto nice daemon to enable the changes. + + +.SH "SETTINGS" + +A valid entry consists of a line of six columns, separated by one or +more spaces. These columns are: (in that order) + +.TP 0.5i +.B user +The user ID the command is running under. May be a user name (which will +be looked up in the password file and, if enabled, via NIS), or a numeric +user ID, or an asterisk for any user. + +.TP 0.5i +.B group +The group ID the command is running under. May be a group name (which will +be looked up in the group file and again, if enabled, via NIS), or a numeric +group ID, or an asterisk for any group. + +.TP 0.5i +.B command +The name of the command, without path. May be a command, a regular +expression to match multiple commands, or an asterisk for any command. +Note that "foobar" will +.B not +match "/usr/bin/foobar" - you probably mean ".*foobar" or even ".*foobar.*". + +.TP 0.5i +.B parent +There are two modes of operation for the parent field, determined by a +keyword: +.B parent=foobar +will match if a process' direct parent process matches the command or regular +expression after the equal sign, whereas +.B ancestor=foobar +will match if +.I any +ancestor process matches. After the keyword and the equal sign goes the +name of the parent process, without path. May be a command, a regular +expression to match multiple commands, or an asterisk for any command. +(You can just use the asterisk if you want to ignore parents for this +entry.) Note that again "foobar" will +.B not +match "/usr/bin/foobar", as with command. + +.TP 0.5i +.B nicelevel 1 +The nice level after lv1time CPU time was used by the command. Positive +numbers and 0 are interpreted as nice levels; negative numbers are +interpreted as signals to be sent to the command. A "nice level" of +19 will almost stop the job, -9 will actually kill it. (Like in kill -9.) +lv1time can be set in +.I /etc/and.conf + +.TP 0.5i +.B nicelevel 2 +Same but after lv2time. + +.TP 0.5i +.B nicelevel 3 +Same but after lv3time. + + +.SH "EXAMPLES" + +Here are some entries from the real world (i.e. from "my" cluster +at the Institute). As lv[123]time, 5 min., 20 min., and 1 hour is +assumed. (Which is the default. See +.I /etc/and.conf +for details.) You might also check the default priority database +that comes with +.B and. + + +# A finer default nice level +.br +* * * * 4 8 12 +.br + +# User dau is an idiot, so treat him like accordingly +.br +dau * * * 19 19 19 +.br + +# Netscape sometimes goes berserk, we must stop it +.br +* * netscape * 4 -9 -9 +.br + +# Most hosts are free for everyone but some are +.br +# especially for the FOO group +.br +* * * * 4 8 12 +.br +on (bar|baz) +.br +* * * * 8 12 16 +.br +# ... or, more radical: * * * * -9 -9 -9 +.br +* foo * * 4 8 12 +.br +on .* +.br + +# KDE screen savers... +.br +* * .*kss * 16 16 16 +.br + +# Grid jobs (assuming they are started by a master +.br +# process) +.br +* * * ancestor=grid_master 10 10 10 +.br +# Now some clever yet deceitful user might start all +.br +# his jobs using a shell script named grid_master. +.br +# He shall regret... whereas the original grid_master +.br +# (owned by grid) is left alone. +.br +* * grid_master * -9 -9 -9 +.br +grid * grid_master * 0 0 0 +.br + +.SH "FILES" + +.TP 0.5i +.B /etc/and.priorities +The priority database (in plain text). Contains the (user, group, command, +nicelevels) tuples. This is what this manual page is about. + + +.SH "SEE ALSO" +.BR and (8), +.BR and.conf (5), +.BR kill (1), +.BR regex (7), +.BR renice (8) + + +.SH "INTERNET" +.B http://and.sourceforge.net/ + + +.SH "AUTHOR" +The auto nice daemon and this manual page were written by +Patrick Schemitz <schemitz@users.sourceforge.net> diff --git a/sensors/and/and.spec b/sensors/and/and.spec new file mode 100644 index 0000000000000000000000000000000000000000..20123e5f6e39e3338980a1c900d1992c9aece109 --- /dev/null +++ b/sensors/and/and.spec @@ -0,0 +1,64 @@ +Name: and +Version: 1.2.0 +Release: 1 +Summary: Auto nice daemon +Vendor: Patrick Schemitz <schemitz@users.sourceforge.net> +Copyright: GPL +Group: Daemons +Buildroot: /var/tmp/%{name}-buildroot +Source: http://and.sourceforge.net/%{name}-%{version}.tar.gz +URL: http://and.sourceforge.net +Prefix: %{_prefix} +ExclusiveOS: linux + +%description +The auto nice daemon renices and even kills jobs according to their CPU time, +owner, and command name. This is especially useful on production machines with +lots of concurrent CPU-intensive jobs and users that tend to forget to +nice their jobs. + +%prep +rm -rf %{buildroot} +%setup -q +make PREFIX=%{_prefix} \ + INSTALL_ETC=/etc \ + INSTALL_INITD= \ + INSTALL_SBIN=%{_sbindir} \ + INSTALL_MAN=%{_mandir} + +%install +mkdir -p %{buildroot}/etc +mkdir -p %{buildroot}$initddir +mkdir -p %{buildroot}%{_sbindir} +mkdir -p %{buildroot}%{_mandir}/man8 +mkdir -p %{buildroot}%{_mandir}/man5 +make PREFIX=%{buildroot}%{_prefix} \ + INSTALL_ETC=%{buildroot}/etc \ + INSTALL_INITD= \ + INSTALL_SBIN=%{buildroot}%{_sbindir} \ + INSTALL_MAN=%{buildroot}%{_mandir} install + +%clean +rm -rf %{buildroot} + +%pre + +%post +initddir=`%{_sbindir}/and-find-init.d` +ln -sf %{_sbindir}/and.init $initddir/and +/sbin/chkconfig --add and + +%preun +%{_sbindir}/and.init stop > /dev/null 2>&1 +/sbin/chkconfig --del and +initddir=`%{_sbindir}/and-find-init.d` +rm -f $initddir/and + +%postun + +%files +%defattr(-,root,root) +%doc README LICENSE CHANGELOG +%config(noreplace) /etc/and.* +%{_sbindir}/* +%{_mandir}/*/* diff --git a/sensors/and/and.startup b/sensors/and/and.startup new file mode 100644 index 0000000000000000000000000000000000000000..ea4d968b51ee35e2543dea22f03dad8973748ac2 --- /dev/null +++ b/sensors/and/and.startup @@ -0,0 +1,57 @@ +#!/bin/sh +# +# /etc/rc.d/init.d/and, /sbin/init.d/and, /etc/init.d/and +# +# SysV init.d compliant startup script for auto nice daemon. +# +# 1999, 2000, 2001 Patrick Schemitz <schemitz@users.sourceforge.net> +# http://and.sourceforge.net/ +# +# chkconfig: 2345 90 10 +# description: automatically renice and kill jobs. +# +# processname: and +# config: /etc/and.conf +# + +AND_FLAGS="" +test -r /etc/rc.config && . /etc/rc.config + +case "$1" in + start) + echo -n "Starting auto nice daemon:" + INSTALL_SBIN/and $AND_FLAGS >&/dev/null + ps axuw | grep -v grep | grep INSTALL_SBIN/and >/dev/null + if [ $? = 0 ]; then + echo " done" + exit 0 + else + echo " failed" + exit 1 + fi + ;; + stop) + echo -n "Shutting down auto nice daemon:" + uname | grep OSF1 >/dev/null || killall INSTALL_SBIN/and + echo " done" + exit 0 + ;; + restart) + $0 stop && $0 start + exit 0 + ;; + status) + echo -n "Checking for auto nice daemon: " + ps axuw | grep -v grep | grep INSTALL_SBIN/and >/dev/null + if [ $? = 0 ]; then + echo "running" + exit 0 + else + echo "no process" + exit 1 + fi + ;; + *) + echo "Usage: $0 {start|stop|status|restart}" + exit 1 +esac