]>
Commit | Line | Data |
---|---|---|
82b7abe3 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 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 |
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); | |
b69e9ffa | 40 | int xerrno = errno; |
82b7abe3 AJ |
41 | fd_bytes(ll->fd, s, FD_WRITE); |
42 | ||
43 | if (s == len) | |
9d65168e | 44 | return; |
82b7abe3 AJ |
45 | |
46 | if (!lf->flags.fatal) | |
9d65168e | 47 | return; |
82b7abe3 | 48 | |
b69e9ffa | 49 | fatalf("logfileWrite: %s: %s\n", lf->path, xstrerr(xerrno)); |
82b7abe3 AJ |
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) { | |
9d65168e A |
58 | /* buffering disabled */ |
59 | logfileWriteWrapper(lf, buf, len); | |
60 | return; | |
82b7abe3 AJ |
61 | } |
62 | if (ll->offset > 0 && (ll->offset + len) > ll->bufsz) | |
9d65168e | 63 | logfileFlush(lf); |
82b7abe3 AJ |
64 | |
65 | if (len > ll->bufsz) { | |
9d65168e A |
66 | /* too big to fit in buffer */ |
67 | logfileWriteWrapper(lf, buf, len); | |
68 | return; | |
82b7abe3 AJ |
69 | } |
70 | /* buffer it */ | |
41d00cd3 | 71 | memcpy(ll->buf + ll->offset, buf, len); |
82b7abe3 AJ |
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 | |
ced8def3 | 81 | logfile_mod_stdio_linestart(Logfile *) |
82b7abe3 AJ |
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) | |
9d65168e | 96 | return; |
82b7abe3 AJ |
97 | logfileWriteWrapper(lf, ll->buf, (size_t) ll->offset); |
98 | ll->offset = 0; | |
99 | } | |
100 | ||
101 | static void | |
efc23871 | 102 | logfile_mod_stdio_rotate(Logfile * lf, const int16_t nRotate) |
82b7abe3 AJ |
103 | { |
104 | #ifdef S_ISREG | |
105 | ||
106 | struct stat sb; | |
107 | #endif | |
108 | ||
82b7abe3 | 109 | l_stdio_t *ll = (l_stdio_t *) lf->data; |
8030a2a0 AJ |
110 | const char *realpath = lf->path+6; // skip 'stdio:' prefix. |
111 | assert(realpath); | |
82b7abe3 AJ |
112 | |
113 | #ifdef S_ISREG | |
114 | ||
8030a2a0 | 115 | if (stat(realpath, &sb) == 0) |
9d65168e A |
116 | if (S_ISREG(sb.st_mode) == 0) |
117 | return; | |
82b7abe3 AJ |
118 | |
119 | #endif | |
120 | ||
8030a2a0 | 121 | debugs(0, DBG_IMPORTANT, "Rotate log file " << lf->path); |
82b7abe3 | 122 | |
b56b37cf AJ |
123 | SBuf basePath(realpath); |
124 | ||
82b7abe3 | 125 | /* Rotate numbers 0 through N up one */ |
efc23871 | 126 | for (int16_t i = nRotate; i > 1;) { |
5e263176 | 127 | --i; |
b56b37cf AJ |
128 | SBuf from(basePath); |
129 | from.appendf(".%d", i-1); | |
130 | SBuf to(basePath); | |
131 | to.appendf(".%d", i); | |
132 | FileRename(from, to); | |
133 | // TODO handle rename errors | |
82b7abe3 AJ |
134 | } |
135 | ||
136 | /* Rotate the current log to .0 */ | |
137 | logfileFlush(lf); | |
138 | ||
f53969cc | 139 | file_close(ll->fd); /* always close */ |
82b7abe3 | 140 | |
efc23871 | 141 | if (nRotate > 0) { |
b56b37cf AJ |
142 | SBuf to(basePath); |
143 | to.appendf(".0"); | |
144 | FileRename(basePath, to); | |
145 | // TODO handle rename errors | |
82b7abe3 AJ |
146 | } |
147 | /* Reopen the log. It may have been renamed "manually" */ | |
8030a2a0 | 148 | ll->fd = file_open(realpath, O_WRONLY | O_CREAT | O_TEXT); |
82b7abe3 AJ |
149 | |
150 | if (DISK_ERROR == ll->fd && lf->flags.fatal) { | |
b69e9ffa AJ |
151 | int xerrno = errno; |
152 | debugs(50, DBG_CRITICAL, MYNAME << "ERROR: " << lf->path << ": " << xstrerr(xerrno)); | |
153 | fatalf("Cannot open %s: %s", lf->path, xstrerr(xerrno)); | |
82b7abe3 AJ |
154 | } |
155 | } | |
156 | ||
157 | static void | |
158 | logfile_mod_stdio_close(Logfile * lf) | |
159 | { | |
160 | l_stdio_t *ll = (l_stdio_t *) lf->data; | |
161 | lf->f_flush(lf); | |
162 | ||
163 | if (ll->fd >= 0) | |
9d65168e | 164 | file_close(ll->fd); |
82b7abe3 AJ |
165 | |
166 | if (ll->buf) | |
9d65168e | 167 | xfree(ll->buf); |
82b7abe3 AJ |
168 | |
169 | xfree(lf->data); | |
170 | lf->data = NULL; | |
171 | } | |
172 | ||
173 | /* | |
174 | * This code expects the path to be a writable filename | |
175 | */ | |
176 | int | |
177 | logfile_mod_stdio_open(Logfile * lf, const char *path, size_t bufsz, int fatal_flag) | |
178 | { | |
179 | lf->f_close = logfile_mod_stdio_close; | |
180 | lf->f_linewrite = logfile_mod_stdio_writeline; | |
181 | lf->f_linestart = logfile_mod_stdio_linestart; | |
182 | lf->f_lineend = logfile_mod_stdio_lineend; | |
183 | lf->f_flush = logfile_mod_stdio_flush; | |
184 | lf->f_rotate = logfile_mod_stdio_rotate; | |
185 | ||
186 | l_stdio_t *ll = static_cast<l_stdio_t*>(xcalloc(1, sizeof(*ll))); | |
187 | lf->data = ll; | |
188 | ||
189 | ll->fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT); | |
190 | ||
191 | if (DISK_ERROR == ll->fd) { | |
b69e9ffa AJ |
192 | int xerrno = errno; |
193 | if (ENOENT == xerrno && fatal_flag) { | |
9d65168e A |
194 | fatalf("Cannot open '%s' because\n" |
195 | "\tthe parent directory does not exist.\n" | |
196 | "\tPlease create the directory.\n", path); | |
b69e9ffa | 197 | } else if (EACCES == xerrno && fatal_flag) { |
9d65168e A |
198 | fatalf("Cannot open '%s' for writing.\n" |
199 | "\tThe parent directory must be writeable by the\n" | |
200 | "\tuser '%s', which is the cache_effective_user\n" | |
201 | "\tset in squid.conf.", path, Config.effectiveUser); | |
b69e9ffa | 202 | } else if (EISDIR == xerrno && fatal_flag) { |
1d470d88 | 203 | fatalf("Cannot open '%s' because it is a directory, not a file.\n", path); |
9d65168e | 204 | } else { |
b69e9ffa | 205 | debugs(50, DBG_IMPORTANT, MYNAME << "ERROR: " << lf->path << ": " << xstrerr(xerrno)); |
9d65168e A |
206 | return 0; |
207 | } | |
82b7abe3 AJ |
208 | } |
209 | if (bufsz > 0) { | |
9d65168e A |
210 | ll->buf = static_cast<char*>(xmalloc(bufsz)); |
211 | ll->bufsz = bufsz; | |
82b7abe3 AJ |
212 | } |
213 | return 1; | |
214 | } | |
f53969cc | 215 |