/*
* Copyright (c) 2001-2002 Packet Design, LLC.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty,
* use and redistribution of this software, in source or object code
* forms, with or without modifications are expressly permitted by
* Packet Design; provided, however, that:
*
* (i) Any and all reproductions of the source or object code
* must include the copyright notice above and the following
* disclaimer of warranties; and
* (ii) No rights are granted, in any manner or form, to use
* Packet Design trademarks, including the mark "PACKET DESIGN"
* on advertising, endorsements, or otherwise except as such
* appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
* THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
* OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
* OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
* OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
* RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
* LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
* OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
* DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
* USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 PACKET DESIGN IS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Archie Cobbs <archie@freebsd.org>
*/
#include "ppp/ppp_defs.h"
#include "ppp/ppp_log.h"
#define LOG_MTYPE "ppp_log"
struct ppp_log {
void *arg;
u_int refs;
ppp_log_vput_t *vput;
ppp_log_close_t *close;
};
/*
* Create a new log.
*/
struct ppp_log *
ppp_log_create(void *arg, ppp_log_vput_t *vput, ppp_log_close_t *close)
{
struct ppp_log *log;
if ((log = MALLOC(LOG_MTYPE, sizeof(*log))) == NULL)
return (NULL);
memset(log, 0, sizeof(*log));
log->arg = arg;
log->vput = vput;
log->close = close;
log->refs = 1;
return (log);
}
struct ppp_log *
ppp_log_dup(struct ppp_log *log)
{
if (log == NULL)
return (NULL);
log->refs++;
return (log);
}
void
ppp_log_close(struct ppp_log **logp)
{
struct ppp_log *const log = *logp;
if (log == NULL)
return;
*logp = NULL;
assert(log->refs > 0);
if (--log->refs == 0) {
if (log->close != NULL)
(*log->close)(log->arg);
FREE(LOG_MTYPE, log);
}
}
void
ppp_log_put(struct ppp_log *log, int sev, const char *fmt, ...)
{
va_list args;
if (log == NULL)
return;
va_start(args, fmt);
ppp_log_vput(log, sev, fmt, args);
va_end(args);
}
void
ppp_log_vput(struct ppp_log *log, int sev, const char *fmt, va_list args)
{
int esave;
if (log == NULL)
return;
esave = errno;
(*log->vput)(log->arg, sev, fmt, args);
errno = esave;
}
void
ppp_log_dump(struct ppp_log *log, int sev, const void *data, size_t len)
{
static const int num = 16; /* # bytes per line */
const u_char *bytes = data;
char buf[128];
int i, j;
/* Dump data */
for (i = 0; i < ((len + num - 1) / num) * num; i += num) {
snprintf(buf, sizeof(buf), "0x%04x ", i);
for (j = i; j < i + num; j++) {
if (j < len) {
snprintf(buf + strlen(buf),
sizeof(buf) - strlen(buf),
"%02x", bytes[j]);
} else {
snprintf(buf + strlen(buf),
sizeof(buf) - strlen(buf), " ");
}
if ((j % 2) == 1) {
snprintf(buf + strlen(buf),
sizeof(buf) - strlen(buf), " ");
}
}
snprintf(buf + strlen(buf),
sizeof(buf) - strlen(buf), " ");
for (j = i; j < i + num; j++) {
if (j < len) {
snprintf(buf + strlen(buf),
sizeof(buf) - strlen(buf), "%c",
isprint(bytes[j]) ? bytes[j] : '.');
}
}
ppp_log_put(log, sev, "%s", buf);
}
}
/***********************************************************************
PREFIX LOG METHODS
***********************************************************************/
struct ppp_log_prefix {
struct ppp_log *log;
char *prefix;
};
/* Internal functions */
static ppp_log_vput_t ppp_log_prefix_vput;
static ppp_log_close_t ppp_log_prefix_close;
/*
* Create a new log that prefixes everything before sending
* it to another underlying log.
*
* The underlying log is NOT closed when the returned log is closed.
*/
struct ppp_log *
ppp_log_prefix(struct ppp_log *log, const char *fmt, ...)
{
struct ppp_log_prefix *priv;
va_list args;
/* If no log or prefix, just duplicate log */
if (log == NULL)
return (NULL);
if (fmt == NULL || *fmt == '\0')
return (ppp_log_dup(log));
/* Create prefix log */
if ((priv = MALLOC(LOG_MTYPE, sizeof(*priv))) == NULL)
return (NULL);
va_start(args, fmt);
VASPRINTF(LOG_MTYPE, &priv->prefix, fmt, args);
va_end(args);
if (priv->prefix == NULL) {
FREE(LOG_MTYPE, priv);
return (NULL);
}
/* Sanity check prefix: we can't handle any formats in it */
if (strchr(priv->prefix, '%') != NULL) {
errno = EINVAL;
return (NULL);
}
/* Create new log object using prefix log methods */
priv->log = ppp_log_dup(log); /* can't fail */
if ((log = ppp_log_create(priv,
ppp_log_prefix_vput, ppp_log_prefix_close)) == NULL) {
ppp_log_close(&priv->log);
FREE(LOG_MTYPE, priv->prefix);
FREE(LOG_MTYPE, priv);
return (NULL);
}
/* Done */
return (log);
}
static void
ppp_log_prefix_vput(void *arg, int sev, const char *fmt, va_list args)
{
struct ppp_log_prefix *const priv = arg;
const size_t plen = strlen(priv->prefix);
const size_t flen = strlen(fmt);
char *pfmt;
/* Create new format string with prefix prefixed */
if ((pfmt = MALLOC(TYPED_MEM_TEMP, plen + flen + 1)) == NULL) {
ppp_log_vput(priv->log, sev, fmt, args); /* salvage */
return;
}
memcpy(pfmt, priv->prefix, plen);
memcpy(pfmt + plen, fmt, flen + 1);
/* Log same arguments with new format string */
ppp_log_vput(priv->log, sev, pfmt, args);
FREE(TYPED_MEM_TEMP, pfmt);
}
static void
ppp_log_prefix_close(void *arg)
{
struct ppp_log_prefix *const priv = arg;
ppp_log_close(&priv->log);
FREE(LOG_MTYPE, priv->prefix);
FREE(LOG_MTYPE, priv);
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>