Mercurial > projects > pwm
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) |