From 01936218a441986666f4e0fcfb4ae8d22f7be891 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 14 Mar 2020 20:30:02 -0400 Subject: [PATCH 01/16] Update usage message --- x5/khatus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/x5/khatus.c b/x5/khatus.c index ea63fa1..b835ad8 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -133,6 +133,7 @@ print_usage() " DATA_TTL = int (* (positive) number of seconds *)\n" " OPTION = -i INTERVAL\n" " | -s SEPARATOR\n" + " | -x (* Output to X root window *)\n" " SEPARATOR = string\n" " INTERVAL = int (* (positive) number of seconds *)\n" "\n", -- 2.20.1 From b6316e94783d975f109c9901e4061ba041f0cb3f Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 14 Mar 2020 21:14:30 -0400 Subject: [PATCH 02/16] Implement log levels --- x5/khatus.c | 81 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index b835ad8..37cbccc 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -15,9 +15,9 @@ #include "bsdtimespec.h" -#define debug(args...) {fprintf(stderr, "[debug] " args); fflush(stderr);} -#define info( args...) {fprintf(stderr, "[info] " args); fflush(stderr);} -#define error(args...) {fprintf(stderr, "[error] " args); fflush(stderr);} +#define debug(args...) if (cfg->log_level >= Debug) {fprintf(stderr, "[debug] " args); fflush(stderr);} +#define info( args...) if (cfg->log_level >= Info ) {fprintf(stderr, "[info] " args); fflush(stderr);} +#define error(args...) if (cfg->log_level >= Error) {fprintf(stderr, "[error] " args); fflush(stderr);} #define fatal(args...) {fprintf(stderr, "[fatal] " args); exit(EXIT_FAILURE);} #define usage(args...) {print_usage(); fatal("[usage] " args);} @@ -28,6 +28,13 @@ static const int errlen = sizeof(ERRMSG) - 1; char *argv0; +typedef enum LogLevel { + Nothing, + Error, + Info, + Debug +} LogLevel; + /* TODO: Convert fifo list to fifo array. */ typedef struct Fifo Fifo; struct Fifo { @@ -48,6 +55,7 @@ struct Config { int fifo_count; int total_width; int output_to_x_root_window; + LogLevel log_level; } defaults = { .interval = 1, .separator = "|", @@ -55,12 +63,13 @@ struct Config { .fifo_count = 0, .total_width = 0, .output_to_x_root_window = 0, + .log_level = Info, }; void -fifo_print_one(Fifo *f) +fifo_print_one(Fifo *f, Config *cfg) { - debug( + info( "Fifo " "{" " name = %s," @@ -82,31 +91,33 @@ fifo_print_one(Fifo *f) } void -fifo_print_all(Fifo *head) +fifo_print_all(Fifo *head, Config *cfg) { for (Fifo *f = head; f; f = f->next) { - fifo_print_one(f); + fifo_print_one(f, cfg); } } void -config_print(Config *c) +config_print(Config *cfg) { - debug( + info( "Config " "{" " interval = %d," " separator = %s," " fifo_count = %d," " total_width = %d," + " log_level = %d," " fifos = ..." " }\n", - c->interval, - c->separator, - c->fifo_count, - c->total_width + cfg->interval, + cfg->separator, + cfg->fifo_count, + cfg->total_width, + cfg->log_level ); - fifo_print_all(c->fifos); + fifo_print_all(cfg->fifos, cfg); } int @@ -134,10 +145,14 @@ print_usage() " OPTION = -i INTERVAL\n" " | -s SEPARATOR\n" " | -x (* Output to X root window *)\n" + " | -l LOG_LEVEL\n" " SEPARATOR = string\n" " INTERVAL = int (* (positive) number of seconds *)\n" + " LOG_LEVEL = int (* %d through %d *)\n" "\n", - argv0 + argv0, + Nothing, + Debug ); fprintf( stderr, @@ -178,6 +193,30 @@ parse_opts_opt_s(Config *cfg, int argc, char *argv[], int i) } } +void +parse_opts_opt_l(Config *cfg, int argc, char *argv[], int i) +{ + int log_level; + + if (i < argc) { + char *param = argv[i++]; + + if (is_pos_num(param)) { + log_level = atoi(param); + if (log_level <= Debug) { + cfg->log_level = log_level; + opts_parse_any(cfg, argc, argv, i); + } else { + usage("Option -l value (%d) exceeds maximum (%d)\n", log_level, Debug); + } + } else { + usage("Option -l parameter is invalid: \"%s\"\n", param); + } + } else { + usage("Option -l parameter is missing.\n"); + } +} + void parse_opts_opt(Config *cfg, int argc, char *argv[], int i) { @@ -194,6 +233,10 @@ parse_opts_opt(Config *cfg, int argc, char *argv[], int i) cfg->output_to_x_root_window = 1; opts_parse_any(cfg, argc, argv, ++i); break; + case 'l': + /* TODO: Generic set_int */ + parse_opts_opt_l(cfg, argc, argv, ++i); + break; default : usage("Option \"%s\" is invalid\n", argv[i]); } @@ -278,7 +321,7 @@ fifo_read_error(Fifo *f, char *buf) } void -fifo_read_one(Fifo *f, char *buf) +fifo_read_one(Fifo *f, char *buf, Config *cfg) { ssize_t current; ssize_t total; @@ -345,13 +388,13 @@ fifo_read_all(Config *cfg, char *buf) for (Fifo *f = cfg->fifos; f; f = f->next) { if (FD_ISSET(f->fd, &fds)) { debug("reading: %s\n", f->name); - fifo_read_one(f, buf); + fifo_read_one(f, buf, cfg); } } } void -snooze(struct timespec *t) +snooze(struct timespec *t, Config *cfg) { struct timespec remainder; int result; @@ -474,7 +517,7 @@ main(int argc, char *argv[]) */ timespecsub(&ti, &td, &tc); debug("snooze YES\n"); - snooze(&tc); + snooze(&tc, cfg); } else debug("snooze NO\n"); } -- 2.20.1 From 64bb32bdd2a5cf0624b34036cfca7d8006f7537f Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 14 Mar 2020 21:26:55 -0400 Subject: [PATCH 03/16] Update README --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ca1fcf1..4fa29a2 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ Experiments The approaches experimented-with so far (later versions do not _necessarily_ obsolete earlier ones, they're just different): -| Name | Status | Language | Tested-on | Description | -|--------|-----------|-----------|--------------|-------------| -| __x1__ | Archived | Bash, AWK | Ubuntu 16.04 | Single, synchronous script, saving state in text files | -| __x2__ | In-use | Bash, AWK | Debian 10 | Parallel processes: collectors, cache and reporters; passing messages over pipes | -| __x3__ | Scratched | OCaml | Debian 10 | Re-write and refinement of __x2__ | -| __x4__ | Prototype | Dash, AWK | Debian 10 | Sensors are completely decoupled daemons, cache is a file tree | -| __x5__ | In-dev | C | Debian 10 | Re-implementation of __x4__ in C | +| Name | Status | Language | Tested-on | Description | +|--------|-----------|-----------|-------------------------|-------------| +| __x1__ | Archived | Bash, AWK | Ubuntu 16.04 | Single, synchronous script, saving state in text files | +| __x2__ | In-use | Bash, AWK | Debian 10, Ubuntu 18.04 | Parallel processes: collectors, cache and reporters; passing messages through a single named pipe | +| __x3__ | Scratched | OCaml | Debian 10 | Re-write and refinement of __x2__ | +| __x4__ | Prototype | Dash, AWK | Debian 10 | Sensors are completely decoupled daemons, cache is a file tree | +| __x5__ | In-dev | C | Ubuntu 18.04 | Sensors are completely decoupled daemons, writing to dedicated named pipes, bar repeatedly `select`s and reads the pipes. | -- 2.20.1 From dbdf0f7b374e9fdde3804fc11f25f5f60ccb5c88 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 14 Mar 2020 21:39:22 -0400 Subject: [PATCH 04/16] Revise status nomenclature --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4fa29a2..6b87dad 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ Experiments The approaches experimented-with so far (later versions do not _necessarily_ obsolete earlier ones, they're just different): -| Name | Status | Language | Tested-on | Description | -|--------|-----------|-----------|-------------------------|-------------| -| __x1__ | Archived | Bash, AWK | Ubuntu 16.04 | Single, synchronous script, saving state in text files | -| __x2__ | In-use | Bash, AWK | Debian 10, Ubuntu 18.04 | Parallel processes: collectors, cache and reporters; passing messages through a single named pipe | -| __x3__ | Scratched | OCaml | Debian 10 | Re-write and refinement of __x2__ | -| __x4__ | Prototype | Dash, AWK | Debian 10 | Sensors are completely decoupled daemons, cache is a file tree | -| __x5__ | In-dev | C | Ubuntu 18.04 | Sensors are completely decoupled daemons, writing to dedicated named pipes, bar repeatedly `select`s and reads the pipes. | +| Name | Status | Language | Tested-on | Description | +|--------|---------------------|-----------|-------------------------|-------------| +| __x1__ | Archive, complete | Bash, AWK | Ubuntu 16.04 | Single, synchronous script, saving state in text files | +| __x2__ | Legacy , complete | Bash, AWK | Debian 10, Ubuntu 18.04 | Parallel processes: collectors, cache and reporters; passing messages through a single named pipe | +| __x3__ | Archive, incomplete | OCaml | Debian 10 | Re-write and refinement of __x2__ | +| __x4__ | Archive, incomplete | Dash, AWK | Debian 10 | Sensors are completely decoupled daemons, cache is a file tree | +| __x5__ | Current, incomplete | C | Ubuntu 18.04 | Sensors are completely decoupled daemons, writing to dedicated named pipes, bar repeatedly `select`s and reads the pipes. | -- 2.20.1 From 4c438cef6b69db82d2835d2c32d41fae12c93016 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 14 Mar 2020 22:07:59 -0400 Subject: [PATCH 05/16] Invert nesting of error checking which reduces nesting levels. --- x5/khatus.c | 53 +++++++++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index 37cbccc..3d81cad 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -167,54 +167,43 @@ void opts_parse_any(Config *, int, char *[], int); /* For mutually-recursive ca void parse_opts_opt_i(Config *cfg, int argc, char *argv[], int i) { - if (i < argc) { - char *param = argv[i++]; + char *param; - if (is_pos_num(param)) { - cfg->interval = atoi(param); - opts_parse_any(cfg, argc, argv, i); - } else { - usage("Option -i parameter is invalid: \"%s\"\n", param); - } - } else { + if (i >= argc) usage("Option -i parameter is missing.\n"); - } + param = argv[i++]; + if (!is_pos_num(param)) + usage("Option -i parameter is invalid: \"%s\"\n", param); + cfg->interval = atoi(param); + opts_parse_any(cfg, argc, argv, i); } void parse_opts_opt_s(Config *cfg, int argc, char *argv[], int i) { - if (i < argc) { - cfg->separator = calloc((strlen(argv[i]) + 1), sizeof(char)); - strcpy(cfg->separator, argv[i]); - opts_parse_any(cfg, argc, argv, ++i); - } else { + if (i >= argc) usage("Option -s parameter is missing.\n"); - } + cfg->separator = calloc((strlen(argv[i]) + 1), sizeof(char)); + strcpy(cfg->separator, argv[i]); + opts_parse_any(cfg, argc, argv, ++i); } void parse_opts_opt_l(Config *cfg, int argc, char *argv[], int i) { + char *param; int log_level; - if (i < argc) { - char *param = argv[i++]; - - if (is_pos_num(param)) { - log_level = atoi(param); - if (log_level <= Debug) { - cfg->log_level = log_level; - opts_parse_any(cfg, argc, argv, i); - } else { - usage("Option -l value (%d) exceeds maximum (%d)\n", log_level, Debug); - } - } else { - usage("Option -l parameter is invalid: \"%s\"\n", param); - } - } else { + if (i >= argc) usage("Option -l parameter is missing.\n"); - } + param = argv[i++]; + if (!is_pos_num(param)) + usage("Option -l parameter is invalid: \"%s\"\n", param); + log_level = atoi(param); + if (log_level > Debug) + usage("Option -l value (%d) exceeds maximum (%d)\n", log_level, Debug); + cfg->log_level = log_level; + opts_parse_any(cfg, argc, argv, i); } void -- 2.20.1 From ce552549378d618f5915f06217626fcdc2b1fc8c Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 14 Mar 2020 22:19:47 -0400 Subject: [PATCH 06/16] Reduce switch case nesting --- x5/khatus.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index 3d81cad..d95390a 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -210,24 +210,24 @@ void parse_opts_opt(Config *cfg, int argc, char *argv[], int i) { switch (argv[i][1]) { - case 'i': - /* TODO: Generic set_int */ - parse_opts_opt_i(cfg, argc, argv, ++i); - break; - case 's': - /* TODO: Generic set_str */ - parse_opts_opt_s(cfg, argc, argv, ++i); - break; - case 'x': - cfg->output_to_x_root_window = 1; - opts_parse_any(cfg, argc, argv, ++i); - break; - case 'l': - /* TODO: Generic set_int */ - parse_opts_opt_l(cfg, argc, argv, ++i); - break; - default : - usage("Option \"%s\" is invalid\n", argv[i]); + case 'i': + /* TODO: Generic set_int */ + parse_opts_opt_i(cfg, argc, argv, ++i); + break; + case 's': + /* TODO: Generic set_str */ + parse_opts_opt_s(cfg, argc, argv, ++i); + break; + case 'x': + cfg->output_to_x_root_window = 1; + opts_parse_any(cfg, argc, argv, ++i); + break; + case 'l': + /* TODO: Generic set_int */ + parse_opts_opt_l(cfg, argc, argv, ++i); + break; + default : + usage("Option \"%s\" is invalid\n", argv[i]); } } @@ -269,11 +269,11 @@ opts_parse_any(Config *cfg, int argc, char *argv[], int i) { if (i < argc) { switch (argv[i][0]) { - case '-': - parse_opts_opt(cfg, argc, argv, i); - break; - default : - parse_opts_spec(cfg, argc, argv, i); + case '-': + parse_opts_opt(cfg, argc, argv, i); + break; + default : + parse_opts_spec(cfg, argc, argv, i); } } } -- 2.20.1 From a6b13fa2d61136a971b2ebbf6eadb943002fa9d5 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sun, 15 Mar 2020 01:50:43 -0400 Subject: [PATCH 07/16] Fix second level indent - should be four spaces --- x5/khatus.c | 115 ++++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index d95390a..ee96d60 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -69,24 +69,23 @@ struct Config { void fifo_print_one(Fifo *f, Config *cfg) { - info( - "Fifo " - "{" - " name = %s," - " fd = %d," - " width = %d," - " last_read = %d," - " ttl = %d," - " pos = %d," - " next = %p," - " }\n", - f->name, - f->fd, - f->width, - f->last_read, - f->ttl, - f->pos, - f->next + info("Fifo " + "{" + " name = %s," + " fd = %d," + " width = %d," + " last_read = %d," + " ttl = %d," + " pos = %d," + " next = %p," + " }\n", + f->name, + f->fd, + f->width, + f->last_read, + f->ttl, + f->pos, + f->next ); } @@ -102,20 +101,20 @@ void config_print(Config *cfg) { info( - "Config " - "{" - " interval = %d," - " separator = %s," - " fifo_count = %d," - " total_width = %d," - " log_level = %d," - " fifos = ..." - " }\n", - cfg->interval, - cfg->separator, - cfg->fifo_count, - cfg->total_width, - cfg->log_level + "Config " + "{" + " interval = %d," + " separator = %s," + " fifo_count = %d," + " total_width = %d," + " log_level = %d," + " fifos = ..." + " }\n", + cfg->interval, + cfg->separator, + cfg->fifo_count, + cfg->total_width, + cfg->log_level ); fifo_print_all(cfg->fifos, cfg); } @@ -134,31 +133,31 @@ print_usage() { assert(argv0); fprintf( - stderr, - "\n" - "Usage: %s [OPTION ...] SPEC [SPEC ...]\n" - "\n" - " SPEC = FILE_PATH DATA_WIDTH DATA_TTL\n" - " FILE_PATH = string\n" - " DATA_WIDTH = int (* (positive) number of characters *)\n" - " DATA_TTL = int (* (positive) number of seconds *)\n" - " OPTION = -i INTERVAL\n" - " | -s SEPARATOR\n" - " | -x (* Output to X root window *)\n" - " | -l LOG_LEVEL\n" - " SEPARATOR = string\n" - " INTERVAL = int (* (positive) number of seconds *)\n" - " LOG_LEVEL = int (* %d through %d *)\n" - "\n", - argv0, - Nothing, - Debug + stderr, + "\n" + "Usage: %s [OPTION ...] SPEC [SPEC ...]\n" + "\n" + " SPEC = FILE_PATH DATA_WIDTH DATA_TTL\n" + " FILE_PATH = string\n" + " DATA_WIDTH = int (* (positive) number of characters *)\n" + " DATA_TTL = int (* (positive) number of seconds *)\n" + " OPTION = -i INTERVAL\n" + " | -s SEPARATOR\n" + " | -x (* Output to X root window *)\n" + " | -l LOG_LEVEL\n" + " SEPARATOR = string\n" + " INTERVAL = int (* (positive) number of seconds *)\n" + " LOG_LEVEL = int (* %d through %d *)\n" + "\n", + argv0, + Nothing, + Debug ); fprintf( - stderr, - "Example: %s -i 1 /dev/shm/khatus/khatus_sensor_x 4 10\n" - "\n", - argv0 + stderr, + "Example: %s -i 1 /dev/shm/khatus/khatus_sensor_x 4 10\n" + "\n", + argv0 ); } @@ -393,9 +392,9 @@ snooze(struct timespec *t, Config *cfg) if (result < 0) { if (errno == EINTR) { info( - "nanosleep interrupted. Remainder: " - "{ tv_sec = %ld, tv_nsec = %ld }", - remainder.tv_sec, remainder.tv_nsec); + "nanosleep interrupted. Remainder: " + "{ tv_sec = %ld, tv_nsec = %ld }", + remainder.tv_sec, remainder.tv_nsec); /* No big deal if we occasionally sleep less, * so not attempting to correct after an interruption. */ -- 2.20.1 From 574a4bff980c2e56c603c81e8c2773e42b4baf71 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sun, 15 Mar 2020 02:26:12 -0400 Subject: [PATCH 08/16] Use braces in elses which follow multi-statement ifs --- x5/khatus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index ee96d60..db800ea 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -325,9 +325,10 @@ fifo_read_one(Fifo *f, char *buf, Config *cfg) if (current == -1) { error("Failed to read: \"%s\". Error: %s\n", f->name, strerror(errno)); fifo_read_error(f, buf); - } else + } else { while (total++ < f->width) *b++ = ' '; + } /* TODO Record timestamp read */ close(f->fd); f->fd = -1; @@ -506,8 +507,9 @@ main(int argc, char *argv[]) timespecsub(&ti, &td, &tc); debug("snooze YES\n"); snooze(&tc, cfg); - } else + } else { debug("snooze NO\n"); + } } return EXIT_SUCCESS; -- 2.20.1 From 7911aa98ea23b71ca4249621bcf861d9f6ca34f4 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 16 Mar 2020 14:42:07 -0400 Subject: [PATCH 09/16] Add warn log level --- x5/khatus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x5/khatus.c b/x5/khatus.c index db800ea..bb76507 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -17,6 +17,7 @@ #define debug(args...) if (cfg->log_level >= Debug) {fprintf(stderr, "[debug] " args); fflush(stderr);} #define info( args...) if (cfg->log_level >= Info ) {fprintf(stderr, "[info] " args); fflush(stderr);} +#define warn( args...) if (cfg->log_level >= Warn ) {fprintf(stderr, "[warn] " args); fflush(stderr);} #define error(args...) if (cfg->log_level >= Error) {fprintf(stderr, "[error] " args); fflush(stderr);} #define fatal(args...) {fprintf(stderr, "[fatal] " args); exit(EXIT_FAILURE);} #define usage(args...) {print_usage(); fatal("[usage] " args);} @@ -31,6 +32,7 @@ char *argv0; typedef enum LogLevel { Nothing, Error, + Warn, Info, Debug } LogLevel; @@ -392,7 +394,7 @@ snooze(struct timespec *t, Config *cfg) if (result < 0) { if (errno == EINTR) { - info( + warn( "nanosleep interrupted. Remainder: " "{ tv_sec = %ld, tv_nsec = %ld }", remainder.tv_sec, remainder.tv_nsec); -- 2.20.1 From 61e033f5d4e3e6080b194cc3a0ede0ae40976464 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 16 Mar 2020 15:55:45 -0400 Subject: [PATCH 10/16] Use __VA_ARGS__ instead of named param --- x5/khatus.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index bb76507..16c9a56 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -15,12 +15,12 @@ #include "bsdtimespec.h" -#define debug(args...) if (cfg->log_level >= Debug) {fprintf(stderr, "[debug] " args); fflush(stderr);} -#define info( args...) if (cfg->log_level >= Info ) {fprintf(stderr, "[info] " args); fflush(stderr);} -#define warn( args...) if (cfg->log_level >= Warn ) {fprintf(stderr, "[warn] " args); fflush(stderr);} -#define error(args...) if (cfg->log_level >= Error) {fprintf(stderr, "[error] " args); fflush(stderr);} -#define fatal(args...) {fprintf(stderr, "[fatal] " args); exit(EXIT_FAILURE);} -#define usage(args...) {print_usage(); fatal("[usage] " args);} +#define debug(...) if (cfg->log_level >= Debug) {fprintf(stderr, "[debug] " __VA_ARGS__); fflush(stderr);} +#define info(...) if (cfg->log_level >= Info ) {fprintf(stderr, "[info] " __VA_ARGS__); fflush(stderr);} +#define warn(...) if (cfg->log_level >= Warn ) {fprintf(stderr, "[warn] " __VA_ARGS__); fflush(stderr);} +#define error(...) if (cfg->log_level >= Error) {fprintf(stderr, "[error] " __VA_ARGS__); fflush(stderr);} +#define fatal(...) {fprintf(stderr, "[fatal] " __VA_ARGS__); exit(EXIT_FAILURE);} +#define usage(...) {print_usage(); fatal("[usage] " __VA_ARGS__);} #define ERRMSG "ERROR" -- 2.20.1 From 4dc09422dcd8b69ad8095bf664a7346291eb95b8 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 16 Mar 2020 16:25:47 -0400 Subject: [PATCH 11/16] Build as C99 --- x5/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x5/Makefile b/x5/Makefile index 59d115b..585ca12 100644 --- a/x5/Makefile +++ b/x5/Makefile @@ -1,5 +1,6 @@ -CFLAGS := -Wall -Wextra -LDLIBS := -lX11 +CPPFLAGS := -D_POSIX_C_SOURCE=200809L +CFLAGS := -std=c99 -Wall -Wextra +LDLIBS := -lX11 .PHONY: build clean rebuild -- 2.20.1 From 17a27e4866eb3e245e17dc211b4469f1c5aa3f1e Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 16 Mar 2020 18:45:26 -0400 Subject: [PATCH 12/16] Break-out logging and time-related functions into lib modules --- x5/Makefile | 12 +++++++-- x5/khatus.c | 63 +++++++++----------------------------------- x5/khatus_lib_log.c | 17 ++++++++++++ x5/khatus_lib_log.h | 17 ++++++++++++ x5/khatus_lib_time.c | 31 ++++++++++++++++++++++ x5/khatus_lib_time.h | 1 + 6 files changed, 88 insertions(+), 53 deletions(-) create mode 100644 x5/khatus_lib_log.c create mode 100644 x5/khatus_lib_log.h create mode 100644 x5/khatus_lib_time.c create mode 100644 x5/khatus_lib_time.h diff --git a/x5/Makefile b/x5/Makefile index 585ca12..1a356f5 100644 --- a/x5/Makefile +++ b/x5/Makefile @@ -4,10 +4,18 @@ LDLIBS := -lX11 .PHONY: build clean rebuild -build: khatus +build: \ + khatus + +khatus: \ + khatus_lib_log.o \ + khatus_lib_time.o + +khatus_lib_time.o: khatus_lib_log.o clean: - @ find . -type f -executable -delete + @find . -type f -executable -delete + @find . -type f -name '*.o' -delete rebuild: @$(MAKE) -s clean diff --git a/x5/khatus.c b/x5/khatus.c index 16c9a56..e0b71cd 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -14,14 +14,10 @@ #include #include "bsdtimespec.h" +#include "khatus_lib_log.h" +#include "khatus_lib_time.h" -#define debug(...) if (cfg->log_level >= Debug) {fprintf(stderr, "[debug] " __VA_ARGS__); fflush(stderr);} -#define info(...) if (cfg->log_level >= Info ) {fprintf(stderr, "[info] " __VA_ARGS__); fflush(stderr);} -#define warn(...) if (cfg->log_level >= Warn ) {fprintf(stderr, "[warn] " __VA_ARGS__); fflush(stderr);} -#define error(...) if (cfg->log_level >= Error) {fprintf(stderr, "[error] " __VA_ARGS__); fflush(stderr);} -#define fatal(...) {fprintf(stderr, "[fatal] " __VA_ARGS__); exit(EXIT_FAILURE);} -#define usage(...) {print_usage(); fatal("[usage] " __VA_ARGS__);} - +#define usage(...) {print_usage(); fprintf(stderr, "Error:\n " __VA_ARGS__); exit(EXIT_FAILURE);} #define ERRMSG "ERROR" static const char errmsg[] = ERRMSG; @@ -29,14 +25,6 @@ static const int errlen = sizeof(ERRMSG) - 1; char *argv0; -typedef enum LogLevel { - Nothing, - Error, - Warn, - Info, - Debug -} LogLevel; - /* TODO: Convert fifo list to fifo array. */ typedef struct Fifo Fifo; struct Fifo { @@ -57,7 +45,6 @@ struct Config { int fifo_count; int total_width; int output_to_x_root_window; - LogLevel log_level; } defaults = { .interval = 1, .separator = "|", @@ -65,11 +52,10 @@ struct Config { .fifo_count = 0, .total_width = 0, .output_to_x_root_window = 0, - .log_level = Info, }; void -fifo_print_one(Fifo *f, Config *cfg) +fifo_print_one(Fifo *f) { info("Fifo " "{" @@ -92,10 +78,10 @@ fifo_print_one(Fifo *f, Config *cfg) } void -fifo_print_all(Fifo *head, Config *cfg) +fifo_print_all(Fifo *head) { for (Fifo *f = head; f; f = f->next) { - fifo_print_one(f, cfg); + fifo_print_one(f); } } @@ -109,16 +95,14 @@ config_print(Config *cfg) " separator = %s," " fifo_count = %d," " total_width = %d," - " log_level = %d," " fifos = ..." " }\n", cfg->interval, cfg->separator, cfg->fifo_count, - cfg->total_width, - cfg->log_level + cfg->total_width ); - fifo_print_all(cfg->fifos, cfg); + fifo_print_all(cfg->fifos); } int @@ -203,7 +187,7 @@ parse_opts_opt_l(Config *cfg, int argc, char *argv[], int i) log_level = atoi(param); if (log_level > Debug) usage("Option -l value (%d) exceeds maximum (%d)\n", log_level, Debug); - cfg->log_level = log_level; + _khatus_lib_log_level = log_level; opts_parse_any(cfg, argc, argv, i); } @@ -311,7 +295,7 @@ fifo_read_error(Fifo *f, char *buf) } void -fifo_read_one(Fifo *f, char *buf, Config *cfg) +fifo_read_one(Fifo *f, char *buf) { ssize_t current; ssize_t total; @@ -379,30 +363,7 @@ fifo_read_all(Config *cfg, char *buf) for (Fifo *f = cfg->fifos; f; f = f->next) { if (FD_ISSET(f->fd, &fds)) { debug("reading: %s\n", f->name); - fifo_read_one(f, buf, cfg); - } - } -} - -void -snooze(struct timespec *t, Config *cfg) -{ - struct timespec remainder; - int result; - - result = nanosleep(t, &remainder); - - if (result < 0) { - if (errno == EINTR) { - warn( - "nanosleep interrupted. Remainder: " - "{ tv_sec = %ld, tv_nsec = %ld }", - remainder.tv_sec, remainder.tv_nsec); - /* No big deal if we occasionally sleep less, - * so not attempting to correct after an interruption. - */ - } else { - fatal("nanosleep: %s\n", strerror(errno)); + fifo_read_one(f, buf); } } } @@ -508,7 +469,7 @@ main(int argc, char *argv[]) */ timespecsub(&ti, &td, &tc); debug("snooze YES\n"); - snooze(&tc, cfg); + snooze(&tc); } else { debug("snooze NO\n"); } diff --git a/x5/khatus_lib_log.c b/x5/khatus_lib_log.c new file mode 100644 index 0000000..16a5509 --- /dev/null +++ b/x5/khatus_lib_log.c @@ -0,0 +1,17 @@ +#include +#include +#include + +#include "khatus_lib_log.h" + +LogLevel _khatus_lib_log_level = Debug; + +void +_fatal(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} diff --git a/x5/khatus_lib_log.h b/x5/khatus_lib_log.h new file mode 100644 index 0000000..ca93ddd --- /dev/null +++ b/x5/khatus_lib_log.h @@ -0,0 +1,17 @@ +#define debug(...) if (_khatus_lib_log_level >= Debug) {fprintf(stderr, "[debug] " __VA_ARGS__); fflush(stderr);} +#define info(...) if (_khatus_lib_log_level >= Info ) {fprintf(stderr, "[info] " __VA_ARGS__); fflush(stderr);} +#define warn(...) if (_khatus_lib_log_level >= Warn ) {fprintf(stderr, "[warn] " __VA_ARGS__); fflush(stderr);} +#define error(...) if (_khatus_lib_log_level >= Error) {fprintf(stderr, "[error] " __VA_ARGS__); fflush(stderr);} +#define fatal(...) _fatal("[fatal] " __VA_ARGS__) + +typedef enum LogLevel { + Nothing, + Error, + Warn, + Info, + Debug +} LogLevel; + +void _fatal(char *, ...); + +LogLevel _khatus_lib_log_level; diff --git a/x5/khatus_lib_time.c b/x5/khatus_lib_time.c new file mode 100644 index 0000000..ba74226 --- /dev/null +++ b/x5/khatus_lib_time.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include "khatus_lib_log.h" +#include "khatus_lib_time.h" + +void +snooze(struct timespec *t) +{ + struct timespec remainder; + int result; + + result = nanosleep(t, &remainder); + + if (result < 0) { + if (errno == EINTR) { + warn( + "nanosleep interrupted. Remainder: " + "{ tv_sec = %ld, tv_nsec = %ld }", + remainder.tv_sec, remainder.tv_nsec); + /* No big deal if we occasionally sleep less, + * so not attempting to correct after an interruption. + */ + } else { + fatal("nanosleep: %s\n", strerror(errno)); + } + } +} diff --git a/x5/khatus_lib_time.h b/x5/khatus_lib_time.h new file mode 100644 index 0000000..2d16d65 --- /dev/null +++ b/x5/khatus_lib_time.h @@ -0,0 +1 @@ +void snooze(struct timespec *); -- 2.20.1 From 8345f2b388e0986829ceeae50ecf186d5d540a9c Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 16 Mar 2020 18:48:38 -0400 Subject: [PATCH 13/16] Implement time sensor --- x5/.gitignore | 1 + x5/Makefile | 7 ++++- x5/khatus_lib_time.c | 14 +++++++++ x5/khatus_lib_time.h | 2 ++ x5/khatus_sensor_time.c | 65 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 x5/khatus_sensor_time.c diff --git a/x5/.gitignore b/x5/.gitignore index fa71cac..09901ba 100644 --- a/x5/.gitignore +++ b/x5/.gitignore @@ -1,2 +1,3 @@ *.o khatus +khatus_sensor_time diff --git a/x5/Makefile b/x5/Makefile index 1a356f5..c6a0576 100644 --- a/x5/Makefile +++ b/x5/Makefile @@ -5,12 +5,17 @@ LDLIBS := -lX11 .PHONY: build clean rebuild build: \ - khatus + khatus \ + khatus_sensor_time khatus: \ khatus_lib_log.o \ khatus_lib_time.o +khatus_sensor_time: \ + khatus_lib_log.o \ + khatus_lib_time.o + khatus_lib_time.o: khatus_lib_log.o clean: diff --git a/x5/khatus_lib_time.c b/x5/khatus_lib_time.c index ba74226..a169471 100644 --- a/x5/khatus_lib_time.c +++ b/x5/khatus_lib_time.c @@ -7,6 +7,20 @@ #include "khatus_lib_log.h" #include "khatus_lib_time.h" +struct timespec +timespec_of_float(double n) +{ + double integral; + double fractional; + struct timespec t; + + fractional = modf(n, &integral); + t.tv_sec = (int) integral; + t.tv_nsec = (int) (1E9 * fractional); + + return t; +} + void snooze(struct timespec *t) { diff --git a/x5/khatus_lib_time.h b/x5/khatus_lib_time.h index 2d16d65..1d4bb44 100644 --- a/x5/khatus_lib_time.h +++ b/x5/khatus_lib_time.h @@ -1 +1,3 @@ +struct timespec timespec_of_float(double); + void snooze(struct timespec *); diff --git a/x5/khatus_sensor_time.c b/x5/khatus_sensor_time.c new file mode 100644 index 0000000..f156f45 --- /dev/null +++ b/x5/khatus_sensor_time.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "khatus_lib_log.h" +#include "khatus_lib_time.h" + +char *argv0; + +void +usage() +{ + printf( + "%s: [OPT ...]\n" + "\n" + "OPT = -i int # interval\n" + " | -f string # format string\n" + " | -h # help message (i.e. what you're reading now :) )\n", + argv0); + fatal("usage\n"); +} + +int +main(int argc, char **argv) +{ + argv0 = argv[0]; + + double opt_interval = 1.0; + char *opt_fmt = "%a %b %d %H:%M:%S"; + + time_t t; + struct timespec ti; + char buf[128]; + char c; + + memset(buf, '\0', 128); + while ((c = getopt(argc, argv, "f:i:h")) != -1) + switch (c) { + case 'f': + opt_fmt = calloc(strlen(optarg), sizeof(char)); + strcpy(opt_fmt, optarg); + break; + case 'i': + opt_interval = atof(optarg); + break; + case 'h': + usage(); + break; + default: + usage(); + } + ti = timespec_of_float(opt_interval); + for (;;) { + t = time(NULL); + strftime(buf, sizeof(buf), opt_fmt, localtime(&t)); + puts(buf); + fflush(stdout); + snooze(&ti); + } + return EXIT_SUCCESS; +} -- 2.20.1 From 348d5f367c12e60de79ac4647417aa7184996d06 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Mon, 16 Mar 2020 19:07:16 -0400 Subject: [PATCH 14/16] Support sub-second intervals --- x5/khatus.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index e0b71cd..b6f66f7 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -39,14 +39,14 @@ struct Fifo { typedef struct Config Config; struct Config { - int interval; + double interval; char * separator; Fifo * fifos; int fifo_count; int total_width; int output_to_x_root_window; } defaults = { - .interval = 1, + .interval = 1.0, .separator = "|", .fifos = NULL, .fifo_count = 0, @@ -91,7 +91,7 @@ config_print(Config *cfg) info( "Config " "{" - " interval = %d," + " interval = %f," " separator = %s," " fifo_count = %d," " total_width = %d," @@ -114,6 +114,22 @@ is_pos_num(char *s) return 1; } +int +is_decimal(char *s) +{ + char c; + int seen = 0; + + while ((c = *(s++)) != '\0') + if (!isdigit(c)) { + if (c == '.' && !seen++) + continue; + else + return 0; + } + return 1; +} + void print_usage() { @@ -157,9 +173,9 @@ parse_opts_opt_i(Config *cfg, int argc, char *argv[], int i) if (i >= argc) usage("Option -i parameter is missing.\n"); param = argv[i++]; - if (!is_pos_num(param)) + if (!is_decimal(param)) usage("Option -i parameter is invalid: \"%s\"\n", param); - cfg->interval = atoi(param); + cfg->interval = atof(param); opts_parse_any(cfg, argc, argv, i); } @@ -394,9 +410,7 @@ main(int argc, char *argv[]) debug("argv0 = %s\n", argv0); config_print(cfg); - /* TODO: Support interval < 1. i.e. implement timespec_of_float */ - ti.tv_sec = cfg->interval; - ti.tv_nsec = 0; + ti = timespec_of_float(cfg->interval); if (cfg->fifos == NULL) usage("No fifo specs were given!\n"); -- 2.20.1 From c7262f37a3abbd4931eefb8cd2c9f9408b76750c Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 21 Mar 2020 16:54:16 -0400 Subject: [PATCH 15/16] Fix fatality trigger --- x5/khatus_lib_log.c | 10 ---------- x5/khatus_lib_log.h | 4 +--- x5/khatus_lib_time.c | 1 + 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/x5/khatus_lib_log.c b/x5/khatus_lib_log.c index 16a5509..ce172e4 100644 --- a/x5/khatus_lib_log.c +++ b/x5/khatus_lib_log.c @@ -5,13 +5,3 @@ #include "khatus_lib_log.h" LogLevel _khatus_lib_log_level = Debug; - -void -_fatal(char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} diff --git a/x5/khatus_lib_log.h b/x5/khatus_lib_log.h index ca93ddd..f2cf46b 100644 --- a/x5/khatus_lib_log.h +++ b/x5/khatus_lib_log.h @@ -2,7 +2,7 @@ #define info(...) if (_khatus_lib_log_level >= Info ) {fprintf(stderr, "[info] " __VA_ARGS__); fflush(stderr);} #define warn(...) if (_khatus_lib_log_level >= Warn ) {fprintf(stderr, "[warn] " __VA_ARGS__); fflush(stderr);} #define error(...) if (_khatus_lib_log_level >= Error) {fprintf(stderr, "[error] " __VA_ARGS__); fflush(stderr);} -#define fatal(...) _fatal("[fatal] " __VA_ARGS__) +#define fatal(...) {fprintf(stderr, "[fatal] " __VA_ARGS__); exit(EXIT_FAILURE);} typedef enum LogLevel { Nothing, @@ -12,6 +12,4 @@ typedef enum LogLevel { Debug } LogLevel; -void _fatal(char *, ...); - LogLevel _khatus_lib_log_level; diff --git a/x5/khatus_lib_time.c b/x5/khatus_lib_time.c index a169471..d13f689 100644 --- a/x5/khatus_lib_time.c +++ b/x5/khatus_lib_time.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include -- 2.20.1 From efa97b71295ad84d9660c392100369f99d533fa7 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sat, 21 Mar 2020 16:56:13 -0400 Subject: [PATCH 16/16] Handle fifo read errors and ends of messages --- x5/khatus.c | 110 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/x5/khatus.c b/x5/khatus.c index b6f66f7..93550a9 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -33,7 +33,9 @@ struct Fifo { int width; int last_read; int ttl; - int pos; /* Position on the output buffer. */ + int pos_init; /* Initial position on the output buffer. */ + int pos_curr; /* Current position on the output buffer. */ + int pos_final; /* Final position on the output buffer. */ Fifo *next; }; @@ -54,6 +56,13 @@ struct Config { .output_to_x_root_window = 0, }; +enum read_status { + FAIL_FINAL = -2, + FAIL_TMP = -1, + END_OF_FILE = 0, + END_OF_MESSAGE = 1 +}; + void fifo_print_one(Fifo *f) { @@ -64,7 +73,9 @@ fifo_print_one(Fifo *f) " width = %d," " last_read = %d," " ttl = %d," - " pos = %d," + " pos_init = %d," + " pos_curr = %d," + " pos_final = %d," " next = %p," " }\n", f->name, @@ -72,7 +83,9 @@ fifo_print_one(Fifo *f) f->width, f->last_read, f->ttl, - f->pos, + f->pos_init, + f->pos_curr, + f->pos_final, f->next ); } @@ -253,7 +266,9 @@ parse_opts_spec(Config *cfg, int argc, char *argv[], int i) f->width = atoi(w); f->ttl = atoi(t); f->last_read = 0; - f->pos = cfg->total_width; + f->pos_init = cfg->total_width; + f->pos_curr = f->pos_init; + f->pos_final = f->pos_init + f->width - 1; f->next = cfg->fifos; cfg->fifos = f; @@ -300,7 +315,7 @@ fifo_read_error(Fifo *f, char *buf) char *b; int i; - b = buf + f->pos; + b = buf + f->pos_init; /* Copy as much of the error message as possible. * EXCLUDING the reminating \0. */ for (i = 0; i < errlen && i < f->width; i++) @@ -310,30 +325,48 @@ fifo_read_error(Fifo *f, char *buf) b[i] = '_'; } -void +enum read_status fifo_read_one(Fifo *f, char *buf) { - ssize_t current; - ssize_t total; - char *b; - char c; + /* Initialize all to an impossible value: */ + ssize_t n = -5; /* Number of bytes read. */ + char c = -1; /* Character read. */ + int r = -1; /* Remaining unused slots in buffer range. */ - current = 0; - total = 0; - c = '\0'; - b = buf + f->pos; - while ((current = read(f->fd, &c, 1)) && c != '\n' && c != '\0' && total++ < f->width) - *b++ = c; - if (current == -1) { - error("Failed to read: \"%s\". Error: %s\n", f->name, strerror(errno)); - fifo_read_error(f, buf); - } else { - while (total++ < f->width) - *b++ = ' '; + for (;;) { + n = read(f->fd, &c, 1); + assert(n >= -1 && n <= 1); + switch (n) { + case -1: + error("Failed to read: \"%s\". errno: %d, msg: %s\n", + f->name, errno, strerror(errno)); + if (errno == 11) + return FAIL_TMP; + else + return FAIL_FINAL; + case 0: + debug("%s: End of FILE\n", f->name); + f->pos_curr = f->pos_init; + return END_OF_FILE; + case 1: + /* TODO: Consider making msg term char a CLI option */ + if (c == '\n' || c == '\0') { + r = f->pos_final - f->pos_curr; + if (r > 0) + memset(buf + f->pos_curr, ' ', r); + f->pos_curr = f->pos_init; + return END_OF_MESSAGE; + } else { + if (f->pos_curr <= f->pos_final) + buf[f->pos_curr++] = c; + /* Drop beyond available range. */ + } + break; + default: + assert(0); + } } /* TODO Record timestamp read */ - close(f->fd); - f->fd = -1; } void @@ -357,15 +390,19 @@ fifo_read_all(Config *cfg, char *buf) fifo_read_error(f, buf); continue; } - debug("opening: %s\n", f->name); - if (f->fd < 0) + if (f->fd < 0) { + debug("%s: closed. opening. fd: %d\n", f->name, f->fd); f->fd = open(f->name, O_RDONLY | O_NONBLOCK); + } else { + debug("%s: already openned. fd: %d\n", f->name, f->fd); + } if (f->fd == -1) { /* TODO: Consider backing off retries for failed fifos. */ error("Failed to open \"%s\"\n", f->name); fifo_read_error(f, buf); continue; } + debug("%s: open. fd: %d\n", f->name, f->fd); if (f->fd > maxfd) maxfd = f->fd; FD_SET(f->fd, &fds); @@ -379,7 +416,18 @@ fifo_read_all(Config *cfg, char *buf) for (Fifo *f = cfg->fifos; f; f = f->next) { if (FD_ISSET(f->fd, &fds)) { debug("reading: %s\n", f->name); - fifo_read_one(f, buf); + switch (fifo_read_one(f, buf)) { + case END_OF_FILE: + case FAIL_FINAL: + close(f->fd); + f->fd = -1; + break; + case END_OF_MESSAGE: + case FAIL_TMP: + break; + default: + assert(0); + } } } } @@ -436,7 +484,9 @@ main(int argc, char *argv[]) /* 2nd pass to make space for separators */ for (Fifo *f = cfg->fifos; f; f = f->next) { - f->pos += prefix; + f->pos_init += prefix; + f->pos_final += prefix; + f->pos_curr = f->pos_init; prefix += seplen; nfifos++; } @@ -448,9 +498,9 @@ main(int argc, char *argv[]) buf[width] = '\0'; /* 3rd pass to set the separators */ for (Fifo *f = cfg->fifos; f; f = f->next) { - if (f->pos) { /* Skip the first, left-most */ + if (f->pos_init) { /* Skip the first, left-most */ /* Copying only seplen ensures we omit the '\0' byte. */ - strncpy(buf + (f->pos - seplen), cfg->separator, seplen); + strncpy(buf + (f->pos_init - seplen), cfg->separator, seplen); } } -- 2.20.1