xref: /illumos-gate/usr/src/lib/libnsl/dial/ulockf.c (revision 0d8b5334)
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 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include "uucp.h"
33 
34 #include <unistd.h>
35 #include <stdlib.h>
36 /* #include <sys/types.h> */
37 /* #include <sys/stat.h> */
38 
39 #undef _STAT
40 #undef _FSTAT
41 
42 #define	_STAT stat64
43 #define	_FSTAT fstat64
44 
45 static void	stlock();
46 static int	onelock();
47 
48 /*
49  * make a lock file with given 'name'
50  * If one already exists, send a signal 0 to the process--if
51  * it fails, then unlink it and make a new one.
52  *
53  * input:
54  *	name - name of the lock file to make
55  *
56  * return:
57  *	0	-> success
58  *	FAIL	-> failure
59  */
60 
61 static int
62 mklock(char *name)
63 {
64 	static	char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */
65 	static char *tempfile;
66 
67 	if (pid[0] == '\0') {
68 		tempfile = malloc(MAXNAMESIZE);
69 		if (tempfile == NULL)
70 			return (FAIL);
71 		(void) sprintf(pid, "%*ld\n", SIZEOFPID, (long)getpid());
72 		(void) snprintf(tempfile, MAXNAMESIZE, "%s/LTMP.%ld", X_LOCKDIR,
73 							(long)getpid());
74 	}
75 
76 	if (onelock(pid, tempfile, name) == -1) {
77 		(void) unlink(tempfile);
78 		if (cklock(name))
79 			return (FAIL);
80 		else {
81 			if (onelock(pid, tempfile, name)) {
82 			(void) unlink(tempfile);
83 			DEBUG(4, "ulockf failed in onelock()\n%s", "");
84 			return (FAIL);
85 			}
86 		}
87 	}
88 	stlock(name);
89 	return (0);
90 }
91 
92 /*
93  * check to see if the lock file exists and is still active
94  * - use kill(pid, 0)
95  *
96  * return:
97  *	0	-> success (lock file removed - no longer active
98  *	FAIL	-> lock file still active
99  */
100 static int
101 cklock(char *name)
102 {
103 	int ret;
104 	pid_t lpid = -1;
105 	char alpid[SIZEOFPID+2];	/* +2 for '\n' and NULL */
106 	int fd;
107 
108 	fd = open(name, O_RDONLY);
109 	DEBUG(4, "ulockf name %s\n", name);
110 	if (fd == -1) {
111 		if (errno == ENOENT) {	/* file does not exist -- OK */
112 			return (0);
113 		}
114 		DEBUG(4, "Lock File--can't read (errno %d) --remove it!\n",
115 									errno);
116 		goto unlk;
117 	}
118 	ret = read(fd, (char *)alpid, SIZEOFPID + 1); /* +1 for '\n' */
119 	(void) close(fd);
120 	if (ret != (SIZEOFPID+1)) {
121 
122 		DEBUG(4, "Lock File--bad format--remove it!\n%s", "");
123 		goto unlk;
124 	}
125 	lpid = (pid_t)strtol(alpid, NULL, 10);
126 	if ((ret = kill(lpid, 0)) == 0 || errno == EPERM) {
127 		DEBUG(4, "Lock File--process still active--not removed\n%s",
128 									"");
129 		return (FAIL);
130 	}
131 	/* 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 unlk:
136 
137 	if (unlink(name) != 0) {
138 		DEBUG(4, "ulockf failed in unlink()\n%s", "");
139 		return (FAIL);
140 	}
141 	return (0);
142 }
143 
144 #define	MAXLOCKS	10	/* maximum number of lock files */
145 static char *Lockfile[MAXLOCKS];
146 static int Nlocks = 0;
147 
148 /*
149  * put name in list of lock files
150  * return:
151  *	none
152  */
153 static void
154 stlock(char *name)
155 {
156 	int i;
157 	char *p;
158 
159 	for (i = 0; i < Nlocks; i++) {
160 		if (Lockfile[i] == NULL)
161 			break;
162 	}
163 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", "", i);
164 	if (i >= Nlocks)
165 		i = Nlocks++;
166 	p = calloc((unsigned)strlen(name) + 1, sizeof (char));
167 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0);
168 	(void) strcpy(p, name);
169 	Lockfile[i] = p;
170 }
171 
172 /*
173  * remove the named lock. If named lock is NULL,
174  *	then remove all locks currently in list.
175  * return:
176  *	none
177  */
178 static void
179 rmlock(char *name)
180 {
181 	int i;
182 
183 	for (i = 0; i < Nlocks; i++) {
184 		if (Lockfile[i] == NULL)
185 			continue;
186 		if (name == NULL || EQUALS(name, Lockfile[i])) {
187 			(void) unlink(Lockfile[i]);
188 			free(Lockfile[i]);
189 			Lockfile[i] = NULL;
190 		}
191 	}
192 }
193 
194 /*
195  * makes a lock on behalf of pid.
196  * input:
197  *	pid - process id
198  *	tempfile - name of a temporary in the same file system
199  *	name - lock file name (full path name)
200  * return:
201  *	-1 - failed
202  *	0  - lock made successfully
203  */
204 static int
205 onelock(char *pid, char *tempfile, char *name)
206 {
207 	int fd;
208 	char	cb[100];
209 
210 	fd = creat(tempfile, (mode_t)0444);
211 	if (fd < 0) {
212 		(void) snprintf(cb, sizeof (cb),
213 					"%s %s %d", tempfile, name, errno);
214 		logent("ULOCKC", cb);
215 		if ((errno == EMFILE) || (errno == ENFILE))
216 			(void) unlink(tempfile);
217 		return (-1);
218 	}
219 	/* +1 for '\n' */
220 	if (write(fd, pid, SIZEOFPID+1) != (SIZEOFPID+1)) {
221 		(void) snprintf(cb, sizeof (cb),
222 					"%s %s %d", tempfile, name, errno);
223 		logent("ULOCKW", cb);
224 		(void) unlink(tempfile);
225 		return (-1);
226 	}
227 	(void) chmod(tempfile, (mode_t)0444);
228 	(void) chown(tempfile, UUCPUID, UUCPGID);
229 	(void) close(fd);
230 	if (link(tempfile, name) < 0) {
231 		DEBUG(4, "%s: ", strerror(errno));
232 		DEBUG(4, "link(%s, ", tempfile);
233 		DEBUG(4, "%s)\n", name);
234 		if (unlink(tempfile) <  0) {
235 			(void) snprintf(cb, sizeof (cb),
236 					"ULK err %s %d", tempfile,  errno);
237 			logent("ULOCKLNK", cb);
238 		}
239 		return (-1);
240 	}
241 	if (unlink(tempfile) < 0) {
242 		(void) snprintf(cb, sizeof (cb), "%s %d", tempfile, errno);
243 		logent("ULOCKF", cb);
244 	}
245 	return (0);
246 }
247 
248 /*
249  * fd_mklock(fd) - lock the device indicated by fd is possible
250  *
251  * return -
252  *	SUCCESS - this process now has the fd locked
253  *	FAIL - this process was not able to lock the fd
254  */
255 
256 static int
257 fd_mklock(int fd)
258 {
259 	int tries = 0;
260 	struct stat64 _st_buf;
261 	char lockname[BUFSIZ];
262 
263 	if (_FSTAT(fd, &_st_buf) != 0)
264 		return (FAIL);
265 
266 	(void) snprintf(lockname, sizeof (lockname),
267 		"%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK,
268 		(unsigned long)major(_st_buf.st_dev),
269 		(unsigned long)major(_st_buf.st_rdev),
270 		(unsigned long)minor(_st_buf.st_rdev));
271 
272 	if (mklock(lockname) == FAIL)
273 		return (FAIL);
274 
275 	while (lockf(fd, F_TLOCK, 0L) != 0) {
276 		DEBUG(7, "fd_mklock: lockf returns %d\n", errno);
277 		if ((++tries >= MAX_LOCKTRY) || (errno != EAGAIN)) {
278 			rmlock(lockname);
279 			logent("fd_mklock", "lockf failed");
280 			return (FAIL);
281 		}
282 		(void) sleep(2);
283 	}
284 	DEBUG(7, "fd_mklock: ok\n%s", "");
285 	return (SUCCESS);
286 }
287 
288 /*
289  * remove the locks associated with the device file descriptor
290  *
291  * return -
292  *	SUCCESS - both BNU lock file and advisory locks removed
293  *	FAIL -
294  */
295 
296 static void
297 fd_rmlock(int fd)
298 {
299 	struct stat64 _st_buf;
300 	char lockname[BUFSIZ];
301 
302 	if (_FSTAT(fd, &_st_buf) == 0) {
303 		(void) snprintf(lockname, sizeof (lockname),
304 			"%s.%3.3lu.%3.3lu.%3.3lu", L_LOCK,
305 			(unsigned long)major(_st_buf.st_dev),
306 			(unsigned long)major(_st_buf.st_rdev),
307 			(unsigned long)minor(_st_buf.st_rdev));
308 		rmlock(lockname);
309 	}
310 	(void) lockf(fd, F_ULOCK, 0L);
311 }
312