common: Move flatpak_run_allocate_id() to flatpak-instance

This localizes knowledge of the internal structure of
$XDG_RUNTIME_DIR/.flatpak into the flatpak-instance module.

Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie
2021-02-15 12:58:02 +00:00
committed by Alexander Larsson
parent 495449daf6
commit 3393366877
3 changed files with 70 additions and 62 deletions

View File

@@ -25,6 +25,8 @@
FlatpakInstance *flatpak_instance_new (const char *dir);
FlatpakInstance *flatpak_instance_new_for_id (const char *id);
char *flatpak_instance_allocate_id (char **host_dir_out,
int *lock_fd_out);
void flatpak_instance_iterate_all_and_gc (GPtrArray *out_instances);

View File

@@ -420,6 +420,71 @@ flatpak_instance_new (const char *dir)
return self;
}
/*
* @host_dir_out: (not optional): used to return the directory on the host
* system representing this instance
* @lock_fd_out: (not optional): used to return a non-exclusive (read) lock
* on the lockdirectory on the host-file
*/
char *
flatpak_instance_allocate_id (char **host_dir_out,
int *lock_fd_out)
{
g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
g_autofree char *base_dir = g_build_filename (user_runtime_dir, ".flatpak", NULL);
int count;
g_return_val_if_fail (host_dir_out != NULL, NULL);
g_return_val_if_fail (*host_dir_out == NULL, NULL);
g_return_val_if_fail (lock_fd_out != NULL, NULL);
g_return_val_if_fail (*lock_fd_out == -1, NULL);
g_mkdir_with_parents (base_dir, 0755);
flatpak_instance_iterate_all_and_gc (NULL);
for (count = 0; count < 1000; count++)
{
g_autofree char *instance_id = NULL;
g_autofree char *instance_dir = NULL;
instance_id = g_strdup_printf ("%u", g_random_int ());
instance_dir = g_build_filename (base_dir, instance_id, NULL);
/* We use an atomic mkdir to ensure the instance id is unique */
if (mkdir (instance_dir, 0755) == 0)
{
g_autofree char *lock_file = g_build_filename (instance_dir, ".ref", NULL);
glnx_autofd int lock_fd = -1;
struct flock l = {
.l_type = F_RDLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0
};
/* Then we take a file lock inside the dir, hold that during
* setup and in bwrap. Anyone trying to clean up unused
* directories need to first verify that there is a .ref
* file and take a write lock on .ref to ensure its not in
* use. */
lock_fd = open (lock_file, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
/* There is a tiny race here between the open creating the file and the lock succeeding.
We work around that by only gc:ing "old" .ref files */
if (lock_fd != -1 && fcntl (lock_fd, F_SETLK, &l) == 0)
{
*lock_fd_out = glnx_steal_fd (&lock_fd);
g_debug ("Allocated instance id %s", instance_id);
*host_dir_out = g_steal_pointer (&instance_dir);
return g_steal_pointer (&instance_id);
}
}
}
return NULL;
}
FlatpakInstance *
flatpak_instance_new_for_id (const char *id)
{
@@ -462,7 +527,8 @@ flatpak_instance_iterate_all_and_gc (GPtrArray *out_instances)
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() */
/* Only gc if created at least 3 secs ago, to work around race mentioned in
* flatpak_instance_allocate_id() */
statbuf.st_mtime + 3 < time (NULL) &&
fcntl (lock_fd, F_GETLK, &l) == 0 &&
l.l_type == F_UNLCK)

View File

@@ -2034,64 +2034,6 @@ flatpak_app_compute_permissions (GKeyFile *app_metadata,
return g_steal_pointer (&app_context);
}
static void
flatpak_run_gc_ids (void)
{
flatpak_instance_iterate_all_and_gc (NULL);
}
static char *
flatpak_run_allocate_id (int *lock_fd_out)
{
g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
g_autofree char *base_dir = g_build_filename (user_runtime_dir, ".flatpak", NULL);
int count;
g_mkdir_with_parents (base_dir, 0755);
flatpak_run_gc_ids ();
for (count = 0; count < 1000; count++)
{
g_autofree char *instance_id = NULL;
g_autofree char *instance_dir = NULL;
instance_id = g_strdup_printf ("%u", g_random_int ());
instance_dir = g_build_filename (base_dir, instance_id, NULL);
/* We use an atomic mkdir to ensure the instance id is unique */
if (mkdir (instance_dir, 0755) == 0)
{
g_autofree char *lock_file = g_build_filename (instance_dir, ".ref", NULL);
glnx_autofd int lock_fd = -1;
struct flock l = {
.l_type = F_RDLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0
};
/* Then we take a file lock inside the dir, hold that during
* setup and in bwrap. Anyone trying to clean up unused
* directories need to first verify that there is a .ref
* file and take a write lock on .ref to ensure its not in
* use. */
lock_fd = open (lock_file, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
/* There is a tiny race here between the open creating the file and the lock succeeding.
We work around that by only gc:ing "old" .ref files */
if (lock_fd != -1 && fcntl (lock_fd, F_SETLK, &l) == 0)
{
*lock_fd_out = glnx_steal_fd (&lock_fd);
g_debug ("Allocated instance id %s", instance_id);
return g_steal_pointer (&instance_id);
}
}
}
return NULL;
}
#ifdef HAVE_DCONF
static void
@@ -2350,14 +2292,12 @@ flatpak_run_add_app_info_args (FlatpakBwrap *bwrap,
g_autofree char *instance_id_host_dir = NULL;
g_autofree char *instance_id_sandbox_dir = NULL;
g_autofree char *instance_id_lock_file = NULL;
g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
g_autofree char *arch = flatpak_decomposed_dup_arch (runtime_ref);
instance_id = flatpak_run_allocate_id (&lock_fd);
instance_id = flatpak_instance_allocate_id (&instance_id_host_dir, &lock_fd);
if (instance_id == NULL)
return flatpak_fail_error (error, FLATPAK_ERROR_SETUP_FAILED, _("Unable to allocate instance id"));
instance_id_host_dir = g_build_filename (user_runtime_dir, ".flatpak", instance_id, NULL);
instance_id_sandbox_dir = g_strdup_printf ("/run/user/%d/.flatpak/%s", getuid (), instance_id);
instance_id_lock_file = g_build_filename (instance_id_sandbox_dir, ".ref", NULL);