diff --git a/common/flatpak-instance-private.h b/common/flatpak-instance-private.h index 61a334a7..6f0b1dd8 100644 --- a/common/flatpak-instance-private.h +++ b/common/flatpak-instance-private.h @@ -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); diff --git a/common/flatpak-instance.c b/common/flatpak-instance.c index 997daeea..9203c0fd 100644 --- a/common/flatpak-instance.c +++ b/common/flatpak-instance.c @@ -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) diff --git a/common/flatpak-run.c b/common/flatpak-run.c index 1bbc3609..13da04b1 100644 --- a/common/flatpak-run.c +++ b/common/flatpak-run.c @@ -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);