xref: /original-bsd/usr.bin/uucp/libuu/ulockf.c (revision 8f210ce8)
1 #ifndef lint
2 static char sccsid[] = "@(#)ulockf.c	5.2 (Berkeley) 01/22/85";
3 #endif
4 
5 #include "uucp.h"
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 
9 extern time_t	time();
10 
11 /* File mode for lock files */
12 #define	LCKMODE	0444
13 
14 /*
15  *	ulockf  -  this routine will create a lock file (file).
16  *	If one already exists, the create time is checked for
17  *	older than the age time (atime).
18  *	If it is older, an attempt will be made to unlink it
19  *	and create a new one.
20  *
21  *	return codes:  0  |  FAIL
22  */
23 
24 ulockf(file, atime)
25 register char *file;
26 time_t atime;
27 {
28 	struct stat stbuf;
29 	time_t ptime;
30 	register int ret;
31 	static int pid = -1;
32 	static char tempfile[NAMESIZE];
33 
34 	if (pid < 0) {
35 		pid = getpid();
36 		sprintf(tempfile, "%s/LTMP.%d", LOCKDIR, pid);
37 	}
38 	if (onelock(pid, tempfile, file) == -1) {
39 		/* lock file exists */
40 		/* get status to check age of the lock file */
41 		ret = stat(file, &stbuf);
42 		if (ret != -1) {
43 			time(&ptime);
44 			if ((ptime - stbuf.st_ctime) < atime) {
45 				/* file not old enough to delete */
46 				return FAIL;
47 			}
48 			ret = unlink(file);
49 			logent(file, "DEAD LOCK");
50 			sleep(5);	/* rti!trt: avoid a race */
51 			ret = onelock(pid, tempfile, file);
52 		}
53 		if (ret != 0)
54 			return FAIL;
55 	}
56 	stlock(file);
57 	return SUCCESS;
58 }
59 
60 
61 #define MAXLOCKS 10	/* maximum number of lock files */
62 char *Lockfile[MAXLOCKS];
63 int Nlocks = 0;
64 
65 /***
66  *	stlock(name)	put name in list of lock files
67  *	char *name;
68  *
69  *	return codes:  none
70  */
71 
72 stlock(name)
73 register char *name;
74 {
75 	register char *p;
76 	register int i;
77 
78 	for (i = 0; i < Nlocks; i++) {
79 		if (Lockfile[i] == NULL)
80 			break;
81 	}
82 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", CNULL, i);
83 	if (i >= Nlocks)
84 		i = Nlocks++;
85 	p = calloc((unsigned)(strlen(name)+1), sizeof (char));
86 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0);
87 	strcpy(p, name);
88 	Lockfile[i] = p;
89 	return;
90 }
91 
92 
93 /*
94  *	remove all lock files in list *	or name
95  *
96  *	return codes: none
97  */
98 
99 rmlock(name)
100 register char *name;
101 {
102 	register int i;
103 
104 	for (i = 0; i < Nlocks; i++) {
105 		if (Lockfile[i] == NULL)
106 			continue;
107 		if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
108 			unlink(Lockfile[i]);
109 			free(Lockfile[i]);
110 			Lockfile[i] = NULL;
111 		}
112 	}
113 }
114 
115 /*
116  *	isalock(name) returns 0 if the name is a lock.
117  *	unlock(name)  unlocks name if it is a lock.
118  *	onelock(pid,tempfile,name) makes lock a name
119  *	on behalf of pid.  Tempfile must be in the same
120  *	file system as name.
121  *	lock(pid,tempfile,names) either locks all the
122  *	names or none of them.
123  */
124 isalock(name)
125 char *name;
126 {
127 	struct stat xstat;
128 	if (stat(name,&xstat) < 0)
129 		return 0;
130 	if (xstat.st_size != sizeof(int))
131 		return 0;
132 	return 1;
133 }
134 unlock(name)
135 char *name;
136 {
137 	if (isalock(name))
138 		return unlink(name);
139 	else
140 		return -1;
141 }
142 onelock(pid,tempfile,name)
143 char *tempfile,*name;
144 {
145 	register int fd;
146 #ifdef VMS
147 	fd = creat(name, LCKMODE, "1version");
148 #else !VMS
149 	fd = creat(tempfile, LCKMODE);
150 #endif !VMS
151 	if (fd<0)
152 		return FAIL;
153 	write(fd, (char *) &pid, sizeof(int));
154 	close(fd);
155 #ifndef	VMS
156 	if (link(tempfile, name) < 0) {
157 		unlink(tempfile);
158 		return FAIL;
159 	}
160 	unlink(tempfile);
161 #endif
162 	return SUCCESS;
163 }
164 
165 
166 lock(pid, tempfile, names)
167 char *tempfile;
168 register char **names;
169 {
170 	register int i, j;
171 
172 	for(i=0; names[i] != 0; i++) {
173 		if (onelock(pid, tempfile, names[i]) == 0)
174 			continue;
175 		for(j=0; j < i ;j++)
176 			unlink(names[j]);
177 		return FAIL;
178 	}
179 	return SUCCESS;
180 }
181 
182 #define LOCKPRE "LCK."
183 
184 /*
185  *	remove a lock file
186  */
187 delock(s)
188 char *s;
189 {
190 	char ln[NAMESIZE];
191 
192 	sprintf(ln, "%s/%s.%s", LOCKDIR, LOCKPRE, s);
193 	rmlock(ln);
194 }
195 
196 /*
197  *	create system lock
198  *
199  *	return codes:  SUCCESS  |  FAIL
200  */
201 mlock(sys)
202 char *sys;
203 {
204 	char lname[NAMESIZE];
205 
206 	sprintf(lname, "%s/%s.%s", LOCKDIR, LOCKPRE, sys);
207 	return ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : SUCCESS;
208 }
209 
210 /***
211  *	update 'change' time for lock files
212  *
213  *	Only update ctime, not mtime or atime.
214  *	The 'chmod' method permits cu(I)-like programs
215  *	to determine how long uucp has been on the line.
216  *	The old "change access, mod, and change time" method
217  *	can be had by defining OLDTOUCH
218  *
219  *	return code - none
220  */
221 
222 ultouch()
223 {
224 	time_t time();
225 	static time_t lasttouch = 0;
226 	register int i;
227 	struct ut {
228 		time_t actime;
229 		time_t modtime;
230 	} ut;
231 
232 	ut.actime = time(&ut.modtime);
233 	/* Do not waste time touching locking files too often */
234 	/* (But, defend against backward time changes) */
235 	if (ut.actime >= lasttouch && ut.actime < lasttouch+60)
236 		return;
237 	lasttouch = ut.actime;
238 	DEBUG(4, "ultouch\n", 0);
239 
240 	for (i = 0; i < Nlocks; i++) {
241 		if (Lockfile[i] == NULL)
242 			continue;
243 #ifdef	OLDTOUCH
244 		utime(Lockfile[i], &ut);
245 #else 	!OLDTOUCH
246 		chmod(Lockfile[i], LCKMODE);
247 #endif !OLDTOUCH
248 	/*
249 	 * set 'nologinflag' if the file /etc/nologin exists.
250 	 * This permits graceful shutdown of uucp.
251 	 */
252 	if (nologinflag == 0 && access(NOLOGIN, 0) == 0)
253 		nologinflag = 1;
254 	}
255 }
256