comparison 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
comparison
equal deleted inserted replaced
18:1e39a251cbe9 19:5c6155c8e9b6
39 #include <time.h> 39 #include <time.h>
40 #include <unistd.h> 40 #include <unistd.h>
41 41
42 #include "pwm.h" 42 #include "pwm.h"
43 #include "cmd.h" 43 #include "cmd.h"
44 #include "io.h"
44 #include "pwfile.h" 45 #include "pwfile.h"
45 #include "tok.h" 46 #include "tok.h"
46 #include "util.h" 47 #include "util.h"
47
48 #ifndef PWM_HISTORY_ENTRIES_MAX
49 #define PWM_HISTORY_ENTRIES_MAX 1024
50 #endif /* !PWM_HISTORY_MAX */
51
52 #ifndef PWM_HISTORY_LINES_MAX
53 #define PWM_HISTORY_LINES_MAX 256
54 #endif /* !PWM_HISTORY_LINES_MAX */
55
56 #ifndef PWM_HISTORY_MAX
57 #define PWM_HISTORY_MAX (PWM_HISTORY_LINES_MAX * PWM_LINE_MAX)
58 #endif /* !PWM_HISTORY_MAX */
59 48
60 static void 49 static void
61 usage(void) 50 usage(void)
62 { 51 {
63 fprintf(stderr, "usage: %s [-P file] [filename]\n", getprogname()); 52 fprintf(stderr, "usage: %s [-P file] [filename]\n", getprogname());
79 } else { 68 } else {
80 ctx->errmsg = NULL; 69 ctx->errmsg = NULL;
81 } 70 }
82 } 71 }
83 72
84 static int 73 void
85 complete_nothing(WordCompletion *cpl, void *data, const char *line, 74 pwm_block_signals(void)
86 int word_end) 75 {
87 { 76 sigset_t set;
88 return (0); 77
78 sigemptyset(&set);
79 sigaddset(&set, SIGINT);
80 sigaddset(&set, SIGTERM);
81 sigaddset(&set, SIGHUP);
82 sigaddset(&set, SIGQUIT);
83 if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) {
84 err(1, "sigprocmask");
85 }
86 }
87
88 void
89 pwm_unblock_signals(void)
90 {
91 sigset_t set;
92
93 sigemptyset(&set);
94 sigaddset(&set, SIGINT);
95 sigaddset(&set, SIGTERM);
96 sigaddset(&set, SIGHUP);
97 sigaddset(&set, SIGQUIT);
98 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
99 err(1, "sigprocmask");
100 }
89 } 101 }
90 102
91 static int 103 static int
92 run_input_loop(struct pwm_ctx *ctx, int is_interactive) 104 run_input_loop(struct pwm_ctx *ctx, int is_interactive)
93 { 105 {
94 int retval = -1; 106 int retval = -1;
95 char prompt[8 + 2 + 1]; 107 char prompt[8 + 2 + 1];
96 GetLine *gl = NULL; 108 GetLine *gl = NULL;
97 char buf[PWM_LINE_MAX]; 109 char buf[PWM_LINE_MAX + 1];
98 char *line = buf; 110 int io_retval;
99 int c;
100 int argc = 0; 111 int argc = 0;
101 char **argv = NULL; 112 char **argv = NULL;
102 struct cmd *cmd; 113 struct cmd *cmd;
103 int i; 114 int i;
104 115
105 snprintf(prompt, sizeof (prompt), "%.*s> ", 8, getprogname()); 116 snprintf(prompt, sizeof (prompt), "%.*s> ", 8, getprogname());
106 117
118 pwm_block_signals();
119
107 /* initialize libtecla */ 120 /* initialize libtecla */
108 gl = new_GetLine(PWM_LINE_MAX, PWM_HISTORY_MAX); 121 gl = new_GetLine(PWM_LINE_MAX, PWM_HISTORY_MAX);
109 if (gl == NULL) { 122 if (gl == NULL) {
110 err(1, "new_GetLine"); 123 err(1, "new_GetLine");
111 } 124 }
125 gl_catch_blocked(gl);
112 gl_limit_history(gl, PWM_HISTORY_LINES_MAX); 126 gl_limit_history(gl, PWM_HISTORY_LINES_MAX);
113 /* disable default filename completion */ 127 /* disable default filename completion */
114 gl_customize_completion(gl, NULL, complete_nothing); 128 gl_customize_completion(gl, NULL, io_gl_complete_nothing);
115 129
116 for (;;) { 130 for (;;) {
131 /* read next line */
117 cmd = NULL; 132 cmd = NULL;
118 line = gl_get_line(gl, prompt, NULL, -1); 133 buf[0] = '\0';
119 if (line == NULL) { 134 io_retval = io_get_line(gl, prompt, 1, NULL, 0,
120 switch (gl_return_status(gl)) { 135 sizeof (buf), buf);
121 case GLR_EOF: 136 switch (io_retval) {
122 break; 137 case IO_OK:
123 case GLR_ERROR:
124 warnx("gl_get_line: %s",
125 gl_error_message(gl, NULL, 0));
126 }
127 break; 138 break;
139 case IO_TRUNCATED:
140 /* line was truncated in non-interactive mode */
141 fprintf(stderr, "line too long\n");
142 goto out;
143 case IO_EOF: /* FALLTHROUGH */
144 case IO_SIGNAL:
145 goto quit;
146 default:
147 fprintf(stderr, "unknown error\n");
148 goto quit;
128 } 149 }
129 150
130 /* tokenize line */ 151 /* tokenize line */
131 switch (tok_tokenize(line, &argc, &argv)) { 152 switch (tok_tokenize(buf, &argc, &argv)) {
132 case TOK_ERR_SYSTEM_ERROR: 153 case TOK_ERR_SYSTEM_ERROR:
133 err(1, "tok_tokenize"); 154 err(1, "tok_tokenize");
134 case TOK_ERR_UNTERMINATED_QUOTE: 155 case TOK_ERR_UNTERMINATED_QUOTE:
135 fprintf(stderr, "unterminated quote\n"); 156 fprintf(stderr, "unterminated quote\n");
136 if (!is_interactive) { 157 if (!is_interactive) {
169 case CMD_ERR: /* FALLTHROUGH */ 190 case CMD_ERR: /* FALLTHROUGH */
170 if (!is_interactive) { 191 if (!is_interactive) {
171 goto out; 192 goto out;
172 } 193 }
173 break; 194 break;
174 case CMD_QUIT: 195 case CMD_SIGNAL:
196 fprintf(stderr, "received signal, quitting\n");
197 case CMD_QUIT: /* FALLTHROUGH */
175 goto quit; 198 goto quit;
176 } 199 }
177 ctx->prev_cmd = cmd->full_cmd; 200 ctx->prev_cmd = cmd->full_cmd;
178 201
179 next: 202 next:
199 } 222 }
200 223
201 int 224 int
202 pwm_read_password(struct pwm_ctx *ctx, int is_new_password) 225 pwm_read_password(struct pwm_ctx *ctx, int is_new_password)
203 { 226 {
204 int retval = -1; 227 switch (io_get_password(is_new_password ? "New Password:" :
205 GetLine *gl = NULL; 228 "Password:", is_new_password ? "Confirm Password:" : NULL,
206 char *line; 229 sizeof (ctx->password), ctx->password)) {
207 size_t len; 230 case IO_OK:
208 char password_buf[sizeof (ctx->password)] = { '\0' }; 231 return (0);
209 232 case IO_SIGNAL:
210 /* initialize libtecla */ 233 return (-2);
211 gl = new_GetLine(sizeof (password_buf) - 1, 0); 234 case IO_PASSWORD_EMPTY:
212 if (gl == NULL) { 235 pwm_err(ctx, "password must not be empty");
213 err(1, "new_GetLine"); 236 return (-1);
214 } 237 case IO_PASSWORD_MISMATCH:
215 /* disable default filename completion */ 238 pwm_err(ctx, "passwords do not match");
216 gl_customize_completion(gl, NULL, complete_nothing); 239 return (-1);
217 gl_echo_mode(gl, 0); 240 default:
218 241 return (-1);
219 line = gl_get_line(gl, is_new_password ? "New password: " : 242 }
220 "Password: ", NULL, -1);
221 putchar('\n');
222 if (line == NULL) {
223 if (gl_return_status(gl) == GLR_ERROR) {
224 errx(1, "gl_get_line: %s", gl_error_message(gl, NULL,
225 0));
226 }
227 goto out;
228 }
229 len = strlen(line);
230 if ((len > 0) && (line[len - 1] == '\n')) {
231 line[--len] = '\0';
232 }
233 if (len == 0) {
234 fprintf(stderr, "password must not be empty\n");
235 goto out;
236 }
237 strcpy(password_buf, line);
238
239 /* confirm the entered password entered */
240 if (is_new_password) {
241 line = gl_get_line(gl, "Confirm password: ", NULL, -1);
242 putchar('\n');
243 if (line == NULL) {
244 if (gl_return_status(gl) == GLR_ERROR) {
245 errx(1, "gl_get_line: %s", gl_error_message(gl,
246 NULL, 0));
247 }
248 goto out;
249 }
250 len = strlen(line);
251 if ((len > 0) && (line[len - 1] == '\n')) {
252 line[--len] = '\0';
253 }
254 if (strcmp(password_buf, line) != 0) {
255 fprintf(stderr, "passwords do not match\n");
256 goto out;
257 }
258 }
259
260 strcpy(ctx->password, password_buf);
261 retval = 0;
262
263 out:
264 del_GetLine(gl);
265
266 return (retval);
267 } 243 }
268 244
269 static int 245 static int
270 read_password_from_file(const char *filename, char *password, 246 read_password_from_file(const char *filename, char *password,
271 size_t password_size) 247 size_t password_size)