Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / support / bboards / mmdfII / bboards / lock.c
1 /* lock.c - universal locking routines */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: lock.c,v 2.2 1990/04/05 15:32:41 sources Exp shettich $";
4 #endif  lint
5
6 #ifdef  MMDFONLY
7 #define LOCKONLY
8 #endif  MMDFONLY
9
10 #include <stdio.h>
11 #ifndef LOCKONLY
12 #include "../h/strings.h"
13 #include "mts.h"
14 #else   LOCKONLY
15 #include "strings.h"
16 #ifdef  MMDFONLY
17 #include "mmdfonly.h"
18 #include "mts.h"
19 #else   not MMDFONLY
20 #include "lockonly.h"
21 #endif  not MMDFONLY
22 #endif  LOCKONLY
23 #include <sys/types.h>
24 #include <sys/stat.h>
25
26
27 #define NOTOK   (-1)
28 #define OK      0
29
30 #define NULLCP  ((char *) 0)
31
32 #ifdef  SYS5
33 #define index   strchr
34 #define rindex  strrchr
35 #endif  SYS5
36
37
38 extern int  errno;
39
40 #ifdef  LOCKONLY
41 #ifndef MMDFONLY
42 char   *lockldir = "/usr/spool/locks";
43 #endif  not MMDFONLY
44 #endif  LOCKONLY
45
46
47 long    time ();
48
49 /* \f */
50
51 int     lkopen (file, access)
52 register char   *file;
53 register int     access;
54 {
55     mts_init ("mts");
56     switch (lockstyle) {
57         case LOK_UNIX:
58 #ifdef  BSD42
59             return f_lkopen (file, access);
60 #endif  BSD42
61
62         default:
63             return b_lkopen (file, access);
64         }
65 }
66
67 /* \f */
68
69 static int  b_lkopen (file, access)
70 register char   *file;
71 register int     access;
72 {
73     register int    i,
74                     j;
75     long    curtime;
76     char    curlock[BUFSIZ],
77             tmplock[BUFSIZ];
78     struct stat st;
79
80     if (stat (file, &st) == NOTOK)
81         return NOTOK;
82     lockname (curlock, tmplock, file, (int) st.st_dev, (int) st.st_ino);
83
84     for (i = 0;;)
85         switch (lockit (tmplock, curlock)) {
86             case OK: 
87                 if ((i = open (file, access)) == NOTOK) {
88                     j = errno;
89                     (void) unlink (curlock);
90                     errno = j;
91                 }
92                 timerON (curlock, i);
93                 return i;
94
95             case NOTOK: 
96                 if (stat (curlock, &st) == NOTOK) {
97                     if (i++ > 5)
98                         return NOTOK;
99                     sleep (5);
100                     break;
101                 }
102
103                 i = 0;
104                 (void) time (&curtime);
105                 if (curtime < st.st_ctime + 60L)
106                     sleep (5);
107                 else
108                     (void) unlink (curlock);
109                 break;
110         }
111 }
112
113
114 static int  lockit (tmp, file)
115 register char   *tmp,
116                 *file;
117 {
118     register int    fd;
119
120     if ((fd = creat (tmp, 0400)) == NOTOK)
121         return NOTOK;
122     (void) close (fd);
123
124     fd = link (tmp, file);
125     (void) unlink (tmp);
126
127     return (fd != NOTOK ? OK : NOTOK);
128 }
129
130 /* \f */
131
132 static  lockname (curlock, tmplock, file, dev, ino)
133 register char   *curlock,
134                 *tmplock,
135                 *file;
136 register int     dev,
137                  ino;
138 {
139     register char  *bp,
140                    *cp;
141
142     bp = curlock;
143     if ((cp = rindex (file, '/')) == NULL || *++cp == NULL)
144         cp = file;
145     if (lockldir == NULL || *lockldir == NULL) {
146         if (cp != file) {
147             (void) sprintf (bp, "%.*s", cp - file, file);
148             bp += strlen (bp);
149         }
150     }
151     else {
152         (void) sprintf (bp, "%s/", lockldir);
153         bp += strlen (bp);
154     }
155
156     switch (lockstyle) {
157         case LOK_BELL: 
158         default: 
159             (void) sprintf (bp, "%s.lock", cp);
160             break;
161
162         case LOK_MMDF: 
163             (void) sprintf (bp, "LCK%05d.%05d", dev, ino);
164             break;
165     }
166
167     if (tmplock) {
168         if ((cp = rindex (curlock, '/')) == NULL || *++cp == NULL)
169             (void) strcpy (tmplock, ",LCK.XXXXXX");
170         else
171             (void) sprintf (tmplock, "%.*s,LCK.XXXXXX",
172                 cp - curlock, curlock);
173         (void) unlink (mktemp (tmplock));
174     }
175 }
176
177 /* \f */
178
179 #ifdef  BSD42
180
181 #include <sys/file.h>
182 #ifdef  SUN40
183 #include <sys/fcntl.h>
184 #endif  SUN40
185
186 static int  f_lkopen (file, access)
187 register char   *file;
188 register int     access;
189 {
190     register int    fd,
191                     i,
192                     j;
193
194     for (i = 0; i < 5; i++) {
195 #ifdef  LOCKF
196         j = access;
197         access &= ! O_APPEND;   /* make sure we open at the beginning */
198 #endif  LOCKF
199         if ((fd = open (file, access | O_NDELAY)) == NOTOK)
200             return NOTOK;
201 #ifndef LOCKF
202         if (flock (fd, LOCK_EX | LOCK_NB) != NOTOK)
203             return fd;
204 #else   LOCKF
205         if (lockf (fd, F_TLOCK, 0L) != NOTOK) {
206             /* see if we should be at the end */
207             if (j & O_APPEND) lseek (fd, 0L, L_XTND);
208             return fd;
209         }
210         /* Fix errno - lockf screws it */
211         if (errno == EACCES) errno = EWOULDBLOCK;
212 #endif  LOCKF
213         j = errno;
214         (void) close (fd);
215
216         sleep (5);
217     }
218
219     (void) close (fd);
220     errno = j;
221     return NOTOK;
222 }
223 #endif  BSD42
224
225 /* \f */
226
227 /* ARGSUSED */
228
229 int     lkclose (fd, file)
230 register int     fd;
231 register char   *file;
232 {
233     char    curlock[BUFSIZ];
234     struct stat st;
235
236     if (fd == NOTOK)
237         return OK;
238     switch (lockstyle) {
239         case LOK_UNIX: 
240 #ifdef  BSD42
241 #ifndef LOCKF
242             flock (fd, LOCK_UN);
243 #else   LOCKF
244             lseek (fd, 0L, L_SET); /* make sure we unlock the whole thing */
245             lockf (fd, F_ULOCK, 0L);
246 #endif  LOCKF
247             break;
248 #endif  BSD42
249
250         default: 
251             if (fstat (fd, &st) != NOTOK) {
252                 lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino);
253                 (void) unlink (curlock);
254                 timerOFF (fd);
255             }
256     }
257
258     return (close (fd));
259 }
260
261
262 /* \f */
263
264 FILE    *lkfopen (file, mode)
265 register char   *file,
266                 *mode;
267 {
268     register int    fd;
269     register FILE  *fp;
270
271     if ((fd = lkopen (file, strcmp (mode, "r") ? 2 : 0)) == NOTOK)
272         return NULL;
273
274     if ((fp = fdopen (fd, mode)) == NULL) {
275         (void) close (fd);
276         return NULL;
277     }
278
279     return fp;
280 }
281
282
283 /* ARGSUSED */
284
285 int     lkfclose (fp, file)
286 register FILE   *fp;
287 register char   *file;
288 {
289     char    curlock[BUFSIZ];
290     struct stat st;
291
292     if (fp == NULL)
293         return OK;
294
295     switch (lockstyle) {
296         case LOK_UNIX: 
297 #ifdef  BSD42
298 #ifndef LOCKF
299             flock (fileno(fp), LOCK_UN);
300 #else   LOCKF
301             fseek (fp, 0L, 0); /* make sure we unlock the whole thing */
302             lockf (fileno(fp), F_ULOCK, 0L);
303 #endif  LOCKF
304             break;
305 #endif  BSD42
306
307         default: 
308             if (fstat (fileno (fp), &st) != NOTOK) {
309                 lockname (curlock, NULLCP, file, (int) st.st_dev, (int) st.st_ino);
310                 (void) unlink (curlock);
311             }
312     }
313
314     return (fclose (fp));
315 }
316
317 /* \f */
318
319 #include <signal.h>
320
321 #define NSECS   ((unsigned) 20)
322
323
324 struct lock {
325     int          l_fd;
326     char        *l_lock;
327     struct lock *l_next;
328 };
329 #define NULLP   ((struct lock *) 0)
330
331 static struct lock *l_top = NULLP;
332
333
334 /* ARGSUSED */
335
336 static alrmser (sig)
337 int     sig;
338 {
339     register int    j;
340     register char  *cp;
341     register struct lock   *lp;
342
343 #ifndef BSD42
344     (void) signal (SIGALRM, alrmser);
345 #endif  BSD42
346
347     for (lp = l_top; lp; lp = lp -> l_next)
348         if (*(cp = lp -> l_lock) && (j = creat (cp, 0400)) != NOTOK)
349             (void) close (j);
350
351     (void) alarm (NSECS);
352 }
353
354 /* \f */
355
356 static timerON (lock, fd)
357 char   *lock;
358 int     fd;
359 {
360     register struct lock   *lp;
361
362     if ((lp = (struct lock *) malloc ((unsigned) (sizeof *lp))) == NULLP)
363         return;                 /* XXX */
364
365     lp -> l_fd = fd;
366     if ((lp -> l_lock = malloc ((unsigned) (strlen (lock) + 1))) == NULLCP) {
367         free ((char *) lp);
368         return;                 /* XXX */
369     }
370     (void) strcpy (lp -> l_lock, lock);
371     lp -> l_next = NULLP;
372
373     if (l_top)
374         lp -> l_next = l_top -> l_next;
375     else {
376         (void) signal (SIGALRM, alrmser);/* perhaps SIGT{STP,TIN,TOU} */
377         (void) alarm (NSECS);
378     }
379     l_top = lp;
380 }
381
382
383 static timerOFF (fd)
384 int     fd;
385 {
386     register struct lock   *pp,
387                            *lp;
388
389     (void) alarm (0);
390
391     if (l_top) {
392         for (pp = lp = l_top; lp; pp = lp, lp = lp -> l_next)
393             if (lp -> l_fd == fd)
394                 break;
395         if (lp) {
396             if (lp == l_top)
397                 l_top = lp -> l_next;
398             else
399                 pp -> l_next = lp -> l_next;
400
401             free (lp -> l_lock);
402             free ((char *) lp);
403         }
404     }
405
406     if (l_top)
407         (void) alarm (NSECS);
408 }