From: Simon Nagl Date: Mon, 9 May 2016 22:27:50 +0000 (+0200) Subject: Command line: Follow IEEE Std 1003.1, 2013 Edition X-Git-Tag: v1.3.0~188^2~5 X-Git-Url: https://arthur.barton.de/gitweb/?p=netdata.git;a=commitdiff_plain;h=a48fb7d4951c2541e713da4b9272db02f1a57abc Command line: Follow IEEE Std 1003.1, 2013 Edition Standardize command line options: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html Make command line options maintainable: - Use getopts for parsing. - Define options in a list of structs. - Compute optstring and help message from the struct. Changed command line options are marked deprecated. We can remove them in the next major release. --- diff --git a/netdata-installer.sh b/netdata-installer.sh index 42ab0e15..be84a717 100755 --- a/netdata-installer.sh +++ b/netdata-installer.sh @@ -566,7 +566,7 @@ echo >&2 # run netdata echo >&2 "Starting netdata..." -run ${NETDATA_PREFIX}/usr/sbin/netdata -pidfile ${NETDATA_RUN_DIR}/netdata.pid "${@}" +run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}" if [ $? -ne 0 ] then diff --git a/src/main.c b/src/main.c index ec3c59ca..97a6364b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,40 +1,38 @@ #ifdef HAVE_CONFIG_H #include #endif +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include "appconfig.h" #include "common.h" -#include "log.h" #include "daemon.h" -#include "web_server.h" +#include "log.h" #include "popen.h" -#include "appconfig.h" -#include "web_client.h" #include "rrd.h" #include "rrd2json.h" +#include "web_client.h" +#include "web_server.h" #include "unit_test.h" -#include "plugins_d.h" -#include "plugin_idlejitter.h" -#include "plugin_tc.h" #include "plugin_checks.h" -#include "plugin_proc.h" +#include "plugin_idlejitter.h" #include "plugin_nfacct.h" #include "registry.h" +#include "plugin_proc.h" +#include "plugin_tc.h" +#include "plugins_d.h" #include "main.h" @@ -192,6 +190,60 @@ void kill_childs() debug(D_EXIT, "All threads/childs stopped."); } +struct option_def options[] = { + // opt description arg name default value + {'c', "Load alternate configuration file", "config_file", CONFIG_DIR "/" CONFIG_FILENAME}, + {'D', "Disable fork into background", NULL, NULL}, + {'h', "Display help message", NULL, NULL}, + {'P', "File to save a pid while running", "FILE", NULL}, + {'p', "Port to listen. Can be from 1 to 65535.", "port_number", "19999"}, + {'s', "Path to access host /proc and /sys when running in a container.", "PATH", NULL}, + {'t', "The frequency in seconds, for data collection. \ + Same as 'update every' config file option.", "seconds", "1"}, + {'l', "The number of entries the netdata daemon will keep in memory \ + for each chart dimension. Same as 'history config file option.", "lines_to_save", NULL}, + {'u', "System username to run as.", "username", "netdata"}, + {'v', "Version of the program", NULL, NULL}, + {'W', "vendor options.", "stacksize=|unittest|debug_flag", NULL}, +}; + +void help(int exitcode) { + FILE *stream; + if(exitcode == 0) + stream = stdout; + else + stream = stderr; + + int num_opts = sizeof(options) / sizeof(struct option_def); + int i; + int max_len_arg = 0; + + // Compute maximum argument length + for( i = 0; i < num_opts; i++ ) { + if(options[i].arg_name) { + int len_arg = strlen(options[i].arg_name); + if(len_arg > max_len_arg) max_len_arg = len_arg; + } + } + + fprintf(stream, "SYNOPSIS: netdata [options]\n"); + fprintf(stream, "\n"); + fprintf(stream, "Options:\n"); + + // Output options description. + for( i = 0; i < num_opts; i++ ) { + fprintf(stream, " -%c %-*s %s", options[i].val, max_len_arg, options[i].arg_name ? options[i].arg_name : "", options[i].description); + if(options[i].default_value) { + fprintf(stream, " Default: %s\n", options[i].default_value); + } else { + fprintf(stream, "\n"); + } + } + + fflush(stream); + exit(exitcode); +} + int main(int argc, char **argv) { @@ -207,53 +259,127 @@ int main(int argc, char **argv) // set the name for logging program_name = "netdata"; - // parse the arguments - for(i = 1; i < argc ; i++) { - if(strcmp(argv[i], "-c") == 0 && (i+1) < argc) { - if(load_config(argv[i+1], 1) != 1) { - error("Cannot load configuration file %s.", argv[i+1]); - exit(1); + // parse command line. + + // parse depercated options + // TODO: Remove this block with the next major release. + { + void remove_option(int opt_index, int *argc, char **argv) { + int i = opt_index; + // remove the options. + do { + *argc = *argc - 1; + for(i = opt_index; i < *argc; i++) { + argv[i] = argv[i+1]; + } + i = opt_index; + } while(argv[i][0] != '-' && opt_index >= *argc); + } + + i = 1; + while(i < argc) { + if(strcmp(argv[i], "-pidfile") == 0 && (i+1) < argc) { + strncpyz(pidfile, argv[i+1], FILENAME_MAX); + fprintf(stderr, "%s: deprecate option -- %s -- please use -P instead.\n", argv[0], argv[i]); + remove_option(i, &argc, argv); } - else { - debug(D_OPTIONS, "Configuration loaded from %s.", argv[i+1]); - config_loaded = 1; + else if(strcmp(argv[i], "-nodaemon") == 0 || strcmp(argv[i], "-nd") == 0) { + dont_fork = 1; + fprintf(stderr, "%s: deprecate option -- %s -- please use -D instead.\n ", argv[0], argv[i]); + remove_option(i, &argc, argv); } - i++; - } - else if(strcmp(argv[i], "-df") == 0 && (i+1) < argc) { config_set("global", "debug flags", argv[i+1]); debug_flags = strtoull(argv[i+1], NULL, 0); i++; } - else if(strcmp(argv[i], "-p") == 0 && (i+1) < argc) { config_set("global", "port", argv[i+1]); i++; } - else if(strcmp(argv[i], "-u") == 0 && (i+1) < argc) { config_set("global", "run as user", argv[i+1]); i++; } - else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) { config_set("global", "history", argv[i+1]); i++; } - else if(strcmp(argv[i], "-t") == 0 && (i+1) < argc) { config_set("global", "update every", argv[i+1]); i++; } - else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) { config_set("global", "host access prefix", argv[i+1]); i++; } - else if(strcmp(argv[i], "-stacksize") == 0 && (i+1) < argc) { config_set("global", "pthread stack size", argv[i+1]); i++; } - else if(strcmp(argv[i], "-nodaemon") == 0 || strcmp(argv[i], "-nd") == 0) dont_fork = 1; - else if(strcmp(argv[i], "-pidfile") == 0 && (i+1) < argc) { - i++; - strncpyz(pidfile, argv[i], FILENAME_MAX); - } - else if(strcmp(argv[i], "--unittest") == 0) { - rrd_update_every = 1; - if(run_all_mockup_tests()) exit(1); - if(unit_test_storage()) exit(1); - fprintf(stderr, "\n\nALL TESTS PASSED\n\n"); - exit(0); + else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) { + config_set("global", "host access prefix", argv[i+1]); + fprintf(stderr, "%s: deprecate option -- %s -- please use -s instead.\n", argv[0], argv[i]); + remove_option(i, &argc, argv); + } + else i++; } - else { - fprintf(stderr, "Cannot understand option '%s'.\n", argv[i]); - fprintf(stderr, "\nUSAGE: %s [-d] [-l LINES_TO_SAVE] [-u UPDATE_TIMER] [-p LISTEN_PORT] [-df debug flags].\n\n", argv[0]); - fprintf(stderr, " -c CONFIG FILE the configuration file to load. Default: %s.\n", CONFIG_DIR "/" CONFIG_FILENAME); - fprintf(stderr, " -l LINES_TO_SAVE can be from 5 to %d lines in JSON data. Default: %d.\n", RRD_HISTORY_ENTRIES_MAX, RRD_DEFAULT_HISTORY_ENTRIES); - fprintf(stderr, " -t UPDATE_TIMER can be from 1 to %d seconds. Default: %d.\n", UPDATE_EVERY_MAX, UPDATE_EVERY); - fprintf(stderr, " -p LISTEN_PORT can be from 1 to %d. Default: %d.\n", 65535, LISTEN_PORT); - fprintf(stderr, " -u USERNAME can be any system username to run as. Default: none.\n"); - fprintf(stderr, " -ch path to access host /proc and /sys when running in a container. Default: empty.\n"); - fprintf(stderr, " -nd or -nodeamon to disable forking in the background. Default: unset.\n"); - fprintf(stderr, " -df FLAGS debug options. Default: 0x%08llx.\n", debug_flags); - fprintf(stderr, " -stacksize BYTES to overwrite the pthread stack size.\n"); - fprintf(stderr, " -pidfile FILENAME to save a pid while running.\n"); - exit(1); + } + + // parse options + { + int num_opts = sizeof(options) / sizeof(struct option_def); + char optstring[(num_opts * 2) + 1]; + + int string_i = 0; + for( i = 0; i < num_opts; i++ ) { + optstring[string_i] = options[i].val; + string_i++; + if(options[i].arg_name) { + optstring[string_i] = ':'; + string_i++; + } } + + int opt; + while( (opt = getopt(argc, argv, optstring)) != -1 ) { + switch(opt) { + case 'c': + if(load_config(optarg, 1) != 1) { + error("Cannot load configuration file %s.", optarg); + exit(1); + } + else { + debug(D_OPTIONS, "Configuration loaded from %s.", optarg); + config_loaded = 1; + } + break; + case 'D': + dont_fork = 1; + break; + case 'h': + help(0); + break; + case 'P': + strncpy(pidfile, optarg, FILENAME_MAX); + pidfile[FILENAME_MAX] = '\0'; + break; + case 'p': + config_set("global", "port", optarg); + break; + case 's': + config_set("global", "host access prefix", optarg); + break; + case 't': + config_set("global", "update every", optarg); + break; + case 'u': + config_set("global", "run as user", optarg); + break; + case 'v': + // TODO: Outsource version to makefile which can compute version from git. + printf("netdata 1.1.0\n"); + return 0; + break; + case 'l': + config_set("global", "history", optarg); + break; + case 'W': + { + char* stacksize = "stacksize="; + char* debug_flags_string = "debug_flags="; + if(strcmp(optarg, "unittest") == 0) { + rrd_update_every = 1; + if(run_all_mockup_tests()) exit(1); + if(unit_test_storage()) exit(1); + fprintf(stderr, "\n\nALL TESTS PASSED\n\n"); + exit(0); + } else if(strncmp(optarg, stacksize, strlen(stacksize)) == 0) { + optarg += strlen(stacksize); + config_set("global", "pthread stack size", optarg); + } else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) { + optarg += strlen(debug_flags_string); + config_set("global", "debug flags", optarg); + debug_flags = strtoull(optarg, NULL, 0); + } + } + break; + default: /* ? */ + help(1); + break; + } + } } if(!config_loaded) load_config(NULL, 0); diff --git a/src/main.h b/src/main.h index d9edda58..701f8ff2 100644 --- a/src/main.h +++ b/src/main.h @@ -1,3 +1,5 @@ +#include + #ifndef NETDATA_MAIN_H #define NETDATA_MAIN_H 1 @@ -5,6 +7,27 @@ extern volatile sig_atomic_t netdata_exit; +/** + * This struct contains information about command line options. + */ +struct option_def { + /** The option character */ + const char val; + /** The name of the long option. */ + const char *description; + /** Short descripton what the option does */ + /** Name of the argument displayed in SYNOPSIS */ + const char *arg_name; + /** Default value if not set */ + const char *default_value; +}; + +/** + * List of command line options. + * This can be used to compute manpage, help messages, ect. + */ +extern struct option_def options[]; + extern void kill_childs(void); extern int killpid(pid_t pid, int signal); extern void netdata_cleanup_and_exit(int ret); diff --git a/src/storage_number.h b/src/storage_number.h index f35e99dd..382d9dae 100644 --- a/src/storage_number.h +++ b/src/storage_number.h @@ -1,3 +1,5 @@ +#include + #ifndef NETDATA_STORAGE_NUMBER_H #define NETDATA_STORAGE_NUMBER_H diff --git a/system/netdata-init-d.in b/system/netdata-init-d.in index 3e82d0d3..07d5a19e 100755 --- a/system/netdata-init-d.in +++ b/system/netdata-init-d.in @@ -14,7 +14,7 @@ DAEMON="netdata" DAEMON_PATH=@sbindir_POST@ PIDFILE=@localstatedir_POST@/$DAEMON.pid -DAEMONOPTS="-pidfile $PIDFILE" +DAEMONOPTS="-P $PIDFILE" STOP_TIMEOUT="10" service_start() diff --git a/system/netdata-openrc.in b/system/netdata-openrc.in index 299db569..3d5f2cdc 100755 --- a/system/netdata-openrc.in +++ b/system/netdata-openrc.in @@ -25,7 +25,7 @@ extra_started_commands="getconf" pidfile="/run/netdata.pid" command="${NETDATA_INSTALL_PATH}/usr/sbin/netdata" command_background="yes" -command_args="-pidfile ${pidfile} ${NETDATA_EXTRA_ARGS}" +command_args="-P ${pidfile} ${NETDATA_EXTRA_ARGS}" # start_stop_daemon_args="-u ${NETDATA_OWNER}" start_stop_daemon_args=""