commit - ee1d108f5e904a480f409dc7720c9b46edb992f2
commit + 6ba5dbba0ae24afbb2f68251959abddba9647e24
blob - a8309bdc5f78d1162658f15c2d6cd903e4b40c3b
blob + 1d79f2a4e0cb8b8b042f9b0322cfe6837078fdc6
--- ria/ria.c
+++ ria/ria.c
{
struct stat pstat;
struct event ev;
- int ret;
signal(SIGTERM, int_handler);
signal(SIGINT, int_handler);
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
#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>
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;
};
}
}
- 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();
}
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;
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;
}
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;
}
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)) {