From acda4d2d315b16d0cf37755a3f9add4e49eb7514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 13 Jun 2019 15:19:10 +0200 Subject: [PATCH] Set up pseudo terminal and fork slave --- main.c | 62 +++++++++++++++++++++++++++++++++++++++++++------ meson.build | 1 + slave.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ slave.h | 4 ++++ 4 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 slave.c create mode 100644 slave.h diff --git a/main.c b/main.c index 9f2002cc..a6be3858 100644 --- a/main.c +++ b/main.c @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include #include @@ -12,7 +14,9 @@ #define LOG_MODULE "main" #define LOG_ENABLE_DBG 1 #include "log.h" + #include "shm.h" +#include "slave.h" struct wayland { struct wl_display *display; @@ -27,6 +31,7 @@ struct wayland { struct context { bool quit; + int ptmx; struct wayland wl; }; @@ -71,7 +76,7 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { - LOG_DBG("global: %s", interface); + //LOG_DBG("global: %s", interface); struct context *c = data; if (strcmp(interface, wl_compositor_interface.name) == 0) { @@ -144,7 +149,7 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states) { //struct context *c = data; - LOG_DBG("xdg-toplevel: configure: %dx%d", width, height); + //LOG_DBG("xdg-toplevel: configure: %dx%d", width, height); if (width <= 0 || height <= 0) return; @@ -169,7 +174,7 @@ static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { - LOG_DBG("xdg-surface: configure"); + //LOG_DBG("xdg-surface: configure"); xdg_surface_ack_configure(xdg_surface, serial); } @@ -196,9 +201,15 @@ main(int argc, const char *const *argv) struct context c = { .quit = false, + .ptmx = posix_openpt(O_RDWR | O_NOCTTY), .wl = {0}, }; + if (c.ptmx == -1) { + LOG_ERRNO("failed to open pseudo terminal"); + goto out; + } + c.wl.display = wl_display_connect(NULL); if (c.wl.display == NULL) { LOG_ERR("failed to connect to wayland; no compositor running?"); @@ -252,23 +263,57 @@ main(int argc, const char *const *argv) wl_display_dispatch_pending(c.wl.display); + pid_t pid = fork(); + switch (pid) { + case -1: + LOG_ERRNO("failed to fork"); + goto out; + + case 0: + /* Child */ + slave_spawn(c.ptmx); + assert(false); + break; + + default: + LOG_DBG("slave has PID %d", pid); + break; + } + while (!c.quit) { struct pollfd fds[] = { {.fd = wl_display_get_fd(c.wl.display), .events = POLLIN}, + {.fd = c.ptmx, .events = POLLIN}, }; wl_display_flush(c.wl.display); - poll(fds, 1, -1); + poll(fds, sizeof(fds) / sizeof(fds[0]), -1); + + if (fds[0].revents & POLLIN) { + wl_display_dispatch(c.wl.display); + } if (fds[0].revents & POLLHUP) { LOG_WARN("disconnected from wayland"); break; } - wl_display_dispatch(c.wl.display); - } + if (fds[1].revents & POLLIN) { + char data[1024]; + ssize_t count = read(c.ptmx, data, sizeof(data)); + if (count < 0) { + LOG_ERRNO("failed to read from pseudo terminal"); + break; + } - ret = EXIT_SUCCESS; + LOG_DBG("%.*s", (int)count, data); + } + + if (fds[1].revents & POLLHUP) { + ret = EXIT_SUCCESS; + break; + } + } out: shm_fini(); @@ -289,6 +334,9 @@ out: if (c.wl.display != NULL) wl_display_disconnect(c.wl.display); + if (c.ptmx != -1) + close(c.ptmx); + cairo_debug_reset_static_data(); return ret; } diff --git a/meson.build b/meson.build index b7f608b5..51683dde 100644 --- a/meson.build +++ b/meson.build @@ -56,6 +56,7 @@ executable( 'log.c', 'log.h', 'main.c', 'shm.c', 'shm.h', + 'slave.c', 'slave.h', 'tllist.h', wl_proto_src + wl_proto_headers, dependencies: [cairo, cairo_ft, fontconfig, wayland_client, wayland_cursor, xkb], diff --git a/slave.c b/slave.c new file mode 100644 index 00000000..77f9649b --- /dev/null +++ b/slave.c @@ -0,0 +1,67 @@ +#define _XOPEN_SOURCE 500 +#include "slave.h" +#include +#include +#include +#include + +#include +#include + +#define LOG_MODULE "slave" +#define LOG_ENABLE_DBG 1 +#include "log.h" + +void +slave_spawn(int ptmx) +{ + int pts = -1; + const char *pts_name = ptsname(ptmx); + + if (grantpt(ptmx) == -1) { + LOG_ERRNO("failed to grantpt()"); + goto err; + } + if (unlockpt(ptmx) == -1) { + LOG_ERRNO("failed to unlockpt()"); + goto err; + } + + close(ptmx); + ptmx = -1; + + if (setsid() == -1) { + LOG_ERRNO("failed to setsid()"); + goto err; + } + + pts = open(pts_name, O_RDWR); + if (pts == -1) { + LOG_ERRNO("failed to open pseudo terminal slave device"); + goto err; + } + + if (dup2(pts, STDIN_FILENO) == -1 || + dup2(pts, STDOUT_FILENO) == -1 || + dup2(pts, STDERR_FILENO) == -1) + { + LOG_ERRNO("failed to dup stdin/stdout/stderr"); + goto err; + } + + close(pts); + pts = -1; + + /* TODO: exec() */ + const char *s = "hello world\n"; + write(STDOUT_FILENO, s, strlen(s)); + + sleep(1000); + +err: + if (pts != -1) + close(pts); + if (ptmx != -1) + close(ptmx); + _exit(errno); +} diff --git a/slave.h b/slave.h new file mode 100644 index 00000000..22ef14f3 --- /dev/null +++ b/slave.h @@ -0,0 +1,4 @@ +#pragma once +#include + +void slave_spawn(int ptmx);