[net.sources] 4.1c flock

steveg@tekecs.UUCP (07/05/83)

The following program is useful on 4.1c bsd for constructing shell
scripts that need to use the kernel advisory lock primitives (e.g.
vipw interactions with passwd(1) mentioned recently by sequel!phil).
It needs no particular permissions, and works with the 4.1c kernel file
locking primitives.

	Steve Glaser, tektronix!steveg or steveg.tektronix@rand-relay

>>>>>>>>>>>>>>man page<<<<<<<<<<<<<<<

\" $Header: /usr/man/manl/man1/RCS/flock.1,v 1.4 83/07/05 00:31:03 steveg Exp $$Locker:  $
.TH FLOCK 1 "4 July 1983 (Tektronix)"
.SH NAME
flock \- file lock
.SH SYNOPSIS
.B flock
[
.B \-w
] [
.B \-t
] [
.B \-c
.I command
] [
.B \-s
]
.I file
.br
.SH DESCRIPTION
.I Flock
attempts to lock the specified
.I file
and preform the indicated action.
It is intended for use in shell scripts to aid in manipulating files amongst cooperating processes.
It used the advisory lock mechanism provided by the kernel (see open(2)).
.PP
The
.B \-t
option tests to see if a lock is possible on the indicated file.
It returns an error if the lock is not available.
.PP
The
.B \-c
option invokes the indicated command as a subprocess while holding the lock.
Typical use of this option might be
.IP
flock -c 'vi /etc/passwd' /etc/passwd
.PP
which edits the password file locking out access by passwd(1).
.PP
The
.B \-w
option gets the lock and then forks a child process to keep the lock active.
.I Flock
prints the process id of this process on standard output and exits
(leaving the child in the background).
.PP
Typical use of the
.B \-w
would be (using csh):
.LP
.in +.5i
.nf
	set p=`flock -w file`
	if ($status == 0) then
		<sequence of commands updating file>
		kill -HUP $p
	else
		echo "can't get a lock on file"
	endif
.fi
.in -.5i
.LP
The
.B \-s
option asks for a
.I shared
lock instead of the default
.I exculsive
lock.
.SH "SEE ALSO"
open(2), passwd(1), flock(2)
.SH BUGS
.I Flock
only prevents access from cooperating programs.
The file may still be maniuplated in the usual ways by programs ignoring the locking protocol.
.PP
The locking mechanism in the kernel is still undergoing changes.
This program will probably need rework as the kernel primitives change.
.PP
The
.B \-w
option is somewhat wasteful of processes and can leave files locked long after
a user has logged off.
A timer that causes the child to go away might be useful.
.SH AUTHOR
Steve Glaser, Tektronix Inc. (tektronix!steveg or steveg.tektronix@rand-relay)

>>>>>>>>>>>>>>program itself<<<<<<<<<<<<<<<<<

/*
 * file lock program
 *
 * aids in using the new file lock primitives from shell scripts
 *
 * flock -w file
 *	opens file with an exculsive lock and waits in the background
 *	prints the process id on standard output of the waiting process
 *	HUP signal will cause waiting process to unlock the file and exit
 *	status returned from flock is 0 if lock was successful
 *
 * flock file command
 *	opens file with an exclusive lock and then runs command
 *	result status is the result of "command"
 *
 * flock -t file
 *	tests to see if a lock would succeed on file
 *
 * Copyright (c) 1983, Tektronix Inc.
 * All Rights Reserved
 *
 */

char _rcsid[] = "$Header: /da/steveg/.src/flock.c,v 1.1 83/06/22 21:43:03 steveg Exp $$Locker:  $";

#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <errno.h>
#include <signal.h>

int	wflag = 0;
int	tflag = 1;
int	cflag = 0;
int	sflag = 0;
int	wpid = -1;
int	lockfd = -1;
char	*fname = NULL;
char	*command = NULL;

extern int errno;
extern int fork();
extern int strcmp();
extern int system();

main(argc, argv)
	int argc;
	char *argv[];
{
	while (argc > 1) {
		if (strcmp(argv[1], "-s") == 0) {
			sflag = 1;
		} else if (strcmp(argv[1], "-w") == 0) {
			wflag = 1;
			tflag = cflag = 0;
		} else if (strcmp(argv[1], "-t") == 0) {
			tflag = 1;
			wflag = cflag = 0;
		} else if (strcmp(argv[1], "-c") == 0) {
			if (argc > 2) {
				command = argv[2];
				argc--; argv++;
				cflag = 1;
				wflag = tflag = 0;
			} else {
				fprintf(stderr, "flock: no command specified for -c\n");
				goto usage;
			}
		} else if (fname == NULL) {
			fname = argv[1];
		} else {
			fprintf(stderr, "flock: too many arguments\n");
	usage:		
			fprintf(stderr, "Usage: flock [-w|-t|-c command] [-s] file\n");
			exit(3);
		}
		argc--; argv++;
	}
	if (fname == NULL) {
		fprintf(stderr, "flock: no file specified\n");
		goto usage;
	}
	if (tflag == 0 && wflag == 0 && cflag == 0) {
		fprintf(stderr, "flock: no option specified\n");
		goto usage;
	}

	if (tflag) {
		lockfd = open(fname, sflag? FNBLOCK+FRDONLY+FSHLOCK: FNBLOCK+FRDONLY+FEXLOCK);
		if (lockfd >= 0)
			exit(0);
		else if (errno == EWOULDBLOCK) {
			fprintf(stderr, "flock: ");
			perror(fname);
			exit(1);
		} else {
			fprintf(stderr, "flock: ");
			perror(fname);
			exit(2);
		}
	} else {
		lockfd = open(fname, sflag? FRDONLY+FSHLOCK: FRDONLY+FEXLOCK);
		if (lockfd < 0) {
			fprintf(stderr, "flock: ");
			perror(fname);
			exit(2);
		}
		if (cflag) {
			return(system(command));
		} else {
			wpid = fork();
			if (wpid == 0) {	/* child */
				signal(SIGHUP, SIG_DFL);
				pause();
				exit(2);
			} else {		/* parent */
				printf("%d\n", wpid);
				exit(0);
			}
		}
	}
}

>>>>>>>>>>>>>> end of submission <<<<<<<<<<<<<<<
rcp: flock.1: Permission denied