matt@oddjob.UChicago.UUCP (Matt Crawford) (01/25/85)
# unpack with sh (or ex -- its short!) sed 's/.//' >README << '7-8-9 EOF' @Here are some subroutines which a program can call to limit @multiple invocations of itself to one per user and/or N total @invocations. I hope the usage is clear from the comments. @As an example, I added @ @ #ifndef NROFF @ (void)ublock(".tru"); @ (void)nblock(".trn"); @ #endif @ @To the troff source file n1.c just before the setjmp. (If you use both @ublock() and nblock(), use them in that order!) Then I created empty @public-write files called /usr/spool/locks/trn.{1,2,...} to determine @how many troff's would be allowed to run simultaneously. @_____________________________________________________ @Matt University crawford@anl-mcs.arpa @Crawford of Chicago ihnp4!oddjob!matt 7-8-9 EOF sed 's/.//' >lockout.c << '7-8-9 EOF' @#include <sys/file.h> @#include <sys/param.h> @#include <sys/errno.h> @ @#define LOCKDIR "/usr/spool/locks/" @#define INITSLEEPTIME ((unsigned)10) @#define MAXSLEEPTIME ((unsigned)30) @ @extern int errno; @extern char *strcpy(), *strcat(), *sprintf(); @ @/* mkblockf(): @** Make a lock file name for nblock() or ublock(). @** This is not declared static because the user might want to @** use it to look at the contents of some other lock file. @*/ @char * @mkblockf( buf, pref ) @char *buf, *pref; @{ @ if ( *pref == '/' ) @ *buf = '\0'; @ else @ (void)strcpy(buf, LOCKDIR); @ return strcat(strcat(buf, pref), "."); @} @ @/* nblock(): @** Block the current process until an existing lock file is @** opened and an exclusive lock obtained on it. The name of @** the lock file is given by the concatenation of LOCKDIR @** (only if prefix does not begin with "/"), the argument @** string prefix, and a dot followed by a positive integer. @** PURPOSE: @** To limit the number of instance of a given program which @** can be running simultaneously. @** RETURN VALUE: @** >= 0 An fd open for writing. The referenced file will @** have been truncated to zero length. @** < 0 Errno will be set if the operation cannot be done. @** The calling process should probably go ahead. @*/ @nblock( prefix ) @char *prefix; @{ @ char namebuf[MAXPATHLEN]; @ char *numptr; @ @ (void)mkblockf(namebuf, prefix); @ numptr = namebuf + strlen(namebuf); @ for ( ; ; ) { @ int sufnum, fd = -1; @ unsigned sleeptime = INITSLEEPTIME; @ @ for ( sufnum=1; fd<0; sufnum++ ) { @ (void)sprintf(numptr, "%d", sufnum); @ if ( (fd=open(namebuf, O_RDWR, 0666)) < 0 ) @ if ( errno == ENOENT || sufnum == 1 ) @ break; @ else @ continue; @ if ( flock(fd, LOCK_EX|LOCK_NB) ) @ (void)close(fd), fd = -1; @ errno=0; @ } @ if ( fd >= 0 ) @ return fd; @ if ( errno && sufnum == 1 ) @ return -1; @ sleep(sleeptime); @ if ( sleeptime < MAXSLEEPTIME ) @ sleeptime += INITSLEEPTIME; @ } @ /* NOTREACHED */ @} @ @/* ublock(): @** Block the current process until a lock file is opened @** and an exclusive lock obtained on it. The file will @** be created if it does not already exist. The name of @** the lock file is given by the concatenation of LOCKDIR @** (only if prefix does not begin with "/"), the argument @** string prefix, and a dot followed by the current ruid. @** (It would have been the username, but troff has it's @** own atoi() that was messing up getpwuid().) @** PURPOSE: @** To limit users to one instance of a given program @** running at a time. @** RETURN VALUE: @** >= 0 An fd open for writing. The referenced file will @** have been truncated to zero length. @** < 0 Errno will be set if the operation cannot be done. @** The calling process should probably go ahead. @*/ @ublock( prefix ) @char *prefix; @{ @ char namebuf[MAXPATHLEN], @ uidbuf[16]; @ int fd; @ @ (void)strcat(mkblockf(namebuf, prefix), @ sprintf(uidbuf, "%d", getuid())); @ fd = open(namebuf, O_RDWR|O_CREAT, 0644); @ if ( fd >= 0 ) { @ do @ errno = 0; @ while ( flock(fd, LOCK_EX) && errno == EINTR ); @ if ( errno ) @ (void)close(fd), fd = -1; @ } @ return fd; @} 7-8-9 EOF exit