diff --git a/.gitignore b/.gitignore
index 1ce14a3..ec3000c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,9 @@ init
libquark.a
libquark_big.a
bpf_prog_skel.h
+# manpages.h is autogenerated
+manpages.h
+man-embedder
manhtml/*.html
elftoolchain/libelf/libelf_pic.a
initramfs/
diff --git a/Makefile b/Makefile
index 4ce3254..763954e 100644
--- a/Makefile
+++ b/Makefile
@@ -74,6 +74,7 @@ EEBPF_INCLUDES:= -Ielastic-ebpf/GPL/Events -Ielastic-ebpf/contrib/vmlinux/$(ARCH
# LIBQUARK
LIBQUARK_DEPS:= $(wildcard *.h) bpf_prog_skel.h $(EEBPF_FILES) include
+LIBQUARK_DEPS:= $(filter-out manpages.h, $(LIBQUARK_DEPS))
LIBQUARK_SRCS:= \
bpf_queue.c \
btf.c \
@@ -198,7 +199,7 @@ docker: docker-image clean-all
$(call msg,DOCKER-RUN,Dockerfile)
$(Q)$(DOCKER) run $(DOCKER_RUN_ARGS) /bin/bash -c "make -C $(PWD)"
-docker-cross-arm64: clean-all docker-image
+docker-cross-arm64: clean-all docker-image manpages.h
$(call msg,DOCKER-RUN,Dockerfile)
$(Q)$(DOCKER) run \
-e ARCH=arm64 \
@@ -278,29 +279,52 @@ init: init.c
$(call msg,CC,$@)
$(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -static -o $@ $^
-quark-mon: quark-mon.c $(LIBQUARK_STATIC_BIG)
+quark-mon: quark-mon.c manpages.h $(LIBQUARK_STATIC_BIG)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -o $@ $^
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) \
+ -o $@ $< $(LIBQUARK_STATIC_BIG)
-quark-btf: quark-btf.c $(LIBQUARK_STATIC_BIG)
+quark-btf: quark-btf.c manpages.h $(LIBQUARK_STATIC_BIG)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -o $@ $^
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) \
+ -o $@ $< $(LIBQUARK_STATIC_BIG)
-quark-test: quark-test.c $(LIBQUARK_STATIC_BIG)
+quark-test: quark-test.c manpages.h $(LIBQUARK_STATIC_BIG)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -o $@ $^
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) \
+ -o $@ $< $(LIBQUARK_STATIC_BIG)
-quark-mon-static: quark-mon.c $(LIBQUARK_STATIC_BIG)
+quark-mon-static: quark-mon.c manpages.h $(LIBQUARK_STATIC_BIG)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -DNO_PRIVDROP $(CDIAGFLAGS) -static -o $@ $^
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -DNO_PRIVDROP $(CDIAGFLAGS) \
+ -static -o $@ $< $(LIBQUARK_STATIC_BIG)
-quark-btf-static: quark-btf.c $(LIBQUARK_STATIC_BIG)
+quark-btf-static: quark-btf.c manpages.h $(LIBQUARK_STATIC_BIG)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -static -o $@ $^
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) \
+ -static -o $@ $< $(LIBQUARK_STATIC_BIG)
-quark-test-static: quark-test.c $(LIBQUARK_STATIC_BIG)
+quark-test-static: quark-test.c manpages.h $(LIBQUARK_STATIC_BIG)
$(call msg,CC,$@)
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -static -o $@ $^
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) \
+ -static -o $@ $< $(LIBQUARK_STATIC_BIG)
+
+man-embedder: man-embedder.c
+ $(call msg,CC,$@)
+ $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(CDIAGFLAGS) -o $@ $^
+
+manpages.h: man-embedder display_man.c quark-btf.8 quark-mon.8 quark-test.8
+ $(Q)echo '// SPDX-License-Identifier: Apache-2.0' > $@
+ $(Q)echo '/* Copyright (c) 2024 Elastic NV */' >> $@
+ $(Q)echo '' >> $@
+ $(call msg,MAN-EMB,quark-btf.8)
+ $(Q)./man-embedder quark-btf.8 MAN_QUARK_BTF >> $@
+ $(call msg,MAN-EMB,quark-mon.8)
+ $(Q)./man-embedder quark-mon.8 MAN_QUARK_MON >> $@
+ $(call msg,MAN-EMB,quark-test.8)
+ $(Q)./man-embedder quark-test.8 MAN_QUARK_TEST >> $@
+ $(call msg,MAN-EMB,display_man.c)
+ $(Q)cat display_man.c >> $@
docs/index.html: docs/quark.7.html
$(call msg,CP,index.html)
@@ -336,6 +360,8 @@ clean:
$(Q)rm -f \
*.o \
*.a \
+ man-embedder \
+ manpages.h \
quark-mon \
quark-mon-static \
quark-btf \
diff --git a/display_man.c b/display_man.c
new file mode 100644
index 0000000..b78cd37
--- /dev/null
+++ b/display_man.c
@@ -0,0 +1,33 @@
+/*
+ * This code is stashed in the end of manpage.h
+ */
+static void
+display_man(void)
+{
+ int fd, status;
+ char template[] = "/tmp/quark-man-display.XXXXXX";
+ pid_t pid;
+
+ fd = mkstemp(template);
+ if (fd == -1)
+ err(1, "mkstemp");
+ if (qwrite(fd, manpage_bin, sizeof(manpage_bin)) != 0)
+ err(1, "qwrite");
+ close(fd);
+
+ if ((pid = fork()) == -1)
+ err(1, "fork");
+
+ /* child */
+ if (pid == 0)
+ exit(execlp("man", "man", template, NULL));
+ /* parent */
+ if (waitpid(pid, &status, 0) == -1)
+ err(1, "waitpid");
+ if (unlink(template) != 0)
+ warn("unlink");
+ if (WIFEXITED(status))
+ exit(WEXITSTATUS(status));
+
+ exit(1);
+}
diff --git a/docs/quark-btf.8.html b/docs/quark-btf.8.html
index 4763501..05c6a8e 100644
--- a/docs/quark-btf.8.html
+++ b/docs/quark-btf.8.html
@@ -46,6 +46,13 @@
+
quark-btf -V |
@@ -80,9 +87,12 @@ DESCRIP
uname
-r.
- This option only used to generate btfhub.c via
- genbtf.sh, chances are you'll never need
- this.
+
This option is only used to generate
+ btfhub.c via genbtf.sh,
+ chances are you'll never need this.
+
+ -h
+ Display this manpage.
-l
version
Lookup the kernel
@@ -155,7 +165,7 @@
diff --git a/docs/quark-mon.8.html b/docs/quark-mon.8.html
index ef0a79c..36f18d3 100644
--- a/docs/quark-mon.8.html
+++ b/docs/quark-mon.8.html
@@ -32,6 +32,13 @@
+
+
quark-mon -V |
@@ -78,6 +85,8 @@
+
+
quark-test -l |
@@ -64,6 +71,8 @@ DESCRIP
-b
- Run only EBPF tests.
+ -h
+ - Display this manpage.
-k
- Run only KPROBE tests.
-l
@@ -120,7 +129,7 @@ SEE
diff --git a/man-embedder.c b/man-embedder.c
new file mode 100644
index 0000000..a27e0a1
--- /dev/null
+++ b/man-embedder.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: Apache-2.0
+/* Copyright (c) 2024 Elastic NV */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s input_file ifdef_name\n",
+ program_invocation_short_name);
+
+ exit(1);
+}
+
+static int
+embed(const char *input_path, const char *ifdef_name)
+{
+ FILE *input;
+ int ch, line_wrap;
+
+ if ((input = fopen(input_path, "r")) == NULL)
+ err(1, "fopen");
+
+ if (ifdef_name != NULL)
+ printf("#ifdef %s\n", ifdef_name);
+ printf("const char manpage_bin[] = {\n");
+
+ line_wrap = 0;
+ while ((ch = fgetc(input)) != EOF) {
+ if (line_wrap == 0)
+ putchar('\t');
+ printf("0x%02x, ", ch);
+ if (++line_wrap == 10) {
+ putchar('\n');
+ line_wrap = 0;
+ }
+ }
+ if (ferror(input))
+ errx(1, "input error");
+ fclose(input);
+
+ printf("\n};\n");
+ if (ifdef_name != NULL)
+ printf("#endif /* %s */", ifdef_name);
+ putchar('\n');
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 3)
+ usage();
+
+ return (embed(argv[1], argv[2]));
+}
diff --git a/quark-btf.8 b/quark-btf.8
index ea6efbb..01bf0c3 100644
--- a/quark-btf.8
+++ b/quark-btf.8
@@ -16,6 +16,8 @@
.Nm quark-btf
.Op Fl v
.Fl g Ar btf_file name version
+.Nm quark-btf
+.Fl h
.Nm quark-btf Fl V
.Sh DESCRIPTION
The
@@ -45,11 +47,14 @@ is a human identifier, like ubuntu-22.
is the kernel version as returned by
.Em uname -r .
.El
-This option only used to generate
+.Pp
+This option is only used to generate
.Pa btfhub.c
via
.Pa genbtf.sh ,
chances are you'll never need this.
+.It Fl h
+Display this manpage.
.It Fl l Ar version
Lookup the kernel
.Em version
diff --git a/quark-btf.c b/quark-btf.c
index 8192db9..0743fcf 100644
--- a/quark-btf.c
+++ b/quark-btf.c
@@ -9,8 +9,13 @@
#include
#include
+#include
+
#include "quark.h"
+#define MAN_QUARK_BTF
+#include "manpages.h"
+
static int bflag;
static int fflag;
static int gflag;
@@ -29,6 +34,8 @@ disply_version(void)
static void
usage(void)
{
+ fprintf(stderr, "usage: %s -h\n",
+ program_invocation_short_name);
fprintf(stderr, "usage: %s [-bv] [targets...]\n",
program_invocation_short_name);
fprintf(stderr, "usage: %s [-bv] [-f btf_file]\n",
@@ -229,7 +236,7 @@ main(int argc, char *argv[])
int ch;
const char *path = NULL;
- while ((ch = getopt(argc, argv, "bf:glvV")) != -1) {
+ while ((ch = getopt(argc, argv, "bf:ghlvV")) != -1) {
switch (ch) {
case 'b':
bflag = 1;
@@ -237,6 +244,12 @@ main(int argc, char *argv[])
case 'g':
gflag = 1;
break;
+ case 'h':
+ if (isatty(STDOUT_FILENO))
+ display_man();
+ else
+ usage();
+ break; /* NOTREACHED */
case 'l':
lflag = 1;
break;
diff --git a/quark-mon.8 b/quark-mon.8
index f3061a3..8349bda 100644
--- a/quark-mon.8
+++ b/quark-mon.8
@@ -10,6 +10,8 @@
.Op Fl C Ar filename
.Op Fl l Ar maxlength
.Op Fl m Ar maxnodes
+.Nm quark-mon
+.Fl h
.Nm quark-mon Fl V
.Sh DESCRIPTION
The
@@ -56,6 +58,8 @@ it is Elastic/ECS specific.
Use minimal aggregation, fork, exec and exit will
.Em not
be aggregated.
+.It Fl h
+Display this manpage.
.It Fl k
Attempt kprobe as the backend.
.It Fl l Ar maxlength
diff --git a/quark-mon.c b/quark-mon.c
index 613383c..50e74b3 100644
--- a/quark-mon.c
+++ b/quark-mon.c
@@ -12,8 +12,13 @@
#include
#include
+#include
+
#include "quark.h"
+#define MAN_QUARK_MON
+#include "manpages.h"
+
static int gotsigint;
static void
@@ -87,6 +92,7 @@ display_version(void)
static void
usage(void)
{
+ fprintf(stderr, "usage: %s -h\n", program_invocation_short_name);
fprintf(stderr, "usage: %s [-bDefkstv] "
"[-C filename ] [-l maxlength] [-m maxnodes]\n",
program_invocation_short_name);
@@ -113,7 +119,7 @@ main(int argc, char *argv[])
nqevs = 32;
graph_by_time = graph_by_pidtime = graph_cache = NULL;
- while ((ch = getopt(argc, argv, "bC:Degklm:tsvV")) != -1) {
+ while ((ch = getopt(argc, argv, "bC:Deghklm:tsvV")) != -1) {
const char *errstr;
switch (ch) {
@@ -134,6 +140,12 @@ main(int argc, char *argv[])
case 'g':
qa.flags |= QQ_MIN_AGG;
break;
+ case 'h':
+ if (isatty(STDOUT_FILENO))
+ display_man();
+ else
+ usage();
+ break; /* NOTREACHED */
case 'k':
qa.flags |= QQ_KPROBE;
break;
diff --git a/quark-test.8 b/quark-test.8
index 65aa892..cfe2007 100644
--- a/quark-test.8
+++ b/quark-test.8
@@ -8,6 +8,8 @@
.Nm quark-test
.Op Fl bkv
.Op Ar tests ...
+.Nm quark-test
+.Fl h
.Nm quark-test Fl l
.Nm quark-test Fl N
.Nm quark-test Fl V
@@ -32,6 +34,8 @@ The options are as follows:
.Bl -tag -width Dtb
.It Fl b
Run only EBPF tests.
+.It Fl h
+Display this manpage.
.It Fl k
Run only KPROBE tests.
.It Fl l
diff --git a/quark-test.c b/quark-test.c
index f69617e..1a7ec2e 100644
--- a/quark-test.c
+++ b/quark-test.c
@@ -16,6 +16,9 @@
#include "quark.h"
+#define MAN_QUARK_TEST
+#include "manpages.h"
+
static int bflag; /* run bpf tests */
static int kflag; /* run kprobe tests */
@@ -145,6 +148,8 @@ display_version(void)
static void
usage(void)
{
+ fprintf(stderr, "usage: %s -h\n",
+ program_invocation_short_name);
fprintf(stderr, "usage: %s [-bkv] [tests ...]\n",
program_invocation_short_name);
fprintf(stderr, "usage: %s -l\n",
@@ -692,11 +697,17 @@ main(int argc, char *argv[])
{
int ch, x, failed;
- while ((ch = getopt(argc, argv, "bklNvV")) != -1) {
+ while ((ch = getopt(argc, argv, "bhklNvV")) != -1) {
switch (ch) {
case 'b':
bflag = 1;
break;
+ case 'h':
+ if (isatty(STDOUT_FILENO))
+ display_man();
+ else
+ usage();
+ break; /* NOTREACHED */
case 'k':
kflag = 1;
break;