feat: wait for X DISPLAY before starting session

Launch X.org with a pipe fd where it will output the DISPLAY number,
once ready.
This commit is contained in:
grialion
2026-01-17 11:40:49 +01:00
parent 2dfd2e5eaf
commit b2019c7934
2 changed files with 76 additions and 42 deletions

View File

@@ -23,10 +23,11 @@
#include "ui.h" #include "ui.h"
#include "util.h" #include "util.h"
#define DEFAULT_XORG_DISPLAY 0
// no PATH search for now // no PATH search for now
#define XORG_COMMAND "/usr/bin/X" #define XORG_COMMAND "/usr/bin/X"
#define XORG_MESSAGE_LENGTH 16
static void try_source_file(struct Vector* NNULLABLE vec_envlist, static void try_source_file(struct Vector* NNULLABLE vec_envlist,
char* NNULLABLE filepath) { char* NNULLABLE filepath) {
log_printf("sourcing %s\n", filepath); log_printf("sourcing %s\n", filepath);
@@ -98,62 +99,103 @@ struct child_msg {
bool err; bool err;
}; };
// TODO: OR check if xorg_pid fail exited /// block until X returns the display number or an error occurs
static int wait_for_x_ready(const int xorg_pipefd[1], __pid_t xorg_pid) { static bool x_get_display(const int xorg_pipefd[2], int* display) {
// TODO char buffer[XORG_MESSAGE_LENGTH];
UNUSED(xorg_pipefd); bool status;
UNUSED(xorg_pid);
sleep(2); close(xorg_pipefd[1]);
return 0; ssize_t bytes_read = read(xorg_pipefd[0], buffer, sizeof(buffer) - 1);
buffer[bytes_read] = '\0';
if (bytes_read > 0) {
char* endptr;
int val = (int) strtol(buffer, &endptr, 10);
if (endptr == buffer) {
(void)fputs("failed to parse Xorg display response\n", stderr);
status = false;
} else {
*display = val;
status = true;
}
} else if (bytes_read == 0) {
(void)fputs("Xorg pipe closed\n", stderr);
status = false;
} else {
perror("read");
status = false;
}
close(xorg_pipefd[0]);
return status;
}
/// small helper to push dyn arr
static void push_dyn_arr(void*** arr, void* item) {
struct Vector vec = vec_from_raw(*arr);
vec_push(&vec, item);
*arr = vec_as_raw(vec);
} }
// TODO: properly pass this down // TODO: properly pass this down
extern int vt; extern int vt;
// TODO: add error msgs // TODO: add error msgs
/// returns on completion
static void launch_with_xorg_server(struct session_exec* NNULLABLE exec, static void launch_with_xorg_server(struct session_exec* NNULLABLE exec,
struct passwd* pw, struct passwd* pw,
char** NNULLABLE envlist) { char** NNULLABLE envlist) {
int xorg_pipefd[2]; int xorg_pipefd[2];
pipe(xorg_pipefd); if (pipe(xorg_pipefd) == -1) _exit(EXIT_FAILURE);
(void)fflush(NULL);
__pid_t xorg_pid = fork(); __pid_t xorg_pid = fork();
if (xorg_pid == 0) { if (xorg_pid == 0) {
close(xorg_pipefd[0]);
if (!pw->pw_dir) _exit(EXIT_FAILURE); if (!pw->pw_dir) _exit(EXIT_FAILURE);
// !!!!!!!!!! ATTENTION: this fails silently, of course add failure msgs but // !!!!!!!!!! ATTENTION: this fails silently, of course add failure msgs but
// for now I can't so be careful // for now I can't so be careful
if (vt == -1) _exit(EXIT_FAILURE); if (vt == -1) _exit(EXIT_FAILURE);
char* display_thing; // pass the pipe so Xorg can write the DISPLAY value in there
asprintf(&display_thing, ":%d", DEFAULT_XORG_DISPLAY); char* fd_str;
if (!display_thing) _exit(EXIT_FAILURE); asprintf(&fd_str, "%d", xorg_pipefd[1]);
if (!fd_str) _exit(EXIT_FAILURE);
char* vt_path; char* vt_path;
asprintf(&vt_path, "vt%d", vt); asprintf(&vt_path, "vt%d", vt);
if (!vt_path) { if (!vt_path) {
free(display_thing); free(fd_str);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
// dup2(xorg_pipefd[1], STDERR_FILENO); int exit = execle(XORG_COMMAND, XORG_COMMAND, "-displayfd", fd_str, vt_path,
// dup2(xorg_pipefd[1], STDOUT_FILENO); NULL, envlist);
// close(xorg_pipefd[0]);
// close(xorg_pipefd[1]);
int exit = execle(XORG_COMMAND, XORG_COMMAND, display_thing, vt_path, NULL,
envlist);
perror("exec"); perror("exec");
// execle("X", "X", display_thing, vt_path, "-auth", xauth_path,
// "-nolisten", "tcp", "-background", "none", NULL, envlist);
printf("wtf3\n");
(void)fflush(stdout);
free(vt_path); free(vt_path);
free(display_thing); free(fd_str);
_exit(exit); _exit(exit);
} }
wait_for_x_ready(xorg_pipefd, xorg_pid); int display = 0;
if (!x_get_display(xorg_pipefd, &display)) {
(void)fputs("failed to get X display, aborting\n", stderr);
int status;
waitpid(xorg_pid, &status, 0);
_exit(EXIT_FAILURE);
}
char* display_env;
asprintf(&display_env, "DISPLAY=:%d", display);
if (!display_env) {
(void)fputs("failure allocating memory for DISPLAY string\n", stderr);
_exit(EXIT_FAILURE);
}
// convert back for convenient push-ing
push_dyn_arr((void***)&envlist, display_env);
if (!envlist) {
(void)fputs("failure allocating memory for DISPLAY env\n", stderr);
_exit(EXIT_FAILURE);
}
__pid_t xorg_session_pid = fork(); __pid_t xorg_session_pid = fork();
if (xorg_session_pid == 0) { if (xorg_session_pid == 0) {
@@ -175,10 +217,6 @@ static void launch_with_xorg_server(struct session_exec* NNULLABLE exec,
kill(pid_to_kill, SIGTERM); kill(pid_to_kill, SIGTERM);
waitpid(pid_to_kill, &status, 0); waitpid(pid_to_kill, &status, 0);
printf("wtf %d, x%d s%d - k%d\n", status, xorg_pid, xorg_session_pid,
pid_to_kill);
(void)fflush(stdout);
sleep(10);
break; break;
} }
@@ -218,6 +256,7 @@ inline static void forked(int pipefd[2], struct passwd* pw,
if (session->type == XORG) { if (session->type == XORG) {
launch_with_xorg_server(&session->exec, pw, envlist); launch_with_xorg_server(&session->exec, pw, envlist);
_exit(EXIT_SUCCESS);
} else { } else {
int exit = session_exec_exec(&session->exec, envlist); int exit = session_exec_exec(&session->exec, envlist);
perror("exec error"); perror("exec error");
@@ -260,16 +299,6 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist); struct Vector envlist_vec = vec_from_raw((void**)env_ret.envlist);
if (session.type == XORG) {
char* display_env;
asprintf(&display_env, "DISPLAY=:%d", DEFAULT_XORG_DISPLAY);
if (!display_env) {
print_err("alloc error");
return false;
}
vec_push(&envlist_vec, display_env);
}
source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir, source_paths(&envlist_vec, &config->behavior.source, pw->pw_dir,
&config->behavior.user_source); &config->behavior.user_source);
char** envlist = (char**)vec_as_raw(envlist_vec); char** envlist = (char**)vec_as_raw(envlist_vec);

View File

@@ -186,6 +186,7 @@ void ui_update_ofield(struct opts_field* NNULLABLE self) {
ui_update_field(input); ui_update_field(input);
} }
/// draw everything
void scratch_print_ui() { void scratch_print_ui() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &window); ioctl(STDOUT_FILENO, TIOCGWINSZ, &window);
box_start = (struct uint_point){ box_start = (struct uint_point){
@@ -313,6 +314,8 @@ int load(struct Vector* users, struct Vector* sessions) {
&restore_all, g_config)) { &restore_all, g_config)) {
print_passwd(utf8len(of_passwd.efield.content), true); print_passwd(utf8len(of_passwd.efield.content), true);
ui_update_cursor_focus(); ui_update_cursor_focus();
} else {
scratch_print_ui();
} }
} else if (ansi_key == A_UP || ansi_key == A_DOWN) { } else if (ansi_key == A_UP || ansi_key == A_DOWN) {
st_ch_focus(ansi_key == A_DOWN ? 1 : -1); st_ch_focus(ansi_key == A_DOWN ? 1 : -1);
@@ -336,6 +339,8 @@ int load(struct Vector* users, struct Vector* sessions) {
&restore_all, g_config)) { &restore_all, g_config)) {
print_passwd(utf8len(of_passwd.efield.content), true); print_passwd(utf8len(of_passwd.efield.content), true);
ui_update_cursor_focus(); ui_update_cursor_focus();
} else {
scratch_print_ui();
} }
} else } else
st_kbd_type(seq, g_config->behavior.include_defshell); st_kbd_type(seq, g_config->behavior.include_defshell);