]>
Commit | Line | Data |
---|---|---|
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 |
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 | 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 | ||
51 | static void | |
52 | logfile_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 | ||
79 | static void | |
ced8def3 | 80 | logfile_mod_stdio_linestart(Logfile *) |
82b7abe3 AJ |
81 | { |
82 | } | |
83 | ||
84 | static void | |
85 | logfile_mod_stdio_lineend(Logfile * lf) | |
86 | { | |
87 | lf->f_flush(lf); | |
88 | } | |
89 | ||
90 | static void | |
91 | logfile_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 | ||
100 | static void | |
efc23871 | 101 | logfile_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 | ||
150 | static void | |
151 | logfile_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 | */ | |
169 | int | |
170 | logfile_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 |