]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/libsmutil/t-lockfile.c
sqlite3: Vendor import of sqlite3 3.41.0
[FreeBSD/FreeBSD.git] / contrib / sendmail / libsmutil / t-lockfile.c
1 /*
2  * Copyright (c) 2005 Proofpoint, Inc. and its suppliers.
3  *      All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10
11 #include <sm/gen.h>
12 SM_IDSTR(id, "@(#)$Id: t-lockfile.c,v 1.2 2013-11-22 20:51:50 ca Exp $")
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <sendmail.h>
16
17 #define IOBUFSZ 64
18 char iobuf[IOBUFSZ];
19 #define FIRSTLINE       "first line\n"
20 #define LASTLINE        "last line\n"
21 static int noio, chk;
22 static pid_t pid;
23
24 int
25 openfile(owner, filename, flags)
26         int owner;
27         char *filename;
28         int flags;
29 {
30         int fd;
31
32         if (owner)
33                 flags |= O_CREAT;
34         fd = open(filename, flags, 0640);
35         if (fd >= 0)
36                 return fd;
37         fprintf(stderr, "%d: %ld: owner=%d, open(%s) failed\n",
38                 (int) pid, (long) time(NULL), owner, filename);
39         return 1;
40 }
41
42 int
43 wrbuf(fd)
44         int fd;
45 {
46         int r;
47
48         if (noio)
49                 return 0;
50         r = write(fd, iobuf, sizeof(iobuf));
51         if (sizeof(iobuf) == r)
52                 return 0;
53         fprintf(stderr, "%d: %ld: owner=1, write(%s)=fail\n",
54                 (int) pid, (long) time(NULL), iobuf);
55         return 1;
56 }
57
58 int
59 rdbuf(fd, xbuf)
60         int fd;
61         const char *xbuf;
62 {
63         int r;
64
65         if (noio)
66                 return 0;
67         r = read(fd, iobuf, sizeof(iobuf));
68         if (sizeof(iobuf) != r)
69         {
70                 fprintf(stderr, "%d: %ld: owner=0, read()=fail\n",
71                         (int) pid, (long) time(NULL));
72                 return 1;
73         }
74         if (strncmp(iobuf, xbuf, strlen(xbuf)))
75         {
76                 fprintf(stderr, "%d: %ld: owner=0, read=%s expected=%s\n",
77                         (int) pid, (long) time(NULL), iobuf, xbuf);
78                 return 1;
79         }
80         return 0;
81 }
82
83 /*
84 **  LOCKTEST -- test of file locking
85 **
86 **      Parameters:
87 **              owner -- create file?
88 **              filename -- name of file.
89 **              flags -- flags for open(2)
90 **              delay -- how long to keep file locked?
91 **
92 **      Returns:
93 **              0 on success
94 **              != 0 on failure.
95 */
96
97 #define DBGPRINTR(str)  \
98         do      \
99         {       \
100                 fprintf(stderr, "%d: %ld: owner=0, ", (int) pid,        \
101                         (long) time(NULL));     \
102                 fprintf(stderr, str, filename, shared ? "RD" : "EX");   \
103         } while (0)
104
105 int
106 locktestwr(filename, flags, delay)
107         char *filename;
108         int flags;
109         int delay;
110 {
111         int fd;
112         bool locked;
113
114         fd = openfile(1, filename, flags);
115         if (fd < 0)
116                 return errno;
117         locked = lockfile(fd, filename, "[owner]", LOCK_EX);
118         if (!locked)
119         {
120                 fprintf(stderr, "%d: %ld: owner=1, lock(%s) failed\n",
121                         (int) pid, (long) time(NULL), filename);
122                 return 1;
123         }
124         else
125                 fprintf(stderr, "%d: %ld: owner=1, lock(%s) ok\n",
126                         (int) pid, (long) time(NULL), filename);
127
128         sm_strlcpy(iobuf, FIRSTLINE, sizeof(iobuf));
129         if (wrbuf(fd))
130                 return 1;
131         sleep(delay);
132         sm_strlcpy(iobuf, LASTLINE, sizeof(iobuf));
133         if (wrbuf(fd))
134                 return 1;
135         locked = lockfile(fd, filename, "[owner]", LOCK_UN);
136         if (!locked)
137         {
138                 fprintf(stderr, "%d: %ld: owner=1, unlock(%s) failed\n",
139                         (int) pid, (long) time(NULL), filename);
140                 return 1;
141         }
142         fprintf(stderr, "%d: %ld: owner=1, unlock(%s) done\n",
143                 (int) pid, (long) time(NULL), filename);
144         if (fd > 0)
145         {
146                 close(fd);
147                 fd = -1;
148         }
149         return 0;
150 }
151
152 long
153 chklck(fd)
154         int fd;
155 {
156 #if !HASFLOCK
157         int action, i;
158         struct flock lfd;
159
160         (void) memset(&lfd, '\0', sizeof lfd);
161         lfd.l_type = F_RDLCK;
162         action = F_GETLK;
163         while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
164                 continue;
165         if (i < 0)
166                 return (long)i;
167         if (F_WRLCK == lfd.l_type)
168                 return (long)lfd.l_pid;
169         return 0L;
170 #else /* !HASFLOCK */
171         fprintf(stderr, "%d: %ld: flock: no lock test\n",
172                 (int) pid, (long) time(NULL));
173         return -1L;
174 #endif /* !HASFLOCK */
175 }
176
177 int
178 locktestrd(filename, flags, delay, shared)
179         char *filename;
180         int flags;
181         int delay;
182         int shared;
183 {
184         int fd, cnt;
185         int lt;
186         bool locked;
187
188         fd = openfile(0, filename, flags);
189         if (fd < 0)
190                 return errno;
191         if (chk)
192         {
193                 long locked;
194
195                 locked = chklck(fd);
196                 if (locked > 0)
197                         fprintf(stderr, "%d: %ld: file=%s status=locked pid=%ld\n",
198                                  (int) pid, (long) time(NULL), filename, locked);
199                 else if (0 == locked)
200                         fprintf(stderr, "%d: %ld: file=%s status=not_locked\n",
201                                  (int) pid, (long) time(NULL), filename);
202                 else
203                         fprintf(stderr, "%d: %ld: file=%s status=unknown\n",
204                                  (int) pid, (long) time(NULL), filename);
205                 goto end;
206         }
207
208         if (shared)
209                 lt = LOCK_SH;
210         else
211                 lt = LOCK_EX;
212
213         for (cnt = 0; cnt < delay - 2; cnt++)
214         {
215                 /* try to get lock: should fail (nonblocking) */
216                 locked = lockfile(fd, filename, "[client]", lt|LOCK_NB);
217                 if (locked)
218                 {
219                         DBGPRINTR("lock(%s)=%s succeeded\n");
220                         return 1;
221                 }
222                 sleep(1);
223         }
224         if (delay > 0)
225                 sleep(2);
226         locked = lockfile(fd, filename, "[client]", lt);
227         if (!locked)
228         {
229                 DBGPRINTR("lock(%s)=%s failed\n");
230                 return 1;
231         }
232         DBGPRINTR("lock(%s)=%s ok\n");
233         if (rdbuf(fd, FIRSTLINE))
234                 return 1;
235         if (rdbuf(fd, LASTLINE))
236                 return 1;
237         sleep(1);
238         locked = lockfile(fd, filename, "[client]", LOCK_UN);
239         if (!locked)
240         {
241                 DBGPRINTR("unlock(%s)=%s failed\n");
242                 return 1;
243         }
244         DBGPRINTR("unlock(%s)=%s done\n");
245
246   end:
247         if (fd > 0)
248         {
249                 close(fd);
250                 fd = -1;
251         }
252         return 0;
253 }
254
255 static void
256 usage(prg)
257         const char *prg;
258 {
259         fprintf(stderr, "usage: %s [options]\n"
260                 "-f filename    use filename\n"
261                 "-i             do not perform I/O\n"
262                 "-n             do not try non-blocking locking first\n"
263                 "-R             only start reader process\n"
264                 "-r             use shared locking for reader\n"
265                 "-s delay       sleep delay seconds before unlocking\n"
266                 "-W             only start writer process\n"
267                 , prg);
268 }
269
270 int
271 main(argc, argv)
272         int argc;
273         char *argv[];
274 {
275         int ch, delay, r, status, flags, shared, nb, reader, writer;
276         char *filename;
277         pid_t fpid;
278         extern char *optarg;
279
280         delay = 5;
281         filename = "testlock";
282         flags = O_RDWR;
283         shared = nb = noio = reader = writer = chk = 0;
284 #define OPTIONS "cf:inRrs:W"
285         while ((ch = getopt(argc, argv, OPTIONS)) != -1)
286         {
287                 switch ((char) ch)
288                 {
289                   case 'c':
290                         chk = 1;
291                         break;
292
293                   case 'f':
294                         filename = optarg;
295                         break;
296
297                   case 'i':
298                         noio = 1;
299                         break;
300
301                   case 'n':
302                         nb = 0;
303                         break;
304
305                   case 'R':
306                         reader = 1;
307                         break;
308
309                   case 'r':
310                         shared = 1;
311                         break;
312
313                   case 's':
314                         delay = atoi(optarg);
315                         break;
316
317                   case 'W':
318                         writer = 1;
319                         break;
320
321                   default:
322                         usage(argv[0]);
323                         exit(69);
324                         break;
325                 }
326         }
327
328         fpid = -1;
329         if (0 == reader && 0 == writer && (fpid = fork()) < 0)
330         {
331                 perror("fork failed\n");
332                 return 1;
333         }
334
335         r = 0;
336         if (reader || fpid == 0)
337         {
338                 /* give the parent the chance to setup data */
339                 pid = getpid();
340                 sleep(1);
341                 r = locktestrd(filename, flags, nb ? delay : 0, shared);
342         }
343         if (writer || fpid > 0)
344         {
345                 fpid = getpid();
346                 r = locktestwr(filename, flags, delay);
347                 (void) wait(&status);
348         }
349         /* (void) unlink(filename); */
350         return r;
351 }