ze-filter  (ze-filter-0.8.0-develop-180218)
ze-txtlog.c
Go to the documentation of this file.
1 /*
2  *
3  * ze-filter - Mail Server Filter for sendmail
4  *
5  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
6  *
7  * Auteur : Jose Marcio Martins da Cruz
8  * jose.marcio.mc@gmail.org
9  *
10  * Historique :
11  * Creation : Mon Jan 9 17:31:39 CET 2006
12  *
13  * This program is free software, but with restricted license :
14  *
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * More details about ze-filter license can be found at ze-filter
21  * web site : http://foss.jose-marcio.org
22  */
23 
24 
25 #include <ze-sys.h>
26 #include <libze.h>
27 #include <ze-libjc.h>
28 #include <ze-txtlog.h>
29 
30 #ifndef LOGLINELEN
31 # define LOGLINELEN 1024
32 #endif /* LOGLINELEN */
33 
34 static bool locked_log_open(LOG_T *);
35 static bool locked_log_close(LOG_T *);
36 static bool locked_log_write(LOG_T *, char *);
37 
38 /* Common */
39 #define LOG_SPEC_WHICH(x) ((x)->argv[0])
40 
41 /* syslog */
42 #define LOG_SPEC_PREFIX(x) ((x)->argv[1])
43 #define LOG_SPEC_PRIORITY(x) ((x)->argv[2])
44 
45 /* file */
46 #define LOG_SPEC_FNAME(x) ((x)->argv[1])
47 
48 /* udp */
49 #define LOG_SPEC_UDPDST(x) ((x)->argv[1])
50 
51 /* common */
52 #define LOG_SPEC_OPTION(x) ((x)->argv[2])
53 
54 #define LOG_MAX_ERRORS 16
55 
56 /* ****************************************************************************
57  * *
58  * *
59  **************************************************************************** */
60 bool
62  LOG_T *log;
63 {
64  ASSERT(log != NULL);
65  ASSERT(log->signature == SIGNATURE);
66 
67  MUTEX_LOCK(&log->mutex);
68 
69  MUTEX_UNLOCK(&log->mutex);
70 
71  return TRUE;
72 }
73 
74 /* ****************************************************************************
75  * *
76  * *
77  **************************************************************************** */
78 bool
79 log_debug(log, debug)
80  LOG_T *log;
81  bool debug;
82 {
83  ASSERT(log != NULL);
84  ASSERT(log->signature == SIGNATURE);
85 
86  MUTEX_LOCK(&log->mutex);
87  log->debug = debug;
88  MUTEX_UNLOCK(&log->mutex);
89 
90  return TRUE;
91 }
92 
93 /* ****************************************************************************
94  * *
95  * *
96  **************************************************************************** */
97 bool
99  LOG_T *log;
100 {
101  ASSERT(log != NULL);
102  ASSERT(log->signature == SIGNATURE);
103 
104  MUTEX_LOCK(&log->gmutex);
105 
106  return TRUE;
107 }
108 
109 /* ****************************************************************************
110  * *
111  * *
112  **************************************************************************** */
113 bool
115  LOG_T *log;
116 {
117  ASSERT(log != NULL);
118  ASSERT(log->signature == SIGNATURE);
119 
120  MUTEX_UNLOCK(&log->gmutex);
121 
122  return TRUE;
123 }
124 
125 /* ****************************************************************************
126  * *
127  * *
128  **************************************************************************** */
129 bool
131  LOG_T *log;
132 {
133  if (log->open && log->logtype == JC_LOG_FILE)
134  {
135 
136  /* log->log.file.fd = -1; */
137  }
138  return log->open;
139 }
140 
141 /* ****************************************************************************
142  * *
143  * *
144  **************************************************************************** */
145 bool
146 log_open(log, spec)
147  LOG_T *log;
148  char *spec;
149 {
150  bool res = FALSE;
151  char *type, *priv, *options;
152 
153  ASSERT(log != NULL);
154  ASSERT(log->signature == SIGNATURE);
155 
156  MUTEX_LOCK(&log->mutex);
157 
158  if (!log->init)
159  {
160  log->argc = 0;
161  memset(log->argv, 0, sizeof (log->argv));
162  memset(&log->log, 0, sizeof (log->log));
163  log->init = TRUE;
164  }
165 
166  if (log->open)
167  {
168  /* XXX */
169  goto fin;
170  }
171 
172  log->open = FALSE;
173  if (spec == NULL || strlen(spec) == 0)
174  spec = "nolog";
175 
176  if ((log->spec = strdup(spec)) == NULL)
177  {
178  ZE_LogSysError("strdup(%s) error", spec);
179  log->error = errno;
180 
181  goto fin;
182  }
183  if ((log->args = strdup(spec)) == NULL)
184  {
185  ZE_LogSysError("strdup(%s) error", spec);
186  log->error = errno;
187 
188  goto fin;
189  }
190 
191  if (log->debug)
192  ZE_MessageInfo(10, "Opening spec %s", spec);
193 
194  log->argc = zeStr2Tokens(log->args, 4, log->argv, ":");
195 
196  if (log->argc == 1 || zeStrRegex(spec, PATH_REGEX, NULL, NULL, TRUE))
197  {
198  /* XXX compatibility with older versions */
199  /* shift right values in argv and add "file" to argv[0] */
200  int i;
201 
202  ZE_MessageNotice(11, "Correcting old configuration option : %s", spec);
203  for (i = ARGVM - 1; i > 0; i--)
204  log->argv[i] = log->argv[i - 1];
205  log->argv[0] = "file";
206  if (log->argc < ARGVM)
207  log->argc++;
208  }
209 
210  if (strcasecmp(LOG_SPEC_WHICH(log), "syslog") == 0)
211  {
212  log->logtype = JC_LOG_SYSLOG;
213 
214  /* log->log.syslog.priority = syslog_priority_value(LOG_SPEC_PRIORITY(log)); */
215  log->log.syslog.priority = zeLog_PriorityValue(LOG_SPEC_PRIORITY(log));
216  if (log->log.syslog.priority < 0)
217  log->log.syslog.priority = LOG_INFO;
218 
219  log->open = TRUE;
220 
221  goto fin;
222  }
223 
224  if (strcasecmp(LOG_SPEC_WHICH(log), "file") == 0)
225  {
226  log->logtype = JC_LOG_FILE;
227 
228  log->log.file.fd = -1;
229  if (log->debug)
230  ZE_MessageInfo(10, "Opening file %s", STRNULL(LOG_SPEC_FNAME(log), "NULL"));
231 
232  log->open = locked_log_open(log);
233 
234  goto fin;
235  }
236 
237  if (strcasecmp(LOG_SPEC_WHICH(log), "udp") == 0)
238  {
239  log->logtype = JC_LOG_UDP;
240  log->log.udp.fd = -1;
241  log->log.udp.connect = FALSE;
242 
243  log->open = locked_log_open(log);
244 
245  goto fin;
246  }
247 
248  if (strcasecmp(LOG_SPEC_WHICH(log), "nolog") == 0 ||
249  strcasecmp(LOG_SPEC_WHICH(log), "none") == 0)
250  {
251  log->open = TRUE;
252 
253  goto fin;
254  }
255 
256 fin:
257  if (!log->open)
258  {
259  FREE(log->spec);
260  FREE(log->args);
261  log_init(log);
262  }
263  res = log->open;
264 
265  MUTEX_UNLOCK(&log->mutex);
266 
267  return res;
268 }
269 
270 /* ****************************************************************************
271  * *
272  * *
273  **************************************************************************** */
274 bool
276  LOG_T *log;
277 {
278  ASSERT(log != NULL);
279  ASSERT(log->signature == SIGNATURE);
280 
281  MUTEX_LOCK(&log->mutex);
282 
283  locked_log_close(log);
284  locked_log_open(log);
285 
286  MUTEX_UNLOCK(&log->mutex);
287 
288  return TRUE;
289 }
290 
291 /* ****************************************************************************
292  * *
293  * *
294  **************************************************************************** */
295 bool
297  LOG_T *log;
298 {
299  ASSERT(log != NULL);
300  ASSERT(log->signature == SIGNATURE);
301 
302  MUTEX_LOCK(&log->mutex);
303 
304  locked_log_close(log);
305 
306  log->open = FALSE;
307 
308  FREE(log->spec);
309  log->argc = 0;
310  memset(&log->argv, 0, sizeof (log->argv));
311 
312  log->error = 0;
313  log->nberror = 0;
314 
315  log->logtype = JC_LOG_NONE;
316 
317  memset(&log->log, 0, sizeof (log->log));
318 
319  MUTEX_UNLOCK(&log->mutex);
320 
321  return TRUE;
322 }
323 
324 /* ****************************************************************************
325  * *
326  * *
327  **************************************************************************** */
328 bool
329 log_write(log, str)
330  LOG_T *log;
331  char *str;
332 {
333  ASSERT(log != NULL);
334  ASSERT(log->signature == SIGNATURE);
335 
336  ASSERT(str != NULL);
337 
338  MUTEX_LOCK(&log->mutex);
339 
340  if (log->open)
341  locked_log_write(log, str);
342  else
343  ZE_LogMsgWarning(0, "Trying to write in a closed log structure");
344 
345  MUTEX_UNLOCK(&log->mutex);
346 
347  return TRUE;
348 }
349 
350 /* ****************************************************************************
351  * *
352  * *
353  **************************************************************************** */
354 bool
355 log_printf(LOG_T * log, char *format, ...)
356 {
357  va_list arg;
358  char str[LOGLINELEN];
359 
360  ASSERT(log != NULL);
361  ASSERT(log->signature == SIGNATURE);
362  ASSERT(log->open);
363  ASSERT(format != NULL);
364 
365  MUTEX_LOCK(&log->mutex);
366 
367  va_start(arg, format);
368  vsnprintf(str, sizeof (str), format, arg);
369  va_end(arg);
370 
371  locked_log_write(log, str);
372 
373  MUTEX_UNLOCK(&log->mutex);
374 
375  return TRUE;
376 }
377 
378 /* ****************************************************************************
379  * *
380  * *
381  **************************************************************************** */
382 int
384  LOG_T *log;
385 {
386  ASSERT(log != NULL);
387  ASSERT(log->signature == SIGNATURE);
388 
389  MUTEX_LOCK(&log->mutex);
390 
391  MUTEX_UNLOCK(&log->mutex);
392 
393  return 0;
394 }
395 
396 /* ****************************************************************************
397  * *
398  * *
399  **************************************************************************** */
400 static bool
401 locked_log_open(log)
402  LOG_T *log;
403 {
404  ASSERT(log != NULL);
405  ASSERT(log->signature == SIGNATURE);
406 
407  switch (log->logtype)
408  {
409  case JC_LOG_NONE:
410  break;
411 
412  case JC_LOG_SYSLOG:
413  /* XXX Need surely to be changed
414  ** Each log structure can't have it's own syslog facility
415  ** in the same processus
416  ** For the moment, I'm considering syslog is already open
417  */
418  log->open = TRUE;
419  break;
420 
421  case JC_LOG_FILE:
422  ASSERT(LOG_SPEC_FNAME(log) != NULL);
423  ASSERT(strlen(LOG_SPEC_FNAME(log)) != 0);
424 
425  if (log->log.file.fd >= 0)
426  {
427  ZE_LogMsgWarning(0, " It seems that log->fname (%s) is already open",
428  LOG_SPEC_FNAME(log));
429  close(log->log.file.fd);
430  log->log.file.fd = -1;
431  break;
432  }
433  if ((log->log.file.fd =
434  open(LOG_SPEC_FNAME(log), O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0)
435  {
436  ZE_LogSysError("error opening : %s", LOG_SPEC_FNAME(log));
437  log->error = errno;
438  log->nberror++;
439  exit(EX_SOFTWARE);
440  }
441 
442  log->nberror = 0;
443 
444  log->open = TRUE;
445  break;
446 
447  case JC_LOG_UDP:
448  {
449  char *inet = LOG_SPEC_UDPDST(log);
450  int port = 10001;
451  char *addr = NULL;
452  int r = 0;
453 
454  port = zeStr2long(inet, NULL, 10001);
455  addr = strchr(inet, '@');
456 
457  ZE_MessageInfo(10, "Opening UDP to %s port %d",
458  addr != NULL ? addr + 1 : "NULL", port);
459  if (addr != NULL)
460  {
461  addr++;
462 
463  memset(&log->log.udp.sock, 0, sizeof (log->log.udp.sock));
464  log->log.udp.sock.sin_family = AF_INET;
465  log->log.udp.sock.sin_port = htons(port);
466  r = jinet_pton(AF_INET, addr, &log->log.udp.sock.sin_addr);
467  if (r >= 0)
468  {
469  log->log.udp.fd = socket(AF_INET, SOCK_DGRAM, 0);
470  log->open = TRUE;
471  log->log.udp.connect = FALSE;
472  r = connect(log->log.udp.fd, (struct sockaddr *) &log->log.udp.sock,
473  sizeof (log->log.udp.sock));
474  if (r >= 0)
475  {
476  log->nberror = 0;
477  log->log.udp.connect = TRUE;
478  } else
479  {
480  log->nberror++;
481  }
482  } else
483  {
484  log->nberror++;
485  }
486  } else
487  {
488  log->nberror++;
489  }
490  }
491  break;
492 
493  default:
494  break;
495  }
496 
497  if (log->nberror > 0 && log->nberror < LOG_MAX_ERRORS)
498  ZE_MessageWarning(5, "Errors...");
499 
500  return log->open;
501 }
502 
503 /* ****************************************************************************
504  * *
505  * *
506  **************************************************************************** */
507 static bool
508 locked_log_close(log)
509  LOG_T *log;
510 {
511  ASSERT(log != NULL);
512  ASSERT(log->signature == SIGNATURE);
513 
514  switch (log->logtype)
515  {
516  case JC_LOG_NONE:
517  break;
518 
519  case JC_LOG_SYSLOG:
520  break;
521 
522  case JC_LOG_FILE:
523  if (log->log.file.fd > 0)
524  close(log->log.file.fd);
525  log->log.file.fd = -1;
526  break;
527 
528  case JC_LOG_UDP:
529  if (log->log.udp.fd > 0)
530  {
531  shutdown(log->log.udp.fd, SHUT_RDWR);
532  close(log->log.udp.fd);
533  log->log.udp.fd = -1;
534  }
535  break;
536 
537  default:
538  break;
539  }
540 
541  log->open = FALSE;
542 
543  return TRUE;
544 }
545 
546 /* ****************************************************************************
547  * *
548  * *
549  **************************************************************************** */
550 static bool
551 locked_log_write(log, str)
552  LOG_T *log;
553  char *str;
554 {
555  char *prefix = NULL;
556  char *x = NULL;
557 
558  switch (log->logtype)
559  {
560  case JC_LOG_NONE:
561  break;
562 
563  case JC_LOG_SYSLOG:
564  if (log->debug)
565  ZE_MessageInfo(10, "func=%s : JC_LOG_SYSLOG : %s", ZE_FUNCTION, str);
566  prefix = LOG_SPEC_PREFIX(log);
567  if (prefix != NULL && strlen(prefix) > 0)
568  zeSyslog(log->log.syslog.priority, "%s : %s", prefix, str);
569  else
570  zeSyslog(log->log.syslog.priority, "%s", str);
571  break;
572 
573  case JC_LOG_FILE:
574  ASSERT(log->log.file.fd >= 0);
575  if (log->debug)
576  ZE_MessageInfo(10, "func=%s : JC_LOG_FILE : %s", ZE_FUNCTION, str);
577  if (write(log->log.file.fd, str, strlen(str)) < 0)
578  {
579  ZE_LogSysError("Error writing to file %s", LOG_SPEC_FNAME(log));
580  log->error = errno;
581  log->nberror++;
582  log->lasterror = time(NULL);
583  } else
584  log->nberror = 0;
585 
586  if (strchr(str, '\n') == NULL)
587  {
588  if (write(log->log.file.fd, "\n", 1) < 0)
589  {
590  ZE_LogSysError("Error writing to file %s", LOG_SPEC_FNAME(log));
591  log->error = errno;
592  log->nberror++;
593  log->lasterror = time(NULL);
594  } else
595  log->nberror = 0;
596  }
597 
598  break;
599 
600  case JC_LOG_UDP:
601  ASSERT(log->log.udp.fd >= 0);
602  if (log->debug)
603  ZE_MessageInfo(10, "func=%s : JC_LOG_UDP : %s", ZE_FUNCTION, str);
604 
605  if (!log->log.udp.connect)
606  {
607  time_t now;
608 
609  now = time(NULL);
610 
611  if (log->nberror < LOG_MAX_ERRORS || log->lasterror + 60 < now)
612  {
613  int r;
614 
615  r = connect(log->log.udp.fd, (struct sockaddr *) &log->log.udp.sock,
616  sizeof (log->log.udp.sock));
617  if (r >= 0)
618  {
619  log->nberror = 0;
620  log->log.udp.connect = TRUE;
621  } else
622  {
623  log->nberror++;
624  log->lasterror = time(NULL);
625  }
626  }
627  }
628  if (sendto(log->log.udp.fd, str, strlen(str), 0, NULL, 0) < 0)
629  {
630  ZE_LogSysError("Error writing to %s", "udp");
631  log->error = errno;
632  } else
633  log->nberror = 0;
634  break;
635 
636  default:
637  break;
638  }
639  if (log->nberror > 0 && log->nberror < LOG_MAX_ERRORS)
640  ZE_MessageWarning(5, "Errors...");
641 
642  return TRUE;
643 }
bool log_write(LOG_T *log, char *str)
Definition: ze-txtlog.c:329
time_t lasterror
Definition: ze-txtlog.h:58
void zeSyslog(int, char *,...)
Definition: zeSyslog.c:54
int jinet_pton(int, char *, void *)
#define JC_LOG_SYSLOG
Definition: ze-txtlog.h:34
bool log_ready(LOG_T *log)
Definition: ze-txtlog.c:130
#define ASSERT(a)
Definition: macros.h:27
#define ZE_FUNCTION
Definition: ze-sys.h:471
int log_error(LOG_T *log)
Definition: ze-txtlog.c:383
bool log_lock(LOG_T *log)
Definition: ze-txtlog.c:98
#define FREE(x)
Definition: macros.h:37
bool log_reopen(LOG_T *log)
Definition: ze-txtlog.c:275
#define MUTEX_UNLOCK(mutex)
Definition: macros.h:101
bool log_open(LOG_T *log, char *spec)
Definition: ze-txtlog.c:146
#define STRNULL(x, r)
Definition: macros.h:81
pthread_mutex_t mutex
Definition: ze-txtlog.h:51
#define LOG_SPEC_FNAME(x)
Definition: ze-txtlog.c:46
bool log_init(LOG_T *log)
Definition: ze-txtlog.c:61
#define MUTEX_LOCK(mutex)
Definition: macros.h:93
struct LOG_T::@1::@4 udp
#define ARGVM
Definition: ze-txtlog.h:44
int error
Definition: ze-txtlog.h:56
#define FALSE
Definition: macros.h:160
bool debug
Definition: ze-txtlog.h:54
bool zeStrRegex(char *, char *, long *, long *, bool)
Definition: zeStrings.c:544
bool open
Definition: ze-txtlog.h:60
int zeStr2Tokens(char *, int, char **, char *)
Definition: zeStrings.c:610
uint32_t signature
Definition: ze-txtlog.h:49
struct LOG_T::@1::@2 syslog
#define strchr
Definition: ze-sys.h:218
bool log_unlock(LOG_T *log)
Definition: ze-txtlog.c:114
#define PATH_REGEX
Definition: macros.h:214
long zeStr2long(char *s, int *error, long dval)
Definition: zeStrConvert.c:35
#define LOGLINELEN
Definition: ze-txtlog.c:31
#define ZE_MessageNotice(level,...)
Definition: zeSyslog.h:91
pthread_mutex_t gmutex
Definition: ze-txtlog.h:50
bool init
Definition: ze-txtlog.h:53
bool log_printf(LOG_T *log, char *format,...)
Definition: ze-txtlog.c:355
#define JC_LOG_UDP
Definition: ze-txtlog.h:36
char * spec
Definition: ze-txtlog.h:63
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
struct LOG_T::@1::@3 file
union LOG_T::@1 log
#define LOG_SPEC_PRIORITY(x)
Definition: ze-txtlog.c:43
#define TRUE
Definition: macros.h:157
#define ZE_MessageWarning(level,...)
Definition: zeSyslog.h:92
#define LOG_SPEC_PREFIX(x)
Definition: ze-txtlog.c:42
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
char * args
Definition: ze-txtlog.h:64
#define ZE_LogMsgWarning(level,...)
Definition: zeSyslog.h:112
bool log_debug(LOG_T *log, bool debug)
Definition: ze-txtlog.c:79
int zeLog_PriorityValue(char *)
Definition: zeSyslog.c:463
#define LOG_MAX_ERRORS
Definition: ze-txtlog.c:54
int logtype
Definition: ze-txtlog.h:61
#define JC_LOG_FILE
Definition: ze-txtlog.h:35
#define LOG_SPEC_UDPDST(x)
Definition: ze-txtlog.c:49
int nberror
Definition: ze-txtlog.h:57
#define JC_LOG_NONE
Definition: ze-txtlog.h:33
bool log_close(LOG_T *log)
Definition: ze-txtlog.c:296
#define LOG_SPEC_WHICH(x)
Definition: ze-txtlog.c:39
#define SIGNATURE
Definition: ze-libjc.h:75
int argc
Definition: ze-txtlog.h:65
char * argv[ARGVM]
Definition: ze-txtlog.h:66