commit 9820edbf3bb79318ceea2da98db9d858ba9dfc27 from: Omar Polo date: Fri Aug 06 20:01:49 2021 UTC add builtin_{recv,send}; connect the tests with the client process commit - eff5e4e8400b014d16790889aa601331ecf4c7b3 commit + 9820edbf3bb79318ceea2da98db9d858ba9dfc27 blob - d5de3c95438a55d1f295443fc147f0a4d81127aa blob + c893cf22d1e5a2e4a857bcf8509876a8f3c522e5 --- Makefile.am +++ Makefile.am @@ -41,9 +41,13 @@ kamirepl_SOURCES = kamid.h \ utils.c \ utils.h -ninepscript_SOURCES = log.c \ +ninepscript_SOURCES = client.c \ + client.h \ + compat.h \ + log.c \ log.h \ np.y \ + sandbox.c \ script.c \ script.h \ utils.c \ blob - 1bc17659b01b849fafb4747eee506fb7a73df8b5 blob + 16e2d92655d1686171735ca8ef78d3ddb69907f9 --- control.c +++ control.c @@ -30,10 +30,11 @@ #include #include -#include "log.h" -#include "kamid.h" #include "control.h" +#include "kamid.h" #include "listener.h" +#include "log.h" +#include "utils.h" #define CONTROL_BACKLOG 5 blob - 206adff8efb288b5416f7769625059a8f204578c blob + bca55cf7f6bc0c1ff3168c8b4f1ca4435e74fd5f --- script.c +++ script.c @@ -16,20 +16,42 @@ #include "compat.h" +#include +#include +#include + #include +#include +#include +#include #include +#include +#include +#include #include #include #include #include #include +#include "client.h" #include "log.h" #include "script.h" #include "utils.h" #define DEBUG 0 +#ifndef INFTIM +#define INFTIM -1 +#endif + +static const char *argv0; + +static uint8_t *lastmsg; + +static struct imsgbuf ibuf; +static int ibuf_inuse; + static struct procs procs = TAILQ_HEAD_INITIALIZER(procs); static struct tests tests = TAILQ_HEAD_INITIALIZER(tests); @@ -435,6 +457,8 @@ op_faccess(struct op *expr, char *field) void ppf_val(FILE *f, struct value *val) { + size_t i; + switch (val->type) { case V_SYM: fprintf(f, "%s", val->v.str); @@ -453,6 +477,13 @@ ppf_val(FILE *f, struct value *val) break; case V_U32: fprintf(f, "%"PRIu32, val->v.u32); + break; + case V_MSG: + fprintf(f, "("); + for (i = 0; i < val->v.msg.len; ++i) + fprintf(f, "%x%s", val->v.msg.msg[i], + i == val->v.msg.len-1 ? "" : " "); + fprintf(f, ")"); break; default: fprintf(f, ""); @@ -1018,11 +1049,253 @@ builtin_iota(int argc) pushv(&v); return EVAL_OK; +} + +static int +builtin_send(int argc) +{ + struct ibuf *buf; + struct value v; + uint32_t len; + uint16_t slen; + int i; + + /* + * Compute the length of the packet. 4 is for the initial + * length field + */ + len = 4; + + for (i = argc; i > 0; --i) { + peekn(i, &v); + switch (v.type) { + case V_STR: + len += 2; /* count */ + len += strlen(v.v.str); + break; + + case V_U8: + len += 1; + break; + + case V_U16: + len += 2; + break; + + case V_U32: + len += 4; + break; + + default: + before_printing(); + printf("%s: can't serialize ", __func__); + pp_val(&v); + printf("\n"); + return EVAL_ERR; + } + } + + if (len > UINT16_MAX) { + before_printing(); + printf("%s: message size too long: got %d when max is %d\n", + __func__, len, UINT16_MAX); + return EVAL_ERR; + } + + if ((buf = imsg_create(&ibuf, IMSG_BUF, 0, 0, len)) == NULL) + fatal("imsg_create(%d)", len); + + imsg_add(buf, &len, sizeof(len)); + for (i = argc; i > 0; --i) { + peekn(i, &v); + switch (v.type) { + case V_STR: + slen = strlen(v.v.str); + slen = htole16(slen); + imsg_add(buf, &slen, sizeof(slen)); + imsg_add(buf, v.v.str, strlen(v.v.str)); + break; + + case V_U8: + imsg_add(buf, &v.v.u8, 1); + break; + + case V_U16: + v.v.u16 = htole16(v.v.u16); + imsg_add(buf, &v.v.u16, 2); + break; + + case V_U32: + v.v.u32 = htole32(v.v.u32); + imsg_add(buf, &v.v.u32, 4); + break; + } + } + + imsg_close(&ibuf, buf); + +#if DEBUG + { + void *data = TAILQ_FIRST(&ibuf.w.bufs)->buf; + size_t len = TAILQ_FIRST(&ibuf.w.bufs)->size; + hexdump("IMSG_BUF", data, len); + } +#endif + + if (imsg_flush(&ibuf) == -1) { + i = errno; + before_printing(); + printf("%s: imsg_flush failed: %s\n", __func__, strerror(i)); + return EVAL_ERR; + } + + return EVAL_OK; +} + +static int +builtin_recv(int argc) +{ + struct pollfd pfd; + struct value v; + struct imsg imsg; + ssize_t n, datalen; + int serrno; + + if (lastmsg != NULL) { + free(lastmsg); + lastmsg = NULL; + } + + pfd.fd = ibuf.fd; + pfd.events = POLLIN; + if (poll(&pfd, 1, INFTIM) == -1) { + serrno = errno; + before_printing(); + printf("%s: poll failed: %s\n", __func__, strerror(serrno)); + return EVAL_ERR; + } + +again: + if ((n = imsg_read(&ibuf)) == -1) { + if (errno == EAGAIN) + goto again; + fatal("imsg_read"); + } + if (n == 0) { +disconnect: + before_printing(); + printf("child disconnected\n"); + return EVAL_ERR; + } + + /* read only one message */ + if ((n = imsg_get(&ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (n == 0) + goto disconnect; + + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + switch (imsg.hdr.type) { + case IMSG_BUF: + v.type = V_MSG; + if ((v.v.msg.msg = malloc(datalen)) == NULL) + fatal("malloc"); + memcpy(v.v.msg.msg, imsg.data, datalen); + v.v.msg.len = datalen; + pushv(&v); + imsg_free(&imsg); + return EVAL_OK; + + case IMSG_CLOSE: + before_printing(); + printf("subprocess closed the connection\n"); + imsg_free(&imsg); + return EVAL_ERR; + + default: + before_printing(); + printf("got unknown message from subprocess: %d\n", + imsg.hdr.type); + imsg_free(&imsg); + return EVAL_ERR; + } } +static pid_t +spawn_client_proc(void) +{ + const char *argv[4]; + int p[2], argc = 0; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + PF_UNSPEC, p) == -1) + fatal("socketpair"); + + switch (pid = fork()) { + case -1: + fatal("cannot fork"); + case 0: + break; + default: + close(p[1]); + if (ibuf_inuse) { + msgbuf_clear(&ibuf.w); + close(ibuf.fd); + } + imsg_init(&ibuf, p[0]); + ibuf_inuse = 1; + return pid; + } + + close(p[0]); + + if (p[1] != 3) { + if (dup2(p[1], 3) == -1) + fatal("cannot setup imsg fd"); + } else if (fcntl(F_SETFD, 0) == -1) + fatal("cannot setup imsg fd"); + + argv[argc++] = argv0; + argv[argc++] = "-Tc"; + +#if DEBUG + argv[argc++] = "-v"; +#endif + + argv[argc++] = NULL; + + execvp(argv0, (char *const *)argv); + fatal("execvp"); +} + +static void +prepare_child_for_test(struct test *t) +{ + struct passwd *pw; + struct stat sb; + + if (stat(t->dir, &sb) == -1) + fatal("stat(\"%s\")", t->dir); + + if ((pw = getpwuid(sb.st_uid)) == NULL) + fatal("getpwuid(%d)", sb.st_uid); + + imsg_compose(&ibuf, IMSG_AUTH, 0, 0, -1, + pw->pw_name, strlen(pw->pw_name)+1); + imsg_compose(&ibuf, IMSG_AUTH_DIR, 0, 0, -1, + t->dir, strlen(t->dir)+1); + + if (imsg_flush(&ibuf) == -1) + fatal("imsg_flush"); +} + static int run_test(struct test *t) { + pid_t pid; + int ret; + #if DEBUG before_printing(); puts("====================="); @@ -1036,7 +1309,14 @@ run_test(struct test *t) return EVAL_SKIP; } - return eval(t->body); + pid = spawn_client_proc(); + prepare_child_for_test(t); + ret = eval(t->body); + + while (waitpid(pid, NULL, 0) != pid) + ; /* nop */ + + return ret; } int @@ -1045,7 +1325,12 @@ main(int argc, char **argv) struct env *e; struct test *t; int ch, i, r, passed = 0, failed = 0, skipped = 0; + int runclient = 0; + assert(argv0 = argv[0]); + + signal(SIGPIPE, SIG_IGN); + log_init(1, LOG_DAEMON); log_setverbose(1); @@ -1056,12 +1341,18 @@ main(int argc, char **argv) add_builtin_proc("debug", builtin_debug, 1, 1); add_builtin_proc("skip", builtin_skip, 0, 0); add_builtin_proc("iota", builtin_iota, 0, 0); + add_builtin_proc("send", builtin_send, 2, 1); + add_builtin_proc("recv", builtin_recv, 0, 0); - while ((ch = getopt(argc, argv, "nv")) != -1) { + while ((ch = getopt(argc, argv, "nT:v")) != -1) { switch (ch) { case 'n': syntaxcheck = 1; break; + case 'T': + assert(*optarg == 'c'); + runclient = 1; + break; case 'v': debug = 1; break; @@ -1074,6 +1365,9 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (runclient) + client(1, debug); + for (i = 0; i < argc; ++i) loadfile(argv[i]); @@ -1082,6 +1376,10 @@ main(int argc, char **argv) return 0; } + /* Check for root privileges. */ + if (geteuid()) + fatalx("need root privileges"); + i = 0; TAILQ_FOREACH(t, &tests, entry) { printf("===> running test \"%s\"... ", t->name); blob - 17f3b1a715d44b40d02f3bd814df9e1dd81ab96d blob + ad15a7b8674cc8967bcb70b55cd19345f30ac9f7 --- script.h +++ script.h @@ -30,6 +30,7 @@ enum { V_NUM, /* foreign */ + V_MSG, V_QID, /* casted */ @@ -46,6 +47,10 @@ struct value { uint8_t u8; uint16_t u16; uint32_t u32; + struct { + uint8_t *msg; + size_t len; + } msg; uint8_t qid[QIDSIZE]; } v; };