xref: /freebsd/lib/libutil/uucplock.c (revision 46cf264a2645fc71e5511ba795d85d87ce47dc23)
1568b59b9SBrian Somers /*
2568b59b9SBrian Somers  * Copyright (c) 1988, 1993
3568b59b9SBrian Somers  *	The Regents of the University of California.  All rights reserved.
4568b59b9SBrian Somers  *
5568b59b9SBrian Somers  * Redistribution and use in source and binary forms, with or without
6568b59b9SBrian Somers  * modification, are permitted provided that the following conditions
7568b59b9SBrian Somers  * are met:
8568b59b9SBrian Somers  * 1. Redistributions of source code must retain the above copyright
9568b59b9SBrian Somers  *    notice, this list of conditions and the following disclaimer.
10568b59b9SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
11568b59b9SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
12568b59b9SBrian Somers  *    documentation and/or other materials provided with the distribution.
13568b59b9SBrian Somers  * 3. All advertising materials mentioning features or use of this software
14568b59b9SBrian Somers  *    must display the following acknowledgement:
15568b59b9SBrian Somers  *	This product includes software developed by the University of
16568b59b9SBrian Somers  *	California, Berkeley and its contributors.
17568b59b9SBrian Somers  * 4. Neither the name of the University nor the names of its contributors
18568b59b9SBrian Somers  *    may be used to endorse or promote products derived from this software
19568b59b9SBrian Somers  *    without specific prior written permission.
20568b59b9SBrian Somers  *
21568b59b9SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22568b59b9SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23568b59b9SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24568b59b9SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25568b59b9SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26568b59b9SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27568b59b9SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28568b59b9SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29568b59b9SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30568b59b9SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31568b59b9SBrian Somers  * SUCH DAMAGE.
3228804f92SAndrey A. Chernov  *
3346cf264aSBrian Somers  * $Id: uucplock.c,v 1.8 1997/08/10 18:42:39 ache Exp $
3428804f92SAndrey A. Chernov  *
35568b59b9SBrian Somers  */
36568b59b9SBrian Somers 
37568b59b9SBrian Somers #ifndef lint
38568b59b9SBrian Somers static const char sccsid[] = "@(#)uucplock.c	8.1 (Berkeley) 6/6/93";
39568b59b9SBrian Somers #endif /* not lint */
40568b59b9SBrian Somers 
41568b59b9SBrian Somers #include <sys/types.h>
42568b59b9SBrian Somers #include <sys/file.h>
43568b59b9SBrian Somers #include <dirent.h>
44568b59b9SBrian Somers #include <errno.h>
45568b59b9SBrian Somers #include <unistd.h>
46568b59b9SBrian Somers #include <signal.h>
47568b59b9SBrian Somers #include <stdio.h>
48568b59b9SBrian Somers #include <stdlib.h>
49568b59b9SBrian Somers #include <paths.h>
50687d0cdeSBrian Somers #include <string.h>
51687d0cdeSBrian Somers #include "libutil.h"
52568b59b9SBrian Somers 
5384dc2299SAndrey A. Chernov #define MAXTRIES 5
5484dc2299SAndrey A. Chernov 
5584dc2299SAndrey A. Chernov #define LOCKTMP "LCKTMP..%d"
56568b59b9SBrian Somers #define LOCKFMT "LCK..%s"
57568b59b9SBrian Somers 
5884dc2299SAndrey A. Chernov #define GORET(level, val) { err = errno; uuerr = (val); \
5984dc2299SAndrey A. Chernov 			    goto __CONCAT(ret, level); }
6084dc2299SAndrey A. Chernov 
61568b59b9SBrian Somers /* Forward declarations */
62568b59b9SBrian Somers static int put_pid (int fd, pid_t pid);
63687d0cdeSBrian Somers static pid_t get_pid (int fd,int *err);
64568b59b9SBrian Somers 
65568b59b9SBrian Somers /*
66568b59b9SBrian Somers  * uucp style locking routines
67568b59b9SBrian Somers  */
68568b59b9SBrian Somers 
6946cf264aSBrian Somers int
7046cf264aSBrian Somers uu_lock(const char *ttyname)
71568b59b9SBrian Somers {
7284dc2299SAndrey A. Chernov 	int fd, tmpfd, i;
73568b59b9SBrian Somers 	pid_t pid;
7484dc2299SAndrey A. Chernov 	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
7584dc2299SAndrey A. Chernov 	     lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
7684dc2299SAndrey A. Chernov 	int err, uuerr;
77568b59b9SBrian Somers 
7884dc2299SAndrey A. Chernov 	pid = getpid();
7984dc2299SAndrey A. Chernov 	(void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
8084dc2299SAndrey A. Chernov 			pid);
8184dc2299SAndrey A. Chernov 	(void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
8284dc2299SAndrey A. Chernov 			ttyname);
8384dc2299SAndrey A. Chernov 	if ((tmpfd = creat(lcktmpname, 0664)) < 0)
8484dc2299SAndrey A. Chernov 		GORET(0, UU_LOCK_CREAT_ERR);
8584dc2299SAndrey A. Chernov 
8684dc2299SAndrey A. Chernov 	for (i = 0; i < MAXTRIES; i++) {
8784dc2299SAndrey A. Chernov 		if (link (lcktmpname, lckname) < 0) {
8884dc2299SAndrey A. Chernov 			if (errno != EEXIST)
8984dc2299SAndrey A. Chernov 				GORET(1, UU_LOCK_LINK_ERR);
90568b59b9SBrian Somers 			/*
91568b59b9SBrian Somers 			 * file is already locked
9284dc2299SAndrey A. Chernov 			 * check to see if the process holding the lock
9384dc2299SAndrey A. Chernov 			 * still exists
94568b59b9SBrian Somers 			 */
9584dc2299SAndrey A. Chernov 			if ((fd = open(lckname, O_RDONLY)) < 0)
9684dc2299SAndrey A. Chernov 				GORET(1, UU_LOCK_OPEN_ERR);
97687d0cdeSBrian Somers 
9884dc2299SAndrey A. Chernov 			if ((pid = get_pid (fd, &err)) == -1)
9984dc2299SAndrey A. Chernov 				GORET(2, UU_LOCK_READ_ERR);
100568b59b9SBrian Somers 
10184dc2299SAndrey A. Chernov 			close(fd);
10284dc2299SAndrey A. Chernov 
10384dc2299SAndrey A. Chernov 			if (kill(pid, 0) == 0 || errno != ESRCH)
10484dc2299SAndrey A. Chernov 				GORET(1, UU_LOCK_INUSE);
105568b59b9SBrian Somers 			/*
106568b59b9SBrian Somers 			 * The process that locked the file isn't running, so
107568b59b9SBrian Somers 			 * we'll lock it ourselves
108568b59b9SBrian Somers 			 */
10984dc2299SAndrey A. Chernov 			(void)unlink(lckname);
11084dc2299SAndrey A. Chernov 		} else {
11184dc2299SAndrey A. Chernov 			if (!put_pid (tmpfd, pid))
11284dc2299SAndrey A. Chernov 				GORET(3, UU_LOCK_WRITE_ERR);
11384dc2299SAndrey A. Chernov 			break;
11484dc2299SAndrey A. Chernov 		}
11584dc2299SAndrey A. Chernov 	}
11684dc2299SAndrey A. Chernov 	GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
11784dc2299SAndrey A. Chernov 
11884dc2299SAndrey A. Chernov ret3:
11984dc2299SAndrey A. Chernov 	(void)unlink(lckname);
12084dc2299SAndrey A. Chernov 	goto ret1;
12184dc2299SAndrey A. Chernov ret2:
122568b59b9SBrian Somers 	(void)close(fd);
12384dc2299SAndrey A. Chernov ret1:
12484dc2299SAndrey A. Chernov 	(void)close(tmpfd);
12584dc2299SAndrey A. Chernov 	(void)unlink(lcktmpname);
12684dc2299SAndrey A. Chernov ret0:
127687d0cdeSBrian Somers 	errno = err;
12884dc2299SAndrey A. Chernov 	return uuerr;
129568b59b9SBrian Somers }
130568b59b9SBrian Somers 
13146cf264aSBrian Somers int
13246cf264aSBrian Somers uu_lock_txfr(const char *ttyname, pid_t pid)
13346cf264aSBrian Somers {
13446cf264aSBrian Somers 	int fd, err;
13546cf264aSBrian Somers 	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
13646cf264aSBrian Somers 
13746cf264aSBrian Somers 	snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, ttyname);
13846cf264aSBrian Somers 
13946cf264aSBrian Somers 	if ((fd = open(lckname, O_RDWR)) < 0)
14046cf264aSBrian Somers 		return UU_LOCK_OWNER_ERR;
14146cf264aSBrian Somers 	if (get_pid(fd, &err) != getpid())
14246cf264aSBrian Somers 		return UU_LOCK_OWNER_ERR;
14346cf264aSBrian Somers         lseek(fd, 0, SEEK_SET);
14446cf264aSBrian Somers 	if (put_pid(fd, pid))
14546cf264aSBrian Somers 		return UU_LOCK_WRITE_ERR;
14646cf264aSBrian Somers 	close(fd);
14746cf264aSBrian Somers 
14846cf264aSBrian Somers 	return UU_LOCK_OK;
14946cf264aSBrian Somers }
15046cf264aSBrian Somers 
15146cf264aSBrian Somers int
15246cf264aSBrian Somers uu_unlock(const char *ttyname)
153568b59b9SBrian Somers {
154568b59b9SBrian Somers 	char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
155568b59b9SBrian Somers 
15628754192SAndrey A. Chernov 	(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname);
157687d0cdeSBrian Somers 	return unlink(tbuf);
158687d0cdeSBrian Somers }
159687d0cdeSBrian Somers 
16046cf264aSBrian Somers const char *
16146cf264aSBrian Somers uu_lockerr(int uu_lockresult)
162687d0cdeSBrian Somers {
16328804f92SAndrey A. Chernov 	static char errbuf[128];
16481d9597cSAndrey A. Chernov 	char *fmt;
165687d0cdeSBrian Somers 
166687d0cdeSBrian Somers 	switch (uu_lockresult) {
167687d0cdeSBrian Somers 		case UU_LOCK_INUSE:
16828754192SAndrey A. Chernov 			return "device in use";
169687d0cdeSBrian Somers 		case UU_LOCK_OK:
17028754192SAndrey A. Chernov 			return "";
171687d0cdeSBrian Somers 		case UU_LOCK_OPEN_ERR:
17281d9597cSAndrey A. Chernov 			fmt = "open error: %s";
173687d0cdeSBrian Somers 			break;
174687d0cdeSBrian Somers 		case UU_LOCK_READ_ERR:
17581d9597cSAndrey A. Chernov 			fmt = "read error: %s";
176687d0cdeSBrian Somers 			break;
17784dc2299SAndrey A. Chernov 		case UU_LOCK_CREAT_ERR:
17884dc2299SAndrey A. Chernov 			fmt = "creat error: %s";
179687d0cdeSBrian Somers 			break;
180687d0cdeSBrian Somers 		case UU_LOCK_WRITE_ERR:
18181d9597cSAndrey A. Chernov 			fmt = "write error: %s";
182687d0cdeSBrian Somers 			break;
18384dc2299SAndrey A. Chernov 		case UU_LOCK_LINK_ERR:
18484dc2299SAndrey A. Chernov 			fmt = "link error: %s";
18584dc2299SAndrey A. Chernov 			break;
18684dc2299SAndrey A. Chernov 		case UU_LOCK_TRY_ERR:
18784dc2299SAndrey A. Chernov 			fmt = "too many tries: %s";
18884dc2299SAndrey A. Chernov 			break;
18946cf264aSBrian Somers 		case UU_LOCK_OWNER_ERR:
19046cf264aSBrian Somers 			fmt = "not locking process: %s";
19146cf264aSBrian Somers 			break;
192687d0cdeSBrian Somers 		default:
19381d9597cSAndrey A. Chernov 			fmt = "undefined error: %s";
194687d0cdeSBrian Somers 			break;
195687d0cdeSBrian Somers 	}
196687d0cdeSBrian Somers 
19781d9597cSAndrey A. Chernov 	(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
198687d0cdeSBrian Somers 	return errbuf;
199568b59b9SBrian Somers }
200568b59b9SBrian Somers 
20146cf264aSBrian Somers static int
20246cf264aSBrian Somers put_pid(int fd, pid_t pid)
203568b59b9SBrian Somers {
204568b59b9SBrian Somers 	char buf[32];
205568b59b9SBrian Somers 	int len;
206568b59b9SBrian Somers 
207568b59b9SBrian Somers 	len = sprintf (buf, "%10d\n", pid);
208568b59b9SBrian Somers 	return write (fd, buf, len) == len;
209568b59b9SBrian Somers }
210568b59b9SBrian Somers 
21146cf264aSBrian Somers static pid_t
21246cf264aSBrian Somers get_pid(int fd, int *err)
213568b59b9SBrian Somers {
214568b59b9SBrian Somers 	int bytes_read;
215568b59b9SBrian Somers 	char buf[32];
216568b59b9SBrian Somers 	pid_t pid;
217568b59b9SBrian Somers 
218568b59b9SBrian Somers 	bytes_read = read (fd, buf, sizeof (buf) - 1);
219568b59b9SBrian Somers 	if (bytes_read > 0) {
220568b59b9SBrian Somers 		buf[bytes_read] = '\0';
221568b59b9SBrian Somers 		pid = strtol (buf, (char **) NULL, 10);
222687d0cdeSBrian Somers 	} else {
223568b59b9SBrian Somers 		pid = -1;
224687d0cdeSBrian Somers 		*err = bytes_read ? errno : EINVAL;
225687d0cdeSBrian Somers 	}
226568b59b9SBrian Somers 	return pid;
227568b59b9SBrian Somers }
228568b59b9SBrian Somers 
229568b59b9SBrian Somers /* end of uucplock.c */
230