[systemd-devel] [Patch] NumLock setting from vconsole.conf

Matthias Berndt matthias_berndt at gmx.de
Tue Feb 5 17:18:15 PST 2013


Hi Lennart,

I've modified the patch again so that it also sets the default state of the 
LED flags to the configued values. Otherwise it'd switch NumLock off again 
when you type reset into the console.

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..5222c71 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,79 @@ 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) {
+                char flag = flags[i] | flags[i] << 4;
+                if (flag_values[i] == NULL)
+                        continue;
+                switch (parse_boolean(flag_values[i])) {
+                case 0:
+                        new_mask &= ~flag;
+                        flags_to_set |= flag;
+                        break;
+                case 1:
+                        new_mask |= flag;
+                        flags_to_set |= flag;
+                        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 +277,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 +295,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 +320,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 +338,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 +357,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 +378,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