Commit 03d1089e authored by Matthew Sakai's avatar Matthew Sakai Committed by Mike Snitzer
Browse files

dm vdo: add basic logging and support utilities



Add various support utilities for the vdo target and deduplication index,
including logging utilities, string and time management, and index-specific
error codes.

Co-developed-by: default avatarJ. corwin Coburn <corwin@hurlbutnet.net>
Signed-off-by: default avatarJ. corwin Coburn <corwin@hurlbutnet.net>
Co-developed-by: default avatarMichael Sclafani <dm-devel@lists.linux.dev>
Signed-off-by: default avatarMichael Sclafani <dm-devel@lists.linux.dev>
Co-developed-by: default avatarThomas Jaskiewicz <tom@jaskiewicz.us>
Signed-off-by: default avatarThomas Jaskiewicz <tom@jaskiewicz.us>
Co-developed-by: default avatarKen Raeburn <raeburn@redhat.com>
Signed-off-by: default avatarKen Raeburn <raeburn@redhat.com>
Signed-off-by: default avatarMatthew Sakai <msakai@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
parent 46766d48
Loading
Loading
Loading
Loading
+312 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2023 Red Hat
 */

#include "errors.h"

#include <linux/compiler.h>
#include <linux/errno.h>

#include "logger.h"
#include "permassert.h"
#include "string-utils.h"

static const struct error_info successful = { "UDS_SUCCESS", "Success" };

static const char *const message_table[] = {
	[EPERM] = "Operation not permitted",
	[ENOENT] = "No such file or directory",
	[ESRCH] = "No such process",
	[EINTR] = "Interrupted system call",
	[EIO] = "Input/output error",
	[ENXIO] = "No such device or address",
	[E2BIG] = "Argument list too long",
	[ENOEXEC] = "Exec format error",
	[EBADF] = "Bad file descriptor",
	[ECHILD] = "No child processes",
	[EAGAIN] = "Resource temporarily unavailable",
	[ENOMEM] = "Cannot allocate memory",
	[EACCES] = "Permission denied",
	[EFAULT] = "Bad address",
	[ENOTBLK] = "Block device required",
	[EBUSY] = "Device or resource busy",
	[EEXIST] = "File exists",
	[EXDEV] = "Invalid cross-device link",
	[ENODEV] = "No such device",
	[ENOTDIR] = "Not a directory",
	[EISDIR] = "Is a directory",
	[EINVAL] = "Invalid argument",
	[ENFILE] = "Too many open files in system",
	[EMFILE] = "Too many open files",
	[ENOTTY] = "Inappropriate ioctl for device",
	[ETXTBSY] = "Text file busy",
	[EFBIG] = "File too large",
	[ENOSPC] = "No space left on device",
	[ESPIPE] = "Illegal seek",
	[EROFS] = "Read-only file system",
	[EMLINK] = "Too many links",
	[EPIPE] = "Broken pipe",
	[EDOM] = "Numerical argument out of domain",
	[ERANGE] = "Numerical result out of range"
};

static const struct error_info error_list[] = {
	{ "UDS_OVERFLOW", "Index overflow" },
	{ "UDS_INVALID_ARGUMENT", "Invalid argument passed to internal routine" },
	{ "UDS_BAD_STATE", "UDS data structures are in an invalid state" },
	{ "UDS_DUPLICATE_NAME", "Attempt to enter the same name into a delta index twice" },
	{ "UDS_ASSERTION_FAILED", "Assertion failed" },
	{ "UDS_QUEUED", "Request queued" },
	{ "UDS_BUFFER_ERROR", "Buffer error" },
	{ "UDS_NO_DIRECTORY", "Expected directory is missing" },
	{ "UDS_ALREADY_REGISTERED", "Error range already registered" },
	{ "UDS_OUT_OF_RANGE", "Cannot access data outside specified limits" },
	{ "UDS_EMODULE_LOAD", "Could not load modules" },
	{ "UDS_DISABLED", "UDS library context is disabled" },
	{ "UDS_UNKNOWN_ERROR", "Unknown error" },
	{ "UDS_UNSUPPORTED_VERSION", "Unsupported version" },
	{ "UDS_CORRUPT_DATA", "Some index structure is corrupt" },
	{ "UDS_NO_INDEX", "No index found" },
	{ "UDS_INDEX_NOT_SAVED_CLEANLY", "Index not saved cleanly" },
};

struct error_block {
	const char *name;
	int base;
	int last;
	int max;
	const struct error_info *infos;
};

enum {
	MAX_ERROR_BLOCKS = 6,
};

static struct {
	int allocated;
	int count;
	struct error_block blocks[MAX_ERROR_BLOCKS];
} registered_errors = {
	.allocated = MAX_ERROR_BLOCKS,
	.count = 1,
	.blocks = { {
			.name = "UDS Error",
			.base = UDS_ERROR_CODE_BASE,
			.last = UDS_ERROR_CODE_LAST,
			.max = UDS_ERROR_CODE_BLOCK_END,
			.infos = error_list,
		  } },
};

/* Get the error info for an error number. Also returns the name of the error block, if known. */
static const char *get_error_info(int errnum, const struct error_info **info_ptr)
{
	struct error_block *block;

	if (errnum == UDS_SUCCESS) {
		*info_ptr = &successful;
		return NULL;
	}

	for (block = registered_errors.blocks;
	     block < registered_errors.blocks + registered_errors.count;
	     block++) {
		if ((errnum >= block->base) && (errnum < block->last)) {
			*info_ptr = block->infos + (errnum - block->base);
			return block->name;
		} else if ((errnum >= block->last) && (errnum < block->max)) {
			*info_ptr = NULL;
			return block->name;
		}
	}

	return NULL;
}

/* Return a string describing a system error message. */
static const char *system_string_error(int errnum, char *buf, size_t buflen)
{
	size_t len;
	const char *error_string = NULL;

	if ((errnum > 0) && (errnum < ARRAY_SIZE(message_table)))
		error_string = message_table[errnum];

	len = ((error_string == NULL) ?
		 snprintf(buf, buflen, "Unknown error %d", errnum) :
		 snprintf(buf, buflen, "%s", error_string));
	if (len < buflen)
		return buf;

	buf[0] = '\0';
	return "System error";
}

/* Convert an error code to a descriptive string. */
const char *uds_string_error(int errnum, char *buf, size_t buflen)
{
	char *buffer = buf;
	char *buf_end = buf + buflen;
	const struct error_info *info = NULL;
	const char *block_name;

	if (buf == NULL)
		return NULL;

	if (errnum < 0)
		errnum = -errnum;

	block_name = get_error_info(errnum, &info);
	if (block_name != NULL) {
		if (info != NULL) {
			buffer = uds_append_to_buffer(buffer, buf_end, "%s: %s",
						      block_name, info->message);
		} else {
			buffer = uds_append_to_buffer(buffer, buf_end, "Unknown %s %d",
						      block_name, errnum);
		}
	} else if (info != NULL) {
		buffer = uds_append_to_buffer(buffer, buf_end, "%s", info->message);
	} else {
		const char *tmp = system_string_error(errnum, buffer, buf_end - buffer);

		if (tmp != buffer)
			buffer = uds_append_to_buffer(buffer, buf_end, "%s", tmp);
		else
			buffer += strlen(tmp);
	}

	return buf;
}

/* Convert an error code to its name. */
const char *uds_string_error_name(int errnum, char *buf, size_t buflen)
{
	char *buffer = buf;
	char *buf_end = buf + buflen;
	const struct error_info *info = NULL;
	const char *block_name;

	if (errnum < 0)
		errnum = -errnum;

	block_name = get_error_info(errnum, &info);
	if (block_name != NULL) {
		if (info != NULL) {
			buffer = uds_append_to_buffer(buffer, buf_end, "%s", info->name);
		} else {
			buffer = uds_append_to_buffer(buffer, buf_end, "%s %d",
						      block_name, errnum);
		}
	} else if (info != NULL) {
		buffer = uds_append_to_buffer(buffer, buf_end, "%s", info->name);
	} else {
		const char *tmp;

		tmp = system_string_error(errnum, buffer, buf_end - buffer);
		if (tmp != buffer)
			buffer = uds_append_to_buffer(buffer, buf_end, "%s", tmp);
		else
			buffer += strlen(tmp);
	}

	return buf;
}

/*
 * Translate an error code into a value acceptable to the kernel. The input error code may be a
 * system-generated value (such as -EIO), or an internal UDS status code. The result will be a
 * negative errno value.
 */
int uds_map_to_system_error(int error)
{
	char error_name[UDS_MAX_ERROR_NAME_SIZE];
	char error_message[UDS_MAX_ERROR_MESSAGE_SIZE];

	/* 0 is success, and negative values are already system error codes. */
	if (likely(error <= 0))
		return error;

	if (error < 1024) {
		/* This is probably an errno from userspace. */
		return -error;
	}

	/* Internal UDS errors */
	switch (error) {
	case UDS_NO_INDEX:
	case UDS_CORRUPT_DATA:
		/* The index doesn't exist or can't be recovered. */
		return -ENOENT;

	case UDS_INDEX_NOT_SAVED_CLEANLY:
	case UDS_UNSUPPORTED_VERSION:
		/*
		 * The index exists, but can't be loaded. Tell the client it exists so they don't
		 * destroy it inadvertently.
		 */
		return -EEXIST;

	case UDS_DISABLED:
		/* The session is unusable; only returned by requests. */
		return -EIO;

	default:
		/* Translate an unexpected error into something generic. */
		uds_log_info("%s: mapping status code %d (%s: %s) to -EIO",
			     __func__, error,
			     uds_string_error_name(error, error_name,
						   sizeof(error_name)),
			     uds_string_error(error, error_message,
					      sizeof(error_message)));
		return -EIO;
	}
}

/*
 * Register a block of error codes.
 *
 * @block_name: the name of the block of error codes
 * @first_error: the first error code in the block
 * @next_free_error: one past the highest possible error in the block
 * @infos: a pointer to the error info array for the block
 * @info_size: the size of the error info array
 */
int uds_register_error_block(const char *block_name, int first_error,
			     int next_free_error, const struct error_info *infos,
			     size_t info_size)
{
	int result;
	struct error_block *block;
	struct error_block new_block = {
		.name = block_name,
		.base = first_error,
		.last = first_error + (info_size / sizeof(struct error_info)),
		.max = next_free_error,
		.infos = infos,
	};

	result = ASSERT(first_error < next_free_error, "well-defined error block range");
	if (result != UDS_SUCCESS)
		return result;

	if (registered_errors.count == registered_errors.allocated) {
		/* This should never happen. */
		return UDS_OVERFLOW;
	}

	for (block = registered_errors.blocks;
	     block < registered_errors.blocks + registered_errors.count;
	     block++) {
		if (strcmp(block_name, block->name) == 0)
			return UDS_DUPLICATE_NAME;

		/* Ensure error ranges do not overlap. */
		if ((first_error < block->max) && (next_free_error > block->base))
			return UDS_ALREADY_REGISTERED;
	}

	registered_errors.blocks[registered_errors.count++] = new_block;
	return UDS_SUCCESS;
}
+81 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright 2023 Red Hat
 */

#ifndef UDS_ERRORS_H
#define UDS_ERRORS_H

#include <linux/compiler.h>
#include <linux/types.h>

/* Custom error codes and error-related utilities for UDS */

/* Valid status codes for internal UDS functions. */
enum uds_status_codes {
	/* Successful return */
	UDS_SUCCESS = 0,

	/* Used as a base value for reporting internal errors */
	UDS_ERROR_CODE_BASE = 1024,
	/* Index overflow */
	UDS_OVERFLOW = UDS_ERROR_CODE_BASE + 0,
	/* Invalid argument passed to internal routine */
	UDS_INVALID_ARGUMENT = UDS_ERROR_CODE_BASE + 1,
	/* UDS data structures are in an invalid state */
	UDS_BAD_STATE = UDS_ERROR_CODE_BASE + 2,
	/* Attempt to enter the same name into an internal structure twice */
	UDS_DUPLICATE_NAME = UDS_ERROR_CODE_BASE + 3,
	/* An assertion failed */
	UDS_ASSERTION_FAILED = UDS_ERROR_CODE_BASE + 4,
	/* A request has been queued for later processing (not an error) */
	UDS_QUEUED = UDS_ERROR_CODE_BASE + 5,
	/* A problem has occurred with a buffer */
	UDS_BUFFER_ERROR = UDS_ERROR_CODE_BASE + 6,
	/* No directory was found where one was expected */
	UDS_NO_DIRECTORY = UDS_ERROR_CODE_BASE + 7,
	/* This error range has already been registered */
	UDS_ALREADY_REGISTERED = UDS_ERROR_CODE_BASE + 8,
	/* Attempt to read or write data outside the valid range */
	UDS_OUT_OF_RANGE = UDS_ERROR_CODE_BASE + 9,
	/* Could not load modules */
	UDS_EMODULE_LOAD = UDS_ERROR_CODE_BASE + 10,
	/* The index session is disabled */
	UDS_DISABLED = UDS_ERROR_CODE_BASE + 11,
	/* Unknown error */
	UDS_UNKNOWN_ERROR = UDS_ERROR_CODE_BASE + 12,
	/* The index configuration or volume format is no longer supported */
	UDS_UNSUPPORTED_VERSION = UDS_ERROR_CODE_BASE + 13,
	/* Some index structure is corrupt */
	UDS_CORRUPT_DATA = UDS_ERROR_CODE_BASE + 14,
	/* No index state found */
	UDS_NO_INDEX = UDS_ERROR_CODE_BASE + 15,
	/* Attempt to access incomplete index save data */
	UDS_INDEX_NOT_SAVED_CLEANLY = UDS_ERROR_CODE_BASE + 16,
	/* One more than the last UDS_INTERNAL error code */
	UDS_ERROR_CODE_LAST,
	/* One more than the last error this block will ever use */
	UDS_ERROR_CODE_BLOCK_END = UDS_ERROR_CODE_BASE + 440,
};

enum {
	UDS_MAX_ERROR_NAME_SIZE = 80,
	UDS_MAX_ERROR_MESSAGE_SIZE = 128,
};

struct error_info {
	const char *name;
	const char *message;
};

const char * __must_check uds_string_error(int errnum, char *buf, size_t buflen);

const char *uds_string_error_name(int errnum, char *buf, size_t buflen);

int uds_map_to_system_error(int error);

int uds_register_error_block(const char *block_name, int first_error,
			     int last_reserved_error, const struct error_info *infos,
			     size_t info_size);

#endif /* UDS_ERRORS_H */
+291 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2023 Red Hat
 */

#include "logger.h"

#include <linux/delay.h>
#include <linux/hardirq.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/sched.h>

#include "thread-device.h"
#include "uds-threads.h"

struct priority_name {
	const char *name;
	const int priority;
};

static const struct priority_name PRIORITIES[] = {
	{ "ALERT", UDS_LOG_ALERT },
	{ "CRITICAL", UDS_LOG_CRIT },
	{ "CRIT", UDS_LOG_CRIT },
	{ "DEBUG", UDS_LOG_DEBUG },
	{ "EMERGENCY", UDS_LOG_EMERG },
	{ "EMERG", UDS_LOG_EMERG },
	{ "ERROR", UDS_LOG_ERR },
	{ "ERR", UDS_LOG_ERR },
	{ "INFO", UDS_LOG_INFO },
	{ "NOTICE", UDS_LOG_NOTICE },
	{ "PANIC", UDS_LOG_EMERG },
	{ "WARN", UDS_LOG_WARNING },
	{ "WARNING", UDS_LOG_WARNING },
	{ NULL, -1 },
};

static const char *const PRIORITY_STRINGS[] = {
	"EMERGENCY",
	"ALERT",
	"CRITICAL",
	"ERROR",
	"WARN",
	"NOTICE",
	"INFO",
	"DEBUG",
};

static int log_level = UDS_LOG_INFO;

int uds_get_log_level(void)
{
	return log_level;
}

void uds_set_log_level(int new_log_level)
{
	log_level = new_log_level;
}

int uds_log_string_to_priority(const char *string)
{
	int i;

	for (i = 0; PRIORITIES[i].name != NULL; i++) {
		if (strcasecmp(string, PRIORITIES[i].name) == 0)
			return PRIORITIES[i].priority;
	}

	return UDS_LOG_INFO;
}

const char *uds_log_priority_to_string(int priority)
{
	if ((priority < 0) || (priority >= (int) ARRAY_SIZE(PRIORITY_STRINGS)))
		return "unknown";

	return PRIORITY_STRINGS[priority];
}

static const char *get_current_interrupt_type(void)
{
	if (in_nmi())
		return "NMI";

	if (in_irq())
		return "HI";

	if (in_softirq())
		return "SI";

	return "INTR";
}

/**
 * emit_log_message_to_kernel() - Emit a log message to the kernel at the specified priority.
 *
 * @priority: The priority at which to log the message
 * @fmt: The format string of the message
 */
static void emit_log_message_to_kernel(int priority, const char *fmt, ...)
{
	va_list args;
	struct va_format vaf;

	if (priority > uds_get_log_level())
		return;

	va_start(args, fmt);
	vaf.fmt = fmt;
	vaf.va = &args;

	switch (priority) {
	case UDS_LOG_EMERG:
	case UDS_LOG_ALERT:
	case UDS_LOG_CRIT:
		printk(KERN_CRIT "%pV", &vaf);
		break;
	case UDS_LOG_ERR:
		printk(KERN_ERR "%pV", &vaf);
		break;
	case UDS_LOG_WARNING:
		printk(KERN_WARNING "%pV", &vaf);
		break;
	case UDS_LOG_NOTICE:
		printk(KERN_NOTICE "%pV", &vaf);
		break;
	case UDS_LOG_INFO:
		printk(KERN_INFO "%pV", &vaf);
		break;
	case UDS_LOG_DEBUG:
		printk(KERN_DEBUG "%pV", &vaf);
		break;
	default:
		printk(KERN_DEFAULT "%pV", &vaf);
		break;
	}

	va_end(args);
}

/**
 * emit_log_message() - Emit a log message to the kernel log in a format suited to the current
 *                      thread context.
 *
 * Context info formats:
 *
 * interrupt:           uds[NMI]: blah
 * kvdo thread:         kvdo12:foobarQ: blah
 * thread w/device id:  kvdo12:myprog: blah
 * other thread:        uds: myprog: blah
 *
 * Fields: module name, interrupt level, process name, device ID.
 *
 * @priority: the priority at which to log the message
 * @module: The name of the module doing the logging
 * @prefix: The prefix of the log message
 * @vaf1: The first message format descriptor
 * @vaf2: The second message format descriptor
 */
static void emit_log_message(int priority, const char *module, const char *prefix,
			     const struct va_format *vaf1, const struct va_format *vaf2)
{
	int device_instance;

	/*
	 * In interrupt context, identify the interrupt type and module. Ignore the process/thread
	 * since it could be anything.
	 */
	if (in_interrupt()) {
		const char *type = get_current_interrupt_type();

		emit_log_message_to_kernel(priority, "%s[%s]: %s%pV%pV\n", module, type,
					   prefix, vaf1, vaf2);
		return;
	}

	/* Not at interrupt level; we have a process we can look at, and might have a device ID. */
	device_instance = uds_get_thread_device_id();
	if (device_instance >= 0) {
		emit_log_message_to_kernel(priority, "%s%u:%s: %s%pV%pV\n", module,
					   device_instance, current->comm, prefix, vaf1,
					   vaf2);
		return;
	}

	/*
	 * If it's a kernel thread and the module name is a prefix of its name, assume it is ours
	 * and only identify the thread.
	 */
	if (((current->flags & PF_KTHREAD) != 0) &&
	    (strncmp(module, current->comm, strlen(module)) == 0)) {
		emit_log_message_to_kernel(priority, "%s: %s%pV%pV\n", current->comm,
					   prefix, vaf1, vaf2);
		return;
	}

	/* Identify the module and the process. */
	emit_log_message_to_kernel(priority, "%s: %s: %s%pV%pV\n", module, current->comm,
				   prefix, vaf1, vaf2);
}

/*
 * uds_log_embedded_message() - Log a message embedded within another message.
 * @priority: the priority at which to log the message
 * @module: the name of the module doing the logging
 * @prefix: optional string prefix to message, may be NULL
 * @fmt1: format of message first part (required)
 * @args1: arguments for message first part (required)
 * @fmt2: format of message second part
 */
void uds_log_embedded_message(int priority, const char *module, const char *prefix,
			      const char *fmt1, va_list args1, const char *fmt2, ...)
{
	va_list args1_copy;
	va_list args2;
	struct va_format vaf1, vaf2;

	va_start(args2, fmt2);

	if (module == NULL)
		module = UDS_LOGGING_MODULE_NAME;

	if (prefix == NULL)
		prefix = "";

	/*
	 * It is implementation dependent whether va_list is defined as an array type that decays
	 * to a pointer when passed as an argument. Copy args1 and args2 with va_copy so that vaf1
	 * and vaf2 get proper va_list pointers irrespective of how va_list is defined.
	 */
	va_copy(args1_copy, args1);
	vaf1.fmt = fmt1;
	vaf1.va = &args1_copy;

	vaf2.fmt = fmt2;
	vaf2.va = &args2;

	emit_log_message(priority, module, prefix, &vaf1, &vaf2);

	va_end(args1_copy);
	va_end(args2);
}

int uds_vlog_strerror(int priority, int errnum, const char *module, const char *format,
		      va_list args)
{
	char errbuf[UDS_MAX_ERROR_MESSAGE_SIZE];
	const char *message = uds_string_error(errnum, errbuf, sizeof(errbuf));

	uds_log_embedded_message(priority, module, NULL, format, args, ": %s (%d)",
				 message, errnum);
	return errnum;
}

int __uds_log_strerror(int priority, int errnum, const char *module, const char *format, ...)
{
	va_list args;

	va_start(args, format);
	uds_vlog_strerror(priority, errnum, module, format, args);
	va_end(args);
	return errnum;
}

void uds_log_backtrace(int priority)
{
	if (priority > uds_get_log_level())
		return;

	dump_stack();
}

void __uds_log_message(int priority, const char *module, const char *format, ...)
{
	va_list args;

	va_start(args, format);
	uds_log_embedded_message(priority, module, NULL, format, args, "%s", "");
	va_end(args);
}

/*
 * Sleep or delay a few milliseconds in an attempt to allow the log buffers to be flushed lest they
 * be overrun.
 */
void uds_pause_for_logger(void)
{
	fsleep(4000);
}
+105 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright 2023 Red Hat
 */

#ifndef UDS_LOGGER_H
#define UDS_LOGGER_H

#include <linux/module.h>
#include <linux/ratelimit.h>

/* Custom logging utilities for UDS */

#define UDS_LOG_EMERG 0
#define UDS_LOG_ALERT 1
#define UDS_LOG_CRIT 2
#define UDS_LOG_ERR 3
#define UDS_LOG_WARNING 4
#define UDS_LOG_NOTICE 5
#define UDS_LOG_INFO 6
#define UDS_LOG_DEBUG 7

#if defined(MODULE)
#define UDS_LOGGING_MODULE_NAME THIS_MODULE->name
#else /* compiled into the kernel */
#define UDS_LOGGING_MODULE_NAME "vdo"
#endif

/* Apply a rate limiter to a log method call. */
#define uds_log_ratelimit(log_fn, ...)                                    \
	do {                                                              \
		static DEFINE_RATELIMIT_STATE(_rs,                        \
					      DEFAULT_RATELIMIT_INTERVAL, \
					      DEFAULT_RATELIMIT_BURST);   \
		if (__ratelimit(&_rs)) {                                  \
			log_fn(__VA_ARGS__);                              \
		}                                                         \
	} while (0)

int uds_get_log_level(void);

void uds_set_log_level(int new_log_level);

int uds_log_string_to_priority(const char *string);

const char *uds_log_priority_to_string(int priority);

void uds_log_embedded_message(int priority, const char *module, const char *prefix,
			      const char *fmt1, va_list args1, const char *fmt2, ...)
	__printf(4, 0) __printf(6, 7);

void uds_log_backtrace(int priority);

/* All log functions will preserve the caller's value of errno. */

#define uds_log_strerror(priority, errnum, ...) \
	__uds_log_strerror(priority, errnum, UDS_LOGGING_MODULE_NAME, __VA_ARGS__)

int __uds_log_strerror(int priority, int errnum, const char *module,
		       const char *format, ...)
	__printf(4, 5);

int uds_vlog_strerror(int priority, int errnum, const char *module, const char *format,
		      va_list args)
	__printf(4, 0);

/* Log an error prefixed with the string associated with the errnum. */
#define uds_log_error_strerror(errnum, ...) \
	uds_log_strerror(UDS_LOG_ERR, errnum, __VA_ARGS__)

#define uds_log_debug_strerror(errnum, ...) \
	uds_log_strerror(UDS_LOG_DEBUG, errnum, __VA_ARGS__)

#define uds_log_info_strerror(errnum, ...) \
	uds_log_strerror(UDS_LOG_INFO, errnum, __VA_ARGS__)

#define uds_log_notice_strerror(errnum, ...) \
	uds_log_strerror(UDS_LOG_NOTICE, errnum, __VA_ARGS__)

#define uds_log_warning_strerror(errnum, ...) \
	uds_log_strerror(UDS_LOG_WARNING, errnum, __VA_ARGS__)

#define uds_log_fatal_strerror(errnum, ...) \
	uds_log_strerror(UDS_LOG_CRIT, errnum, __VA_ARGS__)

#define uds_log_message(priority, ...) \
	__uds_log_message(priority, UDS_LOGGING_MODULE_NAME, __VA_ARGS__)

void __uds_log_message(int priority, const char *module, const char *format, ...)
	__printf(3, 4);

#define uds_log_debug(...) uds_log_message(UDS_LOG_DEBUG, __VA_ARGS__)

#define uds_log_info(...) uds_log_message(UDS_LOG_INFO, __VA_ARGS__)

#define uds_log_notice(...) uds_log_message(UDS_LOG_NOTICE, __VA_ARGS__)

#define uds_log_warning(...) uds_log_message(UDS_LOG_WARNING, __VA_ARGS__)

#define uds_log_error(...) uds_log_message(UDS_LOG_ERR, __VA_ARGS__)

#define uds_log_fatal(...) uds_log_message(UDS_LOG_CRIT, __VA_ARGS__)

void uds_pause_for_logger(void);
#endif /* UDS_LOGGER_H */
+26 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2023 Red Hat
 */

#include "permassert.h"

#include "errors.h"
#include "logger.h"

int uds_assertion_failed(const char *expression_string, const char *file_name,
			 int line_number, const char *format, ...)
{
	va_list args;

	va_start(args, format);

	uds_log_embedded_message(UDS_LOG_ERR, UDS_LOGGING_MODULE_NAME, "assertion \"",
				 format, args, "\" (%s) failed at %s:%d",
				 expression_string, file_name, line_number);
	uds_log_backtrace(UDS_LOG_ERR);

	va_end(args);

	return UDS_ASSERTION_FAILED;
}
Loading