2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 50 Log file handling */
18 #include "log/ModStdio.h"
19 #include "SquidConfig.h"
31 * Aborts with fatal message if write() returns something other
32 * than its length argument.
35 logfileWriteWrapper(Logfile
* lf
, const void *buf
, size_t len
)
37 l_stdio_t
*ll
= (l_stdio_t
*) lf
->data
;
39 s
= FD_WRITE_METHOD(ll
->fd
, (char const *) buf
, len
);
41 fd_bytes(ll
->fd
, s
, FD_WRITE
);
49 fatalf("logfileWrite: %s: %s\n", lf
->path
, xstrerr(xerrno
));
53 logfile_mod_stdio_writeline(Logfile
* lf
, const char *buf
, size_t len
)
55 l_stdio_t
*ll
= (l_stdio_t
*) lf
->data
;
58 /* buffering disabled */
59 logfileWriteWrapper(lf
, buf
, len
);
62 if (ll
->offset
> 0 && (ll
->offset
+ len
) > ll
->bufsz
)
65 if (len
> ll
->bufsz
) {
66 /* too big to fit in buffer */
67 logfileWriteWrapper(lf
, buf
, len
);
71 memcpy(ll
->buf
+ ll
->offset
, buf
, len
);
75 assert(ll
->offset
>= 0);
77 assert((size_t) ll
->offset
<= ll
->bufsz
);
81 logfile_mod_stdio_linestart(Logfile
*)
86 logfile_mod_stdio_lineend(Logfile
* lf
)
92 logfile_mod_stdio_flush(Logfile
* lf
)
94 l_stdio_t
*ll
= (l_stdio_t
*) lf
->data
;
97 logfileWriteWrapper(lf
, ll
->buf
, (size_t) ll
->offset
);
102 logfile_mod_stdio_rotate(Logfile
* lf
, const int16_t nRotate
)
109 char from
[MAXPATHLEN
];
111 l_stdio_t
*ll
= (l_stdio_t
*) lf
->data
;
112 const char *realpath
= lf
->path
+6; // skip 'stdio:' prefix.
117 if (stat(realpath
, &sb
) == 0)
118 if (S_ISREG(sb
.st_mode
) == 0)
123 debugs(0, DBG_IMPORTANT
, "Rotate log file " << lf
->path
);
125 /* Rotate numbers 0 through N up one */
126 for (int16_t i
= nRotate
; i
> 1;) {
128 snprintf(from
, MAXPATHLEN
, "%s.%d", realpath
, i
- 1);
129 snprintf(to
, MAXPATHLEN
, "%s.%d", realpath
, i
);
133 /* Rotate the current log to .0 */
136 file_close(ll
->fd
); /* always close */
139 snprintf(to
, MAXPATHLEN
, "%s.%d", realpath
, 0);
140 xrename(realpath
, to
);
142 /* Reopen the log. It may have been renamed "manually" */
143 ll
->fd
= file_open(realpath
, O_WRONLY
| O_CREAT
| O_TEXT
);
145 if (DISK_ERROR
== ll
->fd
&& lf
->flags
.fatal
) {
147 debugs(50, DBG_CRITICAL
, MYNAME
<< "ERROR: " << lf
->path
<< ": " << xstrerr(xerrno
));
148 fatalf("Cannot open %s: %s", lf
->path
, xstrerr(xerrno
));
153 logfile_mod_stdio_close(Logfile
* lf
)
155 l_stdio_t
*ll
= (l_stdio_t
*) lf
->data
;
169 * This code expects the path to be a writable filename
172 logfile_mod_stdio_open(Logfile
* lf
, const char *path
, size_t bufsz
, int fatal_flag
)
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
;
181 l_stdio_t
*ll
= static_cast<l_stdio_t
*>(xcalloc(1, sizeof(*ll
)));
184 ll
->fd
= file_open(path
, O_WRONLY
| O_CREAT
| O_TEXT
);
186 if (DISK_ERROR
== ll
->fd
) {
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
);
200 debugs(50, DBG_IMPORTANT
, MYNAME
<< "ERROR: " << lf
->path
<< ": " << xstrerr(xerrno
));
205 ll
->buf
= static_cast<char*>(xmalloc(bufsz
));