1 /* $NetBSD: pidlock.c,v 1.14 2006/03/19 21:55:37 christos Exp $ */
4 * Copyright 1996, 1997 by Curt Sampson <cjs@NetBSD.org>.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
16 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 #include <sys/cdefs.h>
26 #if defined(LIBC_SCCS) && !defined(lint)
27 __RCSID("$NetBSD: pidlock.c,v 1.14 2006/03/19 21:55:37 christos Exp $");
28 #endif /* LIBC_SCCS and not lint */
30 #include <sys/param.h>
32 #include <sys/types.h>
46 * Create a lockfile. Return 0 when locked, -1 on error.
49 pidlock(const char *lockfile
, int flags
, pid_t
*locker
, const char *info
)
51 char tempfile
[MAXPATHLEN
];
52 char hostname
[MAXHOSTNAMELEN
+ 1];
61 _DIAGASSERT(lockfile
!= NULL
);
62 /* locker may be NULL */
63 /* info may be NULL */
66 if (gethostname(hostname
, sizeof(hostname
)))
68 hostname
[sizeof(hostname
) - 1] = '\0';
71 * Build a path to the temporary file.
72 * We use the path with the PID and hostname appended.
73 * XXX This is not thread safe.
75 if (snprintf(tempfile
, sizeof(tempfile
), "%s.%d.%s", lockfile
,
76 (int) getpid(), hostname
) >= (int)sizeof(tempfile
)) {
81 /* Open it, write pid, hostname, info. */
82 if ((f
= open(tempfile
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1)
85 (void)snprintf(s
, sizeof(s
), "%10d\n", getpid()); /* pid */
86 if (write(f
, s
, (size_t)11) != 11)
89 if ((flags
& PIDLOCK_USEHOSTNAME
)) { /* hostname */
90 len
= strlen(hostname
);
91 if ((size_t)write(f
, hostname
, len
) != len
92 || write(f
, "\n", (size_t)1) != 1)
95 if (info
) { /* info */
96 if (!(flags
& PIDLOCK_USEHOSTNAME
)) {
97 /* write blank line because there's no hostname */
98 if (write(f
, "\n", (size_t)1) != 1)
102 if ((size_t)write(f
, info
, len
) != len
||
103 write(f
, "\n", (size_t)1) != 1)
109 /* Hard link the temporary file to the real lock file. */
110 /* This is an atomic operation. */
112 while (link(tempfile
, lockfile
) == -1) {
115 /* Find out who has this lockfile. */
116 if ((f
= open(lockfile
, O_RDONLY
, 0)) != -1) {
117 if ((err
= read(f
, s
, (size_t)11)) == -1)
124 if ((err
= read(f
, s
, sizeof(s
) - 2)) == -1)
128 s
[sizeof(s
) - 1] = '\0';
129 if ((p
= strchr(s
, '\n')) != NULL
)
134 if ((flags
& PIDLOCK_USEHOSTNAME
) == 0 ||
135 strcmp(s
, hostname
) == 0) {
136 if (kill(pid2
, 0) == -1 && errno
== ESRCH
) {
137 /* process doesn't exist */
138 (void)unlink(lockfile
);
143 if (flags
& PIDLOCK_NONBLOCK
) {
152 * Check to see that we really were successful (in case we're
153 * using NFS) by making sure that something really is linked
154 * to our tempfile (reference count is two).
156 if (stat(tempfile
, &st
) == -1)
158 if (st
.st_nlink
!= 2)
161 (void)unlink(tempfile
);
163 *locker
= getpid(); /* return this process's PID on lock */
170 (void)unlink(tempfile
);
176 checktty(const char *tty
)
178 char ttyfile
[MAXPATHLEN
];
181 (void)strlcpy(ttyfile
, _PATH_DEV
, sizeof(ttyfile
));
182 (void)strlcat(ttyfile
, tty
, sizeof(ttyfile
));
184 /* make sure the tty exists */
185 if (stat(ttyfile
, &sb
) == -1)
187 if (!S_ISCHR(sb
.st_mode
)) {
194 #define LOCKPATH "/var/spool/lock/LCK.."
197 makelock(char *buf
, size_t bufsiz
, const char *tty
)
199 (void)strlcpy(buf
, LOCKPATH
, bufsiz
);
200 (void)strlcat(buf
, tty
, bufsiz
);
206 ttylock(const char *tty
, int flags
, pid_t
*locker
)
208 char lockfile
[MAXPATHLEN
];
210 _DIAGASSERT(tty
!= NULL
);
212 if (checktty(tty
) != 0)
216 return pidlock(makelock(lockfile
, sizeof(lockfile
), tty
),
221 ttyunlock(const char *tty
)
223 char lockfile
[MAXPATHLEN
];
225 _DIAGASSERT(tty
!= NULL
);
227 if (checktty(tty
) != 0)
230 /* remove the lock */
231 return unlink(makelock(lockfile
, sizeof(lockfile
), tty
));