diff options
Diffstat (limited to 'src/vconsole')
-rw-r--r-- | src/vconsole/vconsole-setup.c | 118 |
1 files changed, 78 insertions, 40 deletions
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 4d82c65..ba742dd 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -217,6 +217,8 @@ static int verify_vc_allocation_byfd(int fd) { static int verify_vc_kbmode(int fd) { int curr_mode; + assert(fd >= 0); + /* * Make sure we only adjust consoles in K_XLATE or K_UNICODE mode. * Otherwise we would (likely) interfere with X11's processing of the @@ -231,6 +233,20 @@ static int verify_vc_kbmode(int fd) { return IN_SET(curr_mode, K_XLATE, K_UNICODE) ? 0 : -EBUSY; } +static int verify_vc_display_mode(int fd) { + int mode; + + assert(fd >= 0); + + /* Similarly the vc is likely busy if it is in KD_GRAPHICS mode. If it's not the case and it's been + * left in graphics mode, the kernel will refuse to operate on the font settings anyway. */ + + if (ioctl(fd, KDGETMODE, &mode) < 0) + return -errno; + + return mode != KD_TEXT ? -EBUSY : 0; +} + static int toggle_utf8_vc(const char *name, int fd, bool utf8) { int r; struct termios tc = {}; @@ -374,13 +390,11 @@ static int font_load_and_wait(const char *vc, Context *c) { } /* - * A newly allocated VT uses the font from the source VT. Here - * we update all possibly already allocated VTs with the configured - * font. It also allows to restart systemd-vconsole-setup.service, - * to apply a new font to all VTs. + * A newly allocated VT uses the font from the source VT. Here we update all possibly already allocated VTs + * with the configured font. It also allows systemd-vconsole-setup.service to be restarted to apply a new + * font to all VTs. * - * We also setup per-console utf8 related stuff: kbdmode, term - * processing, stty iutf8. + * We also setup per-console utf8 related stuff: kbdmode, term processing, stty iutf8. */ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) { struct console_font_op cfo = { @@ -470,24 +484,14 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) { if (cfo.op != KD_FONT_OP_SET) continue; - r = ioctl(fd_d, KDFONTOP, &cfo); + r = verify_vc_display_mode(fd_d); if (r < 0) { - int last_errno, mode; - - /* The fonts couldn't have been copied. It might be due to the - * terminal being in graphical mode. In this case the kernel - * returns -EINVAL which is too generic for distinguishing this - * specific case. So we need to retrieve the terminal mode and if - * the graphical mode is in used, let's assume that something else - * is using the terminal and the failure was expected as we - * shouldn't have tried to copy the fonts. */ - - last_errno = errno; - if (ioctl(fd_d, KDGETMODE, &mode) >= 0 && mode != KD_TEXT) - log_debug("KD_FONT_OP_SET skipped: tty%u is not in text mode", i); - else - log_warning_errno(last_errno, "KD_FONT_OP_SET failed, fonts will not be copied to tty%u: %m", i); + log_debug_errno(r, "KD_FONT_OP_SET skipped: tty%u is not in text mode", i); + continue; + } + if (ioctl(fd_d, KDFONTOP, &cfo) < 0) { + log_warning_errno(errno, "KD_FONT_OP_SET failed, fonts will not be copied to tty%u: %m", i); continue; } @@ -515,14 +519,21 @@ static int find_source_vc(char **ret_path, unsigned *ret_idx) { assert(ret_path); assert(ret_idx); + /* This function returns an fd when it finds a candidate. When it fails, it returns the first error + * that occurred when the VC was being opened or -EBUSY when it finds some VCs but all are busy + * otherwise -ENOENT when there is no allocated VC. */ + for (unsigned i = 1; i <= 63; i++) { _cleanup_close_ int fd = -EBADF; _cleanup_free_ char *path = NULL; + /* We save the first error but we give less importance for the case where we previously fail + * due to the VCs being not allocated. Similarly errors on opening a device has a higher + * priority than errors due to devices either not allocated or busy. */ + r = verify_vc_allocation(i); if (r < 0) { - log_debug_errno(r, "VC %u existence check failed, skipping: %m", i); - RET_GATHER(err, r); + RET_GATHER(err, log_debug_errno(r, "VC %u existence check failed, skipping: %m", i)); continue; } @@ -532,23 +543,36 @@ static int find_source_vc(char **ret_path, unsigned *ret_idx) { fd = open_terminal(path, O_RDWR|O_CLOEXEC|O_NOCTTY); if (fd < 0) { log_debug_errno(fd, "Failed to open terminal %s, ignoring: %m", path); - RET_GATHER(err, r); + if (IN_SET(err, 0, -EBUSY, -ENOENT)) + err = fd; continue; } + r = verify_vc_kbmode(fd); if (r < 0) { log_debug_errno(r, "Failed to check VC %s keyboard mode: %m", path); - RET_GATHER(err, r); + if (IN_SET(err, 0, -ENOENT)) + err = r; continue; } + r = verify_vc_display_mode(fd); + if (r < 0) { + log_debug_errno(r, "Failed to check VC %s display mode: %m", path); + if (IN_SET(err, 0, -ENOENT)) + err = r; + continue; + } + + log_debug("Selecting %s as source console", path); + /* all checks passed, return this one as a source console */ *ret_idx = i; *ret_path = TAKE_PTR(path); return TAKE_FD(fd); } - return log_error_errno(err, "No usable source console found: %m"); + return err; } static int verify_source_vc(char **ret_path, const char *src_vc) { @@ -572,6 +596,13 @@ static int verify_source_vc(char **ret_path, const char *src_vc) { if (r < 0) return log_error_errno(r, "Virtual console %s is not in K_XLATE or K_UNICODE: %m", src_vc); + /* setfont(8) silently ignores when the font can't be applied due to the vc being in + * KD_GRAPHICS. Hence we continue to accept this case however we now let the user know that the vc + * will be initialized only partially.*/ + r = verify_vc_display_mode(fd); + if (r < 0) + log_notice_errno(r, "Virtual console %s is not in KD_TEXT, font settings likely won't be applied.", src_vc); + path = strdup(src_vc); if (!path) return log_oom(); @@ -592,30 +623,37 @@ static int run(int argc, char **argv) { umask(0022); - if (argv[1]) + if (argv[1]) { fd = verify_source_vc(&vc, argv[1]); - else + if (fd < 0) + return fd; + } else { fd = find_source_vc(&vc, &idx); - if (fd < 0) - return fd; + if (fd < 0 && fd != -EBUSY) + return log_error_errno(fd, "No usable source console found: %m"); + } utf8 = is_locale_utf8(); + (void) toggle_utf8_sysfs(utf8); + + if (fd < 0) { + /* We found only busy VCs, which might happen during the boot process when the boot splash is + * displayed on the only allocated VC. In this case we don't interfere and avoid initializing + * the VC partially as some operations are likely to fail. */ + log_notice("All allocated VCs are currently busy, skipping initialization of font and keyboard settings."); + return EXIT_SUCCESS; + } context_load_config(&c); /* Take lock around the remaining operation to avoid being interrupted by a tty reset operation * performed for services with TTYVHangup=yes. */ lock_fd = lock_dev_console(); - if (lock_fd < 0) { - log_full_errno(lock_fd == -ENOENT ? LOG_DEBUG : LOG_ERR, - lock_fd, - "Failed to lock /dev/console%s: %m", - lock_fd == -ENOENT ? ", ignoring" : ""); - if (lock_fd != -ENOENT) - return lock_fd; - } + if (ERRNO_IS_NEG_DEVICE_ABSENT(lock_fd)) + log_debug_errno(lock_fd, "Device /dev/console does not exist, proceeding without lock: %m"); + else if (lock_fd < 0) + log_warning_errno(lock_fd, "Failed to lock /dev/console, proceeding without lock: %m"); - (void) toggle_utf8_sysfs(utf8); (void) toggle_utf8_vc(vc, fd, utf8); r = font_load_and_wait(vc, &c); |