]> git.sur5r.net Git - i3/i3/commitdiff
Reject invalid match criteria with an error. 2103/head
authorIngo Bürk <ingo.buerk@tngtech.com>
Wed, 9 Dec 2015 12:39:08 +0000 (13:39 +0100)
committerIngo Bürk <ingo.buerk@tngtech.com>
Wed, 9 Dec 2015 13:00:53 +0000 (14:00 +0100)
Previously, using a command like

  [con_id=foo] kill

would kill the currently focused window because while an error for
not being able to parse the con_id was logged, no further action
was taken, which caused the criterion to be ignored. In this case,
the fallback behavior of using the focused window took over.

For con_id, id and window_type we now reject incorrect values with
an error and abort the command.

fixes #2091

include/data.h
src/commands.c
src/match.c
testcases/t/260-invalid-criteria.t [new file with mode: 0644]

index 636092d24aae4d024d12bc6d49fbfc3db482a5ae..b122dbfdfc88a4eb26f943e14f7beb928a1c159b 100644 (file)
@@ -436,6 +436,9 @@ struct Window {
  *
  */
 struct Match {
+    /* Set if a criterion was specified incorrectly. */
+    char *error;
+
     struct regex *title;
     struct regex *application;
     struct regex *class;
index 5b28d03ead938b9384e27faac491b8a15299a020..78b1e993d6e5562573fc8f3640796cfcd7232cdf 100644 (file)
         }                                               \
     } while (0)
 
+/** If an error occured during parsing of the criteria, we want to exit instead
+ * of relying on fallback behavior. See #2091. */
+#define HANDLE_INVALID_MATCH                                   \
+    do {                                                       \
+        if (current_match->error != NULL) {                    \
+            yerror("Invalid match: %s", current_match->error); \
+            return;                                            \
+        }                                                      \
+    } while (0)
+
 /** When the command did not include match criteria (!), we use the currently
  * focused container. Do not confuse this case with a command which included
  * criteria but which did not match any windows. This macro has to be called in
@@ -49,6 +59,8 @@
  */
 #define HANDLE_EMPTY_MATCH                              \
     do {                                                \
+        HANDLE_INVALID_MATCH;                           \
+                                                        \
         if (match_is_empty(current_match)) {            \
             owindow *ow = smalloc(sizeof(owindow));     \
             ow->con = focused;                          \
@@ -1233,6 +1245,8 @@ void cmd_kill(I3_CMD, const char *kill_mode_str) {
         return;
     }
 
+    HANDLE_INVALID_MATCH;
+
     /* check if the match is empty, not if the result is empty */
     if (match_is_empty(current_match))
         tree_close_con(kill_mode);
index 950e0fe36f2690c2a81b76bd85001b7b2abf382e..caeb909fce43bfa0cbb129b62535ff505039b769 100644 (file)
@@ -238,6 +238,7 @@ bool match_matches_window(Match *match, i3Window *window) {
  *
  */
 void match_free(Match *match) {
+    FREE(match->error);
     regex_free(match->title);
     regex_free(match->application);
     regex_free(match->class);
@@ -286,6 +287,7 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
             parsed < 0 ||
             (end && *end != '\0')) {
             ELOG("Could not parse con id \"%s\"\n", cvalue);
+            match->error = sstrdup("invalid con_id");
         } else {
             match->con_id = (Con *)parsed;
             DLOG("id as int = %p\n", match->con_id);
@@ -301,6 +303,7 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
             parsed < 0 ||
             (end && *end != '\0')) {
             ELOG("Could not parse window id \"%s\"\n", cvalue);
+            match->error = sstrdup("invalid id");
         } else {
             match->id = parsed;
             DLOG("window id as int = %d\n", match->id);
@@ -309,26 +312,28 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
     }
 
     if (strcmp(ctype, "window_type") == 0) {
-        if (strcasecmp(cvalue, "normal") == 0)
+        if (strcasecmp(cvalue, "normal") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
-        else if (strcasecmp(cvalue, "dialog") == 0)
+        } else if (strcasecmp(cvalue, "dialog") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
-        else if (strcasecmp(cvalue, "utility") == 0)
+        } else if (strcasecmp(cvalue, "utility") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
-        else if (strcasecmp(cvalue, "toolbar") == 0)
+        } else if (strcasecmp(cvalue, "toolbar") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
-        else if (strcasecmp(cvalue, "splash") == 0)
+        } else if (strcasecmp(cvalue, "splash") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
-        else if (strcasecmp(cvalue, "menu") == 0)
+        } else if (strcasecmp(cvalue, "menu") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
-        else if (strcasecmp(cvalue, "dropdown_menu") == 0)
+        } else if (strcasecmp(cvalue, "dropdown_menu") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
-        else if (strcasecmp(cvalue, "popup_menu") == 0)
+        } else if (strcasecmp(cvalue, "popup_menu") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
-        else if (strcasecmp(cvalue, "tooltip") == 0)
+        } else if (strcasecmp(cvalue, "tooltip") == 0) {
             match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
-        else
+        } else {
             ELOG("unknown window_type value \"%s\"\n", cvalue);
+            match->error = sstrdup("unknown window_type value");
+        }
 
         return;
     }
diff --git a/testcases/t/260-invalid-criteria.t b/testcases/t/260-invalid-criteria.t
new file mode 100644 (file)
index 0000000..4c1830f
--- /dev/null
@@ -0,0 +1,27 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://build.i3wm.org/docs/ipc.html
+#   (or docs/ipc)
+#
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
+#   (unless you are already familiar with Perl)
+#
+# Ticket: #2091
+use i3test;
+
+my $ws = fresh_workspace;
+open_window;
+
+my $result = cmd '[con_id=foobar] kill';
+is($result->[0]->{success}, 0, 'command was unsuccessful');
+is($result->[0]->{error}, 'Invalid match: invalid con_id', 'correct error is returned');
+
+done_testing;