From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 514391FF13B for ; Wed, 22 Apr 2026 10:55:25 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id C21251045B; Wed, 22 Apr 2026 10:55:24 +0200 (CEST) From: Dominik Csapak To: pve-devel@lists.proxmox.com Subject: [PATCH] ignore HUP before client connect on pty Date: Wed, 22 Apr 2026 10:52:46 +0200 Message-ID: <20260422085520.959328-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.050 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: YOIHYHWXEF5K32KCTYGOAQNMUYTUNDKE X-Message-ID-Hash: YOIHYHWXEF5K32KCTYGOAQNMUYTUNDKE X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Since debian trixie, the `login` tool timing changed and it always sends a HUP first thing. This caused spiceterm to immediately close again. To fix that, ignore all HUPs on the PTY side until at least one client is connected. To achieve that the client count is moved inside the SpiceScreen struct, since that is reachable from all callbacks needed (connect/disconnect/timeout/channel watcher). The only potential downside is if the cmd really exits before a client connects, it blocks the client for a bit without any indication as to why and then disconnects. Tested that by replacing `login` with `/bin/false` and the client disconnected after a few seconds automatically. Signed-off-by: Dominik Csapak --- i opted to not use the same workaround as in termproxy (which ignores all HUPs on the pty side) since it should be enough to only do that until the client is connected. All HUPs afterwards normally closes the terminal. src/screen.c | 18 +++++++++--------- src/spiceterm.c | 19 ++++++++++++++++++- src/spiceterm.h | 2 ++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/screen.c b/src/screen.c index c5247a8..267fe98 100644 --- a/src/screen.c +++ b/src/screen.c @@ -568,26 +568,24 @@ static void set_client_capabilities(QXLInstance *qin, uint8_t client_present, ui } } -static int client_count = 0; - static void client_connected(SpiceScreen *spice_screen) { - client_count++; + spice_screen->client_count++; - DPRINTF(1, "client_count = %d", client_count); + DPRINTF(1, "client_count = %d", spice_screen->client_count); } static void client_disconnected(SpiceScreen *spice_screen) { - if (client_count > 0) { - client_count--; - DPRINTF(1, "client_count = %d", client_count); + if (spice_screen->client_count > 0) { + spice_screen->client_count--; + DPRINTF(1, "client_count = %d", spice_screen->client_count); exit(0); // fixme: cleanup? } } static void do_conn_timeout(void *opaque) { - // SpiceScreen *spice_screen = opaque; + SpiceScreen *spice_screen = opaque; - if (client_count <= 0) { + if (spice_screen->client_count <= 0) { printf("connection timeout - stopping server\n"); exit(0); // fixme: cleanup? } @@ -664,6 +662,8 @@ SpiceScreen *spice_screen_new( spice_screen->width = width; spice_screen->height = height; + spice_screen->client_count = 0; + g_cond_init(&spice_screen->command_cond); g_mutex_init(&spice_screen->command_mutex); diff --git a/src/spiceterm.c b/src/spiceterm.c index 77d2d05..b5259e7 100644 --- a/src/spiceterm.c +++ b/src/spiceterm.c @@ -1549,6 +1549,22 @@ static gboolean master_error_callback(GIOChannel *channel, GIOCondition conditio return FALSE; } +static gboolean master_hup_callback(GIOChannel *channel, GIOCondition condition, gpointer data) { + spiceTerm *vt = (spiceTerm *)data; + + DPRINTF(1, "condition %d", condition); + + // /usr/bin/login sends a HUP at the beginning, meaning we must ignore them + // until we had at least one client, otherwise we exit immediately. + if (vt->screen->client_count < 1) { + return TRUE; + } + + exit(0); + + return FALSE; +} + static void master_watch(int master, int event, void *opaque) { spiceTerm *vt = (spiceTerm *)opaque; int c; @@ -1717,7 +1733,8 @@ int main(int argc, char **argv) { GIOChannel *channel = g_io_channel_unix_new(master); g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); g_io_channel_set_encoding(channel, NULL, NULL); - g_io_add_watch(channel, G_IO_ERR | G_IO_HUP, master_error_callback, vt); + g_io_add_watch(channel, G_IO_ERR, master_error_callback, vt); + g_io_add_watch(channel, G_IO_HUP, master_hup_callback, vt); vt->screen->mwatch = vt->screen->core->watch_add( master, SPICE_WATCH_EVENT_READ /* |SPICE_WATCH_EVENT_WRITE */, master_watch, vt diff --git a/src/spiceterm.h b/src/spiceterm.h index 9083c4a..9c189e0 100644 --- a/src/spiceterm.h +++ b/src/spiceterm.h @@ -50,6 +50,8 @@ struct SpiceScreen { int primary_height; int primary_width; + int client_count; + SpiceTimer *conn_timeout_timer; SpiceWatch *mwatch; /* watch master pty */ -- 2.47.3