summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/vconsole/90-vconsole.rules.in2
-rw-r--r--src/vconsole/vconsole-setup.c58
2 files changed, 40 insertions, 20 deletions
diff --git a/src/vconsole/90-vconsole.rules.in b/src/vconsole/90-vconsole.rules.in
index 35b9ad5151..84b4d575bd 100644
--- a/src/vconsole/90-vconsole.rules.in
+++ b/src/vconsole/90-vconsole.rules.in
@@ -7,4 +7,4 @@
# Each vtcon keeps its own state of fonts.
#
-ACTION=="add", SUBSYSTEM=="vtconsole", KERNEL=="vtcon*", RUN+="@rootlibexecdir@/systemd-vconsole-setup"
+ACTION=="add", SUBSYSTEM=="vtconsole", KERNEL=="vtcon*", ATTR{name}!="*dummy device", RUN+="@rootlibexecdir@/systemd-vconsole-setup"
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index ac4ceb1486..a0ab5990fc 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -208,9 +208,9 @@ static int font_load_and_wait(const char *vc, const char *font, const char *map,
*/
static void setup_remaining_vcs(int fd, bool utf8) {
struct console_font_op cfo = {
- .op = KD_FONT_OP_GET, .flags = 0,
- .width = 32, .height = 32,
- .charcount = 512,
+ .op = KD_FONT_OP_GET,
+ .width = UINT_MAX, .height = UINT_MAX,
+ .charcount = UINT_MAX,
};
struct vt_stat vcs = {};
struct unimapinit adv = {};
@@ -225,12 +225,6 @@ static void setup_remaining_vcs(int fd, bool utf8) {
return;
}
- fontbuf = malloc(cfo.width * cfo.height * cfo.charcount / 8);
- if (!fontbuf) {
- log_oom();
- return;
- }
-
/* get active, and 16 bit mask of used VT numbers */
r = ioctl(fd, VT_GETSTATE, &vcs);
if (r < 0) {
@@ -238,21 +232,47 @@ static void setup_remaining_vcs(int fd, bool utf8) {
return;
}
- /* get fonts from source console */
- cfo.data = fontbuf;
+ /* get metadata of the current font (width, height, count) */
r = ioctl(fd, KDFONTOP, &cfo);
if (r < 0)
- log_warning_errno(errno, "KD_FONT_OP_GET failed, fonts will not be copied: %m");
+ log_warning_errno(errno, "KD_FONT_OP_GET failed while trying to get the font metadata: %m");
else {
- unimapd.entries = unipairs;
- unimapd.entry_ct = USHRT_MAX;
- r = ioctl(fd, GIO_UNIMAP, &unimapd);
- if (r < 0)
- log_warning_errno(errno, "GIO_UNIMAP failed, fonts will not be copied: %m");
- else
- cfo.op = KD_FONT_OP_SET;
+ /* verify parameter sanity first */
+ if (cfo.width > 32 || cfo.height > 32 || cfo.charcount > 512)
+ log_warning("Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)",
+ cfo.width, cfo.height, cfo.charcount);
+ else {
+ /*
+ * Console fonts supported by the kernel are limited in size to 32 x 32 and maximum 512
+ * characters. Thus with 1 bit per pixel it requires up to 65536 bytes. The height always
+ * requries 32 per glyph, regardless of the actual height - see the comment above #define
+ * max_font_size 65536 in drivers/tty/vt/vt.c for more details.
+ */
+ fontbuf = malloc((cfo.width + 7) / 8 * 32 * cfo.charcount);
+ if (!fontbuf) {
+ log_oom();
+ return;
+ }
+ /* get fonts from source console */
+ cfo.data = fontbuf;
+ r = ioctl(fd, KDFONTOP, &cfo);
+ if (r < 0)
+ log_warning_errno(errno, "KD_FONT_OP_GET failed while trying to read the font data: %m");
+ else {
+ unimapd.entries = unipairs;
+ unimapd.entry_ct = USHRT_MAX;
+ r = ioctl(fd, GIO_UNIMAP, &unimapd);
+ if (r < 0)
+ log_warning_errno(errno, "GIO_UNIMAP failed while trying to read unicode mappings: %m");
+ else
+ cfo.op = KD_FONT_OP_SET;
+ }
+ }
}
+ if (cfo.op != KD_FONT_OP_SET)
+ log_warning("Fonts will not be copied to remaining consoles");
+
for (i = 1; i <= 63; i++) {
char ttyname[strlen("/dev/tty") + DECIMAL_STR_MAX(int)];
_cleanup_close_ int fd_d = -1;