2 * kmscon - Configuration Parser
4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include <xkbcommon/xkbcommon-keysyms.h>
36 #include "kmscon_conf.h"
39 #include "uterm_video.h"
41 static void print_help()
44 * Usage/Help information
45 * This should be scaled to a maximum of 80 characters per line:
48 * | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
49 * "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
50 * 80 char line starting with tab:
51 * |10| 20 | 30 | 40 | 50 | 60 | 70 | 80 |
52 * "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
57 "\t%1$s -h [options]\n"
58 "\t%1$s -l [options] -- /bin/login [login-arguments]\n"
60 "You can prefix boolean options with \"no-\" to negate them. If an argument is\n"
61 "given multiple times, only the last argument matters if not otherwise stated.\n"
64 "\t-h, --help [off] Print this help and exit\n"
65 "\t-v, --verbose [off] Print verbose messages\n"
66 "\t --debug [off] Enable debug mode\n"
67 "\t --silent [off] Suppress notices and warnings\n"
68 "\t-c, --configdir </foo/bar> [/etc/kmscon]\n"
69 "\t Path to config directory\n"
70 "\t --listen [off] Listen for new seats and spawn\n"
71 "\t sessions accordingly (daemon mode)\n"
74 "\t --vt <vt> [auto] Select which VT to run on\n"
75 "\t --switchvt [on] Automatically switch to VT\n"
76 "\t --seats <list,of,seats> [current] Select seats to run on\n"
79 "\t --session-max <max> [50] Maximum number of sessions\n"
80 "\t --session-control [off] Allow keyboard session-control\n"
81 "\t --terminal-session [on] Enable terminal session\n"
82 "\t --cdev-session [off] Enable kernel VT emulation session\n"
85 "\t-l, --login [/bin/login -p]\n"
86 "\t Start the given login process instead\n"
87 "\t of the default process; all arguments\n"
88 "\t following '--' will be be parsed as\n"
89 "\t argv to this process. No more options\n"
90 "\t after '--' will be parsed so use it at\n"
91 "\t the end of the argument string\n"
92 "\t-t, --term <TERM> [xterm-256color]\n"
93 "\t Value of the TERM environment variable\n"
94 "\t for the child process\n"
95 "\t --reset-env [on]\n"
96 "\t Reset environment before running child\n"
98 "\t --palette <name> [default]\n"
99 "\t Select the used color palette\n"
100 "\t --sb-size <num> [1000]\n"
101 "\t Size of the scrollback-buffer in lines\n"
104 "\t --xkb-model <model> [-] Set XkbModel for input devices\n"
105 "\t --xkb-layout <layout> [-] Set XkbLayout for input devices\n"
106 "\t --xkb-variant <variant> [-] Set XkbVariant for input devices\n"
107 "\t --xkb-options <options> [-] Set XkbOptions for input devices\n"
108 "\t --xkb-repeat-delay <msecs> [250]\n"
109 "\t Initial delay for key-repeat in ms\n"
110 "\t --xkb-repeat-rate <msecs> [50]\n"
111 "\t Delay between two key-repeats in ms\n"
113 "Grabs / Keyboard-Shortcuts:\n"
114 "\t --grab-scroll-up <grab> [<Shift>Up]\n"
115 "\t Shortcut to scroll up\n"
116 "\t --grab-scroll-down <grab> [<Shift>Down]\n"
117 "\t Shortcut to scroll down\n"
118 "\t --grab-page-up <grab> [<Shift>Prior]\n"
119 "\t Shortcut to scroll page up\n"
120 "\t --grab-page-down <grab> [<Shift>Next]\n"
121 "\t Shortcut to scroll page down\n"
122 "\t --grab-session-next <grab> [<Ctrl><Logo>Right]\n"
123 "\t Switch to next session\n"
124 "\t --grab-session-prev <grab> [<Ctrl><Logo>Left]\n"
125 "\t Switch to previous session\n"
126 "\t --grab-session-dummy <grab> [<Ctrl><Logo>Escape]\n"
127 "\t Switch to dummy session\n"
128 "\t --grab-session-close <grab> [<Ctrl><Logo>BackSpace]\n"
129 "\t Close current session\n"
130 "\t --grab-terminal-new <grab> [<Ctrl><Logo>Return]\n"
131 "\t Create new terminal session\n"
134 "\t --drm [on] Use DRM if available\n"
135 "\t --hwaccel [off] Use 3D hardware-acceleration if\n"
137 "\t --gpus={all,aux,primary}[all] GPU selection mode\n"
138 "\t --render-engine <eng> [-] Console renderer\n"
139 "\t --render-timing [off] Print renderer timing information\n"
142 "\t --font-engine <engine> [pango]\n"
144 "\t --font-size <points> [12]\n"
145 "\t Font size in points\n"
146 "\t --font-name <name> [monospace]\n"
148 "\t --font-dpi <dpi> [96]\n"
149 "\t Force DPI value for all fonts\n",
153 * | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 |
154 * "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
155 * 80 char line starting with tab:
156 * |10| 20 | 30 | 40 | 50 | 60 | 70 | 80 |
157 * "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
161 #define KMSCON_CONF_FROM_FIELD(_mem, _name) \
162 shl_offsetof((_mem), struct kmscon_conf_t, _name)
166 * The --vt option is special in that it can be an integer, a string or a path.
167 * We use the string-handling of conf_string but the parser is different. See
168 * below for more information on the parser.
171 static void conf_default_vt(struct conf_option *opt)
173 conf_string.set_default(opt);
176 static void conf_free_vt(struct conf_option *opt)
178 conf_string.free(opt);
181 static int conf_parse_vt(struct conf_option *opt, bool on, const char *arg)
183 static const char prefix[] = "/dev/";
188 if (!shl_strtou(arg, &val)) {
189 ret = asprintf(&str, "%stty%u", prefix, val);
192 } else if (*arg && *arg != '.' && *arg != '/') {
193 str = malloc(sizeof(prefix) + strlen(arg));
205 opt->type->free(opt);
206 *(void**)opt->mem = str;
210 static int conf_copy_vt(struct conf_option *opt,
211 const struct conf_option *src)
213 return conf_string.copy(opt, src);
216 static const struct conf_type conf_vt = {
217 .flags = CONF_HAS_ARG,
218 .set_default = conf_default_vt,
219 .free = conf_free_vt,
220 .parse = conf_parse_vt,
221 .copy = conf_copy_vt,
226 * The --login option is special in that it can have an unlimited number of
227 * arguments on the command-line. So on the command-line it is an boolean option
228 * that specifies whether default login or custom login is used.
229 * However, the file-parser does simple string-parsing as it does not need the
230 * special handling that the command-line does.
233 static char *def_argv[] = { "/bin/login", "-p", NULL };
235 static void conf_default_login(struct conf_option *opt)
237 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
239 opt->type->free(opt);
241 conf->argv = def_argv;
244 static void conf_free_login(struct conf_option *opt)
246 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
248 if (conf->argv != def_argv)
254 static int conf_parse_login(struct conf_option *opt, bool on, const char *arg)
256 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
258 opt->type->free(opt);
263 static int conf_copy_login(struct conf_option *opt,
264 const struct conf_option *src)
266 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
267 struct kmscon_conf_t *s = KMSCON_CONF_FROM_FIELD(src->mem, login);
272 ret = shl_dup_array(&t, s->argv);
279 opt->type->free(opt);
281 conf->login = s->login;
285 static const struct conf_type conf_login = {
287 .set_default = conf_default_login,
288 .free = conf_free_login,
289 .parse = conf_parse_login,
290 .copy = conf_copy_login,
293 static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
296 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
300 /* parse "--login [...] -- args" arguments */
301 if (argv && conf->login) {
303 fprintf(stderr, "Arguments for --login missing\n");
307 ret = shl_dup_array_size(&t, &argv[idx], argc - idx);
313 } else if (!conf->argv) {
314 ret = shl_dup_array_size(&t, def_argv,
315 sizeof(def_argv) / sizeof(*def_argv));
325 static int file_login(struct conf_option *opt, bool on, const char *arg)
327 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
333 log_error("no arguments for 'login' config-option");
337 ret = shl_split_string(arg, &t, &size, ' ', false);
339 log_error("cannot split 'login' config-option argument");
344 log_error("empty argument given for 'login' config-option");
348 opt->type->free(opt);
356 * The GPU selection mode is a simple string to enum parser.
359 static void conf_default_gpus(struct conf_option *opt)
361 conf_uint.set_default(opt);
364 static void conf_free_gpus(struct conf_option *opt)
369 static int conf_parse_gpus(struct conf_option *opt, bool on, const char *arg)
371 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, gpus);
374 if (!strcmp(arg, "all")) {
375 mode = KMSCON_GPU_ALL;
376 } else if (!strcmp(arg, "aux") || !strcmp(arg, "auxiliary")) {
377 mode = KMSCON_GPU_AUX;
378 } else if (!strcmp(arg, "primary") || !strcmp(arg, "single")) {
379 mode = KMSCON_GPU_PRIMARY;
381 log_error("invalid GPU selection mode --gpus='%s'", arg);
385 opt->type->free(opt);
390 static int conf_copy_gpus(struct conf_option *opt,
391 const struct conf_option *src)
393 return conf_uint.copy(opt, src);
396 static const struct conf_type conf_gpus = {
397 .flags = CONF_HAS_ARG,
398 .set_default = conf_default_gpus,
399 .free = conf_free_gpus,
400 .parse = conf_parse_gpus,
401 .copy = conf_copy_gpus,
406 * Several other options have side-effects on other options. We use afterchecks
407 * to enforce these. They're pretty simple. See below.
408 * Some of them also need copy-helpers because they copy more than one value.
411 static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
414 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, debug);
416 /* --debug implies --verbose */
423 static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
426 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, help);
428 /* exit after printing --help information */
437 static int aftercheck_drm(struct conf_option *opt, int argc, char **argv,
440 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, drm);
442 /* disable --drm if DRM runtime support is not available */
443 /* TODO: This prevents people from booting without DRM and loading DRM
444 * drivers during runtime. However, if we remove it, we will be unable
445 * to automatically fall back to fbdev-mode.
446 * But with blacklists fbdev-mode is the default so we can run with DRM
447 * enabled but will still correctly use fbdev devices so we can then
448 * remove this check. */
450 if (!uterm_video_available(UTERM_VIDEO_DRM3D) &&
451 !uterm_video_available(UTERM_VIDEO_DRM2D)) {
452 log_info("no DRM runtime support available; disabling --drm");
460 static int aftercheck_vt(struct conf_option *opt, int argc, char **argv,
463 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, vt);
465 if (!conf->vt || conf->seat_config)
468 if (!kmscon_conf_is_single_seat(conf)) {
469 log_error("you cannot use global --vt if --seats contains not exactly one seat");
476 static int aftercheck_listen(struct conf_option *opt, int argc, char **argv,
479 struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, listen);
485 if (conf->cdev_session)
486 log_error("you can use --cdev-session only in combination with --listen");
495 * We use static default values to avoid allocating memory for these. This
496 * speeds up config-parser considerably.
499 static char *def_seats[] = { "current", NULL };
501 static struct conf_grab def_grab_scroll_up =
502 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Up);
504 static struct conf_grab def_grab_scroll_down =
505 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Down);
507 static struct conf_grab def_grab_page_up =
508 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Prior);
510 static struct conf_grab def_grab_page_down =
511 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Next);
513 static struct conf_grab def_grab_session_next =
514 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Right);
516 static struct conf_grab def_grab_session_prev =
517 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Left);
519 static struct conf_grab def_grab_session_dummy =
520 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Escape);
522 static struct conf_grab def_grab_session_close =
523 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_BackSpace);
525 static struct conf_grab def_grab_terminal_new =
526 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Return);
528 int kmscon_conf_new(struct conf_ctx **out)
530 struct conf_ctx *ctx;
532 struct kmscon_conf_t *conf;
537 conf = malloc(sizeof(*conf));
540 memset(conf, 0, sizeof(*conf));
542 struct conf_option options[] = {
544 CONF_OPTION_BOOL_FULL('h', "help", aftercheck_help, NULL, NULL, &conf->help, false),
545 CONF_OPTION_BOOL('v', "verbose", &conf->verbose, false),
546 CONF_OPTION_BOOL_FULL(0, "debug", aftercheck_debug, NULL, NULL, &conf->debug, false),
547 CONF_OPTION_BOOL(0, "silent", &conf->silent, false),
548 CONF_OPTION_STRING('c', "configdir", &conf->configdir, "/etc/kmscon"),
549 CONF_OPTION_BOOL_FULL(0, "listen", aftercheck_listen, NULL, NULL, &conf->listen, false),
552 CONF_OPTION(0, 0, "vt", &conf_vt, aftercheck_vt, NULL, NULL, &conf->vt, NULL),
553 CONF_OPTION_BOOL(0, "switchvt", &conf->switchvt, true),
554 CONF_OPTION_STRING_LIST(0, "seats", &conf->seats, def_seats),
556 /* Session Options */
557 CONF_OPTION_UINT(0, "session-max", &conf->session_max, 50),
558 CONF_OPTION_BOOL(0, "session-control", &conf->session_control, false),
559 CONF_OPTION_BOOL(0, "terminal-session", &conf->terminal_session, true),
560 CONF_OPTION_BOOL(0, "cdev-session", &conf->cdev_session, false),
562 /* Terminal Options */
563 CONF_OPTION(0, 'l', "login", &conf_login, aftercheck_login, NULL, file_login, &conf->login, false),
564 CONF_OPTION_STRING('t', "term", &conf->term, "xterm-256color"),
565 CONF_OPTION_BOOL(0, "reset-env", &conf->reset_env, true),
566 CONF_OPTION_STRING(0, "palette", &conf->palette, NULL),
567 CONF_OPTION_UINT(0, "sb-size", &conf->sb_size, 1000),
570 CONF_OPTION_STRING(0, "xkb-model", &conf->xkb_model, ""),
571 CONF_OPTION_STRING(0, "xkb-layout", &conf->xkb_layout, ""),
572 CONF_OPTION_STRING(0, "xkb-variant", &conf->xkb_variant, ""),
573 CONF_OPTION_STRING(0, "xkb-options", &conf->xkb_options, ""),
574 CONF_OPTION_UINT(0, "xkb-repeat-delay", &conf->xkb_repeat_delay, 250),
575 CONF_OPTION_UINT(0, "xkb-repeat-rate", &conf->xkb_repeat_rate, 50),
577 /* Grabs / Keyboard-Shortcuts */
578 CONF_OPTION_GRAB(0, "grab-scroll-up", &conf->grab_scroll_up, &def_grab_scroll_up),
579 CONF_OPTION_GRAB(0, "grab-scroll-down", &conf->grab_scroll_down, &def_grab_scroll_down),
580 CONF_OPTION_GRAB(0, "grab-page-up", &conf->grab_page_up, &def_grab_page_up),
581 CONF_OPTION_GRAB(0, "grab-page-down", &conf->grab_page_down, &def_grab_page_down),
582 CONF_OPTION_GRAB(0, "grab-session-next", &conf->grab_session_next, &def_grab_session_next),
583 CONF_OPTION_GRAB(0, "grab-session-prev", &conf->grab_session_prev, &def_grab_session_prev),
584 CONF_OPTION_GRAB(0, "grab-session-dummy", &conf->grab_session_dummy, &def_grab_session_dummy),
585 CONF_OPTION_GRAB(0, "grab-session-close", &conf->grab_session_close, &def_grab_session_close),
586 CONF_OPTION_GRAB(0, "grab-terminal-new", &conf->grab_terminal_new, &def_grab_terminal_new),
589 CONF_OPTION_BOOL_FULL(0, "drm", aftercheck_drm, NULL, NULL, &conf->drm, true),
590 CONF_OPTION_BOOL(0, "hwaccel", &conf->hwaccel, false),
591 CONF_OPTION(0, 0, "gpus", &conf_gpus, NULL, NULL, NULL, &conf->gpus, KMSCON_GPU_ALL),
592 CONF_OPTION_STRING(0, "render-engine", &conf->render_engine, NULL),
593 CONF_OPTION_BOOL(0, "render-timing", &conf->render_timing, false),
596 CONF_OPTION_STRING(0, "font-engine", &conf->font_engine, "pango"),
597 CONF_OPTION_UINT(0, "font-size", &conf->font_size, 12),
598 CONF_OPTION_STRING(0, "font-name", &conf->font_name, "monospace"),
599 CONF_OPTION_UINT(0, "font-dpi", &conf->font_ppi, 96),
602 ret = conf_ctx_new(&ctx, options, sizeof(options) / sizeof(*options),
613 void kmscon_conf_free(struct conf_ctx *ctx)
619 conf = conf_ctx_get_mem(ctx);
624 int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv)
627 struct kmscon_conf_t *conf;
632 conf = conf_ctx_get_mem(ctx);
633 conf->seat_config = false;
635 ret = conf_ctx_parse_argv(ctx, argc, argv);
642 if (!conf->debug && !conf->verbose && conf->silent)
643 log_set_config(&LOG_CONFIG_WARNING(0, 0, 0, 0));
645 log_set_config(&LOG_CONFIG_INFO(conf->debug,
648 log_print_init("kmscon");
650 ret = conf_ctx_parse_file(ctx, "%s/kmscon.conf", conf->configdir);
657 int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main,
661 struct kmscon_conf_t *conf;
663 if (!ctx || !main || !seat)
666 log_debug("parsing seat configuration for seat %s", seat);
668 conf = conf_ctx_get_mem(ctx);
669 conf->seat_config = true;
671 ret = conf_ctx_parse_ctx(ctx, main);
675 ret = conf_ctx_parse_file(ctx, "%s/%s.seat.conf", conf->configdir,