#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2009-04-25 20:10 EDT by <rbthomas@fileserver.rcthomas.org>.
# Source directory was `/home/rbthomas/src'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    328 -rwx--s--- shlock/Makefile
#    980 -rwx--s--- shlock/shlock.1
#   3560 -rwx--s--- shlock/shlock.c
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh29125; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= shlock/Makefile ==============
if test ! -d 'shlock'; then
  $echo 'x -' 'creating directory' 'shlock'
  mkdir 'shlock'
fi
if test -f 'shlock/Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'shlock/Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'shlock/Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'shlock/Makefile' &&
# where to install the binary and man page
IDIR	= /usr/local/bin
MDIR	= /usr/local/man
# install flags
IFLAGS	= -m 0555
X
# build options
CC	= gcc
CFLAGS	= -Wall
X
shlock:	shlock.c
X	$(CC) $(CFLAGS) -o shlock shlock.c
X
install: shlock
X	install $(IFLAGS) shlock $(IDIR)/shlock
X	cp shlock.1  $(MDIR)/man1/shlock.1
X
clean:
X	rm shlock
SHAR_EOF
  (set 19 96 02 26 11 39 14 'shlock/Makefile'; eval "$shar_touch") &&
  chmod 0700 'shlock/Makefile' ||
  $echo 'restore of' 'shlock/Makefile' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'shlock/Makefile:' 'MD5 check failed'
02edd3b093253616b88cbc8b88c81edf  shlock/Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'shlock/Makefile'`"
    test 328 -eq "$shar_count" ||
    $echo 'shlock/Makefile:' 'original size' '328,' 'current size' "$shar_count!"
  fi
fi
# ============= shlock/shlock.1 ==============
if test -f 'shlock/shlock.1' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'shlock/shlock.1' '(file already exists)'
else
  $echo 'x -' extracting 'shlock/shlock.1' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'shlock/shlock.1' &&
X.TH SHLOCK l-ucb
X.SH NAME
shlock \- obtain exclusive lock for current shell script
X.SH ORIGIN
4.2BSD
X.SH SYNOPSIS
X.br
X.B shlock
X.B \-f
lockfile
X.B \-p
$$
X.SH DESCRIPTION
X.I Shlock
is a program which provides a shell script with the ability to
lock out copies of itself from running concurrently.  The first time
X.I shlock
attempts to create file
X.I lockfile,
it will write the current pid, represented in a shell scipt by $$,
into
X.I lockfile
and return status 0.  Should another copy of the script
begin to run before the first one finishes,
X.I shlock
will see that
X.I lockfile
already exists and check to see if some process exists whose pid
matches the one given in the existing
X.I lockfile.
If the match succeeds
the program will return status 1.  If no process having a matching
pid can be found, it is assumed that the script that created
X.I lockfile
halted wihtout deleting it.  At this point a new
X.I lockfile
will be created with the new pid.
X.SH SEE\ ALSO
sh(1), csh(1)
SHAR_EOF
  (set 19 88 12 07 19 11 49 'shlock/shlock.1'; eval "$shar_touch") &&
  chmod 0700 'shlock/shlock.1' ||
  $echo 'restore of' 'shlock/shlock.1' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'shlock/shlock.1:' 'MD5 check failed'
2867a2fea0a99af02d60d5ba0f4e0ec4  shlock/shlock.1
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'shlock/shlock.1'`"
    test 980 -eq "$shar_count" ||
    $echo 'shlock/shlock.1:' 'original size' '980,' 'current size' "$shar_count!"
  fi
fi
# ============= shlock/shlock.c ==============
if test -f 'shlock/shlock.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'shlock/shlock.c' '(file already exists)'
else
  $echo 'x -' extracting 'shlock/shlock.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'shlock/shlock.c' &&
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/file.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
X
#ifndef rindex
#define rindex strrchr
#endif
X
#define	LOCK_SET	0
#define	LOCK_FAIL	1
X
#define TRUE	1
#define	FALSE	0
X
int	verbose = FALSE;
char	*pname;
char	*USAGE = "%s: USAGE: shlock -f file -p pid [-v]\n";
#define errmsg strerror
char	*tmpxfile(char *file);
int	p_exists(int pid);
int	mklock(char *file, int pid);
int	cklock(char *file);
X
int main(int ac, char *av[])
{
X	register int	x;
X	char	*file;
X	int	pid;
X
X	pname = ((pname = rindex(av[0], '/')) ? pname + 1 : av[0]);
X
X	if (ac < 5) {
X		fprintf(stderr, USAGE, pname);
X		exit(LOCK_FAIL);
X	}
X
X	for(x = 1; x < ac; x++) {
X		if (av[x][0] == '-') {
X			switch(av[x][1]) {
X			case 'v':
X				verbose = TRUE;
X				break;
X			case 'p':
X				if (strlen(av[x]) > 2) {
X					pid = atoi(&av[x][2]);
X				} else {
X					pid = atoi(av[x + 1]);
X					x++;
X				}
X				break;
X			case 'f':
X				if (strlen(av[x]) > 2) {
X					file = &av[x][2];
X				} else {
X					file = av[x + 1];
X					x++;
X				}
X				break;
X			default:
X				fprintf(stderr, USAGE, pname);
X				exit(LOCK_FAIL);
X			}
X		}
X	}
X	if (pid == 0 || file == (char *)NULL) {
X		fprintf(stderr, USAGE, pname);
X		exit(LOCK_FAIL);
X	}
X	if (mklock(file, pid))
X		exit(LOCK_SET);
X	exit(LOCK_FAIL);
}
X
int
mklock(char *file, int pid)
{
X	register int	fd;
X	register int	len;
X	register char	*tmp = tmpxfile(file);
X	char	buf[BUFSIZ];
X
X	sprintf(buf, "%d\n", pid);
X	len = strlen(buf);
loop:
X	if ((fd = open(tmp, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
X		switch(errno) {
X		case EEXIST:
X			if (unlink(tmp) < 0) {
X				fprintf(stderr,"%s: unlink(%s): %s\n", pname, tmp, errmsg(errno));
X				return(FALSE);
X			}
X			/*
X			** I hereby profane the god of structured programming
X			** Edsgar Djikstra
X			*/
X			goto loop;
X		default:
X			fprintf(stderr,"%s: open(%s): %s\n", pname, tmp, errmsg(errno));
X			return(FALSE);
X		}
X	}
X	if (write(fd, buf, len) < 0) {
X		fprintf(stderr, "%s: write(%s,%d): %s\n", pname, tmp, pid, errmsg(errno));
X		close(fd);
X		return(FALSE);
X	}
X	close(fd);
X
loop2:
X	if (link(tmp, file) < 0) {
X		switch(errno) {
X		case EEXIST:
X			if (cklock(file)) {
X				if (unlink(tmp) < 0) {
X					fprintf(stderr,"%s: unlink(%s): %s\n", pname, tmp, errmsg(errno));
X				}
X				return(FALSE);
X			} else if (unlink(file) < 0) {
X				fprintf(stderr,"%s: unlink(%s): %s\n", pname, file, errmsg(errno));
X				return(FALSE);
X			}
X			goto loop2;
X		default:
X			fprintf(stderr,"%s: link(%s, %s): %s\n", pname, tmp, file, errmsg(errno));
X			return(FALSE);
X		}
X	}
X	if (unlink(tmp) < 0) {
X		fprintf(stderr,"%s: unlink(%s): %s\n", pname, tmp, errmsg(errno));
X	}
X	return(TRUE);
}
X
int
cklock(char *file)
{
X	register int	fd = open(file, O_RDONLY);
X	register int	len;
X	char	buf[BUFSIZ];
X
X	if (fd < 0)
X		return(FALSE);
X	
X	if ((len = read(fd, buf, sizeof(buf))) <= 0) {
X		close(fd);
X		return(FALSE);
X	}
X	close(fd);
X	buf[len + 1] = '\0';
X	return(p_exists(atoi(buf)));
}
X
int
p_exists(int pid)
{
X	if (kill(pid, 0) < 0) {
X		switch(errno) {
X		case ESRCH:
X			return(FALSE);	/* pid does not exist */
X		case EPERM:
X			return(TRUE);	/* pid exists */
X		default:
X			return(TRUE);	/* be conservative */
X		}
X	}
X	return(TRUE);	/* pid exists */
}
X
char *
tmpxfile(char *file)
{
X	register char	*cp;
X	static char	buf[BUFSIZ];
X	char	tempname[BUFSIZ];
X
X	if ((cp = rindex(strcpy(buf, file), '/')) != (char *)NULL) {
X		*(cp + 1) = '\0';
X	} else
X		buf[0] = '\0';
X	sprintf(tempname, "shlock%d", (int)getpid());
X	return(strcat(buf, tempname));
}
SHAR_EOF
  (set 20 02 12 04 18 09 34 'shlock/shlock.c'; eval "$shar_touch") &&
  chmod 0700 'shlock/shlock.c' ||
  $echo 'restore of' 'shlock/shlock.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'shlock/shlock.c:' 'MD5 check failed'
b6c5d11b0e7929dda4054bc12121edc4  shlock/shlock.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'shlock/shlock.c'`"
    test 3560 -eq "$shar_count" ||
    $echo 'shlock/shlock.c:' 'original size' '3560,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh29125
exit 0
