1 /* Copyright (C) 2000-2016 Boris Wesslowski */
2 /* $Id: modes.c 741 2016-02-19 14:35:50Z bw $ */
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <sys/time.h>
9 #include <errno.h>
10 #include <pwd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <syslog.h>
15 #include <signal.h>
16
17 #ifdef HAVE_ZLIB
18 #include <zlib.h>
19 #endif
20
21 #ifdef HAVE_ADNS
22 #include <adns.h>
23 #endif
24
25 #include "parser.h"
26 #include "output.h"
27 #include "compare.h"
28 #include "response.h"
29 #include "utils.h"
30 #include "net.h"
31 #include "whois.h"
32 #include "rcfile.h"
33
34 #ifdef HAVE_ADNS
35 #include "resolve.h"
36 #endif
37
38 extern struct options opt;
39 extern struct conn_data *first;
40 extern struct input_file *first_file;
41
42 #ifdef HAVE_ADNS
43 extern adns_state adns;
44 #endif
45
common_input_loop(int * linenum,int * hitnum,int * errnum,int * oldnum,int * exnum)46 void common_input_loop(int *linenum, int *hitnum, int *errnum, int *oldnum, int *exnum)
47 {
48 char buf[BUFSIZE];
49 int retval, hit = 0;
50
51 #ifdef HAVE_ZLIB
52 if ((opt.std_in) || (opt.mode == REALTIME_RESPONSE)) {
53 #endif
54 retval = (fgets(buf, BUFSIZE, opt.inputfd) != NULL);
55 #ifdef HAVE_ZLIB
56 } else {
57 retval = (gzgets(opt.gzinputfd, buf, BUFSIZE) != Z_NULL);
58 }
59 #endif
60
61 while (retval) {
62 *linenum += 1;
63 hit = parse_line(buf, *linenum);
64 opt.repeated = 0;
65 switch (hit) {
66 case PARSE_OK:
67 *hitnum += 1;
68 opt.repeated = 1;
69 break;
70 case PARSE_WRONG_FORMAT:
71 *errnum += 1;
72 break;
73 case PARSE_TOO_OLD:
74 *oldnum += 1;
75 break;
76 case PARSE_EXCLUDED:
77 *hitnum += 1;
78 *exnum += 1;
79 }
80
81 #ifdef HAVE_ZLIB
82 if ((opt.std_in) || (opt.mode == REALTIME_RESPONSE)) {
83 #endif
84 retval = (fgets(buf, BUFSIZE, opt.inputfd) != NULL);
85 #ifdef HAVE_ZLIB
86 } else {
87 retval = (gzgets(opt.gzinputfd, buf, BUFSIZE) != Z_NULL);
88 }
89 #endif
90 }
91 }
92
mode_summary()93 void mode_summary()
94 {
95 char nows[TIMESIZE], first_entry[TIMESIZE], last_entry[TIMESIZE], *input = NULL, last_file = 0;
96 FILE *output = NULL;
97 int retval, linenum = 0, hitnum = 0, errnum = 0, old_errnum = 0, oldnum = 0, exnum = 0;
98 time_t now;
99 struct passwd *gen_user;
100 struct input_file *file;
101
102 opt.line = xmalloc(sizeof(struct log_line));
103
104 file = first_file;
105 while (last_file == 0) {
106 if (opt.std_in) {
107 if (opt.verbose)
108 fprintf(stderr, _("Using stdin as input\n"));
109
110 opt.inputfd = stdin;
111 } else {
112 input = file->name;
113 if (opt.verbose)
114 fprintf(stderr, _("Opening input file '%s'\n"), input);
115
116 #ifdef HAVE_ZLIB
117 opt.gzinputfd = gzopen(input, "rb");
118 if (opt.gzinputfd == NULL) {
119 fprintf(stderr, "gzopen %s: %s\n", input, strerror(errno));
120 #else
121 opt.inputfd = fopen(input, "r");
122 if (opt.inputfd == NULL) {
123 fprintf(stderr, "fopen %s: %s\n", input, strerror(errno));
124 #endif
125 exit(EXIT_FAILURE);
126 }
127 }
128
129 if (opt.verbose)
130 fprintf(stderr, _("Processing\n"));
131
132 common_input_loop(&linenum, &hitnum, &errnum, &oldnum, &exnum);
133
134 if (opt.verbose == 2)
135 fprintf(stderr, "\n");
136 if (opt.verbose && (errnum > old_errnum)) {
137 fprintf(stderr, _("Unrecognized entries or tokens can be submitted at\n"));
138 fprintf(stderr, "http://fwlogwatch.inside-security.de/unrecognized.php\n");
139 old_errnum = errnum;
140 }
141
142 if (opt.std_in) {
143 last_file++;
144 } else {
145 if (opt.verbose)
146 fprintf(stderr, _("Closing '%s'\n"), input);
147
148 #ifndef HAVE_ZLIB
149 retval = fclose(opt.inputfd);
150 if (retval == EOF) {
151 perror("fclose");
152 #else
153 retval = gzclose(opt.gzinputfd);
154 if (retval != 0) {
155 if (retval != Z_ERRNO) {
156 fprintf(stderr, "gzclose %s: %s\n", input, gzerror(opt.gzinputfd, &retval));
157 } else {
158 perror("gzclose");
159 }
160 #endif
161 exit(EXIT_FAILURE);
162 }
163
164 if (file->next != NULL) {
165 file = file->next;
166 } else {
167 last_file++;
168 }
169 }
170 }
171
172 free(opt.line);
173
174 if (opt.verbose)
175 fprintf(stderr, _("Sorting data\n"));
176
177 if (first != NULL) {
178 time_t last_time;
179 struct conn_data *p;
180
181 opt.sortfield = SORT_END_TIME;
182 opt.sortmode = ORDER_DESCENDING;
183 first = fwlw_pc_mergesort(first);
184 if (opt.verbose == 2)
185 fprintf(stderr, ".");
186 last_time = first->end_time;
187
188 opt.sortfield = SORT_START_TIME;
189 opt.sortmode = ORDER_ASCENDING;
190 first = fwlw_pc_mergesort(first);
191 if (opt.verbose == 2)
192 fprintf(stderr, ".");
193 strftime(first_entry, TIMESIZE, _("%b %d %H:%M:%S"), localtime(&first->start_time));
194
195 p = first;
196 while (p->next != NULL)
197 p = p->next;
198 if (p->start_time > last_time)
199 last_time = p->start_time;
200 strftime(last_entry, TIMESIZE, _("%b %d %H:%M:%S"), localtime(&last_time));
201 } else {
202 first_entry[0] = '\0';
203 }
204
205 sort_data(SORT_PC);
206
207 if (opt.verbose == 2)
208 fprintf(stderr, "\n");
209
210 if (opt.use_out) {
211 if (opt.verbose)
212 fprintf(stderr, _("Opening output file '%s'\n"), opt.outputfile);
213
214 output = freopen(opt.outputfile, "w", stdout);
215 if (output == NULL) {
216 fprintf(stderr, "freopen %s: %s\n", opt.outputfile, strerror(errno));
217 exit(EXIT_FAILURE);
218 }
219 } else if (opt.recipient[0] != '\0') {
220 char buf[BUFSIZE];
221
222 if (opt.verbose)
223 fprintf(stderr, _("Sending\n"));
224
225 snprintf(buf, BUFSIZE, "%s -t", P_SENDMAIL);
226 output = popen(buf, "w");
227 if (output == NULL) {
228 perror("popen");
229 exit(EXIT_FAILURE);
230 }
231
232 generate_email_header(output);
233 fflush(output);
234 } else {
235 output = stdout;
236 }
237
238 if (opt.html) {
239 output_html_header(fileno(output));
240 fprintf(output, "<p>\n");
241 } else {
242 fprintf(output, "%s\n", opt.title);
243 }
244
245 now = time(NULL);
246 strftime(nows, TIMESIZE, _("%A %B %d %H:%M:%S %Z %Y"), localtime(&now));
247 fprintf(output, _("Generated %s by "), nows);
248
249 gen_user = getpwuid(getuid());
250 if (gen_user != NULL) {
251 if (gen_user->pw_gecos[0] != '\0') {
252 fprintf(output, "%s.\n", gen_user->pw_gecos);
253 } else {
254 fprintf(output, "%s.\n", gen_user->pw_name);
255 }
256 } else {
257 fprintf(output, _("an unknown user.\n"));
258 }
259
260 if (opt.html)
261 fprintf(output, "<br />\n");
262
263 fprintf(output, "%d ", hitnum);
264 if (oldnum > 0) {
265 fprintf(output, _("(and %d older than %d seconds) "), oldnum, opt.recent);
266 }
267 if (errnum > 0) {
268 fprintf(output, _("(and %d malformed) "), errnum);
269 }
270 if (opt.filecount == 1) {
271 fprintf(output, _("of %d entries in the file \"%s\" are packet logs, "), linenum, input);
272 } else if (opt.filecount == 0) {
273 fprintf(output, _("of %d entries in standard input are packet logs, "), linenum);
274 } else {
275 fprintf(output, _("of %d entries in %d input files are packet logs, "), linenum, opt.filecount);
276 }
277 retval = list_stats();
278 if (retval == 1) {
279 fprintf(output, _("one has unique characteristics.\n"));
280 } else {
281 fprintf(output, _("%d have unique characteristics.\n"), retval);
282 }
283
284 if (exnum != 0) {
285 if (opt.html)
286 fprintf(output, "<br />\n");
287
288 if (exnum == 1) {
289 fprintf(output, _("One entry was excluded by configuration.\n"));
290 } else {
291 fprintf(output, _("%d entries were excluded by configuration.\n"), exnum);
292 }
293 }
294
295 if (opt.html)
296 fprintf(output, "<br />\n");
297
298 if (first_entry[0] != '\0') {
299 fprintf(output, _("First packet log entry: %s, last: %s.\n"), first_entry, last_entry);
300 } else {
301 fprintf(output, _("No valid time entries found.\n"));
302 }
303
304 if (!opt.loghost) {
305 if (opt.html)
306 fprintf(output, "<br />\n");
307
308 fprintf(output, _("All entries were logged by the same host: \"%s\".\n"), opt.hostname);
309 }
310
311 if (!opt.chains) {
312 if (opt.html)
313 fprintf(output, "<br />\n");
314
315 fprintf(output, _("All entries are from the same chain: \"%s\".\n"), opt.chainlabel);
316 }
317
318 if (!opt.branches) {
319 if (opt.html)
320 fprintf(output, "<br />\n");
321
322 fprintf(output, _("All entries have the same target: \"%s\".\n"), opt.branchname);
323 }
324
325 if (!opt.ifs) {
326 if (opt.html)
327 fprintf(output, "<br />\n");
328
329 fprintf(output, _("All entries are from the same interface: \"%s\".\n"), opt.interface);
330 }
331
332 if (opt.least > 1) {
333 if (opt.html)
334 fprintf(output, "<br />\n");
335
336 fprintf(output, _("Only entries with a count of at least %d are shown.\n"), opt.least);
337 }
338
339 if (opt.max) {
340 if (opt.html)
341 fprintf(output, "<br />\n");
342
343 fprintf(output, _("Only the top %d entries are shown.\n"), opt.max);
344 }
345
346 if (opt.html)
347 output_html_table(output);
348 else
349 fprintf(output, "\n");
350
351 #ifdef HAVE_ADNS
352 if (opt.resolve) {
353 if (opt.verbose)
354 fprintf(stderr, _("Resolving\n"));
355
356 retval = adns_init(&adns, adns_if_none, 0);
357 if (retval) {
358 perror("adns_init");
359 exit(EXIT_FAILURE);
360 }
361 adns_preresolve(RES_ADNS_PC);
362 }
363 #endif
364
365 if (opt.whois_lookup)
366 whois_connect(RADB);
367
368 show_list(output);
369 fflush(output);
370
371 if (opt.whois_lookup)
372 whois_close();
373
374 #ifdef HAVE_ADNS
375 if (opt.resolve)
376 adns_finish(adns);
377 #endif
378
379 if (opt.html) {
380 fprintf(output, "</table>\n");
381 fflush(output);
382 output_html_footer(fileno(output));
383 }
384
385 free_conn_data();
386 free_dns_cache();
387 free_whois();
388 free_exclude_data();
389 free_input_file();
390
391 if (opt.use_out) {
392 if (opt.verbose)
393 fprintf(stderr, _("Closing '%s'\n"), opt.outputfile);
394
395 retval = fclose(output);
396 if (retval == EOF) {
397 perror("fclose");
398 }
399 } else if (opt.recipient[0] != '\0') {
400 retval = pclose(output);
401 if (retval == -1) {
402 perror("pclose");
403 }
404 }
405 }
406
407 void check_pidfile()
408 {
409 struct stat *sbuf;
410
411 sbuf = xmalloc(sizeof(struct stat));
412 if (stat(opt.pidfile, sbuf) != -1) {
413 fprintf(stderr, _("Warning: pidfile exists, another fwlogwatch might be running.\n"));
414 } else {
415 if ((errno != ENOENT) && (errno != EACCES)) {
416 fprintf(stderr, "stat %s: %d, %s\n", opt.pidfile, errno, strerror(errno));
417 exit(EXIT_FAILURE);
418 }
419 }
420 free(sbuf);
421 }
422
423 void mode_rt_response_reread_conf()
424 {
425 free_exclude_data();
426 if (read_rcfile(opt.rcfile, MAY_NOT_EXIST, RCFILE_CF) == EXIT_SUCCESS) {
427 syslog(LOG_NOTICE, _("SIGHUP caught, reread configuration file %s"), opt.rcfile);
428 } else {
429 syslog(LOG_NOTICE, _("SIGHUP caught, unable to reread configuration file %s"), opt.rcfile);
430 }
431 if (opt.rcfile_dns[0] != '\0') {
432 if (read_rcfile(opt.rcfile_dns, MAY_NOT_EXIST, RCFILE_DNS) == EXIT_SUCCESS) {
433 syslog(LOG_NOTICE, _("Reread DNS cache file %s"), opt.rcfile_dns);
434 } else {
435 syslog(LOG_NOTICE, _("Unable to reread DNS cache file %s"), opt.rcfile_dns);
436 }
437 }
438 signal(SIGHUP, mode_rt_response_reread_conf);
439 }
440
441 void mode_rt_response_open()
442 {
443 if (opt.std_in) {
444 opt.inputfd = stdin;
445 } else {
446 opt.inputfd = fopen(first_file->name, "r");
447 if (opt.inputfd == NULL) {
448 syslog(LOG_NOTICE, "fopen %s: %s", first_file->name, strerror(errno));
449 log_exit(EXIT_FAILURE);
450 }
451 }
452 }
453
454 void mode_rt_response_reopen_log()
455 {
456 int retval;
457
458 if (opt.std_in) {
459 syslog(LOG_NOTICE, _("SIGUSR1 caught, reading input from stdin, no need to reopen log file"));
460 } else {
461 syslog(LOG_NOTICE, _("SIGUSR1 caught, reopening log file %s"), first_file->name);
462
463 retval = fclose(opt.inputfd);
464 if (retval == EOF)
465 syslog(LOG_NOTICE, "fclose %s: %s", first_file->name, strerror(errno));
466
467 mode_rt_response_open();
468 signal(SIGUSR1, mode_rt_response_reopen_log);
469 }
470 }
471
472 void mode_rt_response_core()
473 {
474 int retval, linenum = 0, hitnum = 0, ignored = 0;
475 struct stat info;
476 off_t size = 0;
477 fd_set rfds;
478 struct timeval tv;
479
480 if ((!opt.std_in) && (!opt.stateful_start)) {
481 retval = fstat(fileno(opt.inputfd), &info);
482 if (retval == -1) {
483 syslog(LOG_NOTICE, "fstat %s: %s", first_file->name, strerror(errno));
484 log_exit(EXIT_FAILURE);
485 }
486 size = info.st_size;
487 }
488
489 opt.line = xmalloc(sizeof(struct log_line));
490
491 while (1) {
492 if (opt.status) {
493 FD_ZERO(&rfds);
494 FD_SET(opt.sock, &rfds);
495 tv.tv_sec = 1;
496 tv.tv_usec = 0;
497 retval = select(opt.sock + 1, &rfds, NULL, NULL, &tv);
498 if (retval == -1) {
499 if (errno != EINTR) {
500 syslog(LOG_NOTICE, "select: %s", strerror(errno));
501 exit(EXIT_FAILURE);
502 }
503 }
504 if (retval > 0) {
505 handshake(linenum, hitnum, ignored);
506 }
507 } else {
508 sleep(1);
509 }
510
511 remove_old(RESP_REMOVE_OPC | RESP_REMOVE_OHS);
512 if (opt.std_in) {
513 common_input_loop(&linenum, &hitnum, &ignored, &ignored, &ignored);
514 look_for_alert();
515 } else {
516 retval = fstat(fileno(opt.inputfd), &info);
517 if (retval == -1) {
518 syslog(LOG_NOTICE, "fstat %s: %s", first_file->name, strerror(errno));
519 log_exit(EXIT_FAILURE);
520 }
521 if (size != info.st_size) {
522 size = info.st_size;
523 clearerr(opt.inputfd);
524 common_input_loop(&linenum, &hitnum, &ignored, &ignored, &ignored);
525 look_for_alert();
526 }
527 }
528 }
529 }
530
531 void mode_rt_response_terminate()
532 {
533 syslog(LOG_NOTICE, _("SIGTERM caught, cleaning up"));
534 free_hosts();
535 if (opt.response & OPT_RESPOND)
536 modify_firewall(FW_STOP);
537 log_exit(EXIT_SUCCESS);
538 }
539
540 void mode_rt_response()
541 {
542 int retval;
543 FILE *pidfile;
544 #ifndef RR_DEBUG
545 pid_t pid;
546
547 if (opt.pidfile[0] != '\0')
548 check_pidfile();
549
550 pid = fork();
551 if (pid == -1) {
552 perror("fork");
553 exit(EXIT_FAILURE);
554 }
555 if (pid != 0) {
556 _exit(EXIT_SUCCESS);
557 }
558 pid = setsid();
559 if (pid == -1) {
560 perror("setsid");
561 exit(EXIT_FAILURE);
562 }
563 pid = fork();
564 if (pid == -1) {
565 perror("fork");
566 exit(EXIT_FAILURE);
567 }
568 if (pid != 0) {
569 _exit(EXIT_SUCCESS);
570 }
571 retval = chdir("/");
572 if (retval == -1) {
573 perror("chdir");
574 exit(EXIT_FAILURE);
575 }
576 /* umask() */
577 retval = close(2);
578 if (retval == -1) {
579 perror("close");
580 exit(EXIT_FAILURE);
581 }
582 retval = close(1);
583 if (retval == -1) {
584 perror("close");
585 exit(EXIT_FAILURE);
586 }
587 if (!opt.std_in) {
588 retval = close(0);
589 if (retval == -1) {
590 perror("close");
591 exit(EXIT_FAILURE);
592 }
593 }
594 retval = open("/dev/null", O_RDWR);
595 if (retval == -1) {
596 perror("open");
597 exit(EXIT_FAILURE);
598 }
599 retval = dup(0);
600 if (retval == -1) {
601 perror("dup");
602 exit(EXIT_FAILURE);
603 }
604 if (!opt.std_in) {
605 retval = dup(0);
606 if (retval == -1) {
607 perror("dup");
608 exit(EXIT_FAILURE);
609 }
610 }
611 openlog("fwlogwatch", LOG_CONS, LOG_DAEMON);
612 #else
613 openlog("fwlogwatch", LOG_CONS | LOG_PERROR, LOG_DAEMON);
614 #endif
615 syslog(LOG_NOTICE, _("Starting (pid %d)"), getpid());
616
617 signal(SIGTERM, mode_rt_response_terminate);
618
619 if (opt.pidfile[0] != '\0') {
620 pidfile = fopen(opt.pidfile, "w");
621 if (pidfile == NULL) {
622 syslog(LOG_NOTICE, "fopen %s: %s\n", opt.pidfile, strerror(errno));
623 } else {
624 fprintf(pidfile, "%d\n", (int) getpid());
625 retval = fclose(pidfile);
626 if (retval == EOF) {
627 syslog(LOG_NOTICE, "fclose %s: %s\n", opt.pidfile, strerror(errno));
628 }
629 }
630 }
631
632 if (opt.status) {
633 prepare_socket();
634 #ifdef HAVE_ADNS
635 if (opt.resolve) {
636 retval = adns_init(&adns, adns_if_none, 0);
637 if (retval) {
638 syslog(LOG_NOTICE, "adns_init: %s", strerror(errno));
639 log_exit(EXIT_FAILURE);
640 }
641 }
642 #endif
643 }
644
645 if ((opt.ipchains_check == 1) && ((opt.format & PARSER_IPCHAINS) != 0))
646 check_for_ipchains();
647
648 if ((opt.response & OPT_NOTIFY) != 0)
649 check_script_perms(opt.notify_script);
650
651 if ((opt.response & OPT_RESPOND) != 0) {
652 check_script_perms(opt.respond_script);
653 modify_firewall(FW_START);
654 }
655
656 mode_rt_response_open();
657
658 if (opt.run_as[0] != '\0') {
659 uid_t olduid;
660 gid_t oldgid;
661 struct passwd *pwe;
662
663 pwe = getpwnam(opt.run_as);
664 if (pwe == NULL) {
665 syslog(LOG_NOTICE, _("User to run as was not found"));
666 log_exit(EXIT_FAILURE);
667 }
668 olduid = getuid();
669 oldgid = getgid();
670 retval = setgid(pwe->pw_gid);
671 if (retval == -1) {
672 syslog(LOG_NOTICE, "setgid: %s", strerror(errno));
673 log_exit(EXIT_FAILURE);
674 }
675 retval = setuid(pwe->pw_uid);
676 if (retval == -1) {
677 syslog(LOG_NOTICE, "setuid: %s", strerror(errno));
678 log_exit(EXIT_FAILURE);
679 }
680 syslog(LOG_NOTICE, _("Changed uid from %d to %d, gid from %d to %d"), olduid, getuid(), oldgid, getgid());
681 } else {
682 syslog(LOG_NOTICE, _("Running with uid %d, gid %d"), getuid(), getgid());
683 }
684
685 if (opt.threshold == 1) {
686 syslog(LOG_NOTICE, _("Alert threshold is one attempt"));
687 } else {
688 syslog(LOG_NOTICE, _("Alert threshold is %d attempts"), opt.threshold);
689 }
690
691 if (opt.recent < 3600) {
692 syslog(LOG_NOTICE, _("Events older than %d second(s) are discarded"), opt.recent);
693 } else {
694 syslog(LOG_NOTICE, _("Events older than %d hour(s) are discarded"), opt.recent / 3600);
695 }
696
697 syslog(LOG_NOTICE, _("Response mode: Log%s%s"), (opt.response & OPT_NOTIFY) ? _(", notify") : "", (opt.response & OPT_RESPOND) ? _(", respond") : "");
698
699 if ((!opt.std_in) && (!opt.stateful_start)) {
700 retval = fseek(opt.inputfd, 0, SEEK_END);
701 if (retval == -1) {
702 syslog(LOG_NOTICE, "fseek %s: %s", first_file->name, strerror(errno));
703 log_exit(EXIT_FAILURE);
704 }
705 }
706
707 signal(SIGHUP, mode_rt_response_reread_conf);
708 signal(SIGUSR1, mode_rt_response_reopen_log);
709 mode_rt_response_core();
710 }
711
712 void mode_show_log_times()
713 {
714 char buf[BUFSIZE], stime[TIMESIZE], month[4], *input = NULL, last_file = 0;
715 int retval = 0, loop, hour, minute, second, linenum = 0;
716 unsigned int day;
717 struct input_file *file;
718 time_t first = 0, last = 0;
719
720 opt.line = xmalloc(sizeof(struct log_line));
721
722 file = first_file;
723 while (last_file == 0) {
724 if (opt.std_in) {
725 opt.inputfd = stdin;
726
727 if (opt.verbose)
728 fprintf(stderr, _("Reading standard input\n"));
729 } else {
730 input = file->name;
731 #ifdef HAVE_ZLIB
732 opt.gzinputfd = gzopen(input, "rb");
733 if (opt.gzinputfd == NULL) {
734 fprintf(stderr, "gzopen %s: %s\n", input, strerror(errno));
735 #else
736 opt.inputfd = fopen(input, "r");
737 if (opt.inputfd == NULL) {
738 fprintf(stderr, "fopen %s: %s\n", input, strerror(errno));
739 #endif
740 exit(EXIT_FAILURE);
741 }
742
743 if (opt.verbose)
744 fprintf(stderr, _("Reading '%s'\n"), input);
745 }
746
747 #ifdef HAVE_ZLIB
748 if (opt.std_in) {
749 #endif
750 loop = (fgets(buf, BUFSIZE, opt.inputfd) != NULL);
751 #ifdef HAVE_ZLIB
752 } else {
753 loop = (gzgets(opt.gzinputfd, buf, BUFSIZE) != Z_NULL);
754 }
755 #endif
756
757 while (loop) {
758 linenum++;
759 retval = sscanf(buf, "%3s %u %2d:%2d:%2d ", month, &day, &hour, &minute, &second);
760 if (retval == 5) {
761 build_time(month, day, hour, minute, second);
762 if (first == 0)
763 first = last = opt.line->time;
764 if (opt.line->time < first)
765 first = opt.line->time;
766 if (opt.line->time > last)
767 last = opt.line->time;
768 }
769 #ifdef HAVE_ZLIB
770 if (opt.std_in) {
771 #endif
772 loop = (fgets(buf, BUFSIZE, opt.inputfd) != NULL);
773 #ifdef HAVE_ZLIB
774 } else {
775 loop = (gzgets(opt.gzinputfd, buf, BUFSIZE) != Z_NULL);
776 }
777 #endif
778 }
779
780 if (opt.std_in) {
781 last_file++;
782 } else {
783 if (opt.verbose)
784 fprintf(stderr, _("Closing '%s'\n"), input);
785
786 #ifndef HAVE_ZLIB
787 retval = fclose(opt.inputfd);
788 if (retval == EOF) {
789 perror("fclose");
790 #else
791 retval = gzclose(opt.gzinputfd);
792 if (retval != 0) {
793 if (retval != Z_ERRNO) {
794 fprintf(stderr, "gzclose %s: %s\n", input, gzerror(opt.gzinputfd, &retval));
795 } else {
796 perror("gzclose");
797 }
798 #endif
799 exit(EXIT_FAILURE);
800 }
801
802 if (file->next != NULL) {
803 file = file->next;
804 } else {
805 last_file++;
806 }
807 }
808 }
809
810 printf(_("Number of files: %d\n"), opt.filecount);
811 printf(_("Number of lines: %d\n"), linenum);
812 if (first == 0) {
813 printf(_("No valid time entries found.\n"));
814 } else {
815 strftime(stime, TIMESIZE, _("%b %d %H:%M:%S"), localtime(&first));
816 printf(_("First entry: %s\n"), stime);
817 strftime(stime, TIMESIZE, _("%b %d %H:%M:%S"), localtime(&last));
818 printf(_("Last entry : %s\n"), stime);
819 output_timediff(first, last, stime);
820 printf(_("Difference : %s\n"), stime);
821 }
822
823 free(opt.line);
824 }
825