pidlock.c revision 1.4 1 /* $NetBSD: pidlock.c,v 1.4 1998/07/06 06:47:24 mrg Exp $ */
2
3 /*
4 * Copyright 1996, 1997 by Curt Sampson <cjs (at) netbsd.org>.
5 *
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.
11 *
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.
23 */
24
25 #include <sys/cdefs.h>
26 #if defined(LIBC_SCCS) && !defined(lint)
27 __RCSID("$NetBSD: pidlock.c,v 1.4 1998/07/06 06:47:24 mrg Exp $");
28 #endif /* LIBC_SCCS and not lint */
29
30 #include <sys/errno.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <util.h>
42
43 /*
44 * Create a lockfile. Return 0 when locked, -1 on error.
45 */
46 int
47 pidlock(lockfile, flags, locker, info)
48 const char *lockfile;
49 int flags;
50 pid_t *locker;
51 const char *info;
52 {
53 char tempfile[MAXPATHLEN];
54 char hostname[MAXHOSTNAMELEN + 1];
55 pid_t pid2 = -1;
56 struct stat st;
57 int err;
58 int f;
59 char s[256];
60 char *p;
61
62 if (gethostname(hostname, sizeof(hostname)))
63 return -1;
64 hostname[sizeof(hostname) - 1] = '\0';
65
66 /*
67 * Build a path to the temporary file.
68 * We use the path with the PID and hostname appended.
69 * XXX This is not thread safe.
70 */
71 if (snprintf(tempfile, sizeof(tempfile), "%s.%d.%s", lockfile,
72 (int) getpid(), hostname) >= sizeof(tempfile)) {
73 errno = ENAMETOOLONG;
74 return -1;
75 }
76
77 /* Open it, write pid, hostname, info. */
78 if ( (f = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1 ) {
79 err = errno;
80 unlink(tempfile);
81 errno = err;
82 return -1;
83 }
84 snprintf(s, sizeof(s), "%10d\n", getpid()); /* pid */
85 if (write(f, s, 11) != 11) {
86 err = errno;
87 close(f);
88 unlink(tempfile);
89 errno = err;
90 return -1;
91 }
92 if ((flags & PIDLOCK_USEHOSTNAME)) { /* hostname */
93 if ((write(f, hostname, strlen(hostname)) != strlen(hostname))
94 || (write(f, "\n", 1) != 1)) {
95 err = errno;
96 close(f);
97 unlink(tempfile);
98 errno = err;
99 return -1;
100 }
101 }
102 if (info) { /* info */
103 if (!(flags & PIDLOCK_USEHOSTNAME)) {
104 /* write blank line because there's no hostname */
105 if (write(f, "\n", 1) != 1) {
106 err = errno;
107 close(f);
108 unlink(tempfile);
109 errno = err;
110 return -1;
111 }
112 }
113 if (write(f, info, strlen(info)) != strlen(info) ||
114 (write(f, "\n", 1) != 1)) {
115 err = errno;
116 close(f);
117 unlink(tempfile);
118 errno = err;
119 return -1;
120 }
121 }
122 close(f);
123
124 /* Hard link the temporary file to the real lock file. */
125 /* This is an atomic operation. */
126 lockfailed:
127 while (link(tempfile, lockfile) != 0) {
128 if (errno != EEXIST) {
129 err = errno;
130 unlink(tempfile);
131 errno = err;
132 return -1;
133 }
134 /* Find out who has this lockfile. */
135 if ((f = open(lockfile, O_RDONLY, 0)) != 0) {
136 read(f, s, 11);
137 pid2 = atoi(s);
138 read(f, s, sizeof(s)-2);
139 s[sizeof(s)-1] = '\0';
140 if ((p=strchr(s, '\n')))
141 *p = '\0';
142 close(f);
143
144 if (!((flags & PIDLOCK_USEHOSTNAME) &&
145 strcmp(s, hostname))) {
146 if ((kill(pid2, 0) != 0) && (errno == ESRCH)) {
147 /* process doesn't exist */
148 unlink(lockfile);
149 continue;
150 }
151 }
152 }
153 if (flags & PIDLOCK_NONBLOCK) {
154 if (locker)
155 *locker = pid2;
156 unlink(tempfile);
157 errno = EWOULDBLOCK;
158 return -1;
159 } else
160 sleep(5);
161 }
162 /*
163 * Check to see that we really were successful (in case we're
164 * using NFS) by making sure that something really is linked
165 * to our tempfile (reference count is two).
166 */
167 if (stat(tempfile, &st) != 0) {
168 err = errno;
169 /*
170 * We don't know if lockfile was really created by us,
171 * so we can't remove it.
172 */
173 unlink(tempfile);
174 errno = err;
175 return -1;
176 }
177 if (st.st_nlink != 2)
178 goto lockfailed;
179
180 unlink(tempfile);
181 if (locker)
182 *locker = getpid(); /* return this process's PID on lock */
183 errno = 0;
184 return 0;
185 }
186
187 #define LOCKPATH "/var/spool/lock/LCK.."
188 #define DEVPATH "/dev/"
189
190 int
191 ttylock(tty, flags, locker)
192 const char *tty;
193 int flags;
194 pid_t *locker;
195 {
196 char lockfile[MAXPATHLEN];
197 char ttyfile[MAXPATHLEN];
198 struct stat sb;
199
200 /* make sure the tty exists */
201 strcpy(ttyfile, DEVPATH);
202 strncat(ttyfile, tty, MAXPATHLEN-strlen(DEVPATH));
203 if (stat(ttyfile, &sb)) {
204 errno = ENOENT; return -1;
205 }
206 if (!S_ISCHR(sb.st_mode)) {
207 errno = ENOENT; return -1;
208 }
209
210 /* do the lock */
211 strcpy(lockfile, LOCKPATH);
212 strncat(lockfile, tty, MAXPATHLEN-strlen(LOCKPATH));
213 return pidlock(lockfile, 0, 0, 0);
214 }
215
216 int
217 ttyunlock(tty)
218 const char *tty;
219 {
220 char lockfile[MAXPATHLEN];
221 char ttyfile[MAXPATHLEN];
222 struct stat sb;
223
224 /* make sure the tty exists */
225 strcpy(ttyfile, DEVPATH);
226 strncat(ttyfile, tty, MAXPATHLEN-strlen(DEVPATH));
227 if (stat(ttyfile, &sb)) {
228 errno = ENOENT; return -1;
229 }
230 if (!S_ISCHR(sb.st_mode)) {
231 errno = ENOENT; return -1;
232 }
233
234 /* undo the lock */
235 strcpy(lockfile, LOCKPATH);
236 strncat(lockfile, tty, MAXPATHLEN-strlen(LOCKPATH));
237 return unlink(lockfile);
238 }
239