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