termux-x11/starter/src/main/jni/starter.c

159 lines
4.3 KiB
C

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sys/stat.h>
#define unused __attribute__((__unused__))
#define DEFAULT_PREFIX "/data/data/me.sergiotarxz.openmg.x11/files/usr"
#define DEFAULT_XDG_RUNTIME_DIR DEFAULT_PREFIX "/tmp"
#define DEFAULT_SOCKET_NAME "wayland-0"
static int socket_action(int* fd, char* path,
int (*action)(int, const struct sockaddr *, socklen_t)) {
if (!fd || !action) {
errno = -EINVAL;
return -1;
}
struct sockaddr_un local;
size_t len;
if((*fd = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
{
perror("socket");
return *fd;
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
return action(*fd, (struct sockaddr *)&local, len);
}
JNIEXPORT void JNICALL
Java_me_sergiotarxz_openmg_x11_starter_Starter_checkXdgRuntimeDir(unused JNIEnv *env, unused jobject thiz) {
char* XDG_RUNTIME_DIR = getenv("XDG_RUNTIME_DIR");
if (!XDG_RUNTIME_DIR || strlen(XDG_RUNTIME_DIR) == 0) {
printf("$XDG_RUNTIME_DIR is unset.\n");
printf("Exporting default value (%s).\n", DEFAULT_XDG_RUNTIME_DIR);
setenv("XDG_RUNTIME_DIR", DEFAULT_XDG_RUNTIME_DIR, true);
}
}
static const char *getWaylandSocketPath() {
static char* path = NULL;
if (path != NULL)
return path;
path = malloc(256 * sizeof(char));
memset(path, 0, 256 * sizeof(char));
char* XDG_RUNTIME_DIR = getenv("XDG_RUNTIME_DIR");
if (!XDG_RUNTIME_DIR || strlen(XDG_RUNTIME_DIR) == 0) {
printf("$XDG_RUNTIME_DIR is unset");
exit(1);
}
sprintf(path, "%s/%s", XDG_RUNTIME_DIR, DEFAULT_SOCKET_NAME);
return path;
}
JNIEXPORT jboolean JNICALL
Java_me_sergiotarxz_openmg_x11_starter_Starter_checkWaylandSocket(unused JNIEnv *env, unused jobject thiz) {
int fd;
errno = 0;
if (socket_action(&fd, (char *) getWaylandSocketPath(), connect) != -1) {
close(fd);
return 1;
}
return 0;
}
JNIEXPORT jint JNICALL
Java_me_sergiotarxz_openmg_x11_starter_Starter_createWaylandSocket(unused JNIEnv *env, unused jobject thiz) {
int fd;
errno = 0;
unlink(getWaylandSocketPath());
if (socket_action(&fd, (char *) getWaylandSocketPath(), bind) < 0) {
perror("socket");
return -1;
}
return fd;
}
#pragma clang diagnostic push
#pragma ide diagnostic ignored "hicpp-signed-bitwise"
JNIEXPORT jint JNICALL
Java_me_sergiotarxz_openmg_x11_starter_Starter_openLogFD(unused JNIEnv *env, unused jobject thiz) {
const char* TERMUX_X11_LOG_FILE = getenv("TERMUX_X11_LOG_FILE");
int sv[2]; /* the pair of socket descriptors */
if (TERMUX_X11_LOG_FILE == NULL || strlen(TERMUX_X11_LOG_FILE) == 0)
return -1;
int logfd = open(TERMUX_X11_LOG_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (logfd < 0) {
perror("open logfile");
return -1;
}
if (pipe(sv) == -1) {
perror("pipe");
return -1;
}
fchmod (sv[0], 0777);
fchmod (sv[1], 0777);
switch(fork()) {
/*
* Android do not allow another process to write to tty or pipe fd of our process.
* We can not force allowing even using chmod.
* That is a reason we are using pipe and cat here.
*/
case 0: {
int new_stderr = dup(2);
close(sv[1]);
dup2(sv[0], 0);
dup2(logfd, 1);
dup2(logfd, 2);
close(sv[0]);
close(logfd);
printf("cat started (%d)\n", getpid());
struct pollfd pfd = {0};
pfd.fd = 0;
pfd.events = POLLIN | POLLHUP;
poll(&pfd, 1, 10000);
execl("/data/data/me.sergiotarxz.openmg.x11/files/usr/bin/cat", "cat", NULL);
dprintf(new_stderr, "execl cat: %s\n", strerror(errno));
return -1;
}
case -1:
return -1;
default:
close(sv[0]);
close(logfd);
return sv[1];
}
}
#pragma clang diagnostic pop