[systemd-devel] [Patch] NumLock setting from vconsole.conf
Matthias Berndt
matthias_berndt at gmx.de
Tue Feb 5 15:51:59 PST 2013
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
-------------- next part --------------
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);
More information about the systemd-devel
mailing list