#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
-#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define LOG_SUBSYSTEM "config"
struct conf_obj conf_global;
-static char *def_argv[] = { NULL, "-i", NULL };
-
-static void print_help()
-{
- /*
- * Usage/Help information
- * This should be scaled to a maximum of 80 characters per line:
- *
- * 80 char line:
- * | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
- * "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
- * 80 char line starting with tab:
- * |10| 20 | 30 | 40 | 50 | 60 | 70 | 80 |
- * "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
- */
- fprintf(stderr,
- "Usage:\n"
- "\t%1$s [options]\n"
- "\t%1$s -h [options]\n"
- "\t%1$s -l [options] -- /bin/sh [sh-arguments]\n"
- "\n"
- "You can prefix boolean options with \"no-\" to negate it. If an argument is\n"
- "given multiple times, only the last argument matters if not otherwise stated.\n"
- "\n"
- "General Options:\n"
- "\t-h, --help [off] Print this help and exit\n"
- "\t-v, --verbose [off] Print verbose messages\n"
- "\t --debug [off] Enable debug mode\n"
- "\t --silent [off] Suppress notices and warnings\n"
- "\t-s, --switchvt [off] Automatically switch to VT\n"
- "\t --seat <seat-name> [seat0] Select seat; default: seat0\n"
- "\n"
- "Terminal Options:\n"
- "\t-l, --login [/bin/sh]\n"
- "\t Start the given login process instead\n"
- "\t of the default process; all arguments\n"
- "\t following '--' will be be parsed as\n"
- "\t argv to this process. No more options\n"
- "\t after '--' will be parsed so use it at\n"
- "\t the end of the argument string\n"
- "\t-t, --term <TERM> [vt220]\n"
- "\t Value of the TERM environment variable\n"
- "\t for the child process\n"
- "\n"
- "Video Options:\n"
- "\t --fbdev [off] Use fbdev instead of DRM\n"
- "\n"
- "Input Device Options:\n"
- "\t --xkb-layout <layout> [us] Set XkbLayout for input devices\n"
- "\t --xkb-variant <variant> [-] Set XkbVariant for input devices\n"
- "\t --xkb-options <options> [-] Set XkbOptions for input devices\n"
- "\n"
- "Font Options:\n"
- "\t --font-engine <engine> [pango] Font engine\n",
- "kmscon");
- /*
- * 80 char line:
- * | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
- * "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
- * 80 char line starting with tab:
- * |10| 20 | 30 | 40 | 50 | 60 | 70 | 80 |
- * "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
- */
-}
void conf_free_value(struct conf_option *opt)
{
.set_default = conf_default_string,
};
-static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
- int idx)
-{
- /* --debug implies --verbose */
- if (conf_global.debug)
- conf_global.verbose = 1;
-
- return 0;
-}
-
-static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
- int idx)
-{
- /* exit after printing --help information */
- if (conf_global.help) {
- print_help();
- conf_global.exit = true;
- }
-
- return 0;
-}
-
-static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
- int idx)
-{
- int ret;
-
- /* parse "--login [...] -- args" arguments */
- if (conf_global.login) {
- if (idx >= argc) {
- fprintf(stderr, "Arguments for --login missing\n");
- return -EFAULT;
- }
-
- conf_global.argv = &argv[idx];
- ret = argc - idx;
- } else {
- def_argv[0] = getenv("SHELL") ? : _PATH_BSHELL;
- conf_global.argv = def_argv;
- ret = 0;
- }
-
- return ret;
-}
-
-struct conf_option options[] = {
- CONF_OPTION_BOOL('h', "help", aftercheck_help, &conf_global.help, false),
- CONF_OPTION_BOOL('v', "verbose", NULL, &conf_global.verbose, false),
- CONF_OPTION_BOOL(0, "debug", aftercheck_debug, &conf_global.debug, false),
- CONF_OPTION_BOOL(0, "silent", NULL, &conf_global.silent, false),
- CONF_OPTION_BOOL(0, "fbdev", NULL, &conf_global.use_fbdev, false),
- CONF_OPTION_BOOL('s', "switchvt", NULL, &conf_global.switchvt, false),
- CONF_OPTION_BOOL('l', "login", aftercheck_login, &conf_global.login, false),
- CONF_OPTION_STRING('t', "term", NULL, &conf_global.term, "vt220"),
- CONF_OPTION_STRING(0, "xkb-layout", NULL, &conf_global.xkb_layout, "us"),
- CONF_OPTION_STRING(0, "xkb-variant", NULL, &conf_global.xkb_variant, ""),
- CONF_OPTION_STRING(0, "xkb-options", NULL, &conf_global.xkb_options, ""),
- CONF_OPTION_STRING(0, "seat", NULL, &conf_global.seat, "seat0"),
- CONF_OPTION_STRING(0, "font-engine", NULL, &conf_global.font_engine, "pango"),
-};
-
/* free all memory that we allocated and reset to initial state */
-void conf_free(void)
+void conf_free(struct conf_option *opts, size_t len)
{
- unsigned int i, num;
+ unsigned int i;
- num = sizeof(options) / sizeof(*options);
- for (i = 0; i < num; ++i) {
- if (options[i].type->free)
- options[i].type->free(&options[i]);
+ for (i = 0; i < len; ++i) {
+ if (opts[i].type->free)
+ opts[i].type->free(&opts[i]);
}
-
- memset(&conf_global, 0, sizeof(conf_global));
}
/*
* can use the getopt_long() library call. It locks all arguments after they
* have been set so command-line options will always overwrite config-options.
*/
-int conf_parse_argv(int argc, char **argv)
+int conf_parse_argv(struct conf_option *opts, size_t len,
+ int argc, char **argv)
{
char *short_options;
struct option *long_options;
struct option *opt;
- size_t len, i, pos;
+ size_t i, pos;
int c, ret;
if (!argv || argc < 1)
return -EINVAL;
- len = sizeof(options) / sizeof(*options);
-
short_options = malloc(sizeof(char) * (len + 1) * 2);
if (!short_options) {
log_error("cannot allocate enough memory to parse command line arguments (%d): %m");
short_options[pos++] = ':';
opt = long_options;
for (i = 0; i < len; ++i) {
- if (options[i].short_name) {
- short_options[pos++] = options[i].short_name;
- if (options[i].type->flags & CONF_HAS_ARG)
+ if (opts[i].short_name) {
+ short_options[pos++] = opts[i].short_name;
+ if (opts[i].type->flags & CONF_HAS_ARG)
short_options[pos++] = ':';
}
- if (options[i].long_name) {
+ if (opts[i].long_name) {
/* skip the "no-" prefix */
- opt->name = &options[i].long_name[3];
- opt->has_arg = !!(options[i].type->flags & CONF_HAS_ARG);
+ opt->name = &opts[i].long_name[3];
+ opt->has_arg = !!(opts[i].type->flags & CONF_HAS_ARG);
opt->flag = NULL;
opt->val = 100000 + i;
++opt;
/* boolean args are also added with "no-" prefix */
- if (!(options[i].type->flags & CONF_HAS_ARG)) {
- opt->name = options[i].long_name;
+ if (!(opts[i].type->flags & CONF_HAS_ARG)) {
+ opt->name = opts[i].long_name;
opt->has_arg = 0;
opt->flag = NULL;
opt->val = 200000 + i;
return -EFAULT;
} else if (c < 100000) {
for (i = 0; i < len; ++i) {
- if (options[i].short_name == c) {
- ret = options[i].type->parse(&options[i],
- true,
- optarg);
+ if (opts[i].short_name == c) {
+ ret = opts[i].type->parse(&opts[i],
+ true,
+ optarg);
if (ret)
return ret;
- options[i].flags |= CONF_LOCKED;
- options[i].flags |= CONF_DONE;
+ opts[i].flags |= CONF_LOCKED;
+ opts[i].flags |= CONF_DONE;
break;
}
}
} else if (c < 200000) {
i = c - 100000;
- ret = options[i].type->parse(&options[i], true, optarg);
+ ret = opts[i].type->parse(&opts[i], true, optarg);
if (ret)
return ret;
- options[i].flags |= CONF_LOCKED;
- options[i].flags |= CONF_DONE;
+ opts[i].flags |= CONF_LOCKED;
+ opts[i].flags |= CONF_DONE;
} else {
i = c - 200000;
- ret = options[i].type->parse(&options[i], false, NULL);
+ ret = opts[i].type->parse(&opts[i], false, NULL);
if (ret)
return ret;
- options[i].flags |= CONF_LOCKED;
- options[i].flags |= CONF_DONE;
+ opts[i].flags |= CONF_LOCKED;
+ opts[i].flags |= CONF_DONE;
}
}
/* set default values if not configured */
for (i = 0; i < len; ++i) {
- if (!(options[i].flags & CONF_DONE) &&
- options[i].type->set_default) {
- options[i].type->set_default(&options[i]);
+ if (!(opts[i].flags & CONF_DONE) &&
+ opts[i].type->set_default) {
+ opts[i].type->set_default(&opts[i]);
}
}
* arguments passed in. If not all arguments are consumed, then this
* function will report an error to the caller. */
for (i = 0; i < len; ++i) {
- if (options[i].aftercheck) {
- ret = options[i].aftercheck(&options[i], argc, argv, optind);
+ if (opts[i].aftercheck) {
+ ret = opts[i].aftercheck(&opts[i], argc, argv, optind);
if (ret < 0)
return ret;
optind += ret;
return 0;
}
-static int parse_kv_pair(const char *key, const char *value)
+static int parse_kv_pair(struct conf_option *opts, size_t len,
+ const char *key, const char *value)
{
- unsigned int i, num;
+ unsigned int i;
int ret;
bool set;
struct conf_option *opt;
- num = sizeof(options) / sizeof(*options);
- for (i = 0; i < num; ++i) {
- opt = &options[i];
+ for (i = 0; i < len; ++i) {
+ opt = &opts[i];
if (!opt->long_name)
continue;
*tail-- = 0;
}
-static int parse_line(char **buf, size_t *size)
+static int parse_line(struct conf_option *opts, size_t olen,
+ char **buf, size_t *size)
{
char *key;
char *value = NULL;
if (value)
strip_spaces(&value);
- ret = parse_kv_pair(key, value);
+ ret = parse_kv_pair(opts, olen, key, value);
if (ret)
return ret;
}
return 0;
}
-static int parse_buffer(char *buf, size_t size)
+static int parse_buffer(struct conf_option *opts, size_t len,
+ char *buf, size_t size)
{
int ret = 0;
while (!ret && size > 0)
- ret = parse_line(&buf, &size);
+ ret = parse_line(opts, len, &buf, &size);
return ret;
}
/* This reads the file at \path in memory and parses it as if it was given as
* command line options. */
-int conf_parse_file(const char *path)
+int conf_parse_file(struct conf_option *opts, size_t len, const char *path)
{
int fd, ret;
size_t size, pos;
} while (ret > 0);
buf[pos] = 0;
- ret = parse_buffer(buf, pos);
+ ret = parse_buffer(opts, len, buf, pos);
out_free:
free(buf);
return ret;
}
-int conf_parse_all_files(void)
+int conf_parse_all_files(struct conf_option *opts, size_t len)
{
int ret;
const char *file, *home;
log_warning("config file %s exists but read access was denied",
file);
else
- ret = conf_parse_file(file);
+ ret = conf_parse_file(opts, len, file);
}
if (ret)
log_warning("config file %s exists but read access was denied",
path);
else
- ret = conf_parse_file(path);
+ ret = conf_parse_file(opts, len, path);
}
free(path);
}
*/
#include <errno.h>
+#include <paths.h>
#include <signal.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
return ret;
}
+static void print_help()
+{
+ /*
+ * Usage/Help information
+ * This should be scaled to a maximum of 80 characters per line:
+ *
+ * 80 char line:
+ * | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
+ * "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
+ * 80 char line starting with tab:
+ * |10| 20 | 30 | 40 | 50 | 60 | 70 | 80 |
+ * "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
+ */
+ fprintf(stderr,
+ "Usage:\n"
+ "\t%1$s [options]\n"
+ "\t%1$s -h [options]\n"
+ "\t%1$s -l [options] -- /bin/sh [sh-arguments]\n"
+ "\n"
+ "You can prefix boolean options with \"no-\" to negate it. If an argument is\n"
+ "given multiple times, only the last argument matters if not otherwise stated.\n"
+ "\n"
+ "General Options:\n"
+ "\t-h, --help [off] Print this help and exit\n"
+ "\t-v, --verbose [off] Print verbose messages\n"
+ "\t --debug [off] Enable debug mode\n"
+ "\t --silent [off] Suppress notices and warnings\n"
+ "\t-s, --switchvt [off] Automatically switch to VT\n"
+ "\t --seat <seat-name> [seat0] Select seat; default: seat0\n"
+ "\n"
+ "Terminal Options:\n"
+ "\t-l, --login [/bin/sh]\n"
+ "\t Start the given login process instead\n"
+ "\t of the default process; all arguments\n"
+ "\t following '--' will be be parsed as\n"
+ "\t argv to this process. No more options\n"
+ "\t after '--' will be parsed so use it at\n"
+ "\t the end of the argument string\n"
+ "\t-t, --term <TERM> [vt220]\n"
+ "\t Value of the TERM environment variable\n"
+ "\t for the child process\n"
+ "\n"
+ "Video Options:\n"
+ "\t --fbdev [off] Use fbdev instead of DRM\n"
+ "\n"
+ "Input Device Options:\n"
+ "\t --xkb-layout <layout> [us] Set XkbLayout for input devices\n"
+ "\t --xkb-variant <variant> [-] Set XkbVariant for input devices\n"
+ "\t --xkb-options <options> [-] Set XkbOptions for input devices\n"
+ "\n"
+ "Font Options:\n"
+ "\t --font-engine <engine> [pango] Font engine\n",
+ "kmscon");
+ /*
+ * 80 char line:
+ * | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
+ * "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
+ * 80 char line starting with tab:
+ * |10| 20 | 30 | 40 | 50 | 60 | 70 | 80 |
+ * "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
+ */
+}
+
+static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
+ int idx)
+{
+ /* --debug implies --verbose */
+ if (conf_global.debug)
+ conf_global.verbose = 1;
+
+ return 0;
+}
+
+static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
+ int idx)
+{
+ /* exit after printing --help information */
+ if (conf_global.help) {
+ print_help();
+ conf_global.exit = true;
+ }
+
+ return 0;
+}
+
+static char *def_argv[] = { NULL, "-i", NULL };
+
+static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
+ int idx)
+{
+ int ret;
+
+ /* parse "--login [...] -- args" arguments */
+ if (conf_global.login) {
+ if (idx >= argc) {
+ fprintf(stderr, "Arguments for --login missing\n");
+ return -EFAULT;
+ }
+
+ conf_global.argv = &argv[idx];
+ ret = argc - idx;
+ } else {
+ def_argv[0] = getenv("SHELL") ? : _PATH_BSHELL;
+ conf_global.argv = def_argv;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+struct conf_option options[] = {
+ CONF_OPTION_BOOL('h', "help", aftercheck_help, &conf_global.help, false),
+ CONF_OPTION_BOOL('v', "verbose", NULL, &conf_global.verbose, false),
+ CONF_OPTION_BOOL(0, "debug", aftercheck_debug, &conf_global.debug, false),
+ CONF_OPTION_BOOL(0, "silent", NULL, &conf_global.silent, false),
+ CONF_OPTION_BOOL(0, "fbdev", NULL, &conf_global.use_fbdev, false),
+ CONF_OPTION_BOOL('s', "switchvt", NULL, &conf_global.switchvt, false),
+ CONF_OPTION_BOOL('l', "login", aftercheck_login, &conf_global.login, false),
+ CONF_OPTION_STRING('t', "term", NULL, &conf_global.term, "vt220"),
+ CONF_OPTION_STRING(0, "xkb-layout", NULL, &conf_global.xkb_layout, "us"),
+ CONF_OPTION_STRING(0, "xkb-variant", NULL, &conf_global.xkb_variant, ""),
+ CONF_OPTION_STRING(0, "xkb-options", NULL, &conf_global.xkb_options, ""),
+ CONF_OPTION_STRING(0, "seat", NULL, &conf_global.seat, "seat0"),
+ CONF_OPTION_STRING(0, "font-engine", NULL, &conf_global.font_engine, "pango"),
+};
+
int main(int argc, char **argv)
{
int ret;
struct kmscon_app app;
+ size_t onum;
- ret = conf_parse_argv(argc, argv);
+ onum = sizeof(options) / sizeof(*options);
+ ret = conf_parse_argv(options, onum, argc, argv);
if (ret)
goto err_out;
if (conf_global.exit) {
- conf_free();
+ conf_free(options, onum);
return EXIT_SUCCESS;
}
log_print_init("kmscon");
- ret = conf_parse_all_files();
+ ret = conf_parse_all_files(options, onum);
if (ret)
goto err_out;
kmscon_font_freetype2_unload();
kmscon_font_pango_unload();
kmscon_font_8x16_unload();
- conf_free();
+ conf_free(options, onum);
log_info("exiting");
return EXIT_SUCCESS;
kmscon_font_pango_unload();
kmscon_font_8x16_unload();
err_out:
- conf_free();
+ conf_free(options, onum);
log_err("cannot initialize kmscon, errno %d: %s", ret, strerror(-ret));
return -ret;
}