diff --git a/ChangeLog.txt b/ChangeLog.txt index 3fdd40d2..d71d242e 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -27,6 +27,9 @@ Client library: callback. Closes #2127. - Add support for MQTT v5 broker to client topic aliases. +Clients: +- Add `-o` option for all clients loading options from a specific file. + 2.0.9 - 2021-03-xx ================== diff --git a/client/args.txt b/client/args.txt index edf88af7..d4093317 100644 --- a/client/args.txt +++ b/client/args.txt @@ -27,7 +27,7 @@ m - PUB,RR (message input) N - RR,SUB (no end of line) n - PUB,RR (null message) O -o - CTRL (options file) +o - CTRL,PUB,RR,SUB (options file) P - PUB,RR,SUB (password) p - PUB,RR,SUB (port) Q diff --git a/client/client_shared.c b/client/client_shared.c index 26755b7b..491dd701 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -265,8 +265,32 @@ void client_config_cleanup(struct mosq_config *cfg) mosquitto_property_free_all(&cfg->unsubscribe_props); mosquitto_property_free_all(&cfg->disconnect_props); mosquitto_property_free_all(&cfg->will_props); + free(cfg->options_file); } +/* Find if there is "-o" in the options */ +static int client_config_options_file(struct mosq_config *cfg, int argc, char *argv[]) +{ + int i; + + for(i=1; ioptions_file){ + fprintf(stderr, "Error: Duplicate -o argument given.\n\n"); + return 1; + } + if(i==argc-1){ + fprintf(stderr, "Error: -o argument given but no options file specified.\n\n"); + return 1; + }else{ + cfg->options_file = strdup(argv[i+1]); + } + } + } + return 0; +} + + int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) { int rc; @@ -286,94 +310,104 @@ int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char * init_config(cfg, pub_or_sub); + if(client_config_options_file(cfg, argc, argv)){ + return 1; + } + + if(cfg->options_file == NULL){ /* Default config file */ #ifndef WIN32 - env = getenv("XDG_CONFIG_HOME"); - if(env){ - len = strlen(env) + strlen("/mosquitto_pub") + 1; - loc = malloc(len); - if(!loc){ - err_printf(cfg, "Error: Out of memory.\n"); - return 1; - } - if(pub_or_sub == CLIENT_PUB){ - snprintf(loc, len, "%s/mosquitto_pub", env); - }else if(pub_or_sub == CLIENT_SUB){ - snprintf(loc, len, "%s/mosquitto_sub", env); - }else{ - snprintf(loc, len, "%s/mosquitto_rr", env); - } - loc[len-1] = '\0'; - }else{ - env = getenv("HOME"); + env = getenv("XDG_CONFIG_HOME"); if(env){ - len = strlen(env) + strlen("/.config/mosquitto_pub") + 1; + len = strlen(env) + strlen("/mosquitto_pub") + 1; loc = malloc(len); if(!loc){ err_printf(cfg, "Error: Out of memory.\n"); return 1; } if(pub_or_sub == CLIENT_PUB){ - snprintf(loc, len, "%s/.config/mosquitto_pub", env); + snprintf(loc, len, "%s/mosquitto_pub", env); }else if(pub_or_sub == CLIENT_SUB){ - snprintf(loc, len, "%s/.config/mosquitto_sub", env); + snprintf(loc, len, "%s/mosquitto_sub", env); }else{ - snprintf(loc, len, "%s/.config/mosquitto_rr", env); + snprintf(loc, len, "%s/mosquitto_rr", env); } loc[len-1] = '\0'; + }else{ + env = getenv("HOME"); + if(env){ + len = strlen(env) + strlen("/.config/mosquitto_pub") + 1; + loc = malloc(len); + if(!loc){ + err_printf(cfg, "Error: Out of memory.\n"); + return 1; + } + if(pub_or_sub == CLIENT_PUB){ + snprintf(loc, len, "%s/.config/mosquitto_pub", env); + }else if(pub_or_sub == CLIENT_SUB){ + snprintf(loc, len, "%s/.config/mosquitto_sub", env); + }else{ + snprintf(loc, len, "%s/.config/mosquitto_rr", env); + } + loc[len-1] = '\0'; + } } - } #else - rc = GetEnvironmentVariable("USERPROFILE", env, 1024); - if(rc > 0 && rc < 1024){ - len = strlen(env) + strlen("\\mosquitto_pub.conf") + 1; - loc = malloc(len); - if(!loc){ - err_printf(cfg, "Error: Out of memory.\n"); - return 1; - } - if(pub_or_sub == CLIENT_PUB){ - snprintf(loc, len, "%s\\mosquitto_pub.conf", env); - }else if(pub_or_sub == CLIENT_SUB){ - snprintf(loc, len, "%s\\mosquitto_sub.conf", env); - }else{ - snprintf(loc, len, "%s\\mosquitto_rr.conf", env); - } + rc = GetEnvironmentVariable("USERPROFILE", env, 1024); + if(rc > 0 && rc < 1024){ + len = strlen(env) + strlen("\\mosquitto_pub.conf") + 1; + loc = malloc(len); + if(!loc){ + err_printf(cfg, "Error: Out of memory.\n"); + return 1; + } + if(pub_or_sub == CLIENT_PUB){ + snprintf(loc, len, "%s\\mosquitto_pub.conf", env); + }else if(pub_or_sub == CLIENT_SUB){ + snprintf(loc, len, "%s\\mosquitto_sub.conf", env); + }else{ + snprintf(loc, len, "%s\\mosquitto_rr.conf", env); + } loc[len-1] = '\0'; - } + } #endif + } - if(loc){ + if(cfg->options_file){ + fptr = fopen(cfg->options_file, "rt"); + }else if(loc){ fptr = fopen(loc, "rt"); - if(fptr){ - while(fgets(line, 1024, fptr)){ - if(line[0] == '#') continue; /* Comments */ - - while(line[strlen(line)-1] == 10 || line[strlen(line)-1] == 13){ - line[strlen(line)-1] = 0; + free(loc); + }else{ + return 1; + } + if(fptr){ + while(fgets(line, 1024, fptr)){ + if(line[0] == '#') continue; /* Comments */ + + while(line[strlen(line)-1] == 10 || line[strlen(line)-1] == 13){ + line[strlen(line)-1] = 0; + } + /* All offset by one "args" here, because real argc/argv has + * program name as the first entry. */ + args[1] = strtok(line, " "); + if(args[1]){ + args[2] = strtok(NULL, ""); + if(args[2]){ + count = 3; + }else{ + count = 2; } - /* All offset by one "args" here, because real argc/argv has - * program name as the first entry. */ - args[1] = strtok(line, " "); - if(args[1]){ - args[2] = strtok(NULL, ""); - if(args[2]){ - count = 3; - }else{ - count = 2; - } - rc = client_config_line_proc(cfg, pub_or_sub, count, args); - if(rc){ - fclose(fptr); - free(loc); - return rc; - } + rc = client_config_line_proc(cfg, pub_or_sub, count, args); + if(rc){ + fclose(fptr); + free(loc); + return rc; } } - fclose(fptr); } - free(loc); + fclose(fptr); } /* Deal with real argc/argv */ @@ -519,6 +553,7 @@ int cfg_add_topic(struct mosq_config *cfg, int type, char *topic, const char *ar return 0; } + /* Process a tokenised single line from a file or set of real argc/argv */ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) { @@ -841,6 +876,14 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c goto unknown_option; } cfg->eol = false; + }else if(!strcmp(argv[i], "-o")){ + if(i==argc-1){ + fprintf(stderr, "Error: -o argument given but no options file specified.\n\n"); + return 1; + }else{ + /* Already handled */ + } + i++; }else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){ if(i==argc-1){ fprintf(stderr, "Error: -p argument given but no port specified.\n\n"); diff --git a/client/client_shared.h b/client/client_shared.h index 156c7f68..9babc4a0 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -126,6 +126,7 @@ struct mosq_config { bool have_topic_alias; /* pub */ char *response_topic; /* rr */ bool tcp_nodelay; + char *options_file; }; int client_config_load(struct mosq_config *config, int pub_or_sub, int argc, char *argv[]); diff --git a/client/pub_client.c b/client/pub_client.c index 8049de6e..a6b1a626 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -430,6 +430,7 @@ void print_usage(void) #endif printf(" [--property command identifier value]\n"); printf(" [-D command identifier value]\n"); + printf(" [-o options-file]\n"); printf(" mosquitto_pub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); @@ -452,6 +453,8 @@ void print_usage(void) printf(" -m : message payload to send.\n"); printf(" -M : the maximum inflight messages for QoS 1/2..\n"); printf(" -n : send a null (zero length) message.\n"); + printf(" -o : provide options in a file rather than on the command line.\n"); + printf(" See the Options section of https://mosquitto.org/man/mosquitto_pub-1.html\n"); printf(" -p : network port to connect to. Defaults to 1883 for plain MQTT and 8883 for MQTT over TLS.\n"); printf(" -P : provide a password\n"); printf(" -q : quality of service level to use for all messages. Defaults to 0.\n"); diff --git a/client/rr_client.c b/client/rr_client.c index 2331a4ed..4e8ab49e 100644 --- a/client/rr_client.c +++ b/client/rr_client.c @@ -224,6 +224,7 @@ void print_usage(void) printf(" [--proxy socks-url]\n"); #endif printf(" [-D command identifier value]\n"); + printf(" [-o options-file]\n"); printf(" mosquitto_rr --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); @@ -242,6 +243,8 @@ void print_usage(void) printf(" -L : specify user, password, hostname, port and topic as a URL in the form:\n"); printf(" mqtt(s)://[username[:password]@]host[:port]/topic\n"); printf(" -N : do not add an end of line character when printing the payload.\n"); + printf(" -o : provide options in a file rather than on the command line.\n"); + printf(" See the Options section of https://mosquitto.org/man/mosquitto_pub-1.html\n"); printf(" -p : network port to connect to. Defaults to 1883 for plain MQTT and 8883 for MQTT over TLS.\n"); printf(" -P : provide a password\n"); printf(" -q : quality of service level to use for communications. Defaults to 0.\n"); diff --git a/client/sub_client.c b/client/sub_client.c index e2cebcdc..e0ea5274 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -230,6 +230,7 @@ void print_usage(void) printf(" [--proxy socks-url]\n"); #endif printf(" [-D command identifier value]\n"); + printf(" [-o options-file]\n"); printf(" mosquitto_sub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); @@ -251,6 +252,8 @@ void print_usage(void) printf(" -L : specify user, password, hostname, port and topic as a URL in the form:\n"); printf(" mqtt(s)://[username[:password]@]host[:port]/topic\n"); printf(" -N : do not add an end of line character when printing the payload.\n"); + printf(" -o : provide options in a file rather than on the command line.\n"); + printf(" See the Options section of https://mosquitto.org/man/mosquitto_pub-1.html\n"); printf(" -p : network port to connect to. Defaults to 1883 for plain MQTT and 8883 for MQTT over TLS.\n"); printf(" -P : provide a password\n"); printf(" -q : quality of service level to use for the subscription. Defaults to 0.\n"); diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index adb2e2f0..7c33736f 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -117,18 +117,41 @@ Options - The options below may be given on the command line, but may also - be placed in a config file located at + + There are three ways to provide options to mosquitto_pub: the + default config file, a specified config file, or options on + the command line. + + + The default config file is located at or - with one pair of - - per line. The values in the config file will be used as defaults - and can be overridden by using the command line. The exceptions to - this are the message type options, of which only one can be - specified. Note also that currently some options cannot be negated, - e.g. . Config file lines that have a + on POSIX systems, or + on Windows. + + + A config file can be specified on the command line using + . + If the option is used, the default config + file will not be loaded. + + + In both cases, the contents of the config file should consist of + options, one per line in the format: + . If + options are also specified on the command line, those + options will override the same options set in the config + file. The exceptions to this are the message type options, of which + only one can be specified. Note also that currently some options + cannot be negated, e.g. . Config file lines that have a as the first character are treated as comments - and not processed any further. + and not processed any further. + + + It is suggested that config files are primarily used for + authentication purposes. Use of a config file allows you to + authenticate without the need to show the username and password + on the command line. + diff --git a/man/mosquitto_rr.1.xml b/man/mosquitto_rr.1.xml index 27309532..1355f54f 100644 --- a/man/mosquitto_rr.1.xml +++ b/man/mosquitto_rr.1.xml @@ -128,18 +128,41 @@ Options - The options below may be given on the command line, but may also - be placed in a config file located at + + There are three ways to provide options to mosquitto_rr: the + default config file, a specified config file, or options on + the command line. + + + The default config file is located at or - with one pair of - - per line. The values in the config file will be used as defaults - and can be overridden by using the command line. The exceptions to - this is , which if given in the config file will - not be overridden. Note also that currently some options cannot be - negated, e.g. . Config file lines that have a + on POSIX systems, or + on Windows. + + + A config file can be specified on the command line using + . + If the option is used, the default config + file will not be loaded. + + + In both cases, the contents of the config file should consist of + options, one per line in the format: + . If + options are also specified on the command line, those + options will override the same options set in the config + file. The exceptions to this are the message type options, of which + only one can be specified. Note also that currently some options + cannot be negated, e.g. . Config file lines that have a as the first character are treated as comments - and not processed any further. + and not processed any further. + + + It is suggested that config files are primarily used for + authentication purposes. Use of a config file allows you to + authenticate without the need to show the username and password + on the command line. + diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 58b9187b..982f5628 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -129,19 +129,41 @@ Options - The options below may be given on the command line, but may also - be placed in a config file located at + + There are three ways to provide options to mosquitto_sub: the + default config file, a specified config file, or options on + the command line. + + + The default config file is located at or - with one pair of - - per line. The values in the config file will be used as defaults - and can be overridden by using the command line. The exceptions to - this are and , which if - given in the config file will not be overridden. Note also that - currently some options cannot be negated, e.g. - . Config file lines that have a + on POSIX systems, or + on Windows. + + + A config file can be specified on the command line using + . + If the option is used, the default config + file will not be loaded. + + + In both cases, the contents of the config file should consist of + options, one per line in the format: + . If + options are also specified on the command line, those + options will override the same options set in the config + file. The exceptions to this are the message type options, of which + only one can be specified. Note also that currently some options + cannot be negated, e.g. . Config file lines that have a as the first character are treated as comments - and not processed any further. + and not processed any further. + + + It is suggested that config files are primarily used for + authentication purposes. Use of a config file allows you to + authenticate without the need to show the username and password + on the command line. +