diff --git a/app/flatpak-builtins-ps.c b/app/flatpak-builtins-ps.c
index fa9ebfcf..760a97f1 100644
--- a/app/flatpak-builtins-ps.c
+++ b/app/flatpak-builtins-ps.c
@@ -33,7 +33,7 @@
#include "flatpak-builtins.h"
#include "flatpak-table-printer.h"
-#include "flatpak-run-private.h"
+#include "flatpak-instance-private.h"
static gboolean opt_show_cols;
static const char **opt_cols;
@@ -129,121 +129,16 @@ show_columns (void)
g_print ("%s", col_help);
}
-static char *
-get_instance_pid (const char *instance)
-{
- g_autofree char *path = NULL;
- char *pid;
- g_autoptr(GError) error = NULL;
-
- path = g_build_filename (g_get_user_runtime_dir (), ".flatpak", instance, "pid", NULL);
-
- if (!g_file_get_contents (path, &pid, NULL, &error))
- {
- g_debug ("Failed to load pid file for instance '%s': %s", instance, error->message);
- return NULL;
- }
-
- return pid;
-}
-
-static int
-get_child_pid (const char *instance)
-{
- g_autofree char *path = NULL;
- g_autofree char *contents = NULL;
- gsize length;
- g_autoptr(GError) error = NULL;
- g_autoptr(JsonParser) parser = NULL;
- g_autoptr(JsonNode) node = NULL;
- g_autoptr(JsonObject) obj = NULL;
-
- path = g_build_filename (g_get_user_runtime_dir (), ".flatpak", instance, "bwrapinfo.json", NULL);
-
- if (!g_file_get_contents (path, &contents, &length, &error))
- {
- g_debug ("Failed to load bwrapinfo.json file for instance '%s': %s", instance, error->message);
- return 0;
- }
-
- parser = json_parser_new ();
- if (!json_parser_load_from_data (parser, contents, length, &error))
- {
- g_debug ("Failed to parse bwrapinfo.json file for instance '%s': %s", instance, error->message);
- return 0;
- }
-
- node = json_parser_get_root (parser);
- obj = json_node_get_object (node);
-
- return json_object_get_int_member (obj, "child-pid");
-}
-
-static GKeyFile *
-get_instance_info (const char *instance)
-{
- g_autofree char *path = NULL;
- GKeyFile *key_file = NULL;
- g_autoptr(GError) error = NULL;
-
- path = g_build_filename (g_get_user_runtime_dir (), ".flatpak", instance, "info", NULL);
-
- key_file = g_key_file_new ();
- if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error))
- {
- g_debug ("Failed to load info file for instance '%s': %s", instance, error->message);
- return NULL;
- }
-
- return key_file;
-}
-
-static char *
-get_instance_column (GKeyFile *info,
- const char *name)
-{
- if (info == NULL)
- return NULL;
-
- if (strcmp (name, "application") == 0)
- return g_key_file_get_string (info, "Application", "name", NULL);
- if (strcmp (name, "arch") == 0)
- return g_key_file_get_string (info, "Instance", "arch", NULL);
- if (strcmp (name, "branch") == 0)
- return g_key_file_get_string (info, "Instance", "branch", NULL);
- else if (strcmp (name, "commit") == 0)
- return g_key_file_get_string (info, "Instance", "app-commit", NULL);
- else if (strcmp (name, "runtime") == 0)
- {
- g_autofree char *full_ref = g_key_file_get_string (info, "Application", "runtime", NULL);
- g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL);
- return g_strdup (ref[1]);
- }
- else if (strcmp (name, "runtime-branch") == 0)
- {
- g_autofree char *full_ref = g_key_file_get_string (info, "Application", "runtime", NULL);
- g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL);
- return g_strdup (ref[3]);
- }
- else if (strcmp (name, "runtime-commit") == 0)
- return g_key_file_get_string (info, "Instance", "runtime-commit", NULL);
-
- return NULL;
-}
-
static gboolean
enumerate_instances (const char *columns,
GError **error)
{
- g_autofree char *base_dir = NULL;
- g_autoptr(GFile) file = NULL;
- g_autoptr(GFileEnumerator) enumerator = NULL;
- GFileInfo *dir_info;
+ g_autoptr(GPtrArray) instances = NULL;
FlatpakTablePrinter *printer;
g_auto(GStrv) cols = NULL;
g_autofree int *col_idx = NULL;
int n_cols;
- int i;
+ int i, j;
cols = g_strsplit (columns, ",", 0);
n_cols = g_strv_length (cols);
@@ -263,40 +158,58 @@ enumerate_instances (const char *columns,
for (i = 0; i < n_cols; i++)
flatpak_table_printer_set_column_title (printer, i + 1, all_columns[col_idx[i]].title);
- base_dir = g_build_filename (g_get_user_runtime_dir (), ".flatpak", NULL);
- file = g_file_new_for_path (base_dir);
- enumerator = g_file_enumerate_children (file, "standard::name", G_FILE_QUERY_INFO_NONE, NULL, error);
- if (enumerator == NULL)
+ instances = flatpak_instance_get_all ();
+ if (instances->len == 0)
{
- if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
- {
- /* nothing to show */
- g_clear_error (error);
- return TRUE;
- }
- return FALSE;
+ /* nothing to show */
+ return TRUE;
}
- while ((dir_info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL)
+ for (j = 0; j < instances->len; j++)
{
- g_autofree char *instance = g_file_info_get_attribute_as_string (dir_info, "standard::name");
- g_autoptr(GKeyFile) info = get_instance_info (instance);
+ FlatpakInstance *instance = (FlatpakInstance *)g_ptr_array_index (instances, j);
- flatpak_table_printer_add_column (printer, instance);
+ flatpak_table_printer_add_column (printer, flatpak_instance_get_id (instance));
for (i = 0; i < n_cols; i++)
{
- g_autofree char *col = NULL;
+ g_autofree char *freeme = NULL;
+ const char *col = NULL;
+ int idx = col_idx[i];
int len;
- if (strcmp (all_columns[col_idx[i]].name, "pid") == 0)
- col = get_instance_pid (instance);
- else if (strcmp (all_columns[col_idx[i]].name, "child-pid") == 0)
- col = g_strdup_printf ("%d", get_child_pid (instance));
- else
- col = get_instance_column (info, all_columns[col_idx[i]].name);
+ if (strcmp (all_columns[idx].name, "pid") == 0)
+ col = freeme = g_strdup_printf ("%d", flatpak_instance_get_pid (instance));
+ else if (strcmp (all_columns[idx].name, "child-pid") == 0)
+ col = freeme = g_strdup_printf ("%d", flatpak_instance_get_child_pid (instance));
+ else if (strcmp (all_columns[idx].name, "application") == 0)
+ col = flatpak_instance_get_app (instance);
+ else if (strcmp (all_columns[idx].name, "arch") == 0)
+ col = flatpak_instance_get_arch (instance);
+ else if (strcmp (all_columns[idx].name, "commit") == 0)
+ col = flatpak_instance_get_commit (instance);
+ else if (strcmp (all_columns[idx].name, "runtime") == 0)
+ {
+ const char *full_ref = flatpak_instance_get_runtime (instance);
+ if (full_ref != NULL)
+ {
+ g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL);
+ col = freeme = g_strdup (ref[1]);
+ }
+ }
+ else if (strcmp (all_columns[idx].name, "runtime-branch") == 0)
+ {
+ const char *full_ref = flatpak_instance_get_runtime (instance);
+ if (full_ref != NULL)
+ {
+ g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL);
+ col = freeme = g_strdup (ref[3]);
+ }
+ }
+ else if (strcmp (all_columns[idx].name, "runtime-commit") == 0)
+ col = flatpak_instance_get_runtime_commit (instance);
- len = all_columns[col_idx[i]].len;
+ len = all_columns[idx].len;
if (len == 0)
flatpak_table_printer_add_column (printer, col);
else
@@ -304,24 +217,35 @@ enumerate_instances (const char *columns,
}
flatpak_table_printer_finish_row (printer);
-
- g_object_unref (dir_info);
}
flatpak_table_printer_print (printer);
flatpak_table_printer_free (printer);
- if (*error)
- return FALSE;
-
return TRUE;
}
+static gboolean
+list_has (const char *list,
+ const char *term)
+{
+ const char *p;
+ int len;
+
+ p = strstr (list, term);
+ len = strlen (term);
+ if (p &&
+ (p == list || p[-1] == ',') &&
+ (p[len] == '\0' || p[len] == ','))
+ return TRUE;
+ return FALSE;
+}
+
gboolean
-flatpak_builtin_ps (int argc,
- char **argv,
- GCancellable *cancellable,
- GError **error)
+flatpak_builtin_ps (int argc,
+ char **argv,
+ GCancellable *cancellable,
+ GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autofree char *col_help = NULL;
@@ -341,8 +265,6 @@ flatpak_builtin_ps (int argc,
return FALSE;
}
- flatpak_run_gc_ids ();
-
if (opt_show_cols)
{
show_columns ();
@@ -351,38 +273,24 @@ flatpak_builtin_ps (int argc,
if (opt_cols)
{
- gboolean show_help = FALSE;
gboolean show_all = FALSE;
int i;
for (i = 0; opt_cols[i]; i++)
{
- const char *p;
- p = strstr (opt_cols[i], "help");
- if (p &&
- (p == opt_cols[i] || p[-1] == ',') &&
- (p[strlen("help")] == '\0' || p[strlen("help")] == ','))
+ if (list_has (opt_cols[i], "help"))
{
- show_help = TRUE;
- break;
+ show_columns ();
+ return TRUE;
}
-
- p = strstr (opt_cols[i], "all");
- if (p &&
- (p == opt_cols[i] || p[-1] == ',') &&
- (p[strlen("all")] == '\0' || p[strlen("all")] == ','))
+ if (list_has (opt_cols[i], "all"))
{
show_all = TRUE;
break;
}
}
- if (show_help)
- {
- show_columns ();
- return TRUE;
- }
- else if (show_all)
+ if (show_all)
{
cols = g_strdup (ALL_COLUMNS);
}
diff --git a/common/Makefile.am.inc b/common/Makefile.am.inc
index d39d6513..f3966903 100644
--- a/common/Makefile.am.inc
+++ b/common/Makefile.am.inc
@@ -120,6 +120,8 @@ libflatpak_common_la_SOURCES = \
common/flatpak-error.c \
common/flatpak-installation-private.h \
common/flatpak-installation.c \
+ common/flatpak-instance-private.h \
+ common/flatpak-instance.c \
common/valgrind-private.h \
$(NULL)
diff --git a/common/flatpak-instance-private.h b/common/flatpak-instance-private.h
new file mode 100644
index 00000000..f9a27108
--- /dev/null
+++ b/common/flatpak-instance-private.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2018 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors:
+ * Matthias Clasen
+ */
+
+#if !defined(__FLATPAK_H_INSIDE__) && !defined(FLATPAK_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __FLATPAK_INSTANCE_H__
+#define __FLATPAK_INSTANCE_H__
+
+typedef struct _FlatpakInstance FlatpakInstance;
+
+#include
+
+#define FLATPAK_TYPE_INSTANCE flatpak_instance_get_type ()
+#define FLATPAK_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FLATPAK_TYPE_INSTANCE, FlatpakInstance))
+#define FLATPAK_IS_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FLATPAK_TYPE_INSTANCE))
+
+FLATPAK_EXTERN GType flatpak_instance_get_type (void);
+
+struct _FlatpakInstance
+{
+ GObject parent;
+};
+
+typedef struct
+{
+ GObjectClass parent_class;
+} FlatpakInstanceClass;
+
+
+#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakInstance, g_object_unref)
+#endif
+
+FLATPAK_EXTERN GPtrArray * flatpak_instance_get_all (void);
+
+FLATPAK_EXTERN const char * flatpak_instance_get_id (FlatpakInstance *self);
+FLATPAK_EXTERN const char * flatpak_instance_get_app (FlatpakInstance *self);
+FLATPAK_EXTERN const char * flatpak_instance_get_arch (FlatpakInstance *self);
+FLATPAK_EXTERN const char * flatpak_instance_get_branch (FlatpakInstance *self);
+FLATPAK_EXTERN const char * flatpak_instance_get_commit (FlatpakInstance *self);
+FLATPAK_EXTERN const char * flatpak_instance_get_runtime (FlatpakInstance *self);
+FLATPAK_EXTERN const char * flatpak_instance_get_runtime_commit (FlatpakInstance *self);
+FLATPAK_EXTERN int flatpak_instance_get_pid (FlatpakInstance *self);
+FLATPAK_EXTERN int flatpak_instance_get_child_pid (FlatpakInstance *self);
+FLATPAK_EXTERN GKeyFile * flatpak_instance_get_info (FlatpakInstance *self);
+
+FLATPAK_EXTERN gboolean flatpak_instance_is_running (FlatpakInstance *self);
+
+#endif /* __FLATPAK_INSTANCE_H__ */
diff --git a/common/flatpak-instance.c b/common/flatpak-instance.c
new file mode 100644
index 00000000..1f15776f
--- /dev/null
+++ b/common/flatpak-instance.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright © 2018 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors:
+ * Matthias Clasen
+ */
+
+#include "config.h"
+
+#include "flatpak-utils-private.h"
+#include "flatpak-run-private.h"
+#include "flatpak-instance-private.h"
+#include "flatpak-enum-types.h"
+
+
+typedef struct _FlatpakInstancePrivate FlatpakInstancePrivate;
+
+struct _FlatpakInstancePrivate
+{
+ char *id;
+ char *dir;
+
+ GKeyFile *info;
+ char *app;
+ char *arch;
+ char *branch;
+ char *commit;
+ char *runtime;
+ char *runtime_commit;
+
+ int pid;
+ int child_pid;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (FlatpakInstance, flatpak_instance, G_TYPE_OBJECT)
+
+static void
+flatpak_instance_finalize (GObject *object)
+{
+ FlatpakInstance *self = FLATPAK_INSTANCE (object);
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ g_free (priv->id);
+ g_free (priv->dir);
+ g_free (priv->app);
+ g_free (priv->arch);
+ g_free (priv->branch);
+ g_free (priv->commit);
+ g_free (priv->runtime);
+ g_free (priv->runtime_commit);
+
+ if (priv->info)
+ g_key_file_unref (priv->info);
+
+ G_OBJECT_CLASS (flatpak_instance_parent_class)->finalize (object);
+}
+
+static void
+flatpak_instance_class_init (FlatpakInstanceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = flatpak_instance_finalize;
+}
+
+static void
+flatpak_instance_init (FlatpakInstance *self)
+{
+}
+
+const char *
+flatpak_instance_get_id (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->id;
+}
+
+const char *
+flatpak_instance_get_app (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->app;
+}
+
+const char *
+flatpak_instance_get_arch (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->arch;
+}
+
+const char *
+flatpak_instance_get_branch (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->branch;
+}
+
+const char *
+flatpak_instance_get_commit (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->commit;
+}
+
+const char *
+flatpak_instance_get_runtime (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->runtime;
+}
+
+const char *
+flatpak_instance_get_runtime_commit (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->runtime_commit;
+}
+
+int
+flatpak_instance_get_pid (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->pid;
+}
+
+int
+flatpak_instance_get_child_pid (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->child_pid;
+}
+
+GKeyFile *
+flatpak_instance_get_info (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ return priv->info;
+}
+
+static GKeyFile *
+get_instance_info (const char *dir)
+{
+ g_autofree char *file = NULL;
+ g_autoptr(GKeyFile) key_file = NULL;
+ g_autoptr(GError) error = NULL;
+
+ file = g_build_filename (dir, "info", NULL);
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_file (key_file, file, G_KEY_FILE_NONE, &error))
+ {
+ g_debug ("Failed to load instance info file '%s': %s", file, error->message);
+ return NULL;
+ }
+
+ return g_steal_pointer (&key_file);
+}
+
+static int
+get_child_pid (const char *dir)
+{
+ g_autofree char *file = NULL;
+ g_autofree char *contents = NULL;
+ gsize length;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(JsonParser) parser = NULL;
+ JsonNode *node;
+ JsonObject *obj;
+
+ file = g_build_filename (dir, "bwrapinfo.json", NULL);
+
+ if (!g_file_get_contents (file, &contents, &length, &error))
+ {
+ g_debug ("Failed to load bwrapinfo.json file '%s': %s", file, error->message);
+ return 0;
+ }
+
+ parser = json_parser_new ();
+ if (!json_parser_load_from_data (parser, contents, length, &error))
+ {
+ g_debug ("Failed to parse bwrapinfo.json file '%s': %s", file, error->message);
+ return 0;
+ }
+
+ node = json_parser_get_root (parser);
+ obj = json_node_get_object (node);
+
+ return json_object_get_int_member (obj, "child-pid");
+}
+
+static int
+get_pid (const char *dir)
+{
+ g_autofree char *file = NULL;
+ g_autofree char *contents = NULL;
+ g_autoptr(GError) error = NULL;
+
+ file = g_build_filename (dir, "pid", NULL);
+
+ if (!g_file_get_contents (file, &contents, NULL, &error))
+ {
+ g_debug ("Failed to load pid file '%s': %s", file, error->message);
+ return 0;
+ }
+
+ return (int) g_ascii_strtoll (contents, NULL, 10);
+}
+
+static FlatpakInstance *
+flatpak_instance_new (const char *id)
+{
+ FlatpakInstance *self = g_object_new (flatpak_instance_get_type (), NULL);
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ priv->id = g_strdup (id);
+
+ priv->dir = g_build_filename (g_get_user_runtime_dir (), ".flatpak", id, NULL);
+
+ priv->pid = get_pid (priv->dir);
+ priv->child_pid = get_child_pid (priv->dir);
+ priv->info = get_instance_info (priv->dir);
+
+ if (priv->info)
+ {
+ priv->app = g_key_file_get_string (priv->info,
+ FLATPAK_METADATA_GROUP_APPLICATION, FLATPAK_METADATA_KEY_NAME, NULL);
+ priv->runtime = g_key_file_get_string (priv->info,
+ FLATPAK_METADATA_GROUP_APPLICATION, FLATPAK_METADATA_KEY_RUNTIME, NULL);
+
+ priv->arch = g_key_file_get_string (priv->info,
+ FLATPAK_METADATA_GROUP_INSTANCE, FLATPAK_METADATA_KEY_ARCH, NULL);
+ priv->branch = g_key_file_get_string (priv->info,
+ FLATPAK_METADATA_GROUP_INSTANCE, FLATPAK_METADATA_KEY_BRANCH, NULL);
+ priv->commit = g_key_file_get_string (priv->info,
+ FLATPAK_METADATA_GROUP_INSTANCE, FLATPAK_METADATA_KEY_APP_COMMIT, NULL);
+ priv->runtime_commit = g_key_file_get_string (priv->info,
+ FLATPAK_METADATA_GROUP_INSTANCE, FLATPAK_METADATA_KEY_RUNTIME_COMMIT, NULL);
+ }
+
+ return self;
+}
+
+GPtrArray *
+flatpak_instance_get_all (void)
+{
+ g_autoptr(GPtrArray) instances = NULL;
+ g_autofree char *base_dir = NULL;
+ g_auto(GLnxDirFdIterator) iter = { 0 };
+ struct dirent *dent;
+
+ instances = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ base_dir = g_build_filename (g_get_user_runtime_dir (), ".flatpak", NULL);
+
+ if (!glnx_dirfd_iterator_init_at (AT_FDCWD, base_dir, FALSE, &iter, NULL))
+ return g_steal_pointer (&instances);
+
+ while (TRUE)
+ {
+ if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&iter, &dent, NULL, NULL))
+ break;
+
+ if (dent == NULL)
+ break;
+
+ if (dent->d_type == DT_DIR)
+ {
+ g_autofree char *ref_file = g_strconcat (dent->d_name, "/.ref", NULL);
+ struct stat statbuf;
+ struct flock l = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+ glnx_autofd int lock_fd = openat (iter.fd, ref_file, O_RDWR | O_CLOEXEC);
+ if (lock_fd != -1 &&
+ fstat (lock_fd, &statbuf) == 0 &&
+ /* Only gc if created at least 3 secs ago, to work around race mentioned in flatpak_run_allocate_id() */
+ statbuf.st_mtime + 3 < time (NULL) &&
+ fcntl (lock_fd, F_GETLK, &l) == 0 &&
+ l.l_type == F_UNLCK)
+ {
+ /* The instance is not used, remove it */
+ g_debug ("Cleaning up unused container id %s", dent->d_name);
+ glnx_shutil_rm_rf_at (iter.fd, dent->d_name, NULL, NULL);
+ continue;
+ }
+
+ g_ptr_array_add (instances, flatpak_instance_new (dent->d_name));
+ }
+ }
+
+ return g_steal_pointer (&instances);
+}
+
+gboolean
+flatpak_instance_is_running (FlatpakInstance *self)
+{
+ FlatpakInstancePrivate *priv = flatpak_instance_get_instance_private (self);
+
+ if (priv->dir)
+ {
+ g_autofree char *ref_file = g_strconcat (priv->dir, "/.ref", NULL);
+ struct stat statbuf;
+ struct flock l = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+ glnx_autofd int lock_fd = open (ref_file, O_RDWR | O_CLOEXEC);
+ if (lock_fd != -1 &&
+ fstat (lock_fd, &statbuf) == 0 &&
+ /* Only gc if created at least 3 secs ago, to work around race mentioned in flatpak_run_allocate_id() */
+ statbuf.st_mtime + 3 < time (NULL) &&
+ fcntl (lock_fd, F_GETLK, &l) == 0 &&
+ l.l_type == F_UNLCK)
+ {
+ /* The instance is not used, remove it */
+ g_debug ("Cleaning up unused container id %s", priv->id);
+ glnx_shutil_rm_rf_at (-1, priv->dir, NULL, NULL);
+
+ g_clear_pointer (&priv->dir, g_free);
+ }
+ }
+
+ return priv->dir != NULL;
+}
+
diff --git a/common/flatpak-run-private.h b/common/flatpak-run-private.h
index 4fd762e6..90073c51 100644
--- a/common/flatpak-run-private.h
+++ b/common/flatpak-run-private.h
@@ -173,6 +173,4 @@ gboolean flatpak_run_app (const char *app_ref,
GCancellable *cancellable,
GError **error);
-void flatpak_run_gc_ids (void);
-
#endif /* __FLATPAK_RUN_H__ */
diff --git a/common/flatpak-run.c b/common/flatpak-run.c
index c7e477cc..6ab466af 100644
--- a/common/flatpak-run.c
+++ b/common/flatpak-run.c
@@ -1571,7 +1571,7 @@ flatpak_app_compute_permissions (GKeyFile *app_metadata,
return g_steal_pointer (&app_context);
}
-void
+static void
flatpak_run_gc_ids (void)
{
g_autofree char *base_dir = g_build_filename (g_get_user_runtime_dir (), ".flatpak", NULL);