exterror: Add EXTERROR_VERBOSE env variable to control verbosity

If the variable is set and the process is not suid, __uexterr_format(),
used by err(3), prints errno/category/source line/pX always, not only
when there is no kernel message provided.

Requested by:	mckusick
Reviewed by:	emaste, mckusick
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D54380
This commit is contained in:
Konstantin Belousov 2025-12-28 02:23:27 +02:00
parent 8bff95f3ce
commit 42210fe8dc

View file

@ -11,26 +11,69 @@
#include <sys/types.h>
#include <sys/exterrvar.h>
#include <exterr.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const char exterror_verbose_name[] = "EXTERROR_VERBOSE";
enum exterr_verbose_state {
EXTERR_VERBOSE_UNKNOWN = 100,
EXTERR_VERBOSE_DEFAULT,
EXTERR_VERBOSE_ALLOW,
};
static enum exterr_verbose_state exterror_verbose = EXTERR_VERBOSE_UNKNOWN;
static void
exterr_verbose_init(void)
{
/*
* No need to care about thread-safety, the result is
* idempotent.
*/
if (exterror_verbose != EXTERR_VERBOSE_UNKNOWN)
return;
if (issetugid()) {
exterror_verbose = EXTERR_VERBOSE_DEFAULT;
} else if (getenv(exterror_verbose_name) != NULL) {
exterror_verbose = EXTERR_VERBOSE_ALLOW;
} else {
exterror_verbose = EXTERR_VERBOSE_DEFAULT;
}
}
int
__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
{
bool has_msg;
if (bufsz > UEXTERROR_MAXLEN)
bufsz = UEXTERROR_MAXLEN;
if (ue->error == 0) {
strlcpy(buf, "", bufsz);
return (0);
}
if (ue->msg[0] == '\0') {
snprintf(buf, bufsz,
exterr_verbose_init();
has_msg = ue->msg[0] != '\0';
if (has_msg) {
snprintf(buf, bufsz, ue->msg, (uintmax_t)ue->p1,
(uintmax_t)ue->p2);
} else {
strlcpy(buf, "", bufsz);
}
if (exterror_verbose == EXTERR_VERBOSE_ALLOW || !has_msg) {
char lbuf[128];
snprintf(lbuf, sizeof(lbuf),
"errno %d category %u (src line %u) p1 %#jx p2 %#jx",
ue->error, ue->cat, ue->src_line,
(uintmax_t)ue->p1, (uintmax_t)ue->p2);
} else {
snprintf(buf, bufsz, ue->msg, (uintmax_t)ue->p1,
(uintmax_t)ue->p2);
if (has_msg)
strlcat(buf, " ", bufsz);
strlcat(buf, lbuf, bufsz);
}
return (0);
}