]> git.ipfire.org Git - thirdparty/squid.git/blob - src/log/ModStdio.cc
c5b0faa898150bf321708c098eec5125eefafdaa
[thirdparty/squid.git] / src / log / ModStdio.cc
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
9 /* DEBUG: section 50 Log file handling */
10
11 #include "squid.h"
12 #include "disk.h"
13 #include "fd.h"
14 #include "fde.h"
15 #include "globals.h"
16 #include "log/File.h"
17 #include "log/ModStdio.h"
18 #include "SquidConfig.h"
19
20 #include <cerrno>
21
22 typedef struct {
23 int fd;
24 char *buf;
25 size_t bufsz;
26 int offset;
27 } l_stdio_t;
28
29 /*
30 * Aborts with fatal message if write() returns something other
31 * than its length argument.
32 */
33 static void
34 logfileWriteWrapper(Logfile * lf, const void *buf, size_t len)
35 {
36 l_stdio_t *ll = (l_stdio_t *) lf->data;
37 size_t s;
38 s = FD_WRITE_METHOD(ll->fd, (char const *) buf, len);
39 fd_bytes(ll->fd, s, FD_WRITE);
40
41 if (s == len)
42 return;
43
44 if (!lf->flags.fatal)
45 return;
46
47 fatalf("logfileWrite: %s: %s\n", lf->path, xstrerror());
48 }
49
50 static void
51 logfile_mod_stdio_writeline(Logfile * lf, const char *buf, size_t len)
52 {
53 l_stdio_t *ll = (l_stdio_t *) lf->data;
54
55 if (0 == ll->bufsz) {
56 /* buffering disabled */
57 logfileWriteWrapper(lf, buf, len);
58 return;
59 }
60 if (ll->offset > 0 && (ll->offset + len) > ll->bufsz)
61 logfileFlush(lf);
62
63 if (len > ll->bufsz) {
64 /* too big to fit in buffer */
65 logfileWriteWrapper(lf, buf, len);
66 return;
67 }
68 /* buffer it */
69 memcpy(ll->buf + ll->offset, buf, len);
70
71 ll->offset += len;
72
73 assert(ll->offset >= 0);
74
75 assert((size_t) ll->offset <= ll->bufsz);
76 }
77
78 static void
79 logfile_mod_stdio_linestart(Logfile * lf)
80 {
81 }
82
83 static void
84 logfile_mod_stdio_lineend(Logfile * lf)
85 {
86 lf->f_flush(lf);
87 }
88
89 static void
90 logfile_mod_stdio_flush(Logfile * lf)
91 {
92 l_stdio_t *ll = (l_stdio_t *) lf->data;
93 if (0 == ll->offset)
94 return;
95 logfileWriteWrapper(lf, ll->buf, (size_t) ll->offset);
96 ll->offset = 0;
97 }
98
99 static void
100 logfile_mod_stdio_rotate(Logfile * lf)
101 {
102 #ifdef S_ISREG
103
104 struct stat sb;
105 #endif
106
107 int i;
108 char from[MAXPATHLEN];
109 char to[MAXPATHLEN];
110 l_stdio_t *ll = (l_stdio_t *) lf->data;
111 assert(lf->path);
112 const char *realpath = lf->path+6; // skip 'stdio:' prefix.
113 assert(realpath);
114
115 #ifdef S_ISREG
116
117 if (stat(realpath, &sb) == 0)
118 if (S_ISREG(sb.st_mode) == 0)
119 return;
120
121 #endif
122
123 debugs(0, DBG_IMPORTANT, "Rotate log file " << lf->path);
124
125 /* Rotate numbers 0 through N up one */
126 for (i = Config.Log.rotateNumber; i > 1;) {
127 --i;
128 snprintf(from, MAXPATHLEN, "%s.%d", realpath, i - 1);
129 snprintf(to, MAXPATHLEN, "%s.%d", realpath, i);
130 xrename(from, to);
131 }
132
133 /* Rotate the current log to .0 */
134 logfileFlush(lf);
135
136 file_close(ll->fd); /* always close */
137
138 if (Config.Log.rotateNumber > 0) {
139 snprintf(to, MAXPATHLEN, "%s.%d", realpath, 0);
140 xrename(realpath, to);
141 }
142 /* Reopen the log. It may have been renamed "manually" */
143 ll->fd = file_open(realpath, O_WRONLY | O_CREAT | O_TEXT);
144
145 if (DISK_ERROR == ll->fd && lf->flags.fatal) {
146 debugs(50, DBG_CRITICAL, "ERROR: logfileRotate: " << lf->path << ": " << xstrerror());
147 fatalf("Cannot open %s: %s", lf->path, xstrerror());
148 }
149 }
150
151 static void
152 logfile_mod_stdio_close(Logfile * lf)
153 {
154 l_stdio_t *ll = (l_stdio_t *) lf->data;
155 lf->f_flush(lf);
156
157 if (ll->fd >= 0)
158 file_close(ll->fd);
159
160 if (ll->buf)
161 xfree(ll->buf);
162
163 xfree(lf->data);
164 lf->data = NULL;
165 }
166
167 /*
168 * This code expects the path to be a writable filename
169 */
170 int
171 logfile_mod_stdio_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag)
172 {
173 lf->f_close = logfile_mod_stdio_close;
174 lf->f_linewrite = logfile_mod_stdio_writeline;
175 lf->f_linestart = logfile_mod_stdio_linestart;
176 lf->f_lineend = logfile_mod_stdio_lineend;
177 lf->f_flush = logfile_mod_stdio_flush;
178 lf->f_rotate = logfile_mod_stdio_rotate;
179
180 l_stdio_t *ll = static_cast<l_stdio_t*>(xcalloc(1, sizeof(*ll)));
181 lf->data = ll;
182
183 ll->fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
184
185 if (DISK_ERROR == ll->fd) {
186 if (ENOENT == errno && fatal_flag) {
187 fatalf("Cannot open '%s' because\n"
188 "\tthe parent directory does not exist.\n"
189 "\tPlease create the directory.\n", path);
190 } else if (EACCES == errno && fatal_flag) {
191 fatalf("Cannot open '%s' for writing.\n"
192 "\tThe parent directory must be writeable by the\n"
193 "\tuser '%s', which is the cache_effective_user\n"
194 "\tset in squid.conf.", path, Config.effectiveUser);
195 } else if (EISDIR == errno && fatal_flag) {
196 fatalf("Cannot open '%s' because it is a directory, not a file.\n", path);
197 } else {
198 debugs(50, DBG_IMPORTANT, "ERROR: logfileOpen " << lf->path << ": " << xstrerror());
199 return 0;
200 }
201 }
202 if (bufsz > 0) {
203 ll->buf = static_cast<char*>(xmalloc(bufsz));
204 ll->bufsz = bufsz;
205 }
206 return 1;
207 }