kmscon: implement per-seat configuration

Sorry for the huge commit, but this reworks the whole configuration
handler. We now provide conf_ctx contexts which contain a pointer to the
backing storage and the config-options that are used.

It is also possible to copy config-options now. So we can use the
main-config as default value for seat-configurations.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-10-19 16:15:34 +02:00
parent 228a99d4bc
commit 06c6e56d4c
9 changed files with 925 additions and 542 deletions

1009
src/conf.c

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,67 @@
#include <stdlib.h>
#include "shl_misc.h"
/* parsed types */
struct conf_type;
struct conf_option;
struct conf_ctx;
/* Conf Types */
#define CONF_HAS_ARG 0x0001
struct conf_type {
unsigned int flags;
void (*set_default) (struct conf_option *opt);
void (*free) (struct conf_option *opt);
int (*parse) (struct conf_option *opt, bool on, const char *arg);
int (*copy) (struct conf_option *opt, const struct conf_option *src);
};
/*
* Bool: expects "mem" to point to a "bool"
* Initial state is "false".
*/
extern const struct conf_type conf_bool;
/*
* Int: expects "mem" to point to an "int"
* Initial state is "0".
*/
extern const struct conf_type conf_int;
/*
* Uint: expects "mem" to point to an "uint"
* Initial state is "0"
*/
extern const struct conf_type conf_uint;
/*
* String: expects "mem" to point to an "char*"
* Initial state is NULL. Memory is allocated by the parser and a string is
* always zero-terminated.
*/
extern const struct conf_type conf_string;
/*
* Stringlist: expects "mem" to point to an "char**"
* Initial state is NULL. The list is NULL-terminated and each entry is a
* zero-terminated string. Memory is allocated by the parser.
*/
extern const struct conf_type conf_string_list;
/*
* Grabs: expects "mem" to point to an "struct conf_grab*"
* Initial state is NULL. See below for the type definition. The memory for the
* type is allocated by the parser.
* Two small helpers are available to ease the use.
*/
extern const struct conf_type conf_grab;
struct conf_grab {
unsigned int num;
@ -63,25 +123,36 @@ static inline bool conf_grab_matches(const struct conf_grab *grab,
.keysyms = (uint32_t*[]) { (uint32_t[]) { (_sym) } }, \
}
/* configuration parser */
/*
* Configuration Context
* A configuration context is initialized with an array of config-options and
* then can be used to parse different sources. The backing memory is managed by
* the user, not by this context.
* All options are set to their default values on startup and reset.
*/
struct conf_type;
struct conf_option;
struct conf_ctx;
int conf_ctx_new(struct conf_ctx **out, const struct conf_option *opts,
size_t onum, void *mem);
void conf_ctx_free(struct conf_ctx *ctx);
void conf_ctx_reset(struct conf_ctx *ctx);
void *conf_ctx_get_mem(struct conf_ctx *ctx);
int conf_ctx_parse_ctx(struct conf_ctx *ctx, const struct conf_ctx *src);
int conf_ctx_parse_argv(struct conf_ctx *ctx, int argc, char **argv);
int conf_ctx_parse_file(struct conf_ctx *ctx, const char *format, ...);
/*
* Configuration Options
* A configuration option specifies the name of the option, the type, the
* backing memory, the default value and more. Each option is represented by
* this structure.
*/
/* config option flags */
#define CONF_DONE 0x0001
#define CONF_LOCKED 0x0002
/* config type flags */
#define CONF_HAS_ARG 0x0001
struct conf_type {
unsigned int flags;
int (*parse) (struct conf_option *opt, bool on, const char *arg);
void (*free) (struct conf_option *opt);
void (*set_default) (struct conf_option *opt);
};
struct conf_option {
unsigned int flags;
char short_name;
@ -144,32 +215,4 @@ struct conf_option {
_mem, \
_def)
void conf_free_value(struct conf_option *opt);
int conf_parse_bool(struct conf_option *opt, bool on, const char *arg);
void conf_default_bool(struct conf_option *opt);
int conf_parse_int(struct conf_option *opt, bool on, const char *arg);
void conf_default_int(struct conf_option *opt);
int conf_parse_uint(struct conf_option *opt, bool on, const char *arg);
void conf_default_uint(struct conf_option *opt);
int conf_parse_string(struct conf_option *opt, bool on, const char *arg);
void conf_default_string(struct conf_option *opt);
int conf_parse_string_list(struct conf_option *opt, bool on, const char *arg);
void conf_default_string_list(struct conf_option *opt);
int conf_parse_grab(struct conf_option *opt, bool on, const char *arg);
void conf_default_grab(struct conf_option *opt);
extern const struct conf_type conf_bool;
extern const struct conf_type conf_int;
extern const struct conf_type conf_uint;
extern const struct conf_type conf_string;
extern const struct conf_type conf_string_list;
extern const struct conf_type conf_grab;
void conf_free(struct conf_option *opts, size_t len);
int conf_parse_argv(struct conf_option *opts, size_t len,
int argc, char **argv);
int conf_parse_file(struct conf_option *opts, size_t len, const char *path);
int conf_parse_file_f(struct conf_option *opts, size_t len,
const char *format, ...);
#endif /* CONFIG_CONFIG_H */

View File

@ -38,8 +38,6 @@
#include "shl_misc.h"
struct kmscon_conf_t kmscon_conf;
static struct conf_option *kmscon_opt;
static size_t kmscon_onum;
static void print_help()
{
@ -149,6 +147,21 @@ static void print_help()
*/
}
static void conf_default_vt(struct conf_option *opt)
{
opt->type->free(opt);
*(void**)opt->mem = opt->def;
}
static void conf_free_vt(struct conf_option *opt)
{
if (*(void**)opt->mem) {
if (*(void**)opt->mem != opt->def)
free(*(void**)opt->mem);
*(void**)opt->mem = NULL;
}
}
static int conf_parse_vt(struct conf_option *opt, bool on, const char *arg)
{
static const char prefix[] = "/dev/";
@ -178,18 +191,35 @@ static int conf_parse_vt(struct conf_option *opt, bool on, const char *arg)
return 0;
}
static void conf_default_vt(struct conf_option *opt)
static int conf_copy_vt(struct conf_option *opt,
const struct conf_option *src)
{
*(void**)opt->mem = opt->def;
char *val;
if (!*(void**)src->mem) {
val = NULL;
} else {
val = strdup(*(void**)src->mem);
if (!val)
return -ENOMEM;
}
opt->type->free(opt);
*(void**)opt->mem = val;
return 0;
}
static const struct conf_type conf_vt = {
.flags = CONF_HAS_ARG,
.parse = conf_parse_vt,
.free = conf_free_value,
.set_default = conf_default_vt,
.free = conf_free_vt,
.parse = conf_parse_vt,
.copy = conf_copy_vt,
};
#define KMSCON_CONF_FROM_FIELD(_mem, _name) \
shl_offsetof((_mem), struct kmscon_conf_t, _name)
static int aftercheck_debug(struct conf_option *opt, int argc, char **argv,
int idx)
{
@ -281,20 +311,12 @@ static struct conf_grab def_grab_session_close =
static struct conf_grab def_grab_terminal_new =
CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_ALT_MASK, XKB_KEY_Return);
void kmscon_conf_init(struct kmscon_conf_t *conf)
int kmscon_conf_new(struct conf_ctx **out, struct kmscon_conf_t *conf)
{
if (!conf)
return;
struct conf_ctx *ctx;
int ret;
memset(conf, 0, sizeof(*conf));
}
int kmscon_conf_new(struct conf_option **out, size_t *size_out,
struct kmscon_conf_t *conf)
{
struct conf_option *opt;
if (!out || !size_out || !conf)
if (!out || !conf)
return -EINVAL;
struct conf_option options[] = {
@ -349,71 +371,47 @@ int kmscon_conf_new(struct conf_option **out, size_t *size_out,
CONF_OPTION_UINT(0, "font-dpi", NULL, &conf->font_ppi, 96),
};
opt = malloc(sizeof(options));
if (!opt)
return -ENOMEM;
memcpy(opt, options, sizeof(options));
*out = opt;
*size_out = sizeof(options) / sizeof(*options);
return 0;
}
void kmscon_conf_free(struct conf_option *opt, size_t onum)
{
if (!opt || !onum)
return;
conf_free(opt, onum);
free(opt);
}
int kmscon_conf_parse_argv(struct conf_option *opt, size_t onum,
int argc, char **argv)
{
if (!opt || !onum)
return -EINVAL;
return conf_parse_argv(opt, onum, argc, argv);
}
int kmscon_load_config(int argc, char **argv)
{
int ret;
if (!kmscon_opt || !kmscon_onum) {
kmscon_conf_init(&kmscon_conf);
ret = kmscon_conf_new(&kmscon_opt, &kmscon_onum, &kmscon_conf);
if (ret)
return ret;
}
ret = kmscon_conf_parse_argv(kmscon_opt, kmscon_onum, argc, argv);
ret = conf_ctx_new(&ctx, options, sizeof(options) / sizeof(*options),
conf);
if (ret)
return ret;
if (KMSCON_CONF_BOOL(exit))
*out = ctx;
return 0;
}
void kmscon_conf_free(struct conf_ctx *ctx)
{
conf_ctx_free(ctx);
}
int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv)
{
int ret;
ret = conf_ctx_parse_argv(ctx, argc, argv);
if (ret)
return ret;
if (kmscon_conf.exit)
return 0;
if (!KMSCON_CONF_BOOL(debug) && !KMSCON_CONF_BOOL(verbose) &&
KMSCON_CONF_BOOL(silent))
if (!kmscon_conf.debug && !kmscon_conf.verbose && kmscon_conf.silent)
log_set_config(&LOG_CONFIG_WARNING(0, 0, 0, 0));
else
log_set_config(&LOG_CONFIG_INFO(KMSCON_CONF_BOOL(debug),
KMSCON_CONF_BOOL(verbose)));
log_set_config(&LOG_CONFIG_INFO(kmscon_conf.debug,
kmscon_conf.verbose));
log_print_init("kmscon");
ret = conf_parse_file_f(kmscon_opt, kmscon_onum,
"/etc/kmscon/kmscon.conf");
ret = conf_ctx_parse_file(ctx, "/etc/kmscon/kmscon.conf");
if (ret)
return ret;
/* TODO: Deprecated! Remove this! */
if (!access("/etc/kmscon.conf", F_OK)) {
log_error("/etc/kmscon.conf is deprecated, please use /etc/kmscon/kmscon.conf");
ret = conf_parse_file_f(kmscon_opt, kmscon_onum,
"/etc/kmscon.conf");
ret = conf_ctx_parse_file(ctx, "/etc/kmscon.conf");
if (ret)
return ret;
}
@ -421,12 +419,23 @@ int kmscon_load_config(int argc, char **argv)
return 0;
}
void kmscon_free_config(void)
int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main,
const char *seat)
{
if (!kmscon_opt || !kmscon_onum)
return;
int ret;
kmscon_conf_free(kmscon_opt, kmscon_onum);
kmscon_opt = NULL;
kmscon_onum = 0;
if (!ctx || !main || !seat)
return -EINVAL;
log_debug("parsing seat configuration for seat %s", seat);
ret = conf_ctx_parse_ctx(ctx, main);
if (ret)
return ret;
ret = conf_ctx_parse_file(ctx, "/etc/kmscon/%s.seat.conf", seat);
if (ret)
return ret;
return 0;
}

View File

@ -131,32 +131,10 @@ struct kmscon_conf_t {
extern struct kmscon_conf_t kmscon_conf;
void kmscon_conf_init(struct kmscon_conf_t *conf);
int kmscon_conf_new(struct conf_option **out, size_t *size_out,
struct kmscon_conf_t *conf);
void kmscon_conf_free(struct conf_option *opt, size_t onum);
int kmscon_conf_parse_argv(struct conf_option *opt, size_t onum,
int argc, char **argv);
int kmscon_load_config(int argc, char **argv);
void kmscon_free_config(void);
#define KMSCON_CONF_FROM_FIELD(_ptr, _field) \
shl_offsetof(_ptr, struct kmscon_conf_t, _field)
#define KMSCON_CONF_OFFSET(_name) \
offsetof(struct kmscon_conf_t, _name)
#define KMSCON_CONF(_name, _type) \
(*((_type*)(((char*)&kmscon_conf) + KMSCON_CONF_OFFSET(_name))))
#define KMSCON_CONF_BOOL(_name) \
KMSCON_CONF(_name, bool)
#define KMSCON_CONF_UINT(_name) \
KMSCON_CONF(_name, unsigned int)
#define KMSCON_CONF_STRING(_name) \
KMSCON_CONF(_name, char*)
#define KMSCON_CONF_GRAB(_name) \
KMSCON_CONF(_name, struct conf_grab*)
#define KMSCON_CONF_STRINGLIST(_name) \
KMSCON_CONF(_name, char**)
int kmscon_conf_new(struct conf_ctx **out, struct kmscon_conf_t *conf);
void kmscon_conf_free(struct conf_ctx *ctx);
int kmscon_conf_load_main(struct conf_ctx *ctx, int argc, char **argv);
int kmscon_conf_load_seat(struct conf_ctx *ctx, const struct conf_ctx *main,
const char *seat);
#endif /* KMSCON_MAIN_H */

View File

@ -56,10 +56,14 @@ struct app_seat {
bool awake;
char *name;
struct kmscon_seat *seat;
struct conf_ctx *conf_ctx;
struct kmscon_conf_t *conf;
struct shl_dlist videos;
};
struct kmscon_app {
struct conf_ctx *conf;
struct ev_eloop *eloop;
struct ev_eloop *vt_eloop;
unsigned int vt_exit_count;
@ -113,11 +117,11 @@ static int app_seat_new(struct kmscon_app *app, struct app_seat **out,
bool found;
found = false;
if (KMSCON_CONF_BOOL(all_seats)) {
if (kmscon_conf.all_seats) {
found = true;
} else {
for (i = 0; KMSCON_CONF_STRINGLIST(seats)[i]; ++i) {
if (!strcmp(KMSCON_CONF_STRINGLIST(seats)[i], sname)) {
for (i = 0; kmscon_conf.seats[i]; ++i) {
if (!strcmp(kmscon_conf.seats[i], sname)) {
found = true;
break;
}
@ -148,13 +152,15 @@ static int app_seat_new(struct kmscon_app *app, struct app_seat **out,
goto err_free;
}
ret = kmscon_seat_new(&seat->seat, app->eloop, app->vtm, sname,
app_seat_event, seat);
ret = kmscon_seat_new(&seat->seat, app->conf, app->eloop, app->vtm,
sname, app_seat_event, seat);
if (ret) {
log_error("cannot create seat object on seat %s: %d",
sname, ret);
goto err_name;
}
seat->conf_ctx = kmscon_seat_get_conf(seat->seat);
seat->conf = conf_ctx_get_mem(seat->conf_ctx);
shl_dlist_link(&app->seats, &seat->list);
*out = seat;
@ -202,7 +208,7 @@ static int app_seat_add_video(struct app_seat *seat,
unsigned int mode;
struct app_video *vid;
if (KMSCON_CONF_BOOL(fbdev)) {
if (seat->conf->fbdev) {
if (type != UTERM_MONITOR_FBDEV &&
type != UTERM_MONITOR_FBDEV_DRM) {
log_info("ignoring video device %s on seat %s as it is not an fbdev device",
@ -237,7 +243,7 @@ static int app_seat_add_video(struct app_seat *seat,
}
if (type == UTERM_MONITOR_DRM) {
if (KMSCON_CONF_BOOL(dumb))
if (seat->conf->dumb)
mode = UTERM_VIDEO_DUMB;
else
mode = UTERM_VIDEO_DRM;
@ -398,10 +404,11 @@ static void destroy_app(struct kmscon_app *app)
ev_eloop_unref(app->eloop);
}
static int setup_app(struct kmscon_app *app)
static int setup_app(struct kmscon_app *app, struct conf_ctx *conf)
{
int ret;
app->conf = conf;
shl_dlist_init(&app->seats);
ret = ev_eloop_new(&app->eloop, log_llog);
@ -455,16 +462,23 @@ err_app:
int main(int argc, char **argv)
{
int ret;
struct conf_ctx *conf;
struct kmscon_app app;
ret = kmscon_load_config(argc, argv);
ret = kmscon_conf_new(&conf, &kmscon_conf);
if (ret) {
log_error("cannot parse configuration: %d", ret);
log_error("cannot create configuration: %d", ret);
goto err_out;
}
if (KMSCON_CONF_BOOL(exit)) {
kmscon_free_config();
ret = kmscon_conf_load_main(conf, argc, argv);
if (ret) {
log_error("cannot load configuration: %d", ret);
goto err_conf;
}
if (kmscon_conf.exit) {
kmscon_conf_free(conf);
return 0;
}
@ -472,18 +486,18 @@ int main(int argc, char **argv)
kmscon_text_load_all();
memset(&app, 0, sizeof(app));
ret = setup_app(&app);
ret = setup_app(&app, conf);
if (ret)
goto err_unload;
if (KMSCON_CONF_BOOL(switchvt)) {
if (kmscon_conf.switchvt) {
log_debug("activating VTs during startup");
uterm_vt_master_activate_all(app.vtm);
}
ev_eloop_run(app.eloop, -1);
if (KMSCON_CONF_BOOL(switchvt)) {
if (kmscon_conf.switchvt) {
/* The VT subsystem needs to acknowledge the VT-leave so if it
* returns -EINPROGRESS we need to wait for the VT-leave SIGUSR2
* signal to arrive. Therefore, we use a separate eloop object
@ -509,9 +523,9 @@ int main(int argc, char **argv)
err_unload:
kmscon_text_unload_all();
kmscon_font_unload_all();
err_conf:
kmscon_conf_free(conf);
err_out:
kmscon_free_config();
if (ret)
log_err("cannot initialize kmscon, errno %d: %s",
ret, strerror(-ret));

View File

@ -67,6 +67,9 @@ struct kmscon_seat {
struct ev_eloop *eloop;
struct uterm_vt_master *vtm;
struct kmscon_conf_t conf;
struct conf_ctx *conf_ctx;
char *name;
bool awake;
struct uterm_input *input;
@ -355,6 +358,7 @@ static void seat_input_event(struct uterm_input *input,
}
int kmscon_seat_new(struct kmscon_seat **out,
struct conf_ctx *main_conf,
struct ev_eloop *eloop,
struct uterm_vt_master *vtm,
const char *seatname,
@ -386,6 +390,19 @@ int kmscon_seat_new(struct kmscon_seat **out,
goto err_free;
}
ret = kmscon_conf_new(&seat->conf_ctx, &seat->conf);
if (ret) {
log_error("cannot create seat configuration object: %d", ret);
goto err_name;
}
ret = kmscon_conf_load_seat(seat->conf_ctx, main_conf, seat->name);
if (ret) {
log_error("cannot parse seat configuration on seat %s: %d",
seat->name, ret);
goto err_conf;
}
ret = uterm_input_new(&seat->input, seat->eloop,
kmscon_conf.xkb_layout,
kmscon_conf.xkb_variant,
@ -393,7 +410,7 @@ int kmscon_seat_new(struct kmscon_seat **out,
kmscon_conf.xkb_repeat_delay,
kmscon_conf.xkb_repeat_rate);
if (ret)
goto err_name;
goto err_conf;
ret = uterm_input_register_cb(seat->input, seat_input_event, seat);
if (ret)
@ -445,6 +462,8 @@ err_input_cb:
uterm_input_unregister_cb(seat->input, seat_input_event, seat);
err_input:
uterm_input_unref(seat->input);
err_conf:
kmscon_conf_free(seat->conf_ctx);
err_name:
free(seat->name);
err_free:
@ -477,6 +496,7 @@ void kmscon_seat_free(struct kmscon_seat *seat)
uterm_vt_deallocate(seat->vt);
uterm_input_unregister_cb(seat->input, seat_input_event, seat);
uterm_input_unref(seat->input);
kmscon_conf_free(seat->conf_ctx);
free(seat->name);
uterm_vt_master_unref(seat->vtm);
ev_eloop_unref(seat->eloop);
@ -549,6 +569,14 @@ struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat)
return seat->eloop;
}
struct conf_ctx *kmscon_seat_get_conf(struct kmscon_seat *seat)
{
if (!seat)
return NULL;
return seat->conf_ctx;
}
int kmscon_seat_register_session(struct kmscon_seat *seat,
struct kmscon_session **out,
kmscon_session_cb_t cb,

View File

@ -34,6 +34,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include "conf.h"
#include "eloop.h"
#include "uterm.h"
@ -63,6 +64,7 @@ typedef void (*kmscon_session_cb_t) (struct kmscon_session *session,
void *data);
int kmscon_seat_new(struct kmscon_seat **out,
struct conf_ctx *main_conf,
struct ev_eloop *eloop,
struct uterm_vt_master *vtm,
const char *seatname,
@ -80,6 +82,7 @@ void kmscon_seat_remove_input(struct kmscon_seat *seat, const char *node);
const char *kmscon_seat_get_name(struct kmscon_seat *seat);
struct uterm_input *kmscon_seat_get_input(struct kmscon_seat *seat);
struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat);
struct conf_ctx *kmscon_seat_get_conf(struct kmscon_seat *seat);
int kmscon_seat_register_session(struct kmscon_seat *seat,
struct kmscon_session **out,

View File

@ -39,6 +39,7 @@
#include "eloop.h"
#include "log.h"
#include "pty.h"
#include "shl_misc.h"
#include "shl_ring.h"
#define LOG_SUBSYSTEM "pty"
@ -141,35 +142,18 @@ int kmscon_pty_set_term(struct kmscon_pty *pty, const char *term)
int kmscon_pty_set_argv(struct kmscon_pty *pty, char **argv)
{
char **t, *off;
unsigned int size, i;
char **t;
int ret;
if (!pty || !argv || !*argv || !**argv)
return -EINVAL;
size = 0;
for (i = 0; argv[i]; ++i)
size += strlen(argv[i]) + 1;
++i;
ret = shl_dup_array(&t, argv);
if (ret)
return ret;
size += i * sizeof(char*);
t = malloc(size);
if (!t)
return -ENOMEM;
free(pty->argv);
pty->argv = t;
off = (char*)t + i * sizeof(char*);
while (*argv) {
*t++ = off;
for (i = 0; argv[0][i]; ++i)
*off++ = argv[0][i];
*off++ = 0;
argv++;
}
*t = NULL;
return 0;
}

View File

@ -140,6 +140,39 @@ static inline int shl_split_string(const char *arg, char ***out,
return 0;
}
static inline int shl_dup_array(char ***out, char **argv)
{
char **t, *off;
unsigned int size, i;
if (!out || !argv)
return -EINVAL;
size = 0;
for (i = 0; argv[i]; ++i)
size += strlen(argv[i]) + 1;
++i;
size += i * sizeof(char*);
t = malloc(size);
if (!t)
return -ENOMEM;
*out = t;
off = (char*)t + i * sizeof(char*);
while (*argv) {
*t++ = off;
for (i = 0; argv[0][i]; ++i)
*off++ = argv[0][i];
*off++ = 0;
argv++;
}
*t = NULL;
return 0;
}
/* TODO: xkbcommon should provide these flags!
* We currently copy them into each library API we use so we need to keep
* them in sync. Currently, they're used in uterm-input and tsm-vte. */