diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-12-03 19:52:56 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-12-03 20:34:19 +0200 |
commit | 30bf4d542198abc23b897dd81fc280354903e49f (patch) | |
tree | 5e414f29aa6c8a1f720dec837a6c588b89b74d0d /libmailutils | |
parent | 554f80a1122f7a931f8c09056f4238b38d5034e8 (diff) | |
download | mailutils-30bf4d542198abc23b897dd81fc280354903e49f.tar.gz mailutils-30bf4d542198abc23b897dd81fc280354903e49f.tar.bz2 |
Initial implementation of log streams.
* include/mailutils/mailutils.h: Include mailutils/log.h.
* include/mailutils/stream.h (MU_IOCTL_LOGSTREAM_GET_SEVERITY)
(MU_IOCTL_LOGSTREAM_SET_SEVERITY)
(MU_IOCTL_LOGSTREAM_GET_LOCUS,MU_IOCTL_LOGSTREAM_SET_LOCUS)
(MU_IOCTL_LOGSTREAM_GET_MODE,MU_IOCTL_LOGSTREAM_SET_MODE): New ioctls.
* include/mailutils/sys/logstream.h: New file.
* include/mailutils/sys/syslogstream.h: New file.
* include/mailutils/sys/Makefile.am (sysinclude_HEADERS): Add logstream.h
and syslogstream.h
* include/mailutils/types.hin (mu_locus): New struct.
* libmailutils/stream/Makefile.am (libstream_la_SOURCES): Add logstream.c
and syslogstream.c.
* mu/logger.c: New file.
* mu/template.c: New file.
* mu/Makefile.am (MODULES): Add logger.c
(EXTRA_DIST): Add template.c.
Diffstat (limited to 'libmailutils')
-rw-r--r-- | libmailutils/stream/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/stream/dbgstream.c | 4 | ||||
-rw-r--r-- | libmailutils/stream/logstream.c | 364 | ||||
-rw-r--r-- | libmailutils/stream/syslogstream.c | 90 |
4 files changed, 458 insertions, 2 deletions
diff --git a/libmailutils/stream/Makefile.am b/libmailutils/stream/Makefile.am index 82fa573a8..507050dc6 100644 --- a/libmailutils/stream/Makefile.am +++ b/libmailutils/stream/Makefile.am @@ -22,6 +22,7 @@ libstream_la_SOURCES = \ file_stream.c\ fltstream.c\ iostream.c\ + logstream.c\ mapfile_stream.c\ memory_stream.c\ message_stream.c\ @@ -35,6 +36,7 @@ libstream_la_SOURCES = \ stream_vprintf.c\ streamcpy.c\ streamref.c\ + syslogstream.c\ tcp.c\ temp_file_stream.c\ xscript-stream.c diff --git a/libmailutils/stream/dbgstream.c b/libmailutils/stream/dbgstream.c index b7848131a..b1d05696f 100644 --- a/libmailutils/stream/dbgstream.c +++ b/libmailutils/stream/dbgstream.c @@ -63,8 +63,8 @@ _dbg_done (struct _mu_stream *str) } int -mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug, mu_log_level_t level, - int flags) +mu_dbgstream_create (mu_stream_t *pref, mu_debug_t debug, mu_log_level_t level, + int flags) { int rc; mu_stream_t stream; diff --git a/libmailutils/stream/logstream.c b/libmailutils/stream/logstream.c new file mode 100644 index 000000000..5908a27ec --- /dev/null +++ b/libmailutils/stream/logstream.c @@ -0,0 +1,364 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <mailutils/types.h> +#include <mailutils/errno.h> +#include <mailutils/cctype.h> +#include <mailutils/log.h> + +#include <mailutils/nls.h> +#include <mailutils/stream.h> +#include <mailutils/sys/logstream.h> + +char *_mu_severity_str[] = { + N_("DEBUG"), + N_("INFO"), + N_("NOTICE"), + N_("WARNING"), + N_("ERROR"), + N_("CRIT"), + N_("ALERT"), + N_("EMERG"), +}; +int _mu_severity_num = MU_ARRAY_SIZE (_mu_severity_str); + +static int +_locus_set_file (struct mu_locus *loc, const char *file, size_t len) +{ + free (loc->mu_file); + if (file) + { + loc->mu_file = malloc (len + 1); + if (!loc->mu_file) + return ENOMEM; + memcpy (loc->mu_file, file, len); + loc->mu_file[len] = 0; + } + else + loc->mu_file = NULL; + return 0; +} + +#define _locus_set_line(loc, line) ((loc)->mu_line = line) +#define _locus_set_col(loc, col) ((loc)->mu_col = col) + +static int +_log_write (struct _mu_stream *str, const char *buf, size_t size, + size_t *pnwrite) +{ + struct _mu_log_stream *sp = (struct _mu_log_stream *)str; + unsigned severity = sp->severity; + int logmode = sp->logmode; + struct mu_locus loc = sp->locus; + const char *fname = NULL; + unsigned flen = 0; + int save_locus = 0; + int rc; + +#define NEXT do { buf++; size--; if (size == 0) return EINVAL; } while (0) +#define READNUM(n) do { \ + unsigned __x = 0; \ + if (*buf != '<') \ + return EINVAL; \ + NEXT; \ + while (*buf != '>') \ + { \ + if (!mu_isdigit (*buf)) \ + return EINVAL; \ + __x = __x * 10 + (*buf - '0'); \ + NEXT; \ + } \ + NEXT; \ + n = __x; \ +} while (0) + + /* Tell them we've consumed everything */ + *pnwrite = size; + + /* Process escapes */ + while (*buf == '\033') + { + int code; + unsigned n; + + NEXT; + code = *buf; + NEXT; + switch (code) + { + case 'S': + /* Save locus */ + save_locus = 1; + break; + + case 's': + /* Severity code in decimal (single digit) */ + if (!mu_isdigit (*buf)) + return EINVAL; + severity = *buf - '0'; + NEXT; + break; + + case 'O': + /* Flags on. Followed by a bitmask of MU_LOGMODE_*, in decimal */ + READNUM (n); + logmode |= n; + break; + + case 'X': + /* Flags off. Followed by a bitmask of MU_LOGMODE_*, in decimal */ + READNUM (n); + logmode &= ~n; + break; + + case 'l': + /* Input line (decimal) */ + READNUM (n); + _locus_set_line (&loc, n); + break; + + case 'c': + /* Column in input line (decimal) */ + READNUM (n); + _locus_set_col (&loc, n); + break; + + case 'f': + /* File name. Format: <N>S */ + READNUM (flen); + fname = buf; + buf += flen; + size -= flen; + break; + + default: + return EINVAL; + } + } + + if (severity >= _mu_severity_num) + severity = MU_LOG_EMERG; + + if (logmode & MU_LOGMODE_LOCUS) + { + if (fname) + _locus_set_file (&loc, fname, flen); + + if (loc.mu_file) + { + mu_stream_write (sp->transport, loc.mu_file, + strlen (loc.mu_file), NULL); + mu_stream_write (sp->transport, ":", 1, NULL); + if (loc.mu_line) + mu_stream_printf (sp->transport, "%u", loc.mu_line); + mu_stream_write (sp->transport, ":", 1, NULL); + if (loc.mu_col) + mu_stream_printf (sp->transport, "%u:", loc.mu_col); + mu_stream_write (sp->transport, " ", 1, NULL); + } + } + + if (save_locus) + { + _locus_set_file (&sp->locus, loc.mu_file, strlen (loc.mu_file)); + _locus_set_line (&sp->locus, loc.mu_line); + _locus_set_col (&sp->locus, loc.mu_col); + } + + if (fname) + free (loc.mu_file); + + if (logmode & MU_LOGMODE_SEVERITY) + { + char *s = gettext (_mu_severity_str[severity]); + rc = mu_stream_write (sp->transport, s, strlen (s), NULL); + if (rc) + return rc; + mu_stream_write (sp->transport, ": ", 2, NULL); + } + return mu_stream_write (sp->transport, buf, size, NULL); +} + +static int +_log_flush (struct _mu_stream *str) +{ + struct _mu_log_stream *sp = (struct _mu_log_stream *)str; + return mu_stream_flush (sp->transport); +} + +static void +_log_done (struct _mu_stream *str) +{ + struct _mu_log_stream *sp = (struct _mu_log_stream *)str; + if (str->flags & MU_STREAM_AUTOCLOSE) + mu_stream_destroy (&sp->transport); +} + +static int +_log_close (struct _mu_stream *str) +{ + struct _mu_log_stream *sp = (struct _mu_log_stream *)str; + if (str->flags & MU_STREAM_AUTOCLOSE) + return mu_stream_close (sp->transport); + return 0; +} + +static int +_log_setbuf_hook (mu_stream_t str, enum mu_buffer_type type, size_t size) +{ + if (type != mu_buffer_line) + return EACCES; + return 0; +} + +static int +_log_ctl (struct _mu_stream *str, int op, void *arg) +{ + struct _mu_log_stream *sp = (struct _mu_log_stream *)str; + mu_transport_t *ptrans; + + switch (op) + { + case MU_IOCTL_GET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + ptrans[0] = (mu_transport_t) sp->transport; + ptrans[1] = NULL; + break; + + case MU_IOCTL_SET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + if (ptrans[0]) + sp->transport = (mu_stream_t) ptrans[0]; + break; + + case MU_IOCTL_LOGSTREAM_GET_SEVERITY: + if (!arg) + return EINVAL; + *(unsigned*)arg = sp->severity; + break; + + case MU_IOCTL_LOGSTREAM_SET_SEVERITY: + if (!arg) + return EINVAL; + if (*(unsigned*)arg >= _mu_severity_num) + return EINVAL; + sp->severity = *(unsigned*)arg; + break; + + case MU_IOCTL_LOGSTREAM_GET_MODE: + if (!arg) + return EINVAL; + *(int*)arg = sp->logmode; + break; + + case MU_IOCTL_LOGSTREAM_SET_MODE: + if (!arg) + return EINVAL; + sp->logmode = *(int*)arg; + break; + + case MU_IOCTL_LOGSTREAM_GET_LOCUS: + { + struct mu_locus *ploc = arg; + if (!arg) + return EINVAL; + if (sp->locus.mu_file) + { + ploc->mu_file = strdup (sp->locus.mu_file); + if (!ploc->mu_file) + return ENOMEM; + } + else + ploc->mu_file = NULL; + ploc->mu_line = sp->locus.mu_line; + ploc->mu_col = sp->locus.mu_col; + break; + } + + case MU_IOCTL_LOGSTREAM_SET_LOCUS: + { + struct mu_locus *ploc = arg; + if (!arg) + { + free (sp->locus.mu_file); + sp->locus.mu_file = NULL; + sp->locus.mu_line = 0; + sp->locus.mu_col = 0; + } + else + { + if (ploc->mu_file) + _locus_set_file (&sp->locus, ploc->mu_file, + strlen (ploc->mu_file)); + if (ploc->mu_line) + _locus_set_line (&sp->locus, ploc->mu_line); + if (ploc->mu_col) + _locus_set_col (&sp->locus, ploc->mu_col); + } + break; + } + + default: + return ENOSYS; + } + return 0; +} + +int +mu_log_stream_create (mu_stream_t *pstr, mu_stream_t transport) +{ + struct _mu_log_stream *sp; + mu_stream_t stream; + int rc; + + sp = (struct _mu_log_stream *) + _mu_stream_create (sizeof (*sp), MU_STREAM_WRITE); + if (!sp) + return ENOMEM; + sp->base.write = _log_write; + sp->base.flush = _log_flush; + sp->base.close = _log_close; + sp->base.done = _log_done; + sp->base.setbuf_hook = _log_setbuf_hook; + sp->base.ctl = _log_ctl; + sp->transport = transport; + mu_stream_ref (transport); + sp->severity = MU_LOG_ERROR; + sp->logmode = 0; + + stream = (mu_stream_t) sp; + mu_stream_set_buffer (stream, mu_buffer_line, 0); + rc = mu_stream_open (stream); + if (rc) + mu_stream_destroy (&stream); + else + *pstr = stream; + + return rc; +} + + diff --git a/libmailutils/stream/syslogstream.c b/libmailutils/stream/syslogstream.c new file mode 100644 index 000000000..384694e59 --- /dev/null +++ b/libmailutils/stream/syslogstream.c @@ -0,0 +1,90 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <syslog.h> +#include <errno.h> +#include <string.h> +#include <mailutils/stream.h> +#include <mailutils/sys/syslogstream.h> + +static int +_syslog_stream_write (struct _mu_stream *stream, const char *buf, + size_t size, size_t *pret) +{ + struct _mu_syslog_stream *lsp = (struct _mu_syslog_stream *)stream; + + *pret = size; + if (size > 0 && buf[size-1] == '\n') + size--; + if (size == 0) + return 0; + syslog (lsp->prio, "%*.*s", (int) size, (int) size, buf); + return 0; +} + +static int +_syslog_ctl (struct _mu_stream *str, int op, void *arg) +{ + struct _mu_syslog_stream *sp = (struct _mu_syslog_stream *)str; + + switch (op) + { + case MU_IOCTL_LOGSTREAM_GET_SEVERITY: + if (!arg) + return EINVAL; + *(int*)arg = sp->prio; + break; + + case MU_IOCTL_LOGSTREAM_SET_SEVERITY: + if (!arg) + return EINVAL; + sp->prio = *(int*)arg; + break; + + default: + return ENOSYS; + } + return 0; +} + +int +_syslog_setbuf_hook (mu_stream_t str, enum mu_buffer_type type, size_t size) +{ + if (type != mu_buffer_line) + return EACCES; + return 0; +} + +int +mu_syslog_stream_create (mu_stream_t *pstream, int prio) +{ + struct _mu_syslog_stream *str = + (struct _mu_syslog_stream *) _mu_stream_create (sizeof (*str), + MU_STREAM_WRITE); + if (!str) + return ENOMEM; + str->prio = prio; + str->base.write = _syslog_stream_write; + str->base.ctl = _syslog_ctl; + str->base.setbuf_hook = _syslog_setbuf_hook; + *pstream = (mu_stream_t) str; + mu_stream_set_buffer (*pstream, mu_buffer_line, 0); + return 0; +} |