Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions include/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions include/seat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
76 changes: 76 additions & 0 deletions seatd/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down
95 changes: 89 additions & 6 deletions seatd/seat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,14 +74,23 @@ 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) {
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) {
errno = saved_errno != 0 ? saved_errno : ENOENT;
return -1;
}

seat->cur_vt = vt;
return 0;
}

static int vt_open(int vt) {
Expand Down Expand Up @@ -117,8 +126,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;
}
Expand Down Expand Up @@ -939,6 +960,68 @@ 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);
if (vt == -1) {
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) {
Expand Down
Loading