diff options
author | sinanmohd <sinan@firemail.cc> | 2023-05-22 15:25:25 +0530 |
---|---|---|
committer | sinanmohd <sinan@firemail.cc> | 2023-06-26 12:59:10 +0530 |
commit | d7ce046606ce05dd8a37e83fc48667bbe4c20093 (patch) | |
tree | 7e8d44431998e8c9d80f39165b6525866ddb5856 |
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | config.h | 9 | ||||
-rw-r--r-- | main.c | 89 | ||||
-rw-r--r-- | menu.c | 117 | ||||
-rw-r--r-- | menu.h | 3 | ||||
-rw-r--r-- | ui.c | 129 | ||||
-rw-r--r-- | ui.h | 10 | ||||
-rw-r--r-- | util.c | 22 | ||||
-rw-r--r-- | util.h | 26 |
11 files changed, 425 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d613b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +tuil diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a16e712 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +OBJECTS = main.o util.o ui.o menu.o +CC = gcc +CFLAGS = -g -Wvla -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wpedantic -fsanitize=address + +tuil: $(OBJECTS) + $(CC) $(CFLAGS) -o tuil $(OBJECTS) + +main.o: config.h menu.h util.h +menu.o: ui.h util.h +ui.o: util.o config.h + +.PHONY: clean +clean: + rm -f tuil $(OBJECTS) @@ -0,0 +1,4 @@ +remove controling term with ioctl +back fall to stdin +use buf to communicate with child +gets status diff --git a/config.h b/config.h new file mode 100644 index 0000000..b97716d --- /dev/null +++ b/config.h @@ -0,0 +1,9 @@ +#define MAX_PASS 128 +#define MAX_STATUS 128 + +static const char statverf = '.'; +static const char statfail = ','; +static const char statstr[] = "_-"; +static const char headpromt[] = "Authentication Required"; +static const char headverf[] = "Verifying"; +static const char headerr[] = "Authentication Failed"; @@ -0,0 +1,89 @@ +#include <unistd.h> + +#include "menu.h" +#include "ui.h" +#include "config.h" +#include "util.h" + +int main(int argc, char *argv[]) +{ + int errflg, fd, rc; + char c; + + State state = { + .headerr = headerr, + .headverf = headverf, + .statstr = statstr, + .statverf = statverf, + .statfail = statfail, + .cmds[PASS].name = headpromt + }; + + errflg = 0; + while ((c = getopt(argc, argv, "ip:e:v:s:r:l:c:u:d:w:")) != -1) { + switch(c) { + case 'i': + state.flag |= IGNORE_ISIG; + break; + case 'p': + state.cmds[PASS].name = optarg; + break; + case 'e': + state.headerr = optarg; + break; + case 'v': + state.headverf = optarg; + break; + case 's': + state.statstr = optarg; + break; + case 'r': + state.statverf = *optarg; + break; + case 'l': + state.statfail = *optarg; + break; + case 'c': + state.cmds[PASS].cmd = optarg; + break; + case 'u': + state.cmds[UP].name = optarg; + + while (*optarg && *optarg != '=') + optarg++; + if (*optarg == '=') + state.cmds[UP].cmd = optarg + 1; + else + errflg++; + + *optarg = '\0'; + break; + case 'd': + state.cmds[DOWN].name = optarg; + + while (*optarg && *optarg != '=') + optarg++; + if (*optarg == '=') + state.cmds[DOWN].cmd = optarg + 1; + else + errflg++; + + *optarg = '\0'; + break; + case 'w': + state.floc = optarg; + break; + case '?': + errflg++; + } + } + + if (errflg || !state.cmds[PASS].cmd) + die("usage: tuil [-ipevsrl]"); + + fd = uiinit(&state); + rc = menuinit(&state, fd) - 1; + uicleanup(); + + return rc; +} @@ -0,0 +1,117 @@ +#include <ctype.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "menu.h" +#include "ui.h" +#include "util.h" + +#define MAX_PASS 128 +#define NO_OPT 0 + +static char pass[MAX_PASS]; + +static int getip(const State *state, int fd); +static pid_t run(const char *cmd); +static void updatestat(const State *state, unsigned typ, int pos); + +int menuinit(const State *state, int fd) +{ + int rc, wfd = -1, status = 0; + pid_t pid; + + if (state->floc) + if ((wfd = open(state->floc, O_WRONLY | O_CREAT)) == -1) + die ("can't open %s", state->floc); + + do { + if (WEXITSTATUS(status)) + pui(state->headerr, state->statfail); + else + pui(state->cmds[PASS].name, state->statstr[0]); + + rc = getip(state, fd); + + if (wfd >= 0 && rc == PASS) + write(wfd, pass, strlen(pass)); + + pid = run(state->cmds[rc].cmd); + if (rc == PASS) { + pui(state->headverf, state->statverf); + waitpid(pid, &status, NO_OPT); + } + } while (WEXITSTATUS(status) || rc != PASS); + + if (wfd >= 0) + close(wfd); + + return rc; +} + +static int getip(const State *state, int fd) +{ + unsigned i; + int rc, floor, ceil; + + rc = floor = ceil = PASS; + if (state->cmds[DOWN].name) + floor = DOWN; + if (state->cmds[UP].name) + ceil = UP; + + for (i = 0; i + 1 < MAX_PASS; ) { + read(fd, pass + i, 1); + + if (pass[i] == DEL) { + if (i > 0) + --i; + } else if (pass[i] == NL) { + break; + } else if (i >= 2 && pass[i-2] == ESC && pass[i-1] == '[' ) { + if (pass[i] == 'A' && rc < ceil) + ++rc; + else if (pass[i] == 'B' && rc > floor) + --rc; + i -= 2; + } else { + ++i; + } + + pheader(state->cmds[rc].name); + updatestat(state, rc, i); + } + + pass[i] = '\0'; + return rc; +} + +static void updatestat(const State *state, unsigned typ, int pos) +{ + if (typ == PASS) { + if (pos) + genrandstat(state->cmds[PASS].name, state->statstr); + else + pstaticstat(state->cmds[PASS].name, state->statstr[0]); + } else { + pstaticstat(state->cmds[typ].name, state->statverf); + } +} + +static pid_t run(const char *cmd) +{ + pid_t pid; + + if ((pid = fork()) == 0) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + execlp("sh", "sh", "-c", cmd, NULL); + die("run: fork(): %s", cmd); + } + + return pid; +} @@ -0,0 +1,3 @@ +#include "util.h" + +int menuinit(const State *state, int fd); @@ -0,0 +1,129 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <fcntl.h> + +#include "util.h" +#include "ui.h" + +#define MAX_STATUS 128 + +static char stbuf[MAX_STATUS]; + +static unsigned short rows; +static unsigned short cols; +static struct termios prevstate; +static int tty_fd; + +int uiinit(const State *state) +{ + struct winsize w; + struct termios t; + + if ((tty_fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) + die("getpass: can't open /dev/tty for input"); + + tcgetattr(tty_fd, &t); + prevstate = t; + if (state->flag & IGNORE_ISIG) + t.c_lflag &= ~(ISIG); + t.c_lflag &= ~(ECHO|INLCR|IGNCR|ICANON); + t.c_iflag |= ICRNL; + tcsetattr(tty_fd, TCSAFLUSH, &t); + tcdrain(tty_fd); + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &w) == -1) + die("ioctl() failed"); + + rows = w.ws_row; + cols = w.ws_col; + + printf("%c7", ESC); /* save cursor */ + printf("%c[?47h", ESC); /* use alt buffer */ + printf("%c[?25l", ESC); /* hide cursor */ + printf("%c[2J", ESC); /* clear vt */ + + return tty_fd; +} + +void pheader(const char *s) +{ + unsigned short col, row; + + row = rows / 2; + col = (cols - strlen(s)) / 2; + + printf("%c[%d;%dH", ESC, row, col); /* pos curosr */ + printf("%c[2K", ESC); /* clear line */ + puts(s); +} + +void pstatus(const char *s) +{ + unsigned short col, row; + + row = rows / 2 + 1; + col = (cols - strlen(s)) / 2; + + printf("%c[%d;%dH", ESC, row, col); /* pos cursor */ + printf("%c[2K", ESC); /* clear line */ + puts(s); +} + +void pstaticstat(const char *head, const char c) +{ + size_t stlen; + + if ((stlen = strlen(head)) > MAX_STATUS - 1) + stlen = MAX_STATUS - 1; + stbuf[stlen] = '\0'; + + memset(stbuf, c, stlen); + pstatus(stbuf); +} + +void genrandstat(const char *head, const char *statstr) +{ + int entropy; + size_t srlen, stlen, i; + + if ((stlen = strlen(head)) > MAX_STATUS - 1) + stlen = MAX_STATUS - 1; + srlen = strlen(statstr); + + for (entropy = i = 0; i < stlen; ++i, entropy /= srlen) { + if (!entropy) + entropy = rand(); + + stbuf[i] = statstr[entropy % srlen]; + } + + stbuf[stlen] = '\0'; + pstatus(stbuf); +} + +void uicleanup(void) +{ + printf("%c[2J", ESC); /* clear vt */ + printf("%c[?25h", ESC); /* show cursor */ + printf("%c[?47l", ESC); /* use normal buffer */ + printf("%c8", ESC); /* restore cursor */ + + tcsetattr(tty_fd, TCSAFLUSH, &prevstate); + close(tty_fd); +} + +void pui(const char *head, const char stat) +{ + size_t stlen; + + if ((stlen = strlen(head)) > MAX_STATUS - 1) + stlen = MAX_STATUS - 1; + stbuf[stlen] = '\0'; + + pheader(head); + pstatus(memset(stbuf, stat, stlen)); +} @@ -0,0 +1,10 @@ +#include <stddef.h> +#include "util.h" + +int uiinit(const State *state); +void pheader(const char *s); +void pstatus(const char *s); +void genrandstat(const char *head, const char *statstr); +void pui(const char *head, const char stat); +void pstaticstat(const char *head, const char c); +void uicleanup(void); @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include "util.h" + +void die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, ap); + if (errno) + fprintf(stderr, " (%d): %s\n", errno, strerror(errno)); + else + fputc('\n', stderr);; + va_end(ap); + + exit(errno); +} @@ -0,0 +1,26 @@ +#ifndef UTIL_H + +enum ascii { NL = 10, ESC = 27, DEL = 127 }; +enum flags { IGNORE_ISIG = 1 << 0 }; +enum iptyp { DOWN = 0, PASS = 1, UP = 2 }; + +typedef struct { + const char *name; + const char *cmd; +} Menu; + +typedef struct { + int flag; + char statverf; + char statfail; + const char *headverf; + const char *headerr; + const char *statstr; + const char *floc; + Menu cmds[3]; +} State; + +void die(const char *fmt, ...); + +#define UTIL_H +#endif |