From 569f527a427531691dee1b9e305cab5d4b6d00f8 Mon Sep 17 00:00:00 2001
From: ghuter <ghuter@disroot.org>
Date: Tue, 31 Jan 2023 17:32:40 +0100
Subject: [PATCH] Add a generation system for README.md and doc/mojitos.1

- README.md can be updated via `make readme`
- doc/mojitos.1 can be generated via `make man`
- README.md is updated and doc/mojitos.1 generated on `make all`
- correct wrong translation "captor", to "sensor"
- update README.md build instructions
- mv src/optparse.h and src/info_reader.h to ./lib/
- add the possibility to execute an alternative function when parsing
  sensor options (other than `add_source()`)
---
 .gitignore                       |  3 +-
 README.md                        | 75 +++++++++++++-------------
 configure.sh                     | 91 ++++++++++++++++---------------
 doc/counter_ex.h                 |  2 +-
 doc/{mojitos.1 => mojitos.pre.1} | 41 +++-----------
 {src => lib}/info_reader.h       |  0
 {src => lib}/optparse.h          |  1 +
 makefile                         | 18 +++++--
 src/amd_rapl.h                   |  2 +-
 src/counters.c                   |  6 ++-
 src/counters.h                   |  7 +--
 src/infiniband.h                 |  2 +-
 src/load.h                       |  2 +-
 src/mojitos.c                    | 93 +++++++++++++++++++++-----------
 src/network.h                    |  2 +-
 src/rapl.h                       |  2 +-
 src/temperature.h                |  2 +-
 tools/update-readme-usage.sh     | 27 ++++++++++
 18 files changed, 213 insertions(+), 163 deletions(-)
 rename doc/{mojitos.1 => mojitos.pre.1} (69%)
 rename {src => lib}/info_reader.h (100%)
 rename {src => lib}/optparse.h (99%)
 create mode 100755 tools/update-readme-usage.sh

diff --git a/.gitignore b/.gitignore
index 6643912..31260f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,10 @@
 doc/test_main_ex
 doc/info_reader_ex
+doc/mojitos.1
 tests/run
 src/counters_option.h
 src/sensors.h
-captors.mk
+sensors.mk
 bin
 obj
 *.swp
diff --git a/README.md b/README.md
index 6422ce0..10f5aaf 100644
--- a/README.md
+++ b/README.md
@@ -6,51 +6,52 @@ MojitO/S runs on GNU/Linux
 ## Usage
 
 ```bash
-Usage : mojitos [-rsu] [-t time] [-f freq] [-p perf_list]  \
-                [-d network_device] [-o logfile] [-e command arguments...]
-        mojitos [-l]
-
-     -s      Enable overhead statistics (in nanoseconds).
-
-     -u      Enable system-level load monitoring.
-
-     -r      Enable RAPL.
-
-     -p perf_list
-             Enable performance counters.  The argument is a coma separated
-             list of performance counters.
-
-     -d net_device
-             Enable network monitoring.
-
-     -l      List the available performance counters and quit.
-
-     -t time
-             Set duration value (in seconds). If 0, then loops indefinitely.
-
-     -f freq
-             Set amount of measurements per second.
-
-     -e cmd ...
-             Execute a command with optional arguments.  If this option is
-             used, any usage of -t or -f is ignored.
+Usage : ./bin/mojitos [OPTIONS] [SENSOR ...] [-e <cmd> ...]
+
+OPTIONS:
+-f|--freq <freq>
+	set amount of measurements per second.
+-t|--time <time>
+	set duration value (seconds). If 0, then loops infinitely.
+-e|--exec <cmd> ...
+	Execute a command with optional arguments.
+	If this option is used, any usage of -t or -f is ignored.
+-o|--logfile <file>
+	specify a log file.
+-s|--overhead-stats
+	enable overhead statistics (nanoseconds).
+
+SENSORS:
+-p|--perf-list <perf_list>
+	performance counters
+	perf_list is a coma separated list of performance counters.
+	Ex: instructions,cache_misses
+-l|--list
+	list the available performance counters and quit
+-u|--sysload
+	system load
+-d|--net-dev <net_dev>
+	network monitoring (if network_device is X, tries to detect it automatically)
+-r|--rapl
+	RAPL
+-c|--cpu-temp
+	processor temperature
 ```
 
 ## Installation Instructions
 
-Dependencies
-```bash
-sudo apt install libpowercap0 libpowercap-dev powercap-utils python3
-```
 Download the source code
 ```bash
 git clone https://gitlab.irit.fr/sepia-pub/mojitos.git
 ```
-Compile the code
+The quickest way to compile the code is:
 ```bash
 cd mojitos
+./configure.sh
 make
 ```
+You may want to run `./configure.sh --help` to see configuration options.
+
 To execute mojitos without being root to monitor performance counters
 ```bash
 sudo sh -c 'echo 0 >/proc/sys/kernel/perf_event_paranoid'
@@ -65,7 +66,7 @@ sudo chmod a+w /sys/class/powercap/intel-rapl/*/*/*
 
 RAPL values during 2 seconds with a frequency of 2 Hz
 ```bash
-$ ./mojitos -t 2 -f 2 -r
+$ ./bin/mojitos -t 2 -f 2 -r
 #timestamp package-00 core0 dram0
 1036389.135659868 10986 2869 1526
 1036389.500183551 1291440 255736 515562
@@ -75,7 +76,7 @@ $ ./mojitos -t 2 -f 2 -r
 Performance counters (cpu_cycle, cache_ll_r_a and page_faults) during 4 seconds with a frequency of 1Hz. For cache performance counters, _r and _w are respectively read and write, and _a, _m and _p are respectively access, miss, pending.
 
 ```bash
-$ ./mojitos -t 4 -f 1 -p cpu_cycles,cache_ll_r_a,page_faults
+$ ./bin/mojitos -t 4 -f 1 -p cpu_cycles,cache_ll_r_a,page_faults
 #timestamp cpu_cycles cache_ll page_faults
 1036846.351749455 571199 1232 0
 1036847.001098880 348173344 2451387 872
@@ -85,7 +86,7 @@ $ ./mojitos -t 4 -f 1 -p cpu_cycles,cache_ll_r_a,page_faults
 
 Network values with no time limit with a frequency of 1Hz. rxp and txp are the number of received and sent packets, while rxb and txp are the number of received and sent bytes.
 ```bash
-$ ./mojitos -t 0 -f 1 -d enp0s25
+$ ./bin/mojitos -t 0 -f 1 -d enp0s25
 #timestamp rxp rxb txp txb
 1036559.277376027 0 0 0 0
 1036560.000161101 4 581 2 179
@@ -97,7 +98,7 @@ $ ./mojitos -t 0 -f 1 -d enp0s25
 
 Overhead of the monitoring for RAPL and cpu_cycle
 ```bash
-$ ./mojitos -t 5 -f 1 -p cpu_cycles -r -s
+$ ./bin/mojitos -t 5 -f 1 -p cpu_cycles -r -s
 #timestamp cpu_cycles package-00 core0 dram0 overhead
 1036988.197227391 162214 19898 4944 1586 149612
 1036989.000151326 332613664 2513116 379577 1115171 739573
diff --git a/configure.sh b/configure.sh
index 49e1789..62f297a 100755
--- a/configure.sh
+++ b/configure.sh
@@ -20,25 +20,25 @@ decho() {
 }
 
 debug=0
-target_hdr=src/captors.h
-target_mk=captors.mk
+target_hdr=src/sensors.h
+target_mk=sensors.mk
 
-noncaptor='counters_option|optparse|captors|util|info_reader'
+nonsensor='counters_option|optparse|sensors|util|info_reader'
 
-hdr_blacklist=$noncaptor
+hdr_blacklist=$nonsensor
 hdr_whitelist=''
 
 usage() {
-	printf -- 'Usage: %s [-l] [-e <captor>] [-i <captor>] [-u <captor>]\n' "$(basename "$0")" >&2
-	printf -- '-e | --exclude      :   exclude captor, can be called multiple times\n' >&2
-	printf -- '-i | --include      :   include captor, can be called multiple times\n' >&2
-	printf -- '-l | --list-captors :   list all captors and exit\n' >&2
-	printf -- '-u | --unique       :   only include the specified captor\n' >&2
+	printf -- 'Usage: %s [-l] [-e <sensor>] [-i <sensor>] [-u <sensor>]\n' "$(basename "$0")" >&2
+	printf -- '-e | --exclude      :   exclude sensor, can be called multiple times\n' >&2
+	printf -- '-i | --include      :   include sensor, can be called multiple times\n' >&2
+	printf -- '-l | --list-sensors :   list all sensors and exit\n' >&2
+	printf -- '-u | --unique       :   only include the specified sensor\n' >&2
 	printf -- '                        if this option is used, any usage of `-e` or `-i` will be ignored\n' >&2
 	exit 1
 }
 
-ls_captors() {
+ls_sensors() {
 	try cd src
 
 	[ -z "$hdr_whitelist" ] && hdr_whitelist='.*'
@@ -51,49 +51,52 @@ ls_captors() {
 		sed 's/\.h$//'
 }
 
-# gen_captors_h(captors, nb_captors)
-gen_captors_h() {
-	captors=$1
-	nb_captors=$2
-	nb_captor_opts=$(
-		for captor in $captors; do
-			sed -n 's/.*'"${captor}"'_opt\[\([0-9]\+\)\].*/\1/p' "src/${captor}.h"
+# gen_sensors_h(sensor, nb_sensors)
+gen_sensors_h() {
+	sensors=$1
+	nb_sensors=$2
+	nb_sensor_opts=$(
+		for sensor in $sensors; do
+			sed -n 's/.*'"${sensor}"'_opt\[\([0-9]\+\)\].*/\1/p' "src/${sensor}.h"
 		done |
 			paste -s -d '+' |
 			bc
 	)
 
-	dprint captors >&2
-	dprint nb_captor_opts >&2
-	isnum "$nb_captor_opts" || die "could not get total number of captors's command-line options"
+	dprint sensors >&2
+	dprint nb_sensor_opts >&2
+	isnum "$nb_sensor_opts" || die "could not get total number of sensors's command-line options"
 
 	# gen includes
-	for captor in $captors; do
-		printf '#include "%s.h"\n' "$captor"
+	for sensor in $sensors; do
+		printf '#include "%s.h"\n' "$sensor"
 	done
-	printf '\n#define NB_CAPTOR %d\n\n' "$nb_captors"
-	printf '\n#define NB_CAPTOR_OPT %d\n\n' "$nb_captor_opts"
+	printf '\n'
+
+	printf '#define NB_SENSOR %d\n' "$nb_sensors"
+	printf '#define NB_SENSOR_OPT %d\n' "$nb_sensor_opts"
+	printf '\n'
 
-	# gen `init_captors()`
-	printf 'void init_captors(Optparse *longopts, Captor *captors, size_t len, size_t offset, int *nb_defined)\n{\n'
+	# gen `init_sensors()`
+	printf 'void init_sensors(Optparse *opts, Sensor *sensors, size_t len, size_t offset, int *nb_defined)\n{\n'
 	printf '    int opt_idx = offset;\n'
-	for captor in $captors; do
+	for sensor in $sensors; do
 		cat <<-!
-		    for (int i = 0; i < ${captor}.nb_opt; i++) {
-		        longopts[opt_idx++] = ${captor}_opt[i];
+		    for (int i = 0; i < ${sensor}.nb_opt; i++) {
+		        opts[opt_idx++] = ${sensor}_opt[i];
 		    }
-		    captors[(*nb_defined)++] = ${captor};
+		    sensors[(*nb_defined)++] = ${sensor};
 		!
 	done
 	printf '    assert((offset + *nb_defined) <= len);\n'
 	printf '}\n'
 }
 
-gen_captors_mk() {
-	captors=$1
+gen_sensors_mk() {
+	sensors=$1
 	printf 'CAPTOR_OBJ = '
-	for captor in $captors; do
-		printf '$(OBJ_DIR)/%s.o ' "$captor"
+	for sensor in $sensors; do
+		printf '$(OBJ_DIR)/%s.o ' "$sensor"
 	done
 	printf '\n'
 }
@@ -140,8 +143,8 @@ while [ "$1" ]; do
 		shift; [ "$1" ] || usage
 		hdr_blacklist="${hdr_blacklist}|${1}"
 		;;
-	--list-captors|-l)
-		ls_captors
+	--list-sensors|-l)
+		ls_sensors
 		exit 0
 		;;
 	--unique|-u)
@@ -155,20 +158,20 @@ while [ "$1" ]; do
 	shift
 done
 
-captors=$(ls_captors)
-nb_captors=$(echo "$captors" | sed '/^$/d' | wc -l)
+sensors=$(ls_sensors)
+nb_sensors=$(echo "$sensors" | sed '/^$/d' | wc -l)
 
-if [ "$nb_captors" -eq 0 ]; then
-	printf -- '0 captors are selected. cannot build.\n' >&2
+if [ "$nb_sensors" -eq 0 ]; then
+	printf -- '0 sensors are selected. cannot build.\n' >&2
 	exit 1
 fi
 
-try gen_captors_h "$captors" "$nb_captors" > "$target_hdr"
-try gen_captors_mk "$captors" > "$target_mk"
+try gen_sensors_h "$sensors" "$nb_sensors" > "$target_hdr"
+try gen_sensors_mk "$sensors" > "$target_mk"
 
 printf -- 'Run `make` to build `bin/mojitos`.\n' >&2
-printf -- 'The resulting binary will have the %d following captors:\n' "$nb_captors" >&2
-echo "$captors" >&2
+printf -- 'The resulting binary will have the %d following sensors:\n' "$nb_sensors" >&2
+echo "$sensors" >&2
 
 make clean >/dev/null
 
diff --git a/doc/counter_ex.h b/doc/counter_ex.h
index 5702adc..65fabf3 100644
--- a/doc/counter_ex.h
+++ b/doc/counter_ex.h
@@ -7,7 +7,7 @@ unsigned int get_acc(uint64_t *results, void *);
 void clean_acc(void *);
 void label_acc(char **labels, void *);
 
-Captor rapl = {
+Sensor rapl = {
     .init = init_acc,
     .get = get_acc,
     .clean = clean_acc,
diff --git a/doc/mojitos.1 b/doc/mojitos.pre.1
similarity index 69%
rename from doc/mojitos.1
rename to doc/mojitos.pre.1
index a7927e8..af9cb9b 100644
--- a/doc/mojitos.1
+++ b/doc/mojitos.pre.1
@@ -3,47 +3,18 @@
 .Os
 .Sh NAME
 .Nm mojitos
-.Nd An open source system, energy and network monitoring tool.
+.Nd An open source system monitoring tool.
 .Sh SYNOPSIS
 .Nm mojitos
-.Op Fl rsu
-.Op Fl t Ar time
-.Op Fl f Ar freq
-.Op Fl p Ar perf_list
-.Op Fl d Ar net_device
-.Op Fl o Ar logfile
+.Op Ar OPTIONS
+.Op Ar SENSOR ...
 .Op Fl e Ar cmd ...
-.Nm mojitos
-.Op Fl l
 .Sh DESCRIPTION
 .Nm
-enables monitoring the system, its energy comsumption and the network activity, at the OS level.
-It runs on GNU/Linux.
-.Pp
+is a monitoring tool with a multitude of sensors that does measurements at the OS level.
 .Nm
-supports the following options:
-.Bl -tag -width Ds
-.It Fl s
-Enable overhead statistics (in nanoseconds).
-.It Fl u
-Enable system-level load monitoring.
-.It Fl r
-Enable RAPL.
-.It Fl p Ar perf_list
-Enable performance counters.
-The argument is a coma separated list of performance counters.
-.It Fl d Ar net_device
-Enable network monitoring.
-.It Fl l
-List the available performance counters and quit.
-.It Fl t Ar time
-Set duration value (in seconds). If 0, then loops indefinitely.
-.It Fl f Ar freq
-Set amount of measurements per second.
-.It Fl e Ar cmd ...
-Execute a command with optional arguments.
-If this option is used, any usage of -t or -f is ignored.
-.El
+runs on GNU/Linux.
+USAGE
 .Sh EXIT STATUS
 .Ex
 .Sh EXAMPLES
diff --git a/src/info_reader.h b/lib/info_reader.h
similarity index 100%
rename from src/info_reader.h
rename to lib/info_reader.h
diff --git a/src/optparse.h b/lib/optparse.h
similarity index 99%
rename from src/optparse.h
rename to lib/optparse.h
index b1908d4..1925d73 100644
--- a/src/optparse.h
+++ b/lib/optparse.h
@@ -73,6 +73,7 @@ struct optparse_long {
     enum optparse_argtype argtype;
     char *usage_arg;
     char *usage_msg;
+    void *(*fn)(void *, size_t);
 };
 
 /**
diff --git a/makefile b/makefile
index 3f8a70b..d5d2d23 100644
--- a/makefile
+++ b/makefile
@@ -10,21 +10,21 @@ BIN = mojitos
 
 CAPTOR_OBJ =
 
-include ./captors.mk
+include ./sensors.mk
 
 OBJ =  \
 	$(CAPTOR_OBJ) \
 	$(OBJ_DIR)/util.o
 
 CC = gcc
-CPPFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Wno-unused-function
+CPPFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Wno-unused-function -I./lib
 CFLAGS = $(CPPFLAGS) -O3 -Werror
 LDFLAGS =
 
 ASTYLE = astyle --style=kr -xf -s4 -k3 -n -Z -Q
 
 
-all: $(BIN)
+all: $(BIN) readme man
 
 $(BIN): $(BIN_DIR) $(OBJ) $(OBJ_DIR)/$(BIN).o
 	$(CC) $(LDFLAGS) -o $(BIN_DIR)/$(BIN) $(OBJ) $(OBJ_DIR)/$(BIN).o
@@ -48,7 +48,7 @@ $(BIN_DIR):
 	mkdir -p $(BIN_DIR)
 
 debug: CFLAGS = $(CPPFLAGS) -DDEBUG -g -Og
-debug: all
+debug: $(BIN)
 
 tests:
 	gcc $(CPPFLAGS) $(TESTS_DIR)/main.c $(SRC_DIR)/util.c -o $(TESTS_DIR)/run
@@ -64,4 +64,12 @@ clean:
 	\rm -f $(SRC_DIR)/counters_option.h
 	\rm -f $(TESTS_DIR)/run
 
-.PHONY: all clean mojitos debug format tests
+readme: $(BIN)
+	sh ./tools/update-readme-usage.sh
+
+man: $(BIN)
+	awk -v "usage=$$($(BIN_DIR)/$(BIN) -1)" \
+		'/^USAGE/ { $$0=usage } 1' \
+		doc/mojitos.pre.1 > doc/mojitos.1 2>/dev/null
+
+.PHONY: all clean mojitos debug format tests readme man
diff --git a/src/amd_rapl.h b/src/amd_rapl.h
index 52a7c6c..1a16db8 100644
--- a/src/amd_rapl.h
+++ b/src/amd_rapl.h
@@ -23,7 +23,7 @@ unsigned int get_amd_rapl(uint64_t *results, void *);
 void clean_amd_rapl(void *);
 void label_amd_rapl(char **labels, void *);
 
-Captor amd_rapl = {
+Sensor amd_rapl = {
     .init = init_amd_rapl,
     .get = get_amd_rapl,
     .clean = clean_amd_rapl,
diff --git a/src/counters.c b/src/counters.c
index 874e6fc..d42ceae 100644
--- a/src/counters.c
+++ b/src/counters.c
@@ -44,11 +44,15 @@ typedef struct _counter_t *counter_t;
 
 #include "counters_option.h"
 
-void show_all_counters()
+void *show_all_counters(void *none1, size_t none2)
 {
     for (unsigned int i = 0; i < nb_counter_option; i++) {
         printf("%s\n", perf_static_info[i].name);
     }
+    UNUSED(none1);
+    UNUSED(none2);
+    exit(EXIT_SUCCESS);
+    return NULL;	/* not reached */
 }
 
 void perf_type_key(__u32 **perf_type, __u64 **perf_key, int *indexes, int nb)
diff --git a/src/counters.h b/src/counters.h
index a191e5a..0304a07 100644
--- a/src/counters.h
+++ b/src/counters.h
@@ -22,9 +22,9 @@ unsigned int init_counters(char *, void **);
 unsigned int get_counters(uint64_t *results, void *);
 void clean_counters(void *);
 void label_counters(char **labels, void *);
-void show_all_counters();
+void *show_all_counters(void *, size_t);
 
-Captor counters = {
+Sensor counters = {
     .init = init_counters,
     .get = get_counters,
     .clean = clean_counters,
@@ -47,7 +47,8 @@ Optparse counters_opt[2] = {
         .shortname = 'l',
         .argtype = OPTPARSE_NONE,
         .usage_arg = NULL,
-        .usage_msg = "list the possible performance counters and quit"
+        .usage_msg = "list the available performance counters and quit",
+        .fn = show_all_counters,
     },
 };
 
diff --git a/src/infiniband.h b/src/infiniband.h
index 285b2ba..fac05f8 100644
--- a/src/infiniband.h
+++ b/src/infiniband.h
@@ -21,7 +21,7 @@
 unsigned int init_infiniband(char *infi_path, void **ptr);
 void label_infiniband(char **labels, void *);
 
-Captor infiniband = {
+Sensor infiniband = {
     .init = init_infiniband,
     .get = NULL,
     .clean = NULL,
diff --git a/src/load.h b/src/load.h
index c7c5575..038b263 100644
--- a/src/load.h
+++ b/src/load.h
@@ -23,7 +23,7 @@ unsigned int get_load(uint64_t *results, void *);
 void clean_load(void *);
 void label_load(char **labels, void *);
 
-Captor load = {
+Sensor load = {
     .init = init_load,
     .get = get_load,
     .clean = clean_load,
diff --git a/src/mojitos.c b/src/mojitos.c
index 683bdfa..3ecf111 100644
--- a/src/mojitos.c
+++ b/src/mojitos.c
@@ -38,11 +38,11 @@ typedef unsigned int (*getter_t)(uint64_t *, void *);
 typedef void (*cleaner_t)(void *);
 
 typedef struct Opt Opt;
-typedef struct Captor Captor;
+typedef struct Sensor Sensor;
 /* optparse typedef */
 typedef struct optparse_long Optparse;
 
-struct Captor {
+struct Sensor {
     initializer_t init;
     getter_t get;
     cleaner_t clean;
@@ -50,41 +50,70 @@ struct Captor {
     int nb_opt;
 };
 
-int nb_defined_captors = 0;
+int nb_defined_sensors = 0;
 
-#include "captors.h"
+#include "sensors.h"
 
-Captor captors[NB_CAPTOR];
+Sensor sensors[NB_SENSOR];
 
 #define NB_OPT 5
-Optparse longopts[NB_OPT + NB_CAPTOR_OPT + 1] = {
+Optparse opts[NB_OPT + NB_SENSOR_OPT + 1] = {
     {
         .longname = "freq", .shortname = 'f', .argtype = OPTPARSE_REQUIRED,
         .usage_arg = "<freq>",
-        .usage_msg = "specify frequency",
+        .usage_msg = "set amount of measurements per second.",
     },
     {
         .longname = "time", .shortname = 't', .argtype = OPTPARSE_REQUIRED,
         .usage_arg = "<time>",
-        .usage_msg = "specify time",
+        .usage_msg = "set duration value (seconds). If 0, then loops infinitely.",
     },
     {
         .longname = "exec", .shortname = 'e', .argtype = OPTPARSE_REQUIRED,
-        .usage_arg = "<cmd>",
-        .usage_msg = "specify a command",
+        .usage_arg = "<cmd> ...",
+        .usage_msg = "Execute a command with optional arguments.\n"
+        "\tIf this option is used, any usage of -t or -f is ignored.",
     },
     {
         .longname = "logfile", .shortname = 'o', .argtype = OPTPARSE_REQUIRED,
         .usage_arg = "<file>",
-        .usage_msg = "specify a log file",
+        .usage_msg = "specify a log file.",
     },
     {
         .longname = "overhead-stats", .shortname = 's', .argtype = OPTPARSE_NONE,
         .usage_arg = NULL,
-        .usage_msg = "enable overhead statistics in nanoseconds",
+        .usage_msg = "enable overhead statistics (nanoseconds).",
     },
 };
 
+void dumpopt(Optparse *opt)
+{
+    printf(".It Fl %c | Fl \\-%s", opt->shortname, opt->longname);
+    if (opt->usage_arg != NULL) {
+        printf(" Ar %s", opt->usage_arg);
+    }
+    printf("\n");
+    printf("%s\n", opt->usage_msg);
+}
+
+void dumpopts(Optparse *opts, size_t nb_opt, size_t nb_sensor_opt)
+{
+    size_t i;
+
+    /* options */
+    printf(".Pp\nOPTIONS:\n.Bl -tag -width Ds\n");
+    for (i = 0; i < nb_opt; i++) {
+        dumpopt(&opts[i]);
+    }
+    printf(".El\n");
+
+    /* sensors */
+    printf(".Pp\nSENSORS:\n.Bl -tag -width Ds\n");
+    for (i++; i < nb_opt + nb_sensor_opt; i++) {
+        dumpopt(&opts[i]);
+    }
+    printf(".El\n");
+}
 
 void printopt(Optparse *opt)
 {
@@ -98,23 +127,21 @@ void printopt(Optparse *opt)
 
 void usage(char **argv)
 {
-    printf("Usage : %s [OPTIONS] [CAPTOR ...]\n", argv[0]);
+    printf("Usage : %s [OPTIONS] [SENSOR ...] [-e <cmd> ...]\n", argv[0]);
 
     printf("\nOPTIONS:\n");
     for (int i = 0; i < NB_OPT; i++) {
-        printopt(&longopts[i]);
+        printopt(&opts[i]);
     }
-    printf("if time==0 then loops infinitively\n"
-           "if -e is present, time and freq are not used\n");
 
-    if (nb_defined_captors == 0) {
+    if (nb_defined_sensors == 0) {
         // no captor to show
         exit(EXIT_FAILURE);
     }
 
-    printf("\nCAPTORS:\n");
-    for (int i = 0; i < NB_CAPTOR_OPT; i++) {
-        printopt(&longopts[NB_OPT + i]);
+    printf("\nSENSORS:\n");
+    for (int i = 0; i < NB_SENSOR_OPT; i++) {
+        printopt(&opts[NB_OPT + i]);
     }
 
     exit(EXIT_FAILURE);
@@ -149,7 +176,7 @@ unsigned int nb_sensors = 0;
 char **labels = NULL;
 uint64_t *values = NULL;
 
-void add_source(Captor *cpt, char *arg)
+void add_source(Sensor *cpt, char *arg)
 {
     nb_sources++;
     initializer_t init = cpt->init;
@@ -186,12 +213,17 @@ int main(int argc, char **argv)
     char **application = NULL;
     int stat_mode = -1;
 
-    init_captors(longopts, captors, NB_OPT + NB_CAPTOR_OPT, NB_OPT, &nb_defined_captors);
+    init_sensors(opts, sensors, NB_OPT + NB_SENSOR_OPT, NB_OPT, &nb_defined_sensors);
 
     if (argc == 1) {
         usage(argv);
     }
 
+    if (argc == 2 && argv[1][0] == '-' && argv[1][1] == '1' && argv[1][2] == '\0') {
+        dumpopts(opts, NB_OPT, NB_SENSOR_OPT);
+        exit(EXIT_SUCCESS);
+    }
+
     output = stdout;
 
     atexit(flushexit);
@@ -202,7 +234,7 @@ int main(int argc, char **argv)
     options.permute = 0;
 
     optparse_init(&options, argv);
-    while ((opt = optparse_long(&options, longopts, NULL)) != -1 && application == NULL) {
+    while ((opt = optparse_long(&options, opts, NULL)) != -1 && application == NULL) {
         switch (opt) {
         case 'f':
             frequency = atoi(options.optarg);
@@ -218,9 +250,6 @@ int main(int argc, char **argv)
         case 's':
             stat_mode = 0;
             break;
-        case 'l':
-            show_all_counters();
-            exit(EXIT_SUCCESS);
         case 'o':
             if ((output = fopen(options.optarg, "wb")) == NULL) {
                 perror("fopen");
@@ -234,11 +263,15 @@ int main(int argc, char **argv)
         default: {
             int ismatch = 0;
             int opt_idx = NB_OPT;
-            for (int i = 0; i < nb_defined_captors && !ismatch; i++) {
-                for (int j = 0; j < captors[i].nb_opt; j++) {
-                    if (opt == longopts[opt_idx].shortname) {
+            for (int i = 0; i < nb_defined_sensors && !ismatch; i++) {
+                for (int j = 0; j < sensors[i].nb_opt; j++) {
+                    if (opt == opts[opt_idx].shortname) {
                         ismatch = 1;
-                        add_source(&captors[i], options.optarg);
+                        if (opts[opt_idx].fn != NULL) {
+                            (void) opts[opt_idx].fn(NULL, 0);
+                        } else {
+                            add_source(&sensors[i], options.optarg);
+                        }
                         break;
                     }
                     opt_idx++;
diff --git a/src/network.h b/src/network.h
index 82fcfc3..994651a 100644
--- a/src/network.h
+++ b/src/network.h
@@ -23,7 +23,7 @@ unsigned int get_network(uint64_t *results, void *);
 void clean_network(void *);
 void label_network(char **labels, void *);
 
-Captor network = {
+Sensor network = {
     .init = init_network,
     .get = get_network,
     .clean = clean_network,
diff --git a/src/rapl.h b/src/rapl.h
index 95f9fd4..a02624d 100644
--- a/src/rapl.h
+++ b/src/rapl.h
@@ -23,7 +23,7 @@ unsigned int get_rapl(uint64_t *results, void *);
 void clean_rapl(void *);
 void label_rapl(char **labels, void *);
 
-Captor rapl = {
+Sensor rapl = {
     .init = init_rapl,
     .get = get_rapl,
     .clean = clean_rapl,
diff --git a/src/temperature.h b/src/temperature.h
index ec2faef..8609dba 100644
--- a/src/temperature.h
+++ b/src/temperature.h
@@ -23,7 +23,7 @@ unsigned int get_temperature(uint64_t *results, void *);
 void clean_temperature(void *);
 void label_temperature(char **labels, void *);
 
-Captor temperature = {
+Sensor temperature = {
     .init = init_temperature,
     .get = get_temperature,
     .clean = clean_temperature,
diff --git a/tools/update-readme-usage.sh b/tools/update-readme-usage.sh
new file mode 100755
index 0000000..b9f16de
--- /dev/null
+++ b/tools/update-readme-usage.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+die() { yell "$*"; exit 111; }
+try() { "$@" || die "cannot $*"; }
+yell() { echo "$0: $*" >&2; }
+echo() { printf '%s\n' "$*"; }
+
+usage=$(./bin/mojitos)
+[ -n "$usage" ] || die 'empty usage. try to recompile mojitos.'
+
+try awk -v "usage=$usage" '
+	/^Usage/ {
+		print usage
+		del = 1
+	}
+	{
+		if (del == 1) {
+			if (match($0, "^```")) {
+				del = 0
+				print $0
+			}
+		} else {
+			print $0
+		}
+	}
+' README.md > README.tmp
+try mv README.tmp README.md
-- 
GitLab