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