compositor: refactor client forking code
shell.c and tablet-shell.c had almost the same code for forking their
special shell client. Generalise this code and put it into
wlsc_client_launch() in compositor.c.
Improve error cleanup and reporting in wlsc_client_launch().
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
diff --git a/compositor/compositor.c b/compositor/compositor.c
index 2c04c3b..79440fd 100644
--- a/compositor/compositor.c
+++ b/compositor/compositor.c
@@ -34,6 +34,8 @@
#include <assert.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
@@ -84,6 +86,75 @@
}
static void
+child_client_exec(int sockfd, const char *path)
+{
+ int flags;
+ char s[32];
+
+ /* SOCK_CLOEXEC closes both ends, so we need to unset
+ * the flag on the client fd. */
+ flags = fcntl(sockfd, F_GETFD);
+ if (flags != -1)
+ fcntl(sockfd, F_SETFD, flags & ~FD_CLOEXEC);
+
+ snprintf(s, sizeof s, "%d", sockfd);
+ setenv("WAYLAND_SOCKET", s, 1);
+
+ if (execl(path, path, NULL) < 0)
+ fprintf(stderr, "compositor: executing '%s' failed: %m\n",
+ path);
+}
+
+WL_EXPORT struct wl_client *
+wlsc_client_launch(struct wlsc_compositor *compositor,
+ struct wlsc_process *proc,
+ const char *path,
+ wlsc_process_cleanup_func_t cleanup)
+{
+ int sv[2];
+ pid_t pid;
+ struct wl_client *client;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
+ fprintf(stderr, "wlsc_client_launch: "
+ "socketpair failed while launching '%s': %m\n",
+ path);
+ return NULL;
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ close(sv[0]);
+ close(sv[1]);
+ fprintf(stderr, "wlsc_client_launch: "
+ "fork failed while launching '%s': %m\n", path);
+ return NULL;
+ }
+
+ if (pid == 0) {
+ child_client_exec(sv[1], path);
+ exit(-1);
+ }
+
+ close(sv[1]);
+
+ client = wl_client_create(compositor->wl_display, sv[0]);
+ if (!client) {
+ close(sv[0]);
+ fprintf(stderr, "wlsc_client_launch: "
+ "wl_client_create failed while launching '%s'.\n",
+ path);
+ return NULL;
+ }
+
+ proc->pid = pid;
+ proc->cleanup = cleanup;
+ wlsc_watch_process(proc);
+
+ return client;
+}
+
+static void
surface_handle_buffer_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{