Skip to content

Commit 8cf650c

Browse files
committed
fix(tty): set initial console size before exec
When config.json omits process.consoleSize the container pty kept its default 0x0 until the first SIGWINCH, so early reads of TIOCGWINSZ (e.g. `stty size`) returned zeros. Resize the master from the host terminal right after receiving its fd, before the child execs, so the initial size is always correct. consoleSize, when set, is still honored by the in-container slave.set_size(). Signed-off-by: Yuming He <ComixHe1895@outlook.com>
1 parent b2e16f8 commit 8cf650c

4 files changed

Lines changed: 85 additions & 40 deletions

File tree

src/linyaps_box/container.cpp

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,6 +2578,35 @@ int linyaps_box::container::run(run_container_options_t options)
25782578
// TODO: cgroup preenter
25792579
auto [child_pid, socket] = runtime_ns::start_container_process(*this, options);
25802580

2581+
container_monitor monitor(child_pid);
2582+
2583+
auto in = utils::file_descriptor{ STDIN_FILENO, false };
2584+
auto out = utils::file_descriptor{ STDOUT_FILENO, false };
2585+
2586+
bool changed{ false };
2587+
auto in_flags = in.flags();
2588+
auto out_flags = out.flags();
2589+
2590+
auto restore_if_changed =
2591+
utils::make_defer([&]() noexcept {
2592+
if (!changed) {
2593+
return;
2594+
}
2595+
2596+
try {
2597+
in.set_flags(in_flags);
2598+
out.set_flags(out_flags);
2599+
} catch (const std::exception &e) {
2600+
LINYAPS_BOX_ERR()
2601+
<< "failed to restore stdin/stdout flags, some behavior may be unexpected: "
2602+
<< e.what();
2603+
}
2604+
});
2605+
2606+
if (recv_socketpair) {
2607+
monitor.acquire_host_tty(in, out);
2608+
}
2609+
25812610
{
25822611
auto status = this->status();
25832612
if (status.status != container_status_t::runtime_status::CREATING) {
@@ -2594,6 +2623,15 @@ int linyaps_box::container::run(run_container_options_t options)
25942623
runtime_ns::create_runtime_hooks(*this, socket);
25952624
runtime_ns::wait_create_container_result(*this, socket);
25962625

2626+
std::optional<terminal_master> early_master;
2627+
if (recv_socketpair) {
2628+
early_master = runtime_ns::recv_master_tty(recv_socketpair.value());
2629+
recv_socketpair->release();
2630+
if (!config.process.console_size) {
2631+
early_master->resize(monitor.host_tty_size());
2632+
}
2633+
}
2634+
25972635
runtime_ns::wait_socket_close(socket);
25982636

25992637
{
@@ -2609,48 +2647,15 @@ int linyaps_box::container::run(run_container_options_t options)
26092647

26102648
runtime_ns::poststart_hooks(*this);
26112649

2612-
container_monitor monitor(child_pid);
26132650
monitor.enable_signal_forwarding();
26142651

2615-
auto in = utils::file_descriptor{ STDIN_FILENO, false };
2616-
auto out = utils::file_descriptor{ STDOUT_FILENO, false };
2617-
2618-
bool changed{ false };
2619-
auto in_flags = in.flags();
2620-
auto out_flags = out.flags();
2621-
2622-
auto restore_if_changed =
2623-
utils::make_defer([&]() noexcept {
2624-
if (!changed) {
2625-
return;
2626-
}
2627-
2628-
try {
2629-
in.set_flags(in_flags);
2630-
out.set_flags(out_flags);
2631-
} catch (const std::exception &e) {
2632-
LINYAPS_BOX_ERR()
2633-
<< "failed to restore stdin/stdout flags, some behavior may be unexpected: "
2634-
<< e.what();
2635-
}
2636-
});
2637-
2638-
[&recv_socketpair, &monitor, &in, &out, &changed]() -> void {
2639-
if (!recv_socketpair) {
2640-
return;
2641-
}
2642-
2643-
LINYAPS_BOX_DEBUG() << "Container requires a terminal";
2644-
2645-
auto master = runtime_ns::recv_master_tty(recv_socketpair.value());
2646-
recv_socketpair->release();
2647-
2652+
if (early_master) {
26482653
in.set_nonblock(true);
26492654
out.set_nonblock(true);
26502655
changed = true;
26512656

2652-
monitor.enable_io_forwarding(std::move(master), in, out);
2653-
}();
2657+
monitor.attach_terminal(std::move(*early_master), in, out);
2658+
}
26542659

26552660
// TODO: support detach from the parent's process
26562661
// Now we wait for the container process to exit

src/linyaps_box/container_monitor.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,13 @@ auto container_monitor::handle_signals() -> void
9595
}
9696
}
9797

98-
auto container_monitor::enable_io_forwarding(terminal_master master,
99-
const linyaps_box::utils::file_descriptor &in,
100-
const linyaps_box::utils::file_descriptor &out) -> void
98+
auto container_monitor::acquire_host_tty(const utils::file_descriptor &in,
99+
const utils::file_descriptor &out) -> void
101100
{
101+
if (host_tty) {
102+
return;
103+
}
104+
102105
if (utils::isatty(in)) {
103106
host_tty.emplace(in.duplicate());
104107
} else if (utils::isatty(out)) {
@@ -107,8 +110,26 @@ auto container_monitor::enable_io_forwarding(terminal_master master,
107110
auto default_tty = utils::open("/dev/tty", O_RDWR | O_CLOEXEC);
108111
host_tty.emplace(std::move(default_tty));
109112
}
113+
}
110114

111-
host_tty->set_raw();
115+
auto container_monitor::host_tty_size() -> struct winsize
116+
{
117+
if (!host_tty) {
118+
return { };
119+
}
120+
121+
return host_tty->get_size();
122+
123+
}
124+
125+
auto container_monitor::attach_terminal(terminal_master master,
126+
const utils::file_descriptor &in,
127+
const utils::file_descriptor &out) -> void
128+
129+
{
130+
if (host_tty) {
131+
host_tty->set_raw();
132+
}
112133

113134
this->master = std::move(master);
114135

@@ -146,6 +167,14 @@ auto container_monitor::enable_io_forwarding(terminal_master master,
146167
}
147168
}
148169

170+
auto container_monitor::enable_io_forwarding(terminal_master master,
171+
const utils::file_descriptor &in,
172+
const utils::file_descriptor &out) -> void
173+
{
174+
acquire_host_tty(in, out);
175+
attach_terminal(std::move(master), in, out);
176+
}
177+
149178
auto container_monitor::wait_container_exit() -> int
150179
{
151180
// After we enable io forwarding, there may be some data in

src/linyaps_box/container_monitor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ class container_monitor
2323
~container_monitor() noexcept = default;
2424

2525
auto enable_signal_forwarding() -> void;
26+
auto acquire_host_tty(const linyaps_box::utils::file_descriptor &in,
27+
const linyaps_box::utils::file_descriptor &out) -> void;
28+
[[nodiscard]] auto host_tty_size() -> struct winsize;
29+
auto attach_terminal(terminal_master master,
30+
const linyaps_box::utils::file_descriptor &in,
31+
const linyaps_box::utils::file_descriptor &out) -> void;
2632
auto enable_io_forwarding(terminal_master master,
2733
const linyaps_box::utils::file_descriptor &in,
2834
const linyaps_box::utils::file_descriptor &out) -> void;

src/linyaps_box/terminal.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ auto create_pty_pair() -> std::pair<terminal_master, terminal_slave>
2929

3030
auto terminal_master::resize(struct winsize size) -> void
3131
{
32+
if (size.ws_col == 0 || size.ws_row == 0) {
33+
auto default_tty = utils::open("/dev/tty", O_RDWR | O_CLOEXEC);
34+
std::ignore = utils::ioctl(default_tty, TIOCGWINSZ, &size);
35+
}
36+
3237
std::ignore = utils::ioctl(master_, TIOCSWINSZ, &size);
3338
}
3439

0 commit comments

Comments
 (0)