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