load control system (8 of 8)

Keith Muller muller at sdcc3.UUCP
Wed Feb 13 05:07:54 AEST 1985


This is part 8 (last one!) of the load control system. Part 1 must be unpacked
before any other part.

	Keith Muller
	ucbvax!sdcsvax!muller


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by sdcc3!muller on Sat Feb  9 13:58:45 PST 1985
# Contents:  server/setup.c
 
echo x - server/setup.c
sed 's/^@//' > "server/setup.c" <<'@//E*O*F server/setup.c//'

/*-------------------------------------------------------------------------
 * setup.c - server
 *
 * routines needed to start up the server.
 *-------------------------------------------------------------------------
 */

/* $Log$ */

#include "../h/common.h"
#include "../h/server.h"
#include <stdio.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/dir.h>
#include <sys/resource.h>
#include <nlist.h>
#include <signal.h>
#include <errno.h>

/*-------------------------------------------------------------------------
 * doargs
 *
 * check the command line arguement list and set up the global parameters.
 *
 * Note that both -X value and -Xvalue format for any flag X is accepted
 *-------------------------------------------------------------------------
 */

doargs(argc, argv)
int argc;
char **argv;
{
	register int i;
	register char *ptr;
	int lasti;
	int badarg;
#ifdef sun
	extern long loadlevel;
#else
	extern double loadlevel;
#endif sun
	extern u_long mqtime;
	extern struct itimerval startalrm;
	extern long atol();
	extern int atoi();
	extern double atof();

	badarg = 0;
	for (i = 1; i < argc; i++){
		if (argv[i][0] != '-'){
			fprintf(stderr,"bad arg: %s\n", argv[i]);
			badarg = 1;
			break;
		}
		lasti = i;
		/*
		 * set ptr to point at start of flags VALUE.
		 * if strlen > 2 must be -Xvalue format
		 * otherwise set ptr to point at next argv
		 */
		if (strlen(argv[i]) > 2)
			ptr = &(argv[i][2]);
		else if ((i+1) < argc)
			ptr = argv[++i];
		else{
			fprintf(stderr,"bad arg: %s\n", argv[i]);
			badarg = 1;
			break;
		}

		switch(argv[lasti][1]){
			case 'L':
				/*
				 * load level to queue at
				 */
#ifdef sun
				if ((loadlevel = (long)(atof(ptr)*256)) <= 0){
					fprintf(stderr,"bad loadlevel: %ld\n",atof(ptr));
#else
				if ((loadlevel = atof(ptr)) <= 0){
					fprintf(stderr,"bad loadlevel: %lf\n",loadlevel);
#endif
					badarg = 1;
				}
				break;
			case 'T':
				/*
				 * timer cycle time for load checks
				 */
				if ((startalrm.it_value.tv_sec = atol(ptr))<1){
					fprintf(stderr,"bad alarmtime: %ld\n",atol(ptr));
					badarg = 1;
				}
				break;
			default:
				fprintf(stderr,"unknown arg: %s\n",argv[lasti]);
				badarg = 1;
				break;
		}
		if (badarg == 1)
			break;
	}
	if (badarg == 1){
		fprintf(stderr,"Useage: %s [-L load] [-T alarm]\n",argv[0]);
		exit(1);
	}
}

/*--------------------------------------------------------------------------
 * setup
 *
 * a collection of code need at startup to set up the server. such as 
 * checking to make sure only one server runs, detatch server from control
 * terminal etc
 *--------------------------------------------------------------------------
 */
setup()
{

	register int i;
	int lockfile;
	int temp;
	char line[20];
	static struct nlist avenrun[] = { {"_avenrun"}, {""}};
	extern int alrmmask;
	extern long loadaddr;
	extern int descsize;
	extern int kmem;
	extern int errno;
	extern int errorcount;
	extern FILE *errfile;
	extern FILE *fopen();
	extern int getpid();
	extern int onalrm();
	extern int getpid();
	extern int setpriority();
	extern char *sprintf();

	if (getuid() != 0){
		fprintf(stderr, "must run as root\n");
		exit(1);
	}

	/*
	 * see if the spool dir where the client sockets are bound exsists
	 */
	if (access(SPOOLDIR, F_OK) == -1){
		fprintf(stderr,"No directory: %s\n", SPOOLDIR);
		exit(1);
	}

	/*
	 * see if the spool dir where the server sockets are bound exsists
	 */
	if (access(SERVERDIR, F_OK) == -1){
		fprintf(stderr,"No directory: %s\n", SERVERDIR);
		exit(1);
	}

	/*
	 * detach from foreground
	 */
	if (fork() != 0)
		exit(0);

	/*
	 * close down all open descriptors 
	 * so the server is no longer attached to any tty
	 */
	descsize = getdtablesize();
	for (i = 0; i < descsize; i++)
		(void)close(i);
	(void)open("/dev/null",O_RDONLY);
	(void)open("/dev/null", O_WRONLY);
	(void)open("/dev/null", O_WRONLY);

	/*
	 * do an ioctl to /dev/tty to detach server from ttys
	 */
	if ((i = open("/dev/tty", O_RDWR)) > 0){
		(void)ioctl(i, TIOCNOTTY, (char *)0);
		(void)close(i);
	}

	/*
	 * set umask to remove all others permissions
	 */
	(void)umask(027);

	/*
	 * open the error logging file
	 */
	errfile = fopen(ERRORPATH,"a+");
	if (errfile < 0)
		exit(1);

	/*
	 * check lockfile for other servers already running uses advisory
	 * locking
	 */
	lockfile = open (LOCK, O_WRONLY|O_CREAT, 0640);
	if (lockfile < 0){
		errlog("cannot create lockfile");
		exit(1);
	}

	if (flock(lockfile, LOCK_EX|LOCK_NB) < 0){
		if (errno == EWOULDBLOCK)
			exit(0);
		errlog("cannot lock lockfile");
		exit(1);
	}

	/*
	 * write the pid of this server in the lock file in case you
	 * need to blow the server away. (not currently used).
	 */
	i = getpid();
	(void)ftruncate(lockfile, 0);
	(void)sprintf(line, "%d\n", i);
	temp = strlen(line);
	if (write(lockfile, line, temp) != temp)
		errlog("cannot write server pid");

	/*
	 * mark the logfile that a new server is starting
	 */
	(void)fprintf(errfile,"server pid: %d ",i);
	errno = 0;
	errlog("started at");
	errorcount = 0;

	/*
	 * lower the server priority so that under heavy load the server
	 * can get the machine cycles when it needs them. The server
	 * uses very small amounts of cpu, so this is not going to impact
	 * the system.
	 */
	if (setpriority(0, i, PRIO) < 0 )
		errlog("cannot lower priority");

	/*
	 * open kmem where the load average will be read from
	 */
	if ((kmem = open("/dev/kmem", O_RDONLY)) < 0){
		errlog("cannot open kmem");
		cleanup();
	}

	/*
	 * get the address in this vmunix where the load average is 
	 * loacated in the kernel data space
	 */
	nlist("/vmunix", avenrun);
	if (avenrun[0].n_value == 0){
		errlog("cannot find _avenrun");
		cleanup();
	}
	loadaddr = (long)avenrun[0].n_value;

	/*
	 * bind the signal handlers now
	 */
	(void)signal(SIGALRM, onalrm);

	/*
	 * mask used to block off sigalrm when the data structures
	 * are being changed and must not service a timer interrupt
	 * to check the load average
	 */
	alrmmask = 1 << (SIGALRM - 1);
}

/*---------------------------------------------------------------------------
 * scanspool
 *
 * when the server is restarted it could be right after an older server
 * just terminated and left a lot of jobs queued up. since the queue is
 * kept in memory for speed, no record exsists anymore about the queued
 * clients. Since all the client sockets are bound in the same spool 
 * directory simply search the directory for a client socket and send it
 * a POLLCMD. the client will respond to the POLLCMD by resubmitting its
 * work request datagram. The addqueue routine rebuilds the queue by time
 * so the queue will be in the proper order.  Any dead cleints whose bound
 * sockets are still in the spool will be removed (the bound sockets).
 *---------------------------------------------------------------------------
 */
scanspool()
{

	register int i;
	int numfds;
	int readfds;
	u_long pid;
	int cnprlen;
	int clprlen;
	int tag;
	int msgmask;
	struct direct *dp;
	struct stat statbuf;
	DIR *dirp;
	extern struct timeval polltime;
	extern int msgsock;
	extern int descsize;
	extern long atol();

	/*
	 * open a directory for scanning
	 */
	if ((dirp = opendir(SPOOLDIR)) == NULL){
		errlog("cannot open spool directory");
		cleanup();
	}

	/*
	 * cd to the directory, this allows short names for binding and
	 * has a place to look for core dumps if they might occur
	 */
	if (chdir(SPOOLDIR) == -1){
		errlog("cannot cd to spool");
		cleanup();
	}

	/*
	 * clprlen is length of the prefix of client socket. 
	 * cnprlen is length of prefix of control program socket.
	 * needed to extract the uid
	 */
	clprlen = strlen(CLIENTPRE);
	cnprlen = strlen(CNTRLPRE);
	msgmask = 1 << msgsock;
	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
		/*
		 * if not a possable client, go to next entry
		 */
		if (dp->d_ino == 0)
			continue;
	    	if (strncmp(CLIENTPRE, dp->d_name, clprlen) == 0)
			tag = 1;
		else if (strncmp(CNTRLPRE, dp->d_name, cnprlen) == 0)
			tag = 0;
		else
			continue;
		if (stat(dp->d_name, &statbuf) != 0){
			errlog("stat on spool file failed");
			continue;
		}

		/*
		 * file has client or cntrol like name but is not a socket,
		 * remove as could cause problems later
		 */
		if ((statbuf.st_mode & S_IFSOCK) == 0){
			(void)unlink(dp->d_name);
			continue;
		}

		if (tag == 0){
			/*
		 	 * send a message to waiting control program. outcntrl
		 	 * will remove if this is an old socket.
		 	 */
			pid = (u_long)atol(dp->d_name + cnprlen);
			(void)outcntrl(pid, POLLCMD);
			continue;
		}

		/*
		 * is a client socket must force a resubmit of the job. If it
		 * is an old socket outmsg will remove.
		 */
		pid = (u_long)atol(dp->d_name + clprlen);

		/*
		 * throw a couple of POLLCMDS at the client to see if
		 * he is still alive. If the system is loaded could take
		 * a while to swap back in so give him time.
		 */
		for (i = 0; i < MAXPOLLS; i++){
			if (outmsg(pid, POLLCMD) != 0)
				break;
			readfds = msgmask;
			numfds = select(descsize,&readfds,(int*)0,(int*)0,&polltime);
			if ((numfds < 0) && (errno != EINTR)){
				errlog("select error in scanspool");
				cleanup();
			}
			/*
			 * time in select expired and no answer from client
			 * try again
			 */
			if (numfds <= 0){
				continue;
			}
			/*
			 * got a datagram, figure it out
			 */
			msgdis();
		}
	}
}


/*-------------------------------------------------------------------------
 * crsock
 *
 * create all the sockets used by the server
 *-------------------------------------------------------------------------
 */
crsock()
{
	int len;
	struct sockaddr_un name;
	extern int msgsock;
	extern int cntrlsock;
	extern char *strcpy();

	/*
	 * create the msgsocket where queue requests appear
	 */
	name.sun_family = AF_UNIX;
	msgsock = socket(AF_UNIX, SOCK_DGRAM, 0);
	if (msgsock < 0){
		errlog("cannot create msgsock");
		cleanup();
	}
	/*
	 * remove any entry in the file system for this name else the bind
	 * will fail. We are sure from the locking that this is ok to do.
	 */
	(void)unlink(MSGPATH);
	(void)strcpy(name.sun_path, MSGPATH);
	len = strlen(name.sun_path) + sizeof(name.sun_family) + 1;
	if (bind(msgsock, &name, len) < 0){
		errlog("cannot bind msgsock");
		cleanup();
	}

	/*
	 * create the control socket for high priority control commands
	 */
	cntrlsock = socket(AF_UNIX, SOCK_DGRAM, 0);
	if (cntrlsock < 0){
		errlog("cannot create cntrlsock");
		cleanup();
	}
	(void)unlink(CNTRLPATH);
	(void)strcpy(name.sun_path, CNTRLPATH);
	len = strlen(name.sun_path) + sizeof(name.sun_family) + 1;
	if (bind(cntrlsock, &name, len) < 0){
		errlog("cannot bind cntrlsock");
		cleanup();
	}
}
@//E*O*F server/setup.c//
chmod u=r,g=r,o=r server/setup.c
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
     461    1512   10759 setup.c
!!!
wc  server/setup.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0



More information about the Comp.sources.unix mailing list