124417Sbrian/*
224417Sbrian * Copyright (c) 1988, 1993
324417Sbrian *	The Regents of the University of California.  All rights reserved.
424417Sbrian *
524417Sbrian * Redistribution and use in source and binary forms, with or without
624417Sbrian * modification, are permitted provided that the following conditions
724417Sbrian * are met:
824417Sbrian * 1. Redistributions of source code must retain the above copyright
924417Sbrian *    notice, this list of conditions and the following disclaimer.
1024417Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1124417Sbrian *    notice, this list of conditions and the following disclaimer in the
1224417Sbrian *    documentation and/or other materials provided with the distribution.
1324417Sbrian * 4. Neither the name of the University nor the names of its contributors
1424417Sbrian *    may be used to endorse or promote products derived from this software
1524417Sbrian *    without specific prior written permission.
1624417Sbrian *
1724417Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1824417Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1924417Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2024417Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2124417Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2224417Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2324417Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2424417Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2524417Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2624417Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2724417Sbrian * SUCH DAMAGE.
2824417Sbrian */
2924417Sbrian
3084225Sdillon#include <sys/cdefs.h>
3184225Sdillon__FBSDID("$FreeBSD$");
3284225Sdillon
3324417Sbrian#ifndef lint
3424417Sbrianstatic const char sccsid[] = "@(#)uucplock.c	8.1 (Berkeley) 6/6/93";
3524417Sbrian#endif /* not lint */
3624417Sbrian
3724417Sbrian#include <sys/types.h>
3824417Sbrian#include <sys/file.h>
3924417Sbrian#include <dirent.h>
4024417Sbrian#include <errno.h>
41116344Smarkm#include <paths.h>
4224417Sbrian#include <signal.h>
4324417Sbrian#include <stdio.h>
4424417Sbrian#include <stdlib.h>
4524461Sbrian#include <string.h>
46116344Smarkm#include <unistd.h>
4724461Sbrian#include "libutil.h"
4824417Sbrian
4928040Sache#define MAXTRIES 5
5028040Sache
5128040Sache#define LOCKTMP "LCKTMP..%d"
5224417Sbrian#define LOCKFMT "LCK..%s"
5324417Sbrian
5428040Sache#define GORET(level, val) { err = errno; uuerr = (val); \
5528040Sache			    goto __CONCAT(ret, level); }
5628040Sache
5724417Sbrian/* Forward declarations */
5824417Sbrianstatic int put_pid (int fd, pid_t pid);
5924461Sbrianstatic pid_t get_pid (int fd,int *err);
6024417Sbrian
6124417Sbrian/*
6224417Sbrian * uucp style locking routines
6324417Sbrian */
6424417Sbrian
6536451Sbrianint
66121193Smarkmuu_lock(const char *tty_name)
6724417Sbrian{
6828040Sache	int fd, tmpfd, i;
6944652Sbrian	pid_t pid, pid_old;
7028040Sache	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
7128040Sache	     lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
7228040Sache	int err, uuerr;
7324417Sbrian
7428040Sache	pid = getpid();
7528040Sache	(void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
7628040Sache			pid);
7728040Sache	(void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
78121193Smarkm			tty_name);
79255007Sjilles	if ((tmpfd = open(lcktmpname, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
80255007Sjilles	    0664)) < 0)
8128040Sache		GORET(0, UU_LOCK_CREAT_ERR);
8224461Sbrian
8328040Sache	for (i = 0; i < MAXTRIES; i++) {
8428040Sache		if (link (lcktmpname, lckname) < 0) {
8528040Sache			if (errno != EEXIST)
8628040Sache				GORET(1, UU_LOCK_LINK_ERR);
8728040Sache			/*
8828040Sache			 * file is already locked
8928040Sache			 * check to see if the process holding the lock
9028040Sache			 * still exists
9128040Sache			 */
92255007Sjilles			if ((fd = open(lckname, O_RDONLY | O_CLOEXEC)) < 0)
9328040Sache				GORET(1, UU_LOCK_OPEN_ERR);
9424417Sbrian
9544652Sbrian			if ((pid_old = get_pid (fd, &err)) == -1)
9628040Sache				GORET(2, UU_LOCK_READ_ERR);
9728040Sache
9828040Sache			close(fd);
9928040Sache
10044652Sbrian			if (kill(pid_old, 0) == 0 || errno != ESRCH)
10128040Sache				GORET(1, UU_LOCK_INUSE);
10228040Sache			/*
10328040Sache			 * The process that locked the file isn't running, so
10428040Sache			 * we'll lock it ourselves
10528040Sache			 */
10628040Sache			(void)unlink(lckname);
10728040Sache		} else {
10828040Sache			if (!put_pid (tmpfd, pid))
10928040Sache				GORET(3, UU_LOCK_WRITE_ERR);
11028040Sache			break;
11124417Sbrian		}
11224417Sbrian	}
11328040Sache	GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
11428040Sache
11528040Sacheret3:
11628040Sache	(void)unlink(lckname);
11728040Sache	goto ret1;
11828040Sacheret2:
11924417Sbrian	(void)close(fd);
12028040Sacheret1:
12128040Sache	(void)close(tmpfd);
12228040Sache	(void)unlink(lcktmpname);
12328040Sacheret0:
12428040Sache	errno = err;
12528040Sache	return uuerr;
12624417Sbrian}
12724417Sbrian
12836451Sbrianint
129121193Smarkmuu_lock_txfr(const char *tty_name, pid_t pid)
13024417Sbrian{
13136451Sbrian	int fd, err;
13236451Sbrian	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
13336451Sbrian
134121193Smarkm	snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name);
13536451Sbrian
136255007Sjilles	if ((fd = open(lckname, O_RDWR | O_CLOEXEC)) < 0)
13736451Sbrian		return UU_LOCK_OWNER_ERR;
13836451Sbrian	if (get_pid(fd, &err) != getpid())
13966558Sbrian		err = UU_LOCK_OWNER_ERR;
14066558Sbrian	else {
141121193Smarkm        	lseek(fd, (off_t)0, SEEK_SET);
14266558Sbrian		err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
14366558Sbrian	}
14436451Sbrian	close(fd);
14536451Sbrian
14666558Sbrian	return err;
14736451Sbrian}
14836451Sbrian
14936451Sbrianint
150121193Smarkmuu_unlock(const char *tty_name)
15136451Sbrian{
15224417Sbrian	char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
15324417Sbrian
154121193Smarkm	(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name);
15524461Sbrian	return unlink(tbuf);
15624417Sbrian}
15724417Sbrian
15836451Sbrianconst char *
15936451Sbrianuu_lockerr(int uu_lockresult)
16024461Sbrian{
16124531Sache	static char errbuf[128];
162121193Smarkm	const char *fmt;
16324461Sbrian
16424461Sbrian	switch (uu_lockresult) {
16524461Sbrian		case UU_LOCK_INUSE:
16624529Sache			return "device in use";
16724529Sache		case UU_LOCK_OK:
16824461Sbrian			return "";
16924461Sbrian		case UU_LOCK_OPEN_ERR:
17024530Sache			fmt = "open error: %s";
17124461Sbrian			break;
17224461Sbrian		case UU_LOCK_READ_ERR:
17324530Sache			fmt = "read error: %s";
17424461Sbrian			break;
17528040Sache		case UU_LOCK_CREAT_ERR:
17628040Sache			fmt = "creat error: %s";
17724461Sbrian			break;
17824461Sbrian		case UU_LOCK_WRITE_ERR:
17924530Sache			fmt = "write error: %s";
18024461Sbrian			break;
18128040Sache		case UU_LOCK_LINK_ERR:
18228040Sache			fmt = "link error: %s";
18328040Sache			break;
18428040Sache		case UU_LOCK_TRY_ERR:
18528040Sache			fmt = "too many tries: %s";
18628040Sache			break;
18736451Sbrian		case UU_LOCK_OWNER_ERR:
18836451Sbrian			fmt = "not locking process: %s";
18936451Sbrian			break;
19024461Sbrian		default:
19124530Sache			fmt = "undefined error: %s";
19224461Sbrian			break;
19324461Sbrian	}
19424461Sbrian
19524530Sache	(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
19624461Sbrian	return errbuf;
19724461Sbrian}
19824461Sbrian
19936451Sbrianstatic int
20036451Sbrianput_pid(int fd, pid_t pid)
20124417Sbrian{
20224417Sbrian	char buf[32];
20324417Sbrian	int len;
20424417Sbrian
20536833Sbrian	len = sprintf (buf, "%10d\n", (int)pid);
206121193Smarkm	return write (fd, buf, (size_t)len) == len;
20724417Sbrian}
20824417Sbrian
20936451Sbrianstatic pid_t
21036451Sbrianget_pid(int fd, int *err)
21124417Sbrian{
21224417Sbrian	int bytes_read;
21324417Sbrian	char buf[32];
21424417Sbrian	pid_t pid;
21524417Sbrian
21624417Sbrian	bytes_read = read (fd, buf, sizeof (buf) - 1);
21724417Sbrian	if (bytes_read > 0) {
21824417Sbrian		buf[bytes_read] = '\0';
219121193Smarkm		pid = (pid_t)strtol (buf, (char **) NULL, 10);
22024461Sbrian	} else {
22124417Sbrian		pid = -1;
22224461Sbrian		*err = bytes_read ? errno : EINVAL;
22324461Sbrian	}
22424417Sbrian	return pid;
22524417Sbrian}
22624417Sbrian
22724417Sbrian/* end of uucplock.c */
228