chiark / gitweb /
better stats for missing
[inn-innduct.git] / contrib / mlockfile.c
1 /* $Id: mlockfile.c 6014 2002-12-16 11:28:07Z alexk $ */
2
3 /* Locks the files given on the command line into memory using mlock.
4    This code has only been tested on Solaris and may not work on other
5    platforms.
6
7    Contributed by Alex Kiernan <alexk@demon.net>.  */
8
9 #include <sys/types.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <poll.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sysexits.h>
17 #include <unistd.h>
18 #include <sys/mman.h>
19 #include <sys/stat.h>
20 #include <sys/stropts.h>
21
22 struct mlock {
23     const char *path;
24     struct stat st;
25     void *base;
26     off_t offset;
27     size_t length;
28 };
29
30 char *progname;
31
32 int flush = 0;
33 int interval = 60000;
34
35 void
36 inn_lock_files(struct mlock *ml)
37 {
38     for (; ml->path != NULL; ++ml) {
39         int fd;
40
41         fd = open(ml->path, O_RDONLY);
42         if (fd == -1) {
43             fprintf(stderr, "%s: can't open `%s' - %s\n",
44                     progname, ml->path, strerror(errno));
45         } else {
46             struct stat st;
47
48             /* check if size, inode or device of the path have
49              * changed, if so unlock the previous file & lock the new
50              * one */
51             if (fstat(fd, &st) != 0) {
52                 fprintf(stderr, "%s: can't stat `%s' - %s\n",
53                         progname, ml->path, strerror(errno));
54             } else if (ml->st.st_ino != st.st_ino ||
55                      ml->st.st_dev != st.st_dev ||
56                      ml->st.st_size != st.st_size) {
57                 if (ml->base != MAP_FAILED)
58                     munmap(ml->base,
59                            ml->length ? ml->length : ml->st.st_size);
60
61                 /* free everything here, so in case of failure we try
62                  * again next time */
63                 ml->st.st_ino = 0;
64                 ml->st.st_dev = 0;
65                 ml->st.st_size = 0;
66
67                 ml->base = mmap(NULL,
68                                 ml->length ? ml->length : st.st_size,
69                                 PROT_READ,
70                                 MAP_SHARED, fd, ml->offset);
71
72                 if (ml->base == MAP_FAILED) {
73                     fprintf(stderr, "%s: can't mmap `%s' - %s\n",
74                             progname, ml->path, strerror(errno));
75                 } else {
76                     if (mlock(ml->base,
77                               ml->length ? ml->length : st.st_size) != 0) {
78                         fprintf(stderr, "%s: can't mlock `%s' - %s\n",
79                                 progname, ml->path, strerror(errno));
80                     } else {
81                         ml->st = st;
82                     }
83                 }
84             } else if (flush) {
85                 msync(ml->base, ml->length ? ml->length : st.st_size, MS_SYNC);
86             }
87         }
88         close (fd);
89     }
90 }
91
92 static void
93 usage(void)
94 {
95     fprintf(stderr,
96             "usage: %s [-f] [-i interval] file[@offset[:length]] ...\n",
97             progname);
98     fprintf(stderr, "    -f\tflush locked bitmaps at interval\n");
99     fprintf(stderr, "    -i interval\n\tset interval between checks/flushes\n");
100 }
101
102 int
103 main(int argc, char *argv[])
104 {
105     struct mlock *ml;
106     int i;
107
108     progname = *argv;
109     while ((i = getopt(argc, argv, "fi:")) != EOF) {
110         switch (i) {
111         case 'i':
112             interval = 1000 * atoi(optarg);
113             break;
114
115         case 'f':
116             flush = 1;
117             break;
118
119         default:
120             usage();
121             return EX_USAGE;        
122         }
123     }
124     argc -= optind;
125     argv += optind;
126
127     /* construct list of pathnames which we're to operate on, zero out
128      * the "cookies" so we lock it in core first time through */
129     ml = malloc((1 + argc) * sizeof ml);
130     for (i = 0; argc--; ++i, ++argv) {
131         char *at;
132         off_t offset = 0;
133         size_t length = 0;
134
135         ml[i].path = *argv;
136         ml[i].st.st_ino = 0;
137         ml[i].st.st_dev = 0;
138         ml[i].st.st_size = 0;
139         ml[i].base = MAP_FAILED;
140         
141         /* if we have a filename of the form ...@offset:length, only
142          * map in that portion of the file */
143         at = strchr(*argv, '@');
144         if (at != NULL) {
145             char *end;
146
147             *at++ = '\0';
148             errno = 0;
149             offset = strtoull(at, &end, 0);
150             if (errno != 0) {
151                 fprintf(stderr, "%s: can't parse offset `%s' - %s\n",
152                         progname, at, strerror(errno));
153                 return EX_USAGE;
154             }
155             if (*end == ':') {
156                 at = end + 1;
157                 errno = 0;
158                 length = strtoul(at, &end, 0);
159                 if (errno != 0) {
160                     fprintf(stderr, "%s: can't parse length `%s' - %s\n",
161                             progname, at, strerror(errno));
162                     return EX_USAGE;
163                 }
164             }
165             if (*end != '\0') {
166                 fprintf(stderr, "%s: unrecognised separator `%c'\n",
167                         progname, *end);
168                 return EX_USAGE;
169             }
170         }
171         ml[i].offset = offset;
172         ml[i].length = length;      
173     }
174     ml[i].path = NULL;
175
176     /* loop over the list of paths, sleeping 60s between iterations */
177     for (;;) {
178         inn_lock_files(ml);
179         poll(NULL, 0, interval);
180     }
181     return EX_OSERR;
182 }