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