From 824495926a431369a86ed33fc91da319a2bcfa40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:12:25 +0000 Subject: [PATCH 1/3] Initial plan From fb71d1f1962bdf49106ac2e8ffd080b0c378cf64 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 2 Jun 2026 14:04:35 +0800 Subject: [PATCH 2/3] feat(control): expose VT management over DDE control socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add active-vt, free-vt, and switch-vt control operations so DDM can stop issuing VT ioctls directly. 添加 active-vt、free-vt 和 switch-vt control 操作,使DDM不再直接发起VT ioctl。 Reuse the existing seat VT state machine for grouped and unmanaged switches. 复用现有 seat VT 状态机处理 grouped 与非托管切换。 Log: 为control socket补齐VT管理能力 Influence: DDM可通过dde-seatd统一查询和切换VT,减少双写状态机。 --- include/control.h | 14 +++++++ include/seat.h | 3 ++ seatd/control.c | 76 +++++++++++++++++++++++++++++++++++++ seatd/seat.c | 95 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 182 insertions(+), 6 deletions(-) diff --git a/include/control.h b/include/control.h index cbfda1d..f10060e 100644 --- a/include/control.h +++ b/include/control.h @@ -18,8 +18,14 @@ struct server; enum control_opcode { CONTROL_CREATE_GROUP_VT = 1, CONTROL_DESTROY_GROUP_VT = 2, + CONTROL_GET_ACTIVE_VT = 3, + CONTROL_FIND_FREE_VT = 4, + CONTROL_SWITCH_VT = 5, CONTROL_GROUP_VT_CREATED = 100, CONTROL_VT_CHANGED = 101, + CONTROL_OK = 102, + CONTROL_ACTIVE_VT = 103, + CONTROL_FREE_VT = 104, CONTROL_ERROR = 255, }; @@ -39,11 +45,19 @@ struct control_destroy_group_vt_request { int32_t vt; }; +struct control_switch_vt_request { + int32_t vt; +}; + struct control_group_vt_created_event { int32_t owner_pid; int32_t vt; }; +struct control_vt_state_event { + int32_t vt; +}; + struct control_vt_change_event { int32_t old_vt; int32_t new_vt; diff --git a/include/seat.h b/include/seat.h index 92c3e88..b16e241 100644 --- a/include/seat.h +++ b/include/seat.h @@ -63,6 +63,9 @@ struct seat_device *seat_find_device(struct client *client, int device_id); int seat_set_next_session(struct client *client, int session); int seat_vt_activate(struct seat *seat); int seat_vt_release(struct seat *seat); +int seat_get_active_vt(struct seat *seat); +int seat_find_available_vt(struct seat *seat); +int seat_switch_vt(struct seat *seat, int vt); int seat_create_group_vt(struct seat *seat, struct client *owner, int requested_vt, const char *user, const char *session); int seat_destroy_group_vt(struct seat *seat, int vt); diff --git a/seatd/control.c b/seatd/control.c index 3644374..ae9ce22 100644 --- a/seatd/control.c +++ b/seatd/control.c @@ -129,6 +129,17 @@ static int control_send_error(struct control_client *client, int error_code) { return control_client_flush(client); } +static int control_send_ok(struct control_client *client) { + struct control_header header = { + .opcode = CONTROL_OK, + .size = 0, + }; + if (connection_put(&client->connection, &header, sizeof(header)) == -1) { + return -1; + } + return control_client_flush(client); +} + static int control_send_message(struct control_client *client, uint16_t opcode, const void *payload, uint16_t payload_size) { struct control_header header = { @@ -150,6 +161,13 @@ static int control_send_group_vt_created(struct control_client *client, pid_t ow return control_send_message(client, CONTROL_GROUP_VT_CREATED, &event, sizeof(event)); } +static int control_send_vt_state(struct control_client *client, uint16_t opcode, int vt) { + struct control_vt_state_event event = { + .vt = vt, + }; + return control_send_message(client, opcode, &event, sizeof(event)); +} + static int control_send_vt_change(struct control_client *client, int old_vt, int new_vt) { struct control_vt_change_event event = { .old_vt = old_vt, @@ -221,6 +239,49 @@ static int handle_destroy_group_vt(struct control_client *client) { return 0; } +static int handle_get_active_vt(struct control_client *client) { + struct seat *seat = server_get_seat(client->server, "seat0"); + if (seat == NULL) { + return control_send_error(client, ENOENT); + } + + int vt = seat_get_active_vt(seat); + if (vt == -1) { + return control_send_error(client, errno); + } + return control_send_vt_state(client, CONTROL_ACTIVE_VT, vt); +} + +static int handle_find_free_vt(struct control_client *client) { + struct seat *seat = server_get_seat(client->server, "seat0"); + if (seat == NULL) { + return control_send_error(client, ENOENT); + } + + int vt = seat_find_available_vt(seat); + if (vt == -1) { + return control_send_error(client, errno); + } + return control_send_vt_state(client, CONTROL_FREE_VT, vt); +} + +static int handle_switch_vt(struct control_client *client) { + struct control_switch_vt_request request; + if (connection_get(&client->connection, &request, sizeof(request)) == -1) { + return 0; + } + + struct seat *seat = server_get_seat(client->server, "seat0"); + if (seat == NULL) { + return control_send_error(client, ENOENT); + } + + if (seat_switch_vt(seat, request.vt) == -1) { + return control_send_error(client, errno); + } + return control_send_ok(client); +} + static int control_client_handle_opcode(struct control_client *client, uint16_t opcode, uint16_t size) { switch (opcode) { @@ -234,6 +295,21 @@ static int control_client_handle_opcode(struct control_client *client, uint16_t return control_send_error(client, EPROTO); } return handle_destroy_group_vt(client); + case CONTROL_GET_ACTIVE_VT: + if (size != 0) { + return control_send_error(client, EPROTO); + } + return handle_get_active_vt(client); + case CONTROL_FIND_FREE_VT: + if (size != 0) { + return control_send_error(client, EPROTO); + } + return handle_find_free_vt(client); + case CONTROL_SWITCH_VT: + if (size != sizeof(struct control_switch_vt_request)) { + return control_send_error(client, EPROTO); + } + return handle_switch_vt(client); default: return control_send_error(client, EPROTO); } diff --git a/seatd/seat.c b/seatd/seat.c index b29aed0..3b61527 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -42,7 +42,7 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { linked_list_init(&seat->group_vts); seat->vt_bound = vt_bound; seat->seat_name = strdup(seat_name); - seat->cur_vt = 0; + seat->cur_vt = -1; if (seat->seat_name == NULL) { free(seat); return NULL; @@ -74,14 +74,25 @@ void seat_destroy(struct seat *seat) { free(seat); } -static void seat_update_vt(struct seat *seat) { +static int seat_update_vt(struct seat *seat) { int tty0fd = terminal_open(0); if (tty0fd == -1) { + seat->cur_vt = -1; log_errorf("Could not open tty0 to update VT: %s", strerror(errno)); - return; + return -1; } - seat->cur_vt = terminal_current_vt(tty0fd); + + int vt = terminal_current_vt(tty0fd); + int saved_errno = errno; close(tty0fd); + if (vt <= 0) { + seat->cur_vt = -1; + errno = saved_errno != 0 ? saved_errno : ENOENT; + return -1; + } + + seat->cur_vt = vt; + return 0; } static int vt_open(int vt) { @@ -117,8 +128,20 @@ static int vt_switch(struct seat *seat, int vt) { log_errorf("Could not open terminal to switch to VT %d: %s", vt, strerror(errno)); return -1; } - terminal_set_process_switching(ttyfd, true); - terminal_switch_vt(ttyfd, vt); + + if (terminal_set_process_switching(ttyfd, true) == -1) { + int saved_errno = errno; + close(ttyfd); + errno = saved_errno; + return -1; + } + if (terminal_switch_vt(ttyfd, vt) == -1) { + int saved_errno = errno; + close(ttyfd); + errno = saved_errno; + return -1; + } + close(ttyfd); return 0; } @@ -939,6 +962,66 @@ int seat_vt_release(struct seat *seat) { return 0; } +int seat_get_active_vt(struct seat *seat) { + if (!seat->vt_bound) { + errno = EINVAL; + return -1; + } + + if (seat_update_vt(seat) == -1) { + return -1; + } + return seat->cur_vt; +} + +int seat_find_available_vt(struct seat *seat) { + if (!seat->vt_bound) { + errno = EINVAL; + return -1; + } + + int tty0fd = terminal_open(0); + if (tty0fd == -1) { + return -1; + } + + int vt = terminal_find_available(tty0fd); + int saved_errno = errno; + close(tty0fd); + errno = saved_errno; + return vt; +} + +int seat_switch_vt(struct seat *seat, int vt) { + if (!seat->vt_bound) { + errno = EINVAL; + return -1; + } + if (vt <= 0) { + errno = EINVAL; + return -1; + } + + if (seat_update_vt(seat) == -1) { + return -1; + } + if (seat->cur_vt == vt) { + return 0; + } + + if (seat->pending_vt_switch > 0) { + errno = EBUSY; + return -1; + } + + seat->pending_vt_switch = vt; + if (vt_switch(seat, vt) == -1) { + seat->pending_vt_switch = 0; + return -1; + } + return 0; +} + int seat_create_group_vt(struct seat *seat, struct client *owner, int requested_vt, const char *user, const char *session) { if (!seat->vt_bound) { From ef50dcd3f2901914580c3fd3eb4d10fff36e02c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:16:30 +0000 Subject: [PATCH 3/3] fix(seat): keep cur_vt stable on VT query errors --- seatd/seat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index 3b61527..96ab089 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -77,7 +77,6 @@ void seat_destroy(struct seat *seat) { static int seat_update_vt(struct seat *seat) { int tty0fd = terminal_open(0); if (tty0fd == -1) { - seat->cur_vt = -1; log_errorf("Could not open tty0 to update VT: %s", strerror(errno)); return -1; } @@ -86,7 +85,6 @@ static int seat_update_vt(struct seat *seat) { int saved_errno = errno; close(tty0fd); if (vt <= 0) { - seat->cur_vt = -1; errno = saved_errno != 0 ? saved_errno : ENOENT; return -1; } @@ -988,7 +986,9 @@ int seat_find_available_vt(struct seat *seat) { int vt = terminal_find_available(tty0fd); int saved_errno = errno; close(tty0fd); - errno = saved_errno; + if (vt == -1) { + errno = saved_errno; + } return vt; }