]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/log_daemon/file/log_file_daemon.cc
Merge from trunk
[thirdparty/squid.git] / helpers / log_daemon / file / log_file_daemon.cc
1 #include "config.h"
2
3 #if HAVE_STDIO_H
4 #include <stdio.h>
5 #endif
6 #if HAVE_STDLIB_H
7 #include <stdlib.h>
8 #endif
9 #if HAVE_UNISTD_H
10 #include <unistd.h>
11 #endif
12 #if HAVE_FCNTL_H
13 #include <fcntl.h>
14 #endif
15 #if HAVE_ASSERT_H
16 #include <assert.h>
17 #endif
18 #if HAVE_SYS_PARAM_H
19 #include <sys/param.h>
20 #endif
21 #if HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #if HAVE_SIGNAL_H
25 #include <signal.h>
26 #endif
27 #if HAVE_ERRNO_H
28 #include <errno.h>
29 #endif
30 #if HAVE_STRING_H
31 #include <string.h>
32 #endif
33 #if HAVE_PATHS_H
34 #include <paths.h>
35 #endif
36
37 #include "defines.h"
38
39 /* parse buffer - ie, length of longest expected line */
40 #define LOGFILE_BUF_LEN 65536
41
42 static void
43 rotate(const char *path, int rotate_count)
44 {
45 #ifdef S_ISREG
46 struct stat sb;
47 #endif
48 int i;
49 char from[MAXPATHLEN];
50 char to[MAXPATHLEN];
51 assert(path);
52 #ifdef S_ISREG
53 if (stat(path, &sb) == 0)
54 if (S_ISREG(sb.st_mode) == 0)
55 return;
56 #endif
57 /* Rotate numbers 0 through N up one */
58 for (i = rotate_count; i > 1;) {
59 i--;
60 snprintf(from, MAXPATHLEN, "%s.%d", path, i - 1);
61 snprintf(to, MAXPATHLEN, "%s.%d", path, i);
62 #if defined(_SQUID_OS2_) || defined(_SQUID_WIN32_)
63 remove(to);
64 #endif
65 rename(from, to);
66 }
67 if (rotate_count > 0) {
68 snprintf(to, MAXPATHLEN, "%s.%d", path, 0);
69 #if defined(_SQUID_OS2_) || defined(_SQUID_WIN32_)
70 remove(to);
71 #endif
72 rename(path, to);
73 }
74 }
75
76 /**
77 * The commands:
78 *
79 * L<data>\n - logfile data
80 * R\n - rotate file
81 * T\n - truncate file
82 * O\n - repoen file
83 * F\n - flush file
84 * r<n>\n - set rotate count to <n>
85 * b<n>\n - 1 = buffer output, 0 = don't buffer output
86 */
87 int
88 main(int argc, char *argv[])
89 {
90 int t;
91 FILE *fp;
92 char buf[LOGFILE_BUF_LEN];
93 int rotate_count = 10;
94 int do_buffer = 1;
95
96 if (argc < 2) {
97 printf("Error: usage: %s <logfile>\n", argv[0]);
98 exit(1);
99 }
100 fp = fopen(argv[1], "a");
101 if (fp == NULL) {
102 perror("fopen");
103 exit(1);
104 }
105 setbuf(stdout, NULL);
106 close(2);
107 t = open(_PATH_DEVNULL, O_RDWR);
108 assert(t > -1);
109 dup2(t, 2);
110
111 while (fgets(buf, LOGFILE_BUF_LEN, stdin)) {
112 /* First byte indicates what we're logging! */
113 switch (buf[0]) {
114 case 'L':
115 if (buf[1] != '\0') {
116 fprintf(fp, "%s", buf + 1);
117 /* try to detect the 32-bit file too big write error and rotate */
118 int err = ferror(fp);
119 clearerr(fp);
120 if (err < 0) {
121 /* file too big - recover by rotating the logs and starting a new one.
122 * out of device space - recover by rotating and hoping that rotation count drops a big one.
123 */
124 if (err == EFBIG || err == ENOSPC) {
125 fprintf(stderr, "WARNING: %s writing %s. Attempting to recover via a log rotation.\n",strerror(err),argv[1]);
126 fclose(fp);
127 rotate(argv[1], rotate_count);
128 fp = fopen(argv[1], "a");
129 if (fp == NULL) {
130 perror("fopen");
131 exit(1);
132 }
133 fprintf(fp, "%s", buf + 1);
134 } else {
135 perror("fprintf");
136 exit(1);
137 }
138 }
139 }
140 if (!do_buffer)
141 fflush(fp);
142 break;
143 case 'R':
144 fclose(fp);
145 rotate(argv[1], rotate_count);
146 fp = fopen(argv[1], "a");
147 if (fp == NULL) {
148 perror("fopen");
149 exit(1);
150 }
151 break;
152 case 'T':
153 break;
154 case 'O':
155 break;
156 case 'r':
157 //fprintf(fp, "SET ROTATE: %s\n", buf + 1);
158 rotate_count = atoi(buf + 1);
159 break;
160 case 'b':
161 //fprintf(fp, "SET BUFFERED: %s\n", buf + 1);
162 do_buffer = (buf[1] == '1');
163 break;
164 case 'F':
165 fflush(fp);
166 break;
167 default:
168 /* Just in case .. */
169 fprintf(fp, "%s", buf);
170 break;
171 }
172 }
173 fclose(fp);
174 fp = NULL;
175 exit(0);
176 }