1*8a16b7a1SPedro F. Giffuni /*-
2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni *
4568b59b9SBrian Somers * Copyright (c) 1988, 1993
5568b59b9SBrian Somers * The Regents of the University of California. All rights reserved.
6568b59b9SBrian Somers *
7568b59b9SBrian Somers * Redistribution and use in source and binary forms, with or without
8568b59b9SBrian Somers * modification, are permitted provided that the following conditions
9568b59b9SBrian Somers * are met:
10568b59b9SBrian Somers * 1. Redistributions of source code must retain the above copyright
11568b59b9SBrian Somers * notice, this list of conditions and the following disclaimer.
12568b59b9SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
13568b59b9SBrian Somers * notice, this list of conditions and the following disclaimer in the
14568b59b9SBrian Somers * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
16568b59b9SBrian Somers * may be used to endorse or promote products derived from this software
17568b59b9SBrian Somers * without specific prior written permission.
18568b59b9SBrian Somers *
19568b59b9SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20568b59b9SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21568b59b9SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22568b59b9SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23568b59b9SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24568b59b9SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25568b59b9SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26568b59b9SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27568b59b9SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28568b59b9SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29568b59b9SBrian Somers * SUCH DAMAGE.
30568b59b9SBrian Somers */
31568b59b9SBrian Somers
32568b59b9SBrian Somers
33568b59b9SBrian Somers #include <sys/types.h>
34568b59b9SBrian Somers #include <sys/file.h>
35568b59b9SBrian Somers #include <dirent.h>
36568b59b9SBrian Somers #include <errno.h>
370ebec5d3SMark Murray #include <paths.h>
38568b59b9SBrian Somers #include <signal.h>
39568b59b9SBrian Somers #include <stdio.h>
40568b59b9SBrian Somers #include <stdlib.h>
41687d0cdeSBrian Somers #include <string.h>
420ebec5d3SMark Murray #include <unistd.h>
43687d0cdeSBrian Somers #include "libutil.h"
44568b59b9SBrian Somers
4584dc2299SAndrey A. Chernov #define MAXTRIES 5
4684dc2299SAndrey A. Chernov
4784dc2299SAndrey A. Chernov #define LOCKTMP "LCKTMP..%d"
48568b59b9SBrian Somers #define LOCKFMT "LCK..%s"
49568b59b9SBrian Somers
5084dc2299SAndrey A. Chernov #define GORET(level, val) { err = errno; uuerr = (val); \
5184dc2299SAndrey A. Chernov goto __CONCAT(ret, level); }
5284dc2299SAndrey A. Chernov
53568b59b9SBrian Somers /* Forward declarations */
54568b59b9SBrian Somers static int put_pid (int fd, pid_t pid);
55687d0cdeSBrian Somers static pid_t get_pid (int fd,int *err);
56568b59b9SBrian Somers
57568b59b9SBrian Somers /*
58568b59b9SBrian Somers * uucp style locking routines
59568b59b9SBrian Somers */
60568b59b9SBrian Somers
6146cf264aSBrian Somers int
uu_lock(const char * tty_name)62547fa0d9SMark Murray uu_lock(const char *tty_name)
63568b59b9SBrian Somers {
6484dc2299SAndrey A. Chernov int fd, tmpfd, i;
653c42a9c0SBrian Somers pid_t pid, pid_old;
6684dc2299SAndrey A. Chernov char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
6784dc2299SAndrey A. Chernov lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
6884dc2299SAndrey A. Chernov int err, uuerr;
69568b59b9SBrian Somers
7084dc2299SAndrey A. Chernov pid = getpid();
7184dc2299SAndrey A. Chernov (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
7284dc2299SAndrey A. Chernov pid);
7384dc2299SAndrey A. Chernov (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
74547fa0d9SMark Murray tty_name);
75d1d4d952SJilles Tjoelker if ((tmpfd = open(lcktmpname, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
76d1d4d952SJilles Tjoelker 0664)) < 0)
7784dc2299SAndrey A. Chernov GORET(0, UU_LOCK_CREAT_ERR);
7884dc2299SAndrey A. Chernov
7984dc2299SAndrey A. Chernov for (i = 0; i < MAXTRIES; i++) {
8084dc2299SAndrey A. Chernov if (link (lcktmpname, lckname) < 0) {
8184dc2299SAndrey A. Chernov if (errno != EEXIST)
8284dc2299SAndrey A. Chernov GORET(1, UU_LOCK_LINK_ERR);
83568b59b9SBrian Somers /*
84568b59b9SBrian Somers * file is already locked
8584dc2299SAndrey A. Chernov * check to see if the process holding the lock
8684dc2299SAndrey A. Chernov * still exists
87568b59b9SBrian Somers */
88d1d4d952SJilles Tjoelker if ((fd = open(lckname, O_RDONLY | O_CLOEXEC)) < 0)
8984dc2299SAndrey A. Chernov GORET(1, UU_LOCK_OPEN_ERR);
90687d0cdeSBrian Somers
913c42a9c0SBrian Somers if ((pid_old = get_pid (fd, &err)) == -1)
9284dc2299SAndrey A. Chernov GORET(2, UU_LOCK_READ_ERR);
93568b59b9SBrian Somers
9484dc2299SAndrey A. Chernov close(fd);
9584dc2299SAndrey A. Chernov
963c42a9c0SBrian Somers if (kill(pid_old, 0) == 0 || errno != ESRCH)
9784dc2299SAndrey A. Chernov GORET(1, UU_LOCK_INUSE);
98568b59b9SBrian Somers /*
99568b59b9SBrian Somers * The process that locked the file isn't running, so
100568b59b9SBrian Somers * we'll lock it ourselves
101568b59b9SBrian Somers */
10284dc2299SAndrey A. Chernov (void)unlink(lckname);
10384dc2299SAndrey A. Chernov } else {
10484dc2299SAndrey A. Chernov if (!put_pid (tmpfd, pid))
10584dc2299SAndrey A. Chernov GORET(3, UU_LOCK_WRITE_ERR);
10684dc2299SAndrey A. Chernov break;
10784dc2299SAndrey A. Chernov }
10884dc2299SAndrey A. Chernov }
10984dc2299SAndrey A. Chernov GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
11084dc2299SAndrey A. Chernov
11184dc2299SAndrey A. Chernov ret3:
11284dc2299SAndrey A. Chernov (void)unlink(lckname);
11384dc2299SAndrey A. Chernov goto ret1;
11484dc2299SAndrey A. Chernov ret2:
115568b59b9SBrian Somers (void)close(fd);
11684dc2299SAndrey A. Chernov ret1:
11784dc2299SAndrey A. Chernov (void)close(tmpfd);
11884dc2299SAndrey A. Chernov (void)unlink(lcktmpname);
11984dc2299SAndrey A. Chernov ret0:
120687d0cdeSBrian Somers errno = err;
12184dc2299SAndrey A. Chernov return uuerr;
122568b59b9SBrian Somers }
123568b59b9SBrian Somers
12446cf264aSBrian Somers int
uu_lock_txfr(const char * tty_name,pid_t pid)125547fa0d9SMark Murray uu_lock_txfr(const char *tty_name, pid_t pid)
12646cf264aSBrian Somers {
12746cf264aSBrian Somers int fd, err;
12846cf264aSBrian Somers char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
12946cf264aSBrian Somers
130547fa0d9SMark Murray snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name);
13146cf264aSBrian Somers
132d1d4d952SJilles Tjoelker if ((fd = open(lckname, O_RDWR | O_CLOEXEC)) < 0)
13346cf264aSBrian Somers return UU_LOCK_OWNER_ERR;
13446cf264aSBrian Somers if (get_pid(fd, &err) != getpid())
135ecbf047dSBrian Somers err = UU_LOCK_OWNER_ERR;
136ecbf047dSBrian Somers else {
137547fa0d9SMark Murray lseek(fd, (off_t)0, SEEK_SET);
138ecbf047dSBrian Somers err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
139ecbf047dSBrian Somers }
14046cf264aSBrian Somers close(fd);
14146cf264aSBrian Somers
142ecbf047dSBrian Somers return err;
14346cf264aSBrian Somers }
14446cf264aSBrian Somers
14546cf264aSBrian Somers int
uu_unlock(const char * tty_name)146547fa0d9SMark Murray uu_unlock(const char *tty_name)
147568b59b9SBrian Somers {
148568b59b9SBrian Somers char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
149568b59b9SBrian Somers
150547fa0d9SMark Murray (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name);
151687d0cdeSBrian Somers return unlink(tbuf);
152687d0cdeSBrian Somers }
153687d0cdeSBrian Somers
15446cf264aSBrian Somers const char *
uu_lockerr(int uu_lockresult)15546cf264aSBrian Somers uu_lockerr(int uu_lockresult)
156687d0cdeSBrian Somers {
15728804f92SAndrey A. Chernov static char errbuf[128];
158547fa0d9SMark Murray const char *fmt;
159687d0cdeSBrian Somers
160687d0cdeSBrian Somers switch (uu_lockresult) {
161687d0cdeSBrian Somers case UU_LOCK_INUSE:
16228754192SAndrey A. Chernov return "device in use";
163687d0cdeSBrian Somers case UU_LOCK_OK:
16428754192SAndrey A. Chernov return "";
165687d0cdeSBrian Somers case UU_LOCK_OPEN_ERR:
16681d9597cSAndrey A. Chernov fmt = "open error: %s";
167687d0cdeSBrian Somers break;
168687d0cdeSBrian Somers case UU_LOCK_READ_ERR:
16981d9597cSAndrey A. Chernov fmt = "read error: %s";
170687d0cdeSBrian Somers break;
17184dc2299SAndrey A. Chernov case UU_LOCK_CREAT_ERR:
17284dc2299SAndrey A. Chernov fmt = "creat error: %s";
173687d0cdeSBrian Somers break;
174687d0cdeSBrian Somers case UU_LOCK_WRITE_ERR:
17581d9597cSAndrey A. Chernov fmt = "write error: %s";
176687d0cdeSBrian Somers break;
17784dc2299SAndrey A. Chernov case UU_LOCK_LINK_ERR:
17884dc2299SAndrey A. Chernov fmt = "link error: %s";
17984dc2299SAndrey A. Chernov break;
18084dc2299SAndrey A. Chernov case UU_LOCK_TRY_ERR:
18184dc2299SAndrey A. Chernov fmt = "too many tries: %s";
18284dc2299SAndrey A. Chernov break;
18346cf264aSBrian Somers case UU_LOCK_OWNER_ERR:
18446cf264aSBrian Somers fmt = "not locking process: %s";
18546cf264aSBrian Somers break;
186687d0cdeSBrian Somers default:
18781d9597cSAndrey A. Chernov fmt = "undefined error: %s";
188687d0cdeSBrian Somers break;
189687d0cdeSBrian Somers }
190687d0cdeSBrian Somers
19181d9597cSAndrey A. Chernov (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
192687d0cdeSBrian Somers return errbuf;
193568b59b9SBrian Somers }
194568b59b9SBrian Somers
19546cf264aSBrian Somers static int
put_pid(int fd,pid_t pid)19646cf264aSBrian Somers put_pid(int fd, pid_t pid)
197568b59b9SBrian Somers {
198568b59b9SBrian Somers char buf[32];
199568b59b9SBrian Somers int len;
200568b59b9SBrian Somers
2016c78a7b0SBrian Somers len = sprintf (buf, "%10d\n", (int)pid);
202547fa0d9SMark Murray return write (fd, buf, (size_t)len) == len;
203568b59b9SBrian Somers }
204568b59b9SBrian Somers
20546cf264aSBrian Somers static pid_t
get_pid(int fd,int * err)20646cf264aSBrian Somers get_pid(int fd, int *err)
207568b59b9SBrian Somers {
208568b59b9SBrian Somers int bytes_read;
209568b59b9SBrian Somers char buf[32];
210568b59b9SBrian Somers pid_t pid;
211568b59b9SBrian Somers
212568b59b9SBrian Somers bytes_read = read (fd, buf, sizeof (buf) - 1);
213568b59b9SBrian Somers if (bytes_read > 0) {
214568b59b9SBrian Somers buf[bytes_read] = '\0';
215547fa0d9SMark Murray pid = (pid_t)strtol (buf, (char **) NULL, 10);
216687d0cdeSBrian Somers } else {
217568b59b9SBrian Somers pid = -1;
218687d0cdeSBrian Somers *err = bytes_read ? errno : EINVAL;
219687d0cdeSBrian Somers }
220568b59b9SBrian Somers return pid;
221568b59b9SBrian Somers }
222568b59b9SBrian Somers
223568b59b9SBrian Somers /* end of uucplock.c */
224