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.
This commit is contained in:
Marco Trevisan (Treviño) 2022-11-01 00:31:58 +01:00
parent e41e3dc601
commit da8aa0b66d
2 changed files with 109 additions and 23 deletions

View File

@ -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"));

View File

@ -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",