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);
7928040Sache	if ((tmpfd = creat(lcktmpname, 0664)) < 0)
8028040Sache		GORET(0, UU_LOCK_CREAT_ERR);
8124461Sbrian
8228040Sache	for (i = 0; i < MAXTRIES; i++) {
8328040Sache		if (link (lcktmpname, lckname) < 0) {
8428040Sache			if (errno != EEXIST)
8528040Sache				GORET(1, UU_LOCK_LINK_ERR);
8628040Sache			/*
8728040Sache			 * file is already locked
8828040Sache			 * check to see if the process holding the lock
8928040Sache			 * still exists
9028040Sache			 */
9128040Sache			if ((fd = open(lckname, O_RDONLY)) < 0)
9228040Sache				GORET(1, UU_LOCK_OPEN_ERR);
9324417Sbrian
9444652Sbrian			if ((pid_old = get_pid (fd, &err)) == -1)
9528040Sache				GORET(2, UU_LOCK_READ_ERR);
9628040Sache
9728040Sache			close(fd);
9828040Sache
9944652Sbrian			if (kill(pid_old, 0) == 0 || errno != ESRCH)
10028040Sache				GORET(1, UU_LOCK_INUSE);
10128040Sache			/*
10228040Sache			 * The process that locked the file isn't running, so
10328040Sache			 * we'll lock it ourselves
10428040Sache			 */
10528040Sache			(void)unlink(lckname);
10628040Sache		} else {
10728040Sache			if (!put_pid (tmpfd, pid))
10828040Sache				GORET(3, UU_LOCK_WRITE_ERR);
10928040Sache			break;
11024417Sbrian		}
11124417Sbrian	}
11228040Sache	GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
11328040Sache
11428040Sacheret3:
11528040Sache	(void)unlink(lckname);
11628040Sache	goto ret1;
11728040Sacheret2:
11824417Sbrian	(void)close(fd);
11928040Sacheret1:
12028040Sache	(void)close(tmpfd);
12128040Sache	(void)unlink(lcktmpname);
12228040Sacheret0:
12328040Sache	errno = err;
12428040Sache	return uuerr;
12524417Sbrian}
12624417Sbrian
12736451Sbrianint
128121193Smarkmuu_lock_txfr(const char *tty_name, pid_t pid)
12924417Sbrian{
13036451Sbrian	int fd, err;
13136451Sbrian	char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
13236451Sbrian
133121193Smarkm	snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name);
13436451Sbrian
13536451Sbrian	if ((fd = open(lckname, O_RDWR)) < 0)
13636451Sbrian		return UU_LOCK_OWNER_ERR;
13736451Sbrian	if (get_pid(fd, &err) != getpid())
13866558Sbrian		err = UU_LOCK_OWNER_ERR;
13966558Sbrian	else {
140121193Smarkm        	lseek(fd, (off_t)0, SEEK_SET);
14166558Sbrian		err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
14266558Sbrian	}
14336451Sbrian	close(fd);
14436451Sbrian
14566558Sbrian	return err;
14636451Sbrian}
14736451Sbrian
14836451Sbrianint
149121193Smarkmuu_unlock(const char *tty_name)
15036451Sbrian{
15124417Sbrian	char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
15224417Sbrian
153121193Smarkm	(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name);
15424461Sbrian	return unlink(tbuf);
15524417Sbrian}
15624417Sbrian
15736451Sbrianconst char *
15836451Sbrianuu_lockerr(int uu_lockresult)
15924461Sbrian{
16024531Sache	static char errbuf[128];
161121193Smarkm	const char *fmt;
16224461Sbrian
16324461Sbrian	switch (uu_lockresult) {
16424461Sbrian		case UU_LOCK_INUSE:
16524529Sache			return "device in use";
16624529Sache		case UU_LOCK_OK:
16724461Sbrian			return "";
16824461Sbrian		case UU_LOCK_OPEN_ERR:
16924530Sache			fmt = "open error: %s";
17024461Sbrian			break;
17124461Sbrian		case UU_LOCK_READ_ERR:
17224530Sache			fmt = "read error: %s";
17324461Sbrian			break;
17428040Sache		case UU_LOCK_CREAT_ERR:
17528040Sache			fmt = "creat error: %s";
17624461Sbrian			break;
17724461Sbrian		case UU_LOCK_WRITE_ERR:
17824530Sache			fmt = "write error: %s";
17924461Sbrian			break;
18028040Sache		case UU_LOCK_LINK_ERR:
18128040Sache			fmt = "link error: %s";
18228040Sache			break;
18328040Sache		case UU_LOCK_TRY_ERR:
18428040Sache			fmt = "too many tries: %s";
18528040Sache			break;
18636451Sbrian		case UU_LOCK_OWNER_ERR:
18736451Sbrian			fmt = "not locking process: %s";
18836451Sbrian			break;
18924461Sbrian		default:
19024530Sache			fmt = "undefined error: %s";
19124461Sbrian			break;
19224461Sbrian	}
19324461Sbrian
19424530Sache	(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
19524461Sbrian	return errbuf;
19624461Sbrian}
19724461Sbrian
19836451Sbrianstatic int
19936451Sbrianput_pid(int fd, pid_t pid)
20024417Sbrian{
20124417Sbrian	char buf[32];
20224417Sbrian	int len;
20324417Sbrian
20436833Sbrian	len = sprintf (buf, "%10d\n", (int)pid);
205121193Smarkm	return write (fd, buf, (size_t)len) == len;
20624417Sbrian}
20724417Sbrian
20836451Sbrianstatic pid_t
20936451Sbrianget_pid(int fd, int *err)
21024417Sbrian{
21124417Sbrian	int bytes_read;
21224417Sbrian	char buf[32];
21324417Sbrian	pid_t pid;
21424417Sbrian
21524417Sbrian	bytes_read = read (fd, buf, sizeof (buf) - 1);
21624417Sbrian	if (bytes_read > 0) {
21724417Sbrian		buf[bytes_read] = '\0';
218121193Smarkm		pid = (pid_t)strtol (buf, (char **) NULL, 10);
21924461Sbrian	} else {
22024417Sbrian		pid = -1;
22124461Sbrian		*err = bytes_read ? errno : EINVAL;
22224461Sbrian	}
22324417Sbrian	return pid;
22424417Sbrian}
22524417Sbrian
22624417Sbrian/* end of uucplock.c */
227