[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