]>
Commit | Line | Data |
---|---|---|
82b7abe3 | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 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" |
438b04d4 | 12 | #include "disk.h" |
ed6e9fb9 | 13 | #include "fatal.h" |
c4ad1349 | 14 | #include "fd.h" |
82b7abe3 | 15 | #include "fde.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 | |
101 | logfile_mod_stdio_rotate(Logfile * lf) | |
102 | { | |
103 | #ifdef S_ISREG | |
104 | ||
105 | struct stat sb; | |
106 | #endif | |
107 | ||
108 | int i; | |
109 | char from[MAXPATHLEN]; | |
110 | char to[MAXPATHLEN]; | |
111 | l_stdio_t *ll = (l_stdio_t *) lf->data; | |
8030a2a0 AJ |
112 | const char *realpath = lf->path+6; // skip 'stdio:' prefix. |
113 | assert(realpath); | |
82b7abe3 AJ |
114 | |
115 | #ifdef S_ISREG | |
116 | ||
8030a2a0 | 117 | if (stat(realpath, &sb) == 0) |
9d65168e A |
118 | if (S_ISREG(sb.st_mode) == 0) |
119 | return; | |
82b7abe3 AJ |
120 | |
121 | #endif | |
122 | ||
8030a2a0 | 123 | debugs(0, DBG_IMPORTANT, "Rotate log file " << lf->path); |
82b7abe3 AJ |
124 | |
125 | /* Rotate numbers 0 through N up one */ | |
126 | for (i = Config.Log.rotateNumber; i > 1;) { | |
5e263176 | 127 | --i; |
8030a2a0 AJ |
128 | snprintf(from, MAXPATHLEN, "%s.%d", realpath, i - 1); |
129 | snprintf(to, MAXPATHLEN, "%s.%d", realpath, i); | |
9d65168e | 130 | xrename(from, to); |
82b7abe3 AJ |
131 | } |
132 | ||
133 | /* Rotate the current log to .0 */ | |
134 | logfileFlush(lf); | |
135 | ||
f53969cc | 136 | file_close(ll->fd); /* always close */ |
82b7abe3 AJ |
137 | |
138 | if (Config.Log.rotateNumber > 0) { | |
8030a2a0 AJ |
139 | snprintf(to, MAXPATHLEN, "%s.%d", realpath, 0); |
140 | xrename(realpath, to); | |
82b7abe3 AJ |
141 | } |
142 | /* Reopen the log. It may have been renamed "manually" */ | |
8030a2a0 | 143 | ll->fd = file_open(realpath, O_WRONLY | O_CREAT | O_TEXT); |
82b7abe3 AJ |
144 | |
145 | if (DISK_ERROR == ll->fd && lf->flags.fatal) { | |
8030a2a0 | 146 | debugs(50, DBG_CRITICAL, "ERROR: logfileRotate: " << lf->path << ": " << xstrerror()); |
9d65168e | 147 | fatalf("Cannot open %s: %s", lf->path, xstrerror()); |
82b7abe3 AJ |
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) | |
9d65168e | 158 | file_close(ll->fd); |
82b7abe3 AJ |
159 | |
160 | if (ll->buf) | |
9d65168e | 161 | xfree(ll->buf); |
82b7abe3 AJ |
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) { | |
9d65168e A |
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); | |
1d470d88 AJ |
195 | } else if (EISDIR == errno && fatal_flag) { |
196 | fatalf("Cannot open '%s' because it is a directory, not a file.\n", path); | |
9d65168e | 197 | } else { |
8030a2a0 | 198 | debugs(50, DBG_IMPORTANT, "ERROR: logfileOpen " << lf->path << ": " << xstrerror()); |
9d65168e A |
199 | return 0; |
200 | } | |
82b7abe3 AJ |
201 | } |
202 | if (bufsz > 0) { | |
9d65168e A |
203 | ll->buf = static_cast<char*>(xmalloc(bufsz)); |
204 | ll->bufsz = bufsz; | |
82b7abe3 AJ |
205 | } |
206 | return 1; | |
207 | } | |
f53969cc | 208 |