#include #include #include #include #include #include "util.h" #include "debug.h" #include "config.h" #define MAXLINE 128 static char menu[MAXLINE]; void usage() { printf("remu [FILE]\n"); exit(0); } int launch_menu(int *pfd, char *prompt) { int pipefd[4]; pid_t pid; if (pipe(pipefd)) return 1; if (pipe(&pipefd[2])) { close(pipefd[0]); close(pipefd[1]); return 1; } pid = fork(); switch (pid) { case -1: close(pipefd[0]); close(pipefd[1]); close(pipefd[2]); close(pipefd[3]); return 1; case 0: break; default: pfd[0] = pipefd[0]; pfd[1] = pipefd[3]; close(pipefd[1]); close(pipefd[2]); return 0; } /* Child process */ close(pipefd[0]); close(pipefd[3]); if (dup2(pipefd[1], STDOUT_FILENO) == -1) exit(1); if (dup2(pipefd[2], STDIN_FILENO) == -1) exit(1); execvp(menu_cmd[0], (char **)menu_cmd); close(pipefd[1]); close(pipefd[2]); exit(0); } char * nextline(char *c) { while (*c != '\n') c++; return ++c; } char * setline(char *p) { char *end; end = nextline(p); end[-1] = 0; return end; } void resetline(char *end) { end[-1] = '\n'; } char * nextarg(char *c) { while (*c == '\0') c++; return c; } char * process_quoted(char *pnt) { size_t off = 0; char *ret = NULL; pnt[0] = 0; pnt++; while (pnt[off] != '"') { if (pnt[off] == '\0' || pnt[off] == '\n') return NULL; if (pnt[off] == '\\') { if (pnt[off+1] == '\0' || pnt[off+1] == '\n') return NULL; off++; } pnt[0] = pnt[off]; pnt++; } for (ret = &(pnt[off+1]); pnt != ret; pnt++) pnt[0] = 0; return ret; } char * process_unquoted(char *pnt) { size_t off = 0; char *ret = NULL; while (pnt[off] && pnt[off] != '\n') { if (pnt[off] == ' ') { ret = &pnt[off+1]; break; } if (pnt[off] == '"') return NULL; if (pnt[off] == '\\') { if (pnt[off+1] == '\0' || pnt[off+1] == '\n') return NULL; off++; } pnt[0] = pnt[off]; pnt++; } ret = ret ? ret : &pnt[off]; for (; pnt != ret; pnt++) pnt[0] = 0; return ret; } char * process_line(char *pnt) { while (*pnt && *pnt != '\n') { if (*pnt == '"') pnt = process_quoted(pnt); else pnt = process_unquoted(pnt); if (pnt == NULL) return NULL; } return pnt; } unsigned int preprocess(char *buf) { char *pnt = buf; unsigned int line = 0; while (*pnt) { line++; if (*pnt == '#' || *pnt == '\n') { pnt = nextline(pnt); continue; } if (pnt[1] != ' ') return line; pnt[1] = 0; pnt = process_line(pnt+2); if (pnt == NULL) return line; pnt = nextline(pnt); } return 0; } int submenu(char *line) { char *e, *arg, *ea; arg = nextarg(line+2); ea = &arg[strlen(arg) - 1]; if (*ea == '\n') return 1; arg = nextarg(ea+1); e = setline(line); strncpy(menu, arg, MAXLINE); menu[MAXLINE-1] = 0; resetline(e); return 0; } int print(char *line) { char *e, *arg, *ea; arg = nextarg(line+2); ea = &arg[strlen(arg) - 1]; if (*ea != '\n' && *nextarg(ea+1) != '\n') arg = nextarg(ea+1); e = setline(line); printf("%s\n", arg); resetline(e); return 0; } int run(char *line) { char *e, *arg, *ea; arg = nextarg(line+2); ea = &arg[strlen(arg) - 1]; if (*ea == '\n') return 1; arg = nextarg(ea+1); e = setline(line); if (execl("/bin/sh", "sh", "-c", arg, NULL)) error("Error executing process: %s\n", strerror(errno)); resetline(e); return 0; } int main(int argc, char *argv[]) { char *buf, *stop, *pnt, *end, *mpnt, *line; unsigned int i; int pfd[2]; FILE *f[2]; char option[MAXLINE]; strcpy(menu, default_menu); if (argc != 2) usage(); buf = f_read(argv[1]); if (buf == NULL) { fprintf(stderr, "Couldn't read file %s\n", argv[1]); return 1; } stop = &buf[strlen(buf)]; if (stop == buf) { fprintf(stderr, "Wrong format in %s: Empty file\n", argv[1]); return 1; } else if (stop[-1] != '\n') { fprintf(stderr, "Wrong format in %s: Missing EOL at the end of the file\n", argv[1]); return 1; } if (i = preprocess(buf)) { fprintf(stderr, "Wrong format in %s:%u\n", argv[1], i); return 1; } while (1) { for (pnt = buf; pnt != stop; pnt = nextline(pnt)) { if (*pnt != 'm') continue; pnt = nextarg(pnt+1); end = setline(pnt); if (strcmp(menu, pnt) == 0) break; resetline(end); } if (pnt == stop) { fprintf(stderr, "Couldn't find menu %s in file %s\n", menu, argv[1]); return 1; } resetline(end); /* Query option */ if (launch_menu(pfd, NULL)) { fprintf(stderr, "Couldn't open the menu\n"); return 1; } f[0] = fdopen(pfd[0], "r"); f[1] = fdopen(pfd[1], "w"); if (f[0] == NULL || f[1] == NULL) { fprintf(stderr, "Couldn't open the menu\n"); return 1; } mpnt = nextline(pnt); for (pnt = mpnt; pnt != stop; pnt = nextline(pnt)) { if (*pnt == 'm') break; if (*pnt == '\n' || *pnt == '#') continue; pnt = nextarg(pnt+1); end = setline(pnt); fprintf(f[1], "%s\n", pnt); resetline(end); } fclose(f[1]); close(pfd[1]); if (fgets(option, MAXLINE, f[0]) == NULL) { fprintf(stderr, "Couldn't open the menu\n"); return 1; } option[strlen(option)-1] = 0; for (line = mpnt; line != stop; line = nextline(line)) { if (*line == 'm') break; if (*line == '\n' || *line == '#') continue; pnt = nextarg(line+1); if (*pnt == '\n') { fprintf(stderr, "Wrong format in %s: Not enough arguments\n", argv[1]); return 1; } end = setline(pnt); if (strcmp(pnt, option) == 0) break; resetline(end); } /* No option selected */ if (*line == 'm' || line == stop) break; resetline(end); switch (line[0]) { case 's': if (submenu(line)) { fprintf(stderr, "Wrong format in %s: Not enough arguments\n", argv[1]); return 1; } break; case 'p': print(line); return 0; case 'r': if (run(line)) { fprintf(stderr, "Wrong format in %s: Not enough arguments\n", argv[1]); return 1; } return 0; default: return 0; } } }