and-1.2.2/0000755000076400001440000000000010221576046013272 5ustar schemitzusers00000000000000and-1.2.2/CVS/0000755000076400001440000000000010221576046013725 5ustar schemitzusers00000000000000and-1.2.2/CVS/Root0000644000076400001440000000006310221576045014571 0ustar schemitzusers00000000000000:ext:schemitz@cvs.and.sourceforge.net:/cvsroot/and and-1.2.2/CVS/Repository0000644000076400001440000000000410221576045016020 0ustar schemitzusers00000000000000and and-1.2.2/CVS/Entries0000644000076400001440000000171010221576046015260 0ustar schemitzusers00000000000000/CHANGELOG/1.14/Sun Mar 27 19:39:37 2005//Trel-1-2-2 /LICENSE/1.2/Sun Dec 16 18:08:43 2001//Trel-1-2-2 /Makefile/1.15/Sun Mar 27 19:39:37 2005//Trel-1-2-2 /README/1.10/Sun Mar 27 19:39:37 2005//Trel-1-2-2 /and-Linux.c/1.9/Sun Mar 27 19:37:47 2005//Trel-1-2-2 /and-OSF1.c/1.5/Mon Apr 5 19:17:56 2004//Trel-1-2-2 /and-OpenBSD.c/1.4/Sat Mar 6 13:34:02 2004//Trel-1-2-2 /and-find-init.d/1.1/Sun Jun 10 10:34:53 2001//Trel-1-2-2 /and.8.man/1.1/Sun Jan 27 15:59:57 2002//Trel-1-2-2 /and.c/1.18/Mon Apr 5 19:19:01 2004//Trel-1-2-2 /and.conf/1.7/Sat Mar 6 13:34:41 2004//Trel-1-2-2 /and.conf.5.man/1.3/Sun Mar 27 19:38:32 2005//Trel-1-2-2 /and.h/1.6/Sat Mar 13 20:10:35 2004//Trel-1-2-2 /and.init.debian/1.1/Sat Jul 7 19:19:21 2001//Trel-1-2-2 /and.priorities/1.9/Mon Apr 5 19:19:29 2004//Trel-1-2-2 /and.priorities.5.man/1.4/Mon Apr 5 19:19:29 2004//Trel-1-2-2 /and.spec/1.6/Sat Mar 6 13:32:48 2004//Trel-1-2-2 /and.startup/1.6/Sat Mar 6 13:32:21 2004//Trel-1-2-2 D and-1.2.2/CVS/Tag0000644000076400001440000000001310221576046014355 0ustar schemitzusers00000000000000Nrel-1-2-2 and-1.2.2/CHANGELOG0000644000076400001440000000507110221605771014505 0ustar schemitzusers00000000000000Changelog for Auto Nice Daemon ------------------------------ Changes in 1.2.2 - under some Linux variants, /proc//stat always belongs to root so use /proc/ to determine job owner/group (thanks to Jan Starzynski) - fixed minor bug in manpage (defaultnice instead of default) (thanks to Martin Braure de Calignon and Jerome Warnier) 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 and-1.2.2/LICENSE0000644000076400001440000004313107407161453014305 0ustar schemitzusers00000000000000 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. Copyright (C) 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. , 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. and-1.2.2/Makefile0000644000076400001440000001417410221605771014737 0ustar schemitzusers00000000000000# # Makefile for auto nice daemon # # 1999-2005 Patrick Schemitz # 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.2 DATE="27 Mar 2005" # # 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 \{\} \; and-1.2.2/README0000644000076400001440000000650010221605771014151 0ustar schemitzusers00000000000000README 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, 2.4.x and 2.6.x OpenBSD 2.7+ Solaris 5.6 Requires: GNU make ANSI C Compiler Documentation and Download: http://and.sourceforge.net/ Author: Patrick Schemitz Credits: SRPM spec file help by Terje Rosten Linux/AXP jiffies to seconds fix by Markus Lischka Debian package, Debian init script, Debian Makefile patches by Andras Bali Debian Makefile patch by Mikael Andersson The guys at INTEXXIA, http://www.intexxia.com, noticed a format string vulnerability and provided me with a patch. Pauli K. Borodulin pointed out that overwriting existing config files when doing make install was rude. He is right. Janet Casey noticed and reported that the LICENSE file was truncated. Dan Stromberg pointed out that the Digital UNIX version, and-OSF1.c, works virtually unchanged on IRIX, IRIX64 and Solaris (SunOS). "Quake2" pointed out that the OpenBSD version works virtually unchanged on FreeBSD. Marcelo Matus 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 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 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.) Jerome and Martin Braure de Calignon noted and fixed a minor bug in the and.conf man page (default v. defaultnice). Jan Starzynski pointed out that under some Linux variants, /proc//stat is always owned by root and thus unsuitable for obtaining the job's owner/group. He also provided a one-line fix. 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 2005/03/27 by Patrick Schemitz and-1.2.2/and-Linux.c0000644000076400001440000000742110221605613015272 0ustar schemitzusers00000000000000/* AND auto nice daemon - renice programs according to their CPU usage. Copyright (C) 1999-2003 Patrick Schemitz 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 #include #include #include #include #include #include #include #include #include #include /* 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, http://and.sourceforge.net/ */ static DIR *linux_procdir = 0; static struct and_procent linux_proc; int linux_readproc (char *fn) { /* Scan /proc//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; /* stat() /proc/ directory to get uid/gid */ snprintf(name, 1024, "/proc/%s",entry->d_name); if (stat(name,&dirstat)) return linux_getnext(); /* read the job's stat "file" to get command, nice level, etc */ snprintf(name, 1024, "/proc/%s/stat",entry->d_name); if (!linux_readproc(name)) return linux_getnext(); linux_proc.uid = dirstat.st_uid; linux_proc.gid = dirstat.st_gid; return &linux_proc; } struct and_procent *linux_getfirst () { if (linux_procdir) { rewinddir(linux_procdir); } else { linux_procdir = opendir("/proc"); if (!linux_procdir) { and_printf(0,"cannot open /proc, aborting.\n"); abort(); } } return linux_getnext(); } int main (int argc, char** argv) { and_setprocreader(&linux_getfirst,&linux_getnext); return and_main(argc,argv); } and-1.2.2/and-OSF1.c0000644000076400001440000000730010034330344014675 0ustar schemitzusers00000000000000/* AND auto nice daemon - renice programs according to their CPU usage. Copyright (C) 1999-2001 Patrick Schemitz 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, http://and.sourceforge.net/ */ static DIR *digitalunix_procdir = 0; static struct and_procent digitalunix_proc; int digitalunix_readproc (char *fn) { prpsinfo_t ps; double cputime; int res, fd; if ((fd = open(fn, O_RDONLY)) < 0) return 0; res = ioctl(fd, PIOCPSINFO, &ps); close(fd); if (res < 0) return 0; digitalunix_proc.uid = ps.pr_uid; digitalunix_proc.gid = ps.pr_gid; digitalunix_proc.ppid = ps.pr_ppid; strncpy(digitalunix_proc.command,ps.pr_fname,1022); digitalunix_proc.command[1023] = 0; cputime = (double)ps.pr_time.tv_sec + (double)ps.pr_time.tv_nsec / 1.0E9; digitalunix_proc.utime = (int)cputime; digitalunix_proc.pid = ps.pr_pid; digitalunix_proc.nice = getpriority(PRIO_PROCESS, ps.pr_pid); /* printf("%5i %-20s %5i %3i\n", digitalunix_proc.pid, digitalunix_proc.command, digitalunix_proc.utime, digitalunix_proc.nice); */ and_printf(3, "OSF/1: process: %s pid: %d ppid: %d\n", digitalunix_proc.command, digitalunix_proc.pid, digitalunix_proc.ppid); return 1; } struct and_procent *digitalunix_getnext () { char name [1024]; struct dirent* entry; struct stat dirstat; if (!digitalunix_procdir) return NULL; while ((entry = readdir(digitalunix_procdir)) != NULL) { if (!isdigit(entry->d_name[0])) continue; sprintf(name,"/proc/%s",entry->d_name); if (access(name, R_OK) < 0) { and_printf(0,"read access denied: /proc/%s\n",entry->d_name); continue; } break; } if (!entry) return NULL; if (!digitalunix_readproc(name)) return NULL; return &digitalunix_proc; } struct and_procent *digitalunix_getfirst () { if (digitalunix_procdir) { rewinddir(digitalunix_procdir); } else { digitalunix_procdir = opendir("/proc"); if (!digitalunix_procdir) { and_printf(0,"/proc: cannot open /proc. Aborting.\n"); abort(); } } return digitalunix_getnext(); } int main (int argc, char** argv) { and_setprocreader(&digitalunix_getfirst,&digitalunix_getnext); return and_main(argc,argv); } and-1.2.2/and-OpenBSD.c0000644000076400001440000000771610022351512015427 0ustar schemitzusers00000000000000/* AND auto nice daemon - renice programs according to their CPU usage. Copyright (C) 1999-2001 Patrick Schemitz 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 #include #include #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #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, 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); } and-1.2.2/and-find-init.d0000755000076400001440000000062007310646515016065 0ustar schemitzusers00000000000000#!/bin/sh # # Figure out where SysV init.d directory is. On BSD, return /tmp. # # 2001, Patrick Schemitz # # SuSE 7, Debian if [ -d /etc/init.d ]; then echo /etc/init.d exit 0 fi # SuSE 6, OSF/1 if [ -d /sbin/init.d ]; then echo /sbin/init.d exit 0 fi # Redhat 7 if [ -d /etc/rc.d/init.d ]; then echo /etc/rc.d/init.d exit 0 fi # Huh? BSD? echo /tmp exit 1 and-1.2.2/and.8.man0000644000076400001440000000701407425021775014707 0ustar schemitzusers00000000000000.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 and-1.2.2/and.c0000644000076400001440000006662410034330445014207 0ustar schemitzusers00000000000000/* AND auto nice daemon - renice programs according to their CPU usage. Copyright (C) 1999-2004 Patrick Schemitz 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 * * http://and.sourceforge.net/ * * * ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 #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 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 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; iparent == 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= 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; } and-1.2.2/and.conf0000644000076400001440000000305610022351561014677 0ustar schemitzusers00000000000000# # 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 and-1.2.2/and.conf.5.man0000644000076400001440000001161210221605670015615 0ustar schemitzusers00000000000000.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 defaultnice 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 defaultnice 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 defaultnice 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 and-1.2.2/and.h0000644000076400001440000000575410024665273014222 0ustar schemitzusers00000000000000/* AND auto nice daemon - renice programs according to their CPU usage. Copyright (C) 1999-2004 Patrick Schemitz 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 * * 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 and-1.2.2/and.init.debian0000644000076400001440000000253207321660271016145 0ustar schemitzusers00000000000000#! /bin/sh # # and Launch auto nice daemon # # Written by Miquel van Smoorenburg . # Modified for Debian GNU/Linux by Ian Murdock . # Modified for and by Andras Bali # 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 and-1.2.2/and.priorities0000644000076400001440000000637410034330501016143 0ustar schemitzusers00000000000000# # 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 and-1.2.2/and.priorities.5.man0000644000076400001440000001226510034330501017054 0ustar schemitzusers00000000000000.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 and-1.2.2/and.spec0000644000076400001440000000303410022351400014670 0ustar schemitzusers00000000000000Name: and Version: 1.2.0 Release: 1 Summary: Auto nice daemon Vendor: Patrick Schemitz 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}/*/* and-1.2.2/and.startup0000644000076400001440000000217610022351345015456 0ustar schemitzusers00000000000000#!/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 # 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