mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 13:43:22 +00:00 
			
		
		
		
	Might've made a few things too many `static` there. Signed-off-by: David Lamparter <equinox@diac24.net>
		
			
				
	
	
		
			287 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2015-19  David Lamparter, for NetDEF, Inc.
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, and distribute this software for any
 | 
						|
 * purpose with or without fee is hereby granted, provided that the above
 | 
						|
 * copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
						|
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
						|
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef _FRR_ZLOG_H
 | 
						|
#define _FRR_ZLOG_H
 | 
						|
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdbool.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <string.h>
 | 
						|
#include <syslog.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/uio.h>
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
#include "atomlist.h"
 | 
						|
#include "frrcu.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "hook.h"
 | 
						|
#include "printfrr.h"
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
extern "C" {
 | 
						|
#endif
 | 
						|
 | 
						|
DECLARE_MGROUP(LOG);
 | 
						|
 | 
						|
extern char zlog_prefix[];
 | 
						|
extern size_t zlog_prefixsz;
 | 
						|
extern int zlog_tmpdirfd;
 | 
						|
extern int zlog_instance;
 | 
						|
extern const char *zlog_progname;
 | 
						|
 | 
						|
struct xref_logmsg {
 | 
						|
	struct xref xref;
 | 
						|
 | 
						|
	const char *fmtstring;
 | 
						|
	uint32_t priority;
 | 
						|
	uint32_t ec;
 | 
						|
	const char *args;
 | 
						|
};
 | 
						|
 | 
						|
struct xrefdata_logmsg {
 | 
						|
	struct xrefdata xrefdata;
 | 
						|
 | 
						|
	/* nothing more here right now */
 | 
						|
};
 | 
						|
 | 
						|
/* These functions are set up to write to stdout/stderr without explicit
 | 
						|
 * initialization and/or before config load.  There is no need to call e.g.
 | 
						|
 * fprintf(stderr, ...) just because it's "too early" at startup.  Depending
 | 
						|
 * on context, it may still be the right thing to use fprintf though -- try to
 | 
						|
 * determine wether something is a log message or something else.
 | 
						|
 */
 | 
						|
 | 
						|
extern void vzlogx(const struct xref_logmsg *xref, int prio,
 | 
						|
		   const char *fmt, va_list ap);
 | 
						|
#define vzlog(prio, ...) vzlogx(NULL, prio, __VA_ARGS__)
 | 
						|
 | 
						|
PRINTFRR(2, 3)
 | 
						|
static inline void zlog(int prio, const char *fmt, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
 | 
						|
	va_start(ap, fmt);
 | 
						|
	vzlog(prio, fmt, ap);
 | 
						|
	va_end(ap);
 | 
						|
}
 | 
						|
 | 
						|
PRINTFRR(2, 3)
 | 
						|
static inline void zlog_ref(const struct xref_logmsg *xref,
 | 
						|
			    const char *fmt, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
 | 
						|
	va_start(ap, fmt);
 | 
						|
	vzlogx(xref, xref->priority, fmt, ap);
 | 
						|
	va_end(ap);
 | 
						|
}
 | 
						|
 | 
						|
#define _zlog_ecref(ec_, prio, msg, ...)                                       \
 | 
						|
	do {                                                                   \
 | 
						|
		static struct xrefdata _xrefdata = {                           \
 | 
						|
			.xref = NULL,                                          \
 | 
						|
			.uid = {},                                             \
 | 
						|
			.hashstr = (msg),                                      \
 | 
						|
			.hashu32 = {(prio), (ec_)},                            \
 | 
						|
		};                                                             \
 | 
						|
		static const struct xref_logmsg _xref __attribute__(           \
 | 
						|
			(used)) = {                                            \
 | 
						|
			.xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \
 | 
						|
			.fmtstring = (msg),                                    \
 | 
						|
			.priority = (prio),                                    \
 | 
						|
			.ec = (ec_),                                           \
 | 
						|
			.args = (#__VA_ARGS__),                                \
 | 
						|
		};                                                             \
 | 
						|
		XREF_LINK(_xref.xref);                                         \
 | 
						|
		zlog_ref(&_xref, (msg), ##__VA_ARGS__);                        \
 | 
						|
	} while (0)
 | 
						|
 | 
						|
#define zlog_err(...)    _zlog_ecref(0, LOG_ERR, __VA_ARGS__)
 | 
						|
#define zlog_warn(...)   _zlog_ecref(0, LOG_WARNING, __VA_ARGS__)
 | 
						|
#define zlog_info(...)   _zlog_ecref(0, LOG_INFO, __VA_ARGS__)
 | 
						|
#define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__)
 | 
						|
#define zlog_debug(...)  _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__)
 | 
						|
 | 
						|
#define flog_err(ferr_id, format, ...)                                         \
 | 
						|
	_zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
 | 
						|
#define flog_warn(ferr_id, format, ...)                                        \
 | 
						|
	_zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__)
 | 
						|
 | 
						|
#define flog_err_sys(ferr_id, format, ...)                                     \
 | 
						|
	_zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
 | 
						|
 | 
						|
extern void zlog_sigsafe(const char *text, size_t len);
 | 
						|
 | 
						|
/* extra priority value to disable a target without deleting it */
 | 
						|
#define ZLOG_DISABLED	(LOG_EMERG-1)
 | 
						|
 | 
						|
/* zlog_msg encapsulates a particular logging call from somewhere in the code.
 | 
						|
 * The same struct is passed around to all zlog_targets.
 | 
						|
 *
 | 
						|
 * This is used to defer formatting the log message until it is actually
 | 
						|
 * requested by one of the targets.  If none of the targets needs the message
 | 
						|
 * formatted, the formatting call is avoided entirely.
 | 
						|
 *
 | 
						|
 * This struct is opaque / private to the core zlog code.  Logging targets
 | 
						|
 * should use zlog_msg_* functions to get text / timestamps / ... for a
 | 
						|
 * message.
 | 
						|
 */
 | 
						|
 | 
						|
struct zlog_msg;
 | 
						|
 | 
						|
extern int zlog_msg_prio(struct zlog_msg *msg);
 | 
						|
extern const struct xref_logmsg *zlog_msg_xref(struct zlog_msg *msg);
 | 
						|
 | 
						|
/* text is NOT \0 terminated; instead there is a \n after textlen since the
 | 
						|
 * logging targets would jump extra hoops otherwise for a single byte.  (the
 | 
						|
 * \n is not included in textlen)
 | 
						|
 *
 | 
						|
 * calling this with NULL textlen is likely wrong.
 | 
						|
 * use  "%.*s", (int)textlen, text  when passing to printf-like functions
 | 
						|
 */
 | 
						|
extern const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen);
 | 
						|
 | 
						|
extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen,
 | 
						|
			  size_t *n_argpos, const struct fmt_outpos **argpos);
 | 
						|
 | 
						|
/* timestamp formatting control flags */
 | 
						|
 | 
						|
/* sub-second digit count */
 | 
						|
#define ZLOG_TS_PREC		0xfU
 | 
						|
 | 
						|
/* 8601:   0000-00-00T00:00:00Z      (if used with ZLOG_TS_UTC)
 | 
						|
 *         0000-00-00T00:00:00+00:00 (otherwise)
 | 
						|
 * Legacy: 0000/00/00 00:00:00       (no TZ indicated!)
 | 
						|
 */
 | 
						|
#define ZLOG_TS_ISO8601		(1 << 8)
 | 
						|
#define ZLOG_TS_LEGACY		(1 << 9)
 | 
						|
 | 
						|
/* default is local time zone */
 | 
						|
#define ZLOG_TS_UTC		(1 << 10)
 | 
						|
 | 
						|
extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out,
 | 
						|
			  uint32_t flags);
 | 
						|
 | 
						|
/* "mmm dd hh:mm:ss" for RFC3164 syslog.  Only ZLOG_TS_UTC for flags. */
 | 
						|
extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out,
 | 
						|
			       uint32_t flags);
 | 
						|
 | 
						|
/* currently just returns the current PID/TID since we never write another
 | 
						|
 * thread's messages
 | 
						|
 */
 | 
						|
extern void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid);
 | 
						|
 | 
						|
/* This list & struct implements the actual logging targets.  It is accessed
 | 
						|
 * lock-free from all threads, and thus MUST only be changed atomically, i.e.
 | 
						|
 * RCU.
 | 
						|
 *
 | 
						|
 * Since there's no atomic replace, the replacement action is an add followed
 | 
						|
 * by a delete.  This means that during logging config changes, log messages
 | 
						|
 * may be duplicated in the log target that is being changed.  The old entry
 | 
						|
 * being changed MUST also at the very least not crash or do other stupid
 | 
						|
 * things.
 | 
						|
 *
 | 
						|
 * This list and struct are NOT related to config.  Logging config is kept
 | 
						|
 * separately, and results in creating appropriate zlog_target(s) to realize
 | 
						|
 * the config.  Log targets may also be created from varying sources, e.g.
 | 
						|
 * command line options, or VTY commands ("log monitor").
 | 
						|
 *
 | 
						|
 * struct zlog_target is intended to be embedded into a larger structure that
 | 
						|
 * contains additional field for the specific logging target, e.g. an fd or
 | 
						|
 * additional options.  It MUST be the first field in that larger struct.
 | 
						|
 */
 | 
						|
 | 
						|
PREDECL_ATOMLIST(zlog_targets);
 | 
						|
struct zlog_target {
 | 
						|
	struct zlog_targets_item head;
 | 
						|
 | 
						|
	int prio_min;
 | 
						|
 | 
						|
	void (*logfn)(struct zlog_target *zt, struct zlog_msg *msg[],
 | 
						|
		      size_t nmsgs);
 | 
						|
 | 
						|
	/* for crash handlers, set to NULL if log target can't write crash logs
 | 
						|
	 * without possibly deadlocking (AS-Safe)
 | 
						|
	 *
 | 
						|
	 * text is not \0 terminated & split up into lines (e.g. no \n)
 | 
						|
	 */
 | 
						|
	void (*logfn_sigsafe)(struct zlog_target *zt, const char *text,
 | 
						|
			      size_t len);
 | 
						|
 | 
						|
	struct rcu_head rcu_head;
 | 
						|
};
 | 
						|
 | 
						|
/* make a copy for RCUpdating.  oldzt may be NULL to allocate a fresh one. */
 | 
						|
extern struct zlog_target *zlog_target_clone(struct memtype *mt,
 | 
						|
					     struct zlog_target *oldzt,
 | 
						|
					     size_t size);
 | 
						|
 | 
						|
/* update the zlog_targets list;  both oldzt and newzt may be NULL.  You
 | 
						|
 * still need to zlog_target_free() the old target afterwards if it wasn't
 | 
						|
 * NULL.
 | 
						|
 *
 | 
						|
 * Returns oldzt so you can zlog_target_free(zlog_target_replace(old, new));
 | 
						|
 * (Some log targets may need extra cleanup inbetween, but remember the old
 | 
						|
 * target MUST remain functional until the end of the current RCU cycle.)
 | 
						|
 */
 | 
						|
extern struct zlog_target *zlog_target_replace(struct zlog_target *oldzt,
 | 
						|
					       struct zlog_target *newzt);
 | 
						|
 | 
						|
/* Mostly for symmetry for zlog_target_clone(), just rcu_free() internally. */
 | 
						|
#define zlog_target_free(mt, zt) \
 | 
						|
	rcu_free(mt, zt, rcu_head)
 | 
						|
 | 
						|
extern void zlog_init(const char *progname, const char *protoname,
 | 
						|
		      unsigned short instance, uid_t uid, gid_t gid);
 | 
						|
DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname,
 | 
						|
			 unsigned short instance, uid_t uid, gid_t gid),
 | 
						|
			(progname, protoname, instance, uid, gid));
 | 
						|
 | 
						|
extern void zlog_fini(void);
 | 
						|
DECLARE_KOOH(zlog_fini, (), ());
 | 
						|
 | 
						|
extern void zlog_set_prefix_ec(bool enable);
 | 
						|
extern bool zlog_get_prefix_ec(void);
 | 
						|
extern void zlog_set_prefix_xid(bool enable);
 | 
						|
extern bool zlog_get_prefix_xid(void);
 | 
						|
 | 
						|
/* for tools & test programs, i.e. anything not a daemon.
 | 
						|
 * (no cleanup needed at exit)
 | 
						|
 */
 | 
						|
extern void zlog_aux_init(const char *prefix, int prio_min);
 | 
						|
DECLARE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
 | 
						|
			    (prefix, prio_min));
 | 
						|
 | 
						|
extern void zlog_startup_end(void);
 | 
						|
 | 
						|
extern void zlog_tls_buffer_init(void);
 | 
						|
extern void zlog_tls_buffer_flush(void);
 | 
						|
extern void zlog_tls_buffer_fini(void);
 | 
						|
 | 
						|
/* Enable or disable 'immediate' output - default is to buffer messages. */
 | 
						|
extern void zlog_set_immediate(bool set_p);
 | 
						|
 | 
						|
extern const char *zlog_priority_str(int priority);
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#endif /* _FRR_ZLOG_H */
 |