comparison zotnet/mts/lock.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children a6481689f99c
comparison
equal deleted inserted replaced
-1:000000000000 0:bce86c4163a3
1 /* lock.c - universal locking routines */
2 #ifndef lint
3 static char ident[] = "@(#)$Id$";
4 #endif
5 /* compile-time priority:
6 * MAILLOCK or LIBLOCKFILE use if defined
7 * LOCKF use if defined
8 * FCNTL use if SYS5 defined and LOCKF not defined
9 * FLOCK use if BSD42 defined and LOCKF and SYS5 not defined
10 */
11
12 #ifdef MMDFONLY
13 #define LOCKONLY
14 #endif
15
16 #include "../h/mh.h"
17 #include <stdio.h>
18 #ifndef LOCKONLY
19 #include "../h/strings.h"
20 #include "mts.h"
21 #else /* LOCKONLY */
22 #include "strings.h"
23 #ifdef MMDFONLY
24 #include "mmdfonly.h"
25 #include "mts.h"
26 #else /* not MMDFONLY */
27 #include "lockonly.h"
28 #endif /* not MMDFONLY */
29 #endif /* LOCKONLY */
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #ifdef SVR4
33 #ifndef LOCKF
34 #define LOCKF
35 #endif
36 #include <unistd.h>
37 #endif /* SVR4 */
38 #ifdef LOCKF
39 #include <sys/errno.h>
40 #include <sys/file.h>
41 #ifndef F_ULOCK
42 #ifdef UNISTD
43 #include <unistd.h>
44 #else /* UNISTD */
45 #include <sys/fcntl.h>
46 #endif /* UNISTD */
47 #endif
48 #endif /* LOCKF */
49 #if defined(_AIX) || defined(AUX)
50 #include <sys/file.h>
51 #endif
52 #if defined(__386BSD__) || defined(BSD44)
53 #include <fcntl.h>
54 #endif
55 #ifdef _AIX
56 #include <sys/time.h>
57 #include <time.h>
58 #else
59 #ifdef BSD42
60 #include <sys/time.h>
61 #else /* BSD42 */
62 #include <time.h>
63 #endif /* BSD42 */
64 #endif
65
66 #ifdef SYS5
67 #define u_short ushort
68 #define u_long ulong
69 #endif
70
71
72 #if defined(SYS5) && !defined(_AIX)
73 #define index strchr
74 #define rindex strrchr
75 #endif
76 #ifdef BSD42
77 #define FLOCK /* LOCKF will override this, if defined */
78 #endif
79
80 #ifdef __CYGWIN32__
81 #include <errno.h>
82 #endif
83 extern int errno;
84
85 #ifdef LOCKONLY
86 #ifndef MMDFONLY
87 char *lockldir = "/usr/spool/locks";
88 #endif /* not MMDFONLY */
89 #endif /* LOCKONLY */
90
91 #ifdef MAILLOCK
92 /* Both "mts.h" and <maillock.h> defines MAILDIR */
93 #undef MAILDIR
94 #include <maillock.h>
95 static int is_default_spool();
96 #undef LIBLOCKFILE
97 #else /* MAILLOCK */
98 #ifdef LIBLOCKFILE
99 #define LOCK_LIBLOCKFILE 1
100 #define LOCK_B_LKOPEN 2
101 char *lockname_from_fd();
102 #endif
103 #endif /* MAILLOCK */
104
105 static int b_lkopen(), lockit(), f_lkopen();
106 static lockname(), timerON(), timerOFF();
107
108 time_t time ();
109 char *mktemp ();
110
111 /* */
112
113 int lkopen (file, access)
114 register char *file;
115 register int access;
116 {
117 mts_init ("mts");
118 switch (lockstyle) {
119 case LOK_UNIX:
120 #ifdef MAILLOCK
121 if (is_default_spool (file))
122 return f_lkopen (file, access);
123 /* else fall */
124 #else /* MAILLOCK */
125 #if defined(FLOCK) || defined(LOCKF) || defined(FCNTL) || defined(LIBLOCKFILE)
126 return f_lkopen (file, access);
127 #endif
128 #endif /* MAILLOCK */
129
130 default:
131 return b_lkopen (file, access);
132 }
133 }
134
135 /* */
136
137 static int b_lkopen (file, access)
138 register char *file;
139 register int access;
140 {
141 register int i,
142 j;
143 time_t curtime;
144 char curlock[BUFSIZ],
145 tmplock[BUFSIZ];
146 struct stat st;
147
148 if (stat (file, &st) == NOTOK)
149 return NOTOK;
150 lockname (curlock, tmplock, file, (int) st.st_dev, (int) st.st_ino);
151
152 for (i = 0;;)
153 switch (lockit (tmplock, curlock)) {
154 case OK:
155 if ((i = open (file, access)) == NOTOK) {
156 j = errno;
157 (void) unlink (curlock);
158 errno = j;
159 }
160 #ifdef LIBLOCKFILE
161 timerON (curlock, i, LOCK_B_LKOPEN);
162 #else
163 timerON (curlock, i);
164 #endif
165 return i;
166
167 case NOTOK:
168 if (stat (curlock, &st) == NOTOK) {
169 if (i++ > 5)
170 return NOTOK;
171 sleep (5);
172 break;
173 }
174
175 i = 0;
176 (void) time (&curtime);
177 if (curtime < st.st_ctime + 60L)
178 sleep (5);
179 else
180 (void) unlink (curlock);
181 break;
182 }
183 }
184
185
186 static int lockit (tmp, file)
187 register char *tmp,
188 *file;
189 {
190 register int fd;
191
192 if ((fd = creat (tmp, 0400)) == NOTOK)
193 return NOTOK;
194 #if defined(hpux) || defined(ncr)
195 write(fd, "MH lock\n",8);
196 #endif /* hpux */
197 (void) close (fd);
198
199 fd = link (tmp, file);
200 (void) unlink (tmp);
201
202 return (fd != NOTOK ? OK : NOTOK);
203 }
204
205 /* */
206
207 static lockname (curlock, tmplock, file, dev, ino)
208 register char *curlock,
209 *tmplock,
210 *file;
211 register int dev,
212 ino;
213 {
214 register char *bp,
215 *cp;
216
217 bp = curlock;
218 if ((cp = rindex (file, '/')) == NULL || *++cp == 0)
219 cp = file;
220 if (lockldir == NULL || *lockldir == 0) {
221 if (cp != file) {
222 (void) sprintf (bp, "%.*s", cp - file, file);
223 bp += strlen (bp);
224 }
225 }
226 else {
227 (void) sprintf (bp, "%s/", lockldir);
228 bp += strlen (bp);
229 }
230
231 switch (lockstyle) {
232 case LOK_BELL:
233 default:
234 (void) sprintf (bp, "%s.lock", cp);
235 break;
236
237 case LOK_MMDF:
238 (void) sprintf (bp, "LCK%05d.%05d", dev, ino);
239 break;
240 }
241
242 if (tmplock) {
243 if ((cp = rindex (curlock, '/')) == NULL || *++cp == 0)
244 (void) strcpy (tmplock, ",LCK.XXXXXX");
245 else
246 (void) sprintf (tmplock, "%.*s,LCK.XXXXXX",
247 cp - curlock, curlock);
248 (void) unlink (mktemp (tmplock));
249 }
250 }
251
252 /* */
253
254 #if defined(BSD42) || defined(SVR4)
255 #include <sys/file.h>
256 #if defined(SUN40) || defined(SVR4)
257 #include <sys/fcntl.h>
258 #endif
259 #else
260 #ifdef FCNTL
261 #include <fcntl.h>
262 #endif
263 #endif
264
265 #ifdef MAILLOCK
266
267 static int f_lkopen (file, access)
268 register char *file;
269 register int access;
270 {
271 register int fd;
272
273 if (maillock (getusr (), 5) == L_SUCCESS) {
274 if ((fd = open (file, access | O_NDELAY)) == NOTOK)
275 return NOTOK;
276 return fd;
277 }
278
279 return NOTOK;
280 }
281
282 #else /* not MAILLOCK */
283 #ifdef LIBLOCKFILE
284 #include <lockfile.h>
285 #include <limits.h>
286
287 static int f_lkopen (file, access)
288 register char *file;
289 register int access;
290 {
291 int r, fd;
292 char mlockfile[PATH_MAX];
293
294 snprintf(mlockfile, PATH_MAX, "%s.lock", file);
295 r = lockfile_create(mlockfile, 5, 0);
296 if (r != 0)
297 return NOTOK;
298 fd = open(file, access | O_NDELAY);
299 if (fd == -1)
300 return NOTOK;
301 /* we have to set up a timer so we can touch the lockfile occasionally */
302 timerON(mlockfile, fd, LOCK_LIBLOCKFILE);
303 /* NB: it's OK to pass mlockfile as timerON immediately copies it
304 * and we then use the copy in all lockfile_foo() operations.
305 */
306 return fd;
307 }
308
309 #else /* not LIBLOCKFILE */
310 #if defined(FLOCK) || defined(LOCKF) || defined(FCNTL)
311
312 static int f_lkopen (file, access)
313 register char *file;
314 register int access;
315 {
316 register int fd,
317 i,
318 j;
319 #ifdef FCNTL
320 struct flock buf;
321 #endif /* FCNTL */
322
323 for (i = 0; i < 5; i++) {
324 #if defined(LOCKF) || defined(FCNTL)
325 j = access;
326 access &= ~O_APPEND; /* make sure we open at the beginning */
327 if ((access & 03) == O_RDONLY) {
328 /* We MUST have write permission or lockf/fcntl() won't work */
329 /* (Stupid eh?) */
330 access &= ~O_RDONLY;
331 access |= O_RDWR;
332 }
333 #endif /* LOCKF || FCNTL */
334 if ((fd = open (file, access | O_NDELAY)) == NOTOK)
335 return NOTOK;
336 #ifndef LOCKF
337 #ifndef FLOCK
338 #ifndef FCNTL
339 /* should be an error? */
340 #else /* FCNTL */
341 buf.l_type = F_WRLCK;
342 buf.l_whence = 0;
343 buf.l_start = 0;
344 buf.l_len = 0;
345 if (fcntl (fd, F_SETLK, &buf) != NOTOK)
346 return fd;
347 #endif
348 #else /* FLOCK */
349 if (flock (fd, LOCK_EX | LOCK_NB) != NOTOK)
350 return fd;
351 #endif
352 #else /* LOCKF */
353 if (lockf (fd, F_TLOCK, 0L) != NOTOK) {
354 /* see if we should be at the end */
355 if (j & O_APPEND)
356 #ifdef SVR4
357 lseek (fd, (off_t)0, SEEK_END);
358 #else
359 lseek (fd, (off_t)0, L_XTND);
360 #endif
361 return fd;
362 }
363 /* Fix errno - lockf screws it */
364 if (errno == EACCES)
365 errno = EWOULDBLOCK;
366 #endif
367 j = errno;
368 (void) close (fd);
369
370 sleep (5);
371 }
372
373 (void) close (fd);
374 errno = j;
375 return NOTOK;
376 }
377 #endif /* FLOCK || LOCKF || FCNTL */
378 #endif /* not LIBLOCKFILE */
379 #endif /* not MAILLOCK */
380
381 /* */
382
383 /* ARGSUSED */
384
385 int lkclose (fd, file)
386 register int fd;
387 register char *file;
388 {
389 char curlock[BUFSIZ];
390 struct stat st;
391 #ifdef FCNTL
392 struct flock buf;
393 #endif
394
395 if (fd == NOTOK)
396 return OK;
397 switch (lockstyle) {
398 case LOK_UNIX:
399 #ifndef MAILLOCK
400 #ifndef LIBLOCKFILE
401 #ifndef LOCKF
402 #ifndef FLOCK
403 #ifndef FCNTL
404 /* should be an error? */
405 #else /* FCNTL */
406 buf.l_type = F_UNLCK;
407 buf.l_whence = 0;
408 buf.l_start = 0;
409 buf.l_len = 0;
410 fcntl(fd, F_SETLK, &buf);
411 break;
412 #endif
413 #else /* FLOCK */
414 flock (fd, LOCK_UN);
415 break;
416 #endif
417 #else /* LOCKF */
418 lseek (fd, (off_t)0, L_SET); /* make sure we unlock the whole thing */
419 lockf (fd, F_ULOCK, 0L);
420 break;
421 #endif
422 #else /* LIBLOCKFILE */
423 {
424 char *n = lockname_from_fd(fd);
425 if (!n) /* shouldn't happen: would be program bug */
426 return NOTOK;
427 lockfile_remove(n);
428 timerOFF(fd);
429 break;
430 }
431 #endif
432 #else /* MAILLOCK */
433 if (is_default_spool (file)) {
434 mailunlock ();
435 break;
436 }
437 /* else fall */
438 #endif
439
440 default:
441 if (fstat (fd, &st) != NOTOK) {
442 lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino);
443 (void) unlink (curlock);
444 timerOFF (fd);
445 }
446 }
447
448 return (close (fd));
449 }
450
451
452 /* */
453
454 FILE *lkfopen (file, mode)
455 register char *file,
456 *mode;
457 {
458 register int fd;
459 register FILE *fp;
460
461 if ((fd = lkopen (file, strcmp (mode, "r") ? 2 : 0)) == NOTOK)
462 return NULL;
463
464 if ((fp = fdopen (fd, mode)) == NULL) {
465 (void) close (fd);
466 return NULL;
467 }
468
469 return fp;
470 }
471
472
473 /* ARGSUSED */
474
475 int lkfclose (fp, file)
476 register FILE *fp;
477 register char *file;
478 {
479 char curlock[BUFSIZ];
480 struct stat st;
481 #ifdef FCNTL
482 struct flock buf;
483 #endif
484
485 if (fp == NULL)
486 return OK;
487
488 switch (lockstyle) {
489 case LOK_UNIX:
490 #ifndef MAILLOCK
491 #ifndef LIBLOCKFILE
492 #ifndef LOCKF
493 #ifndef FLOCK
494 #ifndef FCNTL
495 /* should be an error? */
496 #else /* FCNTL */
497 buf.l_type = F_UNLCK;
498 buf.l_whence = 0;
499 buf.l_start = 0;
500 buf.l_len = 0;
501 fcntl(fileno(fp), F_SETLK, &buf);
502 break;
503 #endif
504 #else /* FLOCK */
505 flock (fileno(fp), LOCK_UN);
506 break;
507 #endif
508 #else /* LOCKF */
509 fseek (fp, 0L, 0); /* make sure we unlock the whole thing */
510 lockf (fileno(fp), F_ULOCK, 0L);
511 break;
512 #endif
513 #else /* LIBLOCKFILE */
514 {
515 char *n = lockname_from_fd(fileno(fp));
516 if (!n) /* shouldn't happen */
517 return NOTOK;
518 lockfile_remove(n);
519 timerOFF(fileno(fp));
520 break;
521 }
522 #endif
523 #else /* MAILLOCK */
524 if (is_default_spool (file)) {
525 mailunlock ();
526 break;
527 }
528 /* else fall */
529 #endif
530
531 default:
532 if (fstat (fileno (fp), &st) != NOTOK) {
533 lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino);
534 (void) unlink (curlock);
535 #ifdef LIBLOCKFILE
536 /* shouldn't we timerOFF(fileno(fp))? We do in lkclose() -- PMM */
537 #else
538 timerOFF (fileno (fp));
539 #endif
540 }
541 }
542
543 return (fclose (fp));
544 }
545
546 /* */
547
548 #include <signal.h>
549
550 #define NSECS ((unsigned) 20)
551
552
553 struct lock {
554 #ifdef LIBLOCKFILE
555 int l_locktype;
556 #endif
557 int l_fd;
558 char *l_lock;
559 struct lock *l_next;
560 };
561 #define NULLP ((struct lock *) 0)
562
563 static struct lock *l_top = NULLP;
564
565 #ifdef MAILLOCK
566 static int is_default_spool (file)
567 register char *file;
568 {
569 static char *default_spool = NULLCP;
570
571 if (! default_spool)
572 default_spool = concat (MAILDIR, getusr (), NULLCP);
573 return strcmp(file, default_spool) == 0;
574 }
575
576 #else /* MAILLOCK */
577 #ifdef LIBLOCKFILE
578 /* simple routine to allow us to get the filename given an fd.
579 * Returns NULL if the fd isn't valid.
580 */
581 char *lockname_from_fd(fd)
582 int fd;
583 {
584 struct lock *pp;
585
586 for (pp = l_top; pp; pp = pp -> l_next)
587 if (pp->l_fd == fd)
588 return pp->l_lock;
589
590 return NULL;
591 }
592 #endif /* LIBLOCKFILE */
593 #endif /* MAILLOCK */
594
595 /* ARGSUSED */
596
597 static TYPESIG alrmser (sig)
598 int sig;
599 {
600 register int j;
601 register char *cp;
602 register struct lock *lp;
603
604 #ifndef BSD42
605 (void) signal (SIGALRM, alrmser);
606 #endif /* BSD42 */
607
608 for (lp = l_top; lp; lp = lp -> l_next)
609 #ifdef LIBLOCKFILE
610 if (lp->l_locktype == LOCK_LIBLOCKFILE)
611 lockfile_touch(lp->l_lock);
612 else
613 #endif
614 if (*(cp = lp -> l_lock) && (j = creat (cp, 0400)) != NOTOK)
615 (void) close (j);
616
617 (void) alarm (NSECS);
618 }
619
620 /* */
621
622 #ifdef LIBLOCKFILE
623 static timerON (lock, fd, ltype)
624 int ltype;
625 #else
626 static timerON (lock, fd)
627 #endif
628 char *lock;
629 int fd;
630 {
631 register struct lock *lp;
632
633 if ((lp = (struct lock *) malloc ((unsigned) (sizeof *lp))) == NULLP)
634 return; /* XXX */
635
636 lp -> l_fd = fd;
637 #ifdef LIBLOCKFILE
638 lp -> l_locktype = ltype;
639 #endif
640 if ((lp -> l_lock = malloc ((unsigned) (strlen (lock) + 1))) == NULLCP) {
641 free ((char *) lp);
642 return; /* XXX */
643 }
644 (void) strcpy (lp -> l_lock, lock);
645 lp -> l_next = NULLP;
646
647 if (l_top)
648 lp -> l_next = l_top;
649 else {
650 (void) signal (SIGALRM, alrmser);/* perhaps SIGT{STP,TIN,TOU} */
651 (void) alarm (NSECS);
652 }
653 l_top = lp;
654 }
655
656
657 static timerOFF (fd)
658 int fd;
659 {
660 register struct lock *pp,
661 *lp;
662
663 (void) alarm (0);
664
665 if (l_top) {
666 for (pp = lp = l_top; lp; pp = lp, lp = lp -> l_next)
667 if (lp -> l_fd == fd)
668 break;
669 if (lp) {
670 if (lp == l_top)
671 l_top = lp -> l_next;
672 else
673 pp -> l_next = lp -> l_next;
674
675 free (lp -> l_lock);
676 free ((char *) lp);
677 }
678 }
679
680 if (l_top)
681 (void) alarm (NSECS);
682 }