Hi Lennart, > It should suffice to invoke your set_modifiers() function in some > wrapper function set_modifiers_on_all_vcs() which internally just runs > VT_GETSTATE and iterates over all allocated VCs. See > font_copy_to_all_vcs() for inspiration. Done. I've factored out the common code as an iterator.
> I wonder what happens if X11 is currently active on the VC that the leds > setting is applied to. Ideally, the ioctl would just fail, or at least > not have any negative impact on X11 or not break it. Have you played > around with that, by any chance? The ioctls return 0 and don't affect X. After switching back to text mode, the changes do take effect. > A minor optimization might be to suppress the KDSKBLED if no change has > been made. This might be useful to avoid SELinux AVCs or so in case > people have very strict policies and nothing set. Done. The KDGKBLED is also suppressed when nothing is to be set. Cheers Matthias
diff --git a/man/vconsole.conf.xml b/man/vconsole.conf.xml index 45156b7..4335314 100644 --- a/man/vconsole.conf.xml +++ b/man/vconsole.conf.xml @@ -74,7 +74,10 @@ <varname>vconsole.keymap.toggle=</varname>, <varname>vconsole.font=</varname>, <varname>vconsole.font.map=</varname>, - <varname>vconsole.font.unimap=</varname> may be used + <varname>vconsole.font.unimap=</varname>, + <varname>vconsole.scroll_lock</varname>, + <varname>vconsole.num_lock</varname>, + <varname>vconsole.caps_lock</varname> may be used to override the console settings at boot.</para> <para>Depending on the operating system other @@ -115,6 +118,17 @@ font map.</para></listitem> </varlistentry> + <varlistentry> + <term><varname>SCROLL_LOCK=</varname></term> + <term><varname>NUM_LOCK=</varname></term> + <term><varname>CAPS_LOCK=</varname></term> + <listitem><para>These boolean variables control + the state of the respective keyboard flags. + When an invalid or no value is specified, + the state is left unchanged. + </para></listitem> + </varlistentry> + </variablelist> </refsect1> @@ -122,12 +136,13 @@ <title>Example</title> <example> - <title>German keyboard and console</title> + <title>German keyboard and console with NumLock enabled:</title> <para><filename>/etc/vconsole.conf:</filename></para> <programlisting>KEYMAP=de-latin1 -FONT=latarcyrheb-sun16</programlisting> +FONT=latarcyrheb-sun16 +NUM_LOCK=on</programlisting> </example> </refsect1> diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 6501705..b6b7383 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -158,6 +158,35 @@ static int font_load(const char *vc, const char *font, const char *map, const ch return 0; } +struct vt_iter { + int index; + int fd; +}; + +static void vt_iter_init(struct vt_iter *it) { + it->index = 0; + it->fd = -1; +} + +static bool vt_iter_next(struct vt_iter *it) { + if (it->fd >= 0) + close_nointr_nofail(it->fd); + while (++(it->index) < 16) { + char vcname[16]; + + /* skip non-allocated ttys */ + snprintf(vcname, sizeof(vcname), "/dev/vcs%i", it->index); + if (access(vcname, F_OK) < 0) + continue; + + snprintf(vcname, sizeof(vcname), "/dev/tty%i", it->index); + it->fd = open_terminal(vcname, O_RDWR|O_CLOEXEC); + if (it->fd >= 0) + return true; + } + return false; +} + /* * A newly allocated VT uses the font from the active VT. Here * we update all possibly already allocated VTs with the configured @@ -166,41 +195,78 @@ static int font_load(const char *vc, const char *font, const char *map, const ch */ static void font_copy_to_all_vcs(int fd) { struct vt_stat vcs; - int i; int r; + struct vt_iter it; - /* get active, and 16 bit mask of used VT numbers */ + /* get active VT */ zero(vcs); r = ioctl(fd, VT_GETSTATE, &vcs); if (r < 0) return; - for (i = 1; i <= 15; i++) { - char vcname[16]; - int vcfd; + + for (vt_iter_init(&it); vt_iter_next(&it); ) { struct console_font_op cfo; - if (i == vcs.v_active) - continue; - - /* skip non-allocated ttys */ - snprintf(vcname, sizeof(vcname), "/dev/vcs%i", i); - if (access(vcname, F_OK) < 0) - continue; - - snprintf(vcname, sizeof(vcname), "/dev/tty%i", i); - vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC); - if (vcfd < 0) + if (it.index == vcs.v_active) continue; /* copy font from active VT, where the font was uploaded to */ zero(cfo); cfo.op = KD_FONT_OP_COPY; cfo.height = vcs.v_active-1; /* tty1 == index 0 */ - ioctl(vcfd, KDFONTOP, &cfo); + ioctl(it.fd, KDFONTOP, &cfo); + } +} + +static int set_led_flags(int fd, int num_flags, const char *flags, char *const *flag_values) { + char old_mask, new_mask = 0, flags_to_set = 0; + int r = 0; + + for (int i = 0; i < num_flags; ++i) { + if (flag_values[i] == NULL) + continue; + switch (parse_boolean(flag_values[i])) { + case 0: + new_mask &= ~flags[i]; + flags_to_set |= flags[i]; + break; + case 1: + new_mask |= flags[i]; + flags_to_set |= flags[i]; + break; + default: + log_warning("invalid value for keyboard led flag: \"%s\"", flag_values[i]); + } + } + + if (!flags_to_set) { + return 0; + } + + if (ioctl(fd, KDGKBLED, &old_mask) < 0) { + r = -errno; + log_warning("failed to get keyboard led flags: %s", strerror(errno)); + return r; + } + + new_mask |= old_mask & ~flags_to_set; + if (new_mask != old_mask && ioctl(fd, KDSKBLED, new_mask) < 0) { + r = -errno; + log_warning("failed to set keyboard led flag status: %s", strerror(errno)); + return r; + } + + return 0; +} - close_nointr_nofail(vcfd); +static int set_led_flags_on_all_vcs(int num_flags, const char *flags, char *const *flag_values) { + int r = 0; + struct vt_iter it; + for (vt_iter_init(&it); vt_iter_next(&it); ) { + r = set_led_flags(it.fd, num_flags, flags, flag_values) || r; } + return -r; } int main(int argc, char **argv) { @@ -210,10 +276,12 @@ int main(int argc, char **argv) { char *vc_font = NULL; char *vc_font_map = NULL; char *vc_font_unimap = NULL; + const char vc_led_flags[] = { LED_SCR, LED_NUM, LED_CAP }; + char *vc_led_flag_values[ELEMENTSOF(vc_led_flags)] = { }; int fd = -1; bool utf8; pid_t font_pid = 0, keymap_pid = 0; - bool font_copy = false; + bool apply_to_all_vcs = false; int r = EXIT_FAILURE; log_set_target(LOG_TARGET_AUTO); @@ -226,7 +294,7 @@ int main(int argc, char **argv) { vc = argv[1]; else { vc = "/dev/tty0"; - font_copy = true; + apply_to_all_vcs = true; } fd = open_terminal(vc, O_RDWR|O_CLOEXEC); @@ -251,6 +319,9 @@ int main(int argc, char **argv) { "vconsole.font", &vc_font, "vconsole.font.map", &vc_font_map, "vconsole.font.unimap", &vc_font_unimap, + "vconsole.scroll_lock", vc_led_flag_values, + "vconsole.num_lock", vc_led_flag_values + 1, + "vconsole.caps_lock", vc_led_flag_values + 2, NULL); if (r < 0 && r != -ENOENT) @@ -266,6 +337,9 @@ int main(int argc, char **argv) { "FONT", &vc_font, "FONT_MAP", &vc_font_map, "FONT_UNIMAP", &vc_font_unimap, + "SCROLL_LOCK", vc_led_flag_values, + "NUM_LOCK", vc_led_flag_values + 1, + "CAPS_LOCK", vc_led_flag_values + 2, NULL); if (r < 0 && r != -ENOENT) @@ -282,13 +356,20 @@ int main(int argc, char **argv) { font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0) r = EXIT_SUCCESS; + if (apply_to_all_vcs) { + if (set_led_flags_on_all_vcs(ELEMENTSOF(vc_led_flags), vc_led_flags, vc_led_flag_values) != 0) + r = EXIT_FAILURE; + } + else if (set_led_flags(fd, ELEMENTSOF(vc_led_flags), vc_led_flags, vc_led_flag_values)) + r = EXIT_FAILURE; + finish: if (keymap_pid > 0) wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid); if (font_pid > 0) { wait_for_terminate_and_warn(KBD_SETFONT, font_pid); - if (font_copy) + if (apply_to_all_vcs) font_copy_to_all_vcs(fd); } @@ -296,6 +377,9 @@ finish: free(vc_font); free(vc_font_map); free(vc_font_unimap); + free(vc_led_flag_values[0]); + free(vc_led_flag_values[1]); + free(vc_led_flag_values[2]); if (fd >= 0) close_nointr_nofail(fd);
_______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel