/** * @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 #define MAX_LINES 1024 /** * @details Global variable for the program name. */ static const char *pname; /** * @details Global variable for the e-Flag. */ static int eFlag = 0; /** * @details Global variable for the h-Flag. */ static int hFlag = 0; /** * @details Global variable for the s-Flag. */ static int sFlag = 0; /** * @details Global variable for the supplied word. */ static const char *word; /** * @details Global variable for the supplied tag. */ static const char *tag; /** * @details Global array which saves the supplied linux commands. */ static char *lines[MAX_LINES] = {NULL}; /** * @details Variable which gets set on signal received. */ 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 *line) { /* CHILD TWO */ char readbuffer[MAX_LEN]; close(fd[1]); int nbytes = read(fd[0], readbuffer, MAX_LEN); if (nbytes == -1) { perror(pname); exit(EXIT_FAILURE); } readbuffer[nbytes-1] = '\0'; if (eFlag && (strcmp(line, lines[0]) == 0)) { printf("\n"); } if (hFlag) { char *pch = strstr(line, "\n"); if (pch != NULL) strncpy(pch, "\0", 1); printf("

%s

\n", line); } if (sFlag) { if (strstr(readbuffer, word) != NULL) { printf("<%s>%s
\n", tag, readbuffer, tag); } else { printf("%s
\n", readbuffer); } } else { printf("%s
\n", readbuffer); } int i = 0; while (lines[i] != NULL) { i++; } if (eFlag && (strcmp(line, lines[i-1]) == 0)) { printf("\n"); } 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; int status; int w; int fd[2]; pid_t childpid1; pid_t childpid2; pipe(fd); int count = 0; while ((nread = getline(&line, &len, stdin)) > 0) { lines[count] = (char *) malloc (len); strcpy(lines[count], line); count++; if (count == 1024) break; } for (int i = 0; i < count; i++) { switch (childpid1 = fork()) { case -1: perror(pname); free(line); exit(EXIT_FAILURE); case 0: child1(fd, lines[i]); exit(EXIT_SUCCESS); break; default: switch (childpid2 = fork()) { case -1: perror(pname); free(line); exit(EXIT_FAILURE); case 0: child2(fd, lines[i]); exit(EXIT_SUCCESS); break; default: do { w = waitpid(-1, &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)); break; } } } free(line); break; } return 0; }