xref: /illumos-gate/usr/src/cmd/tip/uucplock.c (revision 7c478bd9)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * Copyright (c) 1983 Regents of the University of California.
7  * All rights reserved. The Berkeley software License Agreement
8  * specifies the terms and conditions for redistribution.
9  */
10 #ident	"%Z%%M%	%I%	%E% SMI"	/* from UCB 4.6 6/25/83 */
11 /*
12  * defs that come from uucp.h
13  */
14 #define	NAMESIZE 40
15 #define	FAIL -1
16 #define	SAME 0
17 #define	SLCKTIME (8*60*60)	/* device timeout (LCK.. files) in seconds */
18 #ifdef __STDC__
19 #define	ASSERT(e, f, v) if (!(e)) {\
20 	fprintf(stderr, "AERROR - (%s) ", #e); \
21 	fprintf(stderr, f, v); \
22 	finish(FAIL); \
23 }
24 #else
25 #define	ASSERT(e, f, v) if (!(e)) {\
26 	fprintf(stderr, "AERROR - (%s) ", "e"); \
27 	fprintf(stderr, f, v); \
28 	finish(FAIL); \
29 }
30 #endif
31 #define	SIZEOFPID	10		/* maximum number of digits in a pid */
32 
33 #define	LOCKDIR "/var/spool/locks"
34 #define	LOCKPRE "LK"
35 
36 /*
37  * This code is taken almost directly from uucp and follows the same
38  * conventions.  This is important since uucp and tip should
39  * respect each others locks.
40  */
41 
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/mkdev.h>
45 #include <stdio.h>
46 #include <errno.h>
47 #include <string.h>
48 
49 static void	stlock();
50 static int	onelock();
51 static int	checkLock();
52 
53 
54 /*
55  *	ulockf(file, atime)
56  *	char *file;
57  *	time_t atime;
58  *
59  *	ulockf  -  this routine will create a lock file (file).
60  *	If one already exists, send a signal 0 to the process--if
61  *	it fails, then unlink it and make a new one.
62  *
63  *	input:
64  *		file - name of the lock file
65  *		atime - is unused, but we keep it for lint compatibility
66  *			with non-ATTSVKILL
67  *
68  *	return codes:  0  |  FAIL
69  */
70 
71 static
72 ulockf(file, atime)
73 	char *file;
74 	time_t atime;
75 {
76 	static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */
77 	static char tempfile[NAMESIZE];
78 
79 	if (pid[0] == '\0') {
80 		(void) sprintf(pid, "%*d\n", SIZEOFPID, getpid());
81 		(void) sprintf(tempfile, "%s/LTMP.%d", LOCKDIR, getpid());
82 	}
83 	if (onelock(pid, tempfile, file) == -1) {
84 		/* lock file exists */
85 		(void) unlink(tempfile);
86 		if (checkLock(file))
87 			return (FAIL);
88 		else {
89 			if (onelock(pid, tempfile, file)) {
90 				(void) unlink(tempfile);
91 				return (FAIL);
92 			}
93 		}
94 	}
95 	stlock(file);
96 	return (0);
97 }
98 
99 /*
100  * check to see if the lock file exists and is still active
101  * - use kill(pid, 0) - (this only works on ATTSV and some hacked
102  * BSD systems at this time)
103  * return:
104  *	0	-> success (lock file removed - no longer active)
105  *	FAIL	-> lock file still active
106  */
107 static int
108 checkLock(file)
109 register char *file;
110 {
111 	register int ret;
112 	int lpid = -1;
113 	char alpid[SIZEOFPID+2];	/* +2 for '\n' and NULL */
114 	int fd;
115 	extern int errno;
116 
117 	fd = open(file, 0);
118 	if (fd == -1) {
119 		if (errno == ENOENT)  /* file does not exist -- OK */
120 			return (0);
121 		goto unlk;
122 	}
123 	ret = read(fd, (char *)alpid, SIZEOFPID+1); /* +1 for '\n' */
124 	(void) close(fd);
125 	if (ret != (SIZEOFPID+1))
126 		goto unlk;
127 	lpid = atoi(alpid);
128 	if ((ret = kill(lpid, 0)) == 0 || errno == EPERM)
129 		return (FAIL);
130 
131 unlk:
132 	if (unlink(file) != 0)
133 		return (FAIL);
134 	return (0);
135 }
136 
137 #define	MAXLOCKS 10	/* maximum number of lock files */
138 char *Lockfile[MAXLOCKS];
139 int Nlocks = 0;
140 
141 /*
142  *	stlock(name)	put name in list of lock files
143  *	char *name;
144  *
145  *	return codes:  none
146  */
147 
148 static void
149 stlock(name)
150 	char *name;
151 {
152 	char *p;
153 	extern char *calloc();
154 	int i;
155 
156 	for (i = 0; i < Nlocks; i++) {
157 		if (Lockfile[i] == NULL)
158 			break;
159 	}
160 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
161 	if (i >= Nlocks)
162 		i = Nlocks++;
163 	p = calloc(strlen(name) + 1, sizeof (char));
164 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
165 	strcpy(p, name);
166 	Lockfile[i] = p;
167 }
168 
169 /*
170  *	rmlock(name)	remove all lock files in list
171  *	char *name;	or name
172  *
173  *	return codes: none
174  */
175 
176 static
177 rmlock(name)
178 	char *name;
179 {
180 	int i;
181 
182 	for (i = 0; i < Nlocks; i++) {
183 		if (Lockfile[i] == NULL)
184 			continue;
185 		if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
186 			unlink(Lockfile[i]);
187 			free(Lockfile[i]);
188 			Lockfile[i] = NULL;
189 		}
190 	}
191 }
192 
193 static
194 onelock(pid, tempfile, name)
195 	char *pid, *tempfile, *name;
196 {
197 	int fd;
198 	static int first = 1;
199 	extern int errno;
200 
201 	fd = creat(tempfile, 0444);
202 	if (fd < 0) {
203 		if (first) {
204 			if (errno == EACCES) {
205 				fprintf(stderr,
206 			"tip: can't create files in lock file directory %s\n",
207 				    LOCKDIR);
208 			} else if (access(LOCKDIR, 0) < 0) {
209 				fprintf(stderr, "tip: lock file directory %s: ",
210 				    LOCKDIR);
211 				perror("");
212 			}
213 			first = 0;
214 		}
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 		fprintf(stderr,
222 		    "tip: can't write to files in lock file directory %s: %s\n",
223 		    LOCKDIR, strerror(errno));
224 		(void) unlink(tempfile);
225 		return (-1);
226 	}
227 	fchmod(fd, 0444);
228 	close(fd);
229 	if (link(tempfile, name) < 0) {
230 		unlink(tempfile);
231 		return (-1);
232 	}
233 	unlink(tempfile);
234 	return (0);
235 }
236 
237 /*
238  *	delock(sys)	remove a lock file
239  *	char *sys;
240  *
241  *	return codes:  0  |  FAIL
242  */
243 
244 delock(sys)
245 	char *sys;
246 {
247 	struct stat sb;
248 	char lname[NAMESIZE];
249 
250 	if (stat(sys, &sb) < 0)
251 		return (FAIL);
252 	sprintf(lname, "%s/%s.%3.3lu.%3.3lu.%3.3lu", LOCKDIR, LOCKPRE,
253 		(unsigned long)major(sb.st_dev),
254 		(unsigned long)major(sb.st_rdev),
255 		(unsigned long)minor(sb.st_rdev));
256 	rmlock(lname);
257 }
258 
259 /*
260  *	mlock(sys)	create system lock
261  *	char *sys;
262  *
263  *	return codes:  0  |  FAIL
264  */
265 
266 mlock(sys)
267 	char *sys;
268 {
269 	struct stat sb;
270 	char lname[NAMESIZE];
271 
272 	if (stat(sys, &sb) < 0)
273 		return (FAIL);
274 	sprintf(lname, "%s/%s.%3.3lu.%3.3lu.%3.3lu", LOCKDIR, LOCKPRE,
275 		(unsigned long)major(sb.st_dev),
276 		(unsigned long)major(sb.st_rdev),
277 		(unsigned long)minor(sb.st_rdev));
278 	return (ulockf(lname, (time_t)SLCKTIME) < 0 ? FAIL : 0);
279 }
280 
281 /*
282  * update access and modify times for lock files
283  * return:
284  *	none
285  */
286 void
287 ultouch()
288 {
289 	register int i;
290 	time_t time();
291 
292 	struct ut {
293 		time_t actime;
294 		time_t modtime;
295 	} ut;
296 
297 	ut.actime = time(&ut.modtime);
298 	for (i = 0; i < Nlocks; i++) {
299 		if (Lockfile[i] == NULL)
300 			continue;
301 		utime(Lockfile[i], &ut);
302 	}
303 }
304