summaryrefslogtreecommitdiff
path: root/src/vconsole
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2023-03-23 22:30:30 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2023-03-24 15:07:58 +0900
commit8886ca62864f8551773ac677c79f72b506b42998 (patch)
tree729948e09fc698cae0fdc4533de6fe3707028e9b /src/vconsole
parentba54d7305590bbd5f72c799815ca177e664b1dcc (diff)
downloadsystemd-8886ca62864f8551773ac677c79f72b506b42998.tar.gz
vconsole: introduce Context and its helper functions
Fixes memleaks introduced by 01771226c202183ff447da712f43d2fad8874484 and ea575e176aac9fa8f430bb30a3e8abd8da767a10 Fixes #26945.
Diffstat (limited to 'src/vconsole')
-rw-r--r--src/vconsole/vconsole-setup.c190
1 files changed, 149 insertions, 41 deletions
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index 9a09b0d516..5b8ef74283 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -36,6 +36,149 @@
#include "terminal-util.h"
#include "virt.h"
+typedef enum VCMeta {
+ VC_KEYMAP,
+ VC_KEYMAP_TOGGLE,
+ VC_FONT,
+ VC_FONT_MAP,
+ VC_FONT_UNIMAP,
+ _VC_META_MAX,
+ _VC_META_INVALID = -EINVAL,
+} VCMeta;
+
+typedef struct Context {
+ char *config[_VC_META_MAX];
+} Context;
+
+static const char * const vc_meta_names[_VC_META_MAX] = {
+ [VC_KEYMAP] = "vconsole.keymap",
+ [VC_KEYMAP_TOGGLE] = "vconsole.keymap_toggle",
+ [VC_FONT] = "vconsole.font",
+ [VC_FONT_MAP] = "vconsole.font_map",
+ [VC_FONT_UNIMAP] = "vconsole.font_unimap",
+};
+
+/* compatibility with obsolete multiple-dot scheme */
+static const char * const vc_meta_compat_names[_VC_META_MAX] = {
+ [VC_KEYMAP_TOGGLE] = "vconsole.keymap.toggle",
+ [VC_FONT_MAP] = "vconsole.font.map",
+ [VC_FONT_UNIMAP] = "vconsole.font.unimap",
+};
+
+static const char * const vc_env_names[_VC_META_MAX] = {
+ [VC_KEYMAP] = "KEYMAP",
+ [VC_KEYMAP_TOGGLE] = "KEYMAP_TOGGLE",
+ [VC_FONT] = "FONT",
+ [VC_FONT_MAP] = "FONT_MAP",
+ [VC_FONT_UNIMAP] = "FONT_UNIMAP",
+};
+
+static void context_done(Context *c) {
+ assert(c);
+
+ for (VCMeta i = 0; i < _VC_META_MAX; i++)
+ free(c->config[i]);
+}
+
+static void context_merge_config(
+ Context *dst,
+ Context *src,
+ Context *src_compat) {
+
+ assert(dst);
+ assert(src);
+
+ for (VCMeta i = 0; i < _VC_META_MAX; i++)
+ if (src->config[i])
+ free_and_replace(dst->config[i], src->config[i]);
+ else if (src_compat && src_compat->config[i])
+ free_and_replace(dst->config[i], src_compat->config[i]);
+}
+
+static int context_read_creds(Context *c) {
+ _cleanup_(context_done) Context v = {};
+ int r;
+
+ assert(c);
+
+ r = read_credential_strings_many(
+ vc_meta_names[VC_KEYMAP], &v.config[VC_KEYMAP],
+ vc_meta_names[VC_KEYMAP_TOGGLE], &v.config[VC_KEYMAP_TOGGLE],
+ vc_meta_names[VC_FONT], &v.config[VC_FONT],
+ vc_meta_names[VC_FONT_MAP], &v.config[VC_FONT_MAP],
+ vc_meta_names[VC_FONT_UNIMAP], &v.config[VC_FONT_UNIMAP]);
+ if (r < 0) {
+ if (r != -ENXIO)
+ log_warning_errno(r, "Failed to import credentials, ignoring: %m");
+ return r;
+ }
+
+ context_merge_config(c, &v, NULL);
+ return 0;
+}
+
+static int context_read_env(Context *c) {
+ _cleanup_(context_done) Context v = {};
+ int r;
+
+ assert(c);
+
+ r = parse_env_file(
+ NULL, "/etc/vconsole.conf",
+ vc_env_names[VC_KEYMAP], &v.config[VC_KEYMAP],
+ vc_env_names[VC_KEYMAP_TOGGLE], &v.config[VC_KEYMAP_TOGGLE],
+ vc_env_names[VC_FONT], &v.config[VC_FONT],
+ vc_env_names[VC_FONT_MAP], &v.config[VC_FONT_MAP],
+ vc_env_names[VC_FONT_UNIMAP], &v.config[VC_FONT_UNIMAP]);
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_warning_errno(r, "Failed to read /etc/vconsole.conf, ignoring: %m");
+ return r;
+ }
+
+ context_merge_config(c, &v, NULL);
+ return 0;
+}
+
+static int context_read_proc_cmdline(Context *c) {
+ _cleanup_(context_done) Context v = {}, w = {};
+ int r;
+
+ assert(c);
+
+ r = proc_cmdline_get_key_many(
+ PROC_CMDLINE_STRIP_RD_PREFIX,
+ vc_meta_names[VC_KEYMAP], &v.config[VC_KEYMAP],
+ vc_meta_names[VC_KEYMAP_TOGGLE], &v.config[VC_KEYMAP_TOGGLE],
+ vc_meta_names[VC_FONT], &v.config[VC_FONT],
+ vc_meta_names[VC_FONT_MAP], &v.config[VC_FONT_MAP],
+ vc_meta_names[VC_FONT_UNIMAP], &v.config[VC_FONT_UNIMAP],
+ vc_meta_compat_names[VC_KEYMAP_TOGGLE], &w.config[VC_KEYMAP_TOGGLE],
+ vc_meta_compat_names[VC_FONT_MAP], &w.config[VC_FONT_MAP],
+ vc_meta_compat_names[VC_FONT_UNIMAP], &w.config[VC_FONT_UNIMAP]);
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
+ return r;
+ }
+
+ context_merge_config(c, &v, &w);
+ return 0;
+}
+
+static void context_load_config(Context *c) {
+ assert(c);
+
+ /* Load data from credentials (lowest priority) */
+ (void) context_read_creds(c);
+
+ /* Load data from configuration file (middle priority) */
+ (void) context_read_env(c);
+
+ /* Let the kernel command line override /etc/vconsole.conf (highest priority) */
+ (void) context_read_proc_cmdline(c);
+}
+
static int verify_vc_device(int fd) {
unsigned char data[] = {
TIOCL_GETFGCONSOLE,
@@ -413,10 +556,8 @@ static int verify_source_vc(char **ret_path, const char *src_vc) {
}
int main(int argc, char **argv) {
- _cleanup_free_ char
- *vc = NULL,
- *vc_keymap_alloc = NULL, *vc_keymap_toggle = NULL,
- *vc_font = NULL, *vc_font_map = NULL, *vc_font_unimap = NULL;
+ _cleanup_(context_done) Context c = {};
+ _cleanup_free_ char *vc = NULL;
_cleanup_close_ int fd = -EBADF;
const char *vc_keymap;
bool utf8, keyboard_ok;
@@ -436,48 +577,15 @@ int main(int argc, char **argv) {
utf8 = is_locale_utf8();
- /* Load data from credentials (lowest priority) */
- r = read_credential_strings_many(
- "vconsole.keymap", &vc_keymap_alloc,
- "vconsole.keymap_toggle", &vc_keymap_toggle,
- "vconsole.font", &vc_font,
- "vconsole.font_map", &vc_font_map,
- "vconsole.font_unimap", &vc_font_unimap);
- if (r < 0 && r != -ENXIO)
- log_warning_errno(r, "Failed to import credentials, ignoring: %m");
-
- /* Load data from configuration file (middle priority) */
- r = parse_env_file(NULL, "/etc/vconsole.conf",
- "KEYMAP", &vc_keymap_alloc,
- "KEYMAP_TOGGLE", &vc_keymap_toggle,
- "FONT", &vc_font,
- "FONT_MAP", &vc_font_map,
- "FONT_UNIMAP", &vc_font_unimap);
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read /etc/vconsole.conf, ignoring: %m");
+ context_load_config(&c);
- /* Let the kernel command line override /etc/vconsole.conf (highest priority) */
- r = proc_cmdline_get_key_many(
- PROC_CMDLINE_STRIP_RD_PREFIX,
- "vconsole.keymap", &vc_keymap_alloc,
- "vconsole.keymap_toggle", &vc_keymap_toggle,
- "vconsole.font", &vc_font,
- "vconsole.font_map", &vc_font_map,
- "vconsole.font_unimap", &vc_font_unimap,
- /* compatibility with obsolete multiple-dot scheme */
- "vconsole.keymap.toggle", &vc_keymap_toggle,
- "vconsole.font.map", &vc_font_map,
- "vconsole.font.unimap", &vc_font_unimap);
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
-
- vc_keymap = isempty(vc_keymap_alloc) ? SYSTEMD_DEFAULT_KEYMAP : vc_keymap_alloc;
+ vc_keymap = isempty(c.config[VC_KEYMAP]) ? SYSTEMD_DEFAULT_KEYMAP : c.config[VC_KEYMAP];
(void) toggle_utf8_sysfs(utf8);
(void) toggle_utf8_vc(vc, fd, utf8);
- r = font_load_and_wait(vc, vc_font, vc_font_map, vc_font_unimap);
- keyboard_ok = keyboard_load_and_wait(vc, vc_keymap, vc_keymap_toggle, utf8) == 0;
+ r = font_load_and_wait(vc, c.config[VC_FONT], c.config[VC_FONT_MAP], c.config[VC_FONT_UNIMAP]);
+ keyboard_ok = keyboard_load_and_wait(vc, vc_keymap, c.config[VC_KEYMAP_TOGGLE], utf8) == 0;
if (idx > 0) {
if (r == 0)