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