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