* [PATCH v2 2/2] rawfbt: prvname is not properly set
@ 2026-01-26 22:54 eugene.loh
2026-01-26 23:24 ` Kris Van Hees
0 siblings, 1 reply; 2+ messages in thread
From: eugene.loh @ 2026-01-26 22:54 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
The char array prvname[] is set for each provider. It is used in the
file that implements the provider. It might also be passed to
dt_sdt_populate() via a function argument.
However, dt_provider_tp.h also defines the macro GROUP_DATA in terms of
prvname. In turn, GROUP_DATA is used not only in dt_prov_dtrace.c but
then again in dt_prov_fbt.c to define FBT_GROUP_DATA.
In commit 0b7c5a632 ("fbt, rawfbt: consolidate code to avoid duplication"),
the fbt and rawfbt providers are combined into a single file. Thus, two
uses of prvname collide. The in-file collisions get resolved, but the
cascade of macro definitions does not: FBT_GROUP_DATA ends up using
"fbt" for both fbt and rawfbt providers. As a result, it is possible
for rawfbt probes not to be seen.
Notice that GROUP_DATA is always paired with prp->desc->prb. Therefore,
simply replace:
-#define GROUP_DATA getpid(), prvname
+#define PROBE_DATA getpid(), prp->desc->prv, prp->desc->prb
This makes the code more compact and relieves the macro definitions from
needing prvname. It also makes the FBT_GROUP_DATA macro unnecessary.
The format (FMT) macro is similarly renamed and redefined to include the
probe info.
Add a test to check that a rawfbt probe can be found behind an fbt probe
when the probe description has a wildcard provider.
Orabug: 38842114
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_dtrace.c | 14 ++++-----
libdtrace/dt_prov_fbt.c | 13 ++++----
libdtrace/dt_prov_rawtp.c | 4 +--
libdtrace/dt_prov_sdt.c | 4 +--
libdtrace/dt_provider_tp.h | 12 +++----
.../providers/rawfbt/tst.wildcard-provider.d | 31 +++++++++++++++++++
.../providers/rawfbt/tst.wildcard-provider.r | 6 ++++
7 files changed, 60 insertions(+), 24 deletions(-)
create mode 100644 test/unittest/providers/rawfbt/tst.wildcard-provider.d
create mode 100644 test/unittest/providers/rawfbt/tst.wildcard-provider.r
diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
index 9f1d3e104..1bd405b81 100644
--- a/libdtrace/dt_prov_dtrace.c
+++ b/libdtrace/dt_prov_dtrace.c
@@ -239,8 +239,8 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
/* add a uprobe */
fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
if (fd != -1) {
- rc = dprintf(fd, "p:" GROUP_FMT "/%s %s\n",
- GROUP_DATA, prp->desc->prb, spec);
+ rc = dprintf(fd, "p:" PROBE_FMT " %s\n",
+ PROBE_DATA, spec);
close(fd);
}
free(spec);
@@ -248,14 +248,14 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
return -ENOENT;
/* open format file */
- len = snprintf(NULL, 0, "%s" GROUP_FMT "/%s/format",
- EVENTSFS, GROUP_DATA, prp->desc->prb) + 1;
+ len = snprintf(NULL, 0, "%s" PROBE_FMT "/format",
+ EVENTSFS, PROBE_DATA) + 1;
fn = dt_alloc(dtp, len);
if (fn == NULL)
return -ENOENT;
- snprintf(fn, len, "%s" GROUP_FMT "/%s/format",
- EVENTSFS, GROUP_DATA, prp->desc->prb);
+ snprintf(fn, len, "%s" PROBE_FMT "/format",
+ EVENTSFS, PROBE_DATA);
f = fopen(fn, "r");
dt_free(dtp, fn);
if (f == NULL)
@@ -296,7 +296,7 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
if (fd == -1)
return;
- dprintf(fd, "-:" GROUP_FMT "/%s\n", GROUP_DATA, prp->desc->prb);
+ dprintf(fd, "-:" PROBE_FMT "\n", PROBE_DATA);
close(fd);
}
diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
index 76134ce1d..ed1bd93d9 100644
--- a/libdtrace/dt_prov_fbt.c
+++ b/libdtrace/dt_prov_fbt.c
@@ -53,8 +53,7 @@ static const char prvname[] = "fbt";
#define KPROBE_EVENTS TRACEFS "kprobe_events"
-#define FBT_GROUP_FMT GROUP_FMT "_%s"
-#define FBT_GROUP_DATA GROUP_DATA, prp->desc->prb
+#define FBT_PROBE_FMT "dt_%d_%s_%s"
static const dtrace_pattr_t pattr = {
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
@@ -508,16 +507,16 @@ static int kprobe_attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
if (fd == -1)
goto out;
- rc = dprintf(fd, "%c:" FBT_GROUP_FMT "/%s %s\n",
+ rc = dprintf(fd, "%c:" FBT_PROBE_FMT "/%s %s\n",
prp->desc->prb[0] == 'e' ? 'p' : 'r',
- FBT_GROUP_DATA, tpn, fun);
+ PROBE_DATA, tpn, fun);
close(fd);
if (rc == -1)
goto out;
/* create format file name */
- if (asprintf(&fn, "%s" FBT_GROUP_FMT "/%s/format", EVENTSFS,
- FBT_GROUP_DATA, tpn) == -1)
+ if (asprintf(&fn, "%s" FBT_PROBE_FMT "/%s/format", EVENTSFS,
+ PROBE_DATA, tpn) == -1)
goto out;
/* open format file */
@@ -583,7 +582,7 @@ static void kprobe_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
}
}
- dprintf(fd, "-:" FBT_GROUP_FMT "/%s\n", FBT_GROUP_DATA, tpn);
+ dprintf(fd, "-:" FBT_PROBE_FMT "/%s\n", PROBE_DATA, tpn);
close(fd);
if (tpn != prp->desc->fun)
diff --git a/libdtrace/dt_prov_rawtp.c b/libdtrace/dt_prov_rawtp.c
index 897415459..193795974 100644
--- a/libdtrace/dt_prov_rawtp.c
+++ b/libdtrace/dt_prov_rawtp.c
@@ -56,7 +56,7 @@ static const dtrace_pattr_t pattr = {
/*
* The PROBE_LIST file lists all tracepoints in a <group>:<name> format.
* We need to ignore these groups:
- * - GROUP_FMT (created by DTrace processes)
+ * - PROBE_SFMT
* - kprobes and uprobes
* - syscalls (handled by a different provider)
* - pid and usdt probes (ditto)
@@ -89,7 +89,7 @@ static int populate(dtrace_hdl_t *dtp)
*p++ = '\0';
- if (sscanf(buf, GROUP_SFMT, &dummy, &str) == 2) {
+ if (sscanf(buf, PROBE_SFMT, &dummy, &str) == 2) {
free(str);
continue;
}
diff --git a/libdtrace/dt_prov_sdt.c b/libdtrace/dt_prov_sdt.c
index fb024b078..f9de2cf85 100644
--- a/libdtrace/dt_prov_sdt.c
+++ b/libdtrace/dt_prov_sdt.c
@@ -54,7 +54,7 @@ static const dtrace_pattr_t pattr = {
/*
* The PROBE_LIST file lists all tracepoints in a <group>:<name> format.
* We need to ignore these groups:
- * - GROUP_FMT (created by DTrace processes)
+ * - PROBE_SFMT
* - kprobes and uprobes
* - syscalls (handled by a different provider)
* - pid and usdt probes (ditto)
@@ -87,7 +87,7 @@ static int populate(dtrace_hdl_t *dtp)
*p++ = '\0';
- if (sscanf(buf, GROUP_SFMT, &dummy, &str) == 2) {
+ if (sscanf(buf, PROBE_SFMT, &dummy, &str) == 2) {
free(str);
continue;
}
diff --git a/libdtrace/dt_provider_tp.h b/libdtrace/dt_provider_tp.h
index f131b1e02..406609d1b 100644
--- a/libdtrace/dt_provider_tp.h
+++ b/libdtrace/dt_provider_tp.h
@@ -18,13 +18,13 @@ extern "C" {
* Tracepoint group naming format for DTrace providers. Providers may append
* to this format string as needed.
*
- * GROUP_DATA provides the necessary data items to populate the format string
- * (PID of the dtrace process and the provider name). GROUP_SFMT is like
- * GROUP_FMT, but for sscanf().
+ * PROBE_DATA provides the necessary data items to populate the format string.
+ * PROBE_FMT formats that data.
+ * PROBE_SFMT is a format string for recognizing PROBE_FMT data in sscanf().
*/
-#define GROUP_FMT "dt_%d_%s"
-#define GROUP_SFMT "dt_%d_%ms"
-#define GROUP_DATA getpid(), prvname
+#define PROBE_DATA getpid(), prp->desc->prv, prp->desc->prb
+#define PROBE_FMT "dt_%d_%s/%s"
+#define PROBE_SFMT "dt_%d_%ms"
typedef struct tp_probe tp_probe_t;
diff --git a/test/unittest/providers/rawfbt/tst.wildcard-provider.d b/test/unittest/providers/rawfbt/tst.wildcard-provider.d
new file mode 100644
index 000000000..f73b33f24
--- /dev/null
+++ b/test/unittest/providers/rawfbt/tst.wildcard-provider.d
@@ -0,0 +1,31 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: rawfbt probes can be found even when a wildcard provider
+ * description also allows fbt probes.
+ */
+
+/*
+ * We expect to find 5 probes:
+ * BEGIN
+ * fbt vmlinux do_sys_openat2 entry
+ * fbt vmlinux do_sys_open entry
+ * rawfbt vmlinux do_sys_openat2 entry
+ * rawfbt vmlinux do_sys_open entry
+ *
+ * We want to validate:
+ * - the FBT and rawfbt probes are all found
+ * - the script executes (dtrace could attach to the probes)
+ */
+
+BEGIN,
+*fbt:vmlinux:do_sys_open*:entry
+{
+ printf("success\n");
+ exit(0);
+}
diff --git a/test/unittest/providers/rawfbt/tst.wildcard-provider.r b/test/unittest/providers/rawfbt/tst.wildcard-provider.r
new file mode 100644
index 000000000..f7b429211
--- /dev/null
+++ b/test/unittest/providers/rawfbt/tst.wildcard-provider.r
@@ -0,0 +1,6 @@
+ FUNCTION:NAME
+ :BEGIN success
+
+
+-- @@stderr --
+dtrace: script 'test/unittest/providers/rawfbt/tst.wildcard-provider.d' matched 5 probes
--
2.47.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v2 2/2] rawfbt: prvname is not properly set
2026-01-26 22:54 [PATCH v2 2/2] rawfbt: prvname is not properly set eugene.loh
@ 2026-01-26 23:24 ` Kris Van Hees
0 siblings, 0 replies; 2+ messages in thread
From: Kris Van Hees @ 2026-01-26 23:24 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Mon, Jan 26, 2026 at 05:54:08PM -0500, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> The char array prvname[] is set for each provider. It is used in the
> file that implements the provider. It might also be passed to
> dt_sdt_populate() via a function argument.
>
> However, dt_provider_tp.h also defines the macro GROUP_DATA in terms of
> prvname. In turn, GROUP_DATA is used not only in dt_prov_dtrace.c but
> then again in dt_prov_fbt.c to define FBT_GROUP_DATA.
>
> In commit 0b7c5a632 ("fbt, rawfbt: consolidate code to avoid duplication"),
> the fbt and rawfbt providers are combined into a single file. Thus, two
> uses of prvname collide. The in-file collisions get resolved, but the
> cascade of macro definitions does not: FBT_GROUP_DATA ends up using
> "fbt" for both fbt and rawfbt providers. As a result, it is possible
> for rawfbt probes not to be seen.
>
> Notice that GROUP_DATA is always paired with prp->desc->prb. Therefore,
> simply replace:
> -#define GROUP_DATA getpid(), prvname
> +#define PROBE_DATA getpid(), prp->desc->prv, prp->desc->prb
> This makes the code more compact and relieves the macro definitions from
> needing prvname. It also makes the FBT_GROUP_DATA macro unnecessary.
>
> The format (FMT) macro is similarly renamed and redefined to include the
> probe info.
>
> Add a test to check that a rawfbt probe can be found behind an fbt probe
> when the probe description has a wildcard provider.
>
> Orabug: 38842114
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
> ---
> libdtrace/dt_prov_dtrace.c | 14 ++++-----
> libdtrace/dt_prov_fbt.c | 13 ++++----
> libdtrace/dt_prov_rawtp.c | 4 +--
> libdtrace/dt_prov_sdt.c | 4 +--
> libdtrace/dt_provider_tp.h | 12 +++----
> .../providers/rawfbt/tst.wildcard-provider.d | 31 +++++++++++++++++++
> .../providers/rawfbt/tst.wildcard-provider.r | 6 ++++
> 7 files changed, 60 insertions(+), 24 deletions(-)
> create mode 100644 test/unittest/providers/rawfbt/tst.wildcard-provider.d
> create mode 100644 test/unittest/providers/rawfbt/tst.wildcard-provider.r
>
> diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
> index 9f1d3e104..1bd405b81 100644
> --- a/libdtrace/dt_prov_dtrace.c
> +++ b/libdtrace/dt_prov_dtrace.c
> @@ -239,8 +239,8 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
> /* add a uprobe */
> fd = open(UPROBE_EVENTS, O_WRONLY | O_APPEND);
> if (fd != -1) {
> - rc = dprintf(fd, "p:" GROUP_FMT "/%s %s\n",
> - GROUP_DATA, prp->desc->prb, spec);
> + rc = dprintf(fd, "p:" PROBE_FMT " %s\n",
> + PROBE_DATA, spec);
> close(fd);
> }
> free(spec);
> @@ -248,14 +248,14 @@ static int attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
> return -ENOENT;
>
> /* open format file */
> - len = snprintf(NULL, 0, "%s" GROUP_FMT "/%s/format",
> - EVENTSFS, GROUP_DATA, prp->desc->prb) + 1;
> + len = snprintf(NULL, 0, "%s" PROBE_FMT "/format",
> + EVENTSFS, PROBE_DATA) + 1;
> fn = dt_alloc(dtp, len);
> if (fn == NULL)
> return -ENOENT;
>
> - snprintf(fn, len, "%s" GROUP_FMT "/%s/format",
> - EVENTSFS, GROUP_DATA, prp->desc->prb);
> + snprintf(fn, len, "%s" PROBE_FMT "/format",
> + EVENTSFS, PROBE_DATA);
> f = fopen(fn, "r");
> dt_free(dtp, fn);
> if (f == NULL)
> @@ -296,7 +296,7 @@ static void detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
> if (fd == -1)
> return;
>
> - dprintf(fd, "-:" GROUP_FMT "/%s\n", GROUP_DATA, prp->desc->prb);
> + dprintf(fd, "-:" PROBE_FMT "\n", PROBE_DATA);
> close(fd);
> }
>
> diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
> index 76134ce1d..ed1bd93d9 100644
> --- a/libdtrace/dt_prov_fbt.c
> +++ b/libdtrace/dt_prov_fbt.c
> @@ -53,8 +53,7 @@ static const char prvname[] = "fbt";
>
> #define KPROBE_EVENTS TRACEFS "kprobe_events"
>
> -#define FBT_GROUP_FMT GROUP_FMT "_%s"
> -#define FBT_GROUP_DATA GROUP_DATA, prp->desc->prb
> +#define FBT_PROBE_FMT "dt_%d_%s_%s"
>
> static const dtrace_pattr_t pattr = {
> { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
> @@ -508,16 +507,16 @@ static int kprobe_attach(dtrace_hdl_t *dtp, const dt_probe_t *prp, int bpf_fd)
> if (fd == -1)
> goto out;
>
> - rc = dprintf(fd, "%c:" FBT_GROUP_FMT "/%s %s\n",
> + rc = dprintf(fd, "%c:" FBT_PROBE_FMT "/%s %s\n",
> prp->desc->prb[0] == 'e' ? 'p' : 'r',
> - FBT_GROUP_DATA, tpn, fun);
> + PROBE_DATA, tpn, fun);
> close(fd);
> if (rc == -1)
> goto out;
>
> /* create format file name */
> - if (asprintf(&fn, "%s" FBT_GROUP_FMT "/%s/format", EVENTSFS,
> - FBT_GROUP_DATA, tpn) == -1)
> + if (asprintf(&fn, "%s" FBT_PROBE_FMT "/%s/format", EVENTSFS,
> + PROBE_DATA, tpn) == -1)
> goto out;
>
> /* open format file */
> @@ -583,7 +582,7 @@ static void kprobe_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
> }
> }
>
> - dprintf(fd, "-:" FBT_GROUP_FMT "/%s\n", FBT_GROUP_DATA, tpn);
> + dprintf(fd, "-:" FBT_PROBE_FMT "/%s\n", PROBE_DATA, tpn);
> close(fd);
>
> if (tpn != prp->desc->fun)
> diff --git a/libdtrace/dt_prov_rawtp.c b/libdtrace/dt_prov_rawtp.c
> index 897415459..193795974 100644
> --- a/libdtrace/dt_prov_rawtp.c
> +++ b/libdtrace/dt_prov_rawtp.c
> @@ -56,7 +56,7 @@ static const dtrace_pattr_t pattr = {
> /*
> * The PROBE_LIST file lists all tracepoints in a <group>:<name> format.
> * We need to ignore these groups:
> - * - GROUP_FMT (created by DTrace processes)
> + * - PROBE_SFMT
> * - kprobes and uprobes
> * - syscalls (handled by a different provider)
> * - pid and usdt probes (ditto)
> @@ -89,7 +89,7 @@ static int populate(dtrace_hdl_t *dtp)
>
> *p++ = '\0';
>
> - if (sscanf(buf, GROUP_SFMT, &dummy, &str) == 2) {
> + if (sscanf(buf, PROBE_SFMT, &dummy, &str) == 2) {
> free(str);
> continue;
> }
> diff --git a/libdtrace/dt_prov_sdt.c b/libdtrace/dt_prov_sdt.c
> index fb024b078..f9de2cf85 100644
> --- a/libdtrace/dt_prov_sdt.c
> +++ b/libdtrace/dt_prov_sdt.c
> @@ -54,7 +54,7 @@ static const dtrace_pattr_t pattr = {
> /*
> * The PROBE_LIST file lists all tracepoints in a <group>:<name> format.
> * We need to ignore these groups:
> - * - GROUP_FMT (created by DTrace processes)
> + * - PROBE_SFMT
> * - kprobes and uprobes
> * - syscalls (handled by a different provider)
> * - pid and usdt probes (ditto)
> @@ -87,7 +87,7 @@ static int populate(dtrace_hdl_t *dtp)
>
> *p++ = '\0';
>
> - if (sscanf(buf, GROUP_SFMT, &dummy, &str) == 2) {
> + if (sscanf(buf, PROBE_SFMT, &dummy, &str) == 2) {
> free(str);
> continue;
> }
> diff --git a/libdtrace/dt_provider_tp.h b/libdtrace/dt_provider_tp.h
> index f131b1e02..406609d1b 100644
> --- a/libdtrace/dt_provider_tp.h
> +++ b/libdtrace/dt_provider_tp.h
> @@ -18,13 +18,13 @@ extern "C" {
> * Tracepoint group naming format for DTrace providers. Providers may append
> * to this format string as needed.
> *
> - * GROUP_DATA provides the necessary data items to populate the format string
> - * (PID of the dtrace process and the provider name). GROUP_SFMT is like
> - * GROUP_FMT, but for sscanf().
> + * PROBE_DATA provides the necessary data items to populate the format string.
> + * PROBE_FMT formats that data.
> + * PROBE_SFMT is a format string for recognizing PROBE_FMT data in sscanf().
> */
> -#define GROUP_FMT "dt_%d_%s"
> -#define GROUP_SFMT "dt_%d_%ms"
> -#define GROUP_DATA getpid(), prvname
> +#define PROBE_DATA getpid(), prp->desc->prv, prp->desc->prb
> +#define PROBE_FMT "dt_%d_%s/%s"
> +#define PROBE_SFMT "dt_%d_%ms"
>
> typedef struct tp_probe tp_probe_t;
>
> diff --git a/test/unittest/providers/rawfbt/tst.wildcard-provider.d b/test/unittest/providers/rawfbt/tst.wildcard-provider.d
> new file mode 100644
> index 000000000..f73b33f24
> --- /dev/null
> +++ b/test/unittest/providers/rawfbt/tst.wildcard-provider.d
> @@ -0,0 +1,31 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: rawfbt probes can be found even when a wildcard provider
> + * description also allows fbt probes.
> + */
> +
> +/*
> + * We expect to find 5 probes:
> + * BEGIN
> + * fbt vmlinux do_sys_openat2 entry
> + * fbt vmlinux do_sys_open entry
> + * rawfbt vmlinux do_sys_openat2 entry
> + * rawfbt vmlinux do_sys_open entry
> + *
> + * We want to validate:
> + * - the FBT and rawfbt probes are all found
> + * - the script executes (dtrace could attach to the probes)
> + */
> +
> +BEGIN,
> +*fbt:vmlinux:do_sys_open*:entry
> +{
> + printf("success\n");
> + exit(0);
> +}
> diff --git a/test/unittest/providers/rawfbt/tst.wildcard-provider.r b/test/unittest/providers/rawfbt/tst.wildcard-provider.r
> new file mode 100644
> index 000000000..f7b429211
> --- /dev/null
> +++ b/test/unittest/providers/rawfbt/tst.wildcard-provider.r
> @@ -0,0 +1,6 @@
> + FUNCTION:NAME
> + :BEGIN success
> +
> +
> +-- @@stderr --
> +dtrace: script 'test/unittest/providers/rawfbt/tst.wildcard-provider.d' matched 5 probes
> --
> 2.47.3
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-01-26 23:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-26 22:54 [PATCH v2 2/2] rawfbt: prvname is not properly set eugene.loh
2026-01-26 23:24 ` Kris Van Hees
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox