xref: /f-stack/tools/libutil/uucplock.c (revision 22ce4aff)
1*22ce4affSfengbojiang /*-
2*22ce4affSfengbojiang  * SPDX-License-Identifier: BSD-3-Clause
3*22ce4affSfengbojiang  *
41eaf0ac3Slogwang  * Copyright (c) 1988, 1993
51eaf0ac3Slogwang  *	The Regents of the University of California.  All rights reserved.
61eaf0ac3Slogwang  *
71eaf0ac3Slogwang  * Redistribution and use in source and binary forms, with or without
81eaf0ac3Slogwang  * modification, are permitted provided that the following conditions
91eaf0ac3Slogwang  * are met:
101eaf0ac3Slogwang  * 1. Redistributions of source code must retain the above copyright
111eaf0ac3Slogwang  *    notice, this list of conditions and the following disclaimer.
121eaf0ac3Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
131eaf0ac3Slogwang  *    notice, this list of conditions and the following disclaimer in the
141eaf0ac3Slogwang  *    documentation and/or other materials provided with the distribution.
15*22ce4affSfengbojiang  * 3. Neither the name of the University nor the names of its contributors
161eaf0ac3Slogwang  *    may be used to endorse or promote products derived from this software
171eaf0ac3Slogwang  *    without specific prior written permission.
181eaf0ac3Slogwang  *
191eaf0ac3Slogwang  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
201eaf0ac3Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211eaf0ac3Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221eaf0ac3Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
231eaf0ac3Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241eaf0ac3Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251eaf0ac3Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261eaf0ac3Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271eaf0ac3Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281eaf0ac3Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291eaf0ac3Slogwang  * SUCH DAMAGE.
301eaf0ac3Slogwang  */
311eaf0ac3Slogwang 
321eaf0ac3Slogwang #include <sys/cdefs.h>
331eaf0ac3Slogwang __FBSDID("$FreeBSD$");
34*22ce4affSfengbojiang __SCCSID("@(#)uucplock.c	8.1 (Berkeley) 6/6/93");
351eaf0ac3Slogwang 
361eaf0ac3Slogwang #include <sys/types.h>
371eaf0ac3Slogwang #include <sys/file.h>
381eaf0ac3Slogwang #include <dirent.h>
391eaf0ac3Slogwang #include <errno.h>
401eaf0ac3Slogwang #include <paths.h>
411eaf0ac3Slogwang #include <signal.h>
421eaf0ac3Slogwang #include <stdio.h>
431eaf0ac3Slogwang #include <stdlib.h>
441eaf0ac3Slogwang #include <string.h>
451eaf0ac3Slogwang #include <unistd.h>
461eaf0ac3Slogwang #include "libutil.h"
471eaf0ac3Slogwang 
481eaf0ac3Slogwang #define MAXTRIES 5
491eaf0ac3Slogwang 
501eaf0ac3Slogwang #define LOCKTMP "LCKTMP..%d"
511eaf0ac3Slogwang #define LOCKFMT "LCK..%s"
521eaf0ac3Slogwang 
531eaf0ac3Slogwang #define GORET(level, val) { err = errno; uuerr = (val); \
541eaf0ac3Slogwang 			    goto __CONCAT(ret, level); }
551eaf0ac3Slogwang 
561eaf0ac3Slogwang /* Forward declarations */
571eaf0ac3Slogwang static int put_pid (int fd, pid_t pid);
581eaf0ac3Slogwang static pid_t get_pid (int fd,int *err);
591eaf0ac3Slogwang 
601eaf0ac3Slogwang /*
611eaf0ac3Slogwang  * uucp style locking routines
621eaf0ac3Slogwang  */
631eaf0ac3Slogwang 
641eaf0ac3Slogwang int
uu_lock(const char * tty_name)651eaf0ac3Slogwang uu_lock(const char *tty_name)
661eaf0ac3Slogwang {
671eaf0ac3Slogwang 	int fd, tmpfd, i;
681eaf0ac3Slogwang 	pid_t pid, pid_old;
691eaf0ac3Slogwang 	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
701eaf0ac3Slogwang 	     lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
711eaf0ac3Slogwang 	int err, uuerr;
721eaf0ac3Slogwang 
731eaf0ac3Slogwang 	pid = getpid();
741eaf0ac3Slogwang 	(void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
751eaf0ac3Slogwang 			pid);
761eaf0ac3Slogwang 	(void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
771eaf0ac3Slogwang 			tty_name);
781eaf0ac3Slogwang 	if ((tmpfd = open(lcktmpname, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
791eaf0ac3Slogwang 	    0664)) < 0)
801eaf0ac3Slogwang 		GORET(0, UU_LOCK_CREAT_ERR);
811eaf0ac3Slogwang 
821eaf0ac3Slogwang 	for (i = 0; i < MAXTRIES; i++) {
831eaf0ac3Slogwang 		if (link (lcktmpname, lckname) < 0) {
841eaf0ac3Slogwang 			if (errno != EEXIST)
851eaf0ac3Slogwang 				GORET(1, UU_LOCK_LINK_ERR);
861eaf0ac3Slogwang 			/*
871eaf0ac3Slogwang 			 * file is already locked
881eaf0ac3Slogwang 			 * check to see if the process holding the lock
891eaf0ac3Slogwang 			 * still exists
901eaf0ac3Slogwang 			 */
911eaf0ac3Slogwang 			if ((fd = open(lckname, O_RDONLY | O_CLOEXEC)) < 0)
921eaf0ac3Slogwang 				GORET(1, UU_LOCK_OPEN_ERR);
931eaf0ac3Slogwang 
941eaf0ac3Slogwang 			if ((pid_old = get_pid (fd, &err)) == -1)
951eaf0ac3Slogwang 				GORET(2, UU_LOCK_READ_ERR);
961eaf0ac3Slogwang 
971eaf0ac3Slogwang 			close(fd);
981eaf0ac3Slogwang 
991eaf0ac3Slogwang 			if (kill(pid_old, 0) == 0 || errno != ESRCH)
1001eaf0ac3Slogwang 				GORET(1, UU_LOCK_INUSE);
1011eaf0ac3Slogwang 			/*
1021eaf0ac3Slogwang 			 * The process that locked the file isn't running, so
1031eaf0ac3Slogwang 			 * we'll lock it ourselves
1041eaf0ac3Slogwang 			 */
1051eaf0ac3Slogwang 			(void)unlink(lckname);
1061eaf0ac3Slogwang 		} else {
1071eaf0ac3Slogwang 			if (!put_pid (tmpfd, pid))
1081eaf0ac3Slogwang 				GORET(3, UU_LOCK_WRITE_ERR);
1091eaf0ac3Slogwang 			break;
1101eaf0ac3Slogwang 		}
1111eaf0ac3Slogwang 	}
1121eaf0ac3Slogwang 	GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
1131eaf0ac3Slogwang 
1141eaf0ac3Slogwang ret3:
1151eaf0ac3Slogwang 	(void)unlink(lckname);
1161eaf0ac3Slogwang 	goto ret1;
1171eaf0ac3Slogwang ret2:
1181eaf0ac3Slogwang 	(void)close(fd);
1191eaf0ac3Slogwang ret1:
1201eaf0ac3Slogwang 	(void)close(tmpfd);
1211eaf0ac3Slogwang 	(void)unlink(lcktmpname);
1221eaf0ac3Slogwang ret0:
1231eaf0ac3Slogwang 	errno = err;
1241eaf0ac3Slogwang 	return uuerr;
1251eaf0ac3Slogwang }
1261eaf0ac3Slogwang 
1271eaf0ac3Slogwang int
uu_lock_txfr(const char * tty_name,pid_t pid)1281eaf0ac3Slogwang uu_lock_txfr(const char *tty_name, pid_t pid)
1291eaf0ac3Slogwang {
1301eaf0ac3Slogwang 	int fd, err;
1311eaf0ac3Slogwang 	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
1321eaf0ac3Slogwang 
1331eaf0ac3Slogwang 	snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name);
1341eaf0ac3Slogwang 
1351eaf0ac3Slogwang 	if ((fd = open(lckname, O_RDWR | O_CLOEXEC)) < 0)
1361eaf0ac3Slogwang 		return UU_LOCK_OWNER_ERR;
1371eaf0ac3Slogwang 	if (get_pid(fd, &err) != getpid())
1381eaf0ac3Slogwang 		err = UU_LOCK_OWNER_ERR;
1391eaf0ac3Slogwang 	else {
1401eaf0ac3Slogwang         	lseek(fd, (off_t)0, SEEK_SET);
1411eaf0ac3Slogwang 		err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
1421eaf0ac3Slogwang 	}
1431eaf0ac3Slogwang 	close(fd);
1441eaf0ac3Slogwang 
1451eaf0ac3Slogwang 	return err;
1461eaf0ac3Slogwang }
1471eaf0ac3Slogwang 
1481eaf0ac3Slogwang int
uu_unlock(const char * tty_name)1491eaf0ac3Slogwang uu_unlock(const char *tty_name)
1501eaf0ac3Slogwang {
1511eaf0ac3Slogwang 	char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
1521eaf0ac3Slogwang 
1531eaf0ac3Slogwang 	(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name);
1541eaf0ac3Slogwang 	return unlink(tbuf);
1551eaf0ac3Slogwang }
1561eaf0ac3Slogwang 
1571eaf0ac3Slogwang const char *
uu_lockerr(int uu_lockresult)1581eaf0ac3Slogwang uu_lockerr(int uu_lockresult)
1591eaf0ac3Slogwang {
1601eaf0ac3Slogwang 	static char errbuf[128];
1611eaf0ac3Slogwang 	const char *fmt;
1621eaf0ac3Slogwang 
1631eaf0ac3Slogwang 	switch (uu_lockresult) {
1641eaf0ac3Slogwang 		case UU_LOCK_INUSE:
1651eaf0ac3Slogwang 			return "device in use";
1661eaf0ac3Slogwang 		case UU_LOCK_OK:
1671eaf0ac3Slogwang 			return "";
1681eaf0ac3Slogwang 		case UU_LOCK_OPEN_ERR:
1691eaf0ac3Slogwang 			fmt = "open error: %s";
1701eaf0ac3Slogwang 			break;
1711eaf0ac3Slogwang 		case UU_LOCK_READ_ERR:
1721eaf0ac3Slogwang 			fmt = "read error: %s";
1731eaf0ac3Slogwang 			break;
1741eaf0ac3Slogwang 		case UU_LOCK_CREAT_ERR:
1751eaf0ac3Slogwang 			fmt = "creat error: %s";
1761eaf0ac3Slogwang 			break;
1771eaf0ac3Slogwang 		case UU_LOCK_WRITE_ERR:
1781eaf0ac3Slogwang 			fmt = "write error: %s";
1791eaf0ac3Slogwang 			break;
1801eaf0ac3Slogwang 		case UU_LOCK_LINK_ERR:
1811eaf0ac3Slogwang 			fmt = "link error: %s";
1821eaf0ac3Slogwang 			break;
1831eaf0ac3Slogwang 		case UU_LOCK_TRY_ERR:
1841eaf0ac3Slogwang 			fmt = "too many tries: %s";
1851eaf0ac3Slogwang 			break;
1861eaf0ac3Slogwang 		case UU_LOCK_OWNER_ERR:
1871eaf0ac3Slogwang 			fmt = "not locking process: %s";
1881eaf0ac3Slogwang 			break;
1891eaf0ac3Slogwang 		default:
1901eaf0ac3Slogwang 			fmt = "undefined error: %s";
1911eaf0ac3Slogwang 			break;
1921eaf0ac3Slogwang 	}
1931eaf0ac3Slogwang 
1941eaf0ac3Slogwang 	(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
1951eaf0ac3Slogwang 	return errbuf;
1961eaf0ac3Slogwang }
1971eaf0ac3Slogwang 
1981eaf0ac3Slogwang static int
put_pid(int fd,pid_t pid)1991eaf0ac3Slogwang put_pid(int fd, pid_t pid)
2001eaf0ac3Slogwang {
2011eaf0ac3Slogwang 	char buf[32];
2021eaf0ac3Slogwang 	int len;
2031eaf0ac3Slogwang 
2041eaf0ac3Slogwang 	len = sprintf (buf, "%10d\n", (int)pid);
2051eaf0ac3Slogwang 	return write (fd, buf, (size_t)len) == len;
2061eaf0ac3Slogwang }
2071eaf0ac3Slogwang 
2081eaf0ac3Slogwang static pid_t
get_pid(int fd,int * err)2091eaf0ac3Slogwang get_pid(int fd, int *err)
2101eaf0ac3Slogwang {
2111eaf0ac3Slogwang 	int bytes_read;
2121eaf0ac3Slogwang 	char buf[32];
2131eaf0ac3Slogwang 	pid_t pid;
2141eaf0ac3Slogwang 
2151eaf0ac3Slogwang 	bytes_read = read (fd, buf, sizeof (buf) - 1);
2161eaf0ac3Slogwang 	if (bytes_read > 0) {
2171eaf0ac3Slogwang 		buf[bytes_read] = '\0';
2181eaf0ac3Slogwang 		pid = (pid_t)strtol (buf, (char **) NULL, 10);
2191eaf0ac3Slogwang 	} else {
2201eaf0ac3Slogwang 		pid = -1;
2211eaf0ac3Slogwang 		*err = bytes_read ? errno : EINVAL;
2221eaf0ac3Slogwang 	}
2231eaf0ac3Slogwang 	return pid;
2241eaf0ac3Slogwang }
2251eaf0ac3Slogwang 
2261eaf0ac3Slogwang /* end of uucplock.c */
227