Page MenuHomeFreeBSD

D54380.id168663.diff
No OneTemporary

D54380.id168663.diff

diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c
--- a/lib/libc/gen/err.c
+++ b/lib/libc/gen/err.c
@@ -120,7 +120,7 @@
}
fprintf(err_file, "%s", strerror(code));
if (doexterr && extstatus == 0 && exterr[0] != '\0')
- fprintf(err_file, " (extended error %s)", exterr);
+ fprintf(err_file, " (%s)", exterr);
fprintf(err_file, "\n");
}
diff --git a/lib/libc/gen/exterr_cat_filenames.h b/lib/libc/gen/exterr_cat_filenames.h
new file mode 100644
--- /dev/null
+++ b/lib/libc/gen/exterr_cat_filenames.h
@@ -0,0 +1,17 @@
+/*
+ * Automatically @generated, use
+ * tools/build/make_libc_exterr_cat_filenames.sh
+ */
+ [EXTERR_CAT_FUSE_DEVICE] = "fs/fuse/fuse_device.c",
+ [EXTERR_CAT_FUSE_VFS] = "fs/fuse/fuse_vfsops.c",
+ [EXTERR_CAT_FUSE_VNOPS] = "fs/fuse/fuse_vnops.c",
+ [EXTERR_CAT_GEOM] = "geom/geom_subr.c",
+ [EXTERR_CAT_GEOMVFS] = "geom/geom_vfs.c",
+ [EXTERR_CAT_FILEDESC] = "kern/kern_descrip.c",
+ [EXTERR_CAT_INOTIFY] = "kern/vfs_inotify.c",
+ [EXTERR_CAT_GENIO] = "kern/sys_generic.c",
+ [EXTERR_CAT_VFSBIO] = "kern/vfs_bio.c",
+ [EXTERR_CAT_VFSSYSCALL] = "kern/vfs_syscalls.c",
+ [EXTERR_CAT_BRIDGE] = "net/if_bridge.c",
+ [EXTERR_CAT_SWAP] = "vm/swap_pager.c",
+ [EXTERR_CAT_MMAP] = "vm/vm_mmap.c",
diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c
--- a/lib/libc/gen/uexterr_format.c
+++ b/lib/libc/gen/uexterr_format.c
@@ -8,28 +8,85 @@
* under sponsorship from the FreeBSD Foundation.
*/
-#include <sys/types.h>
+#include <sys/param.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 * const cat_to_filenames[] = {
+#include "exterr_cat_filenames.h"
+};
+
+static const char *
+cat_to_filename(int category)
+{
+ if (category < 0 || category >= nitems(cat_to_filenames) ||
+ cat_to_filenames[category] == NULL)
+ return ("unknown");
+ return (cat_to_filenames[category]);
+}
+
+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,
- "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);
+ 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, ue->msg, bufsz);
+ strlcpy(buf, "", bufsz);
+ }
+
+ if (exterror_verbose == EXTERR_VERBOSE_ALLOW || !has_msg) {
+ char lbuf[128];
+
+ snprintf(lbuf, sizeof(lbuf),
+ "errno %d category %u (src %s:%u) p1 %#jx p2 %#jx",
+ ue->error, ue->cat, cat_to_filename(ue->cat),
+ ue->src_line, (uintmax_t)ue->p1, (uintmax_t)ue->p2);
+ if (has_msg)
+ strlcat(buf, " ", bufsz);
+ strlcat(buf, lbuf, bufsz);
}
return (0);
}
diff --git a/share/man/man9/exterror.9 b/share/man/man9/exterror.9
--- a/share/man/man9/exterror.9
+++ b/share/man/man9/exterror.9
@@ -90,6 +90,16 @@
.Fn EXTERROR
macro can take two optional 64-bit integer arguments,
whose meaning is specific to the subsystem.
+The format string may include up to two printf-like format
+specifiers to insert the optional argument values in the
+user output, which is done in userspace.
+.Pp
+The format specifier must be for an integer type, and include the
+.Dq j
+format modifier to accept only the types
+.Vt intmax_t
+or
+.Vt uintmax_t .
.El
.Pp
The strings passed as the second argument are only retained
diff --git a/sys/fs/fuse/fuse_device.c b/sys/fs/fuse/fuse_device.c
--- a/sys/fs/fuse/fuse_device.c
+++ b/sys/fs/fuse/fuse_device.c
@@ -82,7 +82,7 @@
#include <sys/sysctl.h>
#include <sys/poll.h>
#include <sys/selinfo.h>
-#define EXTERR_CATEGORY EXTERR_CAT_FUSE
+#define EXTERR_CATEGORY EXTERR_CAT_FUSE_DEVICE
#include <sys/exterrvar.h>
#include "fuse.h"
diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c
--- a/sys/fs/fuse/fuse_vfsops.c
+++ b/sys/fs/fuse/fuse_vfsops.c
@@ -81,7 +81,7 @@
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/fcntl.h>
-#define EXTERR_CATEGORY EXTERR_CAT_FUSE
+#define EXTERR_CATEGORY EXTERR_CAT_FUSE_VFS
#include <sys/exterrvar.h>
#include "fuse.h"
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -89,7 +89,7 @@
#include <sys/buf.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
-#define EXTERR_CATEGORY EXTERR_CAT_FUSE
+#define EXTERR_CATEGORY EXTERR_CAT_FUSE_VNOPS
#include <sys/exterrvar.h>
#include <vm/vm.h>
diff --git a/sys/sys/exterr_cat.h b/sys/sys/exterr_cat.h
--- a/sys/sys/exterr_cat.h
+++ b/sys/sys/exterr_cat.h
@@ -8,6 +8,17 @@
* under sponsorship from the FreeBSD Foundation.
*/
+/*
+ * The category identifiers for the extended errors.
+ * The ids participate in ABI between kernel and libc, so they must
+ * never be reused or changed. Only new ids can be added.
+ *
+ * After adding a new category id, run
+ * tools/build//make_libc_exterr_cat_filenames.sh
+ * from the top of the source tree, and commit updated file
+ * lib/libc/gen/exterr_cat_filenames.h
+ */
+
#ifndef _SYS_EXTERR_CAT_H_
#define _SYS_EXTERR_CAT_H_
@@ -15,7 +26,7 @@
#define EXTERR_CAT_FILEDESC 2
#define EXTERR_KTRACE 3 /* To allow inclusion of this
file into kern_ktrace.c */
-#define EXTERR_CAT_FUSE 4
+#define EXTERR_CAT_FUSE_VNOPS 4
#define EXTERR_CAT_INOTIFY 5
#define EXTERR_CAT_GENIO 6
#define EXTERR_CAT_BRIDGE 7
@@ -24,6 +35,8 @@
#define EXTERR_CAT_VFSBIO 10
#define EXTERR_CAT_GEOMVFS 11
#define EXTERR_CAT_GEOM 12
+#define EXTERR_CAT_FUSE_VFS 13
+#define EXTERR_CAT_FUSE_DEVICE 14
#endif
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -197,12 +197,14 @@
check_fp_fn = mrp->mr_check_fp_fn;
if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) {
- return (EXTERROR(EINVAL, "unknown PROT bits"));
+ return (EXTERROR(EINVAL, "unknown PROT bits %#jx", prot));
}
max_prot = PROT_MAX_EXTRACT(prot);
prot = PROT_EXTRACT(prot);
if (max_prot != 0 && (max_prot & prot) != prot) {
- return (EXTERROR(ENOTSUP, "prot is not subset of max_prot"));
+ return (EXTERROR(ENOTSUP,
+ "prot %#jx is not subset of max_prot %#jx",
+ prot, max_prot));
}
p = td->td_proc;
@@ -236,7 +238,7 @@
if ((len == 0 && p->p_osrel >= P_OSREL_MAP_ANON) ||
((flags & MAP_ANON) != 0 && (fd != -1 || pos != 0))) {
return (EXTERROR(EINVAL,
- "offset not zero/fd not -1 for MAP_ANON",
+ "offset %#jd not zero/fd %#jd not -1 for MAP_ANON",
fd, pos));
}
} else {
@@ -247,8 +249,8 @@
if (flags & MAP_STACK) {
if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) !=
(PROT_READ | PROT_WRITE))) {
- return (EXTERROR(EINVAL, "MAP_STACK with prot < rw",
- prot));
+ return (EXTERROR(EINVAL,
+ "MAP_STACK with prot %#jx < rw", prot));
}
flags |= MAP_ANON;
pos = 0;
@@ -257,18 +259,21 @@
MAP_STACK | MAP_NOSYNC | MAP_ANON | MAP_EXCL | MAP_NOCORE |
MAP_PREFAULT_READ | MAP_GUARD | MAP_32BIT |
MAP_ALIGNMENT_MASK)) != 0) {
- return (EXTERROR(EINVAL, "reserved flag set"));
+ return (EXTERROR(EINVAL, "reserved flag set (flags %#jx)",
+ flags));
}
if ((flags & (MAP_EXCL | MAP_FIXED)) == MAP_EXCL) {
- return (EXTERROR(EINVAL, "EXCL without FIXED"));
+ return (EXTERROR(EINVAL, "EXCL without FIXED (flags %#jx)",
+ flags));
}
if ((flags & (MAP_SHARED | MAP_PRIVATE)) == (MAP_SHARED |
MAP_PRIVATE)) {
- return (EXTERROR(EINVAL, "both SHARED and PRIVATE set"));
+ return (EXTERROR(EINVAL,
+ "both SHARED and PRIVATE set (flags %#jx)", flags));
}
if (prot != PROT_NONE &&
(prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0) {
- return (EXTERROR(EINVAL, "invalid prot", prot));
+ return (EXTERROR(EINVAL, "invalid prot %#jx", prot));
}
if ((flags & MAP_GUARD) != 0 && (prot != PROT_NONE || fd != -1 ||
pos != 0 || (flags & ~(MAP_FIXED | MAP_GUARD | MAP_EXCL |
@@ -295,7 +300,7 @@
if (align != 0 && align != MAP_ALIGNED_SUPER &&
(align >> MAP_ALIGNMENT_SHIFT >= sizeof(void *) * NBBY ||
align >> MAP_ALIGNMENT_SHIFT < PAGE_SHIFT)) {
- return (EXTERROR(EINVAL, "bad alignment", align));
+ return (EXTERROR(EINVAL, "bad alignment %#jx", align));
}
/*
@@ -310,8 +315,8 @@
*/
addr -= pageoff;
if ((addr & PAGE_MASK) != 0) {
- return (EXTERROR(EINVAL, "fixed mapping not aligned",
- addr));
+ return (EXTERROR(EINVAL,
+ "fixed mapping at %#jx not aligned", addr));
}
/* Address range must be all in user VM space. */
@@ -321,7 +326,8 @@
}
if (flags & MAP_32BIT && addr + size > MAP_32BIT_MAX_ADDR) {
return (EXTERROR(EINVAL,
- "fixed 32bit mapping does not fit into 4G"));
+ "fixed 32bit mapping of [%#jx %#jx] does not fit into 4G",
+ addr, addr + size));
}
} else if (flags & MAP_32BIT) {
/*
@@ -1495,7 +1501,7 @@
handle, &foff, &object, &writecounted);
break;
default:
- error = EXTERROR(EINVAL, "unsupported backing obj type",
+ error = EXTERROR(EINVAL, "unsupported backing obj type %jd",
handle_type);
break;
}
@@ -1578,7 +1584,7 @@
* exec).
*/
if ((foff & PAGE_MASK) != 0) {
- return (EXTERROR(EINVAL, "offset not page-aligned", foff));
+ return (EXTERROR(EINVAL, "offset %#jx not page-aligned", foff));
}
if ((flags & MAP_FIXED) == 0) {
@@ -1587,7 +1593,8 @@
} else {
if (*addr != trunc_page(*addr)) {
return (EXTERROR(EINVAL,
- "non-fixed mapping address not aligned", *addr));
+ "non-fixed mapping address %#jx not aligned",
+ *addr));
}
fitit = false;
}
@@ -1599,7 +1606,7 @@
}
if (foff != 0) {
return (EXTERROR(EINVAL,
- "anon mapping with non-zero offset"));
+ "anon mapping with non-zero offset %#jx", foff));
}
docow = 0;
} else if (flags & MAP_PREFAULT_READ)
@@ -1702,6 +1709,6 @@
}
if ((curthread->td_pflags2 & (TDP2_UEXTERR | TDP2_EXTERR)) ==
TDP2_UEXTERR)
- EXTERROR(error, "mach error", rv);
+ EXTERROR(error, "mach error %jd", rv);
return (error);
}
diff --git a/tests/sys/kern/exterr_test.c b/tests/sys/kern/exterr_test.c
--- a/tests/sys/kern/exterr_test.c
+++ b/tests/sys/kern/exterr_test.c
@@ -51,7 +51,7 @@
ATF_CHECK_EQ(0, r);
printf("Extended error: %s\n", exterr);
/* Note: error string may need to be updated due to kernel changes */
- ATF_CHECK(strstr(exterr, "prot is not subset of max_prot") != 0);
+ ATF_CHECK(strstr(exterr, " is not subset of ") != 0);
}
ATF_TC(gettext_noextended);
diff --git a/tools/build/make_libc_exterr_cat_filenames.sh b/tools/build/make_libc_exterr_cat_filenames.sh
new file mode 100755
--- /dev/null
+++ b/tools/build/make_libc_exterr_cat_filenames.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+
+check="lib/libc/gen/uexterr_format.c"
+target="lib/libc/gen/exterr_cat_filenames.h"
+
+if [ \! -f "${check}" ] ; then
+ echo "Script must be run from the top of the full source tree"
+ exit 1
+fi
+
+echo "/*" >"${target}"
+printf " * Automatically %sgenerated, use\\n" \@ >>"${target}"
+echo " * tools/build/make_libc_exterr_cat_filenames.sh" >>"${target}"
+echo " */" >>"${target}"
+
+(find sys -type f -name '*.c' | \
+ xargs grep -E '^#define[[:space:]]+EXTERR_CATEGORY[[:space:]]+EXTERR_CAT_' | \
+ sed -E 's/[[:space:]]+/:/g' | \
+ awk -F ':' '{filename = $1; sub(/^sys\//, "", filename);
+ printf("\t[%s] = \"%s\",\n", $4, filename)}') \
+ >>"${target}"

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 23, 4:29 PM (7 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27887548
Default Alt Text
D54380.id168663.diff (12 KB)

Event Timeline