uvtd: vt: implement VT_GETMODE/SETMODE ioctl state-tracking
[platform/upstream/kmscon.git] / src / kmscon_conf.c
1 /*
2  * kmscon - Configuration Parser
3  *
4  * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
5  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
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.
24  */
25
26 #include <errno.h>
27 #include <paths.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <xkbcommon/xkbcommon-keysyms.h>
35 #include "conf.h"
36 #include "kmscon_conf.h"
37 #include "shl_log.h"
38 #include "shl_misc.h"
39 #include "uterm_video.h"
40
41 static void print_help()
42 {
43         /*
44          * Usage/Help information
45          * This should be scaled to a maximum of 80 characters per line:
46          *
47          * 80 char 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"
53          */
54         fprintf(stderr,
55                 "Usage:\n"
56                 "\t%1$s [options]\n"
57                 "\t%1$s -h [options]\n"
58                 "\t%1$s -l [options] -- /bin/login [login-arguments]\n"
59                 "\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"
62                 "\n"
63                 "General Options:\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"
72                 "\n"
73                 "Seat Options:\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"
77                 "\n"
78                 "Session Options:\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"
83                 "\n"
84                 "Terminal Options:\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"
97                 "\t                              process\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"
102                 "\n"
103                 "Input Options:\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"
112                 "\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"
132                 "\n"
133                 "Video Options:\n"
134                 "\t    --drm                   [on]    Use DRM if available\n"
135                 "\t    --hwaccel               [off]   Use 3D hardware-acceleration if\n"
136                 "\t                                    available\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"
140                 "\n"
141                 "Font Options:\n"
142                 "\t    --font-engine <engine>  [pango]\n"
143                 "\t                              Font engine\n"
144                 "\t    --font-size <points>    [12]\n"
145                 "\t                              Font size in points\n"
146                 "\t    --font-name <name>      [monospace]\n"
147                 "\t                              Font name\n"
148                 "\t    --font-dpi <dpi>        [96]\n"
149                 "\t                              Force DPI value for all fonts\n",
150                 "kmscon");
151         /*
152          * 80 char line:
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"
158          */
159 }
160
161 #define KMSCON_CONF_FROM_FIELD(_mem, _name) \
162         shl_offsetof((_mem), struct kmscon_conf_t, _name)
163
164 /*
165  * VT Type
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.
169  */
170
171 static void conf_default_vt(struct conf_option *opt)
172 {
173         conf_string.set_default(opt);
174 }
175
176 static void conf_free_vt(struct conf_option *opt)
177 {
178         conf_string.free(opt);
179 }
180
181 static int conf_parse_vt(struct conf_option *opt, bool on, const char *arg)
182 {
183         static const char prefix[] = "/dev/";
184         unsigned int val;
185         char *str;
186         int ret;
187
188         if (!shl_strtou(arg, &val)) {
189                 ret = asprintf(&str, "%stty%u", prefix, val);
190                 if (ret == -1)
191                         return -ENOMEM;
192         } else if (*arg && *arg != '.' && *arg != '/') {
193                 str = malloc(sizeof(prefix) + strlen(arg));
194                 if (!str)
195                         return -ENOMEM;
196
197                 strcpy(str, prefix);
198                 strcat(str, arg);
199         } else {
200                 str = strdup(arg);
201                 if (!str)
202                         return -ENOMEM;
203         }
204
205         opt->type->free(opt);
206         *(void**)opt->mem = str;
207         return 0;
208 }
209
210 static int conf_copy_vt(struct conf_option *opt,
211                         const struct conf_option *src)
212 {
213         return conf_string.copy(opt, src);
214 }
215
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,
222 };
223
224 /*
225  * Login handling
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.
231  */
232
233 static char *def_argv[] = { "/bin/login", "-p", NULL };
234
235 static void conf_default_login(struct conf_option *opt)
236 {
237         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
238
239         opt->type->free(opt);
240         conf->login = false;
241         conf->argv = def_argv;
242 }
243
244 static void conf_free_login(struct conf_option *opt)
245 {
246         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
247
248         if (conf->argv != def_argv)
249                 free(conf->argv);
250         conf->argv = NULL;
251         conf->login = false;
252 }
253
254 static int conf_parse_login(struct conf_option *opt, bool on, const char *arg)
255 {
256         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
257
258         opt->type->free(opt);
259         conf->login = on;
260         return 0;
261 }
262
263 static int conf_copy_login(struct conf_option *opt,
264                            const struct conf_option *src)
265 {
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);
268         int ret;
269         char **t;
270
271         if (s->argv) {
272                 ret = shl_dup_array(&t, s->argv);
273                 if (ret)
274                         return ret;
275         } else {
276                 t = NULL;
277         }
278
279         opt->type->free(opt);
280         conf->argv = t;
281         conf->login = s->login;
282         return 0;
283 }
284
285 static const struct conf_type conf_login = {
286         .flags = 0,
287         .set_default = conf_default_login,
288         .free = conf_free_login,
289         .parse = conf_parse_login,
290         .copy = conf_copy_login,
291 };
292
293 static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
294                             int idx)
295 {
296         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
297         int ret = 0;
298         char **t;
299
300         /* parse "--login [...] -- args" arguments */
301         if (argv && conf->login) {
302                 if (idx >= argc) {
303                         fprintf(stderr, "Arguments for --login missing\n");
304                         return -EFAULT;
305                 }
306
307                 ret = shl_dup_array_size(&t, &argv[idx], argc - idx);
308                 if (ret)
309                         return ret;
310
311                 conf->argv = t;
312                 ret = argc - idx;
313         } else if (!conf->argv) {
314                 ret = shl_dup_array_size(&t, def_argv,
315                                          sizeof(def_argv) / sizeof(*def_argv));
316                 if (ret)
317                         return ret;
318
319                 conf->argv = t;
320         }
321
322         return ret;
323 }
324
325 static int file_login(struct conf_option *opt, bool on, const char *arg)
326 {
327         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
328         char **t;
329         unsigned int size;
330         int ret;
331
332         if (!arg) {
333                 log_error("no arguments for 'login' config-option");
334                 return -EFAULT;
335         }
336
337         ret = shl_split_string(arg, &t, &size, ' ', false);
338         if (ret) {
339                 log_error("cannot split 'login' config-option argument");
340                 return ret;
341         }
342
343         if (size < 1) {
344                 log_error("empty argument given for 'login' config-option");
345                 return -EFAULT;
346         }
347
348         opt->type->free(opt);
349         conf->login = on;
350         conf->argv = t;
351         return 0;
352 }
353
354 /*
355  * GPU selection type
356  * The GPU selection mode is a simple string to enum parser.
357  */
358
359 static void conf_default_gpus(struct conf_option *opt)
360 {
361         conf_uint.set_default(opt);
362 }
363
364 static void conf_free_gpus(struct conf_option *opt)
365 {
366         conf_uint.free(opt);
367 }
368
369 static int conf_parse_gpus(struct conf_option *opt, bool on, const char *arg)
370 {
371         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, gpus);
372         unsigned int mode;
373
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;
380         } else {
381                 log_error("invalid GPU selection mode --gpus='%s'", arg);
382                 return -EFAULT;
383         }
384
385         opt->type->free(opt);
386         conf->gpus = mode;
387         return 0;
388 }
389
390 static int conf_copy_gpus(struct conf_option *opt,
391                           const struct conf_option *src)
392 {
393         return conf_uint.copy(opt, src);
394 }
395
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,
402 };
403
404 /*
405  * Custom Afterchecks
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.
409  */
410
411 static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
412                             int idx)
413 {
414         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, debug);
415
416         /* --debug implies --verbose */
417         if (conf->debug)
418                 conf->verbose = 1;
419
420         return 0;
421 }
422
423 static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
424                            int idx)
425 {
426         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, help);
427
428         /* exit after printing --help information */
429         if (conf->help) {
430                 print_help();
431                 conf->exit = true;
432         }
433
434         return 0;
435 }
436
437 static int aftercheck_drm(struct conf_option *opt, int argc, char **argv,
438                           int idx)
439 {
440         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, drm);
441
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. */
449         if (conf->drm) {
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");
453                         conf->drm = false;
454                 }
455         }
456
457         return 0;
458 }
459
460 static int aftercheck_vt(struct conf_option *opt, int argc, char **argv,
461                          int idx)
462 {
463         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, vt);
464
465         if (!conf->vt || conf->seat_config)
466                 return 0;
467
468         if (!kmscon_conf_is_single_seat(conf)) {
469                 log_error("you cannot use global --vt if --seats contains not exactly one seat");
470                 return -EFAULT;
471         }
472
473         return 0;
474 }
475
476 static int aftercheck_listen(struct conf_option *opt, int argc, char **argv,
477                              int idx)
478 {
479         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, listen);
480         int ret = -EFAULT;
481
482         if (conf->listen)
483                 return 0;
484
485         if (conf->cdev_session)
486                 log_error("you can use --cdev-session only in combination with --listen");
487         else
488                 ret = 0;
489
490         return ret;
491 }
492
493 /*
494  * Default Values
495  * We use static default values to avoid allocating memory for these. This
496  * speeds up config-parser considerably.
497  */
498
499 static char *def_seats[] = { "current", NULL };
500
501 static struct conf_grab def_grab_scroll_up =
502                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Up);
503
504 static struct conf_grab def_grab_scroll_down =
505                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Down);
506
507 static struct conf_grab def_grab_page_up =
508                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Prior);
509
510 static struct conf_grab def_grab_page_down =
511                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Next);
512
513 static struct conf_grab def_grab_session_next =
514                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Right);
515
516 static struct conf_grab def_grab_session_prev =
517                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Left);
518
519 static struct conf_grab def_grab_session_dummy =
520                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Escape);
521
522 static struct conf_grab def_grab_session_close =
523                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_BackSpace);
524
525 static struct conf_grab def_grab_terminal_new =
526                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Return);
527
528 int kmscon_conf_new(struct conf_ctx **out)
529 {
530         struct conf_ctx *ctx;
531         int ret;
532         struct kmscon_conf_t *conf;
533
534         if (!out)
535                 return -EINVAL;
536
537         conf = malloc(sizeof(*conf));
538         if (!conf)
539                 return -ENOMEM;
540         memset(conf, 0, sizeof(*conf));
541
542         struct conf_option options[] = {
543                 /* Global 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),
550
551                 /* Seat Options */
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),
555
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),
561
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),
568
569                 /* Input Options */
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),
576
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),
587
588                 /* Video Options */
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),
594
595                 /* Font Options */
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),
600         };
601
602         ret = conf_ctx_new(&ctx, options, sizeof(options) / sizeof(*options),
603                            conf);
604         if (ret) {
605                 free(conf);
606                 return ret;
607         }
608
609         *out = ctx;
610         return 0;
611 }
612
613 void kmscon_conf_free(struct conf_ctx *ctx)
614 {
615         void *conf;
616         if (!ctx)
617                 return;
618
619         conf = conf_ctx_get_mem(ctx);
620         conf_ctx_free(ctx);
621         free(conf);
622 }
623
624 int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv)
625 {
626         int ret;
627         struct kmscon_conf_t *conf;
628
629         if (!ctx)
630                 return -EINVAL;
631
632         conf = conf_ctx_get_mem(ctx);
633         conf->seat_config = false;
634
635         ret = conf_ctx_parse_argv(ctx, argc, argv);
636         if (ret)
637                 return ret;
638
639         if (conf->exit)
640                 return 0;
641
642         if (!conf->debug && !conf->verbose && conf->silent)
643                 log_set_config(&LOG_CONFIG_WARNING(0, 0, 0, 0));
644         else
645                 log_set_config(&LOG_CONFIG_INFO(conf->debug,
646                                                 conf->verbose));
647
648         log_print_init("kmscon");
649
650         ret = conf_ctx_parse_file(ctx, "%s/kmscon.conf", conf->configdir);
651         if (ret)
652                 return ret;
653
654         return 0;
655 }
656
657 int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main,
658                           const char *seat)
659 {
660         int ret;
661         struct kmscon_conf_t *conf;
662
663         if (!ctx || !main || !seat)
664                 return -EINVAL;
665
666         log_debug("parsing seat configuration for seat %s", seat);
667
668         conf = conf_ctx_get_mem(ctx);
669         conf->seat_config = true;
670
671         ret = conf_ctx_parse_ctx(ctx, main);
672         if (ret)
673                 return ret;
674
675         ret = conf_ctx_parse_file(ctx, "%s/%s.seat.conf", conf->configdir,
676                                   seat);
677         if (ret)
678                 return ret;
679
680         return 0;
681 }