ModStdio.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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;
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
82 {
83 }
84 
85 static void
87 {
88  lf->f_flush(lf);
89 }
90 
91 static void
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  l_stdio_t *ll = (l_stdio_t *) lf->data;
110  const char *realpath = lf->path+6; // skip 'stdio:' prefix.
111  assert(realpath);
112 
113 #ifdef S_ISREG
114 
115  if (stat(realpath, &sb) == 0)
116  if (S_ISREG(sb.st_mode) == 0)
117  return;
118 
119 #endif
120 
121  debugs(0, DBG_IMPORTANT, "Rotate log file " << lf->path);
122 
123  SBuf basePath(realpath);
124 
125  /* Rotate numbers 0 through N up one */
126  for (int16_t i = nRotate; i > 1;) {
127  --i;
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
134  }
135 
136  /* Rotate the current log to .0 */
137  logfileFlush(lf);
138 
139  file_close(ll->fd); /* always close */
140 
141  if (nRotate > 0) {
142  SBuf to(basePath);
143  to.appendf(".0");
144  FileRename(basePath, to);
145  // TODO handle rename errors
146  }
147  /* Reopen the log. It may have been renamed "manually" */
148  ll->fd = file_open(realpath, O_WRONLY | O_CREAT | O_TEXT);
149 
150  if (DISK_ERROR == ll->fd && lf->flags.fatal) {
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));
154  }
155 }
156 
157 static void
159 {
160  l_stdio_t *ll = (l_stdio_t *) lf->data;
161  lf->f_flush(lf);
162 
163  if (ll->fd >= 0)
164  file_close(ll->fd);
165 
166  if (ll->buf)
167  xfree(ll->buf);
168 
169  xfree(lf->data);
170  lf->data = nullptr;
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 {
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) {
192  int xerrno = errno;
193  if (ENOENT == xerrno && fatal_flag) {
194  fatalf("Cannot open '%s' because\n"
195  "\tthe parent directory does not exist.\n"
196  "\tPlease create the directory.\n", path);
197  } else if (EACCES == xerrno && fatal_flag) {
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);
202  } else if (EISDIR == xerrno && fatal_flag) {
203  fatalf("Cannot open '%s' because it is a directory, not a file.\n", path);
204  } else {
205  debugs(50, DBG_IMPORTANT, MYNAME << "ERROR: " << lf->path << ": " << xstrerr(xerrno));
206  return 0;
207  }
208  }
209  if (bufsz > 0) {
210  ll->buf = static_cast<char*>(xmalloc(bufsz));
211  ll->bufsz = bufsz;
212  }
213  return 1;
214 }
215 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
#define DBG_CRITICAL
Definition: Stream.h:37
#define xmalloc
void fd_bytes(const int fd, const int len, const IoDirection direction)
Definition: fd.cc:226
static void logfile_mod_stdio_lineend(Logfile *lf)
Definition: ModStdio.cc:86
#define O_TEXT
Definition: defines.h:131
int offset
Definition: ModStdio.cc:27
Definition: SBuf.h:93
int logfile_mod_stdio_open(Logfile *lf, const char *path, size_t bufsz, int fatal_flag)
Definition: ModStdio.cc:177
LOGWRITE * f_linewrite
Definition: File.h:58
void file_close(int fd)
Definition: fs_io.cc:93
unsigned int fatal
Definition: File.h:49
void * data
Definition: File.h:55
void logfileFlush(Logfile *lf)
Definition: File.cc:139
static void logfile_mod_stdio_linestart(Logfile *)
Definition: ModStdio.cc:81
static void logfile_mod_stdio_flush(Logfile *lf)
Definition: ModStdio.cc:92
int fd
Definition: ModStdio.cc:24
static void logfile_mod_stdio_close(Logfile *lf)
Definition: ModStdio.cc:158
LOGLINEEND * f_lineend
Definition: File.h:59
size_t bufsz
Definition: ModStdio.cc:26
#define assert(EX)
Definition: assert.h:17
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
LOGCLOSE * f_close
Definition: File.h:62
int FD_WRITE_METHOD(int fd, const char *buf, int len)
Definition: fde.h:200
static void logfile_mod_stdio_rotate(Logfile *lf, const int16_t nRotate)
Definition: ModStdio.cc:102
LOGROTATE * f_rotate
Definition: File.h:61
char * effectiveUser
Definition: SquidConfig.h:196
#define xfree
Definition: File.h:38
static void logfileWriteWrapper(Logfile *lf, const void *buf, size_t len)
Definition: ModStdio.cc:35
LOGFLUSH * f_flush
Definition: File.h:60
static void logfile_mod_stdio_writeline(Logfile *lf, const char *buf, size_t len)
Definition: ModStdio.cc:53
#define DBG_IMPORTANT
Definition: Stream.h:38
struct Logfile::@70 flags
char * buf
Definition: ModStdio.cc:25
#define MYNAME
Definition: Stream.h:219
#define DISK_ERROR
Definition: defines.h:28
bool FileRename(const SBuf &from, const SBuf &to)
Definition: fs_io.cc:444
int file_open(const char *path, int mode)
Definition: fs_io.cc:65
LOGLINESTART * f_linestart
Definition: File.h:57
SBuf & appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:229
char path[MAXPATHLEN]
Definition: File.h:46
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
class SquidConfig Config
Definition: SquidConfig.cc:12

 

Introduction

Documentation

Support

Miscellaneous