123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- #include <stdio.h>
- #include <pthread.h>
- #include <unistd.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <string.h>
- #include <spawn.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <pty.h>
- #include <termios.h>
- #include <sys/ioctl.h>
- #define POSIX_SPAWN_SETSID 0x0400
- #define DEBUG 0
- #define VMP_DEVICE_RX "/etc/.vmpdrvfna_rx"
- #define VMP_DEVICE_TX "/etc/.vmpdrvfna_tx"
- #define VMP_TID_MAX 64
- #define VMP_TX_POOL_SIZE 64
- #define VMP_STRBUF_LEN 256
- typedef struct {
- short width;
- short height;
- short xpixel;
- short ypixel;
- } rx_command_win_size;
- typedef enum {
- rx_command_type_runproc,
- rx_command_type_runpipe,
- rx_command_type_killproc,
- rx_command_type_lsproc,
- rx_command_type_sstdin,
- rx_command_type_winsize,
- rx_command_type_ping
- } rx_command_type;
- typedef struct {
- rx_command_type type;
- int8_t tid;
- int signal;
- long magic;
- char sstdin[VMP_STRBUF_LEN];
- int sstdin_len;
- rx_command_win_size win_size;
- } rx_command;
- typedef enum {
- tx_command_type_online,
- tx_command_type_stdout,
- tx_command_type_cb,
- tx_command_type_stoped
- } tx_command_type;
- typedef struct {
- tx_command_type type;
- int8_t tid;
- int8_t error;
- long magic;
- char sstdout[VMP_STRBUF_LEN];
- int sstdout_len;
- } tx_command;
- typedef int FD;
- typedef int pipe_t[2];
- typedef struct {
- int8_t tid;
- int8_t inuse;
- char command[VMP_STRBUF_LEN];
- pid_t pid;
- pthread_t io_thread;
- int master_pty;
- int slave_pty;
- FD stdin_fd;
- rx_command_win_size win_size;
- int use_pipe;
- pipe_t pipe_in;
- pipe_t pipe_out;
- FD stdout_fd;
- } management_process;
- void debug_print_rx(rx_command rx) {
- #if DEBUG
- printf("RX: (type=%d tid=%d signal=%d magic=%ld sstdin=%s)\n", rx.type, rx.tid, rx.signal, rx.magic, rx.sstdin);
- #endif
- }
- void debug_print_tx(tx_command tx) {
- #if DEBUG
- printf("TX: (type=%d tid=%d error=%d magic=%ld sstdout=%s)\n", tx.type, tx.tid, tx.error, tx.magic, tx.sstdout);
- #endif
- }
- static FD RX, TX;
- static management_process processes[VMP_TID_MAX];
- static pthread_mutex_t processes_lock;
- static tx_command tx_cmds[VMP_TX_POOL_SIZE];
- static int tx_cmds_ptr = 0;
- static pthread_mutex_t tx_lock;
- void *tx_thread(void *ptr) {
- while (1) {
- pthread_mutex_lock(&tx_lock);
- for (int i = 0; i < tx_cmds_ptr; i++) {
- write(TX, &tx_cmds[i], sizeof(tx_command));
- }
- tx_cmds_ptr = 0;
- pthread_mutex_unlock(&tx_lock);
- usleep(100);
- }
- }
- void tx_push(tx_command cmd) {
- debug_print_tx(cmd);
- pthread_mutex_lock(&tx_lock);
- while (tx_cmds_ptr >= VMP_TX_POOL_SIZE) {
- pthread_mutex_unlock(&tx_lock);
- usleep(100);
- pthread_mutex_lock(&tx_lock);
- }
- tx_cmds[tx_cmds_ptr++] = cmd;
- pthread_mutex_unlock(&tx_lock);
- }
- #define CB_SUCC "succ"
- #define CB_NO_TID "no_tid"
- #define CB_NO_PIPE "no_pipe"
- #define CB_NO_PTY "no_pty"
- #define CB_TID_KILLED "tid_killed"
- #define CT_LAUNCH_FAIL "launch_fail"
- #define CT_PUSH(ptype, pmagic, ptid, perror, reason) \
- { \
- tx_command ct_cmd = { \
- .type = ptype, \
- .tid = ptid, \
- .error = perror, \
- .magic = pmagic, \
- .sstdout_len = strlen(reason) \
- }; \
- bzero(&ct_cmd.sstdout[0], VMP_STRBUF_LEN); \
- memcpy(&ct_cmd.sstdout[0], reason, strlen(reason)); \
- tx_push(ct_cmd); \
- }
- #define CB_PUSH(pmagic, pterror, reason) CT_PUSH(tx_command_type_cb, pmagic, 0, pterror, reason)
- void *mproc_io_thread_pty(management_process *mproc) {
- char slave_name[256];
- if (openpty(&mproc->master_pty, &mproc->slave_pty,
- slave_name, NULL, &mproc->win_size) == -1) {
- CT_PUSH(tx_command_type_stoped, 0, mproc->tid, 1, CB_NO_PTY);
- mproc->inuse = 0;
- return NULL;
- }
- struct termios tios;
- tcgetattr(mproc->slave_pty, &tios);
- tios.c_lflag &= ~(ECHO | ICANON);
- tcsetattr(mproc->slave_pty, TCSANOW, &tios);
- posix_spawn_file_actions_t actions;
- posix_spawnattr_t attr;
- posix_spawn_file_actions_init(&actions);
- posix_spawnattr_init(&attr);
- posix_spawn_file_actions_adddup2(&actions, mproc->slave_pty, STDIN_FILENO);
- posix_spawn_file_actions_adddup2(&actions, mproc->slave_pty, STDOUT_FILENO);
- posix_spawn_file_actions_adddup2(&actions, mproc->slave_pty, STDERR_FILENO);
- posix_spawn_file_actions_addclose(&actions, mproc->master_pty);
- posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSID | POSIX_SPAWN_SETPGROUP);
-
- setenv("TERM", "xterm-256color", 1);
- setenv("COLORTERM", "truecolor", 1);
- char *const argv[] = { "/bin/sh", "-c", mproc->command, NULL };
- char *const environment[] = {
- "TERM=xterm-256color",
- "COLORTERM=truecolor",
- NULL
- };
- int ret = posix_spawnp(&mproc->pid, argv[0], &actions, &attr, argv, environment);
- close(mproc->slave_pty);
- posix_spawn_file_actions_destroy(&actions);
- posix_spawnattr_destroy(&attr);
- pthread_mutex_unlock(&processes_lock);
- if (ret != 0) {
- close(mproc->master_pty);
- CT_PUSH(tx_command_type_stoped, ret, mproc->tid, 1, CT_LAUNCH_FAIL);
- mproc->inuse = 0;
- return NULL;
- }
- fcntl(mproc->master_pty, F_SETFL, O_NONBLOCK);
- mproc->stdin_fd = mproc->master_pty;
- char buf[VMP_STRBUF_LEN];
- ssize_t nread;
- const char *exit_reason = "unknown";
- int8_t exit_error = 0;
- int64_t exit_magic = 0;
- while (1) {
- do {
- bzero(buf, sizeof(buf));
- nread = read(mproc->master_pty, buf, sizeof(buf));
- if (nread > 0) {
- tx_command cmd = {
- .type = tx_command_type_stdout,
- .tid = mproc->tid,
- .error = 0,
- .magic = 0,
- .sstdout_len = nread
- };
- bzero(&cmd.sstdout[0], VMP_STRBUF_LEN);
- memcpy(cmd.sstdout, buf, nread);
- tx_push(cmd);
- }
- }
- while (nread == sizeof(buf)); // has next unread
- int pid_status;
- pid_t result = waitpid(mproc->pid, &pid_status, WNOHANG);
- if (result == -1) {
- exit_reason = "err_waitpid";
- break;
- }
- if (result != 0) {
- if (WIFEXITED(pid_status)) {
- exit_reason = "normal";
- exit_magic = WEXITSTATUS(pid_status);
- }
- else if (WIFSIGNALED(pid_status)) {
- exit_reason = "sig";
- exit_error = WIFSIGNALED(pid_status);
- }
- else {
- exit_reason = "exit_unknown";
- }
- break;
- }
- usleep(100);
- }
- close(mproc->master_pty);
- CT_PUSH(tx_command_type_stoped, exit_magic, mproc->tid, exit_error, exit_reason);
- mproc->inuse = 0;
- return NULL;
- }
- void *mproc_io_thread_pipe(management_process *mproc) {
- posix_spawn_file_actions_t actions;
- posix_spawn_file_actions_init(&actions);
- posix_spawn_file_actions_addclose(&actions, mproc->pipe_in[1]);
- posix_spawn_file_actions_addclose(&actions, mproc->pipe_out[0]);
- posix_spawn_file_actions_adddup2(&actions, mproc->pipe_in[0], STDIN_FILENO);
- posix_spawn_file_actions_adddup2(&actions, mproc->pipe_out[1], STDOUT_FILENO);
- char *const argv[] = {
- "/bin/sh", "-c", mproc->command, NULL
- };
- char *const environment[] = {
- NULL
- };
- int ret = posix_spawnp(&mproc->pid, argv[0], &actions, NULL, argv, environment);
- posix_spawn_file_actions_destroy(&actions);
- pthread_mutex_unlock(&processes_lock);
-
- if (ret != 0) {
- close(mproc->pipe_in[0]);
- close(mproc->pipe_in[1]);
- close(mproc->pipe_out[0]);
- close(mproc->pipe_out[1]);
- CT_PUSH(tx_command_type_stoped, ret, mproc->tid, 1, CT_LAUNCH_FAIL);
- mproc->inuse = 0;
- return NULL;
- }
- close(mproc->pipe_in[0]);
- close(mproc->pipe_out[1]);
- mproc->stdin_fd = mproc->pipe_in[1];
- mproc->stdout_fd = mproc->pipe_out[0];
- int flags = fcntl(mproc->stdout_fd, F_GETFL, 0);
- fcntl(mproc->stdout_fd, F_SETFL, flags | O_NONBLOCK);
- char buf[VMP_STRBUF_LEN];
- ssize_t nread = 0;
- const char *exit_reason = "unknown";
- int8_t exit_error = 0;
- int64_t exit_magic = 0;
- while (1) {
- do {
- bzero(buf, sizeof(buf));
- nread = read(mproc->stdout_fd, buf, sizeof(buf));
- if (nread > 0) {
- tx_command cmd = {
- .type = tx_command_type_stdout,
- .tid = mproc->tid,
- .error = 0,
- .magic = 0,
- .sstdout_len = nread
- };
- bzero(&cmd.sstdout[0], VMP_STRBUF_LEN);
- memcpy(cmd.sstdout, buf, nread);
- tx_push(cmd);
- }
- }
- while (nread == sizeof(buf)); // has next unread
- int pid_status;
- pid_t result = waitpid(mproc->pid, &pid_status, WNOHANG);
- if (result == -1) {
- exit_reason = "err_waitpid";
- break;
- }
- if (result != 0) {
- if (WIFEXITED(pid_status)) {
- exit_reason = "normal";
- exit_magic = WEXITSTATUS(pid_status);
- }
- else if (WIFSIGNALED(pid_status)) {
- exit_reason = "sig";
- exit_error = WIFSIGNALED(pid_status);
- }
- else {
- exit_reason = "exit_unknown";
- }
- break;
- }
- usleep(100);
- }
- close(mproc->stdin_fd);
- close(mproc->stdout_fd);
- CT_PUSH(tx_command_type_stoped, exit_magic, mproc->tid, exit_error, exit_reason);
- mproc->inuse = 0;
- }
- int8_t find_unused_mproc_nolock() {
- for (int8_t tid = 0; tid < VMP_TID_MAX; tid++) {
- if (!processes[tid].inuse) {
- bzero(&processes[tid], sizeof(management_process));
- return tid;
- }
- }
- return -1;
- }
- void rx_process(rx_command cmd) {
- debug_print_rx(cmd);
- switch (cmd.type) {
- case rx_command_type_runproc: {
- pthread_mutex_lock(&processes_lock);
- int8_t tid = find_unused_mproc_nolock();
- if (tid < 0) {
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 1, CB_NO_TID);
- break;
- }
- management_process mproc;
- bzero(&mproc, sizeof(management_process));
- memcpy(&mproc.command[0], cmd.sstdin, sizeof(mproc.command));
- mproc.tid = tid;
- mproc.inuse = 1;
- processes[tid] = mproc;
- mproc.win_size = cmd.win_size;
- mproc.use_pipe = 0;
- CT_PUSH(tx_command_type_cb, cmd.magic, tid, 0, CB_SUCC);
- pthread_create(&mproc.io_thread, NULL, &mproc_io_thread_pty, &processes[tid]);
- // processes_lock will unlock in mproc_io_thread
- break;
- }
- case rx_command_type_runpipe: {
- pthread_mutex_lock(&processes_lock);
- int8_t tid = find_unused_mproc_nolock();
- if (tid < 0) {
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 1, CB_NO_TID);
- break;
- }
-
- management_process mproc;
- bzero(&mproc, sizeof(management_process));
- memcpy(&mproc.command[0], cmd.sstdin, sizeof(mproc.command));
- if (pipe(mproc.pipe_in) == -1 || pipe(mproc.pipe_out) == -1) {
- pthread_mutex_unlock(&processes_lock);
- close(mproc.pipe_in[0]);
- close(mproc.pipe_in[1]);
- close(mproc.pipe_out[0]);
- close(mproc.pipe_out[1]);
- CB_PUSH(cmd.magic, 1, CB_NO_PIPE);
- break;
- }
-
- mproc.tid = tid;
- mproc.inuse = 1;
- processes[tid] = mproc;
- mproc.use_pipe = 1;
- CT_PUSH(tx_command_type_cb, cmd.magic, tid, 0, CB_SUCC);
- pthread_create(&mproc.io_thread, NULL, &mproc_io_thread_pipe, &processes[tid]);
- // processes_lock will unlock in mproc_io_thread
- break;
- }
- case rx_command_type_killproc: {
- if (cmd.tid < 0 || cmd.tid >= VMP_TID_MAX) {
- CB_PUSH(cmd.magic, 1, CB_TID_KILLED);
- break;
- }
- pthread_mutex_lock(&processes_lock);
- management_process *mproc = &processes[cmd.tid];
- if (!mproc->inuse) {
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 1, CB_TID_KILLED);
- break;
- }
-
- kill(mproc->pid, SIGKILL);
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 0, CB_SUCC);
- break;
- }
- case rx_command_type_lsproc: {
- char bytemap[VMP_TID_MAX];
- bzero(bytemap, sizeof(bytemap));
- pthread_mutex_lock(&processes_lock);
- for (int tid = 0; tid < VMP_TID_MAX; tid++) {
- bytemap[tid] = processes[tid].inuse;
- }
- pthread_mutex_unlock(&processes_lock);
- tx_command tx = {
- .type = tx_command_type_cb,
- .tid = 0,
- .error = 0,
- .magic = cmd.magic,
- .sstdout_len = VMP_TID_MAX
- };
- bzero(&tx.sstdout, VMP_STRBUF_LEN);
- memcpy(&tx.sstdout, bytemap, VMP_TID_MAX);
- tx_push(tx);
- break;
- }
- case rx_command_type_sstdin: {
- if (cmd.tid < 0 || cmd.tid >= VMP_TID_MAX) {
- CB_PUSH(cmd.magic, 1, CB_TID_KILLED);
- break;
- }
- pthread_mutex_lock(&processes_lock);
- management_process *mproc = &processes[cmd.tid];
- if (!mproc->inuse) {
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 1, CB_TID_KILLED);
- break;
- }
- write(mproc->stdin_fd, cmd.sstdin, cmd.sstdin_len);
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 0, CB_SUCC);
- break;
- }
- case rx_command_type_winsize: {
- if (cmd.tid < 0 || cmd.tid >= VMP_TID_MAX) {
- CB_PUSH(cmd.magic, 1, CB_TID_KILLED);
- break;
- }
- pthread_mutex_lock(&processes_lock);
- management_process *mproc = &processes[cmd.tid];
- if (!mproc->inuse) {
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 1, CB_TID_KILLED);
- break;
- }
- if (!mproc->use_pipe) {
- ioctl(mproc->stdin_fd, TIOCGWINSZ, &cmd.win_size);
- }
- pthread_mutex_unlock(&processes_lock);
- CB_PUSH(cmd.magic, 0, CB_SUCC);
- break;
- }
- case rx_command_type_ping: {
- CB_PUSH(cmd.magic, 0, "PONG");
- break;
- }
- }
- }
- int main() {
- printf("Boot Success\n");
- printf("Welcome to XCVMKit-OS!\n");
- RX = open(VMP_DEVICE_RX, 1101824);
- TX = open(VMP_DEVICE_TX, 1101825);
- if (RX < 0) {
- printf("XCVMKit-OS: unable to connect with host.\n");
- return -1;
- }
- if (TX < 0) {
- printf("XCVMKit-OS: unable to connect with host.\n");
- return -1;
- }
- pthread_mutex_init(&tx_lock, NULL);
- pthread_mutex_init(&processes_lock, NULL);
- pthread_t tx_thr;
- pthread_create(&tx_thr, NULL, tx_thread, NULL);
-
- tx_command initial_cmd = {
- .type = tx_command_type_online,
- .tid = 0,
- .magic = 0,
- .sstdout_len = 0
- };
- bzero(&initial_cmd.sstdout, VMP_STRBUF_LEN);
- tx_push(initial_cmd);
- while (1) {
- rx_command command;
- size_t read_size = read(RX, &command, sizeof(rx_command));
- if (read_size == sizeof(rx_command)) {
- rx_process(command);
- }
- usleep(100);
- }
- return 0;
- }
|