xref: /freebsd/lib/libutil/uucplock.c (revision 0ebec5d3c836a1a8ba2d3b4b06c57c5ecb104485)
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.
32568b59b9SBrian Somers  */
33568b59b9SBrian Somers 
348719c58fSMatthew Dillon #include <sys/cdefs.h>
358719c58fSMatthew Dillon __FBSDID("$FreeBSD$");
368719c58fSMatthew Dillon 
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>
450ebec5d3SMark Murray #include <paths.h>
46568b59b9SBrian Somers #include <signal.h>
47568b59b9SBrian Somers #include <stdio.h>
48568b59b9SBrian Somers #include <stdlib.h>
49687d0cdeSBrian Somers #include <string.h>
500ebec5d3SMark Murray #include <unistd.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;
733c42a9c0SBrian Somers 	pid_t pid, pid_old;
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 
983c42a9c0SBrian Somers 			if ((pid_old = get_pid (fd, &err)) == -1)
9984dc2299SAndrey A. Chernov 				GORET(2, UU_LOCK_READ_ERR);
100568b59b9SBrian Somers 
10184dc2299SAndrey A. Chernov 			close(fd);
10284dc2299SAndrey A. Chernov 
1033c42a9c0SBrian Somers 			if (kill(pid_old, 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())
142ecbf047dSBrian Somers 		err = UU_LOCK_OWNER_ERR;
143ecbf047dSBrian Somers 	else {
14446cf264aSBrian Somers         	lseek(fd, 0, SEEK_SET);
145ecbf047dSBrian Somers 		err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
146ecbf047dSBrian Somers 	}
14746cf264aSBrian Somers 	close(fd);
14846cf264aSBrian Somers 
149ecbf047dSBrian Somers 	return err;
15046cf264aSBrian Somers }
15146cf264aSBrian Somers 
15246cf264aSBrian Somers int
15346cf264aSBrian Somers uu_unlock(const char *ttyname)
154568b59b9SBrian Somers {
155568b59b9SBrian Somers 	char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
156568b59b9SBrian Somers 
15728754192SAndrey A. Chernov 	(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname);
158687d0cdeSBrian Somers 	return unlink(tbuf);
159687d0cdeSBrian Somers }
160687d0cdeSBrian Somers 
16146cf264aSBrian Somers const char *
16246cf264aSBrian Somers uu_lockerr(int uu_lockresult)
163687d0cdeSBrian Somers {
16428804f92SAndrey A. Chernov 	static char errbuf[128];
16581d9597cSAndrey A. Chernov 	char *fmt;
166687d0cdeSBrian Somers 
167687d0cdeSBrian Somers 	switch (uu_lockresult) {
168687d0cdeSBrian Somers 		case UU_LOCK_INUSE:
16928754192SAndrey A. Chernov 			return "device in use";
170687d0cdeSBrian Somers 		case UU_LOCK_OK:
17128754192SAndrey A. Chernov 			return "";
172687d0cdeSBrian Somers 		case UU_LOCK_OPEN_ERR:
17381d9597cSAndrey A. Chernov 			fmt = "open error: %s";
174687d0cdeSBrian Somers 			break;
175687d0cdeSBrian Somers 		case UU_LOCK_READ_ERR:
17681d9597cSAndrey A. Chernov 			fmt = "read error: %s";
177687d0cdeSBrian Somers 			break;
17884dc2299SAndrey A. Chernov 		case UU_LOCK_CREAT_ERR:
17984dc2299SAndrey A. Chernov 			fmt = "creat error: %s";
180687d0cdeSBrian Somers 			break;
181687d0cdeSBrian Somers 		case UU_LOCK_WRITE_ERR:
18281d9597cSAndrey A. Chernov 			fmt = "write error: %s";
183687d0cdeSBrian Somers 			break;
18484dc2299SAndrey A. Chernov 		case UU_LOCK_LINK_ERR:
18584dc2299SAndrey A. Chernov 			fmt = "link error: %s";
18684dc2299SAndrey A. Chernov 			break;
18784dc2299SAndrey A. Chernov 		case UU_LOCK_TRY_ERR:
18884dc2299SAndrey A. Chernov 			fmt = "too many tries: %s";
18984dc2299SAndrey A. Chernov 			break;
19046cf264aSBrian Somers 		case UU_LOCK_OWNER_ERR:
19146cf264aSBrian Somers 			fmt = "not locking process: %s";
19246cf264aSBrian Somers 			break;
193687d0cdeSBrian Somers 		default:
19481d9597cSAndrey A. Chernov 			fmt = "undefined error: %s";
195687d0cdeSBrian Somers 			break;
196687d0cdeSBrian Somers 	}
197687d0cdeSBrian Somers 
19881d9597cSAndrey A. Chernov 	(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
199687d0cdeSBrian Somers 	return errbuf;
200568b59b9SBrian Somers }
201568b59b9SBrian Somers 
20246cf264aSBrian Somers static int
20346cf264aSBrian Somers put_pid(int fd, pid_t pid)
204568b59b9SBrian Somers {
205568b59b9SBrian Somers 	char buf[32];
206568b59b9SBrian Somers 	int len;
207568b59b9SBrian Somers 
2086c78a7b0SBrian Somers 	len = sprintf (buf, "%10d\n", (int)pid);
209568b59b9SBrian Somers 	return write (fd, buf, len) == len;
210568b59b9SBrian Somers }
211568b59b9SBrian Somers 
21246cf264aSBrian Somers static pid_t
21346cf264aSBrian Somers get_pid(int fd, int *err)
214568b59b9SBrian Somers {
215568b59b9SBrian Somers 	int bytes_read;
216568b59b9SBrian Somers 	char buf[32];
217568b59b9SBrian Somers 	pid_t pid;
218568b59b9SBrian Somers 
219568b59b9SBrian Somers 	bytes_read = read (fd, buf, sizeof (buf) - 1);
220568b59b9SBrian Somers 	if (bytes_read > 0) {
221568b59b9SBrian Somers 		buf[bytes_read] = '\0';
222568b59b9SBrian Somers 		pid = strtol (buf, (char **) NULL, 10);
223687d0cdeSBrian Somers 	} else {
224568b59b9SBrian Somers 		pid = -1;
225687d0cdeSBrian Somers 		*err = bytes_read ? errno : EINVAL;
226687d0cdeSBrian Somers 	}
227568b59b9SBrian Somers 	return pid;
228568b59b9SBrian Somers }
229568b59b9SBrian Somers 
230568b59b9SBrian Somers /* end of uucplock.c */
231