diff --git a/.valgrind.suppressions b/.valgrind.suppressions index ce954e3a7..e2515facd 100644 --- a/.valgrind.suppressions +++ b/.valgrind.suppressions @@ -6,6 +6,19 @@ obj:/lib/ld-musl-x86_64.so.1 } +# Ignore another musls' weird error +{ + musl_alpine_libc + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:realloc + fun:getdelim + obj:* + fun:vgMemCheck_new_block + obj:* +} + # rsvg_error_handle_close got fixed in # - GNOME/librsvg@7bf1014 # (2018-11-12, first tags: v2.45.0, v2.44.9) diff --git a/docs/dunst.5.pod b/docs/dunst.5.pod index 3f4f2acb2..62e9a29b9 100644 --- a/docs/dunst.5.pod +++ b/docs/dunst.5.pod @@ -911,7 +911,8 @@ If B is set to off, this setting is ignored. Updates the icon of the notification, it should be a path or a name for a valid image. This overrides the icon that was sent with dunstify or another notification -tool. +tool. Expansion of the argument is carried out using wordexp(3) +with command substitution disabled. =item C (values: [left/right/top/off], default: left) @@ -922,7 +923,8 @@ disables icons. Sets the default icon of the notification, it should be a path or a name for a valid image. This does B override the icon that was sent with dunstify or -another notification tool. +another notification tool. Expansion of the argument is carried out using +wordexp(3) with command substitution disabled. =item C @@ -1087,9 +1089,10 @@ Note that some variables may be empty. If the notification is suppressed, the script will not be run unless B is set to true. -If '~/' occurs at the beginning of the script parameter, it will get replaced by the -users' home directory. If the value is not an absolute path, the directories in the -PATH variable will be searched for an executable of the same name. +The script parameter is expanded according to wordexp(3) with command +substitution disabled. If the expanded value is not an absolute path, the +directories in the PATH variable will be searched for an executable of the same +name. =head1 COLORS diff --git a/src/utils.c b/src/utils.c index 61bc43d83..e47945717 100644 --- a/src/utils.c +++ b/src/utils.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "log.h" #include "settings_data.h" @@ -179,16 +180,34 @@ int string_array_length(char **s) /* see utils.h */ char *string_to_path(char *string) { - - if (string && STRN_EQ(string, "~/", 2)) { - char *home = g_strconcat(user_get_home(), "/", NULL); - - string = string_replace_at(string, 0, 2, home); - - g_free(home); + ASSERT_OR_RET(string, string); + + wordexp_t we; + switch (wordexp(string, &we, WRDE_NOCMD | WRDE_UNDEF)) { + case 0: + break; + case WRDE_BADCHAR: + LOG_W("Expansion of \"%s\" failed. It contains invalid characters.", string); + return string; + case WRDE_BADVAL: + LOG_W("Expansion of \"%s\" failed. It contains an undefined variable.", string); + return string; + case WRDE_CMDSUB: + LOG_W("Expansion of \"%s\" failed. The requested command substitution is currently not supported.", string); + return string; + case WRDE_NOSPACE: + LOG_W("Expansion of \"%s\" failed. We ran out of memory.", string); + return string; + case WRDE_SYNTAX: + LOG_W("Expansion of \"%s\" failed. It contains invalid syntax.", string); + return string; } + g_free(string); + + char *res = g_strjoinv(" ", we.we_wordv); + wordfree(&we); - return string; + return res; } /* see utils.h */ diff --git a/test/option_parser.c b/test/option_parser.c index 8773fad10..72d31a67f 100644 --- a/test/option_parser.c +++ b/test/option_parser.c @@ -521,9 +521,14 @@ TEST test_string_to_path(void) "/path/p argument", "p with multiple arguments", "~/p/p", + "$HOME/p/p", + "$TEST_ENV/p/p", }; + setenv("TEST_ENV", "foobar", 1); + char *expanded_home = g_strconcat(user_get_home(), "/", "p/p", NULL); + char *expanded_env = g_strconcat("foobar", "/p/p", NULL); const char* results[] = { "/bin/something", "something", @@ -531,6 +536,8 @@ TEST test_string_to_path(void) "/path/p argument", "p with multiple arguments", expanded_home, + expanded_home, + expanded_env, }; const char* results2[][5] = { @@ -540,6 +547,8 @@ TEST test_string_to_path(void) {"/path/p", "argument", NULL}, {"p", "with", "multiple", "arguments", NULL}, {expanded_home}, + {expanded_home}, + {expanded_env}, }; ARRAY_SAME_LENGTH(inputs, results); @@ -557,6 +566,7 @@ TEST test_string_to_path(void) } g_free(val); + g_free(expanded_env); g_free(expanded_home); g_strfreev(val2); PASS(); diff --git a/test/utils.c b/test/utils.c index cca574b25..938ebde2a 100644 --- a/test/utils.c +++ b/test/utils.c @@ -1,3 +1,5 @@ +#include + #include "../src/utils.c" #include "greatest.h" @@ -152,6 +154,7 @@ TEST test_string_to_path(void) ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); free(ptr); + // This might fail, when a user named path exists on the host running the tests. exp = "~path/with/wrong/tilde"; ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); free(ptr); @@ -166,6 +169,19 @@ TEST test_string_to_path(void) free(exp); free(ptr); + ASSERT_STR_EQ((exp = g_strconcat(home, "/.path/with/HOME environment variable", NULL)), + (ptr = string_to_path(g_strdup("$HOME/.path/with/HOME environment variable")))); + free(exp); + free(ptr); + +// Just glibc properly returns an error when using `WRDE_UNDEF` and an +// undefined variable is found. musl accepts this flag and ignores it. +#ifdef __GLIBC__ + exp = "/some/$UNDEFINED/variable"; + ASSERT_STR_EQ(exp, (ptr = string_to_path(g_strdup(exp)))); + free(ptr); +#endif + PASS(); }