Commit Diff


commit - ee1d108f5e904a480f409dc7720c9b46edb992f2
commit + 6ba5dbba0ae24afbb2f68251959abddba9647e24
blob - a8309bdc5f78d1162658f15c2d6cd903e4b40c3b
blob + 1d79f2a4e0cb8b8b042f9b0322cfe6837078fdc6
--- ria/ria.c
+++ ria/ria.c
@@ -31,7 +31,6 @@ main()
 {
 	struct stat pstat;
 	struct event ev;
-	int ret;
 
 	signal(SIGTERM, int_handler);
 	signal(SIGINT, int_handler);
@@ -59,10 +58,7 @@ main()
 	fill(0xFF7F7F7F);
 	draw_cursor();
 
-	while (running) {
-		if ((ret = wsctl_run()) == -1)
-			break;
-
+	while (wsctl_run() != -1 && running) {
 		while (event_pop(&ev) != -1) {
 			switch (ev.type) {
 			case EVENT_TYPE_KEYBOARD:
blob - 32eefef87d805428144c1408a4049ca5bad0cbad
blob + 2e378abe7bf09690301f53a6e189f70c253d6495
--- ria/wsctl.c
+++ ria/wsctl.c
@@ -6,9 +6,13 @@
 #include <errno.h>
 #include <string.h>
 #include <poll.h>
+#include <termios.h>
+#include <util.h>
+#include <signal.h>
 
 #include <sys/mman.h>
 #include <sys/ioctl.h>
+#include <sys/wait.h>
 
 #include <sys/un.h>
 #include <sys/socket.h>
@@ -30,15 +34,19 @@ static int read_cmd(void);
 static int sock_init(void);
 static void sock_exit(void);
 static int add_fd(int, int);
+static int remove_fd(int);
 
 enum fdtype {
 	FD_MOUSE,
 	FD_KEYBOARD,
+	FD_MASTER,
+	FD_SLAVE,
 	FD_PROTOCOL,
 };
 
 struct fdinfo {
 	int fd;
+	pid_t pid; /* This is only useful for FD_SLAVE */
 	enum fdtype type;
 };
 
@@ -193,12 +201,20 @@ wsctl_exit()
 		}
 	}
 
-	free(wsctl.pfinfo);
-	free(wsctl.pfds);
-	close(wsctl.mouse.fd);
+	while (wsctl.pflen > 0) {
+		int type = wsctl.pfinfo[wsctl.pflen - 1].type;
+		int pid = wsctl.pfinfo[wsctl.pflen - 1].pid;
+		int fd = wsctl.pfinfo[wsctl.pflen - 1].fd;
+		int status;
+
+		if (type == FD_SLAVE) {
+			kill(pid, SIGTERM);
+			if (waitpid(pid, &status, 0) == -1)
+				perror("waitpid");
+		}
+		remove_fd(fd);
+	}
 	free(fb->bdat);
-	close(wsctl.kbd.fd);
-	close(wsctl.fd);
 	free(fb);
 	sock_exit();
 }
@@ -236,8 +252,28 @@ wsctl_run()
 			case FD_PROTOCOL:
 				read_cmd();
 				break;
+			/*
+			 * Information exchange between nested instance and
+			 * their parents happen here.
+			 */
+			case FD_MASTER:
+				break;
+			case FD_SLAVE:
+				break;
 			}
 		}
+
+		if (pfd->revents & POLLHUP) {
+			if (info->type == FD_SLAVE) {
+				int status;
+
+				/* Making sure no zombie process stays */
+				if (waitpid(info->pid, &status, WNOHANG) == info->pid) {
+					remove_fd(pfd->fd);
+					i--;
+				}
+			}
+		}
 	}
 
 	return 0;
@@ -246,6 +282,70 @@ wsctl_run()
 int
 wsctl_fork()
 {
+	int sv[2];
+	int pid;
+
+	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sv) == -1)
+		return -1;
+
+	if ((pid = fork()) == -1)
+		return -1;
+
+	if (pid == 0) {
+		pid_t shell;
+		int master;
+		int ret;
+
+		remove_fd(wsctl.mouse.fd);
+		remove_fd(wsctl.kbd.fd);
+		remove_fd(wsctl.sock.fd);
+		remove_fd(wsctl.fd);
+		munmap(fb->dat, fb->bytes);
+		free(fb->bdat);
+		close(sv[0]);
+
+		shell = forkpty(&master, NULL, NULL, NULL);
+		fprintf(stderr, "forkpty: master=%d, shell=%d\n", master, shell);
+
+		if (shell == -1) {
+			perror("forkpty");
+			close(sv[1]);
+			_exit(1);
+		}
+
+		if (shell == 0) {
+			setpgid(0, 0);
+			execl("/bin/ksh", "ksh",(char *) NULL);
+			_exit(1);
+		}
+
+		struct pollfd pfd = {
+			.fd = sv[1],
+			.events = POLLIN,
+		};
+
+		while (1) {
+			if ((ret = poll(&pfd, 1, -1)) == -1)
+				break;
+
+			if (pfd.revents & (POLLHUP | POLLERR)) {
+				if (kill(-shell, SIGTERM) == -1)
+					perror("kill");
+				if (waitpid(shell, NULL, 0) == -1)
+					perror("waitpid");
+				break;
+			}
+		}
+		printf("Death\n");
+		close(master);
+		close(sv[1]);
+		_exit(0);
+	}
+
+	close(sv[1]);
+	int idx = add_fd(sv[0], FD_SLAVE);
+	wsctl.pfinfo[idx].pid = pid;
+
 	return 0;
 }
 
@@ -269,6 +369,39 @@ add_fd(int fd, int type)
 	wsctl.pfds = pfds;
 	wsctl.pflen++;
 
+	return idx;
+}
+
+static int
+remove_fd(int fd)
+{
+	struct fdinfo *infos;
+	struct pollfd *pfds;
+	int idx = -1;
+
+	for (int i = 0; i < wsctl.pflen; i++) {
+		if (wsctl.pfds[i].fd == fd) {
+			idx = i;
+			break;
+		}
+	}
+
+	if (idx == -1) return 0;
+
+	close(wsctl.pfds[idx].fd);
+	wsctl.pflen--;
+
+	if (idx < wsctl.pflen) {
+		wsctl.pfinfo[idx] = wsctl.pfinfo[wsctl.pflen];
+		wsctl.pfds[idx] = wsctl.pfds[wsctl.pflen];
+	}
+
+	infos = reallocarray(wsctl.pfinfo, sizeof(*wsctl.pfinfo), wsctl.pflen);
+	pfds = reallocarray(wsctl.pfds, sizeof(*wsctl.pfds), wsctl.pflen);
+
+	wsctl.pfinfo = infos;
+	wsctl.pfds = pfds;
+
 	return 0;
 }
 
@@ -462,8 +595,31 @@ sock_init()
 	wsctl.sock.len = sizeof(wsctl.sock.addr);
 
 	if (bind(wsctl.sock.fd, (struct sockaddr *)&wsctl.sock.addr, wsctl.sock.len) == -1) {
-		close(wsctl.sock.fd);
-		return -1;
+		/* socket exists and might be in use */
+		if (errno != EADDRINUSE) {
+			close(wsctl.sock.fd);
+			return -1;
+		}
+
+		int check = socket(AF_UNIX, SOCK_STREAM, 0);
+		if (check == -1) {
+			close(wsctl.sock.fd);
+			return -1;
+		}
+
+		if (connect(check, (struct sockaddr *)&wsctl.sock.addr, wsctl.sock.len) == 0) {
+			errno = EADDRINUSE;
+			close(wsctl.sock.fd);
+			close(check);
+			return -1;
+		}
+
+		close(check);
+		unlink(RIA_SOCK_PATH);
+
+		if (bind(wsctl.sock.fd, (struct sockaddr *)&wsctl.sock.addr, wsctl.sock.len)) {
+			return -1;
+		}
 	}
 
 	if (listen(wsctl.sock.fd, SOMAXCONN)) {