log_file_daemon.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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 #include "squid.h"
10 
11 #include "compat/unistd.h"
12 
13 #include <cassert>
14 #include <cerrno>
15 #include <csignal>
16 #include <cstring>
17 #if HAVE_FCNTL_H
18 #include <fcntl.h>
19 #endif
20 #if HAVE_SYS_PARAM_H
21 #include <sys/param.h>
22 #endif
23 #if HAVE_SYS_STAT_H
24 #include <sys/stat.h>
25 #endif
26 #if HAVE_PATHS_H
27 #include <paths.h>
28 #endif
29 
31 
32 /* parse buffer - ie, length of longest expected line */
33 #define LOGFILE_BUF_LEN 65536
34 
35 static void
36 rotate(const char *path, int rotate_count)
37 {
38 #ifdef S_ISREG
39  struct stat sb;
40 #endif
41  int i;
42  char from[MAXPATHLEN];
43  char to[MAXPATHLEN];
44  assert(path);
45 #ifdef S_ISREG
46  if (stat(path, &sb) == 0)
47  if (S_ISREG(sb.st_mode) == 0)
48  return;
49 #endif
50  /* Rotate numbers 0 through N up one */
51  for (i = rotate_count; i > 1;) {
52  --i;
53  snprintf(from, MAXPATHLEN, "%s.%d", path, i - 1);
54  snprintf(to, MAXPATHLEN, "%s.%d", path, i);
55 #if _SQUID_OS2_ || _SQUID_WINDOWS_
56  if (remove(to) < 0) {
57  int xerrno = errno;
58  fprintf(stderr, "WARNING: remove '%s' failure: %s\n", to, xstrerr(xerrno));
59  }
60 #endif
61  if (rename(from, to) < 0 && errno != ENOENT) {
62  int xerrno = errno;
63  fprintf(stderr, "WARNING: rename '%s' to '%s' failure: %s\n", from, to, xstrerr(xerrno));
64  }
65  }
66  if (rotate_count > 0) {
67  snprintf(to, MAXPATHLEN, "%s.%d", path, 0);
68 #if _SQUID_OS2_ || _SQUID_WINDOWS_
69  if (remove(to) < 0) {
70  int xerrno = errno;
71  fprintf(stderr, "WARNING: remove '%s' failure: %s\n", to, xstrerr(xerrno));
72  }
73 #endif
74  if (rename(path, to) < 0 && errno != ENOENT) {
75  int xerrno = errno;
76  fprintf(stderr, "WARNING: rename %s to %s failure: %s\n", path, to, xstrerr(xerrno));
77  }
78  }
79 }
80 
92 int
93 main(int argc, char *argv[])
94 {
95  int t;
96  FILE *fp;
97  char buf[LOGFILE_BUF_LEN];
98  int rotate_count = 10;
99  int do_buffer = 1;
100 
101  if (argc < 2) {
102  printf("Error: usage: %s <logfile>\n", argv[0]);
103  exit(EXIT_FAILURE);
104  }
105  fp = fopen(argv[1], "a");
106  if (fp == nullptr) {
107  perror("fopen");
108  exit(EXIT_FAILURE);
109  }
110  setbuf(stdout, nullptr);
111  /* XXX stderr should not be closed, but in order to support squid must be
112  * able to collect and manage modules' stderr first.
113  */
114  xclose(2);
115  t = xopen(_PATH_DEVNULL, O_RDWR);
116  assert(t > -1);
117  dup2(t, 2);
118 
119  while (fgets(buf, LOGFILE_BUF_LEN, stdin)) {
120  /* First byte indicates what we're logging! */
121  switch (buf[0]) {
122  case 'L':
123  if (buf[1] != '\0') {
124  fprintf(fp, "%s", buf + 1);
125  /* try to detect the 32-bit file too big write error and rotate */
126  int err = ferror(fp);
127  clearerr(fp);
128  if (err != 0) {
129  /* file too big - recover by rotating the logs and starting a new one.
130  * out of device space - recover by rotating and hoping that rotation count drops a big one.
131  */
132  if (err == EFBIG || err == ENOSPC) {
133  fprintf(stderr, "WARNING: %s writing %s. Attempting to recover via a log rotation.\n",xstrerr(err),argv[1]);
134  fclose(fp);
135  rotate(argv[1], rotate_count);
136  fp = fopen(argv[1], "a");
137  if (fp == nullptr) {
138  perror("fopen");
139  exit(EXIT_FAILURE);
140  }
141  fprintf(fp, "%s", buf + 1);
142  } else {
143  perror("fprintf");
144  exit(EXIT_FAILURE);
145  }
146  }
147  }
148  if (!do_buffer)
149  fflush(fp);
150  break;
151  case 'R':
152  fclose(fp);
153  rotate(argv[1], rotate_count);
154  fp = fopen(argv[1], "a");
155  if (fp == nullptr) {
156  perror("fopen");
157  exit(EXIT_FAILURE);
158  }
159  break;
160  case 'T':
161  break;
162  case 'O':
163  break;
164  case 'r':
165  //fprintf(fp, "SET ROTATE: %s\n", buf + 1);
166  rotate_count = atoi(buf + 1);
167  break;
168  case 'b':
169  //fprintf(fp, "SET BUFFERED: %s\n", buf + 1);
170  do_buffer = (buf[1] == '1');
171  break;
172  case 'F':
173  fflush(fp);
174  break;
175  default:
176  /* Just in case .. */
177  fprintf(fp, "%s", buf);
178  break;
179  }
180  }
181  fclose(fp);
182  fp = nullptr;
183  return EXIT_SUCCESS;
184 }
185 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
#define LOGFILE_BUF_LEN
int main(int argc, char *argv[])
#define assert(EX)
Definition: assert.h:17
int xopen(const char *filename, int oflag, int pmode=0)
POSIX open(2) equivalent.
Definition: unistd.h:55
int xclose(int fd)
POSIX close(2) equivalent.
Definition: unistd.h:43
#define MAXPATHLEN
Definition: stdio.h:62
static void rotate(const char *path, int rotate_count)

 

Introduction

Documentation

Support

Miscellaneous