"Fossies" - the Fresh Open Source Software Archive 
Member "leafnode-1.12.0/xoverutil.c" (25 Mar 2017, 16629 Bytes) of package /linux/misc/leafnode-1.12.0.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "xoverutil.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.11.11_vs_1.11.12.
1 /*
2 libutil -- handling xover records
3
4 Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995
5 Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47
6 22646949.
7 Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>
8 and Randolf Skerka <Randolf.Skerka@gmx.de>.
9 Copyright of the modifications 1997.
10 Modified by Kent Robotti <robotti@erols.com>. Copyright of the
11 modifications 1998.
12 Modified by Markus Enzenberger <enz@cip.physik.uni-muenchen.de>.
13 Copyright of the modifications 1998.
14 Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
15 Copyright of the modifications 1998, 1999.
16 Modified by Ralf Wildenhues <ralf.wildenhues@gmx.de>
17 Copyright of the modifications 2002.
18 Modified by Matthias Andree <matthias.andree@gmx.de>
19 Copyright of the modifications 2000 - 2005, 2007.
20
21 See file COPYING for restrictions on the use of this software.
22 */
23
24 #include "leafnode.h"
25 #include <fcntl.h>
26 #include <sys/param.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdlib.h>
33 #include <netdb.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <syslog.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include "system.h"
42 #include "strlcpy.h"
43 #include "ln_log.h"
44
45 static void
46 tabstospaces(char *t)
47 {
48 while (*t) {
49 if (*t == '\t')
50 *t = ' ';
51 t++;
52 }
53
54 }
55
56 static /*@null@*/ /*@only@*/
57 char *getxoverline(const char *filename, const char **e /** error message is stored here */)
58 {
59 char *l;
60 const char *em;
61 char *result;
62 FILE *f;
63
64 result = NULL;
65 *e = NULL;
66 debug = 0;
67 if ((f = fopen(filename, "r"))) {
68 char *from, *subject, *date, *msgid, *references, *lines, *xref;
69 unsigned long bytes, linecount;
70 char **h;
71 int body;
72
73 from = subject = date = msgid = references = xref = lines = NULL;
74 bytes = linecount = 0;
75 h = NULL;
76 body = 0;
77
78 while (!feof(f) && ((l = getaline(f)) != NULL)) {
79 tabstospaces(l);
80 linecount++;
81 bytes += strlen(l) + 2; /* normalize CR LF -> add 2 per line */
82 if (body || !l) {
83 /* do nothing */
84 } else if (!body && !*l) {
85 linecount = 0;
86 body = 1;
87 } else if (*l && isspace((unsigned char)*l)) {
88 /* cater for folded headers */
89 if (h) {
90 (*h) = critrealloc(*h, strlen(*h) + strlen(l) + 1,
91 "extending header");
92 strcat(*h, l); /* RATS: ignore */
93 }
94 } else if (!from && !strncasecmp("From:", l, 5)) {
95 l += 5;
96 SKIPLWS(l);
97 if (*l) {
98 from = critstrdup(l, "getxoverline");
99 h = &from;
100 }
101 } else if (!subject && !strncasecmp("Subject:", l, 8)) {
102 l += 8;
103 SKIPLWS(l);
104 if (*l) {
105 subject = critstrdup(l, "getxoverline");
106 h = &subject;
107 }
108 } else if (!date && !strncasecmp("Date:", l, 5)) {
109 l += 5;
110 SKIPLWS(l);
111 if (*l) {
112 date = critstrdup(l, "getxoverline");
113 h = &date;
114 }
115 } else if (!msgid && !strncasecmp("Message-ID:", l, 11)) {
116 l += 11;
117 SKIPLWS(l);
118 if (*l) {
119 msgid = critstrdup(l, "getxoverline");
120 h = &msgid;
121 }
122 } else if (!references && !strncasecmp("References:", l, 11)) {
123 l += 11;
124 SKIPLWS(l);
125 if (*l) {
126 references = critstrdup(l, "getxoverline");
127 h = &references;
128 }
129 } else if (!lines && !strncasecmp("Lines:", l, 6)) {
130 l += 6;
131 SKIPLWS(l);
132 if (*l) {
133 lines = critstrdup(l, "getxoverline");
134 h = &lines;
135 }
136 } else if (!xref && !strncasecmp("Xref:", l, 5)) {
137 l += 5;
138 SKIPLWS(l);
139 if (*l) {
140 xref = critstrdup(l, "getxoverline");
141 h = &xref;
142 }
143 } else {
144 h = NULL;
145 }
146 }
147 if (from != NULL && date != NULL && subject != NULL &&
148 msgid != NULL && bytes) {
149 result = critmalloc(strlen(filename) + strlen(subject) + strlen(from) +
150 strlen(date) + strlen(msgid) +
151 (references ? strlen(references) : 0) +
152 100 + (xref ? strlen(xref) : 0),
153 "computing overview line");
154 sprintf(result, "%s\t%s\t%s\t%s\t%s\t%s\t%lu\t%lu", /* RATS: ignore */
155 filename, subject, from, date, msgid,
156 references ? references : "",
157 bytes, lines ? strtoul(lines, NULL, 10) : linecount);
158 if (xref) {
159 strcat(result, "\tXref: "); /* RATS: ignore */
160 strcat(result, xref); /* RATS: ignore */
161 }
162 } else {
163 if (from == NULL)
164 *e = "missing From: header";
165 else if (date == NULL)
166 *e = "missing Date: header";
167 else if (subject == NULL)
168 *e = "missing Subject: header";
169 else if (msgid == NULL)
170 *e = "missing Message-ID: header";
171 else if (bytes == 0)
172 *e = "article has 0 bytes";
173 }
174 (void)fclose(f);
175 if (from)
176 free(from);
177 if (date)
178 free(date);
179 if (subject)
180 free(subject);
181 if (msgid)
182 free(msgid);
183 if (references)
184 free(references);
185 if (lines)
186 free(lines);
187 if (xref)
188 free(xref);
189 } else {
190 ln_log(LNLOG_SERR, LNLOG_CARTICLE,
191 "error: getxoverline: cannot open %s: %m", filename);
192 }
193 debug = debugmode;
194 if (result && !legalxoverline(result, &em)) {
195 *e = em;
196 free(result);
197 result = NULL;
198 }
199 return result;
200 }
201
202 /*
203 * return 1 if xover is a legal overview line, 0 else
204 */
205 int
206 legalxoverline(const char *xover, const char **e)
207 {
208 const char *p;
209 const char *q;
210
211 if (!xover)
212 return 0;
213
214 /* anything that isn't tab, printable ascii, or latin-* -> kill */
215
216 p = xover;
217 while (*p) {
218 int c = (unsigned char)*p++;
219
220 if ((c != '\t' && c < ' ') || (c > 126 && c < 160)) {
221 *e = "non-printable characters in headers (relaxed check allows for iso-8859*)";
222 return 0;
223 }
224 }
225
226 p = xover;
227 q = strchr(p, '\t');
228 if (!q) {
229 *e = "missing Subject: header";
230 return 0;
231 }
232
233 /* article number */
234
235 while (p != q) {
236 if (!isdigit((unsigned char)*p)) {
237 *e = "article number contains non-digit characters";
238 return 0;
239 }
240 p++;
241 }
242
243 p = q + 1;
244 q = strchr(p, '\t');
245 if (!q) {
246 *e = "missing From: header";
247 return 0;
248 }
249
250 /* subject: no limitations */
251
252 p = q + 1;
253 q = strchr(p, '\t');
254 if (!q) {
255 *e = "missing Date: header";
256 return 0;
257 }
258
259 /* from: no limitations */
260
261 p = q + 1;
262 q = strchr(p, '\t');
263 if (!q) {
264 *e = "missing Message-ID: header";
265 return 0;
266 }
267
268 /* date: no limitations */
269
270 p = q + 1;
271 q = strchr(p, '\t');
272 if (!q) {
273 *e = "missing References: or Bytes: header";
274 return 0;
275 }
276
277 /* message-id: <*@*> */
278
279 if (*p != '<') {
280 *e = "Message-ID: does not start with \"<\"";
281 return 0;
282 }
283 while (p != q && *p != '@' && *p != '>' && *p != ' ')
284 p++;
285 if (*p != '@') {
286 *e = "Message-ID: does not contain @";
287 return 0;
288 }
289 while (p != q && *p != '>' && *p != ' ')
290 p++;
291 if (*p != '>') {
292 *e = "Message-ID: does not end with \">\"";
293 return 0;
294 }
295 if (++p != q) {
296 *e = "Message-ID: does not end with \">\"";
297 return 0;
298 }
299
300 p = q + 1;
301 q = strchr(p, '\t');
302 if (!q) {
303 *e = "missing Bytes: header";
304 return 0;
305 }
306
307 /* references: a series of <*@*> separated by space */
308
309 #if 0
310 while (p != q) {
311 /* reference validation - users don't like it */
312 if (*p != '<') {
313 *e = "References: does not start with \"<\"";
314 return 0;
315 }
316 while (p != q && *p != '@' && *p != '>' && *p != ' ')
317 p++;
318 if (*p != '@') {
319 *e = "References: does not contain @";
320 return 0;
321 }
322 while (p != q && *p != '>' && *p != ' ')
323 p++;
324 if (*p++ != '>') {
325 *e = "References: does not end with \">\"";
326 return 0;
327 }
328 while (p != q && *p == ' ')
329 p++;
330 }
331 #endif
332
333 p = q + 1;
334 q = strchr(p, '\t');
335 if (!q) {
336 *e = "missing Lines: header";
337 return 0;
338 }
339
340 /* byte count */
341
342 while (p != q) {
343 if (!isdigit((unsigned char)*p)) {
344 *e = "non-digit character in Bytes: header";
345 return 0;
346 }
347 p++;
348 }
349
350 p = q + 1;
351 q = strchr(p, '\t');
352
353 /* line count */
354
355 while (p && *p && p != q) {
356 if (!isdigit((unsigned char)*p)) {
357 *e = "non-digit character in Lines: header";
358 return 0;
359 }
360 p++;
361 }
362
363 if (!q) {
364 *e = "missing Xref: entry";
365 return 0;
366 }
367
368 {
369 p = q + 1;
370
371 /* xref */
372 if (0 != strncasecmp(p, "Xref:", 5)) {
373 *e = "Xref header is missing or lacks Xref: tag";
374 return 0;
375 }
376 }
377
378 return 1;
379 }
380
381 static void killcwd(void) {
382 char *t = NULL;
383 size_t s_t;
384
385 if (agetcwd(&t, &s_t)) {
386 if (chdir(spooldir)) {
387 ln_log(LNLOG_SERR, LNLOG_CTOP, "error: cannot chdir(%s): %m", spooldir);
388 }
389 if (rmdir(t) && errno != ENOTEMPTY && errno != EEXIST) {
390 ln_log(LNLOG_SERR, LNLOG_CTOP, "error: cannot rmdir(%s): %m", t);
391 }
392 free(t);
393 }
394 }
395
396 void freexover(void) {
397 unsigned long art;
398
399 if (xoverinfo) {
400 for (art = xfirst; art <= xlast; art++) {
401 if (xoverinfo[art - xfirst].text) {
402 free(xoverinfo[art - xfirst].text);
403 xoverinfo[art - xfirst].text = NULL;
404 }
405 }
406 free(xoverinfo);
407 xoverinfo = NULL;
408 }
409
410 }
411
412 /* utility routine to pull the xover info into memory
413 returns 0 if there's some error, non-zero else */
414 int
415 getxover(void)
416 {
417 DIR *d;
418 struct dirent *de;
419 int fd;
420 struct stat st;
421 unsigned long art;
422 char *overview = NULL;
423 int error;
424 char *p, *q;
425 char *tt = NULL; size_t s_tt;
426
427 error = 0;
428
429 /* free any memory left over from last time */
430 freexover();
431
432 /* find article range */
433 d = opendir(".");
434 if (!d) {
435 ln_log(LNLOG_SERR, LNLOG_CTOP, "error: opendir: %m");
436 return 0;
437 }
438
439 xfirst = ULONG_MAX;
440 xlast = 0;
441 while ((de = readdir(d))) {
442 /* weed out temporary .overview files from aborted earlier run */
443 if (0 == strncmp(".overview.", de->d_name, 10))
444 log_unlink(de->d_name, 0);
445 if (!isdigit((unsigned char)de->d_name[0]))
446 continue; /* skip files that don't start with a digit */
447 /* WARNING: strtoul will happily return the negated value when
448 * fed a string that starts with a minus character! */
449 art = strtoul(de->d_name, &p, 10);
450 if (art && p && !*p) {
451 if (art < xfirst)
452 xfirst = art;
453 if (art > xlast)
454 xlast = art;
455 }
456 }
457
458 if (xlast < xfirst) {
459 /* we did not find any article files (1, 17, 815 or the like) */
460 closedir(d);
461 (void)unlink(".overview");
462 if (debugmode) {
463 char *t = NULL; size_t s_t;
464 if (!agetcwd(&t, &s_t)) {
465 ln_log(LNLOG_SERR, LNLOG_CGROUP, "error: getcwd: %m");
466 } else {
467 syslog(LOG_DEBUG, "removed .overview file for %s", t);
468 free(t);
469 }
470 }
471 killcwd();
472 return 0;
473 }
474
475 /* next, read .overview, correct it if it seems too different from
476 what the directory implies, and write the result back */
477 rewinddir(d);
478
479 xoverinfo = (struct xoverinfo *)
480 critmalloc(sizeof(struct xoverinfo) * (xlast + 1 - xfirst),
481 "allocating overview array");
482 memset(xoverinfo, 0, sizeof(struct xoverinfo) * (xlast + 1 - xfirst));
483
484 if ((fd = open(".overview", O_RDONLY)) >= 0 &&
485 fstat(fd, &st) == 0) {
486 overview = (char *)critmalloc(st.st_size + 1, "getxover");
487 if ((off_t) read(fd, overview, st.st_size) != st.st_size) {
488 int e = errno;
489 char *t = NULL; size_t s_t;
490 /* short read */
491 close(fd);
492
493 if (!agetcwd(&t, &s_t)) {
494 ln_log(LNLOG_SERR, LNLOG_CGROUP, "error: getcwd: %m");
495 } else {
496 ln_log(LNLOG_SWARNING, LNLOG_CGROUP,
497 "warning: short read on %s/.overview: %s",
498 t, strerror(e));
499 free(t);
500 }
501 } else {
502 close(fd);
503 overview[st.st_size] = '\0';
504
505 /* okay, we have the content, so let's parse it roughly */
506 /* iterate line-wise */
507 p = overview;
508 while (p && *p) {
509 const char *t;
510
511 while (p && isspace((unsigned char)*p))
512 p++;
513 q = strchr(p, '\n');
514 if (q)
515 *q++ = '\0';
516
517
518 art = strtoul(p, NULL, 10);
519 if (legalxoverline(p, &t)) {
520 if (art > xlast || art < xfirst) {
521 error++;
522 } else if (xoverinfo[art - xfirst].text) {
523 char *tt = NULL; size_t s_tt;
524 error++;
525 if (!agetcwd(&tt, &s_tt)) {
526 ln_log(LNLOG_SERR, LNLOG_CARTICLE, "error: getcwd: %m");
527 } else {
528 ln_log(LNLOG_SERR, LNLOG_CARTICLE, "error: multiple lines for article %lu "
529 "in .overview for %s", art, tt);
530 free(tt);
531 }
532 free (xoverinfo[art - xfirst].text);
533 xoverinfo[art - xfirst].text = NULL;
534 xoverinfo[art - xfirst].exists = -1;
535 } else if (xoverinfo[art - xfirst].exists == 0) {
536 xoverinfo[art - xfirst].text = critstrdup(p, "getxover");
537 }
538 } else {
539 char *tt = NULL; size_t s_tt;
540 if (!agetcwd(&tt, &s_tt)) {
541 ln_log(LNLOG_SERR, LNLOG_CTOP, "error: getcwd: %m");
542 } else {
543 ln_log(LNLOG_SNOTICE, LNLOG_CARTICLE, "illegal line for article %lu in .overview for %s: %s", art, tt, t);
544 free(tt);
545 }
546 }
547
548 p = q;
549 } /* while p && *p */
550 } /* if read went fine */
551 } /* if open && fstat */
552
553 if (!agetcwd(&tt, &s_tt)) {
554 ln_log(LNLOG_SERR, LNLOG_CTOP, "error: getcwd: %m");
555 closedir(d);
556 return 0;
557 }
558
559 /* so, what was missing? */
560 while ((de = readdir(d))) {
561 if (de->d_name[0] == '.')
562 continue;
563 art = strtoul(de->d_name, &p, 10);
564 if (p && !*p && art >= xfirst && art <= xlast) {
565 if (!xoverinfo[art - xfirst].text) {
566 const char *e;
567
568 xoverinfo[art - xfirst].exists = 0;
569 if (debugmode) {
570 syslog(LOG_DEBUG, "reading XOVER info from %s/%s",
571 tt, de->d_name);
572 }
573 error++;
574 if ((xoverinfo[art - xfirst].text =
575 getxoverline(de->d_name, &e)) == NULL) {
576 ln_log(LNLOG_SINFO, LNLOG_CARTICLE,
577 "article %s/%s contained illegal headers: %s",
578 tt, de->d_name, e);
579 if (truncate(de->d_name, (off_t)0))
580 ln_log(LNLOG_SWARNING, LNLOG_CARTICLE,
581 "warning: failed to truncate broken %s/%s to 0 size: %m",
582 tt,de->d_name);
583 if ((lstat(de->d_name, &st) == 0) && S_ISREG(st.st_mode)) {
584 if (unlink(de->d_name))
585 ln_log(LNLOG_SWARNING, LNLOG_CARTICLE,
586 "warning: failed to remove broken %s/%s: %m", tt, de->d_name);
587 } else {
588 ln_log(LNLOG_SWARNING, LNLOG_CARTICLE,
589 "warning: %s/%s is not a regular file", tt, de->d_name);
590 }
591 }
592 }
593 }
594
595 if (art >= xfirst && art <= xlast && xoverinfo[art - xfirst].text) {
596 xoverinfo[art - xfirst].exists = 1;
597 } else {
598 /* kill non-article files, like "core" */
599 if (art == 0)
600 {
601 if (unlink(de->d_name)
602 && errno != EISDIR
603 && errno != EPERM
604 && verbose) {
605 ln_log(LNLOG_SWARNING, LNLOG_CGROUP,
606 "warning: deleting junk %s/%s failed: %s",
607 tt, de->d_name, strerror(errno));
608 }
609 }
610 }
611 } /* while (de = readdir(d)) */
612
613 /* count removed articles */
614 for (art = xfirst; art <= xlast; art++) {
615 if (xoverinfo[art - xfirst].text
616 && !xoverinfo[art - xfirst].exists) {
617 ++error;
618 free(xoverinfo[art - xfirst].text);
619 xoverinfo[art - xfirst].text = NULL;
620 }
621 }
622
623 /* if something had to be fixed, write a better file to disk for
624 next time - race conditions here, but none dangerous */
625 if (error) {
626 int wfd;
627 char newfile[20]; /* RATS: ignore */
628
629 if (debugmode)
630 syslog(LOG_DEBUG, "updated %d line%s in %s/.overview",
631 error, PLURAL(error), tt);
632
633 strcpy(newfile, ".overview.XXXXXX");
634 if ((wfd = mkstemp(newfile)) != -1) {
635 int va;
636
637 va = 1;
638 for (art = xfirst; art <= xlast; art++) {
639 if (xoverinfo[art - xfirst].exists
640 && xoverinfo[art - xfirst].text) {
641 if (writes(wfd, xoverinfo[art - xfirst].text) == - 1
642 || writes(wfd, "\n") == -1)
643 {
644 ln_log(LNLOG_SERR, LNLOG_CGROUP,
645 "error: write() for .overview failed: %m");
646 va = 0;
647 break;
648 }
649 }
650 }
651 if (fchmod(wfd, 0664)) va = 0;
652 if (fsync(wfd)) va = 0;
653 if (close(wfd)) va = 0;
654 if (va) {
655 if (rename(newfile, ".overview")) {
656 if (unlink(newfile))
657 ln_log(LNLOG_SERR, LNLOG_CGROUP,
658 "error: unlink(%s) failed: %m", newfile);
659 else
660 ln_log(LNLOG_SERR, LNLOG_CGROUP,
661 "error: rename(%s/%s, .overview) failed: %m",
662 tt, newfile);
663 } else {
664 if (debugmode)
665 syslog(LOG_DEBUG, "wrote %s/.overview", tt);
666 }
667 } else {
668 unlink(newfile);
669 /* the group must be newly empty: I want to keep the old
670 .overview file I think */
671 }
672 } else {
673 ln_log(LNLOG_SERR, LNLOG_CGROUP,
674 "error: mkstemp of new .overview failed: %m");
675 }
676 }
677
678 closedir(d);
679 free(tt);
680 if (overview) {
681 free(overview);
682 }
683 return 1;
684 }
685
686 void
687 fixxover(void)
688 {
689 DIR *d;
690 struct dirent *de;
691 char s[SIZE_s + 1];
692
693 xsnprintf(s, SIZE_s, "%s/interesting.groups", spooldir);
694 d = opendir(s);
695 if (!d) {
696 ln_log(LNLOG_SERR, LNLOG_CGROUP, "error: opendir %s: %m", s);
697 return;
698 }
699
700 while ((de = readdir(d))) {
701 if (isalnum((unsigned char)*(de->d_name)) && findgroup(de->d_name)) {
702 if (chdirgroup(de->d_name, FALSE))
703 getxover();
704 freexover();
705 }
706 }
707 closedir(d);
708 }