commit - 056b9939639819c1a2e85f0e73fc02dda5b27b78
commit + 10b6dbfa3cb419e92d575e24b5f37c0748f97a97
blob - 93314c1cf5366d4e2cbfa834d399e80834883a5f
blob + 199147eb2fd7136670773126d6998110a272d666
--- regress/imsgev/Makefile
+++ regress/imsgev/Makefile
PROG= imsgev_test
-SRCS= imsgev_test.c imsgev.c log.c
+SRCS= imsgev_test.c imsgev_regress.c log.c
LDADD= -levent -lutil
DPADD= ${LIBEVENT} ${LIBUTIL}
blob - f2fdf7f0d1295eab089010d5678c8daf04235d2d
blob + 6c3766888c8fd793a430fc901c944614bfa62815
--- regress/imsgev/imsgev_test.c
+++ regress/imsgev/imsgev_test.c
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <err.h>
#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
#include <imsg.h>
#include <stdint.h>
+#include <stdio.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include "imsgev.h"
+#include "log.h"
+#include "imsgev_regress.h"
#include "regress.h"
+#define TEST_DATA 41
+#define TEST_END 42
+
static void
make_imsg(const void *data, size_t len, struct imsgbuf *receiver,
struct imsg *imsg)
close(fds[1]);
}
+static void
+channel_init(struct imsgev *iev, struct imsgbuf *receiver, int fds[2])
+{
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) == -1)
+ err(1, "socketpair");
+ imsgev_regress_reset();
+ imsgev_init(iev, fds[0], NULL, NULL);
+ if (imsgbuf_init(receiver, fds[1]) == -1)
+ err(1, "imsgbuf_init receiver");
+}
+
+static void
+channel_clear(struct imsgev *iev, struct imsgbuf *receiver, int fds[2])
+{
+ imsgev_clear(iev);
+ imsgbuf_clear(receiver);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+static int
+receive_one(struct imsgev *iev, struct imsgbuf *receiver, struct imsg *imsg)
+{
+ if (imsgbuf_flush(&iev->ibuf) == -1)
+ err(1, "imsgbuf_flush");
+ if (imsgbuf_read(receiver) != 1)
+ errx(1, "imsgbuf_read");
+ return (imsgbuf_get(receiver, imsg));
+}
+
+static int
+dies(void (*fn)(void))
+{
+ pid_t pid;
+ int devnull, status;
+
+ fflush(stdout);
+ switch (pid = fork()) {
+ case -1:
+ err(1, "fork");
+ case 0:
+ if ((devnull = open("/dev/null", O_WRONLY)) != -1)
+ (void)dup2(devnull, STDERR_FILENO);
+ fn();
+ _exit(0);
+ default:
+ if (waitpid(pid, &status, 0) == -1)
+ err(1, "waitpid");
+ return (WIFEXITED(status) && WEXITSTATUS(status) == 1);
+ }
+}
+
+static void
+die_init_add(void)
+{
+ struct imsgev iev;
+ int fds[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) == -1)
+ err(1, "socketpair");
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_EVENT_ADD, 1);
+ imsgev_init(&iev, fds[0], NULL, NULL);
+}
+
+static void
+die_compose(void)
+{
+ struct imsgbuf receiver;
+ struct imsgev iev;
+ int fds[2];
+
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_COMPOSE, 1);
+ imsgev_send(&iev, TEST_DATA, 0, NULL, 0);
+}
+
+static void
+die_rearm_del(void)
+{
+ struct imsgbuf receiver;
+ struct imsgev iev;
+ int fds[2];
+
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_EVENT_DEL, 1);
+ imsgev_send(&iev, TEST_DATA, 0, NULL, 0);
+}
+
+static void
+die_rearm_add(void)
+{
+ struct imsgbuf receiver;
+ struct imsgev iev;
+ int fds[2];
+
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_EVENT_ADD, 1);
+ imsgev_send(&iev, TEST_DATA, 0, NULL, 0);
+}
+
+static void
+die_clear_del(void)
+{
+ struct imsgbuf receiver;
+ struct imsgev iev;
+ int fds[2];
+
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_EVENT_DEL, 1);
+ imsgev_clear(&iev);
+}
+
+static int
+failed_sequence(unsigned int fail_at, uint32_t *trace, size_t *trace_len)
+{
+ struct imsgbuf receiver;
+ struct imsgev iev;
+ ssize_t n;
+ size_t off;
+ pid_t pid;
+ int devnull, fds[2], pfd[2], status;
+
+ if (pipe(pfd) == -1)
+ err(1, "pipe");
+ fflush(stdout);
+ switch (pid = fork()) {
+ case -1:
+ err(1, "fork");
+ case 0:
+ close(pfd[0]);
+ if ((devnull = open("/dev/null", O_WRONLY)) != -1)
+ (void)dup2(devnull, STDERR_FILENO);
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_trace(pfd[1]);
+ imsgev_regress_fail(IMSGEV_REGRESS_COMPOSE, fail_at);
+ imsgev_send(&iev, TEST_DATA, 0, "a", 1);
+ imsgev_send(&iev, TEST_DATA, 0, "b", 1);
+ imsgev_send(&iev, TEST_END, 0, NULL, 0);
+ _exit(0);
+ default:
+ close(pfd[1]);
+ off = 0;
+ while (off < 4 * sizeof(*trace) &&
+ (n = read(pfd[0], (u_char *)trace + off,
+ 4 * sizeof(*trace) - off)) > 0)
+ off += (size_t)n;
+ close(pfd[0]);
+ if (waitpid(pid, &status, 0) == -1)
+ err(1, "waitpid");
+ *trace_len = off / sizeof(*trace);
+ return (WIFEXITED(status) && WEXITSTATUS(status) == 1);
+ }
+}
+
int
main(void)
{
static const u_char binary[] = { 'a', '\0', 'b' };
struct imsgev_payload payload;
struct imsgbuf receiver;
+ struct imsgev iev;
struct imsg imsg;
+ uint32_t trace[4];
+ size_t trace_len;
u_char byte;
+ int fds[2];
+ log_init(LOG_TO_STDERR, 0, LOG_USER);
+ if (event_init() == NULL)
+ errx(1, "event_init");
+
make_imsg(NULL, 0, &receiver, &imsg);
payload.data = (const u_char *)1;
payload.len = 1;
imsg_free(&imsg);
imsgbuf_clear(&receiver);
+ /* A normal send queues one exact empty frame and arms EV_WRITE. */
+ channel_init(&iev, &receiver, fds);
+ imsgev_send(&iev, TEST_DATA, 7, NULL, 0);
+ CHECK(imsgbuf_queuelen(&iev.ibuf) == 1);
+ CHECK(iev.events == (EV_READ | EV_WRITE));
+ CHECK(receive_one(&iev, &receiver, &imsg) == 1);
+ CHECK(imsg.hdr.type == TEST_DATA && imsg.hdr.peerid == 7);
+ CHECK(imsg_get_len(&imsg) == 0);
+ imsg_free(&imsg);
+ channel_clear(&iev, &receiver, fds);
+
+ /* Embedded NULs remain bytes across the checked-send Interface. */
+ channel_init(&iev, &receiver, fds);
+ imsgev_send(&iev, TEST_DATA, 9, binary, sizeof(binary));
+ CHECK(imsgbuf_queuelen(&iev.ibuf) == 1);
+ CHECK(iev.events == (EV_READ | EV_WRITE));
+ CHECK(receive_one(&iev, &receiver, &imsg) == 1);
+ CHECK(imsg.hdr.type == TEST_DATA && imsg.hdr.peerid == 9);
+ CHECK(imsgev_get_payload(&imsg, &payload) == 0);
+ CHECK(payload.len == sizeof(binary) &&
+ memcmp(payload.data, binary, sizeof(binary)) == 0);
+ imsg_free(&imsg);
+ channel_clear(&iev, &receiver, fds);
+
+ /* Every checked event operation and composition failure is fatal. */
+ CHECK(dies(die_init_add));
+ CHECK(dies(die_compose));
+ CHECK(dies(die_rearm_del));
+ CHECK(dies(die_rearm_add));
+ CHECK(dies(die_clear_del));
+
+ /* A failed chunk stops the exchange before any terminal send. */
+ CHECK(failed_sequence(1, trace, &trace_len));
+ CHECK(trace_len == 1 && trace[0] == TEST_DATA);
+ CHECK(failed_sequence(2, trace, &trace_len));
+ CHECK(trace_len == 2 && trace[0] == TEST_DATA &&
+ trace[1] == TEST_DATA);
+ CHECK(failed_sequence(3, trace, &trace_len));
+ CHECK(trace_len == 3 && trace[0] == TEST_DATA &&
+ trace[1] == TEST_DATA && trace[2] == TEST_END);
+
+ /* Teardown is synchronous, best effort, and never re-arms events. */
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_send_teardown(&iev, TEST_END);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_COMPOSE) == 1);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_FLUSH) == 1);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_EVENT_ADD) == 0);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_EVENT_DEL) == 0);
+ CHECK(imsgbuf_read(&receiver) == 1);
+ CHECK(imsgbuf_get(&receiver, &imsg) == 1 &&
+ imsg.hdr.type == TEST_END && imsg_get_len(&imsg) == 0);
+ imsg_free(&imsg);
+ channel_clear(&iev, &receiver, fds);
+
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_COMPOSE, 1);
+ imsgev_send_teardown(&iev, TEST_END);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_COMPOSE) == 1);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_FLUSH) == 0);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_EVENT_ADD) == 0);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_EVENT_DEL) == 0);
+ channel_clear(&iev, &receiver, fds);
+
+ channel_init(&iev, &receiver, fds);
+ imsgev_regress_reset();
+ imsgev_regress_fail(IMSGEV_REGRESS_FLUSH, 1);
+ imsgev_send_teardown(&iev, TEST_END);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_COMPOSE) == 1);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_FLUSH) == 1);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_EVENT_ADD) == 0);
+ CHECK(imsgev_regress_calls(IMSGEV_REGRESS_EVENT_DEL) == 0);
+ channel_clear(&iev, &receiver, fds);
+
REGRESS_END();
}
blob - /dev/null
blob + 12829ba9ecd954ba6f7469ad64678f1a2ff6585e (mode 644)
--- /dev/null
+++ regress/imsgev/imsgev_regress.c
+/*
+ * Copyright (c) 2026 Isaac <isaac@itm.works>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Compile the production implementation against regression-private
+ * transport adapters. The public imsgev Interface stays free of failure
+ * injection while this internal seam can force every checked operation.
+ */
+
+#include <sys/types.h>
+
+#include <event.h>
+#include <errno.h>
+#include <imsg.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "imsgev.h"
+#include "imsgev_regress.h"
+
+static struct {
+ enum imsgev_regress_op fail_op;
+ unsigned int fail_at;
+ unsigned int calls[IMSGEV_REGRESS_OPS];
+ int trace_fd;
+} regress_state = {
+ .fail_op = IMSGEV_REGRESS_OPS,
+ .trace_fd = -1
+};
+
+void
+imsgev_regress_reset(void)
+{
+ memset(regress_state.calls, 0, sizeof(regress_state.calls));
+ regress_state.fail_op = IMSGEV_REGRESS_OPS;
+ regress_state.fail_at = 0;
+ regress_state.trace_fd = -1;
+}
+
+void
+imsgev_regress_fail(enum imsgev_regress_op op, unsigned int call)
+{
+ regress_state.fail_op = op;
+ regress_state.fail_at = call;
+}
+
+void
+imsgev_regress_trace(int fd)
+{
+ regress_state.trace_fd = fd;
+}
+
+unsigned int
+imsgev_regress_calls(enum imsgev_regress_op op)
+{
+ return (regress_state.calls[op]);
+}
+
+static int
+regress_fails(enum imsgev_regress_op op)
+{
+ regress_state.calls[op]++;
+ if (regress_state.fail_op == op &&
+ regress_state.calls[op] == regress_state.fail_at) {
+ errno = EIO;
+ return (1);
+ }
+ return (0);
+}
+
+static int
+regress_imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t id,
+ pid_t pid, int fd, const void *data, size_t len)
+{
+ ssize_t n;
+
+ if (regress_state.trace_fd != -1) {
+ n = write(regress_state.trace_fd, &type, sizeof(type));
+ if (n != (ssize_t)sizeof(type)) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+ if (regress_fails(IMSGEV_REGRESS_COMPOSE))
+ return (-1);
+ return (imsg_compose(ibuf, type, id, pid, fd, data, len));
+}
+
+static int
+regress_imsgbuf_flush(struct imsgbuf *ibuf)
+{
+ if (regress_fails(IMSGEV_REGRESS_FLUSH))
+ return (-1);
+ return (imsgbuf_flush(ibuf));
+}
+
+static int
+regress_event_add(struct event *ev, const struct timeval *tv)
+{
+ if (regress_fails(IMSGEV_REGRESS_EVENT_ADD))
+ return (-1);
+ return (event_add(ev, tv));
+}
+
+static int
+regress_event_del(struct event *ev)
+{
+ if (regress_fails(IMSGEV_REGRESS_EVENT_DEL))
+ return (-1);
+ return (event_del(ev));
+}
+
+#define imsg_compose regress_imsg_compose
+#define imsgbuf_flush regress_imsgbuf_flush
+#define event_add regress_event_add
+#define event_del regress_event_del
+
+#include "../../src/common/imsgev.c"
+
+#undef imsg_compose
+#undef imsgbuf_flush
+#undef event_add
+#undef event_del
blob - /dev/null
blob + 5feb4bd80968781b2a2b5843315aae47adfcd4fd (mode 644)
--- /dev/null
+++ regress/imsgev/imsgev_regress.h
+/*
+ * Copyright (c) 2026 Isaac <isaac@itm.works>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IMSGEV_REGRESS_H
+#define IMSGEV_REGRESS_H
+
+enum imsgev_regress_op {
+ IMSGEV_REGRESS_COMPOSE,
+ IMSGEV_REGRESS_FLUSH,
+ IMSGEV_REGRESS_EVENT_ADD,
+ IMSGEV_REGRESS_EVENT_DEL,
+ IMSGEV_REGRESS_OPS
+};
+
+void imsgev_regress_reset(void);
+void imsgev_regress_fail(enum imsgev_regress_op, unsigned int);
+void imsgev_regress_trace(int);
+unsigned int imsgev_regress_calls(enum imsgev_regress_op);
+
+#endif /* IMSGEV_REGRESS_H */
blob - eae76c222a9645b9bd3757daa9fcf0204a9b45c7
blob + a871534c0365bae20aa5ea5ee4e649d5bc73f8dd
--- src/common/imsgev.c
+++ src/common/imsgev.c
iev->data = data;
iev->events = EV_READ;
event_set(&iev->ev, fd, iev->events, handler, data);
- event_add(&iev->ev, NULL);
+ if (event_add(&iev->ev, NULL) == -1)
+ fatal("event_add");
}
/*
if (imsgbuf_queuelen(&iev->ibuf) > 0)
iev->events |= EV_WRITE;
- event_del(&iev->ev);
+ if (event_del(&iev->ev) == -1)
+ fatal("event_del");
event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler,
iev->data);
- event_add(&iev->ev, NULL);
+ if (event_add(&iev->ev, NULL) == -1)
+ fatal("event_add");
}
-int
-imsgev_compose(struct imsgev *iev, uint32_t type, uint32_t peerid,
- pid_t pid, int fd, const void *data, size_t datalen)
+void
+imsgev_send(struct imsgev *iev, uint32_t type, uint32_t peerid,
+ const void *data, size_t datalen)
{
- int ret;
+ if (imsg_compose(&iev->ibuf, type, peerid, -1, -1, data,
+ datalen) == -1)
+ fatal("imsg_compose");
+ imsgev_add(iev);
+}
- ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd,
- data, datalen);
- if (ret != -1)
- imsgev_add(iev);
- return (ret);
+/*
+ * Teardown has no event-loop future in which queued output can drain.
+ * Attempt one synchronous empty frame and flush, but never turn cleanup
+ * failure into a second fatal path while the Role is already exiting.
+ */
+void
+imsgev_send_teardown(struct imsgev *iev, uint32_t type)
+{
+ if (imsg_compose(&iev->ibuf, type, 0, -1, -1, NULL, 0) == -1)
+ return;
+ (void)imsgbuf_flush(&iev->ibuf);
}
int
void
imsgev_clear(struct imsgev *iev)
{
- event_del(&iev->ev);
+ if (event_del(&iev->ev) == -1)
+ fatal("event_del");
imsgbuf_clear(&iev->ibuf);
}
blob - c19e3d504553e550f77a3268b8d2a63617840730
blob + 17920eec05b8c5a24a21b4d3d47c72941dd0298f
--- src/common/imsgev.h
+++ src/common/imsgev.h
void imsgev_init(struct imsgev *, int, void (*)(int, short, void *),
void *);
void imsgev_add(struct imsgev *);
-int imsgev_compose(struct imsgev *, uint32_t, uint32_t, pid_t, int,
- const void *, size_t);
+/* Normal sends are checked and own the no-fd/no-pid transport policy. */
+void imsgev_send(struct imsgev *, uint32_t, uint32_t, const void *,
+ size_t);
+/* Teardown attempts one synchronous empty frame without re-arming events. */
+void imsgev_send_teardown(struct imsgev *, uint32_t);
int imsgev_get_payload(struct imsg *, struct imsgev_payload *);
void imsgev_clear(struct imsgev *);
blob - fb18c42b8dae64d769db946ee08450cff6456cce
blob + 3bec9f667fc5ff3e063fd8573fc16846cb499c22
--- src/common/worker.c
+++ src/common/worker.c
/* If we are still alive, the action was not pledge-killed;
* report the syscall outcome for the test to judge. */
- imsgev_compose(&worker->iev, FUGU_IMSG_SELFTEST_RESULT, 0, -1, -1,
+ imsgev_send(&worker->iev, FUGU_IMSG_SELFTEST_RESULT, 0,
&r, sizeof(r));
}
if (w->lockdown(w, &imsg) == -1)
fatalx("%s: lockdown failed", w->title);
w->ready = 1;
- if (imsgev_compose(&w->iev, FUGU_IMSG_READY, 0, -1,
- -1, NULL, 0) == -1)
- fatal("compose READY");
+ imsgev_send(&w->iev, FUGU_IMSG_READY, 0, NULL, 0);
break;
case FUGU_IMSG_PING:
- if (imsgev_compose(&w->iev, FUGU_IMSG_PONG, 0, -1,
- -1, NULL, 0) == -1)
- fatal("compose PONG");
+ imsgev_send(&w->iev, FUGU_IMSG_PONG, 0, NULL, 0);
break;
case FUGU_IMSG_LOG_SYSLOG:
if (imsg_get_len(&imsg) != 0)
blob - 6a041592b8100a7964a10178d9a337589172090f
blob + 23e224028b672b78a69570779b65f39049b5ca2e
--- src/fugu/coord.c
+++ src/fugu/coord.c
fatalx("nested tool Turn control");
c->tool_ctl_expected = type;
c->tool_ctl_done = 0;
- if (imsgev_compose(&c->iev[ROLE_TOOL], type, 0, -1, -1,
- NULL, 0) == -1)
- fatal("compose tool Turn control");
+ imsgev_send(&c->iev[ROLE_TOOL], type, 0, NULL, 0);
while (!c->tool_ctl_done) {
c->wait = WAIT_TOOL_CTL;
rc = event_dispatch();
h.agent = agent;
h.protect_snapshot = 1;
h.protect_len = c->protect_len;
- if (imsgev_compose(iev, FUGU_IMSG_HELLO, 0, -1, -1, &h,
- sizeof(h)) == -1)
- fatal("compose tool HELLO");
+ imsgev_send(iev, FUGU_IMSG_HELLO, 0, &h, sizeof(h));
}
static void
h.cols = 80;
h.rows = 24;
h.curses = c->ui; /* only start curses in terminal mode */
- if (imsgev_compose(iev, FUGU_IMSG_HELLO, 0, -1, -1, &h,
- sizeof(h)) == -1)
- fatal("compose tty HELLO");
+ imsgev_send(iev, FUGU_IMSG_HELLO, 0, &h, sizeof(h));
break;
}
case ROLE_API: {
buf_add(&b, &h, sizeof(h));
if (key != NULL)
buf_add(&b, key, strlen(key));
- if (imsgev_compose(iev, FUGU_IMSG_HELLO, 0, -1, -1, b.data,
- b.len) == -1) {
- buf_freezero(&b);
- fatal("compose api HELLO");
- }
+ imsgev_send(iev, FUGU_IMSG_HELLO, 0, b.data, b.len);
buf_freezero(&b); /* the key traversed this buffer */
/* every named provider block follows: the custodian holds
buf_add(&b, &hp, sizeof(hp));
if (fp->api_key != NULL)
buf_add(&b, fp->api_key, strlen(fp->api_key));
- if (imsgev_compose(iev, FUGU_IMSG_PROV, 0, -1, -1,
- b.data, b.len) == -1) {
- buf_freezero(&b);
- fatal("compose provider");
- }
+ imsgev_send(iev, FUGU_IMSG_PROV, 0, b.data, b.len);
buf_freezero(&b);
}
if (c->conf->initial_provider_slot > 0) {
memset(&sel, 0, sizeof(sel));
sel.slot = c->conf->initial_provider_slot;
- if (imsgev_compose(iev, FUGU_IMSG_SET_PROVIDER, 0, -1,
- -1, &sel, sizeof(sel)) == -1)
- fatal("compose initial provider");
+ imsgev_send(iev, FUGU_IMSG_SET_PROVIDER, 0, &sel,
+ sizeof(sel));
}
break;
}
buf_add(&b, token, h.tokenlen);
buf_add(&b, allow, h.allowlen);
buf_add(&b, block, h.blocklen);
- if (imsgev_compose(iev, FUGU_IMSG_HELLO, 0, -1, -1,
- b.data, b.len) == -1)
- fatal("compose web HELLO");
+ imsgev_send(iev, FUGU_IMSG_HELLO, 0, b.data, b.len);
buf_freezero(&b);
break;
}
case ROLE_EDIT:
- if (imsgev_compose(iev, FUGU_IMSG_HELLO, 0, -1, -1,
- NULL, 0) == -1)
- fatal("compose editor HELLO");
+ imsgev_send(iev, FUGU_IMSG_HELLO, 0, NULL, 0);
break;
case ROLE_TOOL: {
send_tool_hello(c, iev, 0);
static void
ui_send(struct coord *c, int type, const void *p, size_t len)
{
- imsgev_compose(&c->iev[ROLE_TTY], type, 0, -1, -1, p, len);
+ imsgev_send(&c->iev[ROLE_TTY], type, 0, p, len);
}
static void
c->conf->provider_type = fp->type;
} else
fatalx("bad provider slot");
- imsgev_compose(&c->iev[ROLE_API], FUGU_IMSG_SET_PROVIDER, 0,
- -1, -1, &sel, sizeof(sel));
+ imsgev_send(&c->iev[ROLE_API], FUGU_IMSG_SET_PROVIDER, 0,
+ &sel, sizeof(sel));
c->active_provider_slot = sel.slot;
c->provider_window = sel.context_window;
free(c->conf->model);
if (c->compose_in + len > FUGU_EDIT_MAX)
fatalx("compose seed overrun");
c->compose_in += len;
- imsgev_compose(&c->iev[ROLE_EDIT], FUGU_IMSG_EDIT_SEED, 0,
- -1, -1, p, len);
+ imsgev_send(&c->iev[ROLE_EDIT], FUGU_IMSG_EDIT_SEED, 0, p, len);
break;
case FUGU_IMSG_UI_COMPOSE_GO:
c->compose_in = 0;
- imsgev_compose(&c->iev[ROLE_EDIT], FUGU_IMSG_EDIT_RUN, 0,
- -1, -1, NULL, 0);
+ imsgev_send(&c->iev[ROLE_EDIT], FUGU_IMSG_EDIT_RUN, 0, NULL, 0);
break;
case FUGU_IMSG_EDIT_DATA:
if (len == 0)
if (a->done)
return;
- if (imsgev_compose(&a->iev, FUGU_IMSG_AGENT_WEB_OUT, 0, -1, -1,
- s, strlen(s)) == -1)
- fatal("compose subagent web local error");
+ imsgev_send(&a->iev, FUGU_IMSG_AGENT_WEB_OUT, 0, s, strlen(s));
memset(&r, 0, sizeof(r));
r.is_error = 1;
- if (imsgev_compose(&a->iev, FUGU_IMSG_AGENT_WEB_RESULT, 0, -1, -1,
- &r, sizeof(r)) == -1)
- fatal("compose subagent web local result");
+ imsgev_send(&a->iev, FUGU_IMSG_AGENT_WEB_RESULT, 0, &r, sizeof(r));
}
static void
a->web_inflight = 1;
c->agent_web_active = a;
c->web_busy_id = a->web_id;
- if (imsgev_compose(&c->iev[ROLE_WEB], FUGU_IMSG_WEB_REQ,
- a->web_id, -1, -1, &req, sizeof(req)) == -1)
- fatal("relay subagent WEB_REQ");
+ imsgev_send(&c->iev[ROLE_WEB], FUGU_IMSG_WEB_REQ,
+ a->web_id, &req, sizeof(req));
for (off = 0; off < a->web_arg.len; ) {
size_t k = a->web_arg.len - off;
if (k > FUGU_CHUNK)
k = FUGU_CHUNK;
- if (imsgev_compose(&c->iev[ROLE_WEB],
- FUGU_IMSG_WEB_ARG, a->web_id, -1, -1,
- a->web_arg.data + off, k) == -1)
- fatal("relay subagent WEB_ARG");
+ imsgev_send(&c->iev[ROLE_WEB], FUGU_IMSG_WEB_ARG,
+ a->web_id, a->web_arg.data + off, k);
off += k;
}
- if (imsgev_compose(&c->iev[ROLE_WEB], FUGU_IMSG_WEB_RUN,
- a->web_id, -1, -1, NULL, 0) == -1)
- fatal("relay subagent WEB_RUN");
+ imsgev_send(&c->iev[ROLE_WEB], FUGU_IMSG_WEB_RUN,
+ a->web_id, NULL, 0);
agent_web_arg_free(c, a);
return;
}
fatal("get relayed provider payload");
p = payload.data;
len = payload.len;
- if (!a->done && imsgev_compose(&a->iev, type, 0, -1, -1, p, len) == -1)
- fatal("relay provider event to subagent");
+ if (!a->done)
+ imsgev_send(&a->iev, type, 0, p, len);
if (type == FUGU_IMSG_A_DONE || type == FUGU_IMSG_A_ERROR)
a->api_inflight = 0;
if (a->coord->wait == WAIT_AGENTS && agents_settled(a->coord))
outtype = FUGU_IMSG_AGENT_WEB_RESULT;
else
fatalx("bad subagent web event");
- if (!a->done && imsgev_compose(&a->iev, outtype, 0, -1, -1, p,
- len) == -1)
- fatal("relay web event to subagent");
+ if (!a->done)
+ imsgev_send(&a->iev, outtype, 0, p, len);
if (outtype == FUGU_IMSG_AGENT_WEB_RESULT) {
a->web_inflight = 0;
a->web_id = 0;
log_init(LOG_TO_SYSLOG, coord->verbose,
LOG_DAEMON);
for (r = ROLE_TTY; r < ROLE_MAX; r++)
- if (imsgev_compose(&coord->iev[r],
- FUGU_IMSG_LOG_SYSLOG, 0, -1, -1,
- NULL, 0) == -1)
- fatal("compose LOG_SYSLOG");
+ imsgev_send(&coord->iev[r],
+ FUGU_IMSG_LOG_SYSLOG, 0, NULL, 0);
}
if (++coord->nready == coord->nkids)
event_loopexit(NULL);
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- imsgev_compose(iev, FUGU_IMSG_REQUEST, id, -1, -1,
+ imsgev_send(iev, FUGU_IMSG_REQUEST, id,
body->data + off, n);
off += n;
}
memset(&end, 0, sizeof(end));
end.provider_slot = provider_slot;
- imsgev_compose(iev, FUGU_IMSG_REQUEST_END, id, -1, -1, &end,
+ imsgev_send(iev, FUGU_IMSG_REQUEST_END, id, &end,
sizeof(end));
}
memset(&req, 0, sizeof(req));
strlcpy(req.name, tc->name, sizeof(req.name));
- imsgev_compose(iev, FUGU_IMSG_TOOL_REQ, 0, -1, -1, &req, sizeof(req));
+ imsgev_send(iev, FUGU_IMSG_TOOL_REQ, 0, &req, sizeof(req));
for (off = 0; off < tc->input.len; ) {
size_t n = tc->input.len - off;
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- imsgev_compose(iev, FUGU_IMSG_TOOL_ARG, 0, -1, -1,
+ imsgev_send(iev, FUGU_IMSG_TOOL_ARG, 0,
tc->input.data + off, n);
off += n;
}
- imsgev_compose(iev, FUGU_IMSG_TOOL_RUN, 0, -1, -1, NULL, 0);
+ imsgev_send(iev, FUGU_IMSG_TOOL_RUN, 0, NULL, 0);
buf_reset(&c->tool_out);
buf_reset(&c->diff);
strlcpy(req.name, tc->name, sizeof(req.name));
c->web_id = agent_unique_id(c);
c->web_busy_id = c->web_id;
- if (imsgev_compose(iev, FUGU_IMSG_WEB_REQ, c->web_id, -1, -1, &req,
- sizeof(req)) == -1)
- fatal("compose WEB_REQ");
+ imsgev_send(iev, FUGU_IMSG_WEB_REQ, c->web_id, &req, sizeof(req));
for (off = 0; off < tc->input.len; ) {
size_t n = tc->input.len - off;
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- if (imsgev_compose(iev, FUGU_IMSG_WEB_ARG, c->web_id, -1, -1,
- tc->input.data + off, n) == -1)
- fatal("compose WEB_ARG");
+ imsgev_send(iev, FUGU_IMSG_WEB_ARG, c->web_id,
+ tc->input.data + off, n);
off += n;
}
- if (imsgev_compose(iev, FUGU_IMSG_WEB_RUN, c->web_id, -1, -1,
- NULL, 0) == -1)
- fatal("compose WEB_RUN");
+ imsgev_send(iev, FUGU_IMSG_WEB_RUN, c->web_id, NULL, 0);
c->wait = WAIT_WEB;
rc = event_dispatch();
agent_web_arg_free(c, a);
}
if (a->api_assembling || a->api_inflight) {
- if (imsgev_compose(&c->iev[ROLE_API],
- FUGU_IMSG_REQUEST_CANCEL, a->api_id, -1, -1,
- NULL, 0) == -1)
- fatal("compose failed-agent REQUEST_CANCEL");
+ imsgev_send(&c->iev[ROLE_API], FUGU_IMSG_REQUEST_CANCEL,
+ a->api_id, NULL, 0);
a->api_assembling = 0;
a->api_inflight = 1; /* cleared by the cancellation terminal */
}
fatalx("bad subagent provider request chunk");
a->api_assembling = 1;
a->request_bytes += len;
- if (imsgev_compose(&c->iev[ROLE_API], FUGU_IMSG_REQUEST,
- a->api_id, -1, -1, p, len) == -1)
- fatal("relay subagent provider request");
+ imsgev_send(&c->iev[ROLE_API], FUGU_IMSG_REQUEST,
+ a->api_id, p, len);
break;
case FUGU_IMSG_AGENT_REQUEST_END: {
struct api_request_end end;
fatalx("bad subagent provider request end");
memset(&end, 0, sizeof(end));
end.provider_slot = a->provider_slot;
- if (imsgev_compose(&c->iev[ROLE_API],
- FUGU_IMSG_REQUEST_END, a->api_id, -1, -1, &end,
- sizeof(end)) == -1)
- fatal("relay subagent request end");
+ imsgev_send(&c->iev[ROLE_API], FUGU_IMSG_REQUEST_END,
+ a->api_id, &end, sizeof(end));
a->api_assembling = 0;
a->api_inflight = 1;
a->request_bytes = 0;
static void
ctx_read_project(struct coord *c, const char *path)
{
- imsgev_compose(&c->iev[ROLE_TOOL], FUGU_IMSG_CTX_READ, 0, -1, -1,
+ imsgev_send(&c->iev[ROLE_TOOL], FUGU_IMSG_CTX_READ, 0,
path, strlen(path));
buf_reset(&c->ctx_data);
c->ctx_done = 0;
n = len - off;
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- if (imsgev_compose(iev, type, 0, -1, -1, p + off, n) == -1)
- fatal("compose subagent launch bytes");
+ imsgev_send(iev, type, 0, p + off, n);
}
}
buf_addc(&b, '\0');
buf_addstr(&b, a->label);
buf_addc(&b, '\0');
- if (imsgev_compose(&a->iev, FUGU_IMSG_AGENT_START, 0, -1, -1,
- b.data, b.len) == -1)
- fatal("compose AGENT_START");
+ imsgev_send(&a->iev, FUGU_IMSG_AGENT_START, 0, b.data, b.len);
buf_free(&b);
agent_compose_bytes(&a->iev, FUGU_IMSG_AGENT_SYSTEM, system->data,
system->len);
agent_compose_bytes(&a->iev, FUGU_IMSG_AGENT_PROMPT, a->prompt.data,
a->prompt.len);
- if (imsgev_compose(&a->iev, FUGU_IMSG_AGENT_RUN, 0, -1, -1,
- NULL, 0) == -1)
- fatal("compose AGENT_RUN");
+ imsgev_send(&a->iev, FUGU_IMSG_AGENT_RUN, 0, NULL, 0);
}
static void
if (cancel && (a->api_assembling || a->api_inflight)) {
cancelled_id_add(c->cancelled_api, &c->ncancelled_api,
a->api_id);
- if (imsgev_compose(&c->iev[ROLE_API],
- FUGU_IMSG_REQUEST_CANCEL, a->api_id, -1, -1,
- NULL, 0) == -1)
- fatal("compose subagent REQUEST_CANCEL");
+ imsgev_send(&c->iev[ROLE_API], FUGU_IMSG_REQUEST_CANCEL,
+ a->api_id, NULL, 0);
a->api_assembling = 0;
a->api_inflight = 0;
}
}
if (a->kid.fd >= 0) {
if (cancel) {
- (void)imsgev_compose(&a->iev, FUGU_IMSG_SHUTDOWN, 0,
- -1, -1, NULL, 0);
- (void)imsgbuf_flush(&a->iev.ibuf);
+ imsgev_send_teardown(&a->iev,
+ FUGU_IMSG_SHUTDOWN);
(void)kill(a->kid.pid, SIGTERM);
}
imsgev_clear(&a->iev);
buf_addstr(&m, "\n- ");
buf_addstr(&m, text);
buf_addc(&m, '\n');
- imsgev_compose(&c->iev[ROLE_TOOL], FUGU_IMSG_CTX_APPEND, 0, -1, -1,
+ imsgev_send(&c->iev[ROLE_TOOL], FUGU_IMSG_CTX_APPEND, 0,
m.data, m.len);
buf_free(&m);
c->listed_models = NULL;
c->nlisted_models = 0;
c->models_collecting = 1;
- imsgev_compose(&c->iev[ROLE_API],
- FUGU_IMSG_LIST_MODELS, 0, -1, -1, NULL, 0);
+ imsgev_send(&c->iev[ROLE_API],
+ FUGU_IMSG_LIST_MODELS, 0, NULL, 0);
emit_note(c, "fetching the model list...");
} else
fprintf(stderr, "fugu: /model is interactive-only\n");
for (role = ROLE_TTY; role < ROLE_MAX; role++) {
if (c->kids[role].pid <= 0)
continue;
- (void)imsgev_compose(&c->iev[role], FUGU_IMSG_SHUTDOWN, 0,
- -1, -1, NULL, 0);
- (void)imsgbuf_flush(&c->iev[role].ibuf);
+ imsgev_send_teardown(&c->iev[role], FUGU_IMSG_SHUTDOWN);
}
/* Give cooperative workers time to dispatch SHUTDOWN and run atexit.
* In particular fugu-tty must restore termios/bracketed paste before a
blob - 2935e1ff82c36ffc61949854b34bf9e6fe29eda1
blob + c6f79ced52336f1652d68757b1b3409f1ade861f
--- src/fugu-api/main.c
+++ src/fugu-api/main.c
relay_id(struct worker *w, uint32_t id, uint32_t type, const void *data,
size_t len)
{
- if (imsgev_compose(&w->iev, type, id, -1, -1, data, len) == -1)
- fatal("compose provider event");
+ imsgev_send(&w->iev, type, id, data, len);
}
static void
blob - 7840fd7766fb54edcb5b70b8462764f98d184973
blob + a8a09dd372615a9daec10e4c7d8ee5ac4e2ecfdf
--- src/fugu-editor/main.c
+++ src/fugu-editor/main.c
memset(&r, 0, sizeof(r));
r.ok = ok;
r.reason = reason;
- if (imsgev_compose(&w->iev, FUGU_IMSG_EDIT_RESULT, 0, -1, -1, &r,
- sizeof(r)) == -1)
- fatal("compose EDIT_RESULT");
+ imsgev_send(&w->iev, FUGU_IMSG_EDIT_RESULT, 0, &r, sizeof(r));
}
/*
send_result(w, 0, EDIT_R_OVERSIZE);
return;
}
- if (imsgev_compose(&w->iev, FUGU_IMSG_EDIT_DATA, 0, -1, -1,
- tmp, (size_t)n) == -1)
- fatal("compose EDIT_DATA");
+ imsgev_send(&w->iev, FUGU_IMSG_EDIT_DATA, 0, tmp,
+ (size_t)n);
sent += (size_t)n;
}
close(fd);
blob - 2f07ba49a039d9992f3210584cd7ced3f6ef9042
blob + 07b7f6d8e57a4e1802416d7fe25b7a3b420d0546
--- src/fugu-tool/main.c
+++ src/fugu-tool/main.c
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- imsgev_compose(&w->iev, FUGU_IMSG_TOOL_OUT, 0, -1, -1,
+ imsgev_send(&w->iev, FUGU_IMSG_TOOL_OUT, 0,
out->data + off, n);
off += n;
}
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- imsgev_compose(&w->iev, FUGU_IMSG_TOOL_DIFF, 0, -1, -1,
+ imsgev_send(&w->iev, FUGU_IMSG_TOOL_DIFF, 0,
diff->data + off, n);
off += n;
}
memset(&r, 0, sizeof(r));
r.is_error = is_error;
- imsgev_compose(&w->iev, FUGU_IMSG_TOOL_RESULT, 0, -1, -1, &r,
+ imsgev_send(&w->iev, FUGU_IMSG_TOOL_RESULT, 0, &r,
sizeof(r));
}
if (type == FUGU_IMSG_TOOL_TURN_ABORT)
cancel_tool = 0;
ack.control = type;
- if (imsgev_compose(&w->iev, FUGU_IMSG_TOOL_TURN_ACK, 0,
- -1, -1, &ack, sizeof(ack)) == -1)
- fatal("compose TURN_ACK");
+ imsgev_send(&w->iev, FUGU_IMSG_TOOL_TURN_ACK, 0, &ack,
+ sizeof(ack));
return (0);
}
case FUGU_IMSG_TOOL_REQ: {
if (k > FUGU_CHUNK)
k = FUGU_CHUNK;
- imsgev_compose(&w->iev, FUGU_IMSG_CTX_DATA, 0, -1, -1,
+ imsgev_send(&w->iev, FUGU_IMSG_CTX_DATA, 0,
ctx.data + off, k);
off += k;
}
- imsgev_compose(&w->iev, FUGU_IMSG_CTX_END, 0, -1, -1, NULL, 0);
+ imsgev_send(&w->iev, FUGU_IMSG_CTX_END, 0, NULL, 0);
buf_free(&ctx);
return (0);
}
r.reason = ctx_file_append(ts->ctx, path, bytes,
len - plen - 1);
r.ok = (r.reason == 0);
- imsgev_compose(&w->iev, FUGU_IMSG_CTX_RESULT, 0, -1, -1, &r,
+ imsgev_send(&w->iev, FUGU_IMSG_CTX_RESULT, 0, &r,
sizeof(r));
return (0);
}
blob - a3bfff69f738ee02517ed6fd50a3bd136efdecc8
blob + 5606c58654257e575fb61aaa0b53c773f7495e87
--- src/fugu-tty/ui.c
+++ src/fugu-tty/ui.c
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- imsgev_compose(&u->w->iev, chunk_type, 0, -1, -1, p + off, n);
+ imsgev_send(&u->w->iev, chunk_type, 0, p + off, n);
off += n;
}
- imsgev_compose(&u->w->iev, end_type, 0, -1, -1, NULL, 0);
+ imsgev_send(&u->w->iev, end_type, 0, NULL, 0);
}
static void
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- imsgev_compose(&u->w->iev, FUGU_IMSG_UI_COMPOSE, 0, -1, -1,
+ imsgev_send(&u->w->iev, FUGU_IMSG_UI_COMPOSE, 0,
text + off, n);
off += n;
}
- imsgev_compose(&u->w->iev, FUGU_IMSG_UI_COMPOSE_GO, 0, -1, -1,
+ imsgev_send(&u->w->iev, FUGU_IMSG_UI_COMPOSE_GO, 0,
NULL, 0);
u->composing = 1;
}
break;
case K_ENTER:
if (u->drawer_sel == 0) { /* a fresh session */
- imsgev_compose(&u->w->iev, FUGU_IMSG_UI_SWITCH, 0,
- -1, -1, NULL, 0);
+ imsgev_send(&u->w->iev, FUGU_IMSG_UI_SWITCH, 0,
+ NULL, 0);
strlcpy(u->notice, "switching...", sizeof(u->notice));
} else {
struct sess *s = &u->sess[u->drawer_sel - 1];
drawer_close(u);
break;
}
- imsgev_compose(&u->w->iev, FUGU_IMSG_UI_SWITCH, 0,
- -1, -1, s->id, strlen(s->id));
+ imsgev_send(&u->w->iev, FUGU_IMSG_UI_SWITCH, 0,
+ s->id, strlen(s->id));
strlcpy(u->notice, "switching...", sizeof(u->notice));
}
break;
buf_init(&b);
buf_add(&b, &sel, sizeof(sel));
buf_addstr(&b, m->id);
- imsgev_compose(&u->w->iev, FUGU_IMSG_UI_SELECT_MODEL, 0,
- -1, -1, b.data, b.len);
+ imsgev_send(&u->w->iev, FUGU_IMSG_UI_SELECT_MODEL, 0,
+ b.data, b.len);
buf_free(&b);
pick_close(u);
break;
case R_QUIT:
/* ask the coordinator to quit; it will send SHUTDOWN back,
* which restores the terminal and exits cleanly */
- imsgev_compose(&u->w->iev, FUGU_IMSG_UI_QUIT, 0, -1, -1,
+ imsgev_send(&u->w->iev, FUGU_IMSG_UI_QUIT, 0,
NULL, 0);
break;
case R_SCROLL_LINE_UP: scroll_by(u, -1); break;
blob - efcc30a384f2600ea0ffd58567d501f97d1025dc
blob + c2665884939d8193e3321c1b2f77f94048dae9bd
--- src/fugu-web/main.c
+++ src/fugu-web/main.c
if (n > FUGU_CHUNK)
n = FUGU_CHUNK;
- if (imsgev_compose(&w->iev, FUGU_IMSG_WEB_OUT, reqid, -1, -1,
- out->data + off, n) == -1)
- fatal("compose WEB_OUT");
+ imsgev_send(&w->iev, FUGU_IMSG_WEB_OUT, reqid,
+ out->data + off, n);
off += n;
}
memset(&r, 0, sizeof(r));
r.is_error = is_error;
- if (imsgev_compose(&w->iev, FUGU_IMSG_WEB_RESULT, reqid, -1, -1, &r,
- sizeof(r)) == -1)
- fatal("compose WEB_RESULT");
+ imsgev_send(&w->iev, FUGU_IMSG_WEB_RESULT, reqid, &r, sizeof(r));
}
static int