xref: /original-bsd/usr.bin/uucp/libuu/ulockf.c (revision 71eaf591)
1 /*-
2  * Copyright (c) 1985, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ulockf.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #include "uucp.h"
13 #include <sys/stat.h>
14 #include <errno.h>
15 
16 #define	LCKMODE	0444	/* File mode for lock files */
17 #define MAXLOCKS 16	/* Maximum number of lock files */
18 
19 char *Lockfile[MAXLOCKS];
20 char *LockDirectory = LOCKDIR;
21 int Nlocks = 0;
22 extern int errno;
23 
24 /*LINTLIBRARY*/
25 
26 /*
27  *	This routine will attempt to create a lock file (file).
28  *	It makes sure that the lock file is valid if it already exists.
29  *
30  *	return codes:  SUCCESS  |  FAIL
31  */
32 ulockf(hfile, atime)
33 char *hfile;
34 time_t atime;
35 {
36 	register char *p;
37 	register int i;
38 	static char tempfile[NAMESIZE];
39 	char file[NAMESIZE];
40 	static int pid = -1;
41 
42 	if (pid < 0) {
43 		pid = getpid();
44 		sprintf(tempfile, "%s/LTMP.%d", LockDirectory, pid);
45 	}
46 	sprintf(file, "%s/LCK..%s", LockDirectory, hfile);
47 	i = 0;
48 	while (onelock(pid, tempfile, file) == -1) { /* lock file exists */
49 #if !defined(BSD4_2) && !defined(USG)
50 		struct stat stbuf;
51 		time_t ptime;
52 		/* get status to check age of the lock file */
53 		if (stat(file, &stbuf) == 0) {
54 			(void) time(&ptime);
55 			if ((ptime - stbuf.st_ctime) < atime)
56 				return FAIL; /* file not old enough to delete */
57 		}
58 #else	BSD4_2 || USG
59 		register int fd;
60 		fd = open(file, 0);
61 		if (fd >= 0) {
62 			int upid, ret;
63 			ret = read(fd, &upid, sizeof upid);
64 			close(fd);
65 			if (ret == sizeof upid && (kill(upid, 0) == 0
66 				|| errno != ESRCH))
67 				return FAIL; /* process is still running */
68 		}
69 #endif BSD4_2 || USG
70 		syslog(LOG_WARNING, "%s: dead lock %s", Rmtname, file);
71 		logent(file, "DEAD LOCK");
72 		(void) unlink(file);
73 		sleep(5);	/* avoid a possible race */
74 		if (i++ >= 5) {
75 			syslog(LOG_ERR, "%s: can't get lockfile %s: %m",
76 				Rmtname, tempfile);
77 			cleanup(FAIL);
78 		}
79 	}
80 
81 	for (i = 0; i < Nlocks; i++) {
82 		if (Lockfile[i] == NULL)
83 			break;
84 	}
85 	if (i >= MAXLOCKS) {
86 		syslog(LOG_ERR, "Too many locks");
87 		cleanup(FAIL);
88 	}
89 	if (i >= Nlocks)
90 		i = Nlocks++;
91 	p = malloc((unsigned)(strlen(file)+1));
92 	if (p == NULL) {
93 		syslog(LOG_ERR, "malloc failed: %m");
94 		cleanup(FAIL);
95 	}
96 	strcpy(p, file);
97 	Lockfile[i] = p;
98 
99 	return SUCCESS;
100 }
101 
102 /*
103  *	remove all lock files in list or name
104  */
105 rmlock(name)
106 register char *name;
107 {
108 	register int i;
109 	char file[MAXFULLNAME];
110 
111 	if (name != NULL) {
112 		sprintf(file, "%s/LCK..%s", LockDirectory, name);
113 		name = file;
114 	}
115 	for (i = 0; i < Nlocks; i++) {
116 		if (Lockfile[i] == NULL)
117 			continue;
118 		if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
119 			unlink(Lockfile[i]);
120 			free(Lockfile[i]);
121 			Lockfile[i] = NULL;
122 		}
123 	}
124 }
125 
126 /*
127  *	makes lock a name on behalf of pid. Tempfile must be in the same
128  *	file system as name.
129  */
130 onelock(pid, tempfile, name)
131 int pid;
132 char *tempfile, *name;
133 {
134 	register int fd, ret;
135 #ifdef VMS
136 	fd = creat(name, LCKMODE, "1version");
137 #else !VMS
138 	fd = creat(tempfile, LCKMODE);
139 #endif !VMS
140 	if (fd < 0) {
141 		DEBUG(1,"Can't creat temp file %s ", tempfile);
142 		DEBUG(1,"-- errno %d", errno);
143 		return FAIL;
144 	}
145 	ret = write(fd, (char *)&pid, sizeof(int));
146 	(void) close(fd);
147 
148 	if (ret != sizeof(int)) {
149 		DEBUG(1,"Temp file write failed -- errno %d\n", errno);
150 #ifdef VMS
151 		(void) unlink(name);
152 #else !VMS
153 		(void) unlink(tempfile);
154 #endif !VMS
155 		return FAIL;
156 	}
157 #ifndef VMS
158 	if (link(tempfile, name) < 0) {
159 		(void) unlink(tempfile);
160 		return FAIL;
161 	}
162 	unlink(tempfile);
163 #endif	!VMS
164 	return SUCCESS;
165 }
166 
167 #if !defined(BSD4_2) && !defined(USG)
168 /*
169  *	update 'change' time for lock files
170  *
171  *	Only update ctime, not mtime or atime.
172  *	The 'chmod' method permits cu(I)-like programs
173  *	to determine how long uucp has been on the line.
174  *	The old "change access, mod, and change time" method
175  *	can be had by defining OLDTOUCH
176  *
177  *	return code - none
178  */
179 
180 ultouch()
181 {
182 	static time_t lasttouch = 0;
183 	register int i;
184 	struct ut {
185 		time_t actime;
186 		time_t modtime;
187 	} ut;
188 
189 #ifdef USG
190 	time(&Now.time);
191 	t1.millitm = 0;
192 #else !USG
193 	ftime(&Now);
194 #endif !USG
195 	ut.actime = ut.modtime = Now.time;
196 	/* Do not waste time touching locking files too often */
197 	/* (But, defend against backward time changes) */
198 	if (ut.actime >= lasttouch && ut.actime < lasttouch+60)
199 		return;
200 	lasttouch = ut.actime;
201 	DEBUG(4, "ultouch\n", 0);
202 
203 	for (i = 0; i < Nlocks; i++) {
204 		if (Lockfile[i] == NULL)
205 			continue;
206 #ifdef	OLDTOUCH
207 		utime(Lockfile[i], &ut);
208 #else 	!OLDTOUCH
209 		chmod(Lockfile[i], LCKMODE);
210 #endif !OLDTOUCH
211 	}
212 }
213 #endif !BSD4_2 && ! USG
214