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