Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libutil / pidlock.c
blob9f52f5f59a230939a87e930d033addee711367fa
1 /* $NetBSD: pidlock.c,v 1.14 2006/03/19 21:55:37 christos Exp $ */
3 /*
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
8 * are met:
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
22 * SUCH DAMAGE.
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>
31 #include <sys/stat.h>
32 #include <sys/types.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <util.h>
43 #include <paths.h>
46 * Create a lockfile. Return 0 when locked, -1 on error.
48 int
49 pidlock(const char *lockfile, int flags, pid_t *locker, const char *info)
51 char tempfile[MAXPATHLEN];
52 char hostname[MAXHOSTNAMELEN + 1];
53 pid_t pid2 = -1;
54 struct stat st;
55 int err;
56 int f = -1;
57 char s[256];
58 char *p;
59 size_t len;
61 _DIAGASSERT(lockfile != NULL);
62 /* locker may be NULL */
63 /* info may be NULL */
66 if (gethostname(hostname, sizeof(hostname)))
67 return -1;
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)) {
77 errno = ENAMETOOLONG;
78 return -1;
81 /* Open it, write pid, hostname, info. */
82 if ((f = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1)
83 goto out;
85 (void)snprintf(s, sizeof(s), "%10d\n", getpid()); /* pid */
86 if (write(f, s, (size_t)11) != 11)
87 goto out;
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)
93 goto out;
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)
99 goto out;
101 len = strlen(info);
102 if ((size_t)write(f, info, len) != len ||
103 write(f, "\n", (size_t)1) != 1)
104 goto out;
106 (void)close(f);
107 f = -1;
109 /* Hard link the temporary file to the real lock file. */
110 /* This is an atomic operation. */
111 lockfailed:
112 while (link(tempfile, lockfile) == -1) {
113 if (errno != EEXIST)
114 goto out;
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)
118 goto out;
119 if (err == 0) {
120 errno = EINVAL;
121 goto out;
123 pid2 = atoi(s);
124 if ((err = read(f, s, sizeof(s) - 2)) == -1)
125 goto out;
126 if (err == 0)
127 *s = '\0';
128 s[sizeof(s) - 1] = '\0';
129 if ((p = strchr(s, '\n')) != NULL)
130 *p = '\0';
131 (void)close(f);
132 f = -1;
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);
139 continue;
143 if (flags & PIDLOCK_NONBLOCK) {
144 if (locker)
145 *locker = pid2;
146 errno = EWOULDBLOCK;
147 goto out;
148 } else
149 sleep(5);
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)
157 goto out;
158 if (st.st_nlink != 2)
159 goto lockfailed;
161 (void)unlink(tempfile);
162 if (locker)
163 *locker = getpid(); /* return this process's PID on lock */
164 errno = 0;
165 return 0;
166 out:
167 err = errno;
168 if (f != -1)
169 (void)close(f);
170 (void)unlink(tempfile);
171 errno = err;
172 return -1;
175 static int
176 checktty(const char *tty)
178 char ttyfile[MAXPATHLEN];
179 struct stat sb;
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)
186 return -1;
187 if (!S_ISCHR(sb.st_mode)) {
188 errno = EFTYPE;
189 return -1;
191 return 0;
194 #define LOCKPATH "/var/spool/lock/LCK.."
196 static char *
197 makelock(char *buf, size_t bufsiz, const char *tty)
199 (void)strlcpy(buf, LOCKPATH, bufsiz);
200 (void)strlcat(buf, tty, bufsiz);
201 return buf;
204 /*ARGSUSED*/
206 ttylock(const char *tty, int flags, pid_t *locker)
208 char lockfile[MAXPATHLEN];
210 _DIAGASSERT(tty != NULL);
212 if (checktty(tty) != 0)
213 return -1;
215 /* do the lock */
216 return pidlock(makelock(lockfile, sizeof(lockfile), tty),
217 flags, locker, 0);
221 ttyunlock(const char *tty)
223 char lockfile[MAXPATHLEN];
225 _DIAGASSERT(tty != NULL);
227 if (checktty(tty) != 0)
228 return -1;
230 /* remove the lock */
231 return unlink(makelock(lockfile, sizeof(lockfile), tty));