Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site sdcc3.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxb!mhuxn!mhuxm!mhuxj!houxm!whuxlm!harpo!decvax!ittvax!dcdwest!sdcsvax!sdcc3!muller From: muller@sdcc3.UUCP (Keith Muller) Newsgroups: net.sources Subject: load control (4 of 8) Message-ID: <2679@sdcc3.UUCP> Date: Tue, 12-Feb-85 03:15:24 EST Article-I.D.: sdcc3.2679 Posted: Tue Feb 12 03:15:24 1985 Date-Received: Wed, 13-Feb-85 07:38:44 EST Organization: U.C. San Diego, Academic Computer Center Lines: 911 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#include #include /*----------------------------------------------------------------------- * 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 #include #include #include #include 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 #include #include #include #include #include #include /*------------------------------------------------------------------------- * 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 #include #include /*--------------------------------------------------------------------------- * 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