/** * @file websh.c * @date 2018-04-16 * * @brief Formats program output for the web. */ #include #include #include #include #include #include #include #include #define MAX_LEN 256 static const char *pname; static int eFlag = 0; static int hFlag = 0; static int sFlag = 0; static const char *word; static const char *tag; volatile sig_atomic_t quit = 0; static void handle_signal(int signal) { quit = 1; } void usage(void) { fprintf(stderr, "Usage: websh [-e] [-h] [-s WORD:TAG]\n"); exit(EXIT_FAILURE); } void parsesArg(char *sArg) { char *token; int i = 0; while ((token = strsep(&sArg, ":"))) { if (strcmp(token, "") == 0) usage(); if (i == 2) usage(); if (i == 0) { word = token; } else { tag = token; } i++; } } void parse(int argc, char *argv[]) { int optInd = 0; char *sArg; while ((optInd = getopt(argc, argv, "ehs:")) != -1) { switch (optInd) { case 'e': if (eFlag != 0) { usage(); } else { eFlag = 1; } break; case 'h': if (hFlag != 0) { usage(); } else { hFlag = 1; } break; case 's': if (sFlag != 0) { usage(); } else { sFlag = 1; sArg = optarg; parsesArg(sArg); } break; case '?': usage(); default: assert(0); } } pname = argv[0]; } void child2(int fd[], char readbuffer[]) { /* CHILD TWO */ close(fd[1]); int nbytes = read(fd[0], readbuffer, MAX_LEN); if (nbytes == -1) { perror(pname); exit(EXIT_FAILURE); } printf("%s", readbuffer); return; } void child1(int fd[], char *line) { /* CHILD ONE */ close(fd[0]); dup2(fd[1], STDOUT_FILENO); execl("/bin/bash", "/bin/bash", "-c", line, (char *) NULL); fprintf(stderr, "[%s] exec failed\n", pname); free(line); exit(EXIT_FAILURE); return; } int main(int argc, char *argv[]) { parse(argc, argv); struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handle_signal; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); while (quit == 0) { char *line = NULL; size_t len = 0; ssize_t nread; char readbuffer[MAX_LEN]; int status; int w; if (eFlag) printf("\n"); int fd[2]; pid_t childpid1; pid_t childpid2; pipe(fd); while ((nread = getline(&line, &len, stdin)) > 0) { childpid1 = fork(); if (childpid1 > 0) { /* PARENT ONE */ childpid2 = fork(); if (childpid2 > 0) { /* PARENT TWO */ } else if (childpid2 == 0) { /* CHILD TWO */ child2(fd, readbuffer); } else { perror(pname); free(line); exit(EXIT_FAILURE); } do { w = waitpid(childpid2, &status, WUNTRACED | WCONTINUED); if (w == -1) { perror(pname); exit(EXIT_FAILURE); } if (WIFSIGNALED(status)) { printf("Killed by signal %d\n", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { printf("Stopped by signal %d\n", WSTOPSIG(status)); } else if (WIFCONTINUED(status)) { printf("Continued\n"); } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); } else if (childpid1 == 0) { /* CHILD ONE */ child1(fd, line); } else { perror(pname); free(line); exit(EXIT_FAILURE); } } free(line); break; } return 0; }