aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands.c
diff options
context:
space:
mode:
authorLibravatar Matt Coffin <mcoffin13@gmail.com>2019-06-11 12:10:17 -0600
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2019-06-11 14:40:36 -0400
commit2b5bf78fafdf027624ca88e1f703bc9e577f4690 (patch)
treeee24a2a3740563aecfab9fdc922eafebf1527c97 /sway/commands.c
parentAdd docs for new IPC keyboard properties (diff)
downloadsway-2b5bf78fafdf027624ca88e1f703bc9e577f4690.tar.gz
sway-2b5bf78fafdf027624ca88e1f703bc9e577f4690.tar.zst
sway-2b5bf78fafdf027624ca88e1f703bc9e577f4690.zip
Fix segfaults caused by faulty command parsing
This patch fixes faulty command parsing introduced by f0f5de9a9e87ca1f0d74e7cbf82ffceba51ffbe6. When that commit allowed criteria reset on ';' delimeters in commands lists, it failed to account for its inner ','-parsing loop eating threw the entire rest of the string. This patch refactors argsep to use a list of multiple separators, and (optionally) return the separator that it matched against in this iteration via a pointer. This allows it to hint at the command parser which separator was used at the end of the last command, allowing it to trigger a potential secondary read of the criteria. Fixes #4239
Diffstat (limited to 'sway/commands.c')
-rw-r--r--sway/commands.c113
1 files changed, 55 insertions, 58 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 377f2d01..a670f813 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -211,8 +211,8 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
211 list_t *res_list = create_list(); 211 list_t *res_list = create_list();
212 char *exec = strdup(_exec); 212 char *exec = strdup(_exec);
213 char *head = exec; 213 char *head = exec;
214 char *cmdlist;
215 char *cmd; 214 char *cmd;
215 char matched_delim = ';';
216 list_t *views = NULL; 216 list_t *views = NULL;
217 217
218 if (seat == NULL) { 218 if (seat == NULL) {
@@ -227,16 +227,13 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
227 227
228 head = exec; 228 head = exec;
229 do { 229 do {
230 // Split command list 230 for (; isspace(*head); ++head) {}
231 cmdlist = argsep(&head, ";"); 231 // Extract criteria (valid for this command list only).
232 do { 232 if (matched_delim == ';') {
233 // Skip leading whitespace
234 for (; isspace(*cmdlist); ++cmdlist) {}
235 // Extract criteria (valid for this command chain only).
236 config->handler_context.using_criteria = false; 233 config->handler_context.using_criteria = false;
237 if (*cmdlist == '[') { 234 if (*head == '[') {
238 char *error = NULL; 235 char *error = NULL;
239 struct criteria *criteria = criteria_parse(cmdlist, &error); 236 struct criteria *criteria = criteria_parse(head, &error);
240 if (!criteria) { 237 if (!criteria) {
241 list_add(res_list, 238 list_add(res_list,
242 cmd_results_new(CMD_INVALID, "%s", error)); 239 cmd_results_new(CMD_INVALID, "%s", error));
@@ -245,71 +242,71 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
245 } 242 }
246 list_free(views); 243 list_free(views);
247 views = criteria_get_views(criteria); 244 views = criteria_get_views(criteria);
248 cmdlist += strlen(criteria->raw); 245 head += strlen(criteria->raw);
249 criteria_destroy(criteria); 246 criteria_destroy(criteria);
250 config->handler_context.using_criteria = true; 247 config->handler_context.using_criteria = true;
251 // Skip leading whitespace 248 // Skip leading whitespace
252 for (; isspace(*cmdlist); ++cmdlist) {} 249 for (; isspace(*head); ++head) {}
253 }
254 // Split command chain into commands
255 cmd = argsep(&cmdlist, ",");
256 for (; isspace(*cmd); ++cmd) {}
257 if (strcmp(cmd, "") == 0) {
258 sway_log(SWAY_INFO, "Ignoring empty command.");
259 continue;
260 } 250 }
261 sway_log(SWAY_INFO, "Handling command '%s'", cmd); 251 }
262 //TODO better handling of argv 252 // Split command list
263 int argc; 253 cmd = argsep(&head, ";,", &matched_delim);
264 char **argv = split_args(cmd, &argc); 254 for (; isspace(*cmd); ++cmd) {}
265 if (strcmp(argv[0], "exec") != 0 && 255
266 strcmp(argv[0], "exec_always") != 0 && 256 if (strcmp(cmd, "") == 0) {
267 strcmp(argv[0], "mode") != 0) { 257 sway_log(SWAY_INFO, "Ignoring empty command.");
268 int i; 258 continue;
269 for (i = 1; i < argc; ++i) { 259 }
270 if (*argv[i] == '\"' || *argv[i] == '\'') { 260 sway_log(SWAY_INFO, "Handling command '%s'", cmd);
271 strip_quotes(argv[i]); 261 //TODO better handling of argv
272 } 262 int argc;
263 char **argv = split_args(cmd, &argc);
264 if (strcmp(argv[0], "exec") != 0 &&
265 strcmp(argv[0], "exec_always") != 0 &&
266 strcmp(argv[0], "mode") != 0) {
267 for (int i = 1; i < argc; ++i) {
268 if (*argv[i] == '\"' || *argv[i] == '\'') {
269 strip_quotes(argv[i]);
273 } 270 }
274 } 271 }
275 struct cmd_handler *handler = find_handler(argv[0], NULL, 0); 272 }
276 if (!handler) { 273 struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
277 list_add(res_list, cmd_results_new(CMD_INVALID, 274 if (!handler) {
278 "Unknown/invalid command '%s'", argv[0])); 275 list_add(res_list, cmd_results_new(CMD_INVALID,
276 "Unknown/invalid command '%s'", argv[0]));
277 free_argv(argc, argv);
278 goto cleanup;
279 }
280
281 // Var replacement, for all but first argument of set
282 for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
283 argv[i] = do_var_replacement(argv[i]);
284 }
285
286 if (!config->handler_context.using_criteria) {
287 // The container or workspace which this command will run on.
288 struct sway_node *node = con ? &con->node :
289 seat_get_focus_inactive(seat, &root->node);
290 set_config_node(node);
291 struct cmd_results *res = handler->handle(argc-1, argv+1);
292 list_add(res_list, res);
293 if (res->status == CMD_INVALID) {
279 free_argv(argc, argv); 294 free_argv(argc, argv);
280 goto cleanup; 295 goto cleanup;
281 } 296 }
282 297 } else {
283 // Var replacement, for all but first argument of set 298 for (int i = 0; i < views->length; ++i) {
284 for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { 299 struct sway_view *view = views->items[i];
285 argv[i] = do_var_replacement(argv[i]); 300 set_config_node(&view->container->node);
286 }
287
288 if (!config->handler_context.using_criteria) {
289 // The container or workspace which this command will run on.
290 struct sway_node *node = con ? &con->node :
291 seat_get_focus_inactive(seat, &root->node);
292 set_config_node(node);
293 struct cmd_results *res = handler->handle(argc-1, argv+1); 301 struct cmd_results *res = handler->handle(argc-1, argv+1);
294 list_add(res_list, res); 302 list_add(res_list, res);
295 if (res->status == CMD_INVALID) { 303 if (res->status == CMD_INVALID) {
296 free_argv(argc, argv); 304 free_argv(argc, argv);
297 goto cleanup; 305 goto cleanup;
298 } 306 }
299 } else {
300 for (int i = 0; i < views->length; ++i) {
301 struct sway_view *view = views->items[i];
302 set_config_node(&view->container->node);
303 struct cmd_results *res = handler->handle(argc-1, argv+1);
304 list_add(res_list, res);
305 if (res->status == CMD_INVALID) {
306 free_argv(argc, argv);
307 goto cleanup;
308 }
309 }
310 } 307 }
311 free_argv(argc, argv); 308 }
312 } while(cmdlist); 309 free_argv(argc, argv);
313 } while(head); 310 } while(head);
314cleanup: 311cleanup:
315 free(exec); 312 free(exec);