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