#include "spawn_utils.h"
typedef enum SyscallId { SyscallRead, SyscallWrite, SyscallClose } SyscallId;
typedef struct Command {
SyscallId id;
uint64_t buf_ptr;
uint64_t len_ptr;
size_t fd_index;
} Command;
typedef struct Data {
uint8_t* ptr;
uint64_t offset;
uint64_t total_size;
} Data;
int extract_command(Data* data, Command* cmd) {
if ((data->offset + 1) > data->total_size) {
return -1;
}
uint8_t id = data->ptr[0];
if (id > 250) {
cmd->id = SyscallClose;
cmd->fd_index = (size_t)(id % 2);
data->offset += 1;
} else if (id > 128) {
if ((data->offset + 7) > data->total_size) {
return -1;
}
cmd->id = SyscallRead;
memcpy(&cmd->buf_ptr, &data->ptr[data->offset + 1], 3);
memcpy(&cmd->len_ptr, &data->ptr[data->offset + 4], 3);
data->offset += 7;
} else {
if ((data->offset + 7) > data->total_size) {
return -1;
}
cmd->id = SyscallWrite;
memcpy(&cmd->buf_ptr, &data->ptr[data->offset + 1], 3);
memcpy(&cmd->len_ptr, &data->ptr[data->offset + 4], 3);
data->offset += 7;
}
return 0;
}
int random_read_write(uint64_t fds[2], size_t index) {
int err = 0;
uint8_t cmd_buf[4096] = {0};
uint64_t cmd_len = sizeof(cmd_buf);
err = ckb_load_witness(cmd_buf, &cmd_len, 0, index, CKB_SOURCE_INPUT);
CHECK(err);
Data data = {.ptr = cmd_buf, .total_size = cmd_len, .offset = 0};
while (true) {
Command cmd = {0};
err = extract_command(&data, &cmd);
if (err) break;
if (cmd.id == SyscallRead) {
ckb_read(fds[CKB_STDIN], (void*)cmd.buf_ptr, (uint64_t*)cmd.len_ptr);
} else if (cmd.id == SyscallWrite) {
ckb_write(fds[CKB_STDOUT], (void*)cmd.buf_ptr, (uint64_t*)cmd.len_ptr);
} else if (cmd.id == SyscallClose) {
ckb_close(fds[cmd.fd_index]);
} else {
CHECK2(false, -1);
}
}
exit:
return err;
}
int parent_entry() {
int err = 0;
uint64_t pid = 0;
const char* argv[] = {"", 0};
uint64_t fds[2] = {0};
err = full_spawn(0, 1, argv, fds, &pid);
CHECK(err);
random_read_write(fds, 0);
int8_t exit_code = 0;
err = ckb_wait(pid, &exit_code);
CHECK(err);
CHECK(exit_code);
exit:
return err;
}
int child_entry() {
int err = 0;
uint64_t inherited_fds[2];
size_t inherited_fds_length = 2;
err = ckb_inherited_fds(inherited_fds, &inherited_fds_length);
CHECK(err);
random_read_write(inherited_fds, 0);
exit:
return err;
}
int main(int argc, const char* argv[]) {
if (argc > 0) {
return child_entry();
} else {
return parent_entry();
}
}