]> git.ipfire.org Git - thirdparty/squid.git/blob - src/log/ModStdio.cc
b4c5c720c83d4a67a4a224eae69aa613df165fcd
[thirdparty/squid.git] / src / log / ModStdio.cc
1 /*
2 * Copyright (C) 1996-2016 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 "fatal.h"
13 #include "fd.h"
14 #include "fde.h"
15 #include "fs_io.h"
16 #include "globals.h"
17 #include "log/File.h"
18 #include "log/ModStdio.h"
19 #include "SquidConfig.h"
20
21 #include <cerrno>
22
23 typedef 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 */
34 static void
35 logfileWriteWrapper(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 int xerrno = errno;
41 fd_bytes(ll->fd, s, FD_WRITE);
42
43 if (s == len)
44 return;
45
46 if (!lf->flags.fatal)
47 return;
48
49 fatalf("logfileWrite: %s: %s\n", lf->path, xstrerr(xerrno));
50 }
51
52 static void
53 logfile_mod_stdio_writeline(Logfile * lf, const char *buf, size_t len)
54 {
55 l_stdio_t *ll = (l_stdio_t *) lf->data;
56
57 if (0 == ll->bufsz) {
58 /* buffering disabled */
59 logfileWriteWrapper(lf, buf, len);
60 return;
61 }
62 if (ll->offset > 0 && (ll->offset + len) > ll->bufsz)
63 logfileFlush(lf);
64
65 if (len > ll->bufsz) {
66 /* too big to fit in buffer */
67 logfileWriteWrapper(lf, buf, len);
68 return;
69 }
70 /* buffer it */
71 memcpy(ll->buf + ll->offset, buf, len);
72
73 ll->offset += len;
74
75 assert(ll->offset >= 0);
76
77 assert((size_t) ll->offset <= ll->bufsz);
78 }
79
80 static void
81 logfile_mod_stdio_linestart(Logfile *)
82 {
83 }
84
85 static void
86 logfile_mod_stdio_lineend(Logfile * lf)
87 {
88 lf->f_flush(lf);
89 }
90
91 static void
92 logfile_mod_stdio_flush(Logfile * lf)
93 {
94 l_stdio_t *ll = (l_stdio_t *) lf->data;
95 if (0 == ll->offset)
96 return;
97 logfileWriteWrapper(lf, ll->buf, (size_t) ll->offset);
98 ll->offset = 0;
99 }
100
101 static void
102 logfile_mod_stdio_rotate(Logfile * lf, const int16_t nRotate)
103 {
104 #ifdef S_ISREG
105
106 struct stat sb;
107 #endif
108
109 char from[MAXPATHLEN];
110 char to[MAXPATHLEN];
111 l_stdio_t *ll = (l_stdio_t *) lf->data;
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 (int16_t i = nRotate; 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 (nRotate > 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 int xerrno = errno;
147 debugs(50, DBG_CRITICAL, MYNAME << "ERROR: " << lf->path << ": " << xstrerr(xerrno));
148 fatalf("Cannot open %s: %s", lf->path, xstrerr(xerrno));
149 }
150 }
151
152 static void
153 logfile_mod_stdio_close(Logfile * lf)
154 {
155 l_stdio_t *ll = (l_stdio_t *) lf->data;
156 lf->f_flush(lf);
157
158 if (ll->fd >= 0)
159 file_close(ll->fd);
160
161 if (ll->buf)
162 xfree(ll->buf);
163
164 xfree(lf->data);
165 lf->data = NULL;
166 }
167
168 /*
169 * This code expects the path to be a writable filename
170 */
171 int
172 logfile_mod_stdio_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag)
173 {
174 lf->f_close = logfile_mod_stdio_close;
175 lf->f_linewrite = logfile_mod_stdio_writeline;
176 lf->f_linestart = logfile_mod_stdio_linestart;
177 lf->f_lineend = logfile_mod_stdio_lineend;
178 lf->f_flush = logfile_mod_stdio_flush;
179 lf->f_rotate = logfile_mod_stdio_rotate;
180
181 l_stdio_t *ll = static_cast<l_stdio_t*>(xcalloc(1, sizeof(*ll)));
182 lf->data = ll;
183
184 ll->fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
185
186 if (DISK_ERROR == ll->fd) {
187 int xerrno = errno;
188 if (ENOENT == xerrno && fatal_flag) {
189 fatalf("Cannot open '%s' because\n"
190 "\tthe parent directory does not exist.\n"
191 "\tPlease create the directory.\n", path);
192 } else if (EACCES == xerrno && fatal_flag) {
193 fatalf("Cannot open '%s' for writing.\n"
194 "\tThe parent directory must be writeable by the\n"
195 "\tuser '%s', which is the cache_effective_user\n"
196 "\tset in squid.conf.", path, Config.effectiveUser);
197 } else if (EISDIR == xerrno && fatal_flag) {
198 fatalf("Cannot open '%s' because it is a directory, not a file.\n", path);
199 } else {
200 debugs(50, DBG_IMPORTANT, MYNAME << "ERROR: " << lf->path << ": " << xstrerr(xerrno));
201 return 0;
202 }
203 }
204 if (bufsz > 0) {
205 ll->buf = static_cast<char*>(xmalloc(bufsz));
206 ll->bufsz = bufsz;
207 }
208 return 1;
209 }
210