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
×ecs,&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