Skip to content

Commit f0743fc

Browse files
committed
DLPX-95602 X11 console Keymaps broken
PR URL: https://www.github.com/delphix/delphix-platform/pull/552
1 parent cdd6630 commit f0743fc

File tree

1 file changed

+59
-4
lines changed

1 file changed

+59
-4
lines changed

files/common/usr/bin/delphix-startup-screen

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ the IP address, hostname, and services (description and status).
2222
import curses
2323
import curses.ascii
2424
import curses.textpad
25+
import re
2526
import sys
2627
import signal
2728
import os
29+
import shutil
30+
import tempfile
2831
import logging
2932
import subprocess
3033
from typing import List, Any, Tuple, Generator
@@ -102,11 +105,63 @@ def get_keyboard_layout() -> str:
102105

103106
def set_keyboard_layout(layout: str) -> subprocess.CompletedProcess:
104107
"""
105-
Set the keyboard layout based on the user selection.
108+
Set the keyboard layout by editing /etc/default/keyboard and applying it with setupcon.
109+
This avoids localectl (which is disabled on Debian/Ubuntu builds).
110+
111+
Notes:
112+
- Does NOT trigger update-initramfs; only applies to the running system's console.
106113
"""
107-
cmd: List[str] = ['localectl', 'set-x11-keymap', layout, 'pc105']
108-
subprocess.run(cmd, shell=False, check=True)
109-
return subprocess.run('setupcon', shell=False, check=True)
114+
kb_path = "/etc/default/keyboard"
115+
kb_backup = kb_path + ".bak"
116+
117+
# Read current content (if file doesn't exist, start with a minimal stub)
118+
try:
119+
with open(kb_path, "r", encoding="utf-8") as f:
120+
lines = f.readlines()
121+
except FileNotFoundError:
122+
lines = [
123+
'XKBMODEL="pc105"\n',
124+
f'XKBLAYOUT="{layout}"\n',
125+
'XKBVARIANT=""\n',
126+
'XKBOPTIONS=""\n',
127+
'BACKSPACE="guess"\n',
128+
]
129+
else:
130+
# Update or append XKBLAYOUT line
131+
updated = False
132+
pattern = re.compile(r'^\s*XKBLAYOUT\s*=')
133+
for i, line in enumerate(lines):
134+
if pattern.match(line):
135+
lines[i] = f'XKBLAYOUT="{layout}"\n'
136+
updated = True
137+
break
138+
if not updated:
139+
# Append if not present
140+
lines.append(f'XKBLAYOUT="{layout}"\n')
141+
142+
# Atomic write with backup
143+
os.makedirs(os.path.dirname(kb_path), exist_ok=True)
144+
if os.path.exists(kb_path):
145+
shutil.copy2(kb_path, kb_backup)
146+
147+
fd, tmp = tempfile.mkstemp(prefix=".keyboard.", dir=os.path.dirname(kb_path))
148+
try:
149+
with os.fdopen(fd, "w", encoding="utf-8") as f:
150+
f.writelines(lines)
151+
os.replace(tmp, kb_path)
152+
except Exception:
153+
# Clean temp file and restore from backup if we wrote a partial file
154+
try:
155+
os.remove(tmp)
156+
except OSError:
157+
pass
158+
if os.path.exists(kb_backup):
159+
shutil.copy2(kb_backup, kb_path)
160+
raise
161+
162+
# Apply to current console immediately (does not affect serial consoles)
163+
# Use --force so it rebuilds/loads even if it thinks nothing changed.
164+
return subprocess.run(["setupcon", "--force"], shell=False, check=True)
110165

111166

112167
def get_valid_keyboard_layouts() -> List[str]:

0 commit comments

Comments
 (0)