mirror of
https://github.com/flatpak/flatpak.git
synced 2026-10-28 10:29:42 -04:00
In commit 21f413f1, flatpak_instance_new was changed to require the pid
file to be written in order to succeed. This causes problems when
calling Spawn with NOTIFY_START, however, because portal expects to be
able to call flatpak_instance_new once the instance ID is retrieved. As
per the comments in the code that writes said instance ID, the idea was
that the instance would be *usable* at the point where the write takes
place (hence it being positioned *after* saving `bwrapinfo.json`), so it
makes sense to now move the write to *after* after the pid file is
written.
Since the pid file write and the instance ID write now go hand-in-hand,
both actions now take place in a separate function, so the logic can be
in one place. Additionally, the write itself is migrated to
`glnx_loop_write`, to shorten the code.
Assisted-by: DeepSeek-V4.1-Flash
149 lines
4.3 KiB
C
149 lines
4.3 KiB
C
#include "libglnx.h"
|
|
|
|
#include "flatpak-glib-backports-private.h"
|
|
#include "portal/flatpak-portal.h"
|
|
#include "portal/flatpak-portal-dbus.h"
|
|
|
|
static gboolean opt_notify_start;
|
|
static const char *opt_write_after_start;
|
|
|
|
static GOptionEntry options[] = {
|
|
{ "notify-start", 0, 0, G_OPTION_ARG_NONE, &opt_notify_start,
|
|
"Pass FLATPAK_SPAWN_FLAGS_NOTIFY_START", NULL },
|
|
{ "write-after-start", 0, 0, G_OPTION_ARG_STRING, &opt_write_after_start,
|
|
"Write 'done\\n' to the given path after SpawnStarted is received", NULL },
|
|
{ NULL }
|
|
};
|
|
|
|
typedef struct {
|
|
GMainLoop *loop;
|
|
gboolean done;
|
|
} SpawnData;
|
|
|
|
static void
|
|
spawn_started_cb (PortalFlatpak *portal,
|
|
guint pid,
|
|
guint relpid,
|
|
gpointer user_data)
|
|
{
|
|
g_print ("spawn-started pid=%u relpid=%u\n", pid, relpid);
|
|
|
|
if (opt_write_after_start != NULL)
|
|
{
|
|
glnx_autofd int fd = open (opt_write_after_start, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
const char done[] = "done\n";
|
|
if (fd == -1 || glnx_loop_write (fd, done, strlen (done)) == -1)
|
|
{
|
|
int saved_errno = errno;
|
|
g_error ("writing to %s: %s", opt_write_after_start, strerror (saved_errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
spawn_exited_cb (PortalFlatpak *portal,
|
|
guint pid,
|
|
guint exit_status,
|
|
gpointer user_data)
|
|
{
|
|
SpawnData *data = user_data;
|
|
|
|
g_print ("spawn-exited pid=%u status=%u\n", pid, exit_status);
|
|
data->done = TRUE;
|
|
g_main_loop_quit (data->loop);
|
|
}
|
|
|
|
static gboolean
|
|
spawn_timeout_cb (gpointer user_data)
|
|
{
|
|
SpawnData *data = user_data;
|
|
|
|
g_printerr ("Timed out waiting for SpawnStarted or SpawnExited\n");
|
|
g_main_loop_quit (data->loop);
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
g_autoptr(GDBusConnection) connection = NULL;
|
|
g_autoptr(PortalFlatpak) portal = NULL;
|
|
g_autoptr(GUnixFDList) fds_out = NULL;
|
|
g_autoptr(GOptionContext) context = NULL;
|
|
g_autoptr(GMainLoop) loop = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
guint flags = FLATPAK_SPAWN_FLAGS_NONE;
|
|
SpawnData data = { NULL, FALSE };
|
|
guint pid;
|
|
|
|
context = g_option_context_new ("COMMAND [ARG...]");
|
|
g_option_context_set_strict_posix (context, TRUE);
|
|
g_option_context_add_main_entries (context, options, NULL);
|
|
if (!g_option_context_parse (context, &argc, &argv, &error))
|
|
{
|
|
g_printerr ("Option parsing failed: %s\n", error->message);
|
|
return 1;
|
|
}
|
|
|
|
if (argc < 2)
|
|
{
|
|
g_printerr ("A command to run is required\n");
|
|
return 1;
|
|
}
|
|
|
|
if (opt_notify_start)
|
|
flags |= FLATPAK_SPAWN_FLAGS_NOTIFY_START;
|
|
|
|
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
if (connection == NULL)
|
|
{
|
|
g_printerr ("Error connecting to session bus: %s\n", error->message);
|
|
return 1;
|
|
}
|
|
|
|
portal = portal_flatpak_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE,
|
|
FLATPAK_PORTAL_BUS_NAME,
|
|
FLATPAK_PORTAL_PATH,
|
|
NULL, &error);
|
|
if (portal == NULL)
|
|
{
|
|
g_printerr ("Error creating portal proxy: %s\n", error->message);
|
|
return 1;
|
|
}
|
|
|
|
loop = g_main_loop_new (NULL, FALSE);
|
|
data.loop = loop;
|
|
|
|
g_signal_connect (portal, "spawn-exited", G_CALLBACK (spawn_exited_cb), &data);
|
|
if (opt_notify_start)
|
|
g_signal_connect (portal, "spawn-started", G_CALLBACK (spawn_started_cb), &data);
|
|
|
|
if (!portal_flatpak_call_spawn_sync (portal,
|
|
"/", /* cwd */
|
|
(const char * const *) &argv[1],
|
|
g_variant_new ("a{uh}", NULL),
|
|
g_variant_new ("a{ss}", NULL),
|
|
flags,
|
|
g_variant_new ("a{sv}", NULL),
|
|
NULL, /* fd list */
|
|
&pid,
|
|
&fds_out,
|
|
NULL,
|
|
&error))
|
|
{
|
|
g_printerr ("Error calling Spawn: %s\n", error->message);
|
|
return 1;
|
|
}
|
|
|
|
if (!data.done)
|
|
{
|
|
g_timeout_add_seconds (15, spawn_timeout_cb, &data);
|
|
g_main_loop_run (loop);
|
|
|
|
if (!data.done)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|