From da8aa0b66d478761906e4ca63091a5f8a3800960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 1 Nov 2022 00:31:58 +0100 Subject: [PATCH] desktop-app-info: Use launch context PATH and desktop Path to find terminals We used to launch applications with terminals using the normal program finder logic that did not consider the context path nor the desktop file working dir. Switch to g_find_program_for_path() to find terminals so we can ensure that both conditions are true. Update tests to consider this case too. --- gio/gdesktopappinfo.c | 15 +++-- gio/tests/desktop-app-info.c | 117 +++++++++++++++++++++++++++++------ 2 files changed, 109 insertions(+), 23 deletions(-) diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index 697c7b9d1..aca7e9c37 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -1864,6 +1864,7 @@ g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info, if (try_exec && try_exec[0] != '\0') { char *t; + /* Use the desktop file path (if any) as working dir to search program */ t = g_find_program_for_path (try_exec, NULL, path); if (t == NULL) { @@ -1896,6 +1897,7 @@ g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info, /* Since @exec is not an empty string, there must be at least one * argument, so dereferencing argv[0] should return non-NULL. */ g_assert (argc > 0); + /* Use the desktop file path (if any) as working dir to search program */ t = g_find_program_for_path (argv[0], NULL, path); g_strfreev (argv); @@ -2631,8 +2633,10 @@ expand_application_parameters (GDesktopAppInfo *info, } static gboolean -prepend_terminal_to_vector (int *argc, - char ***argv) +prepend_terminal_to_vector (int *argc, + char ***argv, + const char *path, + const char *working_dir) { #ifndef G_OS_WIN32 char **real_argv; @@ -2678,7 +2682,8 @@ prepend_terminal_to_vector (int *argc, for (i = 0, found_terminal = NULL; i < G_N_ELEMENTS (known_terminals); i++) { - found_terminal = g_find_program_in_path (known_terminals[i].exec); + found_terminal = g_find_program_for_path (known_terminals[i].exec, + path, working_dir); if (found_terminal != NULL) { term_arg = known_terminals[i].exec_arg; @@ -2880,7 +2885,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info, launched_uris = g_list_prepend (launched_uris, iter->data); launched_uris = g_list_reverse (launched_uris); - if (info->terminal && !prepend_terminal_to_vector (&argc, &argv)) + if (info->terminal && !prepend_terminal_to_vector (&argc, &argv, + g_environ_getenv (envp, "PATH"), + info->path)) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unable to find terminal required for application")); diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c index 0839eb0a2..c5e4f2f85 100644 --- a/gio/tests/desktop-app-info.c +++ b/gio/tests/desktop-app-info.c @@ -1369,6 +1369,17 @@ get_terminal_divider (const char *terminal_name) g_return_val_if_reached (NULL); } +typedef enum { + TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE, + TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT, + TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH, +} TerminalLaunchType; + +typedef struct { + const char *exec; + TerminalLaunchType type; +} TerminalLaunchData; + static void test_launch_uris_with_terminal (gconstpointer data) { @@ -1376,8 +1387,9 @@ test_launch_uris_with_terminal (gconstpointer data) int ret; int flags; int terminal_divider_arg_length; - const char *terminal_exec = data; - char *old_path; + const TerminalLaunchData *launch_data = data; + const char *terminal_exec = launch_data->exec; + char *old_path = NULL; char *command_line; char *bin_path; char *terminal_path; @@ -1392,6 +1404,7 @@ test_launch_uris_with_terminal (gconstpointer data) GError *error = NULL; GInputStream *input_stream; GDataInputStream *data_input_stream; + GAppLaunchContext *launch_context; sh = g_find_program_in_path ("sh"); g_assert_nonnull (sh); @@ -1399,26 +1412,40 @@ test_launch_uris_with_terminal (gconstpointer data) bin_path = g_dir_make_tmp ("bin-path-XXXXXX", &error); g_assert_no_error (error); - old_path = g_strdup (g_getenv ("PATH")); - g_assert_true (g_setenv ("PATH", bin_path, TRUE)); + launch_context = g_object_new (test_launch_context_get_type (), NULL); + + switch (launch_data->type) + { + case TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE: + old_path = g_strdup (g_getenv ("PATH")); + g_assert_true (g_setenv ("PATH", bin_path, TRUE)); + break; + + case TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT: + g_app_launch_context_setenv (launch_context, "PATH", bin_path); + break; + + case TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH: + g_app_launch_context_setenv (launch_context, "PATH", "/not/valid"); + break; + + default: + g_assert_not_reached (); + } terminal_path = g_build_filename (bin_path, terminal_exec, NULL); output_fd_path = g_build_filename (bin_path, "fifo", NULL); ret = mkfifo (output_fd_path, 0600); - g_assert_cmpint (ret, ==, 0); fd = g_open (output_fd_path, O_RDONLY | O_CLOEXEC | O_NONBLOCK, 0); - g_assert_cmpint (fd, >=, 0); flags = fcntl (fd, F_GETFL); - g_assert_cmpint (flags, >=, 0); ret = fcntl (fd, F_SETFL, flags & ~O_NONBLOCK); - g_assert_cmpint (ret, ==, 0); input_stream = g_unix_input_stream_new (fd, TRUE); @@ -1435,12 +1462,43 @@ test_launch_uris_with_terminal (gconstpointer data) g_test_message ("Fake '%s' terminal created as: %s", terminal_exec, terminal_path); command_line = g_strdup_printf ("true %s-argument", terminal_exec); - app_info = g_app_info_create_from_commandline (command_line, - "Test App on Terminal", - G_APP_INFO_CREATE_NEEDS_TERMINAL | - G_APP_INFO_CREATE_SUPPORTS_URIS, - &error); - g_assert_no_error (error); + + if (launch_data->type == TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH) + { + GKeyFile *key_file; + char *key_file_contents; + const char base_file[] = + "[Desktop Entry]\n" + "Type=Application\n" + "Name=terminal launched app\n" + "Terminal=true\n" + "Path=%s\n" + "Exec=%s\n"; + + key_file = g_key_file_new (); + key_file_contents = g_strdup_printf (base_file, bin_path, command_line); + + g_assert_true ( + g_key_file_load_from_data (key_file, key_file_contents, -1, + G_KEY_FILE_NONE, NULL)); + + app_info = (GAppInfo*) g_desktop_app_info_new_from_keyfile (key_file); + g_assert_true (G_IS_DESKTOP_APP_INFO (app_info)); + g_assert_true ( + g_desktop_app_info_get_boolean (G_DESKTOP_APP_INFO (app_info), "Terminal")); + + g_key_file_unref (key_file); + g_free (key_file_contents); + } + else + { + app_info = g_app_info_create_from_commandline (command_line, + "Test App on Terminal", + G_APP_INFO_CREATE_NEEDS_TERMINAL | + G_APP_INFO_CREATE_SUPPORTS_URIS, + &error); + g_assert_no_error (error); + } paths = g_list_prepend (NULL, bin_path); uris = g_list_prepend (NULL, g_filename_to_uri (bin_path, NULL, &error)); @@ -1451,7 +1509,7 @@ test_launch_uris_with_terminal (gconstpointer data) g_assert_no_error (error); g_assert_cmpint (g_list_length (paths), ==, 2); - g_app_info_launch_uris (app_info, uris, NULL, &error); + g_app_info_launch_uris (app_info, uris, launch_context, &error); g_assert_no_error (error); while (output_contents == NULL) @@ -1523,7 +1581,9 @@ test_launch_uris_with_terminal (gconstpointer data) g_clear_pointer (&output_args, g_strfreev); g_assert_null (paths); - g_assert_true (g_setenv ("PATH", old_path, TRUE)); + + if (launch_data->type == TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE) + g_assert_true (g_setenv ("PATH", old_path, TRUE)); g_close (fd, &error); g_assert_no_error (error); @@ -1540,6 +1600,7 @@ test_launch_uris_with_terminal (gconstpointer data) g_clear_object (&data_input_stream); g_clear_object (&input_stream); g_clear_object (&app_info); + g_clear_object (&launch_context); g_clear_error (&error); g_clear_list (&paths, NULL); g_clear_list (&uris, g_free); @@ -1685,12 +1746,30 @@ main (int argc, { char *path; - path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/%s", + path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-path/%s", supported_terminals[i]); - g_test_add_data_func (path, supported_terminals[i], - test_launch_uris_with_terminal); + g_test_add_data_func (path, &(TerminalLaunchData) { + .exec = supported_terminals[i], + .type = TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_PATH_OVERRIDE, + }, test_launch_uris_with_terminal); g_free (path); + + path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-context/%s", + supported_terminals[i]); + g_test_add_data_func (path, &(TerminalLaunchData) { + .exec = supported_terminals[i], + .type = TERMINAL_LAUNCH_TYPE_COMMAND_LINE_WITH_CONTEXT, + }, test_launch_uris_with_terminal); + g_clear_pointer (&path, g_free); + + path = g_strdup_printf ("/desktop-app-info/launch-uris-with-terminal/with-desktop-path/%s", + supported_terminals[i]); + g_test_add_data_func (path, &(TerminalLaunchData) { + .exec = supported_terminals[i], + .type = TERMINAL_LAUNCH_TYPE_KEY_FILE_WITH_PATH, + }, test_launch_uris_with_terminal); + g_clear_pointer (&path, g_free); } g_test_add_func ("/desktop-app-info/launch-uris-with-terminal/invalid-glib-terminal",