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