#define _POSIX_C_SOURCE 200809L #define _DEFAULT_SOURCE #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include char stdinName[PATH_MAX]; char stdoutName[PATH_MAX]; char stderrName[PATH_MAX]; char ctrlinName[PATH_MAX]; char ctrloutName[PATH_MAX]; char progRunning = 0; char progQuit = 0; sig_atomic_t progStatus = 0; pid_t child = 0; char * normalize_path(const char * src, char * res) { size_t src_len = strlen(src); size_t res_len; const char * ptr = src; const char * end = &src[src_len]; const char * next; if (src_len == 0 || src[0] != '/') { // relative path char pwd[PATH_MAX]; size_t pwd_len; if (getcwd(pwd, sizeof(pwd)) == NULL) { return NULL; } pwd_len = strlen(pwd); //res = malloc(pwd_len + 1 + src_len + 1); memcpy(res, pwd, pwd_len); res_len = pwd_len; } else { //res = malloc((src_len > 0 ? src_len : 1) + 1); res_len = 0; } for (ptr = src; ptr < end; ptr=next+1) { size_t len; next = memchr(ptr, '/', end-ptr); if (next == NULL) { next = end; } len = next-ptr; switch(len) { case 2: if (ptr[0] == '.' && ptr[1] == '.') { const char * slash = memrchr(res, '/', res_len); if (slash != NULL) { res_len = slash - res; } continue; } break; case 1: if (ptr[0] == '.') { continue; } break; case 0: continue; } res[res_len++] = '/'; memcpy(&res[res_len], ptr, len); res_len += len; } if (res_len == 0) { res[res_len++] = '/'; } res[res_len] = '\0'; return res; } void cleanup(void) { if(stdinName != 0) { remove(stdinName); } if(stdoutName != 0) { remove(stdoutName); } if(stderrName != 0) { remove(stderrName); } if(ctrlinName != 0) { remove(ctrlinName); } if(ctrloutName != 0) { remove(ctrloutName); } } void sigchld_handler(int sig) { (void)sig; wait(&progStatus); if(WIFEXITED(progStatus) || WIFSIGNALED(progStatus) || WTERMSIG(progStatus)) { progQuit = 1; } } void exitHandler(int sig) { (void)sig; cleanup(); exit(0); } int main(int argc, char *argv[]) { if(argc != 2) { fprintf(stderr, "Usage: %s FIFONAME_PREFIX\n", argv[0]); return 1; } const char* fifonamePrefix = argv[1]; char tempstdinName[PATH_MAX]; char tempstdoutName[PATH_MAX]; char tempstderrName[PATH_MAX]; char tempctrlinName[PATH_MAX]; char tempctrloutName[PATH_MAX]; sprintf(tempstdinName, "%sstdin", fifonamePrefix); realpath(tempstdinName, stdinName); sprintf(tempstdoutName, "%sstdout", fifonamePrefix); realpath(tempstdoutName, stdoutName); sprintf(tempstderrName, "%sstderr", fifonamePrefix); realpath(tempstderrName, stderrName); sprintf(tempctrlinName, "%sctrlin", fifonamePrefix); realpath(tempctrlinName, ctrlinName); sprintf(tempctrloutName, "%sctrlout", fifonamePrefix); realpath(tempctrloutName, ctrloutName); cleanup(); //signal(SIGCHLD, sigchld_hanlder); struct sigaction sa; sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if(sigaction(SIGCHLD, &sa, 0) == -1) { perror("sigaction"); cleanup(); return 1; } signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGINT, exitHandler); signal(SIGHUP, exitHandler); signal(SIGQUIT, exitHandler); signal(SIGTERM, exitHandler); mode_t origMask = umask(0000); if(mkfifo(stdinName, 0666) == -1) { perror("stdinfifo"); cleanup(); return 1; } int stdinFifo = -1; // = open(stdinName, O_RDONLY | O_NONBLOCK); if(mkfifo(stdoutName, 0666) == -1) { perror("stdoutfifo"); cleanup(); return 1; } int stdoutFifo = -1;// = open(stdoutName, O_WRONLY); if(mkfifo(stderrName, 0666) == -1) { perror("stdoutfifo"); cleanup(); return 1; } int stderrFifo = -1;// = open(stderrName, O_WRONLY); if(mkfifo(ctrlinName, 0666) == -1) { perror("ctrlinfifo"); cleanup(); return 1; } if(mkfifo(ctrloutName, 0666) == -1) { perror("ctrloutfifo"); cleanup(); return 1; } umask(origMask); int ctrlinFifo = open(ctrlinName, O_RDONLY); int ctrloutFifo = open(ctrloutName, O_WRONLY); if(ctrloutFifo == -1 || ctrlinFifo == -1) { perror("open"); cleanup(); return 1; } FILE* ctrloutFile = fdopen(ctrloutFifo, "w"); setlinebuf(ctrloutFile); open(ctrloutName, O_RDONLY); char* buf = (char*)malloc(4096 * sizeof(char)); if(buf == 0) { perror("malloc"); cleanup(); return 1; } int bufSize = 4096, curPos = 0; char shouldExit = 0; for(;!shouldExit;) { char* newlinePos = 0; if(progQuit && progRunning) { progRunning = 0; progQuit = 0; fprintf(ctrloutFile, "QUIT: %d\n", WEXITSTATUS(progStatus)); close(stdinFifo); close(stdoutFifo); close(stderrFifo); } int count = read(ctrlinFifo, (void*)buf, 4096); if(count == 0 || count == -1) { close(ctrlinFifo); ctrlinFifo = open(ctrlinName, O_RDONLY); } else { buf[count] = '\0'; do { if(strcmp("HELLO\n", buf) == 0) { fputs("HELLO\n", ctrloutFile); } else if(strcmp("STATUS\n", buf) == 0) { if(progRunning) { fprintf(ctrloutFile, "RUNNING: %d\n", child); } else { fputs("NOTRUNNING\n", ctrloutFile); } } else if(strncmp("START ", buf, 6) == 0) { if(progRunning && ctrloutFile != 0) { fputs("ALREADY\n", ctrloutFile); } else { char* prog = buf + 6; while((newlinePos = strchr(prog, '\n')) == 0) { bufSize += count; buf = (char*)realloc((void*)buf, bufSize); if(buf == 0) { perror("realloc"); cleanup(); return 1; } count = read(ctrlinFifo, (void*)(buf+curPos), 4096); if(count == 0) { close(ctrlinFifo); ctrlinFifo = open(ctrlinName, O_RDONLY); break; } curPos += count; } *newlinePos = '\0'; char** nargv = (char**)malloc(2 * sizeof(char*)); if(nargv == 0) { perror("malloc"); cleanup(); return 1; } nargv[0] = prog; int nargc = 1; unsigned int len = strlen(prog); for(unsigned int i = 0; i < len; ++i) { if(prog[i] == '\\' && (prog[i+1] == '\\' || prog[i+1] == ' ')) { memmove(prog + i, prog + i + 1, strlen(prog + i)); --len; } else if(prog[i] == ' ') { prog[i] = '\0'; nargv = (char**)realloc((void*)nargv, (++nargc + 1) * sizeof(char*)); if(nargv == 0) { perror("realloc"); cleanup(); return 1; } nargv[nargc - 1] = prog + i + 1; } } nargv[nargc] = 0; char absPath[PATH_MAX]; nargv[0] = normalize_path(nargv[0], absPath); if(nargv[0] == 0) { fprintf(ctrloutFile, "STARTFAIL: %s\n", strerror(errno)); } progRunning = 1; child = fork(); if(child == -1) { perror("fork"); cleanup(); return 1; } if(child == 0) { stdinFifo = open(stdinName, O_RDONLY); if(stdinFifo == -1) { perror("open"); } stdoutFifo = open(stdoutName, O_WRONLY); if(stdoutFifo == -1) { perror("open"); } stderrFifo = open(stderrName, O_WRONLY); if(stderrFifo == -1) { perror("open"); } dup2(stdinFifo, STDIN_FILENO); dup2(stdoutFifo, STDOUT_FILENO); dup2(stderrFifo, STDERR_FILENO); if(execvp(nargv[0], nargv) == -1) { perror("execvp"); exit(1); } } else { stdinFifo = open(stdinName, O_WRONLY); stdoutFifo = open(stdoutName, O_RDONLY); stderrFifo = open(stderrName, O_RDONLY); fprintf(ctrloutFile, "RUNNING: %d\n", child); } bufSize = 4096; buf = (char*)realloc((void*)buf, bufSize); if(buf == 0) { perror("realloc"); cleanup(); return 1; } } } else if(strncmp(buf, "CD ", 3) == 0) { char* dir = buf + 3; if((newlinePos = strchr(dir, '\n')) != 0) { *newlinePos = '\0'; } char tempDir[PATH_MAX]; realpath(dir, tempDir); if(chdir(tempDir) == 0) { fputs("CHANGED\n", ctrloutFile); } else { fprintf(ctrloutFile, "CD FAILED: %s\n", strerror(errno)); } } else if(strcmp(buf, "EXIT\n") == 0) { shouldExit = 1; break; } else if(strcmp(buf, "CLOSE\n") == 0) { close(stdinFifo); close(stdoutFifo); close(stderrFifo); fputs("CLOSED\n", ctrloutFile); } else if(strcmp(buf, "KILL\n") == 0) { if(!progRunning) { fputs("NOTRUNNING\n", ctrloutFile); } else { kill(child, SIGTERM); fputs("KILLED\n", ctrloutFile); } } if(newlinePos != 0) { strcpy(buf, newlinePos + 1); } else { buf[0] = '\0'; } } while(buf[0] != '\0'); } } cleanup(); return 0; }