summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chat.c108
-rw-r--r--chat.h2
-rw-r--r--url.c30
3 files changed, 94 insertions, 46 deletions
diff --git a/chat.c b/chat.c
index 41fc3cb..332cfd6 100644
--- a/chat.c
+++ b/chat.c
@@ -25,9 +25,95 @@
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
+#include <sys/wait.h>
#include "chat.h"
+static union {
+ struct {
+ struct pollfd ui;
+ struct pollfd irc;
+ struct pollfd pipe;
+ };
+ struct pollfd fds[3];
+} fds = {
+ .ui = { .events = POLLIN, .fd = STDIN_FILENO },
+ .irc = { .events = POLLIN },
+ .pipe = { .events = 0 },
+};
+
+void spawn(char *const argv[]) {
+ if (fds.pipe.events) {
+ uiLog(L"spawn: existing pipe");
+ return;
+ }
+
+ int rw[2];
+ int error = pipe(rw);
+ if (error) err(EX_OSERR, "pipe");
+
+ pid_t pid = fork();
+ if (pid < 0) err(EX_OSERR, "fork");
+ if (!pid) {
+ close(rw[0]);
+ close(STDIN_FILENO);
+ dup2(rw[1], STDOUT_FILENO);
+ dup2(rw[1], STDERR_FILENO);
+ close(rw[1]);
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ exit(EX_CONFIG);
+ }
+
+ close(rw[1]);
+ fds.pipe.fd = rw[0];
+ fds.pipe.events = POLLIN;
+}
+
+static void pipeRead(void) {
+ char buf[256];
+ ssize_t len = read(fds.pipe.fd, buf, sizeof(buf) - 1);
+ if (len < 0) err(EX_IOERR, "read");
+ if (len) {
+ buf[len] = '\0';
+ len = strcspn(buf, "\n");
+ uiFmt("%.*s", (int)len, buf);
+ } else {
+ close(fds.pipe.fd);
+ fds.pipe.events = 0;
+ fds.pipe.revents = 0;
+ }
+}
+
+static void eventLoop(void) {
+ for (;;) {
+ uiDraw();
+
+ int n = poll(fds.fds, (fds.pipe.events ? 3 : 2), -1);
+ if (n < 0) {
+ if (errno != EINTR) err(EX_IOERR, "poll");
+ uiRead();
+ continue;
+ }
+
+ if (fds.ui.revents) uiRead();
+ if (fds.irc.revents) ircRead();
+ if (fds.pipe.revents) pipeRead();
+ }
+}
+
+static void sigchld(int sig) {
+ (void)sig;
+ int status;
+ pid_t pid = wait(&status);
+ if (pid < 0) err(EX_OSERR, "wait");
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ uiFmt("spawn: exit %d", WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ uiFmt("spawn: signal %d", WTERMSIG(status));
+ }
+}
+
static void sigint(int sig) {
(void)sig;
input("/quit");
@@ -80,28 +166,14 @@ int main(int argc, char *argv[]) {
inputTab();
- signal(SIGINT, sigint);
uiInit();
uiLog(L"Traveling...");
uiDraw();
- int sock = ircConnect(host, port, pass, webirc);
+ fds.irc.fd = ircConnect(host, port, pass, webirc);
free(host);
- struct pollfd fds[2] = {
- { .fd = STDIN_FILENO, .events = POLLIN },
- { .fd = sock, .events = POLLIN },
- };
- for (;;) {
- int nfds = poll(fds, 2, -1);
- if (nfds < 0) {
- if (errno != EINTR) err(EX_IOERR, "poll");
- fds[0].revents = POLLIN;
- fds[1].revents = 0;
- }
-
- if (fds[0].revents) uiRead();
- if (fds[1].revents) ircRead();
- uiDraw();
- }
+ signal(SIGINT, sigint);
+ signal(SIGCHLD, sigchld);
+ eventLoop();
}
diff --git a/chat.h b/chat.h
index fce1ba2..9a1b855 100644
--- a/chat.h
+++ b/chat.h
@@ -32,6 +32,8 @@ struct {
char *join;
} chat;
+void spawn(char *const argv[]);
+
int ircConnect(
const char *host, const char *port, const char *pass, const char *webPass
);
diff --git a/url.c b/url.c
index 33652ff..1c57126 100644
--- a/url.c
+++ b/url.c
@@ -64,32 +64,6 @@ void urlList(void) {
void urlOpen(size_t i) {
char *url = ring[(last - i) & (RING_LEN - 1)];
if (!url) return;
-
- int fd[2];
- int error = pipe(fd);
- if (error) err(EX_OSERR, "pipe");
-
- pid_t pid = fork();
- if (pid < 0) err(EX_OSERR, "fork");
-
- if (!pid) {
- close(STDIN_FILENO);
- dup2(fd[1], STDOUT_FILENO);
- dup2(fd[1], STDERR_FILENO);
- execlp("open", "open", url, NULL);
- perror("open");
- exit(EX_CONFIG);
- }
- close(fd[1]);
-
- // FIXME: This should technically go on the main event loop.
- char buf[256];
- ssize_t len = read(fd[0], buf, sizeof(buf) - 1);
- if (len < 0) err(EX_IOERR, "read");
- if (len) {
- buf[len] = '\0';
- len = strcspn(buf, "\n");
- uiFmt("%.*s", (int)len, buf);
- }
- close(fd[0]);
+ char *argv[] = { "open", url, NULL };
+ spawn(argv);
}