1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24 /*
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 #include "uucp.h"
30
31 #include <unistd.h>
32 /* #include <sys/types.h> */
33 /* #include <sys/stat.h> */
34
35 static struct stat _st_buf;
36 static char lockname[BUFSIZ];
37
38 static void stlock(char *);
39 static int onelock(char *, char *, char *);
40
41 /*
42 * make a lock file with given 'name'
43 * If one already exists, send a signal 0 to the process--if
44 * it fails, then unlink it and make a new one.
45 *
46 * input:
47 * name - name of the lock file to make
48 *
49 * return:
50 * 0 -> success
51 * FAIL -> failure
52 */
53
54 GLOBAL int
mklock(char * name)55 mklock(char *name)
56 {
57 static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */
58 static char tempfile[MAXNAMESIZE];
59
60 #ifdef V8
61 char *cp;
62 #endif
63
64 if (pid[0] == '\0') {
65 (void) sprintf(pid, "%*ld\n", SIZEOFPID, (long)getpid());
66 (void) sprintf(tempfile, "%s/LTMP.%ld", X_LOCKDIR,
67 (long)getpid());
68 }
69
70 #ifdef V8 /* this wouldn't be a problem if we used lock directories */
71 /* some day the truncation of system names will bite us */
72 cp = rindex(name, '/');
73 if (cp++ != CNULL)
74 if (strlen(cp) > MAXBASENAME)
75 *(cp+MAXBASENAME) = NULLCHAR;
76 #endif /* V8 */
77 if (onelock(pid, tempfile, name) == -1) {
78 (void) unlink(tempfile);
79 if (cklock(name)) {
80 return (FAIL);
81 } else {
82 if (onelock(pid, tempfile, name)) {
83 (void) unlink(tempfile);
84 DEBUG(4, "ulockf failed in onelock()\n%s", "");
85 return (FAIL);
86 }
87 }
88 }
89
90 stlock(name);
91 return (0);
92 }
93
94 /*
95 * check to see if the lock file exists and is still active
96 * - use kill(pid,0)
97 *
98 * return:
99 * 0 -> success (lock file removed - no longer active
100 * FAIL -> lock file still active
101 */
102 GLOBAL int
cklock(char * name)103 cklock(char *name)
104 {
105 int ret;
106 pid_t lpid = -1;
107 char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */
108 int fd;
109
110 fd = open(name, O_RDONLY);
111 DEBUG(4, "ulockf name %s\n", name);
112 if (fd == -1) {
113 if (errno == ENOENT) /* file does not exist -- OK */
114 return (0);
115 DEBUG(4, "Lock File--can't read (errno %d) --remove it!\n",
116 errno);
117 goto unlk;
118 }
119 ret = read(fd, (char *)alpid, SIZEOFPID + 1); /* +1 for '\n' */
120 (void) close(fd);
121 if (ret != (SIZEOFPID+1)) {
122
123 DEBUG(4, "Lock File--bad format--remove it!\n%s", "");
124 goto unlk;
125 }
126 lpid = (pid_t)strtol(alpid, NULL, 10);
127 if ((ret = kill(lpid, 0)) == 0 || errno == EPERM) {
128 DEBUG(4, "Lock File--process still active--not removed\n%s",
129 "");
130 return (FAIL);
131 } else { /* process no longer active */
132 DEBUG(4, "kill pid (%ld), ", (long)lpid);
133 DEBUG(4, "returned %d", ret);
134 DEBUG(4, "--ok to remove lock file (%s)\n", name);
135 }
136 unlk:
137
138 if (unlink(name) != 0) {
139 DEBUG(4, "ulockf failed in unlink()\n%s", "");
140 return (FAIL);
141 }
142 return (0);
143 }
144
145 #define MAXLOCKS 10 /* maximum number of lock files */
146 static char *Lockfile[MAXLOCKS];
147 GLOBAL int Nlocks = 0;
148
149 /*
150 * put name in list of lock files
151 * return:
152 * none
153 */
154 static void
stlock(char * name)155 stlock(char *name)
156 {
157 int i;
158 char *p;
159
160 for (i = 0; i < Nlocks; i++) {
161 if (Lockfile[i] == NULL)
162 break;
163 }
164 ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", "", i);
165 if (i >= Nlocks)
166 i = Nlocks++;
167 p = calloc((unsigned)strlen(name) + 1, sizeof (char));
168 ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0);
169 (void) strcpy(p, name);
170 Lockfile[i] = p;
171 }
172
173 /*
174 * remove the named lock. If named lock is NULL,
175 * then remove all locks currently in list.
176 * return:
177 * none
178 */
179 GLOBAL void
rmlock(char * name)180 rmlock(char *name)
181 {
182 int i;
183 #ifdef V8
184 char *cp;
185
186 cp = rindex(name, '/');
187 if (cp++ != CNULL)
188 if (strlen(cp) > MAXBASENAME)
189 *(cp+MAXBASENAME) = NULLCHAR;
190 #endif /* V8 */
191
192
193 for (i = 0; i < Nlocks; i++) {
194 if (Lockfile[i] == NULL)
195 continue;
196 if (name == NULL || EQUALS(name, Lockfile[i])) {
197 (void) unlink(Lockfile[i]);
198 free(Lockfile[i]);
199 Lockfile[i] = NULL;
200 }
201 }
202 }
203
204
205
206 /*
207 * remove a lock file
208 *
209 * Parameters:
210 * pre - Path and first part of file name of the lock file to be
211 * removed.
212 * s - The suffix part of the lock file. The name of the lock file
213 * will be derrived by concatenating pre, a period, and s.
214 *
215 * return:
216 * none
217 */
218 GLOBAL void
delock(char * pre,char * s)219 delock(char *pre, char *s)
220 {
221 char ln[MAXNAMESIZE];
222
223 (void) sprintf(ln, "%s.%s", pre, s);
224 BASENAME(ln, '/')[MAXBASENAME] = '\0';
225 rmlock(ln);
226 }
227
228
229 /*
230 * create lock file
231 *
232 * Parameters:
233 * pre - Path and first part of file name of the lock file to be
234 * created.
235 * name - The suffix part of the lock file. The name of the lock file
236 * will be derrived by concatenating pre, a period, and name.
237 *
238 * return:
239 * 0 -> success
240 * FAIL -> failure
241 */
242 GLOBAL int
mlock(char * pre,char * name)243 mlock(char *pre, char *name)
244 {
245 char lname[MAXNAMESIZE];
246
247 /*
248 * if name has a '/' in it, then it's a device name and it's
249 * not in /dev (i.e., it's a remotely-mounted device or it's
250 * in a subdirectory of /dev). in either case, creating our normal
251 * lockfile (/var/spool/locks/LCK..<dev>) is going to bomb if
252 * <dev> is "/remote/dev/term/14" or "/dev/net/foo/clone", so never
253 * mind. since we're using advisory filelocks on the devices
254 * themselves, it'll be safe.
255 *
256 * of course, programs and people who are used to looking at the
257 * lockfiles to find out what's going on are going to be a trifle
258 * misled. we really need to re-consider the lockfile naming structure
259 * to accomodate devices in directories other than /dev ... maybe in
260 * the next release.
261 */
262 if (strchr(name, '/') != NULL)
263 return (0);
264 (void) sprintf(lname, "%s.%s", pre, BASENAME(name, '/'));
265 BASENAME(lname, '/')[MAXBASENAME] = '\0';
266 return (mklock(lname));
267 }
268
269 /*
270 * makes a lock on behalf of pid.
271 * input:
272 * pid - process id
273 * tempfile - name of a temporary in the same file system
274 * name - lock file name (full path name)
275 * return:
276 * -1 - failed
277 * 0 - lock made successfully
278 */
279 static int
onelock(char * pid,char * tempfile,char * name)280 onelock(char *pid, char *tempfile, char *name)
281 {
282 int fd;
283 char cb[100];
284
285 fd = creat(tempfile, (mode_t)0444);
286 if (fd < 0) {
287 (void) sprintf(cb, "%s %s %d", tempfile, name, errno);
288 logent("ULOCKC", cb);
289 if ((errno == EMFILE) || (errno == ENFILE))
290 (void) unlink(tempfile);
291 return (-1);
292 }
293 /* +1 for '\n' */
294 if (write(fd, pid, SIZEOFPID + 1) != (SIZEOFPID + 1)) {
295 (void) sprintf(cb, "%s %s %d", tempfile, name, errno);
296 logent("ULOCKW", cb);
297 (void) unlink(tempfile);
298 return (-1);
299 }
300 (void) chmod(tempfile, (mode_t)0444);
301 (void) chown(tempfile, UUCPUID, UUCPGID);
302 (void) close(fd);
303 if (link(tempfile, name) < 0) {
304 DEBUG(4, "%s: ", strerror(errno));
305 DEBUG(4, "link(%s, ", tempfile);
306 DEBUG(4, "%s)\n", name);
307 if (unlink(tempfile) < 0) {
308 (void) sprintf(cb, "ULK err %s %d", tempfile, errno);
309 logent("ULOCKLNK", cb);
310 }
311 return (-1);
312 }
313 if (unlink(tempfile) < 0) {
314 (void) sprintf(cb, "%s %d", tempfile, errno);
315 logent("ULOCKF", cb);
316 }
317 return (0);
318 }
319
320 /*
321 * fd_mklock(fd) - lock the device indicated by fd is possible
322 *
323 * return -
324 * SUCCESS - this process now has the fd locked
325 * FAIL - this process was not able to lock the fd
326 */
327
328 GLOBAL int
fd_mklock(int fd)329 fd_mklock(int fd)
330 {
331 int tries = 0;
332
333 if (fstat(fd, &_st_buf) != 0)
334 return (FAIL);
335
336 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK,
337 (unsigned long) major(_st_buf.st_dev),
338 (unsigned long) major(_st_buf.st_rdev),
339 (unsigned long) minor(_st_buf.st_rdev));
340
341 if (mklock(lockname) == FAIL)
342 return (FAIL);
343
344 while (lockf(fd, F_TLOCK, 0L) != 0) {
345 DEBUG(7, "fd_mklock: lockf returns %d\n", errno);
346 if ((++tries >= MAX_LOCKTRY) || (errno != EAGAIN)) {
347 rmlock(lockname);
348 logent("fd_mklock", "lockf failed");
349 return (FAIL);
350 }
351 (void) sleep(2);
352 }
353 DEBUG(7, "fd_mklock: ok\n%s", "");
354 return (SUCCESS);
355 }
356
357 /*
358 * fn_cklock(name) - determine if the device indicated by name is locked
359 *
360 * return -
361 * SUCCESS - the name is not locked
362 * FAIL - the name is locked by another process
363 */
364
365 GLOBAL int
fn_cklock(char * name)366 fn_cklock(char *name)
367 {
368 /* we temporarily use lockname to hold full path name */
369 (void) sprintf(lockname, "%s%s", (*name == '/' ? "" : "/dev/"), name);
370
371 if (stat(lockname, &_st_buf) != 0)
372 return (FAIL);
373
374 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK,
375 (unsigned long) major(_st_buf.st_dev),
376 (unsigned long) major(_st_buf.st_rdev),
377 (unsigned long) minor(_st_buf.st_rdev));
378
379 return (cklock(lockname));
380 }
381
382 /*
383 * fd_cklock(fd) - determine if the device indicated by fd is locked
384 *
385 * return -
386 * SUCCESS - the fd is not locked
387 * FAIL - the fd is locked by another process
388 */
389
390 GLOBAL int
fd_cklock(int fd)391 fd_cklock(int fd)
392 {
393 if (fstat(fd, &_st_buf) != 0)
394 return (FAIL);
395
396 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK,
397 (unsigned long) major(_st_buf.st_dev),
398 (unsigned long) major(_st_buf.st_rdev),
399 (unsigned long) minor(_st_buf.st_rdev));
400
401 if (cklock(lockname) == FAIL)
402 return (FAIL);
403 else
404 return (lockf(fd, F_TEST, 0L));
405 }
406
407 /*
408 * remove the locks associated with the device file descriptor
409 *
410 * return -
411 * SUCCESS - both BNU lock file and advisory locks removed
412 * FAIL -
413 */
414
415 GLOBAL void
fd_rmlock(int fd)416 fd_rmlock(int fd)
417 {
418 if (fstat(fd, &_st_buf) == 0) {
419 (void) sprintf(lockname, "%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK,
420 (unsigned long) major(_st_buf.st_dev),
421 (unsigned long) major(_st_buf.st_rdev),
422 (unsigned long) minor(_st_buf.st_rdev));
423 rmlock(lockname);
424 }
425 (void) lockf(fd, F_ULOCK, 0L);
426 }
427