1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
/*
* wayback-session launches the wayback compositor, XWayback/XWayland
* and the given session executable
*
* SPDX-License-Identifier: MIT
*/
#include "utils.h"
#include "wayback_log.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t xwayback_pid;
pid_t session_pid;
char *get_xinitrc_path()
{
char *home = getenv("HOME");
if (home) {
char *xinitrc;
asprintf_or_exit(&xinitrc, "%s/.xinitrc", home);
if (access(xinitrc, R_OK) == 0)
return xinitrc;
free(xinitrc);
}
if (access("/etc/X11/xinit/xinitrc", R_OK) == 0)
return strdup_or_exit("/etc/X11/xinit/xinitrc");
wayback_log(LOG_ERROR, "Unable to find xinitrc file");
exit(EXIT_FAILURE);
}
void handle_child_exit(int sig)
{
pid_t pid = waitpid(-1, NULL, WNOHANG);
if (pid == session_pid || pid == xwayback_pid) {
if (pid == session_pid && xwayback_pid > 0)
kill(xwayback_pid, SIGTERM);
if (pid == xwayback_pid && session_pid > 0)
kill(session_pid, SIGTERM);
exit(EXIT_SUCCESS);
}
}
int main(int argc, char *argv[])
{
wayback_log_init("wayback-session", LOG_INFO, NULL);
wayback_log(LOG_INFO, "Wayback <https://wayback.freedesktop.org/> X.Org compatibility layer");
wayback_log(LOG_INFO, "Version %s", WAYBACK_VERSION);
char **session_cmd = NULL;
char *xinitrc_path = NULL;
signal(SIGCHLD, handle_child_exit);
if (argc == 1) {
xinitrc_path = get_xinitrc_path();
} else {
session_cmd = &argv[1];
}
char *xwayback_path = getenv("XWAYBACK_PATH");
if (xwayback_path != NULL) {
if (access(xwayback_path, X_OK) == -1) {
wayback_log(
LOG_ERROR, "Xwayback executable %s not found or not executable", xwayback_path);
exit(EXIT_FAILURE);
}
} else {
xwayback_path = "Xwayback";
}
int fd[2];
if (pipe(fd) == -1) {
wayback_log(LOG_ERROR, "Failed to create pipe");
exit(EXIT_FAILURE);
}
xwayback_pid = fork();
if (xwayback_pid == 0) {
close(fd[0]);
wayback_log(LOG_INFO, "Launching with fd %d", fd[1]);
char *fd_str;
asprintf_or_exit(&fd_str, "%d", fd[1]);
execlp(xwayback_path, xwayback_path, "-displayfd", fd_str, (void *)NULL);
wayback_log(LOG_ERROR, "Failed to launch Xwayback: %s", strerror(errno));
exit(EXIT_FAILURE);
}
char buffer[4095];
close(fd[1]);
ssize_t n = read(fd[0], buffer, sizeof(buffer) - 1);
if (n > 0) {
buffer[n - 1] = '\0'; // Convert from newline-terminated to null-terminated string
wayback_log(LOG_INFO, "Received display %s", buffer);
}
char *x_display;
asprintf_or_exit(&x_display, ":%s", buffer);
session_pid = fork();
if (session_pid == 0) {
unsetenv("WAYLAND_DISPLAY");
setenv("XDG_SESSION_TYPE", "x11", true);
setenv("DISPLAY", x_display, true);
if (xinitrc_path != NULL) {
execlp("sh", "sh", xinitrc_path, (void *)NULL);
} else if (session_cmd != NULL) {
execvp(session_cmd[0], session_cmd);
}
wayback_log(LOG_ERROR, "Failed to launch session: %s", strerror(errno));
free(xinitrc_path);
exit(EXIT_FAILURE);
}
while (1)
pause();
return 0;
}
|