418 lines
11 KiB
C
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
|