diff pwm.c @ 18:1e39a251cbe9

Use libtecla for interactive input
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Thu, 24 Aug 2017 13:10:56 +0200
parents a07665727c19
children 5c6155c8e9b6
line wrap: on
line diff
--- a/pwm.c	Sat Aug 12 10:41:52 2017 +0200
+++ b/pwm.c	Thu Aug 24 13:10:56 2017 +0200
@@ -27,12 +27,10 @@
 #include <err.h>
 #endif /* HAVE_ERR_H */
 #include <errno.h>
+#include <fcntl.h>
 #include <langinfo.h>
 #include <locale.h>
 #include <pwd.h>
-#ifdef	HAVE_READPASSPHRASE_H
-#include <readpassphrase.h>
-#endif /* READPASSPHRASE_H */
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -47,9 +45,17 @@
 #include "tok.h"
 #include "util.h"
 
-#ifndef	PWM_LINE_MAX
-#define	PWM_LINE_MAX	16384
-#endif /* !PWM_LINE_MAX */
+#ifndef	PWM_HISTORY_ENTRIES_MAX
+#define	PWM_HISTORY_ENTRIES_MAX	1024
+#endif /* !PWM_HISTORY_MAX */
+
+#ifndef	PWM_HISTORY_LINES_MAX
+#define	PWM_HISTORY_LINES_MAX	256
+#endif /* !PWM_HISTORY_LINES_MAX */
+
+#ifndef	PWM_HISTORY_MAX
+#define	PWM_HISTORY_MAX	(PWM_HISTORY_LINES_MAX * PWM_LINE_MAX)
+#endif /* !PWM_HISTORY_MAX */
 
 static void
 usage(void)
@@ -76,49 +82,53 @@
 }
 
 static int
+complete_nothing(WordCompletion *cpl, void *data, const char *line,
+    int word_end)
+{
+	return (0);
+}
+
+static int
 run_input_loop(struct pwm_ctx *ctx, int is_interactive)
 {
 	int		retval = -1;
+	char		prompt[8 + 2 + 1];
+	GetLine		*gl = NULL;
 	char		buf[PWM_LINE_MAX];
+	char		*line = buf;
 	int		c;
 	int		argc = 0;
 	char		**argv = NULL;
 	struct cmd	*cmd;
 	int		i;
 
+	snprintf(prompt, sizeof (prompt), "%.*s> ", 8, getprogname());
+
+	/* initialize libtecla */
+	gl = new_GetLine(PWM_LINE_MAX, PWM_HISTORY_MAX);
+	if (gl == NULL) {
+		err(1, "new_GetLine");
+	}
+	gl_limit_history(gl, PWM_HISTORY_LINES_MAX);
+	/* disable default filename completion */
+	gl_customize_completion(gl, NULL, complete_nothing);
+
 	for (;;) {
 		cmd = NULL;
-		if (fgets(buf, (int)sizeof (buf), stdin) == NULL) {
-			if (ferror(stdin)) {
-				/* error */
-				warn("failed to read command");
-				goto out;
-			} else if (feof(stdin)) {
-				/* EOF */
+		line = gl_get_line(gl, prompt, NULL, -1);
+		if (line == NULL) {
+			switch (gl_return_status(gl)) {
+			case GLR_EOF:
 				break;
+			case GLR_ERROR:
+				warnx("gl_get_line: %s",
+				    gl_error_message(gl, NULL, 0));
 			}
-		}
-		if ((buf[strlen(buf) - 1] != '\n') && !feof(stdin)) {
-			/* line was truncated */
-			fprintf(stderr, "line too long\n");
-			if (is_interactive) {
-				/* skip input to next newline */
-				do {
-					errno = 0;
-					c = fgetc(stdin);
-					if ((c == EOF) && (errno != 0)) {
-						warn("failed to read command");
-						goto out;
-					}
-				} while ((c != '\n') && (c != EOF));
-			} else {
-				/* fatal error in non-interactive mode */
-				goto out;
-			}
+			break;
 		}
 
 		/* tokenize line */
-		switch(tok_tokenize(buf, &argc, &argv)) {
+		switch (tok_tokenize(line, &argc, &argv)) {
 		case TOK_ERR_SYSTEM_ERROR:
 			err(1, "tok_tokenize");
 		case TOK_ERR_UNTERMINATED_QUOTE:
@@ -183,6 +193,75 @@
 		free(argv[i]);
 	}
 	free(argv);
+	del_GetLine(gl);
+
+	return (retval);
+}
+
+int
+pwm_read_password(struct pwm_ctx *ctx, int is_new_password)
+{
+	int	retval = -1;
+	GetLine	*gl = NULL;
+	char	*line;
+	size_t	len;
+	char	password_buf[sizeof (ctx->password)] = { '\0' };
+
+	/* initialize libtecla */
+	gl = new_GetLine(sizeof (password_buf) - 1, 0);
+	if (gl == NULL) {
+		err(1, "new_GetLine");
+	}
+	/* disable default filename completion */
+	gl_customize_completion(gl, NULL, complete_nothing);
+	gl_echo_mode(gl, 0);
+
+	line = gl_get_line(gl, is_new_password ? "New password: " :
+	    "Password: ", NULL, -1);
+	putchar('\n');
+	if (line == NULL) {
+		if (gl_return_status(gl) == GLR_ERROR) {
+			errx(1, "gl_get_line: %s", gl_error_message(gl, NULL,
+			    0));
+		}
+		goto out;
+	}
+	len = strlen(line);
+	if ((len > 0) && (line[len - 1] == '\n')) {
+		line[--len] = '\0';
+	}
+	if (len == 0) {
+		fprintf(stderr, "password must not be empty\n");
+		goto out;
+	}
+	strcpy(password_buf, line);
+
+	/* confirm the entered password entered */
+	if (is_new_password) {
+		line = gl_get_line(gl, "Confirm password: ", NULL, -1);
+		putchar('\n');
+		if (line == NULL) {
+			if (gl_return_status(gl) == GLR_ERROR) {
+				errx(1, "gl_get_line: %s", gl_error_message(gl,
+				    NULL, 0));
+			}
+			goto out;
+		}
+		len = strlen(line);
+		if ((len > 0) && (line[len - 1] == '\n')) {
+			line[--len] = '\0';
+		}
+		if (strcmp(password_buf, line) != 0) {
+			fprintf(stderr, "passwords do not match\n");
+			goto out;
+		}
+	}
+
+	strcpy(ctx->password, password_buf);
+	retval = 0;
+
+out:
+	del_GetLine(gl);
 
 	return (retval);
 }
@@ -253,7 +332,6 @@
 	struct passwd	*passwd;
 	char		*pwm_dirname = NULL;
 	FILE		*fp = NULL;
-	char		password_buf[PWS3_MAX_PASSWORD_LEN + 1];
 
 	setprogname(argv[0]);
 
@@ -343,27 +421,8 @@
 		    ctx.password, sizeof (ctx.password)) != 0) {
 			goto out;
 		}
-	} else {
-		if (readpassphrase("Enter password: ", ctx.password,
-		    sizeof (ctx.password), RPP_ECHO_OFF | RPP_REQUIRE_TTY) ==
-		    NULL) {
-			err(1, "readpassphrase");
-		}
-		if (ctx.password[0] == '\0') {
-			fprintf(stderr, "password must not be empty\n");
-			goto out;
-		}
-		if (fp == NULL) {
-			if (readpassphrase("Confirm password: ", password_buf,
-			    sizeof (password_buf),
-			    RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL) {
-				err(1, "readpassphrase");
-			}
-			if (strcmp(ctx.password, password_buf) != 0) {
-				fprintf(stderr, "passwords do not match\n");
-				goto out;
-			}
-		}
+	} else if (pwm_read_password(&ctx, (fp == NULL)) != 0) {
+		goto out;
 	}
 	if (fp != NULL) {
 		if (pwfile_read_file(&ctx, fp) != 0) {