/* $Id: logger.c,v 1.2 2001/03/03 13:59:05 steve Exp $ */ /*- * Copyright (c) 2001 Steve C. Woodford. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Steve C. Woodford. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "context.h" #include "buffer.h" #include "config.h" #include "logger.h" static const char *cf_logger_init(void *, char **, int, int, void *); static int logger_init(struct client_ctx *, const void *); static void logger_destroy(struct client_ctx *); static int logger_event(struct client_ctx *, int); static int logger_output(struct client_ctx *, const char *, size_t, struct client_ctx *); static int logger_write_pending(struct client_ctx *); static int logger_read_pending(struct client_ctx *); struct client_ops logger_ops = { "logger", cf_logger_init, logger_init, logger_destroy, logger_event, logger_output, logger_read_pending, logger_write_pending, NULL }; static const char *cf_logger_file(void *, char **, int, int, void *); static const char *cf_logger_mode(void *, char **, int, int, void *); static const char *cf_logger_trunc(void *, char **, int, int, void *); static struct config_tokens cf_logger_tokens[] = { {"file", 1, cf_logger_file}, {"mode", 1, cf_logger_mode}, {"trunc", 1, cf_logger_trunc}, {NULL, 0, NULL} }; struct logger_opts { char *lo_file; mode_t lo_mode; int lo_fmode; int lo_fd; }; struct logger_ctx { struct buffer_ctx *lc_bc; int lc_fd; }; /* ARGSUSED */ static const char * cf_logger_init(void *cs, char **argv, int argc, int is_compound, void *arg) { struct context *ctx = arg; struct client_ctx *cc; struct logger_opts lo; const char *errstr; lo.lo_file = NULL; lo.lo_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; lo.lo_fmode = O_RDWR | O_CREAT | O_APPEND; errstr = config_parse(cs, cf_logger_tokens, (void *)&lo); if (errstr) return (errstr); if (lo.lo_file == NULL) return (config_err(cs, "`file' option required")); if ((lo.lo_fd = open(lo.lo_file, lo.lo_fmode, lo.lo_mode)) < 0) { (void) free(lo.lo_file); return (config_err(cs, "%s: %s", lo.lo_file, strerror(errno))); } if (client_init(&cc, NULL, &logger_ops, NULL, &lo) < 0) { errstr = config_err(cs, "%s: %s", lo.lo_file, strerror(errno)); (void) free(lo.lo_file); } else if (context_add_client(ctx, cc) < 0) { errstr = (config_err(cs, "%s: %s", lo.lo_file, strerror(errno))); client_destroy(cc); } return (errstr); } static int logger_init(struct client_ctx *cc, const void *arg) { const struct logger_opts *lo = arg; struct buffer_ctx *bc; if (buffer_init(&bc, lo->lo_fd) < 0) return (-1); cc->cc_name = lo->lo_file; cc->cc_data = (void *) bc; cc->cc_fd = lo->lo_fd; return (0); } static void logger_destroy(struct client_ctx *cc) { buffer_destroy((struct buffer_ctx *)cc->cc_data); (void) close(cc->cc_fd); (void) free(cc->cc_name); } static int logger_event(struct client_ctx *cc, int events) { if ((events & POLLWRNORM) != 0) return ((int) buffer_drain((struct buffer_ctx *) cc->cc_data)); return (0); } /* ARGSUSED */ static int logger_output(struct client_ctx *cc, const char *buff, size_t len, struct client_ctx *sender) { return (buffer_fill((struct buffer_ctx *) cc->cc_data, buff, len)); } static int logger_write_pending(struct client_ctx *cc) { return (buffer_length((struct buffer_ctx *) cc->cc_data) != 0); } /* ARGSUSED */ static int logger_read_pending(struct client_ctx *cc) { return (0); } /* ARGSUSED */ static const char * cf_logger_file(void *cs, char **argv, int argc, int cmpnd, void *arg) { struct logger_opts *lo = arg; if ((lo->lo_file = strdup(argv[1])) == NULL) return (config_err(cs, "log file: %s", strerror(errno))); return (NULL); } /* ARGSUSED */ static const char * cf_logger_mode(void *cs, char **argv, int argc, int cmpnd, void *arg) { struct logger_opts *lo = arg; const char *errstr; int mode; if ((errstr = config_integer(cs, argv[1], &mode)) == NULL) lo->lo_mode = (mode_t) mode; return (errstr); } /* ARGSUSED */ static const char * cf_logger_trunc(void *cs, char **argv, int argc, int cmpnd, void *arg) { struct logger_opts *lo = arg; const char *errstr; int trunc; if ((errstr = config_boolean(cs, argv[1], &trunc)) != NULL) return (errstr); if (trunc) lo->lo_fmode |= O_TRUNC; return (NULL); }