iobridge/iobridge_unix.h

418 lines
11 KiB
C

#ifdef NEEDS_TYPES
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <dirent.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
#include <assert.h>
#define FILE_HANDLE_TYPE FILE *
char host[] = "UNIX";
#else
struct files_t {
FILE *in;
FILE *out;
};
struct files_t *popen2(char * program, char * args[]);
int pclose2(struct files_t *fp);
#define CLEANUP_PIPE(pipe) close((pipe)[0]); close((pipe)[1])
typedef struct files_t files_t;
struct files_chain_t {
files_t files;
pid_t pid;
struct files_chain_t *next;
};
typedef struct files_chain_t files_chain_t;
static files_chain_t *files_chain;
static files_t * root_handle;
static int _do_popen2(files_chain_t *link, char * program, char * args[]) {
int child_in[2];
int child_out[2];
if (0 != pipe(child_in)) {
return -1;
}
if (0 != pipe(child_out)) {
CLEANUP_PIPE(child_in);
return -1;
}
pid_t cpid = link->pid = fork();
if (0 > cpid) {
CLEANUP_PIPE(child_in);
CLEANUP_PIPE(child_out);
return -1;
}
if (0 == cpid) {
if (0 > dup2(child_in[0], 0) || 0 > dup2(child_out[1], 1)) {
exit(1);
}
CLEANUP_PIPE(child_in);
CLEANUP_PIPE(child_out);
for (files_chain_t *p = files_chain; p; p = p->next) {
int fd_in = fileno(p->files.in);
if (fd_in != 0) {
close(fd_in);
}
int fd_out = fileno(p->files.out);
if (fd_out != 1) {
close(fd_out);
}
}
execv(program, args);
exit(1);
}
close(child_in[0]);
close(child_out[1]);
link->files.in = fdopen(child_in[1], "w");
link->files.out = fdopen(child_out[0], "r");
return 0;
}
files_t *popen2(char * program, char * args[]) {
files_chain_t *link = (files_chain_t *) malloc(sizeof (files_chain_t));
if (NULL == link) {
return NULL;
}
if (0 > _do_popen2(link, program, args)) {
free(link);
return NULL;
}
link->next = files_chain;
files_chain = link;
return (files_t *) link;
}
int pclose2(files_t *fp) {
files_chain_t **p = &files_chain;
int found = 0;
while (*p) {
if (*p == (files_chain_t *) fp) {
*p = (*p)->next;
found = 1;
break;
}
p = &(*p)->next;
}
if (!found) {
return -1;
}
if (0 > fclose(fp->in) || 0 > fclose(fp->out)) {
free((files_chain_t *) fp);
return -1;
}
int status = -1;
pid_t wait_pid;
do {
wait_pid = waitpid(((files_chain_t *) fp)->pid, &status, 0);
} while (-1 == wait_pid && EINTR == errno);
free((files_chain_t *) fp);
if (wait_pid == -1) {
return -1;
}
return status;
}
void write_be32(uint32_t value) {
fputc(value >> 24, root_handle->in);
fputc(value >> 16, root_handle->in);
fputc(value >> 8, root_handle->in);
fputc(value, root_handle->in);
}
uint32_t read_be32() {
uint32_t value = fgetc(root_handle->out) << 24;
value |= fgetc(root_handle->out) << 16;
value |= fgetc(root_handle->out) << 8;
value |= fgetc(root_handle->out);
return value;
}
int main(int argc, char * argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <command> [args...]\n", argv[0]);
exit(1);
}
if (!(root_handle = popen2(argv[1], argv + 2))) {
fprintf(stderr, "Failed to run %s.\n", argv[1]);
exit(1);
}
while(!feof(root_handle->out)) {
int packet_code = fgetc(root_handle->out);
switch(packet_code) {
case 0x01: packet_0x01(); break;
case 0x02: packet_0x02(); break;
case 0x03: packet_0x03(); break;
case 0x04: packet_0x04(); break;
case 0x05: packet_0x05(); break;
case 0x06: packet_0x06(); break;
case 0x07: packet_0x07(); break;
case 0x08: packet_0x08(); break;
case 0x09: packet_0x09(); break;
case 0x0A: packet_0x0A(); break;
case 0x0B: packet_0x0B(); break;
case 0x0C: packet_0x0C(); break;
case 0x0D: packet_0x0D(); break;
case 0x0E: packet_0x0E(); break;
case 0x0F: packet_0x0F(); break;
case 0x10: packet_0x10(); break;
case 0x11: packet_0x11(); break;
case 0x12: packet_0x12(); break;
case 0x13: packet_0x13(); break;
case 0x14: packet_0x14(); break;
case 0x15: packet_0x15(); break;
case 0x16: packet_0x16(); break;
case 0x17: packet_0x17(); break;
case 0x18: packet_0x18(); break;
case 0x19: packet_0x19(); break;
case 0x1A: packet_0x1A(); break;
case 0x1B: packet_0x1B(); break;
case 0x1C: packet_0x1C(); break;
case 0x1D: packet_0x1D(); break;
case 0x1E: packet_0x1E(); break;
case 0x1F: packet_0x1F(); break;
case 0x20: packet_0x20(); break;
case 0x21: packet_0x21(); break;
case 0x22: packet_0x22(); break;
case 0x23: packet_0x23(); break;
case 0x24: packet_0x24(); break;
case 0x25: packet_0x25(); break;
case 0x26: packet_0x26(); break;
case 0x27: packet_0x27(); break;
default: fprintf(stderr, "[IOBridge] Unknown packet code: 0x%02X\n", packet_code); exit(1);
}
}
pclose2(root_handle);
}
void child_send(int c) {
fputc(c, root_handle->in);
}
int child_recv() {
int c = fgetc(root_handle->out);
return c == EOF ? -1 : c;
}
void child_read(char ** buffer, uint32_t * size) {
*buffer = (char *) malloc(*size);
if (!*buffer) {
fprintf(stderr, "Failed to allocate %u bytes.\n", *size);
exit(1);
}
*size = fread(buffer, 1, *size, root_handle->out);
}
void stdin_read(char ** buffer, uint32_t * size) {
*buffer = (char *) malloc(*size);
if (!*buffer) {
fprintf(stderr, "Failed to allocate %u bytes.\n", *size);
exit(1);
}
*size = fread(buffer, 1, *size, stdin);
}
void child_write(uint8_t * buffer, uint32_t size) {
fwrite(buffer, 1, size, root_handle->in);
}
ssize_t read_line(char ** buffer, size_t * size) {
return getline(buffer, size, root_handle->out) != -1;
}
void write_output(uint8_t * buffer, size_t size) {
fwrite(buffer, 1, size, stdout);
}
void write_error(uint8_t * buffer, size_t size) {
fwrite(buffer, 1, size, stderr);
}
int get_key() {
int x = fgetc(stdin);
if (x == EOF) return -1;
else return x;
}
void * io_malloc(size_t size) {
return malloc(size);
}
void io_free(void * ptr) {
free(ptr);
}
void * io_realloc(void * ptr, size_t size) {
return realloc(ptr, size);
}
FILE *io_open(char *f, char *m) {
return fopen(f, m);
}
void io_close(FILE *f) {
fclose(f);
}
void io_read_file(FILE * f, uint8_t ** buf, uint32_t * len) {
*buf = (uint8_t *) malloc(*len);
*len = fread(*buf, 1, *len, f);
}
void io_write_file(FILE * f, uint8_t * buf, uint32_t len) {
fwrite(buf, 1, len, f);
}
uint32_t io_get_file_size(FILE * f) {
long pos = ftell(f);
fseek(f, 0, SEEK_END);
uint32_t size = ftell(f);
fseek(f, pos, SEEK_SET);
return size;
}
void io_seek_file(FILE_HANDLE_TYPE f, uint32_t off, uint8_t whence) {
switch (whence) {
case 0: fseek(f, off, SEEK_SET); break;
case 1: fseek(f, off, SEEK_CUR); break;
case 2: fseek(f, off, SEEK_END); break;
}
}
void io_rename(char * src, char * dst) {
rename(src, dst);
}
void io_delete(char * f) {
unlink(f);
}
void io_mkdir(char * src) {
mkdir(src, 0777);
}
void io_rmdir(char * src) {
rmdir(src);
}
void io_chdir(char * src) {
chdir(src);
}
void io_getcwd(char ** buffer) {
uint32_t size = PATH_MAX;
*buffer = (char *) malloc(size);
if (!getcwd(*buffer, size)) {
free(*buffer);
*buffer = NULL;
}
}
unsigned long io_time() {
return time(NULL);
}
void io_localtime(uint32_t * year, uint8_t * month, uint8_t * day, uint8_t * hour, uint8_t * minute, uint8_t * second) {
struct tm * timeinfo;
time_t rawtime;
time(&rawtime);
timeinfo = localtime(&rawtime);
*year = timeinfo->tm_year + 1900;
*month = timeinfo->tm_mon + 1;
*day = timeinfo->tm_mday;
*hour = timeinfo->tm_hour;
*minute = timeinfo->tm_min;
*second = timeinfo->tm_sec;
}
void io_gmtime(uint32_t * year, uint8_t * month, uint8_t * day, uint8_t * hour, uint8_t * minute, uint8_t * second) {
struct tm * timeinfo;
time_t rawtime;
time(&rawtime);
timeinfo = gmtime(&rawtime);
*year = timeinfo->tm_year + 1900;
*month = timeinfo->tm_mon + 1;
*day = timeinfo->tm_mday;
*hour = timeinfo->tm_hour;
*minute = timeinfo->tm_min;
*second = timeinfo->tm_sec;
}
void io_sleep(uint32_t time) {
usleep(time * 1000);
}
void term_cooked() {
struct termios cooked;
tcgetattr(STDIN_FILENO, &cooked);
cooked.c_lflag |= (ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &cooked);
}
void term_raw() {
struct termios raw;
tcgetattr(STDIN_FILENO, &raw);
raw.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
}
void term_bounds(uint32_t * width, uint32_t * height) {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
*width = w.ws_col;
*height = w.ws_row;
}
void term_flush() { fflush(stdout); }
void io_flush(FILE_HANDLE_TYPE f) { fflush(f); }
uint8_t get_errno() { return errno; }
uint8_t file_exists(char * path) {
struct stat st;
return stat(path, &st) == 0;
}
void io_handle_packet_0x25() {
uint32_t len = read_be32();
uint8_t * data; child_read((char **) &data, &len);
if(data[len - 1] == 0) data[len - 1] = 0x00;
DIR * dir = opendir((char *) data);
if(dir == NULL) {
child_send(0x25);
write_be32(0);
io_free(data);
return;
}
struct dirent * ent;
vector(uint8_t) buffer = NULL;
while((ent = readdir(dir)) != NULL) {
uint32_t len = strlen(ent->d_name) + 1;
vector_push_back(buffer, (len >> 8) & 0xff);
vector_push_back(buffer, len & 0xff);
for (int i = 0; i < len; i++) {
vector_push_back(buffer, ent->d_name[i]);
}
vector_push_back(buffer, ent->d_type);
}
closedir(dir);
child_send(0x25);
write_be32(vector_size(buffer));
child_write(buffer, vector_size(buffer));
vector_free(data);
}
#endif