kmscon: rework --login handling
authorDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 23 Oct 2012 11:22:06 +0000 (13:22 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 23 Oct 2012 11:22:06 +0000 (13:22 +0200)
We implement --login as special type now. This allows us to correctly
parse it in configuration files.
We also replace the default value by /bin/login.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/kmscon_conf.c

index c984f40..43b6b9b 100644 (file)
@@ -208,40 +208,81 @@ static const struct conf_type conf_vt = {
        .copy = conf_copy_vt,
 };
 
+/*
+ * Login handling
+ * The --login option is special in that it can have an unlimited number of
+ * arguments on the command-line. So on the command-line it is an boolean option
+ * that specifies whether default login or custom login is used.
+ * However, the file-parser does simple string-parsing as it does not need the
+ * special handling that the command-line does.
+ */
 
-static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
-                           int idx)
+static char *def_argv[] = { "/bin/login", NULL };
+
+static void conf_default_login(struct conf_option *opt)
 {
-       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, debug);
+       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
 
-       /* --debug implies --verbose */
-       if (conf->debug)
-               conf->verbose = 1;
+       opt->type->free(opt);
+       conf->login = false;
+       conf->argv = def_argv;
+}
 
+static void conf_free_login(struct conf_option *opt)
+{
+       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
+
+       if (conf->argv != def_argv)
+               free(conf->argv);
+       conf->argv = NULL;
+       conf->login = false;
+}
+
+static int conf_parse_login(struct conf_option *opt, bool on, const char *arg)
+{
+       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
+
+       opt->type->free(opt);
+       conf->login = on;
        return 0;
 }
 
-static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
-                          int idx)
+static int conf_copy_login(struct conf_option *opt,
+                          const struct conf_option *src)
 {
-       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, help);
+       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
+       struct kmscon_conf_t *s = KMSCON_CONF_FROM_FIELD(src->mem, login);
+       int ret;
+       char **t;
 
-       /* exit after printing --help information */
-       if (conf->help) {
-               print_help();
-               conf->exit = true;
+       if (s->argv) {
+               ret = shl_dup_array(&t, s->argv);
+               if (ret)
+                       return ret;
+       } else {
+               t = NULL;
        }
 
+       opt->type->free(opt);
+       conf->argv = t;
+       conf->login = s->login;
        return 0;
 }
 
-static char *def_argv[] = { NULL, "-i", NULL };
+static const struct conf_type conf_login = {
+       .flags = 0,
+       .set_default = conf_default_login,
+       .free = conf_free_login,
+       .parse = conf_parse_login,
+       .copy = conf_copy_login,
+};
 
 static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
                            int idx)
 {
-       int ret;
        struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
+       int ret = 0;
+       char **t;
 
        /* parse "--login [...] -- args" arguments */
        if (argv && conf->login) {
@@ -250,32 +291,82 @@ static int aftercheck_login(struct conf_option *opt, int argc, char **argv,
                        return -EFAULT;
                }
 
-               conf->argv = &argv[idx];
+               ret = shl_dup_array_size(&t, &argv[idx], argc - idx);
+               if (ret)
+                       return ret;
+
+               conf->argv = t;
                ret = argc - idx;
        } else if (!conf->argv) {
-               def_argv[0] = getenv("SHELL") ? : _PATH_BSHELL;
-               conf->argv = def_argv;
-               ret = 0;
-       } else {
-               ret = 0;
+               ret = shl_dup_array_size(&t, def_argv,
+                                        sizeof(def_argv) / sizeof(*def_argv));
+               if (ret)
+                       return ret;
+
+               conf->argv = t;
        }
 
        return ret;
 }
 
-static int copy_login(struct conf_option *opt, const struct conf_option *src)
+static int file_login(struct conf_option *opt, bool on, const char *arg)
 {
        struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, login);
-       struct kmscon_conf_t *s = KMSCON_CONF_FROM_FIELD(src->mem, login);
-       int ret;
        char **t;
+       unsigned int size;
+       int ret;
 
-       ret = shl_dup_array(&t, s->argv);
-       if (ret)
+       if (!arg) {
+               log_error("no arguments for 'login' config-option");
+               return -EFAULT;
+       }
+
+       ret = shl_split_string(arg, &t, &size, ' ', false);
+       if (ret) {
+               log_error("cannot split 'login' config-option argument");
                return ret;
+       }
+
+       if (size < 1) {
+               log_error("empty argument given for 'login' config-option");
+               return -EFAULT;
+       }
 
-       free(conf->argv);
+       opt->type->free(opt);
+       conf->login = on;
        conf->argv = t;
+       return 0;
+}
+
+/*
+ * Custom Afterchecks
+ * Several other options have side-effects on other options. We use afterchecks
+ * to enforce these. They're pretty simple. See below.
+ * Some of them also need copy-helpers because they copy more than one value.
+ */
+
+static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
+                           int idx)
+{
+       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, debug);
+
+       /* --debug implies --verbose */
+       if (conf->debug)
+               conf->verbose = 1;
+
+       return 0;
+}
+
+static int aftercheck_help(struct conf_option *opt, int argc, char **argv,
+                          int idx)
+{
+       struct kmscon_conf_t *conf = KMSCON_CONF_FROM_FIELD(opt->mem, help);
+
+       /* exit after printing --help information */
+       if (conf->help) {
+               print_help();
+               conf->exit = true;
+       }
 
        return 0;
 }
@@ -302,6 +393,12 @@ static int copy_seats(struct conf_option *opt, const struct conf_option *src)
        return 0;
 }
 
+/*
+ * Default Values
+ * We use static default values to avoid allocating memory for these. This
+ * speeds up config-parser considerably.
+ */
+
 static char *def_seats[] = { "seat0", NULL };
 
 static struct conf_grab def_grab_scroll_up =
@@ -358,7 +455,7 @@ int kmscon_conf_new(struct conf_ctx **out)
                CONF_OPTION_UINT(0, "session-max", &conf->session_max, 50),
 
                /* Terminal Options */
-               CONF_OPTION_BOOL_FULL('l', "login", aftercheck_login, copy_login, NULL, &conf->login, false),
+               CONF_OPTION(0, 'l', "login", &conf_login, aftercheck_login, NULL, file_login, &conf->login, false),
                CONF_OPTION_STRING('t', "term", &conf->term, "xterm-256color"),
                CONF_OPTION_STRING(0, "palette", &conf->palette, NULL),
                CONF_OPTION_UINT(0, "sb-size", &conf->sb_size, 1000),