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

 

Introduction

Documentation

Support

Miscellaneous