Mercurial > hg > Applications > mh
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 } |