uucplock.c revision 36451
185909Simp/*
285909Simp * Copyright (c) 1988, 1993
385909Simp *	The Regents of the University of California.  All rights reserved.
485909Simp *
585909Simp * Redistribution and use in source and binary forms, with or without
685909Simp * modification, are permitted provided that the following conditions
785909Simp * are met:
885909Simp * 1. Redistributions of source code must retain the above copyright
985909Simp *    notice, this list of conditions and the following disclaimer.
1085909Simp * 2. Redistributions in binary form must reproduce the above copyright
1185909Simp *    notice, this list of conditions and the following disclaimer in the
1285909Simp *    documentation and/or other materials provided with the distribution.
1385909Simp * 3. All advertising materials mentioning features or use of this software
1485909Simp *    must display the following acknowledgement:
1585909Simp *	This product includes software developed by the University of
1685909Simp *	California, Berkeley and its contributors.
1785909Simp * 4. Neither the name of the University nor the names of its contributors
1885909Simp *    may be used to endorse or promote products derived from this software
1985909Simp *    without specific prior written permission.
2085909Simp *
2185909Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2285909Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2385909Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2485909Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2585909Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2685909Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2785909Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2885909Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2985909Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3085909Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3185909Simp * SUCH DAMAGE.
3285909Simp *
3385909Simp * $Id: uucplock.c,v 1.8 1997/08/10 18:42:39 ache Exp $
3485909Simp *
3585909Simp */
3685909Simp
3785909Simp#ifndef lint
3885909Simpstatic const char sccsid[] = "@(#)uucplock.c	8.1 (Berkeley) 6/6/93";
3985909Simp#endif /* not lint */
4085909Simp
4185909Simp#include <sys/types.h>
4285909Simp#include <sys/file.h>
4385909Simp#include <dirent.h>
4485909Simp#include <errno.h>
4585909Simp#include <unistd.h>
4685909Simp#include <signal.h>
4785909Simp#include <stdio.h>
4885909Simp#include <stdlib.h>
4985909Simp#include <paths.h>
5085909Simp#include <string.h>
5185909Simp#include "libutil.h"
5285909Simp
5385909Simp#define MAXTRIES 5
5485909Simp
5585909Simp#define LOCKTMP "LCKTMP..%d"
5685909Simp#define LOCKFMT "LCK..%s"
5785909Simp
5885909Simp#define GORET(level, val) { err = errno; uuerr = (val); \
5985909Simp			    goto __CONCAT(ret, level); }
6085909Simp
6185909Simp/* Forward declarations */
6285909Simpstatic int put_pid (int fd, pid_t pid);
6385909Simpstatic pid_t get_pid (int fd,int *err);
6485909Simp
6585909Simp/*
6685909Simp * uucp style locking routines
6785909Simp */
6885909Simp
6985909Simpint
7085909Simpuu_lock(const char *ttyname)
7185909Simp{
7285909Simp	int fd, tmpfd, i;
7385909Simp	pid_t pid;
7485909Simp	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
7585909Simp	     lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
7685909Simp	int err, uuerr;
7785909Simp
7885909Simp	pid = getpid();
7985909Simp	(void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
8085909Simp			pid);
8185909Simp	(void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
8285909Simp			ttyname);
8385909Simp	if ((tmpfd = creat(lcktmpname, 0664)) < 0)
8485909Simp		GORET(0, UU_LOCK_CREAT_ERR);
8585909Simp
8685909Simp	for (i = 0; i < MAXTRIES; i++) {
8785909Simp		if (link (lcktmpname, lckname) < 0) {
8885909Simp			if (errno != EEXIST)
8985909Simp				GORET(1, UU_LOCK_LINK_ERR);
9085909Simp			/*
9185909Simp			 * file is already locked
9285909Simp			 * check to see if the process holding the lock
9385909Simp			 * still exists
9485909Simp			 */
9585909Simp			if ((fd = open(lckname, O_RDONLY)) < 0)
9685909Simp				GORET(1, UU_LOCK_OPEN_ERR);
9785909Simp
9885909Simp			if ((pid = get_pid (fd, &err)) == -1)
9985909Simp				GORET(2, UU_LOCK_READ_ERR);
10085909Simp
10185909Simp			close(fd);
10285909Simp
10385909Simp			if (kill(pid, 0) == 0 || errno != ESRCH)
10485909Simp				GORET(1, UU_LOCK_INUSE);
10585909Simp			/*
10685909Simp			 * The process that locked the file isn't running, so
10785909Simp			 * we'll lock it ourselves
10885909Simp			 */
10985909Simp			(void)unlink(lckname);
11085909Simp		} else {
11185909Simp			if (!put_pid (tmpfd, pid))
11285909Simp				GORET(3, UU_LOCK_WRITE_ERR);
11385909Simp			break;
11485909Simp		}
11585909Simp	}
11685909Simp	GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
11785909Simp
11885909Simpret3:
11985909Simp	(void)unlink(lckname);
12085909Simp	goto ret1;
12185909Simpret2:
12285909Simp	(void)close(fd);
12385909Simpret1:
12485909Simp	(void)close(tmpfd);
12585909Simp	(void)unlink(lcktmpname);
12685909Simpret0:
12785909Simp	errno = err;
12885909Simp	return uuerr;
12985909Simp}
13085909Simp
13185909Simpint
13285909Simpuu_lock_txfr(const char *ttyname, pid_t pid)
13385909Simp{
13485909Simp	int fd, err;
13585909Simp	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
13685909Simp
13785909Simp	snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, ttyname);
13885909Simp
13985909Simp	if ((fd = open(lckname, O_RDWR)) < 0)
14085909Simp		return UU_LOCK_OWNER_ERR;
14185909Simp	if (get_pid(fd, &err) != getpid())
14285909Simp		return UU_LOCK_OWNER_ERR;
14385909Simp        lseek(fd, 0, SEEK_SET);
14485909Simp	if (put_pid(fd, pid))
14585909Simp		return UU_LOCK_WRITE_ERR;
14685909Simp	close(fd);
14785909Simp
14885909Simp	return UU_LOCK_OK;
14985909Simp}
15085909Simp
15185909Simpint
15285909Simpuu_unlock(const char *ttyname)
15385909Simp{
15485909Simp	char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
15585909Simp
15685909Simp	(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname);
15785909Simp	return unlink(tbuf);
15885909Simp}
15985909Simp
16085909Simpconst char *
16185909Simpuu_lockerr(int uu_lockresult)
16285909Simp{
16385909Simp	static char errbuf[128];
16485909Simp	char *fmt;
16585909Simp
16685909Simp	switch (uu_lockresult) {
16785909Simp		case UU_LOCK_INUSE:
16885909Simp			return "device in use";
16985909Simp		case UU_LOCK_OK:
17085909Simp			return "";
17185909Simp		case UU_LOCK_OPEN_ERR:
17285909Simp			fmt = "open error: %s";
17385909Simp			break;
17485909Simp		case UU_LOCK_READ_ERR:
17585909Simp			fmt = "read error: %s";
17685909Simp			break;
17785909Simp		case UU_LOCK_CREAT_ERR:
17885909Simp			fmt = "creat error: %s";
17985909Simp			break;
18085909Simp		case UU_LOCK_WRITE_ERR:
18185909Simp			fmt = "write error: %s";
18285909Simp			break;
18385909Simp		case UU_LOCK_LINK_ERR:
18485909Simp			fmt = "link error: %s";
18585909Simp			break;
18685909Simp		case UU_LOCK_TRY_ERR:
18785909Simp			fmt = "too many tries: %s";
18885909Simp			break;
18985909Simp		case UU_LOCK_OWNER_ERR:
19085909Simp			fmt = "not locking process: %s";
19185909Simp			break;
19285909Simp		default:
19385909Simp			fmt = "undefined error: %s";
19485909Simp			break;
19585909Simp	}
19685909Simp
19785909Simp	(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
19885909Simp	return errbuf;
19985909Simp}
20085909Simp
20185909Simpstatic int
20285909Simpput_pid(int fd, pid_t pid)
20385909Simp{
20485909Simp	char buf[32];
20585909Simp	int len;
20685909Simp
20785909Simp	len = sprintf (buf, "%10d\n", pid);
20885909Simp	return write (fd, buf, len) == len;
20985909Simp}
21085909Simp
21185909Simpstatic pid_t
21285909Simpget_pid(int fd, int *err)
21385909Simp{
21485909Simp	int bytes_read;
21585909Simp	char buf[32];
21685909Simp	pid_t pid;
21785909Simp
21885909Simp	bytes_read = read (fd, buf, sizeof (buf) - 1);
21985909Simp	if (bytes_read > 0) {
22085909Simp		buf[bytes_read] = '\0';
22185909Simp		pid = strtol (buf, (char **) NULL, 10);
22285909Simp	} else {
22385909Simp		pid = -1;
22485909Simp		*err = bytes_read ? errno : EINVAL;
22585909Simp	}
22685909Simp	return pid;
22785909Simp}
22885909Simp
22985909Simp/* end of uucplock.c */
23085909Simp