]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/zotnet/mts/lock.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / zotnet / mts / lock.c
1 /* lock.c - universal locking routines */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: lock.c,v 2.19 1993/08/25 17:33:09 jromine Exp $";
4 #endif
5 /* compile-time priority:
6 * LOCKF use if defined
7 * FCNTL use if SYS5 defined and LOCKF not defined
8 * FLOCK use if BSD42 defined and LOCKF and SYS5 not defined
9 */
10
11 #ifdef MMDFONLY
12 #define LOCKONLY
13 #endif
14
15 #include "../h/mh.h"
16 #include <stdio.h>
17 #ifndef LOCKONLY
18 #include "../h/strings.h"
19 #include "mts.h"
20 #else /* LOCKONLY */
21 #include "strings.h"
22 #ifdef MMDFONLY
23 #include "mmdfonly.h"
24 #include "mts.h"
25 #else /* not MMDFONLY */
26 #include "lockonly.h"
27 #endif /* not MMDFONLY */
28 #endif /* LOCKONLY */
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #ifdef SVR4
32 #define LOCKF
33 #include <unistd.h>
34 #endif
35 #ifdef LOCKF
36 #include <sys/errno.h>
37 #include <sys/file.h>
38 #ifndef F_ULOCK
39 #ifdef UNISTD
40 #include <unistd.h>
41 #else /* UNISTD */
42 #include <sys/fcntl.h>
43 #endif /* UNISTD */
44 #endif
45 #endif /* LOCKF */
46 #if defined(_AIX) || defined(AUX)
47 #include <sys/file.h>
48 #endif
49
50 #ifdef SYS5
51 #define u_short ushort
52 #define u_long ulong
53 #endif
54
55
56 #if defined(SYS5) && !defined(_AIX)
57 #define index strchr
58 #define rindex strrchr
59 #endif
60 #ifdef BSD42
61 #define FLOCK /* LOCKF will override this, if defined */
62 #endif
63
64 extern int errno;
65
66 #ifdef LOCKONLY
67 #ifndef MMDFONLY
68 char *lockldir = "/usr/spool/locks";
69 #endif /* not MMDFONLY */
70 #endif /* LOCKONLY */
71
72 static int b_lkopen(), lockit(), f_lkopen();
73 static lockname(), timerON(), timerOFF();
74
75 long time ();
76
77 /* \f */
78
79 int lkopen (file, access)
80 register char *file;
81 register int access;
82 {
83 mts_init ("mts");
84 switch (lockstyle) {
85 case LOK_UNIX:
86 #if defined (FLOCK) || defined(LOCKF) || defined(FCNTL)
87 return f_lkopen (file, access);
88 #endif
89
90 default:
91 return b_lkopen (file, access);
92 }
93 }
94
95 /* \f */
96
97 static int b_lkopen (file, access)
98 register char *file;
99 register int access;
100 {
101 register int i,
102 j;
103 long curtime;
104 char curlock[BUFSIZ],
105 tmplock[BUFSIZ];
106 struct stat st;
107
108 if (stat (file, &st) == NOTOK)
109 return NOTOK;
110 lockname (curlock, tmplock, file, (int) st.st_dev, (int) st.st_ino);
111
112 for (i = 0;;)
113 switch (lockit (tmplock, curlock)) {
114 case OK:
115 if ((i = open (file, access)) == NOTOK) {
116 j = errno;
117 (void) unlink (curlock);
118 errno = j;
119 }
120 timerON (curlock, i);
121 return i;
122
123 case NOTOK:
124 if (stat (curlock, &st) == NOTOK) {
125 if (i++ > 5)
126 return NOTOK;
127 sleep (5);
128 break;
129 }
130
131 i = 0;
132 (void) time (&curtime);
133 if (curtime < st.st_ctime + 60L)
134 sleep (5);
135 else
136 (void) unlink (curlock);
137 break;
138 }
139 }
140
141
142 static int lockit (tmp, file)
143 register char *tmp,
144 *file;
145 {
146 register int fd;
147
148 if ((fd = creat (tmp, 0400)) == NOTOK)
149 return NOTOK;
150 #if defined(hpux) || defined(ncr)
151 write(fd, "MH lock\n",8);
152 #endif /* hpux */
153 (void) close (fd);
154
155 fd = link (tmp, file);
156 (void) unlink (tmp);
157
158 return (fd != NOTOK ? OK : NOTOK);
159 }
160
161 /* \f */
162
163 static lockname (curlock, tmplock, file, dev, ino)
164 register char *curlock,
165 *tmplock,
166 *file;
167 register int dev,
168 ino;
169 {
170 register char *bp,
171 *cp;
172
173 bp = curlock;
174 if ((cp = rindex (file, '/')) == NULL || *++cp == 0)
175 cp = file;
176 if (lockldir == NULL || *lockldir == 0) {
177 if (cp != file) {
178 (void) sprintf (bp, "%.*s", cp - file, file);
179 bp += strlen (bp);
180 }
181 }
182 else {
183 (void) sprintf (bp, "%s/", lockldir);
184 bp += strlen (bp);
185 }
186
187 switch (lockstyle) {
188 case LOK_BELL:
189 default:
190 (void) sprintf (bp, "%s.lock", cp);
191 break;
192
193 case LOK_MMDF:
194 (void) sprintf (bp, "LCK%05d.%05d", dev, ino);
195 break;
196 }
197
198 if (tmplock) {
199 if ((cp = rindex (curlock, '/')) == NULL || *++cp == 0)
200 (void) strcpy (tmplock, ",LCK.XXXXXX");
201 else
202 (void) sprintf (tmplock, "%.*s,LCK.XXXXXX",
203 cp - curlock, curlock);
204 (void) unlink (mktemp (tmplock));
205 }
206 }
207
208 /* \f */
209
210 #if defined(FLOCK) || defined(LOCKF) || defined(FCNTL)
211
212 #if defined(BSD42) || defined(SVR4)
213 #include <sys/file.h>
214 #if defined(SUN40) || defined(SVR4)
215 #include <sys/fcntl.h>
216 #endif
217 #else
218 #ifdef FCNTL
219 #include <fcntl.h>
220 #endif
221 #endif
222
223 static int f_lkopen (file, access)
224 register char *file;
225 register int access;
226 {
227 register int fd,
228 i,
229 j;
230 #ifdef FCNTL
231 struct flock buf;
232 #endif /* FCNTL */
233
234 for (i = 0; i < 5; i++) {
235 #if defined(LOCKF) || defined(FCNTL)
236 j = access;
237 access &= ~O_APPEND; /* make sure we open at the beginning */
238 if ((access & 03) == O_RDONLY) {
239 /* We MUST have write permission or lockf/fcntl() won't work */
240 /* (Stupid eh?) */
241 access &= ~O_RDONLY;
242 access |= O_RDWR;
243 }
244 #endif /* LOCKF || FCNTL */
245 if ((fd = open (file, access | O_NDELAY)) == NOTOK)
246 return NOTOK;
247 #ifndef LOCKF
248 #ifndef FLOCK
249 #ifndef FCNTL
250 /* should be an error? */
251 #else /* FCNTL */
252 buf.l_type = F_WRLCK;
253 buf.l_whence = 0;
254 buf.l_start = 0;
255 buf.l_len = 0;
256 if (fcntl (fd, F_SETLK, &buf) != NOTOK)
257 return fd;
258 #endif
259 #else /* FLOCK */
260 if (flock (fd, LOCK_EX | LOCK_NB) != NOTOK)
261 return fd;
262 #endif
263 #else /* LOCKF */
264 if (lockf (fd, F_TLOCK, 0L) != NOTOK) {
265 /* see if we should be at the end */
266 if (j & O_APPEND)
267 #ifdef SVR4
268 lseek (fd, (off_t)0, SEEK_END);
269 #else
270 lseek (fd, (off_t)0, L_XTND);
271 #endif
272 return fd;
273 }
274 /* Fix errno - lockf screws it */
275 if (errno == EACCES)
276 errno = EWOULDBLOCK;
277 #endif
278 j = errno;
279 (void) close (fd);
280
281 sleep (5);
282 }
283
284 (void) close (fd);
285 errno = j;
286 return NOTOK;
287 }
288 #endif /* FLOCK || LOCKF || FCNTL */
289
290 /* \f */
291
292 /* ARGSUSED */
293
294 int lkclose (fd, file)
295 register int fd;
296 register char *file;
297 {
298 char curlock[BUFSIZ];
299 struct stat st;
300 #ifdef FCNTL
301 struct flock buf;
302 #endif
303
304 if (fd == NOTOK)
305 return OK;
306 switch (lockstyle) {
307 case LOK_UNIX:
308 #ifndef LOCKF
309 #ifndef FLOCK
310 #ifndef FCNTL
311 /* should be an error? */
312 #else /* FCNTL */
313 buf.l_type = F_UNLCK;
314 buf.l_whence = 0;
315 buf.l_start = 0;
316 buf.l_len = 0;
317 fcntl(fd, F_SETLK, &buf);
318 break;
319 #endif
320 #else /* FLOCK */
321 flock (fd, LOCK_UN);
322 break;
323 #endif
324 #else /* LOCKF */
325 lseek (fd, (off_t)0, L_SET); /* make sure we unlock the whole thing */
326 lockf (fd, F_ULOCK, 0L);
327 break;
328 #endif
329
330 default:
331 if (fstat (fd, &st) != NOTOK) {
332 lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino);
333 (void) unlink (curlock);
334 timerOFF (fd);
335 }
336 }
337
338 return (close (fd));
339 }
340
341
342 /* \f */
343
344 FILE *lkfopen (file, mode)
345 register char *file,
346 *mode;
347 {
348 register int fd;
349 register FILE *fp;
350
351 if ((fd = lkopen (file, strcmp (mode, "r") ? 2 : 0)) == NOTOK)
352 return NULL;
353
354 if ((fp = fdopen (fd, mode)) == NULL) {
355 (void) close (fd);
356 return NULL;
357 }
358
359 return fp;
360 }
361
362
363 /* ARGSUSED */
364
365 int lkfclose (fp, file)
366 register FILE *fp;
367 register char *file;
368 {
369 char curlock[BUFSIZ];
370 struct stat st;
371 #ifdef FCNTL
372 struct flock buf;
373 #endif
374
375 if (fp == NULL)
376 return OK;
377
378 switch (lockstyle) {
379 case LOK_UNIX:
380 #ifndef LOCKF
381 #ifndef FLOCK
382 #ifndef FCNTL
383 /* should be an error? */
384 #else /* FCNTL */
385 buf.l_type = F_UNLCK;
386 buf.l_whence = 0;
387 buf.l_start = 0;
388 buf.l_len = 0;
389 fcntl(fileno(fp), F_SETLK, &buf);
390 break;
391 #endif
392 #else /* FLOCK */
393 flock (fileno(fp), LOCK_UN);
394 break;
395 #endif
396 #else /* LOCKF */
397 fseek (fp, 0L, 0); /* make sure we unlock the whole thing */
398 lockf (fileno(fp), F_ULOCK, 0L);
399 break;
400 #endif
401
402 default:
403 if (fstat (fileno (fp), &st) != NOTOK) {
404 lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino);
405 (void) unlink (curlock);
406 }
407 }
408
409 return (fclose (fp));
410 }
411
412 /* \f */
413
414 #include <signal.h>
415
416 #define NSECS ((unsigned) 20)
417
418
419 struct lock {
420 int l_fd;
421 char *l_lock;
422 struct lock *l_next;
423 };
424 #define NULLP ((struct lock *) 0)
425
426 static struct lock *l_top = NULLP;
427
428
429 /* ARGSUSED */
430
431 static TYPESIG alrmser (sig)
432 int sig;
433 {
434 register int j;
435 register char *cp;
436 register struct lock *lp;
437
438 #ifndef BSD42
439 (void) signal (SIGALRM, alrmser);
440 #endif /* BSD42 */
441
442 for (lp = l_top; lp; lp = lp -> l_next)
443 if (*(cp = lp -> l_lock) && (j = creat (cp, 0400)) != NOTOK)
444 (void) close (j);
445
446 (void) alarm (NSECS);
447 }
448
449 /* \f */
450
451 static timerON (lock, fd)
452 char *lock;
453 int fd;
454 {
455 register struct lock *lp;
456
457 if ((lp = (struct lock *) malloc ((unsigned) (sizeof *lp))) == NULLP)
458 return; /* XXX */
459
460 lp -> l_fd = fd;
461 if ((lp -> l_lock = malloc ((unsigned) (strlen (lock) + 1))) == NULLCP) {
462 free ((char *) lp);
463 return; /* XXX */
464 }
465 (void) strcpy (lp -> l_lock, lock);
466 lp -> l_next = NULLP;
467
468 if (l_top)
469 lp -> l_next = l_top -> l_next;
470 else {
471 (void) signal (SIGALRM, alrmser);/* perhaps SIGT{STP,TIN,TOU} */
472 (void) alarm (NSECS);
473 }
474 l_top = lp;
475 }
476
477
478 static timerOFF (fd)
479 int fd;
480 {
481 register struct lock *pp,
482 *lp;
483
484 (void) alarm (0);
485
486 if (l_top) {
487 for (pp = lp = l_top; lp; pp = lp, lp = lp -> l_next)
488 if (lp -> l_fd == fd)
489 break;
490 if (lp) {
491 if (lp == l_top)
492 l_top = lp -> l_next;
493 else
494 pp -> l_next = lp -> l_next;
495
496 free (lp -> l_lock);
497 free ((char *) lp);
498 }
499 }
500
501 if (l_top)
502 (void) alarm (NSECS);
503 }