[alt.sources] flock command for XENIX

richard@berner.uucp (Richard Greenall) (07/20/89)

I was in need of an equivilent to the BSD flock command under XENIX 2.3.2, so
I wrote one.  It comes in handy in shell scripts.

So without further adieu, here it is.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  flock.c
# Wrapped by richard@berner on Thu Jul 20 12:43:42 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'flock.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'flock.c'\"
else
echo shar: Extracting \"'flock.c'\" \(4361 characters\)
sed "s/^X//" >'flock.c' <<'END_OF_FILE'
X/*  flock.
X	
X	This program is a close equivilent to the 4.3 bsd flock command for
X	locking files from the command line.  The only differences between this
X	flock command and the bsd flock command is that only 1 file name
X	may appear on the command line instead of multiple file names.
X
X	This program is in the public domain and may be used and
X	distributed as long as this message is not removed from the source.
X
X	This program was written under SCO XENIX 2.3.2 (386) but should
X	run under any SYSTEM V machine with little change.  I have tried
X	to stay away from anything XENIX specific, but who knows? 
X
X									Richard Greenall
X									berner!richard
X*/
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <values.h>
X#include <getopt.h>
X#include <prototypes.h>
X
Xint child, parent, fildes;
X
Xvoid (*deffunc1)();
Xvoid (*deffunc2)();
X
Xvoid childdone( void );
Xvoid killchild( void );
Xvoid closefile( void );
X
Xint main(argc,argv) 
Xint argc;
Xchar *argv[];
X{
X	int c,shared,exclusive,nonblocking,errflag;
X	int status;
X
X	struct flock flock;
X
X	/* initialize all data to zero at begining  */
X
X	c = shared = exclusive = nonblocking = errflag = 0;
X	parent = getpid();
X
X	/* get options.  Options to the program are s, e, & n without
X		any parameters.  The options s & e are mutually exclusive */
X
X	while( (c = getopt(argc,argv,"sen")) != EOF)
X		switch( (char) c ) {
X			case 's' : shared++; break;
X			case 'e' : exclusive++; break;
X			case 'n' : nonblocking++; break;
X			case '?' : errflag++; break;
X		}
X
X	/* check for errors from options and report if any */
X
X	if(errflag || (shared && exclusive) || argc != optind+1 ) {
X		fprintf(stderr,"Usage : %s [ -sen ] filename\n",argv[0]);
X		exit(1);
X	}
X
X	/* if neither shared or exclusive flag set, default to exclusive mode */
X	if(!shared && !exclusive) exclusive++;
X
X	/* use this signal to let the parent know when everything has gone
X		ok, and that it may exit */
X
X	signal(SIGUSR1,childdone);
X
X	switch(child = fork()) {
X		case -1:
X			perror(argv[0]);
X			exit(1);
X		case 0:
X			/* ignore break key presses */
X
X			signal(SIGINT,SIG_IGN);
X
X			/* open the file for read only if shared access requested, read and
X				write if exclusive */
X
X			fildes = open(argv[optind], (shared) ? O_RDONLY : O_RDWR);
X			if(fildes == -1) {
X				perror(argv[0]);
X				exit(1);
X			}
X
X			/* set flags to lock the entire file */
X
X			flock.l_whence = 0;
X			flock.l_start = flock.l_len = 0L;
X
X			/* type of lock */
X			if(shared) flock.l_type = F_RDLCK;
X			if(exclusive) flock.l_type = F_WRLCK;
X
X			/* use fcntl to lock the file.  If the type of lock is
X				blocking, and we get an error, report it.  If the 
X				type of lock is nonblocking and we get an error, it 
X				could be that another process has the file
X				locked, so just report is silently by exiting 
X				with status 1 */
X	
X			if(fcntl(fildes,(nonblocking) ? F_SETLK : F_SETLKW, &flock)== -1)
X				if(nonblocking) {
X					if(errno == EAGAIN) {
X						fprintf(stderr, "%s: Operation would block\n",argv[0]);
X						exit(2);
X					}
X					else {
X						perror(argv[0]);
X						exit(1);
X					}
X				} else {
X					perror(argv[0]);
X					exit(1);
X				}
X
X			/* let the parent know that everything has gone ok, and it
X				can exit */
X
X			kill(parent,SIGUSR1);
X
X			/* set up to sleep forever */
X
X			signal(SIGTERM,closefile);
X
X			/* close all streams so that the shell will not expect any
X				more output */
X
X			fclose(stdin);
X			fclose(stdout);
X			fclose(stderr);
X
X			/* sleep forever till killed */
X
X			for ( ; ; ) sleep(MAXINT);
X
X		default:
X			/* kill the child if any signals are received while waiting */
X			deffunc1 = signal(SIGINT,killchild);
X			deffunc2 = signal(SIGHUP,killchild);
X
X			/* if this wait returns, there must have been an error becuase
X				an ok exit would call the function childdone() */
X
X			wait(&status);
X			signal(SIGINT,deffunc1);
X			signal(SIGHUP,deffunc2);
X
X			/* now exit with the same status code as the child (high order
X				8 bits */
X			exit( (status >> 8) );
X		}
X	/* NOTREACHED */
X}
X
X
Xvoid childdone() {
X	/* child has finished so exit printing out its pid number so that
X		it may be killed later by the user */
X	printf("%d\n",child);
X	exit(0);
X}
X
X
Xvoid killchild() {
X	/* a Break was hit, so kill the child so that the lock won't be left */
X	kill(child,SIGTERM);
X	exit(1);
X}
X
X
Xvoid closefile() {
X	close(fildes);
X	exit(0);
X}

END_OF_FILE
echo shar: NEWLINE appended to \"'flock.c'\"
if test 4362 -ne `wc -c <'flock.c'`; then
    echo shar: \"'flock.c'\" unpacked with wrong size!
fi
# end of 'flock.c'
fi
echo shar: End of shell archive.
exit 0