From 4e8dbd84925d36f1193a7339a542677d884d3ba1 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Tue, 6 Dec 2016 19:40:36 +0100 Subject: [PATCH] ptp4l: Accept any configuration option as a command line argument. This patch provides a way to use the entire table of configuration options as "long" command line switches. Signed-off-by: Richard Cochran --- config.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- config.h | 11 ++++++++++ ptp4l.c | 11 ++++++++-- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/config.c b/config.c index 5da5ecc..384b437 100644 --- a/config.c +++ b/config.c @@ -329,6 +329,7 @@ static enum parser_result parse_section_line(char *s, enum config_section *secti } static enum parser_result parse_item(struct config *cfg, + int commandline, const char *section, const char *option, const char *value) @@ -387,7 +388,7 @@ static enum parser_result parse_item(struct config *cfg, return NOT_PARSED; } } - } else if (cgi->flags & CFG_ITEM_LOCKED) { + } else if (!commandline && cgi->flags & CFG_ITEM_LOCKED) { /* This global option was set on the command line. */ return PARSED_OK; } else { @@ -415,6 +416,10 @@ static enum parser_result parse_item(struct config *cfg, dst->flags |= CFG_ITEM_DYNSTR; break; } + + if (commandline) { + dst->flags &= CFG_ITEM_LOCKED; + } return PARSED_OK; } @@ -490,6 +495,25 @@ static void check_deprecated_options(const char **option) } } +static struct option *config_alloc_longopts(struct config *cfg) +{ + struct config_item *ci; + struct option *opts; + int i; + + opts = calloc(1, (1 + N_CONFIG_ITEMS) * sizeof(*opts)); + if (!opts) { + return NULL; + } + for (i = 0; i < N_CONFIG_ITEMS; i++) { + ci = &config_tab[i]; + opts[i].name = ci->label; + opts[i].has_arg = required_argument; + } + + return opts; +} + int config_read(char *name, struct config *cfg) { enum config_section current_section = UNKNOWN_SECTION; @@ -554,7 +578,7 @@ int config_read(char *name, struct config *cfg) check_deprecated_options(&option); - parser_res = parse_item(cfg, current_section == GLOBAL_SECTION ? + parser_res = parse_item(cfg, 0, current_section == GLOBAL_SECTION ? NULL : current_port->name, option, value); switch (parser_res) { @@ -627,8 +651,15 @@ struct config *config_create(void) } STAILQ_INIT(&cfg->interfaces); + cfg->opts = config_alloc_longopts(cfg); + if (!cfg->opts) { + free(cfg); + return NULL; + } + cfg->htab = hash_create(); if (!cfg->htab) { + free(cfg->opts); free(cfg); return NULL; } @@ -657,6 +688,7 @@ struct config *config_create(void) return cfg; fail: hash_destroy(cfg->htab, NULL); + free(cfg->opts); free(cfg); return NULL; } @@ -670,6 +702,7 @@ void config_destroy(struct config *cfg) free(iface); } hash_destroy(cfg->htab, config_item_free); + free(cfg->opts); free(cfg); } @@ -720,6 +753,33 @@ char *config_get_string(struct config *cfg, const char *section, return ci->val.s; } +int config_parse_option(struct config *cfg, const char *opt, const char *val) +{ + enum parser_result result; + + result = parse_item(cfg, 1, NULL, opt, val); + + switch (result) { + case PARSED_OK: + return 0; + case NOT_PARSED: + fprintf(stderr, "unknown option %s\n", opt); + break; + case BAD_VALUE: + fprintf(stderr, "%s is a bad value for option %s\n", val, opt); + break; + case MALFORMED: + fprintf(stderr, "%s is a malformed value for option %s\n", + val, opt); + break; + case OUT_OF_RANGE: + fprintf(stderr, "%s is an out of range value for option %s\n", + val, opt); + break; + } + return -1; +} + int config_set_double(struct config *cfg, const char *option, double val) { struct config_item *ci = config_find_item(cfg, NULL, option); diff --git a/config.h b/config.h index b02bde6..1cc7051 100644 --- a/config.h +++ b/config.h @@ -20,6 +20,7 @@ #ifndef HAVE_CONFIG_H #define HAVE_CONFIG_H +#include #include #include "ds.h" @@ -43,6 +44,9 @@ struct config { STAILQ_HEAD(interfaces_head, interface) interfaces; int n_interfaces; + /* for parsing command line options */ + struct option *opts; + /* hash of all non-legacy items */ struct hash *htab; }; @@ -64,6 +68,13 @@ int config_get_int(struct config *cfg, const char *section, char *config_get_string(struct config *cfg, const char *section, const char *option); +static inline struct option *config_long_options(struct config *cfg) +{ + return cfg->opts; +} + +int config_parse_option(struct config *cfg, const char *opt, const char *val); + int config_set_double(struct config *cfg, const char *option, double val); int config_set_section_int(struct config *cfg, const char *section, diff --git a/ptp4l.c b/ptp4l.c index a87e7e6..e90fcb2 100644 --- a/ptp4l.c +++ b/ptp4l.c @@ -73,8 +73,9 @@ static void usage(char *progname) int main(int argc, char *argv[]) { char *config = NULL, *req_phc = NULL, *progname; - int c, err = -1, print_level; + int c, err = -1, index, print_level; struct clock *clock = NULL; + struct option *opts; struct config *cfg; if (handle_term_signals()) @@ -84,12 +85,18 @@ int main(int argc, char *argv[]) if (!cfg) { return -1; } + opts = config_long_options(cfg); /* Process the command line arguments. */ progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, "AEP246HSLf:i:p:sl:mqvh"))) { + while (EOF != (c = getopt_long(argc, argv, "AEP246HSLf:i:p:sl:mqvh", + opts, &index))) { switch (c) { + case 0: + if (config_parse_option(cfg, opts[index].name, optarg)) + goto out; + break; case 'A': if (config_set_int(cfg, "delay_mechanism", DM_AUTO)) goto out;