rsalz@bbn.com (Rich Salz) (06/06/91)
Submitted-by: Dikran Kassabian <deke@ee.rochester.edu> Posting-number: Volume 24, Issue 88 Archive-name: lb LB is a load-balancing program. It can check the current load on various machines on a LAN, and find the best candidate machine to accept a new job to it's run queue. Additionally, it can send the job to that machine using rsh(1). LB works best in homogeneous environments, where each machine has similar or identical file system layout. Here at the University of Rochester Department of Electrical Engineering, we have nearly 70 SUN computers, which share home-directories and local binaries. When a user sitting at a small workstation wants to run a compute intensive job, LB helps to find a machine on the network that has a low load, knowing that that machine will also have his/her home directory and required program. #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: INSTALL Makefile OTHER_SERVERS README config.h lb.1 lb.5 # rsdclnt.c srvclnt.c st_sendrecv.c stats.h # Wrapped by rsalz@litchi.bbn.com on Thu Jun 6 12:43:40 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive."' if test -f 'INSTALL' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'INSTALL'\" else echo shar: Extracting \"'INSTALL'\" \(1988 characters\) sed "s/^X//" >'INSTALL' <<'END_OF_FILE' X X LB - The Load Balancer (version 1.2) X by Dikran Kassabian X X University Of Rochester X Department of Electrical Engineering X March 3, 1991 X XINSTALLATION NOTES: X X X1. CHOOSING A SERVER X==================== XThe lb load balancer uses statistics gathered via connection with Xservers on each of the candidate machines. Two servers are supported, Xthe SUN rstatd, and Dave Curry's statsrv. The installer must see to Xit that all candidate machines support the selected server program. XIn an all SUN environment, rstatd is the better choice as it seems to Xbe somewhat faster. In other environments, it may be necessary to use Xthe statsrv server, which is public domain. X X2. BUILDING THE PROGRAM X======================= XOnce a server is selected, the Makefile must be edited to reflect the Xchoice. If rstatd is to be used, edit the Makefile definition for SERVER Xto be 'SERVER=rstatd'. If the statsrv server is to be used, make it X'SERVER=statsrv'. Check the defines in config.h, and choose the location Xof the configuration file. Remember that every machine that wants to Xuse lb needs to be able to see that configuration file. You may choose Xto use multiple copies, or a single copy that all machines can see. Once Xthe Makefile and config.h are setup to your satisfaction, type 'make'. XThe program 'lb' will be built. X X3. WRITING THE CONFIGURATION FILE X================================= XThe configuration file contains information on every machine on which lb Xmay start jobs. See the man page lb(5) for details on its setup. X X X4. INSTALLING THE FILES X======================= XInstall the program lb in a location within the path of the users requiring Xit. Good choices would include /usr/local/bin or /usr/new. Then install Xthe configuration file wherever the config.h file claimed it would be. Again, Xremember that every machine needs to have read access to this file. Finally, Xinstall the man pages lb(1) and lb(5) as appropriate. X XThat's all! X X XDeke Kassabian, 3/8/91 END_OF_FILE if test 1988 -ne `wc -c <'INSTALL'`; then echo shar: \"'INSTALL'\" unpacked with wrong size! fi # end of 'INSTALL' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(1069 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X# Makefile for "lb", the load-balancer X# ^Deke Kassabian 6/3/88, mods and additions 3/7/89 X# XSERVER=rstatd X# X#CFLAGS= -g -f68881 XCFLAGS= -O XLDFLAGS= -s X#PRINT= ptroff -man XPRINT= troff -t -man X XSRCS= rsdclnt.c srvclnt.c st_sendrecv.c stats.h config.h XMANS= lb.1 lb.5 XOBJS_SRV= srvclnt.o st_sendrecv.o XOBJS_RSD= rsdclnt.o XLIBS= -lrpcsvc X Xlb: lb.$(SERVER) X @echo "lb has been built for $(SERVER) server." X Xlb.rstatd: $(OBJS_RSD) X $(CC) $(CFLAGS) $(LDFLAGS) -o lb $(OBJS_RSD) $(LIBS) X Xlb.statsrv: $(OBJS_SRV) X $(CC) $(CFLAGS) $(LDFLAGS) -o lb $(OBJS_SRV) X Xtags: X ctags *.c > tags X Xclean: X rm -f core *.o X Xspotless: X rm -f core lb *.o X Xlove: X @echo 'not war?' X Xjoke: X @echo 'What do you want for nothing?' X Xshar: X @shar Makefile README INSTALL OTHER_SERVERS $(MANS) $(SRCS) >lb.shar X @chmod a+r lb.shar X @echo "SHAR file lb.shar created." X Xhardcopy: X lpr README INSTALL OTHER_SERVERS $(SRCS) X $(PRINT) $(MANS) | lpr -t X X# Dependencies Xlbmain.o: lbmain.c stats.h config.h Xst_sendrecv.o: st_sendrecv.c stats.h config.h Xrsdclnt.o: rsdclnt.c config.h END_OF_FILE if test 1069 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'OTHER_SERVERS' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'OTHER_SERVERS'\" else echo shar: Extracting \"'OTHER_SERVERS'\" \(1224 characters\) sed "s/^X//" >'OTHER_SERVERS' <<'END_OF_FILE' X XWHAT? No rstatd? No statsrv? Fear not. X------------------------------------------ X XLB is simple enough to modify for use with other servers. This package Xincludes client programs to talk to rstatd or statsrv, and these clients Xcan be used as templates for others. X Xstatsrv is available from comp.sources.unix archive servers. X X------------------------------------------------------------------------- XFrom the SunOS rstatd manual page: X X rstatd is a server which returns performance statistics obtained X from the kernel. The rstatd daemon is normally invoked by inetd(8C). X X------------------------------------------------------------------------- XThe opening paragraph from Dave Curry's statsrv README file: X X This is a remote statistics server as described in RFC996, "Statistics X Server", D. L. Mills, February 1987. With it, you can collect things X like load averages, number of users, uptime, and network statistics X from remote machines easily. (David Curry, davy@riacs.edu) X------------------------------------------------------------------------- X X ^Deke Kassabian, deke@ee.rochester.edu or ur-valhalla!deke X Univ of Rochester, Dept of EE, Rochester, NY 14627 (+1 716-275-3106) END_OF_FILE if test 1224 -ne `wc -c <'OTHER_SERVERS'`; then echo shar: \"'OTHER_SERVERS'\" unpacked with wrong size! fi # end of 'OTHER_SERVERS' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(2930 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X LB - The Load Balancer (version 1.2) X by Dikran Kassabian X X University Of Rochester X Department of Electrical Engineering X March 3, 1991 X_______________________________________________________________________ X XWhat is LB? X X LB is a load-balancing program. It can check the current X load on various machines on a LAN, and find the best candidate X machine to accept a new job to it's run queue. Additionally, X it can send the job to that machine using rsh(1). X X LB works best in homogeneous environments, where each machine X has similar or identical file system layout. Here at the X University of Rochester Department of Electrical Engineering, X we have nearly 70 SUN computers, which share home-directories X and local binaries. When a user sitting at a small workstation X wants to run a compute intensive job, LB helps to find a machine X on the network that has a low load, knowing that that machine X will also have his/her home directory and required program. X XHow to install LB: X X A separate file, called INSTALL, is included with detailed X installation notes, but briefly... X X To install lb, unpack the shar file (hmm, I guess you've already X done that :-), decide which statistics server you want to use X (rstatd or statsrv) and make the two small adjustments to the X Makefile, then type "make". The program 'lb' will be produced. X Then move 'lb' to an appropriate directory (/usr/local/bin), X edit and install the configuration file, and you're ready to X go. The relevant man pages are included, and can be installed X in your local man page directory. X XHow to use LB: X X To use lb, just type 'lb <command-line>' at your prompt, where X <command line> is some shell command you might normally type X at your prompt. LB will read a configuration file that tells X it about the candidate machines, select one, and then use rsh(1) X to run <command-line> on the specified machine. X X See the man page for lb(1) for more information. X XSpecial thanks to Dave Curry (davy@riacs.edu), whose statsrv server can Xbe used as an option to the rpc.rstatd server. He was nice enough to let Xme include some of his code with this package. The files st_sendrecv.c Xand stats.h are directly from his statsrv distribution. X XThis version of lb has been tested in only a few environments. It works on Xour Sun-3 and Sun-4 computers under SunOS 4.1. It also works on our 68030 XNeXT Cubes under 1.0a OS. Previous versions ran on our Vax 11/750 under XMt.Xinu BSD (but that machine has since been retired). Beyond that I don't Xknow. If you port it to other operating systems and hardware, send me the Xdiffs so I can include them in the next release (if there is one). X XIf you have comments/fixes/bug-reports/flames, send 'em to me at Xdeke@ee.rochester.edu. I'll make every effort to reply, and to address Xyour concerns, but can't always guarantee that I can be quick about it. X XGood luck with lb! I hope you find it useful. END_OF_FILE if test 2930 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'config.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'config.h'\" else echo shar: Extracting \"'config.h'\" \(730 characters\) sed "s/^X//" >'config.h' <<'END_OF_FILE' X/* */ X/* Configuration parameters for the load balancer, 'lb' */ X/* Copyright (c) 1988, 1989 University of Rochester */ X/* Department of Electrical Engineering. */ X/* */ X X#define CONFIGFILE "/usr/share/lb.conf" X#define RSH "/usr/ucb/rsh" X X#define loadavg(sp,n) (((float) (sp)->avenrun[n]) / 256.0) X#define MAXLINE 255 /* largest line in config file*/ X#define MAXSHBUF 10240 /* max size of shell buffer */ X#define MAXHOST 64 /* longest allowable hostname */ X X#if u3b || u3b5 || sun X#define MAXFLOAT ((float)3.40282346638528860e+38) X#endif X X#if pdp11 || vax X#define MAXFLOAT ((float)1.701411733192644299e+38) X#endif X X#ifndef MAXFLOAT X#define MAXFLOAT ((float)1.701411733192644299e+38) X#endif END_OF_FILE if test 730 -ne `wc -c <'config.h'`; then echo shar: \"'config.h'\" unpacked with wrong size! fi # end of 'config.h' fi if test -f 'lb.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lb.1'\" else echo shar: Extracting \"'lb.1'\" \(2521 characters\) sed "s/^X//" >'lb.1' <<'END_OF_FILE' X.tr ~ \ X.TH LB 1 "options X.SH NAME XLb \- load balancer for homogeneous environment X.SH SYNOPSIS X.BR "lb [ -v | -q ] <command string> X.PP X.SH DESCRIPTION X.I lb Xfinds the best machine in the environment on which to run a batch type Xcompute task. This is done by comparing load averages Xand computing power for various machines, and selecting the machine Xbest able to accept the compute task. X.I lb Xis especially useful in distributing compute intensive jobs among Xthe many computers in a homogeneous environment. X.sp X.SH OPTIONS XWith no options, X.I lb Xprints a one line output identifying Xthe selected machine and the command being submitted. X.sp X.nf X -v verbose mode: causes an excessive amount of X information about the determination of the best X machine selection to be printed. X X -q quiet mode: causes even the usual one line X output identifying the selected machine to be X eliminated. The job will be sent to the remote X machine, but you will never be told which machine X was selected! X.fi X.SH EXAMPLES X.nf X.I lb X.fi X This gives the output of lb -v, but executes no command X.sp X.nf X.I lb fortune X.fi X This executes "fortune" on the least loaded machine. X.sp X.nf X.I lb -v foobar X.fi X This executes "foobar" on the least loaded machine, and gives Xverbose messages. X.sp X.nf X.I lb -q minimos infile X.fi X This executes "minimos infile" on the least loaded machine, Xand gives no messages. X.sp X.nf X.I lb 'spice<infile>outfile' X.fi X This is an important example. Here, a program called "spice" is Xbeing run with redirected input and output. Anytime redirection is Xdesired in using X.I lb, Xthe portion using redirection must be quoted to avoid interpretation at Xthe originating shell. The quoted string in this example allows for the Xredirection to take place on the remote machine. X.sp X.nf X.SH FILES X.fi X.I lb Xalso requires the configuration file X.I lb.conf Xwhich lists machines to be Xconsidered, and some basic information about them. See the manual Xpage lb(5) for more on the configuration file. X.nf X.SH CAVEATS X.fi X.sp X.I lb Xshould really use X.I csh job control Xso that the user may track the progress of the submitted job. Maybe in Xthe next version. X.sp X.nf X.SH NOTES XThis program is still under development. Send Xdescriptions of problems and/or comments to deke@ee.rochester.edu X(also ...!rochester!ur-valhalla!deke). X.SH AUTHOR X.nf XDikran Kassabian, XUniversity of Rochester Dept. of Electrical Engineering XRochester, NY 14627 (716) 275-3106 X.SH "SEE ALSO" Xrstatd(8), statsrv(8), w(1), uptime(1), lb(5) END_OF_FILE if test 2521 -ne `wc -c <'lb.1'`; then echo shar: \"'lb.1'\" unpacked with wrong size! fi # end of 'lb.1' fi if test -f 'lb.5' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lb.5'\" else echo shar: Extracting \"'lb.5'\" \(2063 characters\) sed "s/^X//" >'lb.5' <<'END_OF_FILE' X.tr ~ \ X.TH LB 5 "limit X.SH NAME XLb.conf \- load balancer configuration file for lb(1) X.fi X.SH DESCRIPTION XThis file contains information about local machines recognized by X.IR lb (1). XThe format consists of single line entries with three fields. The Xfields are X.I machine-name, X.I power-factor, Xand X.I load-limit. X.sp X.I machine-name Xis a legal or recognized hostname which is to be a candidate for jobs Xinitiated through the use of lb(1). This machine must support the Xstatistics server protocol used by lb(1). X.sp X.I power-factor Xis a floating point value, and has meaning only by comparison to Xthe power-factors of other machines. The machines with the larger Xpower-factors will be preferred to those with smaller power-factors. X.sp X.I load-limit Xspecifies the load-average beyond which jobs should not be sent Xto that machine. X.sp X.SH SAMPLE FILE X.nf X# lb.conf X# X# The format of this file is <machine> <sfactor> <limit> X.ta .8i X# where <machine> is a legal machine name X# <sfactor> is that machines selection factor X# <limit> is the load limit for that machine X# X.ta 2.2i 3.2i X# MACHINE SFACTOR LIMIT Xbrahms.fubar.com 200 3.0 Xmozart.fubar.com 150 2.5 Xchopin.fubar.com 120 2.5 Xbach.fubar.com 100 1.5 X.sp X.fi XLines beginning with X.B # Xare comments. X.sp XIn this example, brahms.fubar.com is preferred to mozart.fubar.com, which Xis preferred to chopin.fubar.com, if their loads are exactly equal. In Xpractice, the load average (number of jobs in the run queue over the last Xminute) is compared to the load-limit and then divided by the power-factor, Xfor each machine listed. If the load average exceeds the load-limit, that Xmachine will not be considered. When all machines listed have been considered, Xthe one with the smallest value of (load-average/power-factor) will be Xselected. X.sp X.SH "SEE ALSO" Xlb(1), w(1), uptime(1) X.SH NOTES XThere are limits to the line-length and the hostname length, which are Xset in the file config.h when lb(1) is built. By default, these are X255 and 64 respectively, but may be tweaked at the installers discretion. END_OF_FILE if test 2063 -ne `wc -c <'lb.5'`; then echo shar: \"'lb.5'\" unpacked with wrong size! fi # end of 'lb.5' fi if test -f 'rsdclnt.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rsdclnt.c'\" else echo shar: Extracting \"'rsdclnt.c'\" \(5598 characters\) sed "s/^X//" >'rsdclnt.c' <<'END_OF_FILE' X/* X * Copyright (c) 1989,1990,1991 University of Rochester X * Department of Electrical Engineering X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * at the University of Rochester. X * X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X/* X * rsdclnt.c for the 'lb' load balancer X * -Deke Kassabian, University of Rochester EE Department X * ( deke@ee.rochester.edu ) (716) 275-3106 X * X * $Revision: 1.2 $ X * $Author: deke $ X * $Date: 91/03/03 17:52:36 $ X * $Log: rsdclnt.c,v $ X * Revision 1.2 91/03/03 17:52:36 deke X * changed stats to lstats to avoid name clash: required by change in rstat.h X * X */ X X#include <stdio.h> X#include <rpc/rpc.h> X#include <rpcsvc/rstat.h> X#include "config.h" X Xmain(argc, argv, envp) Xint argc; Xchar *argv[]; Xchar *envp[]; X{ X Xstruct statstime lstats; XFILE *fd,*fopen(); Xchar *fgets(); Xint getstats(); X Xint start, /* where in the argv the command begins */ X ppgrp, /* parent process group */ X command, /* whether there is a command */ X verbose_mode, /* all possible output */ X quiet_mode; /* no output */ X Xchar *path=RSH; X Xchar *dir,*pname; Xchar *cmd_exec[MAXSHBUF], /* command to execute (local) */ X *rcmd_exec[MAXSHBUF], /* command to execute (remote) */ X dbuf[MAXSHBUF], /* working directory placeholder */ X host[MAXHOST], /* hostname placeholder */ X best_host[MAXHOST], /* hostname placeholder */ X fentry[MAXLINE]; /* file buffer */ X Xfloat my_sfactor, X best_sfactor, X factor, limit, /* file variables */ X load; X X pname = *argv; /* Name of this program */ X verbose_mode=0,quiet_mode=0; /* Default is neither */ X best_sfactor=MAXFLOAT; /* Practically infinity! */ X command=1; /* There is a command */ X X /* Check arguments. X * X * if argc=1 then verbose=Y and command=NULL X * if argc>=2 check for flags: X * -v=verbose (full output), -q=quiet (don't output machine selection) X * with no flags, only machine selection will be output X * The above flags are mutually exclusive. v overrides q X * X * Additional arguments are taken to be a command. No sanity checking X * will be done. When a machine is selected, the command will be sent X * to that machine as a shell command. X * X */ X X if (argc == 1) { X command=0; /* no command to execute */ X verbose_mode=1; /* verbose mode */ X } X else { X start=1; X if(!strcmp(argv[1],"-q")){ X quiet_mode=1; /* quiet mode - no output */ X start=2; X if(argc == 2) exit(0); /* No command, no output! */ X } X if(!strcmp(argv[1],"-v")){ X verbose_mode=1; /* verbose mode */ X start=2; X if(argc == 2) command=0; /* No command - verbose */ X } X } X if(command){ X for( ; start<argc ; start++){ X strcat(cmd_exec," "); strcat(cmd_exec,argv[start]); X } X } X X X if((fd=fopen(CONFIGFILE,"r"))==0){ X fprintf(stderr,"Error opening configuration file\n"); X exit(1); X } X X while((fgets(fentry,MAXLINE,fd))!=NULL){ X sscanf(fentry,"%s %f %f",host,&factor,&limit); X if(fentry[0]=='#') continue; /*ignore comments*/ X X if(verbose_mode) X printf("\nHOST=%s\tFACTOR=%.2f\tLIMIT=%.2f\n",host,factor,limit); X X if(getstats(host,&lstats) !=0){ X load=MAXFLOAT; /* skip this one */ X } X else { X load=loadavg(&lstats,0); X } X X if( load > limit){ X if(verbose_mode) printf("Host %s is over defined limit\n",host); X continue; X } X X my_sfactor=100*(load/factor); X X if(verbose_mode) X printf("Load avg=%.3f\tSelection factor=%.3f\n", X load,my_sfactor); X X if(best_sfactor>my_sfactor){ X best_sfactor=my_sfactor; X strcpy(best_host,host); X } X } /*endwhile */ X X if(verbose_mode) X printf("Selected host: <%s> factor=<%.3f>\n",best_host,best_sfactor); X X if(command){ X sprintf(rcmd_exec,"(cd %s;%s)",getwd(dbuf),cmd_exec); X if(!quiet_mode){ /* print if not quiet_mode */ X printf("\nrsh %s %s &\n",best_host,rcmd_exec); X } X ppgrp = getpgrp(getppid()); X if (fork()) X exit(0); X if(setpgrp(getpid(), ppgrp)) X perror("stepgrp"); X execle(path,path,best_host,rcmd_exec,(char *)0,envp); exit(0); X perror(""); X } Xexit(0); X} X Xgetstats(hostname,lstats) Xchar *hostname; Xstruct statstime *lstats; X{ Xint c; X c=rstat(hostname,lstats); /* rstat seems to return: */ X /* 0 on success */ X /* 13 on hostname lookup fail */ X /* 14 on connection timeout */ X /* 15 on "rstat not supported" */ X /* I chose to generate my own error messages. perror() didn't */ X /* give error messages I liked. Switch back to perror if you */ X /* care to. */ X X switch(c){ X case 0: X break; X case 13: X fprintf(stderr,"rstat error (%d): ",c); X fprintf(stderr,"host %s is unknown.\n",hostname); X break; X case 14: X fprintf(stderr,"rstat error (%d): ",c); X fprintf(stderr,"host %s is down or unreachable.\n",hostname); X break; X case 15: X fprintf(stderr,"rstat error (%d): ",c); X fprintf(stderr,"host %s does not support protocol.\n",hostname); X break; X default: X fprintf(stderr,"rstat error (%d): ",c); X fprintf(stderr,"unknown error\n"); X break; X } X return(c); X} END_OF_FILE if test 5598 -ne `wc -c <'rsdclnt.c'`; then echo shar: \"'rsdclnt.c'\" unpacked with wrong size! fi # end of 'rsdclnt.c' fi if test -f 'srvclnt.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'srvclnt.c'\" else echo shar: Extracting \"'srvclnt.c'\" \(5875 characters\) sed "s/^X//" >'srvclnt.c' <<'END_OF_FILE' X/* X * Copyright (c) 1989, University of Rochester X * Department of Electrical Engineering X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * at the University of Rochester. X * X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X/* srvclnt.c version 1.1 3/7/89 X * for the 'lb' load balancer - by Deke Kassabian X * X * -Deke Kassabian, University of Rochester EE Department X * ( deke@ee.rochester.edu ) (716) 275-3106 X */ X X#include <sys/param.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <netdb.h> X#include <stdio.h> X#include <string.h> X#include "stats.h" X#include "config.h" X Xchar *pname; Xshort server = 0; /* indicates we aren't server */ Xstruct sockaddr_in sin; /* address of remote host */ X Xmain(argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X FILE *fd,*fopen(); X Xint start, /* where in the argv the command begins */ X ppgrp, /* parent process group */ X command, /* whether there is a command */ X verbose_mode, /* all possible output */ X quiet_mode; /* no output */ X Xchar *path=RSH; X Xchar *dir; Xchar *cmd_exec[MAXSHBUF], /* command to execute (local) */ X *rcmd_exec[MAXSHBUF], /* command to execute (remote) */ X dbuf[MAXSHBUF], /* working directory placeholder */ X host[MAXHOST], /* hostname placeholder */ X best_host[MAXHOST], /* hostname placeholder */ X fentry[MAXLINE]; /* file entry */ X Xfloat my_sfactor, X best_sfactor, X load, X factor,limit; /* file variables */ X X int socktype; X register int s; X char buf[10240]; X struct hostent *hp; X struct servent *sp; X char *servtype; X struct hostent *gethostbyname(); X struct servent *getservbyname(); X X pname = *argv; /* Name of this program */ X X verbose_mode=0,quiet_mode=0; /* Default is neither */ X best_sfactor=MAXFLOAT; /* Practically infinity! */ X command=1; /* There is a command */ X X /* Check arguments. X * X * if argc=1 then verbose=Y and command=NULL X * if argc>=2 check for flags: X * -v=verbose (full output), -q=quiet (don't output machine selection) X * with no flags, only machine selection will be output X * The above flags are mutually exclusive. v overrides q X * X * Additional arguments are taken to be a command. No sanity checking X * will be done. When a machine is selected, the command will be run X * on that machine X * X */ X X if (argc == 1) { X command=0; /* no command to execute */ X verbose_mode=1; /* verbose mode */ X } X else { X start=1; X if(!strcmp(argv[1],"-q")){ X quiet_mode=1; /* quiet mode - no output */ X start=2; X if(argc == 2) exit(0); /* No command, no output! */ X } X if(!strcmp(argv[1],"-v")){ X verbose_mode=1; /* verbose mode */ X start=2; X if(argc == 2) command=0; /* No command - verbose */ X } X } X X if(command){ X for( ; start<argc; start++){ X strcat(cmd_exec," "); strcat(cmd_exec,argv[start]); X } X } X X /* Open the config file */ X if((fd=fopen(CONFIGFILE,"r"))==0){ X fprintf(stderr,"Error opening configuration file "); X exit(1); X } X X /* Set up to use TCP stream sockets. */ X servtype = "tcp"; X socktype = SOCK_STREAM; X X /* Look up the port the server lives on. */ X if ((sp = getservbyname(SERVNAME, servtype)) == NULL) { X fprintf(stderr, "%s: %s/%s: service unknown.\n", X pname, SERVNAME, servtype); X exit(1); X } X X /* Read the config file */ X strcpy(best_host,"localhost"); X while((fgets(fentry,MAXLINE,fd))!=NULL){ X sscanf(fentry,"%s %f %f",host,&factor,&limit); X if(fentry[0]=='#') continue; /*ignore comments*/ X X if(verbose_mode) X printf("\nHOST=%s\tFACTOR=%.2f\tLIMIT=%.2f\n",host,factor,limit); X X X /* Look up the host's address. */ X if ((hp = gethostbyname(host)) == NULL) { X fprintf(stderr, "%s: %s: host unknown.\n", pname, host); X exit(1); X } X X /* Get a socket. */ X if ((s = socket(AF_INET, socktype, 0)) < 0) { X error("socket"); X exit(1); X } X X /* Build the server's address. */ X sin.sin_port = sp->s_port; X sin.sin_family = hp->h_addrtype; X bcopy(hp->h_addr, &sin.sin_addr, sizeof(sin.sin_addr)); X X /* connect to the remote host. */ X if (connect(s, &sin, sizeof(struct sockaddr_in)) < 0) { X /* if not quiet mode, print connect error */ X error("connect"); X /* can't reach this host, try the next */ X continue; X } X X /* make the request and grab the result */ X st_send(s,"loadav"); X st_recv(s,buf,sizeof(buf),"response"); X sscanf(buf,"%f",&load); X X if( load > limit){ X if(verbose_mode) X printf("Host %s is over defined limit\n",host); X continue; X } X X my_sfactor=100*( load / factor ); X if(verbose_mode){ X printf("Load avg=%.3f ",load); X printf("Selection factor=%.2f\n",my_sfactor); X } X X if(best_sfactor>my_sfactor){ X best_sfactor=my_sfactor; X strcpy(best_host,host); X } X X } /*endwhile */ X Xif(verbose_mode) X printf("Selected host: <%s> factor=<%.3f>\n",best_host,best_sfactor); X X if(command){ X sprintf(rcmd_exec,"(cd %s;%s)",getwd(dbuf),cmd_exec); X if(!quiet_mode){ /* print if not quiet_mode */ X printf("\nrsh %s %s &\n",best_host,rcmd_exec); X } X ppgrp = getpgrp(getppid()); X if (fork()) X exit(0); X if(setpgrp(getpid(), ppgrp)) X perror("stepgrp"); X execle(path,path,best_host,rcmd_exec,(char *)0,envp); exit(0); X perror(""); X } Xexit(0); X} X Xerror(s) X{ X fprintf(stderr, "%s: ", pname); perror(s); X} END_OF_FILE if test 5875 -ne `wc -c <'srvclnt.c'`; then echo shar: \"'srvclnt.c'\" unpacked with wrong size! fi # end of 'srvclnt.c' fi if test -f 'st_sendrecv.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'st_sendrecv.c'\" else echo shar: Extracting \"'st_sendrecv.c'\" \(1717 characters\) sed "s/^X//" >'st_sendrecv.c' <<'END_OF_FILE' X#ifndef lint Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/st_sendrecv.c,v 1.2 87/10/19 08:37:02 davy Exp $"; X#endif X/* X * st_sendrecv.c - stream send/recv functions X * X * David A. Curry X * Purdue University X * Engineering Computer Network X * davy@riacs.edu (previously davy@intrepid.ecn.purdue.edu) X * October, 1987 X * X * $Log: st_sendrecv.c,v $ X * Revision 1.2 87/10/19 08:37:02 davy X * Fixed to catch end of file on socket. X * X * Revision 1.1 87/10/17 21:01:46 davy X * Initial revision X * X */ X#include <sys/param.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <syslog.h> X#include <stdio.h> X X#include "stats.h" X Xextern char *pname; Xextern short server; X X/* X * st_send - send buf on the socket s. X */ Xst_send(s, buf) Xchar *buf; Xint s; X{ X register int cnt; X X /* X * We want the length including the null. X */ X cnt = strlen(buf) + 1; X X /* X * Send the buffer. X */ X if (send(s, buf, cnt, 0) < 0) { X if (server) X syslog(LOG_ERR, "send: %m"); X else X error("send"); X exit(1); X } X} X X/* X * st_recv - receive data of maximum length cnt into the buffer buf on X * socket s. err describes what we're expecting for the error X * message. X */ Xst_recv(s, buf, cnt, err) Xchar *buf, *err; Xint s, cnt; X{ X char c; X register int n; X X /* X * Receive a character at a time up to a null. X */ X do { X if ((n = recv(s, &c, sizeof(char), 0)) < 0) { X if (server) X syslog(LOG_ERR, "recv: %m"); X else X error("recv"); X exit(1); X } X X /* X * End of file. X */ X if (n == 0) X exit(0); X X if (--cnt < 0) { X if (server) X syslog(LOG_ERR, "%s too long", err); X else X fprintf(stderr, "%s: %s too long.\n", pname, err); X exit(1); X } X X *buf++ = c; X } while (c != '\0'); X} END_OF_FILE if test 1717 -ne `wc -c <'st_sendrecv.c'`; then echo shar: \"'st_sendrecv.c'\" unpacked with wrong size! fi # end of 'st_sendrecv.c' fi if test -f 'stats.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stats.h'\" else echo shar: Extracting \"'stats.h'\" \(951 characters\) sed "s/^X//" >'stats.h' <<'END_OF_FILE' X/* X * $Header: /ecn1/src/ecn/statsrv/RCS/stats.h,v 1.2 87/12/17 14:54:27 davy Exp $ X * X * stats.h - definitions for statistics server X * X * David A. Curry X * Purdue University X * Engineering Computer Network X * davy@intrepid.ecn.purdue.edu X * October, 1987 X * X * $Log: stats.h,v $ X * Revision 1.2 87/12/17 14:54:27 davy X * Added defines for VMUNIX and KMEM. X * X * Revision 1.1 87/10/17 21:01:03 davy X * Initial revision X * X */ X X#define SERVNAME "statsrv" /* name of our service */ X#define MAXDGRAM 576 /* maximum size of a datagram */ X X#define KMEM "/dev/kmem" /* path to kernel memory */ X X#if vax || sun || gould || tahoe X#define VMUNIX "/vmunix" /* path to kernel */ X#endif X#if sequent X#define VMUNIX "/dynix" X#endif X X/* X * For 4.2BSD syslogs. X */ X#ifndef LOG_DAEMON X#define LOG_DAEMON (3<<3) X#endif X Xextern int st_send(), st_recv(); /* stream send/recv functions */ Xextern int dg_send(), dg_recv(); /* datagram send/recv functions */ END_OF_FILE if test 951 -ne `wc -c <'stats.h'`; then echo shar: \"'stats.h'\" unpacked with wrong size! fi # end of 'stats.h' fi echo shar: End of archive. exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.