kmscon: remove cdev sessions
[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                 "\n"
83                 "Terminal Options:\n"
84                 "\t-l, --login                 [/bin/login -p]\n"
85                 "\t                              Start the given login process instead\n"
86                 "\t                              of the default process; all arguments\n"
87                 "\t                              following '--' will be be parsed as\n"
88                 "\t                              argv to this process. No more options\n"
89                 "\t                              after '--' will be parsed so use it at\n"
90                 "\t                              the end of the argument string\n"
91                 "\t-t, --term <TERM>           [xterm-256color]\n"
92                 "\t                              Value of the TERM environment variable\n"
93                 "\t                              for the child process\n"
94                 "\t    --reset-env             [on]\n"
95                 "\t                              Reset environment before running child\n"
96                 "\t                              process\n"
97                 "\t    --palette <name>        [default]\n"
98                 "\t                              Select the used color palette\n"
99                 "\t    --sb-size <num>         [1000]\n"
100                 "\t                              Size of the scrollback-buffer in lines\n"
101                 "\n"
102                 "Input Options:\n"
103                 "\t    --xkb-model <model>        [-]  Set XkbModel for input devices\n"
104                 "\t    --xkb-layout <layout>      [-]  Set XkbLayout for input devices\n"
105                 "\t    --xkb-variant <variant>    [-]  Set XkbVariant for input devices\n"
106                 "\t    --xkb-options <options>    [-]  Set XkbOptions for input devices\n"
107                 "\t    --xkb-keymap <FILE>        [-]  Use a predefined keymap for\n"
108                 "\t                                    input devices\n"
109                 "\t    --xkb-repeat-delay <msecs> [250]\n"
110                 "\t                                 Initial delay for key-repeat in ms\n"
111                 "\t    --xkb-repeat-rate <msecs>  [50]\n"
112                 "\t                                 Delay between two key-repeats in ms\n"
113                 "\n"
114                 "Grabs / Keyboard-Shortcuts:\n"
115                 "\t    --grab-scroll-up <grab>     [<Shift>Up]\n"
116                 "\t                                  Shortcut to scroll up\n"
117                 "\t    --grab-scroll-down <grab>   [<Shift>Down]\n"
118                 "\t                                  Shortcut to scroll down\n"
119                 "\t    --grab-page-up <grab>       [<Shift>Prior]\n"
120                 "\t                                  Shortcut to scroll page up\n"
121                 "\t    --grab-page-down <grab>     [<Shift>Next]\n"
122                 "\t                                  Shortcut to scroll page down\n"
123                 "\t    --grab-zoom-in <grab>       [<Ctrl>Plus]\n"
124                 "\t                                  Shortcut to increase font size\n"
125                 "\t    --grab-zoom-out <grab>      [<Ctrl>Minus]\n"
126                 "\t                                  Shortcut to decrease font size\n"
127                 "\t    --grab-session-next <grab>  [<Ctrl><Logo>Right]\n"
128                 "\t                                  Switch to next session\n"
129                 "\t    --grab-session-prev <grab>  [<Ctrl><Logo>Left]\n"
130                 "\t                                  Switch to previous session\n"
131                 "\t    --grab-session-dummy <grab> [<Ctrl><Logo>Escape]\n"
132                 "\t                                  Switch to dummy session\n"
133                 "\t    --grab-session-close <grab> [<Ctrl><Logo>BackSpace]\n"
134                 "\t                                  Close current session\n"
135                 "\t    --grab-terminal-new <grab>  [<Ctrl><Logo>Return]\n"
136                 "\t                                  Create new terminal session\n"
137                 "\n"
138                 "Video Options:\n"
139                 "\t    --drm                   [on]    Use DRM if available\n"
140                 "\t    --hwaccel               [off]   Use 3D hardware-acceleration if\n"
141                 "\t                                    available\n"
142                 "\t    --gpus={all,aux,primary}[all]   GPU selection mode\n"
143                 "\t    --render-engine <eng>   [-]     Console renderer\n"
144                 "\t    --render-timing         [off]   Print renderer timing information\n"
145                 "\n"
146                 "Font Options:\n"
147                 "\t    --font-engine <engine>  [pango]\n"
148                 "\t                              Font engine\n"
149                 "\t    --font-size <points>    [12]\n"
150                 "\t                              Font size in points\n"
151                 "\t    --font-name <name>      [monospace]\n"
152                 "\t                              Font name\n"
153                 "\t    --font-dpi <dpi>        [96]\n"
154                 "\t                              Force DPI value for all fonts\n",
155                 "kmscon");
156         /*
157          * 80 char line:
158          *       |   10   |    20   |    30   |    40   |    50   |    60   |    70   |    80   |
159          *      "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
160          * 80 char line starting with tab:
161          *       |10|    20   |    30   |    40   |    50   |    60   |    70   |    80   |
162          *      "\t901234567890123456789012345678901234567890123456789012345678901234567890\n"
163          */
164 }
165
166 #define KMSCON_CONF_FROM_FIELD(_mem, _name) \
167         shl_offsetof((_mem), struct kmscon_conf_t, _name)
168
169 /*
170  * VT Type
171  * The --vt option is special in that it can be an integer, a string or a path.
172  * We use the string-handling of conf_string but the parser is different. See
173  * below for more information on the parser.
174  */
175
176 static void conf_default_vt(struct conf_option *opt)
177 {
178         conf_string.set_default(opt);
179 }
180
181 static void conf_free_vt(struct conf_option *opt)
182 {
183         conf_string.free(opt);
184 }
185
186 static int conf_parse_vt(struct conf_option *opt, bool on, const char *arg)
187 {
188         static const char prefix[] = "/dev/";
189         unsigned int val;
190         char *str;
191         int ret;
192
193         if (!shl_strtou(arg, &val)) {
194                 ret = asprintf(&str, "%stty%u", prefix, val);
195                 if (ret == -1)
196                         return -ENOMEM;
197         } else if (*arg && *arg != '.' && *arg != '/') {
198                 str = malloc(sizeof(prefix) + strlen(arg));
199                 if (!str)
200                         return -ENOMEM;
201
202                 strcpy(str, prefix);
203                 strcat(str, arg);
204         } else {
205                 str = strdup(arg);
206                 if (!str)
207                         return -ENOMEM;
208         }
209
210         opt->type->free(opt);
211         *(void**)opt->mem = str;
212         return 0;
213 }
214
215 static int conf_copy_vt(struct conf_option *opt,
216                         const struct conf_option *src)
217 {
218         return conf_string.copy(opt, src);
219 }
220
221 static const struct conf_type conf_vt = {
222         .flags = CONF_HAS_ARG,
223         .set_default = conf_default_vt,
224         .free = conf_free_vt,
225         .parse = conf_parse_vt,
226         .copy = conf_copy_vt,
227 };
228
229 /*
230  * Login handling
231  * The --login option is special in that it can have an unlimited number of
232  * arguments on the command-line. So on the command-line it is an boolean option
233  * that specifies whether default login or custom login is used.
234  * However, the file-parser does simple string-parsing as it does not need the
235  * special handling that the command-line does.
236  */
237
238 static char *def_argv[] = { "/bin/login", "-p", NULL };
239
240 static void conf_default_login(struct conf_option *opt)
241 {
242         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
243
244         opt->type->free(opt);
245         conf->login = false;
246         conf->argv = def_argv;
247 }
248
249 static void conf_free_login(struct conf_option *opt)
250 {
251         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
252
253         if (conf->argv != def_argv)
254                 free(conf->argv);
255         conf->argv = NULL;
256         conf->login = false;
257 }
258
259 static int conf_parse_login(struct conf_option *opt, bool on, const char *arg)
260 {
261         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
262
263         opt->type->free(opt);
264         conf->login = on;
265         return 0;
266 }
267
268 static int conf_copy_login(struct conf_option *opt,
269                            const struct conf_option *src)
270 {
271         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
272         struct kmscon_conf_t *s = KMSCON_CONF_FROM_FIELD(src->mem, login);
273         int ret;
274         char **t;
275
276         if (s->argv) {
277                 ret = shl_dup_array(&t, s->argv);
278                 if (ret)
279                         return ret;
280         } else {
281                 t = NULL;
282         }
283
284         opt->type->free(opt);
285         conf->argv = t;
286         conf->login = s->login;
287         return 0;
288 }
289
290 static const struct conf_type conf_login = {
291         .flags = 0,
292         .set_default = conf_default_login,
293         .free = conf_free_login,
294         .parse = conf_parse_login,
295         .copy = conf_copy_login,
296 };
297
298 static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
299                             int idx)
300 {
301         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
302         int ret = 0;
303         char **t;
304
305         /* parse "--login [...] -- args" arguments */
306         if (argv && conf->login) {
307                 if (idx >= argc) {
308                         fprintf(stderr, "Arguments for --login missing\n");
309                         return -EFAULT;
310                 }
311
312                 ret = shl_dup_array_size(&t, &argv[idx], argc - idx);
313                 if (ret)
314                         return ret;
315
316                 conf->argv = t;
317                 ret = argc - idx;
318         } else if (!conf->argv) {
319                 ret = shl_dup_array_size(&t, def_argv,
320                                          sizeof(def_argv) / sizeof(*def_argv));
321                 if (ret)
322                         return ret;
323
324                 conf->argv = t;
325         }
326
327         return ret;
328 }
329
330 static int file_login(struct conf_option *opt, bool on, const char *arg)
331 {
332         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
333         char **t;
334         unsigned int size;
335         int ret;
336
337         if (!arg) {
338                 log_error("no arguments for 'login' config-option");
339                 return -EFAULT;
340         }
341
342         ret = shl_split_string(arg, &t, &size, ' ', false);
343         if (ret) {
344                 log_error("cannot split 'login' config-option argument");
345                 return ret;
346         }
347
348         if (size < 1) {
349                 log_error("empty argument given for 'login' config-option");
350                 return -EFAULT;
351         }
352
353         opt->type->free(opt);
354         conf->login = on;
355         conf->argv = t;
356         return 0;
357 }
358
359 /*
360  * GPU selection type
361  * The GPU selection mode is a simple string to enum parser.
362  */
363
364 static void conf_default_gpus(struct conf_option *opt)
365 {
366         conf_uint.set_default(opt);
367 }
368
369 static void conf_free_gpus(struct conf_option *opt)
370 {
371         conf_uint.free(opt);
372 }
373
374 static int conf_parse_gpus(struct conf_option *opt, bool on, const char *arg)
375 {
376         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, gpus);
377         unsigned int mode;
378
379         if (!strcmp(arg, "all")) {
380                 mode = KMSCON_GPU_ALL;
381         } else if (!strcmp(arg, "aux") || !strcmp(arg, "auxiliary")) {
382                 mode = KMSCON_GPU_AUX;
383         } else if (!strcmp(arg, "primary") || !strcmp(arg, "single")) {
384                 mode = KMSCON_GPU_PRIMARY;
385         } else {
386                 log_error("invalid GPU selection mode --gpus='%s'", arg);
387                 return -EFAULT;
388         }
389
390         opt->type->free(opt);
391         conf->gpus = mode;
392         return 0;
393 }
394
395 static int conf_copy_gpus(struct conf_option *opt,
396                           const struct conf_option *src)
397 {
398         return conf_uint.copy(opt, src);
399 }
400
401 static const struct conf_type conf_gpus = {
402         .flags = CONF_HAS_ARG,
403         .set_default = conf_default_gpus,
404         .free = conf_free_gpus,
405         .parse = conf_parse_gpus,
406         .copy = conf_copy_gpus,
407 };
408
409 /*
410  * Custom Afterchecks
411  * Several other options have side-effects on other options. We use afterchecks
412  * to enforce these. They're pretty simple. See below.
413  * Some of them also need copy-helpers because they copy more than one value.
414  */
415
416 static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
417                             int idx)
418 {
419         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, debug);
420
421         /* --debug implies --verbose */
422         if (conf->debug)
423                 conf->verbose = 1;
424
425         return 0;
426 }
427
428 static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
429                            int idx)
430 {
431         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, help);
432
433         /* exit after printing --help information */
434         if (conf->help) {
435                 print_help();
436                 conf->exit = true;
437         }
438
439         return 0;
440 }
441
442 static int aftercheck_drm(struct conf_option *opt, int argc, char **argv,
443                           int idx)
444 {
445         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, drm);
446
447         /* disable --drm if DRM runtime support is not available */
448         /* TODO: This prevents people from booting without DRM and loading DRM
449          * drivers during runtime. However, if we remove it, we will be unable
450          * to automatically fall back to fbdev-mode.
451          * But with blacklists fbdev-mode is the default so we can run with DRM
452          * enabled but will still correctly use fbdev devices so we can then
453          * remove this check. */
454         if (conf->drm) {
455                 if (!uterm_video_available(UTERM_VIDEO_DRM3D) &&
456                     !uterm_video_available(UTERM_VIDEO_DRM2D)) {
457                         log_info("no DRM runtime support available; disabling --drm");
458                         conf->drm = false;
459                 }
460         }
461
462         return 0;
463 }
464
465 static int aftercheck_vt(struct conf_option *opt, int argc, char **argv,
466                          int idx)
467 {
468         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, vt);
469
470         if (!conf->vt || conf->seat_config)
471                 return 0;
472
473         if (!kmscon_conf_is_single_seat(conf)) {
474                 log_error("you cannot use global --vt if --seats contains not exactly one seat");
475                 return -EFAULT;
476         }
477
478         return 0;
479 }
480
481 static int aftercheck_listen(struct conf_option *opt, int argc, char **argv,
482                              int idx)
483 {
484         struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, listen);
485
486         if (conf->listen)
487                 return 0;
488
489         return 0;
490 }
491
492 /*
493  * Default Values
494  * We use static default values to avoid allocating memory for these. This
495  * speeds up config-parser considerably.
496  */
497
498 static char *def_seats[] = { "current", NULL };
499
500 static struct conf_grab def_grab_scroll_up =
501                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Up);
502
503 static struct conf_grab def_grab_scroll_down =
504                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Down);
505
506 static struct conf_grab def_grab_page_up =
507                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Prior);
508
509 static struct conf_grab def_grab_page_down =
510                 CONF_SINGLE_GRAB(SHL_SHIFT_MASK, XKB_KEY_Next);
511
512 static struct conf_grab def_grab_zoom_in =
513                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK, XKB_KEY_plus);
514
515 static struct conf_grab def_grab_zoom_out =
516                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK, XKB_KEY_minus);
517
518 static struct conf_grab def_grab_session_next =
519                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Right);
520
521 static struct conf_grab def_grab_session_prev =
522                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Left);
523
524 static struct conf_grab def_grab_session_dummy =
525                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Escape);
526
527 static struct conf_grab def_grab_session_close =
528                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_BackSpace);
529
530 static struct conf_grab def_grab_terminal_new =
531                 CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Return);
532
533 int kmscon_conf_new(struct conf_ctx **out)
534 {
535         struct conf_ctx *ctx;
536         int ret;
537         struct kmscon_conf_t *conf;
538
539         if (!out)
540                 return -EINVAL;
541
542         conf = malloc(sizeof(*conf));
543         if (!conf)
544                 return -ENOMEM;
545         memset(conf, 0, sizeof(*conf));
546
547         struct conf_option options[] = {
548                 /* Global Options */
549                 CONF_OPTION_BOOL_FULL('h', "help", aftercheck_help, NULL, NULL, &conf->help, false),
550                 CONF_OPTION_BOOL('v', "verbose", &conf->verbose, false),
551                 CONF_OPTION_BOOL_FULL(0, "debug", aftercheck_debug, NULL, NULL, &conf->debug, false),
552                 CONF_OPTION_BOOL(0, "silent", &conf->silent, false),
553                 CONF_OPTION_STRING('c', "configdir", &conf->configdir, "/etc/kmscon"),
554                 CONF_OPTION_BOOL_FULL(0, "listen", aftercheck_listen, NULL, NULL, &conf->listen, false),
555
556                 /* Seat Options */
557                 CONF_OPTION(0, 0, "vt", &conf_vt, aftercheck_vt, NULL, NULL, &conf->vt, NULL),
558                 CONF_OPTION_BOOL(0, "switchvt", &conf->switchvt, true),
559                 CONF_OPTION_STRING_LIST(0, "seats", &conf->seats, def_seats),
560
561                 /* Session Options */
562                 CONF_OPTION_UINT(0, "session-max", &conf->session_max, 50),
563                 CONF_OPTION_BOOL(0, "session-control", &conf->session_control, false),
564                 CONF_OPTION_BOOL(0, "terminal-session", &conf->terminal_session, true),
565
566                 /* Terminal Options */
567                 CONF_OPTION(0, 'l', "login", &conf_login, aftercheck_login, NULL, file_login, &conf->login, false),
568                 CONF_OPTION_STRING('t', "term", &conf->term, "xterm-256color"),
569                 CONF_OPTION_BOOL(0, "reset-env", &conf->reset_env, true),
570                 CONF_OPTION_STRING(0, "palette", &conf->palette, NULL),
571                 CONF_OPTION_UINT(0, "sb-size", &conf->sb_size, 1000),
572
573                 /* Input Options */
574                 CONF_OPTION_STRING(0, "xkb-model", &conf->xkb_model, ""),
575                 CONF_OPTION_STRING(0, "xkb-layout", &conf->xkb_layout, ""),
576                 CONF_OPTION_STRING(0, "xkb-variant", &conf->xkb_variant, ""),
577                 CONF_OPTION_STRING(0, "xkb-options", &conf->xkb_options, ""),
578                 CONF_OPTION_STRING(0, "xkb-keymap", &conf->xkb_keymap, ""),
579                 CONF_OPTION_UINT(0, "xkb-repeat-delay", &conf->xkb_repeat_delay, 250),
580                 CONF_OPTION_UINT(0, "xkb-repeat-rate", &conf->xkb_repeat_rate, 50),
581
582                 /* Grabs / Keyboard-Shortcuts */
583                 CONF_OPTION_GRAB(0, "grab-scroll-up", &conf->grab_scroll_up, &def_grab_scroll_up),
584                 CONF_OPTION_GRAB(0, "grab-scroll-down", &conf->grab_scroll_down, &def_grab_scroll_down),
585                 CONF_OPTION_GRAB(0, "grab-page-up", &conf->grab_page_up, &def_grab_page_up),
586                 CONF_OPTION_GRAB(0, "grab-page-down", &conf->grab_page_down, &def_grab_page_down),
587                 CONF_OPTION_GRAB(0, "grab-zoom-in", &conf->grab_zoom_in, &def_grab_zoom_in),
588                 CONF_OPTION_GRAB(0, "grab-zoom-out", &conf->grab_zoom_out, &def_grab_zoom_out),
589                 CONF_OPTION_GRAB(0, "grab-session-next", &conf->grab_session_next, &def_grab_session_next),
590                 CONF_OPTION_GRAB(0, "grab-session-prev", &conf->grab_session_prev, &def_grab_session_prev),
591                 CONF_OPTION_GRAB(0, "grab-session-dummy", &conf->grab_session_dummy, &def_grab_session_dummy),
592                 CONF_OPTION_GRAB(0, "grab-session-close", &conf->grab_session_close, &def_grab_session_close),
593                 CONF_OPTION_GRAB(0, "grab-terminal-new", &conf->grab_terminal_new, &def_grab_terminal_new),
594
595                 /* Video Options */
596                 CONF_OPTION_BOOL_FULL(0, "drm", aftercheck_drm, NULL, NULL, &conf->drm, true),
597                 CONF_OPTION_BOOL(0, "hwaccel", &conf->hwaccel, false),
598                 CONF_OPTION(0, 0, "gpus", &conf_gpus, NULL, NULL, NULL, &conf->gpus, KMSCON_GPU_ALL),
599                 CONF_OPTION_STRING(0, "render-engine", &conf->render_engine, NULL),
600                 CONF_OPTION_BOOL(0, "render-timing", &conf->render_timing, false),
601
602                 /* Font Options */
603                 CONF_OPTION_STRING(0, "font-engine", &conf->font_engine, "pango"),
604                 CONF_OPTION_UINT(0, "font-size", &conf->font_size, 12),
605                 CONF_OPTION_STRING(0, "font-name", &conf->font_name, "monospace"),
606                 CONF_OPTION_UINT(0, "font-dpi", &conf->font_ppi, 96),
607         };
608
609         ret = conf_ctx_new(&ctx, options, sizeof(options) / sizeof(*options),
610                            conf);
611         if (ret) {
612                 free(conf);
613                 return ret;
614         }
615
616         *out = ctx;
617         return 0;
618 }
619
620 void kmscon_conf_free(struct conf_ctx *ctx)
621 {
622         void *conf;
623         if (!ctx)
624                 return;
625
626         conf = conf_ctx_get_mem(ctx);
627         conf_ctx_free(ctx);
628         free(conf);
629 }
630
631 int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv)
632 {
633         int ret;
634         struct kmscon_conf_t *conf;
635
636         if (!ctx)
637                 return -EINVAL;
638
639         conf = conf_ctx_get_mem(ctx);
640         conf->seat_config = false;
641
642         ret = conf_ctx_parse_argv(ctx, argc, argv);
643         if (ret)
644                 return ret;
645
646         if (conf->exit)
647                 return 0;
648
649         if (!conf->debug && !conf->verbose && conf->silent)
650                 log_set_config(&LOG_CONFIG_WARNING(0, 0, 0, 0));
651         else
652                 log_set_config(&LOG_CONFIG_INFO(conf->debug,
653                                                 conf->verbose));
654
655         log_print_init("kmscon");
656
657         ret = conf_ctx_parse_file(ctx, "%s/kmscon.conf", conf->configdir);
658         if (ret)
659                 return ret;
660
661         return 0;
662 }
663
664 int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main,
665                           const char *seat)
666 {
667         int ret;
668         struct kmscon_conf_t *conf;
669
670         if (!ctx || !main || !seat)
671                 return -EINVAL;
672
673         log_debug("parsing seat configuration for seat %s", seat);
674
675         conf = conf_ctx_get_mem(ctx);
676         conf->seat_config = true;
677
678         ret = conf_ctx_parse_ctx(ctx, main);
679         if (ret)
680                 return ret;
681
682         ret = conf_ctx_parse_file(ctx, "%s/%s.seat.conf", conf->configdir,
683                                   seat);
684         if (ret)
685                 return ret;
686
687         return 0;
688 }