load control (4 of 8)

Keith Muller muller at sdcc3.UUCP
Tue Feb 12 18:15:24 AEST 1985


This is part 4 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:51:28 PST 1985
# Contents:  control/Makefile control/delete.c control/globals.c control/ipc.c
#	control/ldccmds.c
 
echo x - control/Makefile
sed 's/^@//' > "control/Makefile" <<'@//E*O*F control/Makefile//'

#
# Makefile for ldc control programs : ldc, ldrm, ldq
#

CFLAGS= -O

BGID=	lddgrp

DEST=	/etc

DEST2=  /usr/local

HDR=	../h/common.h ../h/control.h

LDCSRC=	ldcmain.c ldccmds.c list.c delete.c ldccmdtab.c ipc.c globals.c 

LDRMSRC= ldrmmain.c delete.c ipc.c globals.c

LDQSRC=	ldqmain.c list.c ipc.c globals.c

LDCOBJ=	ldcmain.o ldccmds.o list.o delete.o ldccmdtab.o ipc.o globals.o

LDRMOBJ=ldrmmain.o delete.o ipc.o globals.o

LDQOBJ=	ldqmain.o list.o ipc.o globals.o

all:	ldc ldrm ldq

ldc:  $(LDCOBJ)
	cc -o ldc $(LDCOBJ)

ldrm: $(LDRMOBJ)
	cc -o ldrm $(LDRMOBJ)

ldq:  $(LDQOBJ)
	cc -o ldq $(LDQOBJ)

$(LDCOBJ):  $(HDR)

$(LDRMOBJ): $(HDR)

$(LDQOBJ):  $(HDR)

install: $(DEST)/ldc $(DEST2)/ldq $(DEST2)/ldrm

$(DEST)/ldc: ldc
	install -c -m 4711 -o root -g $(BGID) ldc $(DEST)

$(DEST2)/ldrm: ldrm
	install -c -m 4711 -o root -g $(BGID) ldrm $(DEST2)

$(DEST2)/ldq: ldq
	install -c -m 4711 -o root -g $(BGID) ldq $(DEST2)

clean:
	rm -f *.o core ldc ldrm ldq

lint:
	@echo "*************************lint for ldc*************************"
	lint -abchx $(LDCSRC)
	@echo "*************************lint for ldrm************************"
	lint -abchx $(LDRMSRC)
	@echo "*************************lint for ldq*************************"
	lint -abchx $(LDQSRC)
@//E*O*F control/Makefile//
chmod u=r,g=r,o=r control/Makefile
 
echo x - control/delete.c
sed 's/^@//' > "control/delete.c" <<'@//E*O*F control/delete.c//'

/*-----------------------------------------------------------------------
 * delete.c - control program
 *
 * this file contains the delete command which is common to both ldc
 * and ldrm
 *-----------------------------------------------------------------------
 */

/* $Log$ */

#include "../h/common.h"
#include <sys/time.h>
#include <stdio.h>
#include <pwd.h>

/*-----------------------------------------------------------------------
 * delete
 *
 * tell the server to remove all a users jobs or a specific job from its
 * queue. a user can remove only his jobs, root can remove any job.
 *-----------------------------------------------------------------------
 */
delete(argc, argv)
int argc;
char **argv;
{
	register int i;
	struct passwd *pwd;
	long temp;
	extern int uid;
	extern struct request job;
	extern struct passwd *getpwnam();
	extern long atol();
	extern int endpwent();
	extern int strncmp();

	if (argc < 2){
		printf("Usage: delete [pid(s)] [-u user(s)]\n");
		return;
	}

 	if (strncmp(argv[1], "-u", 2) == 0){
		/*
	 	 * remove all jobs by user (-u option)
	 	 */
		if (argc < 3){
			printf("No user name\n");
			printf("Usage: delete [pid(s)] [-u user(s)]\n");
			return;
		}
		job.type = PUSRCMD;
		for (i = 2; i < argc; i++){
			/*
			 * loop through each arg and remove that users jobs
			 */
			if ((pwd = getpwnam(argv[i])) == (struct passwd *)NULL){
				/*
				 * couldn't find the user, go to next one
				 */
				printf("No such user: %s\n", argv[i]);
				continue;
			}

			/*
			 * the server DOES NOT check to see if this command
			 * can be performed by this user.
			 */
			 if ((uid != 0) && (uid != pwd->pw_uid)){
				printf("You are not: %s\n", argv[i]);
				continue;
			}

			/*
			 * remove the specified users jobs
			 */
			job.uid = (u_long)pwd->pw_uid;
			printf("user %s: ", argv[i]);
			if (sendcntrl() == 0)
				printf("removed from the queue.\n");
		}
		(void)endpwent();
	}else{
		/*
		 * remove a job specified by its pid. Only the server
		 * can determine if the pid is a valid pid for a queued job.
		 * The server will check to see if this user can remove that
		 * pid from the queue (root can remove any job, a user can only
		 * remove his jobs).
		 */
		job.type = PJOBCMD;
		job.uid = uid;

		for (i = 1; i < argc; i++){
			/*
		 	 * loop through each arg and try to remove it (each arg 
		 	 * is a pid).
		 	 */
			if ((temp = atol(argv[i])) <= 0){
				/*
				 * bad pid, try next
				 */
				printf("Bad pid: %ld\n", temp);
				continue;
			}
			job.time = (u_long)temp;
			printf("pid %ld: ", temp);
			if (sendcntrl() == 0)
				printf("removed\n");
		}
	}
}
@//E*O*F control/delete.c//
chmod u=r,g=r,o=r control/delete.c
 
echo x - control/globals.c
sed 's/^@//' > "control/globals.c" <<'@//E*O*F control/globals.c//'

/*-------------------------------------------------------------------------
 * globals.c - control program, used in ldc, ldq, and ldrm
 *
 *-------------------------------------------------------------------------
 */

/* $Log$ */

#include "../h/common.h"
#include "../h/control.h"
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <stdio.h>

int	uid;					/* uid of the user */
char	path[256];				/* path to bound socket */
int	sock = -1;				/* socket desriptor */
int	descsize;				/* number of desc table */
int 	sockmask;				/* mask to select socket */
int 	stdinmask;				/* mask to select stdin */
int	len;					/* length of address */
FILE	*out = NULL;				/* file desc for status file */
struct sockaddr_un name;			/* socket address */
struct request job;				/* datagram to server */
struct timeval polltime = {WAITTIME, 0};	/* time so select not hangs */
@//E*O*F control/globals.c//
chmod u=r,g=r,o=r control/globals.c
 
echo x - control/ipc.c
sed 's/^@//' > "control/ipc.c" <<'@//E*O*F control/ipc.c//'

/*-------------------------------------------------------------------------
 * ipc.c - control
 *
 * all the routines used to communicate with the server
 *-------------------------------------------------------------------------
 */

/* $Log$ */

#include "../h/common.h"
#include "../h/control.h"
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>

/*-------------------------------------------------------------------------
 * setup
 *
 * create all the goodies needed to run the control programs
 *-------------------------------------------------------------------------
 */
setup()
{

	extern struct sockaddr_un name;
	extern int uid;
	extern int len;
	extern int sock;
	extern int sockmask;
	extern int stdinmask;
	extern int descsize;
	extern char *strcpy();
	extern int onint();
	extern int quit();
	extern struct request job;
	extern char path[];
	extern int getpid();
	extern int getuid();
	extern int getgid();
	extern int errno;
	extern char *sprintf();

	/*
	 * set the global uid as it will be used throughout the control
	 * program
	 */
	uid = getuid();

	/*
	 * setup the socket to send and recieve messages
	 */
	name.sun_family = AF_UNIX;
	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
	if (sock < 0){
		perror("cannot create socket:");
		exit(1);
	}

	/*
	 * bind the interrupt handler
	 */
	(void)signal(SIGINT, onint);
	(void)signal(SIGHUP, quit);
	(void)signal(SIGQUIT, quit);
	(void)signal(SIGTERM, quit);

	/*
	 * bind the socket
	 */
	job.pid = (u_long)getpid();
	(void)sprintf(path, "%s/%s%u",SPOOLDIR, CNTRLPRE, job.pid);
	(void)strcpy(name.sun_path, path);
	name.sun_family = AF_UNIX;
	len = strlen(name.sun_path) + 1 + sizeof(name.sun_family);
	(void)unlink(name.sun_path);
	if (bind(sock, &name, len) < 0){
		perror("cannot bind socket");
		exit(1);
	}

	/*
	 * set the users real and effective uid back to the user (we are
	 * running setuid root). All cntrl sockets must be owned by root.
	 * set gid to lddgrp so socket can be removed later.
	 */
	(void)setregid(getgid(), LDDGID);
	(void)setreuid(uid, uid);

	/*
	 * setup the name structure so all messages will be sent
	 * to the server
	 */
	(void)strcpy(name.sun_path, CNTRLPATH);
	len = strlen(name.sun_path) + 1 + sizeof(name.sun_family);

	/*
	 * descsize for the select call
	 */
	descsize = getdtablesize();

	/*
	 * mask to select the socket for messages or stdin input
	 */
	sockmask = 1 << sock;
	stdinmask = 1 << fileno(stdin);
}

/*-------------------------------------------------------------------------
 * sendcntrl
 *
 * send the job datagram as set up by the specific command to the server
 * and then wait for a response. Print diagnostics if the command was not
 * executed by the server or the server does not respond.
 *-------------------------------------------------------------------------
 */
sendcntrl()
{
	int readfds;
	int numfds;
	char msg;
	int fromlen = 0;
	extern struct timeval polltime;
	extern int len;
	extern int errno;
	extern int descsize;
	extern int sockmask;
	extern int sock;
	extern struct request job;
	extern struct sockaddr_un name;
	extern int quit();

	if (sendto(sock,&job,sizeof(struct request),0,&name,len) < 0){
		perror("message to server failed");
		return(-1);
	}

	readfds = sockmask;

	/*
	 * wait for the ok from the server
	 */
	numfds = select(descsize,&readfds,(int *)0,(int *)0,&polltime);
	if ((numfds < 0) && (errno != EINTR)){
		perror("select failed");
		return(-1);
	}

	if (numfds <= 0){
		printf("Server did not respond after %ld seconds\n",WAITTIME);
		return(-1);
	}

	if (recvfrom(sock,&msg,sizeof(msg),0,(struct sockaddr *)0,&fromlen)<=0){
		perror("message from server failed");
		return(-1);
	}
	switch(msg){
		case RUNCMD:
			return(0);
		case POLLCMD:
			printf("new server started, command lost\n");
			return(-1);
		case STOPCMD:
			printf("command failed\n");
			return(-1);
		default:
			printf("unknown message from server\n");
			return(-1);
	}
}
@//E*O*F control/ipc.c//
chmod u=r,g=r,o=r control/ipc.c
 
echo x - control/ldccmds.c
sed 's/^@//' > "control/ldccmds.c" <<'@//E*O*F control/ldccmds.c//'

/*-----------------------------------------------------------------------
 * commands.c - control program
 *
 * this file contains the commands that the ldc program can execute
 *-----------------------------------------------------------------------
 */

/* $Log$ */

#include "../h/common.h"
#include "../h/control.h"
#include <sys/time.h>
#include <stdio.h>
#include <pwd.h>


/*---------------------------------------------------------------------------
 * abortserver
 *
 * tell the server to give it up
 * NOTE: for saftey reasons you must type both words: abort server 
 *       abort alone will NOT work (for people who cannot type!)
 *---------------------------------------------------------------------------
 */
abortserv(argc, argv)
int argc;
char **argv;
{
	extern struct request job;

	if (argc != 2){
		printf("Usage: abort server\n");
		return;
	}

	/*
	 * second arg better be a prefix of the word server, else a typo!
	 */
	if (strncmp(argv[1], "server", strlen(argv[1])) != 0){
		printf("Usage: abort server\n");
		return;
	}

	/*
	 * bye bye old server
	 */
	job.type = ABORTCMD;
	(void)sendcntrl();
}

/*-------------------------------------------------------------------------
 * errprint
 *
 * print out the contents of the error logging file.
 *-------------------------------------------------------------------------
 */
errprint(argc, argv)
int argc;
char **argv;
{
	char linebuf[256];
	extern char *fgets();
	extern FILE *out;
	extern int fclose();
	FILE *fopen();

	if (argc != 1){
		printf("Usage: errprint\n");
		return;
	}

	if ((out = fopen(ERRORPATH, "r")) == NULL){
		printf("cannot open error file\n");
		return;
	}

	/*
	 * print out the contents of the error file exactly
	 */
	while (fgets(linebuf, sizeof(linebuf), out) != (char *)0)
		fputs(linebuf, stdout);

	(void)fclose(out);
	out = NULL;
}

/*-------------------------------------------------------------------------
 * loadlimt
 *
 * tell the server to change the point at which it queues jobs
 *-------------------------------------------------------------------------
 */
loadlimit(argc, argv)
int argc;
char **argv;
{
	double load;
	extern struct request job;
	extern double atof();

	if (argc != 2){
		printf("Usage: loadlimit load\n");
		return;
	}

	job.type = LOADLIMCMD;
	if ((load = atof(argv[1])) <= 0){
		printf("Bad value for loadlimit: %.2lf\n",load);
		return;
	}
	if (load < LOWLOAD)
		printf("WARNING: %.2lf load might cause excessive queue times\n",load);
	else if (load > HIGHLOAD)
		printf("WARNING: %.2lf load might never queue jobs\n",load);
	
	/*
	 * the value 256 is used to scale up the floating point load
	 * average so the value fits in a long. The 256 value was picked
	 * as that is the same value sun uses in the kernel to scale the
	 * load averages
	 */
	job.time  = (u_long)(256.0 * load);
	(void)sendcntrl();
}

/*-------------------------------------------------------------------------
 * move
 *
 * move a pid around in the queue
 *-------------------------------------------------------------------------
 */
move(argc, argv)
int argc;
char **argv;
{
	long temp;
	extern struct request job;
	extern long atol();

	if (argc != 3){
		printf("Usage: move pid rank\n");
		return;
	}
	job.type = MOVECMD;
	if ((temp = atol(argv[1])) <= 0){
		printf("Bad pid: %ld\n",temp);
		return;
	}
	job.uid = (u_long)temp;
	if ((temp = atol(argv[2])) <= 0){
		printf("Bad rank: %ld\n",temp);
		return;
	}
	job.time = (u_long)temp;
	(void)sendcntrl();
}

/*-------------------------------------------------------------------------
 * purge
 *
 * tell the server to blow away all the jobs in its queue.
 * NOTE: for saftey you must type purge all!
 *-------------------------------------------------------------------------
 */
purge(argc, argv)
int argc;
char **argv;
{
	extern struct request job;

	if (argc != 2){
		printf("Usage: purge all\n");
		return;
	}

	/*
	 * next arg must be a prefix of the word: all
	 */
	if (strncmp(argv[1], "all", strlen(argv[1])) != 0){
		printf("Usage: purge all\n");
		return;
	}

	/*
	 * clean up the queue server
	 */
	job.type = PALLCMD;
	(void)sendcntrl();
}

/*-------------------------------------------------------------------------
 * run
 *
 * tell the server to run listed job[s] regardless of the load
 *-------------------------------------------------------------------------
 */
run(argc, argv)
int argc;
char **argv;
{
	register int i;
	long temp;
	struct passwd *pwd;
	extern int uid;
	extern struct request job;
	extern long atol();
	extern int strncmp();
	extern int endpwent();
	extern struct passwd *getpwnam();

	if (argc < 2){
		printf("Usage: run [pid(s)] [-u user(s)]\n");
		return;
	}

	if (strncmp(argv[1], "-u", 2) == 0){
		/*
		 * run all jobs owned by user (-u option)
		 */
		if (argc < 3){
			printf("No user name\n");
			printf("Usage: run [pid(s)] [-u user(s)]\n");
			return;
		}
		job.type = RUSRCMD;
		for (i = 2; i < argc; i++){
			/*
			 * loop through each arg and run all that users jobs
			 */
		 	if ((pwd = getpwnam(argv[i])) == (struct passwd *)NULL){
				/*
				 * couldn't find the user go to next one
				 */
				printf("No such user: %s\n", argv[i]);
				continue;
			}

			/*
			 * run all this users jobs
			 */
			job.uid = (u_long)pwd->pw_uid;
			printf("user %s: ", argv[i]);
			if (sendcntrl() == 0)
				printf("running.\n");
		}
		(void)endpwent();
	}else{
		job.type = RJOBCMD;
		job.uid = uid;
		for (i = 1; i < argc; i++){
			if ((temp = atol(argv[i])) <= 0){
				printf("Bad pid: %ld\n",temp);
				continue;
			}
			job.time = (u_long)temp;
			printf("%ld: ", temp);
			if (sendcntrl() == 0)
				printf("running\n");
		}
	}
}

/*-------------------------------------------------------------------------
 * status
 *
 * ask the server to update the status file. The status file contains the
 * current settings of those paramters the control program can adjust.
 *-------------------------------------------------------------------------
 */
status(argc, argv)
int argc;
char **argv;
{
	int qcount;
	int full;
	int timerstop;
	u_long timesecs;
	u_long mqtime;
	int errorcount;
#ifdef sun
	long loadlevel;
#else
	double loadlevel;
#endif
	extern int fclose();
	FILE *fopen();
	extern FILE *out;
	extern struct request job;

	if (argc != 1){
		printf("Usage: status\n");
		return;
	}

	job.type = STATUSCMD;

	/*
	 * only print if ok
	 */
	if (sendcntrl() < 0)
		return;
	
	if ((out = fopen(STATUSFILE, "r")) == NULL){
		printf("Cannot open status file\n");
		return;
	}

	/*
	 * the value 7 below is the argument count returned by fscanf.
	 * should be the same as the number of variables read.
	 */
#ifdef sun
	if (fscanf(out,"%d %d %d %ld %ld %d %ld",&qcount,&full,&timerstop,
#else
	if (fscanf(out,"%d %d %d %ld %ld %d %lf",&qcount,&full,&timerstop,
#endif
			      &timesecs,&mqtime,&errorcount,&loadlevel) != 7){
		printf("Status file has a data count error.\n");
		(void)fclose(out);
		out = NULL;
		return;
	}
	(void)fclose(out);
	out = NULL;

	if ((timerstop == 1) && (qcount != 0)){
		printf("WARNING: the timer is stopped (nonempty queue)\n");
		printf("THIS SHOULD NEVER HAPPEN!\n");
		printf("Try the timerset command to restart\n\n");
	}

	printf("number of jobs in queue:\t%d ", qcount);
	if (qcount >= full)
		printf("\t\t*** WARNING: FULL QUEUE ***\n");
	else
		printf("\n");
	printf("current maximium queue size:\t%d ", full);
	if (full < LOWSIZE)
		printf("\t\t*** WARNING: SET TOO LOW ***\n");
	else if  (full > HIGHSIZE)
		printf("\t\t*** WARNING: SET TOO HIGH ***\n");
	else
		printf("\n");
#ifdef sun
	printf("jobs queue at loads above:\t%3.2lf ",((double)loadlevel)/256.0);
	if (loadlevel < (LOWLOAD * 256))
		printf("\t\t*** WARNING: SET TOO LOW ***\n");
	else if (loadlevel > (HIGHLOAD * 256))
		printf("\t\t*** WARNING: SET TOO HIGH ***\n");
	else
		printf("\n");
#else
	printf("jobs queue at loads above:\t%3.2lf ", loadlevel);
	if (loadlevel < LOWLOAD)
		printf("\t\t*** WARNING: SET TOO LOW ***\n");
	else if (loadlevel > HIGHLOAD)
		printf("\t\t*** WARNING: SET TOO HIGH ***\n");
	else
		printf("\n");
#endif
	printf("jobs are queued no more than:\t%u (secs) ", mqtime);
	if (mqtime <= timesecs)
		printf("\t*** WARNING: SET TOO LOW ***\n");
	else if (mqtime > HIGHMAX)
		printf("\t*** WARNING: SET TOO HIGH ***\n");
	else
		printf("\n");
	printf("load average is checked every:\t%u (secs) ",timesecs);
	if (timesecs > (mqtime/2))
		printf("\t*** WARNING: SET TOO HIGH ***\n");
	else if (timesecs < LOWCYCLE)
		printf("\t*** WARNING: SET TOO LOW ***\n");
	else
		printf("\n");
	printf("the number of server errors:\t%d\n", errorcount);
}

/*-------------------------------------------------------------------------
 * sizeset
 *
 * change the limit on the number of jobs allowed to be queued waiting for
 * the systems load average to drop.
 *-------------------------------------------------------------------------
 */
sizeset(argc, argv)
int argc;
char **argv;
{
	long temp;
	extern struct request job;
	extern long atol();

	if (argc != 2){
		printf("Usage: sizeset size\n");
		return;
	}
	job.type = QUEUESIZE;
	if ((temp = atol(argv[1])) <= 0){
		printf("Bad value for size of queue: %ld\n", temp);
		return;
	}
	if (temp < LOWSIZE)
		printf("WARNING: %ld is a very small queue size limit.\n",temp);
	else if (temp > HIGHSIZE)
		printf("WARNING: %ld is a very large queue size limit.\n",temp);
	job.time = (u_long)temp;
	(void)sendcntrl();
}

/*-------------------------------------------------------------------------
 * timerset
 *
 * change the number of second the server waits before checking the load
 * average to see if queued jobs can run
 *-------------------------------------------------------------------------
 */
timerset(argc, argv)
int argc;
char **argv;
{
	long temp;
	extern struct request job;
	extern long atol();

	if (argc != 2){
		printf("Usage: timerset seconds\n");
		return;
	}
	job.type = CHTIMER;
	if ((temp = atol(argv[1])) <= 0){
		printf("Bad value for cycle time: %ld\n", temp);
		return;
	}
	if (temp < LOWCYCLE)
		printf("WARNING: %ld is a very small cycle time\n", temp);
	else if (temp > HIGHCYCLE)
		printf("WARNING: %ld is a very large cycle time\n", temp);
	job.time = (u_long)temp;
	(void)sendcntrl();
}

/*-------------------------------------------------------------------------
 * waitset
 *
 * change the maximium time a job can remain queued. After that time the
 * job will run regardless of the current load. This is needed in case the
 * loadlimit is set too low, or not enough of the programs that are causing
 * the high load are NOT controlled by the server. This keeps jobs from
 * being queued up for excessive times.
 *-------------------------------------------------------------------------
 */
waitset(argc, argv)
int argc;
char **argv;
{
	long temp;
	extern struct request job;
	extern long atol();

	if (argc != 2){
		printf("Usage: waitset seconds\n");
		return;
	}
	job.type = MQTIMECMD;
	if ((temp = atol(argv[1])) <= 0){
		printf("Bad value for waitset: %ld\n",temp);
		return;
	}
	job.time = (u_long)temp;
	if (job.time < LOWMAX)
		printf("WARNING: %u is a very short time limit for the max queue time\n",job.time);
	else if (job.time > HIGHMAX)
		printf("WARNING: %u is a very large time limit for the max queue time\n",job.time);
	(void)sendcntrl();
}
@//E*O*F control/ldccmds.c//
chmod u=r,g=r,o=r control/ldccmds.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 <<\!!!
      65     156    1262 Makefile
     112     382    2627 delete.c
      28     126     907 globals.c
     175     492    4008 ipc.c
     476    1455   11267 ldccmds.c
     856    2611   20071 total
!!!
wc  control/Makefile control/delete.c control/globals.c control/ipc.c control/ldccmds.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