6 * This program uses expire.ctl.ctl as input; please see the end of this
7 * file for an example of such a file.
11 * Date: Mon, 21 Nov 1994 12:29:52 -0801
12 * From: Matthew Dillon <dillon@apollo.west.oic.com>
13 * Message-Id: <199411212030.MAA21835@apollo.west.oic.com>
14 * To: rsalz@uunet.uu.net
15 * Subject: Re: INN is great, bug fix for BSDI
18 * Oh, while I'm at it, I also wrote a cute program that builds the
19 * expire.ctl file dynamically based on available space. Feel free
20 * to include this in the dist (or not) as you please.
22 * Basically, the expirectl programs determines the amount of disk blocks
23 * and inodes free in the spool and creates a new expire.ctl file based
24 * on an expire.ctl.ctl template. The template specifies expiration times
25 * as a fraction of nominal. expirectl adjusts the nominal expiration
26 * up or down based on available disk space.
28 * The idea is to make expiration as hands off as possible. I tested
29 * it on a smaller spool and it appeared to work fine. Currently it
30 * only works for single-partition news spools tho. The above spool
31 * will not really exercise the program for another 14 days or so :-).
35 #include <sys/types.h>
36 #include <sys/mount.h>
42 #define EXPIRE_CTL_DIR "/home/news"
43 #define NEWS_SPOOL "/home/news/spool/news/."
45 #define EXPIRE_DAYS EXPIRE_CTL_DIR "/expire.days"
46 #define EXPIRE_CTL EXPIRE_CTL_DIR "/expire.ctl"
47 #define EXPIRE_CTL_CTL EXPIRE_CTL_DIR "/expire.ctl.ctl"
50 main(int ac, char **av)
53 long minFree = 100 * 1024 * 1024;
54 long minIFree = 20 * 1024;
56 time_t expireIncTime = time(NULL) - 24 * 60 * 60;
67 for (i = 1; i < ac; ++i) {
83 minFree = strtol(((*ptr) ? ptr : av[++i]), &ptr, 0);
87 minFree *= 1024 * 1024;
90 minIFree = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
94 minIFree *= 1024 * 1024;
97 fprintf(stderr, "bad option: %s\n", ptr - 2);
101 fprintf(stderr, "bad option: %s\n", ptr);
107 if (statfs("/home/news/spool/news/.", &sfs) != 0) {
108 fprintf(stderr, "expirectl: couldn't fsstat /home/news/spool/news/.\n");
113 * Load /home/news/expire.days
120 if ((fi = fopen(EXPIRE_DAYS, "r")) != NULL) {
121 while (fgets(buf, sizeof(buf), fi) != NULL) {
122 if (strncmp(buf, "time", 4) == 0) {
123 expireIncTime = strtol(buf + 4, NULL, 0);
124 } else if (strncmp(buf, "days", 4) == 0) {
125 expireDays = strtol(buf + 4, NULL, 0);
132 printf("creating %s\n", EXPIRE_DAYS);
141 printf("spool: %4.2lfM / %3.2lfKinode free\n",
142 (double)sfs.f_fsize * (double)sfs.f_bavail / (1024.0 * 1024.0),
143 (double)sfs.f_ffree / 1024.0
145 printf("decrs: %4.2lfM / %3.2lfKinode\n",
146 (double)(minFree) / (double)(1024*1024),
147 (double)(minIFree) / (double)(1024)
149 printf("incrs: %4.2lfM / %3.2lfKinode\n",
150 (double)(minFree * 2) / (double)(1024*1024),
151 (double)(minIFree * 2) / (double)(1024)
156 * Check limits, update as appropriate
163 bytes = (double)sfs.f_fsize * (double)sfs.f_bavail;
164 inodes = sfs.f_ffree;
166 if (bytes < (double)minFree || inodes < minIFree) {
167 if (--expireDays <= 0) {
169 expireIncTime = time(NULL) - 24 * 60 * 60;
173 printf("decrement expiration to %d days\n", expireDays);
174 } else if (bytes >= (double)minFree * 2.0 && inodes >= minIFree * 2) {
175 long dt = (long)(time(NULL) - expireIncTime);
177 if (dt >= 60 * 60 * 24 || dt < -60) {
179 expireIncTime = time(NULL);
182 printf("increment expiration to %d days\n", expireDays);
184 printf("will increment expiration later\n");
186 } else if (verbose) {
187 printf("expiration unchanged: %d\n", expireDays);
192 * Write EXPIRE_CTL file from EXPIRE_CTL_CTL template
199 if ((fi = fopen(EXPIRE_CTL_CTL, "r")) != NULL) {
200 if ((fo = fopen(EXPIRE_CTL ".tmp", "w")) != NULL) {
204 while (fgets(sbuf, sizeof(sbuf), fi) != NULL) {
209 while ((sptr = strchr(base, '[')) != NULL) {
213 bcopy(base, dptr, sptr - base);
217 d = strtod(sptr + 1, &sptr);
219 m = strtol(sptr + 1, &sptr, 0);
221 long v = (long)((double)expireDays * d + 0.5);
226 sprintf(dptr, "%d", v);
227 dptr += strlen(dptr);
236 if (rename(EXPIRE_CTL ".tmp", EXPIRE_CTL) != 0) {
237 fprintf(stderr, "rename(%s,%s): %s\n",
249 * Write EXPIRE_DAYS file
255 if ((fo = fopen(EXPIRE_DAYS, "w")) != NULL) {
256 fprintf(fo, "time 0x%08lx\n", expireIncTime);
257 fprintf(fo, "days %d\n", expireDays);
260 fprintf(stderr, "unable to create %s\n", EXPIRE_DAYS);
269 # Start of sample expire.ctl.ctl file.
271 # EXPIRE.CTL.CTL (EXPIRE.CTL GENERATED FROM EXPIRE.CTL.CTL !!!)
273 # The expire.ctl file is generated by the expirectl program from the
274 # expire.ctl.ctl file. The expirectl program calculates the proper
275 # expiration based on the number of free inodes and free bytes available.
277 # This file is exactly expire.ctl but with the multiplier [N] replaced by
278 # a calculated value, where a multiplier of '1' nominally fills the whole
281 # Any field [N] is substituted after being multiplied by the expiration
282 # time (in days). A integer minimum can also be specified with a slash,
285 # expirectl is normally run just after expire is run. Note that expirectl
286 # isn't very useful for the case where you are 'catching up' on news after
287 # a long period of downtime UNLESS you use the -p option to expire.
291 ## Keep for 1-10 days, allow Expires headers to work.
294 *.advocacy:A:1:[0.5]:[2.0]
295 alt.binaries.pictures.erotica:A:1:[0.8]:[2.0]
297 # permanent, semi-permanent
299 best.intro:A:never:never:never
300 best.announce:A:5:60:120
301 best.general:A:never:never:never
302 best.bugs:A:never:never:never
304 # End of sample expire.ctl.ctl file.