File: wayback-session.c

package info (click to toggle)
wayback 0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 212 kB
  • sloc: ansic: 1,308; makefile: 6
file content (129 lines) | stat: -rw-r--r-- 3,142 bytes parent folder | download
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;
}