diff pwm.c @ 19:5c6155c8e9b6

Handle signals Handled signals are generally blocked and only unblocked when doing blocking I/O, i.e. either when reading commands or printing results. A (possibly queued) signal will then interrupt I/O and can be dealt with in the main loop.
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Fri, 01 Sep 2017 22:33:41 +0200
parents 1e39a251cbe9
children efef93e54c5f
line wrap: on
line diff
--- a/pwm.c	Thu Aug 24 13:10:56 2017 +0200
+++ b/pwm.c	Fri Sep 01 22:33:41 2017 +0200
@@ -41,22 +41,11 @@
 
 #include "pwm.h"
 #include "cmd.h"
+#include "io.h"
 #include "pwfile.h"
 #include "tok.h"
 #include "util.h"
 
-#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)
 {
@@ -81,11 +70,34 @@
 	}
 }
 
-static int
-complete_nothing(WordCompletion *cpl, void *data, const char *line,
-    int word_end)
+void
+pwm_block_signals(void)
 {
-	return (0);
+	sigset_t	set;
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGINT);
+	sigaddset(&set, SIGTERM);
+	sigaddset(&set, SIGHUP);
+	sigaddset(&set, SIGQUIT);
+	if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) {
+		err(1, "sigprocmask");
+	}
+}
+
+void
+pwm_unblock_signals(void)
+{
+	sigset_t	set;
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGINT);
+	sigaddset(&set, SIGTERM);
+	sigaddset(&set, SIGHUP);
+	sigaddset(&set, SIGQUIT);
+	if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
+		err(1, "sigprocmask");
+	}
 }
 
 static int
@@ -94,9 +106,8 @@
 	int		retval = -1;
 	char		prompt[8 + 2 + 1];
 	GetLine		*gl = NULL;
-	char		buf[PWM_LINE_MAX];
-	char		*line = buf;
-	int		c;
+	char		buf[PWM_LINE_MAX + 1];
+	int		io_retval;
 	int		argc = 0;
 	char		**argv = NULL;
 	struct cmd	*cmd;
@@ -104,31 +115,41 @@
 
 	snprintf(prompt, sizeof (prompt), "%.*s> ", 8, getprogname());
 
+	pwm_block_signals();
+
 	/* initialize libtecla */
 	gl = new_GetLine(PWM_LINE_MAX, PWM_HISTORY_MAX);
 	if (gl == NULL) {
 		err(1, "new_GetLine");
 	}
+	gl_catch_blocked(gl);
 	gl_limit_history(gl, PWM_HISTORY_LINES_MAX);
 	/* disable default filename completion */
-	gl_customize_completion(gl, NULL, complete_nothing);
+	gl_customize_completion(gl, NULL, io_gl_complete_nothing);
 
 	for (;;) {
+		/* read next line */
 		cmd = NULL;
-		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));
-			}
+		buf[0] = '\0';
+		io_retval = io_get_line(gl, prompt, 1, NULL, 0,
+		    sizeof (buf), buf);
+		switch (io_retval) {
+		case IO_OK:
 			break;
+		case IO_TRUNCATED:
+			/* line was truncated in non-interactive mode */
+			fprintf(stderr, "line too long\n");
+			goto out;
+		case IO_EOF:	/* FALLTHROUGH */
+		case IO_SIGNAL:
+			goto quit;
+		default:
+			fprintf(stderr, "unknown error\n");
+			goto quit;
 		}
 
 		/* tokenize line */
-		switch (tok_tokenize(line, &argc, &argv)) {
+		switch (tok_tokenize(buf, &argc, &argv)) {
 		case TOK_ERR_SYSTEM_ERROR:
 			err(1, "tok_tokenize");
 		case TOK_ERR_UNTERMINATED_QUOTE:
@@ -171,7 +192,9 @@
 				goto out;
 			}
 			break;
-		case CMD_QUIT:
+		case CMD_SIGNAL:
+			fprintf(stderr, "received signal, quitting\n");
+		case CMD_QUIT:	/* FALLTHROUGH */
 			goto quit;
 		}
 		ctx->prev_cmd = cmd->full_cmd;
@@ -201,69 +224,22 @@
 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';
+	switch (io_get_password(is_new_password ? "New Password:" :
+	    "Password:", is_new_password ? "Confirm Password:" : NULL,
+	    sizeof (ctx->password), ctx->password)) {
+	case IO_OK:
+		return (0);
+	case IO_SIGNAL:
+		return (-2);
+	case IO_PASSWORD_EMPTY:
+		pwm_err(ctx, "password must not be empty");
+		return (-1);
+	case IO_PASSWORD_MISMATCH:
+		pwm_err(ctx, "passwords do not match");
+		return (-1);
+	default:
+		return (-1);
 	}
-	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);
 }
 
 static int