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