home *** CD-ROM | disk | FTP | other *** search
- From decwrl!labrea!rutgers!ukma!cwjcc!hal!ncoast!allbery Sun Oct 30 15:06:24 PST 1988
- Article 691 of comp.sources.misc:
- Path: granite!decwrl!labrea!rutgers!ukma!cwjcc!hal!ncoast!allbery
- From: ksb@s.cc.purdue.edu (Kevin Braunsdorf)
- Newsgroups: comp.sources.misc
- Subject: v05i014: flock - shell level access to flock(2)
- Message-ID: <8810232013.AA06867@s.cc.purdue.edu>
- Date: 28 Oct 88 02:46:21 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: ksb@s.cc.purdue.edu (Kevin Braunsdorf)
- Lines: 411
- Approved: allbery@ncoast.UUCP
-
- Posting-number: Volume 5, Issue 14
- Submitted-by: "Kevin Braunsdorf" <ksb@s.cc.purdue.edu>
- Archive-name: flock
-
- [This was supposed to have been posted a few weeks ago but somehow found a
- crack to get lost in! (oops!) ++bsa]
-
- # This is a shell archive.
- # Remove everything above and including the cut line.
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # README Makefile
- # flock.1l flock.c
- # This archive created: Sun Oct 23 15:09:58 1988
- # By: Kevin Braunsdorf (Purdue UNIX Group)
- sed 's/^K//' << \SHAR_EOF > README
- KFlock applies or removes an advisory lock on the named file or file
- Kdescriptor. Advisory locks allow cooperating processes to perform
- Kconsistent operations on files see flock(2). This program is *very*
- Kuseful on a Sequent machine; almost as useful on fast uniprocessors.
- K
- KHere is a case where flock(1) is very useful: on a Sequent Balance
- Kseries machine parallel make can be used to compile many files at the
- Ksame time. This doesn't work for programs that use xstr(1) because
- Kcompeting processes using xstrings fails. In the Makefile for vi one
- Kmight use a flock on the Makefile to force (only) the xstr to be run
- Ksequentially:
- K
- K .c.o:
- K ${CC} -E ${CFLAGS} $*.c | \
- K flock Makefile sh -c "${XSTR} -c -; mv x.c $*.p.x"; \
- K sed '/rcsid\[\]/d' < $*.p.x > $*.p.c; \
- K ${CC} ${CFLAGS} -c $*.p.c; \
- K mv $*.p.o $*.o; \
- K rm $*.p.x $*.p.c
- K
- KWhich will start a few cpps in parallel and run only one xstr at a time,
- Kas soon as it can it will run the sed/cc/mv/rm allowing another process
- Kto begin using xstr.
- K
- K(I flock the Makefile by convention, because I know I always have one.
- K If more then one command set needs to work from the same Makefile I
- K flock `complie.lock', and `yacc.lock' or some such, not using Makefile
- K for either. The clean target in the Makefile removes these files.)
- K
- Kkayessbee (Kevin S Braunsdorf) ksb@j.cc.purdue.edu, pur-ee!ksb
- SHAR_EOF
- sed 's/^K//' << \SHAR_EOF > flock.1l
- K.\" $Id: flock.1l,v 1.3 88/10/23 14:53:53 ksb Exp $
- K.\" by Kevin Braunsdorf and Matthew Bradburn
- K.TH FLOCK 1L LOCAL
- K.SH NAME
- Kflock - lock a file to synchronize command streams
- K.SH SYNOPSIS
- K\fBflock\fP [-\fBc\fP\fBh\fP\fBn\fP] [\-\fBEX\fP|\fBSH\fP|\fBUN\fP|\fBNB\fP] \fIfile\fP|\fIfd\fP [\fIcmd\fP]
- K.SH DESCRIPTION
- KFlock applies or removes an advisory lock on the named file or file descriptor.
- KAdvisory locks allow cooperating processes to perform consistent operations
- Kon files see \fIflock\fP(2).
- K.PP
- KThe exit status from the \fBflock\fP command is the exit status of
- Kits child. The default \fIcmd\fP is ``/bin/true'' so that by default
- K\fBflock\fP will succeed. \fBFlock\fP with exit nonzero if either
- K\-\fBNB\fP (nonblocking) is specified and flock fails, or
- Kthe specified \fIfile\fP (\fIfd\fP) cannot be (isn't) opened.
- K.PP
- KIt \fBflock\fP has to open the file to get the lock it will not pass
- Kthe created file descriptor to the child process. (Said process might
- Kunlock the descriptor.)
- K.SH OPTIONS
- K.TP
- K.BI \-c
- KCreate the lock file if it doesn't exist.
- K.TP
- K.BI \-h
- KGive a brief help message.
- K.TP
- K.BI \-n
- KDo not create the lock file if it doesn't exist. This is the default.
- K.TP
- K.BI \-EX
- KSet or reset the LOCK_EX bit in the arguments to \fIflock\fP(2).
- KThis is the default if no locking bits are given.
- K.TP
- K.BI \-NB
- KSet or reset the LOCK_NB bit in the arguments to \fIflock\fP(2).
- K.TP
- K.BI \-SH
- KSet or reset the LOCK_SH bit in the arguments to \fIflock\fP(2).
- K.TP
- K.BI \-UN
- KSet or reset the LOCK_UN bit in the arguments to \fIflock\fP(2).
- KThis option is only useful when a file descriptor is given as the
- K`file' on which to operate.
- K.PP
- KThe option \-\fBEX\fP may be spelled \-\fBLOCK_EX\fP, likewise the other
- Klocking bits may be spelled more verbosely.
- K.PP
- KThe locking bits may be inclusive or'ed together with a pipe (`|'), which
- Kmust be quoted from the shell.
- K.SH EXAMPLES
- K.PP
- KIf a given daemon flocks its log file before each group of writes
- Kone might use:
- K.sp 1
- K flock -EX 1 echo \*(lqsomething important\*(rq >>daemon.log
- K.sp 1
- Kto avoid interlaminate writes to the log.
- K.PP
- KIn a shell script:
- K.sp 1
- K # stdout is a (possibly) shared file so we wait for it
- K.br
- K flock -EX 1
- K.br
- K # these have to be run under one lock
- K.br
- K doit1 ; doit2; doit3
- K.br
- K # end critical code, unlock the descriptor
- K.br
- K flock -UN 1
- K.sp 1
- KTo edit a shared file:
- K.sp 1
- K flock share.c vi share.c
- K.sp 1
- K.SH BUGS
- KNone known.
- K.SH AUTHOR
- KKevin Braunsdorf
- K.br
- KPurdue University, West Laffayette IN
- K.br
- Kpur-ee!ksb, ksb@j.cc.purdue.edu
- K.SH "SEE ALSO"
- Ksh(1), true(1), flock(2), open(2)
- SHAR_EOF
- sed 's/^K//' << \SHAR_EOF > Makefile
- K# makefile for flock
- K# by Kevin S Braunsdorf, PUCC
- K
- KBIN= ${DESTDIR}$$HOME/bin
- K
- KI=/usr/include
- KS=/usr/include/sys
- K
- KINCLUDE=
- KDEBUG= -O
- KCDEFS= -Dbsd
- KCFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
- K
- KHDR=
- KSRC= flock.c
- KOBJ= flock.o
- KSOURCE= Makefile ${HDR} ${SRC}
- K
- Kall: flock
- K
- Kflock:
- K ${CC} -o $@ ${CFLAGS} flock.c
- K
- Kclean: FRC
- K rm -f Makefile.bak flock *.o a.out core errs tags
- K
- Kdepend: ${SRC} ${HDR} FRC
- K maketd -a ${CDEFS} ${INCLUDE} -b flock.c
- K
- Kinstall: all FRC
- K install -c -s flock ${BIN}
- K
- Klint: ${HDR} ${SRC} FRC
- K lint -hnx ${CDEFS} ${INCLUDE} ${SRC}
- K
- Kprint: source FRC
- K lpr -J'flock source' ${SOURCE}
- K
- Ksource: ${SOURCE}
- K
- Kspotless: clean
- K rcsclean ${SOURCE}
- K
- Ktags: ${SRC} ${HDR}
- K ctags -t ${SRC} ${HDR}
- K
- K${SOURCE}:
- K co $@
- K
- KFRC:
- K
- K# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
- K
- Kflock: $I/fcntl.h $I/stdio.h $S/file.h $S/types.h $S/wait.h flock.c
- K
- K# *** Do not add anything here - It will go away. ***
- SHAR_EOF
- sed 's/^K//' << \SHAR_EOF > flock.c
- K/*
- K * flock a file and wait for a process to exit (ksb)
- K *
- K * Copyright 1988, All Rights Reserved
- K * Kevin S Braunsdorf
- K * ksb@j.cc.purdue.edu, pur-ee!ksb
- K * Math/Sci Building, Purdue Univ
- K * West Lafayette, IN
- K *
- K * `You may redistibute this code as long as you don't claim to have
- K * written it. -- kayessbee'
- K *
- K * $Compile: ${cc-cc} ${DEBUG--C} ${SYS--Dbsd} %f -o %F
- K */
- K#include <sys/types.h>
- K#include <sys/file.h>
- K#include <sys/wait.h>
- K#include <fcntl.h>
- K#include <stdio.h>
- K
- K#if defined(bsd)
- K#define strchr index
- K#define strrchr rindex
- K#endif
- K
- Kstatic char *progname =
- K "$Id: flock.c,v 2.0 88/10/23 15:06:21 ksb Exp $";
- K
- Kstatic char acUsage[] = /* this is the usage line for the user */
- K "%s: usage [-chn] [-EX|SH|UN|NB] file|fd [cmd]\n";
- Kstatic char *apcHelp[] = { /* help text */
- K "c create file, if nonexistant",
- K "h print this help message",
- K "n do not create file",
- K "EX exclusive lock, default",
- K "NB do not block for lock",
- K "SH shared lock",
- K "UN unlock",
- K (char *)0
- K};
- K
- Ktypedef struct LKnode { /* a cmd line option implies a lock bit */
- K char *pcflag;
- K int iflag;
- K} LOCKKEY;
- K
- Kstatic LOCKKEY aLKLocks[] = { /* the list of the cmd lines we know */
- K {"LOCK_EX", LOCK_EX},
- K {"LOCK_SH", LOCK_SH},
- K {"LOCK_UN", LOCK_UN},
- K {"LOCK_NB", LOCK_NB},
- K {"EX", LOCK_EX},
- K {"SH", LOCK_SH},
- K {"UN", LOCK_UN},
- K {"NB", LOCK_NB},
- K {(char *)0, -1}
- K};
- K
- K/*
- K * determine which flag the use wants to set/clear (ksb)
- K */
- Kint
- KFlag(pcCmd)
- Kchar *pcCmd;
- K{
- K register char *pcTry;
- K register LOCKKEY *pLK;
- K extern char *strchr();
- K
- K for (pLK = aLKLocks; (char *)0 != (pcTry = pLK->pcflag); ++pLK) {
- K if (0 == strcmp(pcTry, pcCmd)) {
- K return pLK->iflag;
- K }
- K }
- K if ((char *)0 != (pcTry = strchr(pcCmd, '|'))) {
- K *pcTry++ = '\000';
- K return Flag(pcCmd)|Flag(pcTry);
- K }
- K
- K fprintf(stderr, "%s: `%s' is not a flock key\n", progname, pcCmd);
- K exit(1);
- K /*NOTREACHED*/
- K}
- K
- K/*
- K * is this character string all digits (ksb)
- K */
- Kint
- Kisnumber(pc)
- Kchar *pc;
- K{
- K while (*pc) {
- K if (*pc < '0' || *pc > '9')
- K break;
- K ++pc;
- K }
- K return *pc == '\000';
- K}
- K
- K/*
- K * Get a lock on the named file and execute the rest of our arguments (ksb)
- K * while the lock is active, when this command exits exit with it's
- K * extit status.
- K */
- Kint
- Kmain(argc, argv)
- Kint argc;
- Kchar **argv;
- K{
- K extern int atoi();
- K extern char *strrchr();
- K static char *apcTrue[] = {"true", (char *)0};
- K auto union wait wait_buf;
- K auto int fd, tClose, oFlags, fCreate = 0;
- K auto int iLock = -1;
- K auto char **ppcHelp;
- K
- K
- K if ((char *)0 != (progname = strrchr(*argv, '/'))) {
- K ++progname;
- K } else {
- K progname = *argv;
- K }
- K ++argv, --argc;
- K while (argc > 0 && '-' == argv[0][0]) {
- K switch (*++argv[0]) {
- K case '\000':
- K break;
- K case 'n':
- K case 'c':
- K fCreate = argv[0][0] == 'c';
- K argv[0][0] = '-';
- K continue;
- K case 'h':
- K fprintf(stdout, acUsage, progname);
- K for (ppcHelp = apcHelp; (char *)0 != *ppcHelp; ++ppcHelp) {
- K fprintf(stdout, "%s\n", *ppcHelp);
- K }
- K exit(0);
- K default:
- K if (-1 == iLock)
- K iLock = 0;
- K iLock ^= Flag(argv[0]);
- K break;
- K }
- K ++argv, --argc;
- K }
- K
- K if (-1 == iLock) {
- K iLock = LOCK_EX;
- K }
- K
- K if (0 == argc) {
- K fprintf(stderr, acUsage, progname);
- K exit(1);
- K }
- K
- K tClose = 1;
- K if (-1 == (fd = open(argv[0], O_RDONLY, 0600))) {
- K oFlags = 0 != fCreate ? O_CREAT|O_WRONLY|O_APPEND : O_WRONLY|O_APPEND;
- K if (-1 == (fd = open(argv[0], oFlags, 0666))) {
- K if (!isnumber(argv[0])) {
- K fprintf(stderr, "%s: open: ", progname);
- K perror(argv[0]);
- K exit(1);
- K }
- K fd = atoi(argv[0]);
- K if (-1 == fcntl(fd, F_GETFD, 0)) {
- K fprintf(stderr, "%s: %d: ", progname, fd);
- K perror("fcntl");
- K exit(1);
- K }
- K tClose = 0;
- K }
- K }
- K if (-1 == flock(fd, iLock)) {
- K fprintf(stderr, "%s: flock: ", progname);
- K perror(argv[0]);
- K exit(1);
- K }
- K ++argv, --argc;
- K
- K if (0 == argc) {
- K argv = apcTrue;
- K }
- K if (tClose != 0) { /* save a fork */
- K switch (fork()) {
- K case 0:
- K close(fd);
- K break;
- K case -1:
- K fprintf(stderr, "%s: ", progname);
- K perror("fork");
- K exit(1);
- K /*NOTREACHED*/
- K default:
- K wait(& wait_buf);
- K /* exit will close fd for us */
- K exit((int) wait_buf.w_retcode);
- K /*NOTREACHED*/
- K }
- K }
- K execvp(argv[0], argv);
- K fprintf(stderr, "%s: ", progname);
- K perror(argv[0]);
- K exit(1);
- K /*NOTREACHED*/
- K}
- SHAR_EOF
- # End of shell archive
- exit 0
-
-
-