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