Blame src/nm-logging.c

Packit Service b23acc
// SPDX-License-Identifier: GPL-2.0+
Packit Service b23acc
/*
Packit Service b23acc
 * Copyright (C) 2006 - 2012 Red Hat, Inc.
Packit Service b23acc
 * Copyright (C) 2006 - 2008 Novell, Inc.
Packit Service b23acc
 */
Packit Service b23acc
Packit Service b23acc
#include "nm-default.h"
Packit Service b23acc
Packit Service b23acc
#include "nm-logging.h"
Packit Service b23acc
Packit Service b23acc
#include <dlfcn.h>
Packit Service b23acc
#include <syslog.h>
Packit Service b23acc
#include <stdio.h>
Packit Service b23acc
#include <stdlib.h>
Packit Service b23acc
#include <unistd.h>
Packit Service b23acc
#include <sys/wait.h>
Packit Service b23acc
#include <sys/stat.h>
Packit Service b23acc
#include <strings.h>
Packit Service b23acc
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
#define SD_JOURNAL_SUPPRESS_LOCATION
Packit Service b23acc
#include <systemd/sd-journal.h>
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
#include "nm-glib-aux/nm-logging-base.h"
Packit Service b23acc
#include "nm-glib-aux/nm-time-utils.h"
Packit Service b23acc
#include "nm-errors.h"
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
/* Notes about thread-safety:
Packit Service b23acc
 *
Packit Service b23acc
 * NetworkManager generally is single-threaded and uses a (GLib) mainloop.
Packit Service b23acc
 * However, nm-logging is in parts thread-safe. That means:
Packit Service b23acc
 *
Packit Service b23acc
 * - functions that configure logging (nm_logging_init(), nm_logging_setup()) and
Packit Service b23acc
 *   most other functions MUST be called only from the main-thread. These functions
Packit Service b23acc
 *   are expected to be called infrequently, so they may or may not use a mutex
Packit Service b23acc
 *   (but the overhead is negligible here).
Packit Service b23acc
 *
Packit Service b23acc
 * - functions that do the actual logging logging (nm_log(), nm_logging_enabled()) are
Packit Service b23acc
 *   thread-safe and may be used from multiple threads.
Packit Service b23acc
 *    - When called from the not-main-thread, @mt_require_locking must be set to %TRUE.
Packit Service b23acc
 *      In this case, a Mutex will be used for accessing the global state.
Packit Service b23acc
 *    - When called from the main-thread, they may optionally pass @mt_require_locking %FALSE.
Packit Service b23acc
 *      This avoids extra locking and is in particular interesting for nm_logging_enabled(),
Packit Service b23acc
 *      which is expected to be called frequently and from the main-thread.
Packit Service b23acc
 *
Packit Service b23acc
 * Note that the logging macros honor %NM_THREAD_SAFE_ON_MAIN_THREAD define, to automatically
Packit Service b23acc
 * set @mt_require_locking. That means, by default %NM_THREAD_SAFE_ON_MAIN_THREAD is "1",
Packit Service b23acc
 * and code that only runs on the main-thread (which is the majority), can get away
Packit Service b23acc
 * without locking.
Packit Service b23acc
 */
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
G_STATIC_ASSERT (LOG_EMERG   == 0);
Packit Service b23acc
G_STATIC_ASSERT (LOG_ALERT   == 1);
Packit Service b23acc
G_STATIC_ASSERT (LOG_CRIT    == 2);
Packit Service b23acc
G_STATIC_ASSERT (LOG_ERR     == 3);
Packit Service b23acc
G_STATIC_ASSERT (LOG_WARNING == 4);
Packit Service b23acc
G_STATIC_ASSERT (LOG_NOTICE  == 5);
Packit Service b23acc
G_STATIC_ASSERT (LOG_INFO    == 6);
Packit Service b23acc
G_STATIC_ASSERT (LOG_DEBUG   == 7);
Packit Service b23acc
Packit Service b23acc
/* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */
Packit Service b23acc
G_STATIC_ASSERT (sizeof (NMLogDomain) >= sizeof (guint64));
Packit Service b23acc
Packit Service b23acc
/* Combined domains */
Packit Service b23acc
#define LOGD_ALL_STRING     "ALL"
Packit Service b23acc
#define LOGD_DEFAULT_STRING "DEFAULT"
Packit Service b23acc
#define LOGD_DHCP_STRING    "DHCP"
Packit Service b23acc
#define LOGD_IP_STRING      "IP"
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
typedef enum {
Packit Service b23acc
	LOG_BACKEND_GLIB,
Packit Service b23acc
	LOG_BACKEND_SYSLOG,
Packit Service b23acc
	LOG_BACKEND_JOURNAL,
Packit Service b23acc
} LogBackend;
Packit Service b23acc
Packit Service b23acc
typedef struct {
Packit Service b23acc
	NMLogDomain num;
Packit Service b23acc
	const char *name;
Packit Service b23acc
} LogDesc;
Packit Service b23acc
Packit Service b23acc
typedef struct {
Packit Service b23acc
	char *logging_domains_to_string;
Packit Service b23acc
} GlobalMain;
Packit Service b23acc
Packit Service b23acc
typedef struct {
Packit Service b23acc
	NMLogLevel log_level;
Packit Service b23acc
	bool uses_syslog:1;
Packit Service b23acc
	bool init_pre_done:1;
Packit Service b23acc
	bool init_done:1;
Packit Service b23acc
	bool debug_stderr:1;
Packit Service b23acc
	const char *prefix;
Packit Service b23acc
	const char *syslog_identifier;
Packit Service b23acc
Packit Service b23acc
	/* before we setup syslog (during start), the backend defaults to GLIB, meaning:
Packit Service b23acc
	 * we use g_log() for all logging. At that point, the application is not yet supposed
Packit Service b23acc
	 * to do any logging and doing so indicates a bug.
Packit Service b23acc
	 *
Packit Service b23acc
	 * Afterwards, the backend is either SYSLOG or JOURNAL. From that point, also
Packit Service b23acc
	 * g_log() is redirected to this backend via a logging handler. */
Packit Service b23acc
	LogBackend log_backend;
Packit Service b23acc
} Global;
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
G_LOCK_DEFINE_STATIC (log);
Packit Service b23acc
Packit Service b23acc
/* This data must only be accessed from the main-thread (and as
Packit Service b23acc
 * such does not need any lock). */
Packit Service b23acc
static GlobalMain gl_main = { };
Packit Service b23acc
Packit Service b23acc
static union {
Packit Service b23acc
	/* a union with an immutable and a mutable alias for the Global.
Packit Service b23acc
	 * Since nm-logging must be thread-safe, we must take care at which
Packit Service b23acc
	 * places we only read value ("imm") and where we modify them ("mut"). */
Packit Service b23acc
	Global       mut;
Packit Service b23acc
	const Global imm;
Packit Service b23acc
} gl = {
Packit Service b23acc
	.imm = {
Packit Service b23acc
		/* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL); */
Packit Service b23acc
		.log_level = LOGL_INFO,
Packit Service b23acc
		.log_backend = LOG_BACKEND_GLIB,
Packit Service b23acc
		.syslog_identifier = "SYSLOG_IDENTIFIER="G_LOG_DOMAIN,
Packit Service b23acc
		.prefix = "",
Packit Service b23acc
	},
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL] = {
Packit Service b23acc
	/* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL);
Packit Service b23acc
	 *
Packit Service b23acc
	 * Note: LOGD_VPN_PLUGIN is special and must be disabled for
Packit Service b23acc
	 * DEBUG and TRACE levels. */
Packit Service b23acc
	[LOGL_INFO] = LOGD_DEFAULT,
Packit Service b23acc
	[LOGL_WARN] = LOGD_DEFAULT,
Packit Service b23acc
	[LOGL_ERR]  = LOGD_DEFAULT,
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static const LogDesc domain_desc[] = {
Packit Service b23acc
	{ LOGD_PLATFORM,  "PLATFORM" },
Packit Service b23acc
	{ LOGD_RFKILL,    "RFKILL" },
Packit Service b23acc
	{ LOGD_ETHER,     "ETHER" },
Packit Service b23acc
	{ LOGD_WIFI,      "WIFI" },
Packit Service b23acc
	{ LOGD_BT,        "BT" },
Packit Service b23acc
	{ LOGD_MB,        "MB" },
Packit Service b23acc
	{ LOGD_DHCP4,     "DHCP4" },
Packit Service b23acc
	{ LOGD_DHCP6,     "DHCP6" },
Packit Service b23acc
	{ LOGD_PPP,       "PPP" },
Packit Service b23acc
	{ LOGD_WIFI_SCAN, "WIFI_SCAN" },
Packit Service b23acc
	{ LOGD_IP4,       "IP4" },
Packit Service b23acc
	{ LOGD_IP6,       "IP6" },
Packit Service b23acc
	{ LOGD_AUTOIP4,   "AUTOIP4" },
Packit Service b23acc
	{ LOGD_DNS,       "DNS" },
Packit Service b23acc
	{ LOGD_VPN,       "VPN" },
Packit Service b23acc
	{ LOGD_SHARING,   "SHARING" },
Packit Service b23acc
	{ LOGD_SUPPLICANT,"SUPPLICANT" },
Packit Service b23acc
	{ LOGD_AGENTS,    "AGENTS" },
Packit Service b23acc
	{ LOGD_SETTINGS,  "SETTINGS" },
Packit Service b23acc
	{ LOGD_SUSPEND,   "SUSPEND" },
Packit Service b23acc
	{ LOGD_CORE,      "CORE" },
Packit Service b23acc
	{ LOGD_DEVICE,    "DEVICE" },
Packit Service b23acc
	{ LOGD_OLPC,      "OLPC" },
Packit Service b23acc
	{ LOGD_INFINIBAND,"INFINIBAND" },
Packit Service b23acc
	{ LOGD_FIREWALL,  "FIREWALL" },
Packit Service b23acc
	{ LOGD_ADSL,      "ADSL" },
Packit Service b23acc
	{ LOGD_BOND,      "BOND" },
Packit Service b23acc
	{ LOGD_VLAN,      "VLAN" },
Packit Service b23acc
	{ LOGD_BRIDGE,    "BRIDGE" },
Packit Service b23acc
	{ LOGD_DBUS_PROPS,"DBUS_PROPS" },
Packit Service b23acc
	{ LOGD_TEAM,      "TEAM" },
Packit Service b23acc
	{ LOGD_CONCHECK,  "CONCHECK" },
Packit Service b23acc
	{ LOGD_DCB,       "DCB" },
Packit Service b23acc
	{ LOGD_DISPATCH,  "DISPATCH" },
Packit Service b23acc
	{ LOGD_AUDIT,     "AUDIT" },
Packit Service b23acc
	{ LOGD_SYSTEMD,   "SYSTEMD" },
Packit Service b23acc
	{ LOGD_VPN_PLUGIN,"VPN_PLUGIN" },
Packit Service b23acc
	{ LOGD_PROXY,     "PROXY" },
Packit Service b23acc
	{ 0 },
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static char *_domains_to_string (gboolean include_level_override,
Packit Service b23acc
                                 NMLogLevel log_level,
Packit Service b23acc
                                 const NMLogDomain log_state[static _LOGL_N_REAL]);
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static gboolean
Packit Service b23acc
_syslog_identifier_valid_domain (const char *domain)
Packit Service b23acc
{
Packit Service b23acc
	char c;
Packit Service b23acc
Packit Service b23acc
	if (!domain || !domain[0])
Packit Service b23acc
		return FALSE;
Packit Service b23acc
Packit Service b23acc
	/* we pass the syslog identifier as format string. No funny stuff. */
Packit Service b23acc
Packit Service b23acc
	for (; (c = domain[0]); domain++) {
Packit Service b23acc
		if (   (c >= 'a' && c <= 'z')
Packit Service b23acc
		    || (c >= 'A' && c <= 'Z')
Packit Service b23acc
		    || (c >= '0' && c <= '9')
Packit Service b23acc
		    || NM_IN_SET (c, '-', '_'))
Packit Service b23acc
			continue;
Packit Service b23acc
		return FALSE;
Packit Service b23acc
	}
Packit Service b23acc
	return TRUE;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static gboolean
Packit Service b23acc
_syslog_identifier_assert (const char *syslog_identifier)
Packit Service b23acc
{
Packit Service b23acc
	g_assert (syslog_identifier);
Packit Service b23acc
	g_assert (g_str_has_prefix (syslog_identifier, "SYSLOG_IDENTIFIER="));
Packit Service b23acc
	g_assert (_syslog_identifier_valid_domain (&syslog_identifier[NM_STRLEN ("SYSLOG_IDENTIFIER=")]));
Packit Service b23acc
	return TRUE;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static const char *
Packit Service b23acc
syslog_identifier_domain (const char *syslog_identifier)
Packit Service b23acc
{
Packit Service b23acc
	nm_assert (_syslog_identifier_assert (syslog_identifier));
Packit Service b23acc
	return &syslog_identifier[NM_STRLEN ("SYSLOG_IDENTIFIER=")];
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
static const char *
Packit Service b23acc
syslog_identifier_full (const char *syslog_identifier)
Packit Service b23acc
{
Packit Service b23acc
	nm_assert (_syslog_identifier_assert (syslog_identifier));
Packit Service b23acc
	return &syslog_identifier[0];
Packit Service b23acc
}
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static gboolean
Packit Service b23acc
match_log_level (const char  *level,
Packit Service b23acc
                 NMLogLevel  *out_level,
Packit Service b23acc
                 GError     **error)
Packit Service b23acc
{
Packit Service b23acc
	if (_nm_log_parse_level (level, out_level))
Packit Service b23acc
		return TRUE;
Packit Service b23acc
Packit Service b23acc
	g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_LEVEL,
Packit Service b23acc
	             _("Unknown log level '%s'"), level);
Packit Service b23acc
	return FALSE;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
gboolean
Packit Service b23acc
nm_logging_setup (const char  *level,
Packit Service b23acc
                  const char  *domains,
Packit Service b23acc
                  char       **bad_domains,
Packit Service b23acc
                  GError     **error)
Packit Service b23acc
{
Packit Service b23acc
	GString *unrecognized = NULL;
Packit Service b23acc
	NMLogDomain cur_log_state[_LOGL_N_REAL];
Packit Service b23acc
	NMLogDomain new_log_state[_LOGL_N_REAL];
Packit Service b23acc
	NMLogLevel cur_log_level;
Packit Service b23acc
	NMLogLevel new_log_level;
Packit Service b23acc
	gs_free const char **domains_v = NULL;
Packit Service b23acc
	gsize i_d;
Packit Service b23acc
	int i;
Packit Service b23acc
	gboolean had_platform_debug;
Packit Service b23acc
	gs_free char *domains_free = NULL;
Packit Service b23acc
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	g_return_val_if_fail (!bad_domains || !*bad_domains, FALSE);
Packit Service b23acc
	g_return_val_if_fail (!error || !*error, FALSE);
Packit Service b23acc
Packit Service b23acc
	cur_log_level = gl.imm.log_level;
Packit Service b23acc
	memcpy (cur_log_state, _nm_logging_enabled_state, sizeof (cur_log_state));
Packit Service b23acc
Packit Service b23acc
	new_log_level = cur_log_level;
Packit Service b23acc
Packit Service b23acc
	if (!domains || !*domains) {
Packit Service b23acc
		domains_free = _domains_to_string (FALSE,
Packit Service b23acc
		                                   cur_log_level,
Packit Service b23acc
		                                   cur_log_state);
Packit Service b23acc
		domains = domains_free;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	for (i = 0; i < G_N_ELEMENTS (new_log_state); i++)
Packit Service b23acc
		new_log_state[i] = 0;
Packit Service b23acc
Packit Service b23acc
	if (level && *level) {
Packit Service b23acc
		if (!match_log_level (level, &new_log_level, error))
Packit Service b23acc
			return FALSE;
Packit Service b23acc
		if (new_log_level == _LOGL_KEEP) {
Packit Service b23acc
			new_log_level = cur_log_level;
Packit Service b23acc
			for (i = 0; i < G_N_ELEMENTS (new_log_state); i++)
Packit Service b23acc
				new_log_state[i] = cur_log_state[i];
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	domains_v = nm_utils_strsplit_set (domains, ", ");
Packit Service b23acc
	for (i_d = 0; domains_v && domains_v[i_d]; i_d++) {
Packit Service b23acc
		const char *s = domains_v[i_d];
Packit Service b23acc
		const char *p;
Packit Service b23acc
		const LogDesc *diter;
Packit Service b23acc
		NMLogLevel domain_log_level;
Packit Service b23acc
		NMLogDomain bits;
Packit Service b23acc
Packit Service b23acc
		/* LOGD_VPN_PLUGIN is protected, that is, when setting ALL or DEFAULT,
Packit Service b23acc
		 * it does not enable the verbose levels DEBUG and TRACE, because that
Packit Service b23acc
		 * may expose sensitive data. */
Packit Service b23acc
		NMLogDomain protect = LOGD_NONE;
Packit Service b23acc
Packit Service b23acc
		p = strchr (s, ':');
Packit Service b23acc
		if (p) {
Packit Service b23acc
			*((char *) p) = '\0';
Packit Service b23acc
			if (!match_log_level (p + 1, &domain_log_level, error))
Packit Service b23acc
				return FALSE;
Packit Service b23acc
		} else
Packit Service b23acc
			domain_log_level = new_log_level;
Packit Service b23acc
Packit Service b23acc
		bits = 0;
Packit Service b23acc
Packit Service b23acc
		if (domains_free) {
Packit Service b23acc
			/* The caller didn't provide any domains to set (`nmcli general logging level DEBUG`).
Packit Service b23acc
			 * We reset all domains that were previously set, but we still want to protect
Packit Service b23acc
			 * VPN_PLUGIN domain. */
Packit Service b23acc
			protect = LOGD_VPN_PLUGIN;
Packit Service b23acc
		}
Packit Service b23acc
Packit Service b23acc
		/* Check for combined domains */
Packit Service b23acc
		if (!g_ascii_strcasecmp (s, LOGD_ALL_STRING)) {
Packit Service b23acc
			bits = LOGD_ALL;
Packit Service b23acc
			protect = LOGD_VPN_PLUGIN;
Packit Service b23acc
		} else if (!g_ascii_strcasecmp (s, LOGD_DEFAULT_STRING)) {
Packit Service b23acc
			bits = LOGD_DEFAULT;
Packit Service b23acc
			protect = LOGD_VPN_PLUGIN;
Packit Service b23acc
		} else if (!g_ascii_strcasecmp (s, LOGD_DHCP_STRING))
Packit Service b23acc
			bits = LOGD_DHCP;
Packit Service b23acc
		else if (!g_ascii_strcasecmp (s, LOGD_IP_STRING))
Packit Service b23acc
			bits = LOGD_IP;
Packit Service b23acc
Packit Service b23acc
		/* Check for compatibility domains */
Packit Service b23acc
		else if (!g_ascii_strcasecmp (s, "HW"))
Packit Service b23acc
			bits = LOGD_PLATFORM;
Packit Service b23acc
		else if (!g_ascii_strcasecmp (s, "WIMAX"))
Packit Service b23acc
			continue;
Packit Service b23acc
Packit Service b23acc
		else {
Packit Service b23acc
			for (diter = &domain_desc[0]; diter->name; diter++) {
Packit Service b23acc
				if (!g_ascii_strcasecmp (diter->name, s)) {
Packit Service b23acc
					bits = diter->num;
Packit Service b23acc
					break;
Packit Service b23acc
				}
Packit Service b23acc
			}
Packit Service b23acc
Packit Service b23acc
			if (!bits) {
Packit Service b23acc
				if (!bad_domains) {
Packit Service b23acc
					g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN,
Packit Service b23acc
					             _("Unknown log domain '%s'"), s);
Packit Service b23acc
					return FALSE;
Packit Service b23acc
				}
Packit Service b23acc
Packit Service b23acc
				if (unrecognized)
Packit Service b23acc
					g_string_append (unrecognized, ", ");
Packit Service b23acc
				else
Packit Service b23acc
					unrecognized = g_string_new (NULL);
Packit Service b23acc
				g_string_append (unrecognized, s);
Packit Service b23acc
				continue;
Packit Service b23acc
			}
Packit Service b23acc
		}
Packit Service b23acc
Packit Service b23acc
		if (domain_log_level == _LOGL_KEEP) {
Packit Service b23acc
			for (i = 0; i < G_N_ELEMENTS (new_log_state); i++)
Packit Service b23acc
				new_log_state[i] = (new_log_state[i] & ~bits) | (cur_log_state[i] & bits);
Packit Service b23acc
		} else {
Packit Service b23acc
			for (i = 0; i < G_N_ELEMENTS (new_log_state); i++) {
Packit Service b23acc
				if (i < domain_log_level)
Packit Service b23acc
					new_log_state[i] &= ~bits;
Packit Service b23acc
				else {
Packit Service b23acc
					new_log_state[i] |= bits;
Packit Service b23acc
					if (   (protect & bits)
Packit Service b23acc
					    && i < LOGL_INFO)
Packit Service b23acc
						new_log_state[i] &= ~protect;
Packit Service b23acc
				}
Packit Service b23acc
			}
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	nm_clear_g_free (&gl_main.logging_domains_to_string);
Packit Service b23acc
Packit Service b23acc
	had_platform_debug = _nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_PLATFORM);
Packit Service b23acc
Packit Service b23acc
	G_LOCK (log);
Packit Service b23acc
Packit Service b23acc
	gl.mut.log_level = new_log_level;
Packit Service b23acc
	for (i = 0; i < G_N_ELEMENTS (new_log_state); i++)
Packit Service b23acc
		_nm_logging_enabled_state[i] = new_log_state[i];
Packit Service b23acc
Packit Service b23acc
	G_UNLOCK (log);
Packit Service b23acc
Packit Service b23acc
	if (   had_platform_debug
Packit Service b23acc
	    && !_nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_PLATFORM)) {
Packit Service b23acc
		/* when debug logging is enabled, platform will cache all access to
Packit Service b23acc
		 * sysctl. When the user disables debug-logging, we want to clear that
Packit Service b23acc
		 * cache right away. */
Packit Service b23acc
		_nm_logging_clear_platform_logging_cache ();
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (unrecognized)
Packit Service b23acc
		*bad_domains = g_string_free (unrecognized, FALSE);
Packit Service b23acc
Packit Service b23acc
	return TRUE;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
const char *
Packit Service b23acc
nm_logging_level_to_string (void)
Packit Service b23acc
{
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	return level_desc[gl.imm.log_level].name;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
const char *
Packit Service b23acc
nm_logging_all_levels_to_string (void)
Packit Service b23acc
{
Packit Service b23acc
	static GString *str;
Packit Service b23acc
Packit Service b23acc
	if (G_UNLIKELY (!str)) {
Packit Service b23acc
		int i;
Packit Service b23acc
Packit Service b23acc
		str = g_string_new (NULL);
Packit Service b23acc
		for (i = 0; i < G_N_ELEMENTS (level_desc); i++) {
Packit Service b23acc
			if (str->len)
Packit Service b23acc
				g_string_append_c (str, ',');
Packit Service b23acc
			g_string_append (str, level_desc[i].name);
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	return str->str;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
const char *
Packit Service b23acc
nm_logging_domains_to_string (void)
Packit Service b23acc
{
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	if (G_UNLIKELY (!gl_main.logging_domains_to_string)) {
Packit Service b23acc
		gl_main.logging_domains_to_string = _domains_to_string (TRUE,
Packit Service b23acc
		                                                        gl.imm.log_level,
Packit Service b23acc
		                                                        _nm_logging_enabled_state);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	return gl_main.logging_domains_to_string;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static char *
Packit Service b23acc
_domains_to_string (gboolean include_level_override,
Packit Service b23acc
                    NMLogLevel log_level,
Packit Service b23acc
                    const NMLogDomain log_state[static _LOGL_N_REAL])
Packit Service b23acc
{
Packit Service b23acc
	const LogDesc *diter;
Packit Service b23acc
	GString *str;
Packit Service b23acc
	int i;
Packit Service b23acc
Packit Service b23acc
	/* We don't just return g_strdup() the logging domains that were set during
Packit Service b23acc
	 * nm_logging_setup(), because we want to expand "DEFAULT" and "ALL".
Packit Service b23acc
	 */
Packit Service b23acc
Packit Service b23acc
	str = g_string_sized_new (75);
Packit Service b23acc
	for (diter = &domain_desc[0]; diter->name; diter++) {
Packit Service b23acc
		/* If it's set for any lower level, it will also be set for LOGL_ERR */
Packit Service b23acc
		if (!(diter->num & log_state[LOGL_ERR]))
Packit Service b23acc
			continue;
Packit Service b23acc
Packit Service b23acc
		if (str->len)
Packit Service b23acc
			g_string_append_c (str, ',');
Packit Service b23acc
		g_string_append (str, diter->name);
Packit Service b23acc
Packit Service b23acc
		if (!include_level_override)
Packit Service b23acc
			continue;
Packit Service b23acc
Packit Service b23acc
		/* Check if it's logging at a lower level than the default. */
Packit Service b23acc
		for (i = 0; i < log_level; i++) {
Packit Service b23acc
			if (diter->num & log_state[i]) {
Packit Service b23acc
				g_string_append_printf (str, ":%s", level_desc[i].name);
Packit Service b23acc
				break;
Packit Service b23acc
			}
Packit Service b23acc
		}
Packit Service b23acc
		/* Check if it's logging at a higher level than the default. */
Packit Service b23acc
		if (!(diter->num & log_state[log_level])) {
Packit Service b23acc
			for (i = log_level + 1; i < _LOGL_N_REAL; i++) {
Packit Service b23acc
				if (diter->num & log_state[i]) {
Packit Service b23acc
					g_string_append_printf (str, ":%s", level_desc[i].name);
Packit Service b23acc
					break;
Packit Service b23acc
				}
Packit Service b23acc
			}
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
	return g_string_free (str, FALSE);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static char _all_logging_domains_to_str[273];
Packit Service b23acc
Packit Service b23acc
const char *
Packit Service b23acc
nm_logging_all_domains_to_string (void)
Packit Service b23acc
{
Packit Service b23acc
	static const char *volatile str = NULL;
Packit Service b23acc
	const char *s;
Packit Service b23acc
Packit Service b23acc
again:
Packit Service b23acc
	s = g_atomic_pointer_get (&str);
Packit Service b23acc
	if (G_UNLIKELY (!s)) {
Packit Service b23acc
		static gsize once = 0;
Packit Service b23acc
		const LogDesc *diter;
Packit Service b23acc
		gsize buf_l;
Packit Service b23acc
		char *buf_p;
Packit Service b23acc
Packit Service b23acc
		if (!g_once_init_enter (&once))
Packit Service b23acc
			goto again;
Packit Service b23acc
Packit Service b23acc
		buf_p = _all_logging_domains_to_str;
Packit Service b23acc
		buf_l = sizeof (_all_logging_domains_to_str);
Packit Service b23acc
Packit Service b23acc
		nm_utils_strbuf_append_str (&buf_p, &buf_l, LOGD_DEFAULT_STRING);
Packit Service b23acc
		for (diter = &domain_desc[0]; diter->name; diter++) {
Packit Service b23acc
			nm_utils_strbuf_append_c (&buf_p, &buf_l, ',');
Packit Service b23acc
			nm_utils_strbuf_append_str (&buf_p, &buf_l, diter->name);
Packit Service b23acc
			if (diter->num == LOGD_DHCP6)
Packit Service b23acc
				nm_utils_strbuf_append_str (&buf_p, &buf_l, ","LOGD_DHCP_STRING);
Packit Service b23acc
			else if (diter->num == LOGD_IP6)
Packit Service b23acc
				nm_utils_strbuf_append_str (&buf_p, &buf_l, ","LOGD_IP_STRING);
Packit Service b23acc
		}
Packit Service b23acc
		nm_utils_strbuf_append_str (&buf_p, &buf_l, LOGD_ALL_STRING);
Packit Service b23acc
Packit Service b23acc
		/* Did you modify the logging domains (or their names)? Adjust the size of
Packit Service b23acc
		 * _all_logging_domains_to_str buffer above to have the exact size. */
Packit Service b23acc
		nm_assert (strlen (_all_logging_domains_to_str) == sizeof (_all_logging_domains_to_str) - 1);
Packit Service b23acc
		nm_assert (buf_l == 1);
Packit Service b23acc
Packit Service b23acc
		s = _all_logging_domains_to_str;
Packit Service b23acc
		g_atomic_pointer_set (&str, s);
Packit Service b23acc
		g_once_init_leave (&once, 1);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	return s;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/**
Packit Service b23acc
 * nm_logging_get_level:
Packit Service b23acc
 * @domain: find the lowest enabled logging level for the
Packit Service b23acc
 *   given domain. If this is a set of multiple
Packit Service b23acc
 *   domains, the most verbose level will be returned.
Packit Service b23acc
 *
Packit Service b23acc
 * Returns: the lowest (most verbose) logging level for the
Packit Service b23acc
 *   give @domain, or %_LOGL_OFF if it is disabled.
Packit Service b23acc
 **/
Packit Service b23acc
NMLogLevel
Packit Service b23acc
nm_logging_get_level (NMLogDomain domain)
Packit Service b23acc
{
Packit Service b23acc
	NMLogLevel sl = _LOGL_OFF;
Packit Service b23acc
Packit Service b23acc
	G_STATIC_ASSERT (LOGL_TRACE == 0);
Packit Service b23acc
	while (   sl > LOGL_TRACE
Packit Service b23acc
	       && _nm_logging_enabled_lockfree (sl - 1, domain))
Packit Service b23acc
		sl--;
Packit Service b23acc
	return sl;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
gboolean
Packit Service b23acc
_nm_logging_enabled_locking (NMLogLevel level,
Packit Service b23acc
                             NMLogDomain domain)
Packit Service b23acc
{
Packit Service b23acc
	gboolean v;
Packit Service b23acc
Packit Service b23acc
	G_LOCK (log);
Packit Service b23acc
	v = _nm_logging_enabled_lockfree (level, domain);
Packit Service b23acc
	G_UNLOCK (log);
Packit Service b23acc
	return v;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
gboolean
Packit Service b23acc
_nm_log_enabled_impl (gboolean mt_require_locking,
Packit Service b23acc
                      NMLogLevel level,
Packit Service b23acc
                      NMLogDomain domain)
Packit Service b23acc
{
Packit Service b23acc
	return nm_logging_enabled_mt (mt_require_locking, level, domain);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
static void
Packit Service b23acc
_iovec_set (struct iovec *iov, const void *str, gsize len)
Packit Service b23acc
{
Packit Service b23acc
	iov->iov_base = (void *) str;
Packit Service b23acc
	iov->iov_len = len;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_iovec_set_string (struct iovec *iov, const char *str)
Packit Service b23acc
{
Packit Service b23acc
	_iovec_set (iov, str, strlen (str));
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
#define _iovec_set_string_literal(iov, str) _iovec_set ((iov), ""str"", NM_STRLEN (str))
Packit Service b23acc
Packit Service b23acc
_nm_printf (3, 4)
Packit Service b23acc
static void
Packit Service b23acc
_iovec_set_format (struct iovec *iov, char **iov_free, const char *format, ...)
Packit Service b23acc
{
Packit Service b23acc
	va_list ap;
Packit Service b23acc
	char *str;
Packit Service b23acc
Packit Service b23acc
	va_start (ap, format);
Packit Service b23acc
	str = g_strdup_vprintf (format, ap);
Packit Service b23acc
	va_end (ap);
Packit Service b23acc
Packit Service b23acc
	_iovec_set_string (iov, str);
Packit Service b23acc
	*iov_free = str;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
#define _iovec_set_format_a(iov, reserve_extra, format, ...) \
Packit Service b23acc
	G_STMT_START { \
Packit Service b23acc
		const gsize _size = (reserve_extra) + (NM_STRLEN (format) + 3); \
Packit Service b23acc
		char *const _buf = g_alloca (_size); \
Packit Service b23acc
		int _len; \
Packit Service b23acc
		\
Packit Service b23acc
		G_STATIC_ASSERT_EXPR ((reserve_extra) + (NM_STRLEN (format) + 3) <= 96); \
Packit Service b23acc
		\
Packit Service b23acc
		_len = g_snprintf (_buf, _size, ""format"", ##__VA_ARGS__);\
Packit Service b23acc
		\
Packit Service b23acc
		nm_assert (_len >= 0); \
Packit Service b23acc
		nm_assert (_len < _size); \
Packit Service b23acc
		nm_assert (_len == strlen (_buf)); \
Packit Service b23acc
		\
Packit Service b23acc
		_iovec_set ((iov), _buf, _len); \
Packit Service b23acc
	} G_STMT_END
Packit Service b23acc
Packit Service b23acc
#define _iovec_set_format_str_a(iov, max_str_len, format, str_arg) \
Packit Service b23acc
	G_STMT_START { \
Packit Service b23acc
		const char *_str_arg = (str_arg); \
Packit Service b23acc
		\
Packit Service b23acc
		nm_assert (_str_arg && strlen (_str_arg) < (max_str_len)); \
Packit Service b23acc
		_iovec_set_format_a ((iov), (max_str_len), format, str_arg); \
Packit Service b23acc
	} G_STMT_END
Packit Service b23acc
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
_nm_log_impl (const char *file,
Packit Service b23acc
              guint line,
Packit Service b23acc
              const char *func,
Packit Service b23acc
              gboolean mt_require_locking,
Packit Service b23acc
              NMLogLevel level,
Packit Service b23acc
              NMLogDomain domain,
Packit Service b23acc
              int error,
Packit Service b23acc
              const char *ifname,
Packit Service b23acc
              const char *conn_uuid,
Packit Service b23acc
              const char *fmt,
Packit Service b23acc
              ...)
Packit Service b23acc
{
Packit Service b23acc
	va_list args;
Packit Service b23acc
	char *msg;
Packit Service b23acc
	GTimeVal tv;
Packit Service b23acc
	int errsv;
Packit Service b23acc
	const NMLogDomain *cur_log_state;
Packit Service b23acc
	NMLogDomain cur_log_state_copy[_LOGL_N_REAL];
Packit Service b23acc
	Global g_copy;
Packit Service b23acc
	const Global *g;
Packit Service b23acc
Packit Service b23acc
	if (G_UNLIKELY (mt_require_locking)) {
Packit Service b23acc
		G_LOCK (log);
Packit Service b23acc
		/* we evaluate logging-enabled under lock. There is still a race that
Packit Service b23acc
		 * we might log the message below *after* logging was disabled. That means,
Packit Service b23acc
		 * when disabling logging, we might still log messages. */
Packit Service b23acc
		if (!_nm_logging_enabled_lockfree (level, domain)) {
Packit Service b23acc
			G_UNLOCK (log);
Packit Service b23acc
			return;
Packit Service b23acc
		}
Packit Service b23acc
		g_copy = gl.imm;
Packit Service b23acc
		memcpy (cur_log_state_copy, _nm_logging_enabled_state, sizeof (cur_log_state_copy));
Packit Service b23acc
		G_UNLOCK (log);
Packit Service b23acc
		g = &g_copy;
Packit Service b23acc
		cur_log_state = cur_log_state_copy;
Packit Service b23acc
	} else {
Packit Service b23acc
		NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
		if (!_nm_logging_enabled_lockfree (level, domain))
Packit Service b23acc
			return;
Packit Service b23acc
		g = &gl.imm;
Packit Service b23acc
		cur_log_state = _nm_logging_enabled_state;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	(void) cur_log_state;
Packit Service b23acc
Packit Service b23acc
	errsv = errno;
Packit Service b23acc
Packit Service b23acc
	/* Make sure that %m maps to the specified error */
Packit Service b23acc
	if (error != 0) {
Packit Service b23acc
		if (error < 0)
Packit Service b23acc
			error = -error;
Packit Service b23acc
		errno = error;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	va_start (args, fmt);
Packit Service b23acc
	msg = g_strdup_vprintf (fmt, args);
Packit Service b23acc
	va_end (args);
Packit Service b23acc
Packit Service b23acc
#define MESSAGE_FMT "%s%-7s [%ld.%04ld] %s"
Packit Service b23acc
#define MESSAGE_ARG(prefix, tv, msg) \
Packit Service b23acc
    prefix, \
Packit Service b23acc
    level_desc[level].level_str, \
Packit Service b23acc
    (tv).tv_sec, \
Packit Service b23acc
    ((tv).tv_usec / 100), \
Packit Service b23acc
    (msg)
Packit Service b23acc
Packit Service b23acc
	g_get_current_time (&tv;;
Packit Service b23acc
Packit Service b23acc
	if (g->debug_stderr)
Packit Service b23acc
		g_printerr (MESSAGE_FMT"\n", MESSAGE_ARG (g->prefix, tv, msg));
Packit Service b23acc
Packit Service b23acc
	switch (g->log_backend) {
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
	case LOG_BACKEND_JOURNAL:
Packit Service b23acc
		{
Packit Service b23acc
			gint64 now, boottime;
Packit Service b23acc
			struct iovec iov_data[15];
Packit Service b23acc
			struct iovec *iov = iov_data;
Packit Service b23acc
			char *iov_free_data[5];
Packit Service b23acc
			char **iov_free = iov_free_data;
Packit Service b23acc
			const LogDesc *diter;
Packit Service b23acc
			NMLogDomain dom_all;
Packit Service b23acc
			char s_log_domains_buf[NM_STRLEN ("NM_LOG_DOMAINS=") + sizeof (_all_logging_domains_to_str)];
Packit Service b23acc
			char *s_log_domains;
Packit Service b23acc
			gsize l_log_domains;
Packit Service b23acc
Packit Service b23acc
			now = nm_utils_get_monotonic_timestamp_nsec ();
Packit Service b23acc
			boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1);
Packit Service b23acc
Packit Service b23acc
			_iovec_set_format_a (iov++, 30, "PRIORITY=%d", level_desc[level].syslog_level);
Packit Service b23acc
			_iovec_set_format (iov++, iov_free++, "MESSAGE="MESSAGE_FMT, MESSAGE_ARG (g->prefix, tv, msg));
Packit Service b23acc
			_iovec_set_string (iov++, syslog_identifier_full (g->syslog_identifier));
Packit Service b23acc
			_iovec_set_format_a (iov++, 30, "SYSLOG_PID=%ld", (long) getpid ());
Packit Service b23acc
Packit Service b23acc
			dom_all = domain;
Packit Service b23acc
			s_log_domains = s_log_domains_buf;
Packit Service b23acc
			l_log_domains = sizeof (s_log_domains_buf);
Packit Service b23acc
Packit Service b23acc
			nm_utils_strbuf_append_str (&s_log_domains, &l_log_domains, "NM_LOG_DOMAINS=");
Packit Service b23acc
			for (diter = &domain_desc[0]; dom_all != 0 && diter->name; diter++) {
Packit Service b23acc
				if (!NM_FLAGS_ANY (dom_all, diter->num))
Packit Service b23acc
					continue;
Packit Service b23acc
				if (dom_all != domain)
Packit Service b23acc
					nm_utils_strbuf_append_c (&s_log_domains, &l_log_domains, ',');
Packit Service b23acc
				nm_utils_strbuf_append_str (&s_log_domains, &l_log_domains, diter->name);
Packit Service b23acc
				dom_all &= ~diter->num;
Packit Service b23acc
			}
Packit Service b23acc
			nm_assert (l_log_domains > 0);
Packit Service b23acc
			_iovec_set (iov++, s_log_domains_buf, s_log_domains - s_log_domains_buf);
Packit Service b23acc
Packit Service b23acc
			G_STATIC_ASSERT_EXPR (LOG_FAC (LOG_DAEMON) == 3);
Packit Service b23acc
			_iovec_set_string_literal (iov++, "SYSLOG_FACILITY=3");
Packit Service b23acc
			_iovec_set_format_str_a (iov++, 15, "NM_LOG_LEVEL=%s", level_desc[level].name);
Packit Service b23acc
			if (func)
Packit Service b23acc
				_iovec_set_format (iov++, iov_free++, "CODE_FUNC=%s", func);
Packit Service b23acc
			_iovec_set_format (iov++, iov_free++, "CODE_FILE=%s", file ?: "");
Packit Service b23acc
			_iovec_set_format_a (iov++, 20, "CODE_LINE=%u", line);
Packit Service b23acc
			_iovec_set_format_a (iov++, 60, "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NSEC_PER_SEC), (long long) ((now % NM_UTILS_NSEC_PER_SEC) / 1000));
Packit Service b23acc
			_iovec_set_format_a (iov++, 60, "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NSEC_PER_SEC), (long long) ((boottime % NM_UTILS_NSEC_PER_SEC) / 1000));
Packit Service b23acc
			if (error != 0)
Packit Service b23acc
				_iovec_set_format_a (iov++, 30, "ERRNO=%d", error);
Packit Service b23acc
			if (ifname)
Packit Service b23acc
				_iovec_set_format (iov++, iov_free++, "NM_DEVICE=%s", ifname);
Packit Service b23acc
			if (conn_uuid)
Packit Service b23acc
				_iovec_set_format (iov++, iov_free++, "NM_CONNECTION=%s", conn_uuid);
Packit Service b23acc
Packit Service b23acc
			nm_assert (iov <= &iov_data[G_N_ELEMENTS (iov_data)]);
Packit Service b23acc
			nm_assert (iov_free <= &iov_free_data[G_N_ELEMENTS (iov_free_data)]);
Packit Service b23acc
Packit Service b23acc
			sd_journal_sendv (iov_data, iov - iov_data);
Packit Service b23acc
Packit Service b23acc
			for (; --iov_free >= iov_free_data; )
Packit Service b23acc
				g_free (*iov_free);
Packit Service b23acc
		}
Packit Service b23acc
		break;
Packit Service b23acc
#endif
Packit Service b23acc
	case LOG_BACKEND_SYSLOG:
Packit Service b23acc
		syslog (level_desc[level].syslog_level,
Packit Service b23acc
		        MESSAGE_FMT, MESSAGE_ARG (g->prefix, tv, msg));
Packit Service b23acc
		break;
Packit Service b23acc
	default:
Packit Service b23acc
		g_log (syslog_identifier_domain (g->syslog_identifier), level_desc[level].g_log_level,
Packit Service b23acc
		       MESSAGE_FMT, MESSAGE_ARG (g->prefix, tv, msg));
Packit Service b23acc
		break;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	g_free (msg);
Packit Service b23acc
Packit Service b23acc
	errno = errsv;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
_nm_utils_monotonic_timestamp_initialized (const struct timespec *tp,
Packit Service b23acc
                                           gint64 offset_sec,
Packit Service b23acc
                                           gboolean is_boottime)
Packit Service b23acc
{
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	if (_nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_CORE)) {
Packit Service b23acc
		time_t now = time (NULL);
Packit Service b23acc
		struct tm tm;
Packit Service b23acc
		char s[255];
Packit Service b23acc
Packit Service b23acc
		strftime (s, sizeof (s), "%Y-%m-%d %H:%M:%S", localtime_r (&now, &tm));
Packit Service b23acc
		nm_log_dbg (LOGD_CORE, "monotonic timestamp started counting 1.%09ld seconds ago with "
Packit Service b23acc
		                       "an offset of %lld.0 seconds to %s (local time is %s)",
Packit Service b23acc
		                       tp->tv_nsec,
Packit Service b23acc
		                       (long long) -offset_sec,
Packit Service b23acc
		                       is_boottime ? "CLOCK_BOOTTIME" : "CLOCK_MONOTONIC", s);
Packit Service b23acc
	}
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
nm_log_handler (const char *log_domain,
Packit Service b23acc
                GLogLevelFlags level,
Packit Service b23acc
                const char *message,
Packit Service b23acc
                gpointer ignored)
Packit Service b23acc
{
Packit Service b23acc
	int syslog_priority;
Packit Service b23acc
Packit Service b23acc
	switch (level & G_LOG_LEVEL_MASK) {
Packit Service b23acc
	case G_LOG_LEVEL_ERROR:
Packit Service b23acc
		syslog_priority = LOG_CRIT;
Packit Service b23acc
		break;
Packit Service b23acc
	case G_LOG_LEVEL_CRITICAL:
Packit Service b23acc
		syslog_priority = LOG_ERR;
Packit Service b23acc
		break;
Packit Service b23acc
	case G_LOG_LEVEL_WARNING:
Packit Service b23acc
		syslog_priority = LOG_WARNING;
Packit Service b23acc
		break;
Packit Service b23acc
	case G_LOG_LEVEL_MESSAGE:
Packit Service b23acc
		syslog_priority = LOG_NOTICE;
Packit Service b23acc
		break;
Packit Service b23acc
	case G_LOG_LEVEL_DEBUG:
Packit Service b23acc
		syslog_priority = LOG_DEBUG;
Packit Service b23acc
		break;
Packit Service b23acc
	case G_LOG_LEVEL_INFO:
Packit Service b23acc
	default:
Packit Service b23acc
		syslog_priority = LOG_INFO;
Packit Service b23acc
		break;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	/* we don't need any locking here. The glib log handler gets only registered
Packit Service b23acc
	 * once during nm_logging_init() and the global data is not modified afterwards. */
Packit Service b23acc
	nm_assert (gl.imm.init_done);
Packit Service b23acc
Packit Service b23acc
	if (gl.imm.debug_stderr)
Packit Service b23acc
		g_printerr ("%s%s\n", gl.imm.prefix, message ?: "");
Packit Service b23acc
Packit Service b23acc
	switch (gl.imm.log_backend) {
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
	case LOG_BACKEND_JOURNAL:
Packit Service b23acc
		{
Packit Service b23acc
			gint64 now, boottime;
Packit Service b23acc
Packit Service b23acc
			now = nm_utils_get_monotonic_timestamp_nsec ();
Packit Service b23acc
			boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1);
Packit Service b23acc
Packit Service b23acc
			sd_journal_send ("PRIORITY=%d", syslog_priority,
Packit Service b23acc
			                 "MESSAGE=%s%s", gl.imm.prefix, message ?: "",
Packit Service b23acc
			                 syslog_identifier_full (gl.imm.syslog_identifier),
Packit Service b23acc
			                 "SYSLOG_PID=%ld", (long) getpid (),
Packit Service b23acc
			                 "SYSLOG_FACILITY=3",
Packit Service b23acc
			                 "GLIB_DOMAIN=%s", log_domain ?: "",
Packit Service b23acc
			                 "GLIB_LEVEL=%d", (int) (level & G_LOG_LEVEL_MASK),
Packit Service b23acc
			                 "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NSEC_PER_SEC), (long long) ((now % NM_UTILS_NSEC_PER_SEC) / 1000),
Packit Service b23acc
			                 "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NSEC_PER_SEC), (long long) ((boottime % NM_UTILS_NSEC_PER_SEC) / 1000),
Packit Service b23acc
			                 NULL);
Packit Service b23acc
		}
Packit Service b23acc
		break;
Packit Service b23acc
#endif
Packit Service b23acc
	default:
Packit Service b23acc
		syslog (syslog_priority, "%s%s", gl.imm.prefix, message ?: "");
Packit Service b23acc
		break;
Packit Service b23acc
	}
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
gboolean
Packit Service b23acc
nm_logging_syslog_enabled (void)
Packit Service b23acc
{
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	return gl.imm.uses_syslog;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_logging_init_pre (const char *syslog_identifier,
Packit Service b23acc
                     char *prefix_take)
Packit Service b23acc
{
Packit Service b23acc
	/* this function may be called zero or one times, and only
Packit Service b23acc
	 * - on the main thread
Packit Service b23acc
	 * - not after nm_logging_init(). */
Packit Service b23acc
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	if (gl.imm.init_pre_done)
Packit Service b23acc
		g_return_if_reached ();
Packit Service b23acc
Packit Service b23acc
	if (gl.imm.init_done)
Packit Service b23acc
		g_return_if_reached ();
Packit Service b23acc
Packit Service b23acc
	if (!_syslog_identifier_valid_domain (syslog_identifier))
Packit Service b23acc
		g_return_if_reached ();
Packit Service b23acc
Packit Service b23acc
	if (!prefix_take || !prefix_take[0])
Packit Service b23acc
		g_return_if_reached ();
Packit Service b23acc
Packit Service b23acc
	G_LOCK (log);
Packit Service b23acc
Packit Service b23acc
	gl.mut.init_pre_done = TRUE;
Packit Service b23acc
Packit Service b23acc
	gl.mut.syslog_identifier = g_strdup_printf ("SYSLOG_IDENTIFIER=%s", syslog_identifier);
Packit Service b23acc
	nm_assert (_syslog_identifier_assert (gl.imm.syslog_identifier));
Packit Service b23acc
Packit Service b23acc
	/* we pass the allocated string on and never free it. */
Packit Service b23acc
	gl.mut.prefix = prefix_take;
Packit Service b23acc
Packit Service b23acc
	G_UNLOCK (log);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_logging_init (const char *logging_backend, gboolean debug)
Packit Service b23acc
{
Packit Service b23acc
	gboolean fetch_monotonic_timestamp = FALSE;
Packit Service b23acc
	gboolean obsolete_debug_backend = FALSE;
Packit Service b23acc
	LogBackend x_log_backend;
Packit Service b23acc
Packit Service b23acc
	/* this function may be called zero or one times, and only on the
Packit Service b23acc
	 * main thread. */
Packit Service b23acc
Packit Service b23acc
	NM_ASSERT_ON_MAIN_THREAD ();
Packit Service b23acc
Packit Service b23acc
	nm_assert (NM_IN_STRSET (""NM_CONFIG_DEFAULT_LOGGING_BACKEND,
Packit Service b23acc
	                         NM_LOG_CONFIG_BACKEND_JOURNAL,
Packit Service b23acc
	                         NM_LOG_CONFIG_BACKEND_SYSLOG));
Packit Service b23acc
Packit Service b23acc
	if (gl.imm.init_done)
Packit Service b23acc
		g_return_if_reached ();
Packit Service b23acc
Packit Service b23acc
	if (!logging_backend)
Packit Service b23acc
		logging_backend = ""NM_CONFIG_DEFAULT_LOGGING_BACKEND;
Packit Service b23acc
Packit Service b23acc
	if (nm_streq (logging_backend, NM_LOG_CONFIG_BACKEND_DEBUG)) {
Packit Service b23acc
		/* "debug" was wrongly documented as a valid logging backend. It makes no sense however,
Packit Service b23acc
		 * because printing to stderr only makes sense when not demonizing. Whether to daemonize
Packit Service b23acc
		 * is only controlled via command line arguments (--no-daemon, --debug) and not via the
Packit Service b23acc
		 * logging backend from configuration.
Packit Service b23acc
		 *
Packit Service b23acc
		 * Fall back to the default. */
Packit Service b23acc
		logging_backend = ""NM_CONFIG_DEFAULT_LOGGING_BACKEND;
Packit Service b23acc
		obsolete_debug_backend = TRUE;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
Packit Service b23acc
	G_LOCK (log);
Packit Service b23acc
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
	if (!nm_streq (logging_backend, NM_LOG_CONFIG_BACKEND_SYSLOG)) {
Packit Service b23acc
		x_log_backend = LOG_BACKEND_JOURNAL;
Packit Service b23acc
Packit Service b23acc
		/* We only log the monotonic-timestamp with structured logging (journal).
Packit Service b23acc
		 * Only in this case, fetch the timestamp. */
Packit Service b23acc
		fetch_monotonic_timestamp = TRUE;
Packit Service b23acc
	} else
Packit Service b23acc
#endif
Packit Service b23acc
	{
Packit Service b23acc
		x_log_backend = LOG_BACKEND_SYSLOG;
Packit Service b23acc
		openlog (syslog_identifier_domain (gl.imm.syslog_identifier), LOG_PID, LOG_DAEMON);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	gl.mut.init_done = TRUE;
Packit Service b23acc
	gl.mut.log_backend = x_log_backend;
Packit Service b23acc
	gl.mut.uses_syslog = TRUE;
Packit Service b23acc
	gl.mut.debug_stderr = debug;
Packit Service b23acc
Packit Service b23acc
	g_log_set_handler (syslog_identifier_domain (gl.imm.syslog_identifier),
Packit Service b23acc
	                   G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
Packit Service b23acc
	                   nm_log_handler,
Packit Service b23acc
	                   NULL);
Packit Service b23acc
Packit Service b23acc
	G_UNLOCK (log);
Packit Service b23acc
Packit Service b23acc
Packit Service b23acc
	if (fetch_monotonic_timestamp) {
Packit Service b23acc
		/* ensure we read a monotonic timestamp. Reading the timestamp the first
Packit Service b23acc
		 * time causes a logging message. We don't want to do that during _nm_log_impl. */
Packit Service b23acc
		nm_utils_get_monotonic_timestamp_nsec ();
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (obsolete_debug_backend)
Packit Service b23acc
		nm_log_dbg (LOGD_CORE, "config: ignore deprecated logging backend 'debug', fallback to '%s'", logging_backend);
Packit Service b23acc
Packit Service b23acc
	if (nm_streq (logging_backend, NM_LOG_CONFIG_BACKEND_SYSLOG)) {
Packit Service b23acc
		/* good */
Packit Service b23acc
	} else if (nm_streq (logging_backend, NM_LOG_CONFIG_BACKEND_JOURNAL)) {
Packit Service b23acc
#if !SYSTEMD_JOURNAL
Packit Service b23acc
		nm_log_warn (LOGD_CORE, "config: logging backend 'journal' is not available, fallback to 'syslog'");
Packit Service b23acc
#endif
Packit Service b23acc
	} else {
Packit Service b23acc
		nm_log_warn (LOGD_CORE, "config: invalid logging backend '%s', fallback to '%s'",
Packit Service b23acc
		             logging_backend,
Packit Service b23acc
#if SYSTEMD_JOURNAL
Packit Service b23acc
		             NM_LOG_CONFIG_BACKEND_JOURNAL
Packit Service b23acc
#else
Packit Service b23acc
		             NM_LOG_CONFIG_BACKEND_SYSLOG
Packit Service b23acc
#endif
Packit Service b23acc
		             );
Packit Service b23acc
	}
Packit Service b23acc
}