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 */
ulockf(hfile,atime)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 */
rmlock(name)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 */
onelock(pid,tempfile,name)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
ultouch()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