Update Ukrainian translation

This commit is contained in:
Yuri Chornoivan
2018-03-18 11:17:50 +02:00
138 changed files with 22875 additions and 21333 deletions

25
.gitignore vendored
View File

@@ -36,10 +36,10 @@ flatpak-session-helper
xdg-document-portal
xdg-permission-store
flatpak-builder
testdb
*~
profile/flatpak.sh
flatpak-dbus.[ch]
flatpak-document-dbus.[ch]
flatpak-systemd-dbus.[ch]
flatpak-resources.[ch]
flatpak-dbus-proxy
@@ -68,11 +68,24 @@ Flatpak-1.0.*
/doc/flatpak-docs.xml
/doc/*.1
/doc/*.5
/test-doc-portal
/test-doc-portal.log
/test-doc-portal.trs
/testdb.log
/testdb.trs
/test-libglnx-errors
/test-libglnx-errors.log
/test-libglnx-errors.trs
/test-libglnx-fdio
/test-libglnx-fdio.log
/test-libglnx-fdio.trs
/test-libglnx-macros
/test-libglnx-macros.log
/test-libglnx-macros.trs
/test-libglnx-shutil
/test-libglnx-shutil.log
/test-libglnx-shutil.trs
/test-libglnx-xattrs
/test-libglnx-xattrs.log
/test-libglnx-xattrs.trs
/testlibrary
/testlibrary.log
/testlibrary.trs
/tests/test-keyring/.gpg-v21-migrated
/tests/test-keyring/private-keys-v1.d/
/tests/test-keyring/trustdb.gpg

84
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,84 @@
# Code of Conduct
## 1. Purpose
A primary goal of Flatpak is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.
We invite all those who participate in Flatpak to help us create safe and positive experiences for everyone.
## 2. Open Source Citizenship
A supplemental goal of this Code of Conduct is to increase open source citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community.
Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.
If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know.
## 3. Expected Behavior
The following behaviors are expected and requested of all community members:
* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community.
* Exercise consideration and respect in your speech and actions.
* Attempt collaboration before conflict.
* Refrain from demeaning, discriminatory, or harassing behavior and speech.
* Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential.
* Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations.
## 4. Unacceptable Behavior
The following behaviors are considered harassment and are unacceptable within our community:
* Violence, threats of violence or violent language directed against another person.
* Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language.
* Posting or displaying sexually explicit or violent material.
* Posting or threatening to post other peoples personally identifying information ("doxing").
* Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.
* Inappropriate photography or recording.
* Inappropriate physical contact. You should have someones consent before touching them.
* Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances.
* Deliberate intimidation, stalking or following (online or in person).
* Advocating for, or encouraging, any of the above behavior.
* Sustained disruption of community events, including talks and presentations.
## 5. Consequences of Unacceptable Behavior
Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated.
Anyone asked to stop unacceptable behavior is expected to comply immediately.
If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event).
## 6. Reporting Guidelines
If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. alexander.larsson@gmail.com.
Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.
## 7. Addressing Grievances
If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify Flatpak with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
## 8. Scope
We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venuesonline and in-personas well as in all one-on-one communications pertaining to community business.
This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members.
## 9. Contact info
alexander.larsson@gmail.com
## 10. License and attribution
This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy).
Retrieved on November 22, 2016 from [http://citizencodeofconduct.org/](http://citizencodeofconduct.org/)

View File

@@ -94,8 +94,6 @@ include lib/Makefile.am.inc
include session-helper/Makefile.am.inc
include system-helper/Makefile.am.inc
include dbus-proxy/Makefile.am.inc
include permission-store/Makefile.am.inc
include document-portal/Makefile.am.inc
include tests/Makefile.am.inc
if !WITH_SYSTEM_BWRAP

120
NEWS
View File

@@ -1,3 +1,123 @@
Major changes in 0.11.3
=======================
* Fix "open with" and flatpak run --file-forwarding crash
* Fix build with glibc 2.27
Major changes in 0.11.2
=======================
* Remove fuse dependency, since we don't ship document portal anymore
* Fix various issues with /home being a symlink to /var/home (atomic)
* Allow downgrades when using collection ids
* Search on all supported architectures
Major changes in 0.11.1
=======================
This release removes the document portal and the permission store as they
have been added to xdg-desktop-portal 0.10. Packagers need to update
these two in lock-step. Flatpak technically doesn't depend on
xdg-desktop-portal, but it is recommended that the flatpak package
depends on xdg-desktop-portal in some way, because most flatpaks will
want it.
* Remove document portal and permission store
* Add --socket=fallback-x11 permission
* Fix dbus proxy vulnerability in authentication phase
* Allow personality syscall in devel mode
* commit-from: Migrate static deltas with commit
* Add "network" storage type for installations
* Add flatpak info --show-permissions
* Add flatpak info --file-access
* search: Update appstream (if stale) before searching
* Make libflatpak work when /var/lib/flatpak is empty
* build-bundle: Add --from-commit option
* Allow appstream ids that don't end in .desktop
* Make permission handling ignore unknown permissions for forwards
compatibility
* Removed incorrect error message in update --appdata when there
was no updates
* Fix handling of abort in the duplicate remote prompt
* Fix division by zero in progress calculation
* Fix flatpak remote-info --show-metadata
* Fixed crash when installing some flatpak bundle files
* Fix installation of telegram
* remote-ls -u only considers app from the origin remote
* Fix assertion error in extra-data progress reporting
* Report nicer errors when trying to downgrade as non-root
* pulseaudio: Try to find pulseaudio socket better
* Fixed some warnings reported by coverity
* Cleaned up code by splitting up some large source files
Major changes in 0.10.2
=======================
* Flatpak now requires OSTree 2017.14
* flatpak update now updates from both system and user installations
by default.
* flatpak update is less noisy when updating appstream info.
* All the remote-* commands now by default automatically decide to use
--user or --system based on the given remote name.
* flatpak remote-ls with no remote lists the content of all remotes
* Fixed regression that made xdg-user-dirs and theme selection
for kde apps break.
* flatpak override with no argument now overrides globally, i.e. for
all apps.
* flatpak override now supports --nofilesystem properly. For example
flatpak override --nofilesystem=~/.ssh hides the ssh dir for all
apps, even those who have homedir access.
* flatpak install now takes a --reinstall argument which uninstalls
a previously installed version if necessary. This is very useful
when you want to install a new version from a different source.
* flatpak install now allows you to pass an absolute pathname as
remote name, which will create a temporary remote and install
from that. The remote will be removed when the app is uninstalled.
This is very useful during development and testing.
* Flatpak now creates CLI wrappers for all installed apps, so if you
add /var/lib/flatpak/exports/bin or ~/.local/share/flatpak/exports/bin
to your PATH you can easily start flatpak apps by their application id.
Major changes in 0.10.1
=======================
* New command "flatpak remote-info" shows information about applications
in a remote. In particular the --log operation shows the history and
can be used in combination with flatpak upate --commit=XYZ to roll
back to a previous version.
* New command "flatpak search" which allows you to search the appstream
data from the commandline.
* flatpak update now upates appstream data for all confured remotes, which
is important for search to work.
* Allow automatic installation of gtk themes matching the active theme.
* Handle the case when /etc/resolv.conf is a symlink
* /usr an /etc are now expose in /run/host in the app if the app has
full filesystem access.
* flatpak remote-add now works as a user when /var/lib/flatpak is empty,
allowing flatpak to work on stateless systems.
* Add support for flatpak build --log-session/system-bus, similar to
what flatpak run already does.
* flatpak build --readonly runs with the target directory (normally /app)
mounted read-only.
* Fall back to LD_LIBRARY_PATH if a runtime doesn't have /usr/bin/ldconfig.
* Updated the support for OCI remotes. This is work in progress and still
disabled by default though.
Major changes in 0.10
=====================
This is the first release in a new series of stable releases called
0.10.x. New features will be added to 0.11.x, and bugfixes will be
backported to 0.10.x. During the early phase of the 0.10.x series we
may also backport minor features, but we guarantee backwards
compatibility.
Changes since 0.9.99
* Added the flatpak config option which can set the language settings
* Fix issue where sometimes ld.so.conf were not generated
* /dev/mali0 is added to --device=dri
* Work around ostree static delta issues in some cases
Major changes in 0.9.99
=======================

View File

@@ -5,12 +5,23 @@
Flatpak is a system for building, distributing and running sandboxed
desktop applications on Linux.
See http://flatpak.org/ for more information.
See https://flatpak.org/ for more information.
Read documentation for the flatpak [commandline tools](http://flatpak.github.io/flatpak/flatpak-docs.html) and for the libflatpak [library API](http://flatpak.github.io/flatpak/reference/html/index.html).
Community discussion happens in [#flatpak on Freenode](ircs://chat.freenode.net/flatpak) and on [the mailing list](https://lists.freedesktop.org/mailman/listinfo/flatpak).
# INSTALLATION
Read documentation for the flatpak [commandline tools](http://docs.flatpak.org/en/latest/command-reference.html) and for the libflatpak [library API](http://flatpak.github.io/flatpak/reference/html/index.html).
# Contributing
Flatpak welcomes contributions from anyone! Here are some ways you can help:
* Fix [one of the issues](https://github.com/flatpak/flatpak/issues/) and submit a PR
* Update flatpak's translations and submit a PR
* Update flatpak's documentation, hosted at http://docs.flatpak.org and developed over in [flatpak-docs](https://github.com/flatpak/flatpak-docs)
* Find a bug and [submit a detailed report](https://github.com/flatpak/flatpak/issues/new) including your OS, flatpak version, and the steps to reproduce
* Add your favorite application to [Flathub](https://flathub.org) by writing a flatpak-builder manifest and [submitting it](https://github.com/flathub/flathub/wiki/App-Submission)
* Improve the Flatpak support in your favorite Linux distribution
# Hacking
Flatpak uses a traditional autoconf-style build mechanism. To build just do
```
./configure [args]
@@ -31,10 +42,8 @@ has a recent enough version of Bubblewrap already, you can use
Bubblewrap can run in two modes, either using unprivileged user
namespaces or setuid mode. This requires that the kernel supports this,
which some distributions disable. For instance, Arch completely
disables user namespaces, while Debian supports unprivileged user
namespaces, but only if you turn on the
`kernel.unprivileged_userns_clone` sysctl.
which some distributions disable. For instance, Debian and Arch
([linux](https://www.archlinux.org/packages/?name=linux) kernel v4.14.5 or later), support user namespaces with the `kernel.unprivileged_userns_clone` sysctl enabled.
If unprivileged user namespaces are not available, then Bubblewrap must
be built as setuid root. This is believed to be safe, as it is

View File

@@ -13,6 +13,7 @@ flatpak_SOURCES = \
app/flatpak-builtins-delete-remote.c \
app/flatpak-builtins-list-remotes.c \
app/flatpak-builtins-ls-remote.c \
app/flatpak-builtins-info-remote.c \
app/flatpak-builtins-install.c \
app/flatpak-builtins-override.c \
app/flatpak-builtins-make-current.c \
@@ -37,8 +38,10 @@ flatpak_SOURCES = \
app/flatpak-builtins-document-unexport.c \
app/flatpak-builtins-document-info.c \
app/flatpak-builtins-document-list.c \
app/flatpak-builtins-search.c \
$(NULL)
flatpak_LDADD = $(AM_LDADD) $(BASE_LIBS) $(OSTREE_LIBS) $(SOUP_LIBS) $(JSON_LIBS) libglnx.la libflatpak-common.la
flatpak_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) \
flatpak_LDADD = $(AM_LDADD) $(BASE_LIBS) $(OSTREE_LIBS) $(SOUP_LIBS) $(JSON_LIBS) $(APPSTREAM_GLIB_LIBS) \
libglnx.la libflatpak-common.la
flatpak_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) $(APPSTREAM_GLIB_CFLAGS) \
-DLOCALEDIR=\"$(localedir)\"

View File

@@ -89,9 +89,16 @@ static GOptionEntry common_options[] = {
static GKeyFile *
get_config_from_opts (FlatpakDir *dir, const char *remote_name, gboolean *changed)
{
GKeyFile *config = ostree_repo_copy_config (flatpak_dir_get_repo (dir));
OstreeRepo *repo;
GKeyFile *config;
g_autofree char *group = g_strdup_printf ("remote \"%s\"", remote_name);
repo = flatpak_dir_get_repo (dir);
if (repo == NULL)
config = g_key_file_new ();
else
config = ostree_repo_copy_config (repo);
if (opt_no_gpg_verify)
{
g_key_file_set_boolean (config, group, "gpg-verify", FALSE);
@@ -298,7 +305,8 @@ flatpak_builtin_add_remote (int argc, char **argv,
GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
g_autoptr(GFile) file = NULL;
g_auto(GStrv) remotes = NULL;
g_autofree char *remote_url = NULL;
@@ -314,9 +322,13 @@ flatpak_builtin_add_remote (int argc, char **argv,
g_option_context_add_main_entries (context, common_options, NULL);
if (!flatpak_option_context_parse (context, add_options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, add_options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR | FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO,
&dirs, cancellable, error))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
if (argc < 2)
return usage_error (context, _("NAME must be specified"), error);
@@ -371,8 +383,8 @@ flatpak_builtin_add_remote (int argc, char **argv,
if (opt_oci && g_getenv ("FLATPAK_ENABLE_EXPERIMENTAL_OCI") == NULL)
return flatpak_fail (error, "flatpak remote-add --oci is currently unsupported and experimental, enable it by setting the FLATPAK_ENABLE_EXPERIMENTAL_OCI env var");
/* Default to gpg verify */
if (!opt_no_gpg_verify)
/* Default to gpg verify, except for --oci */
if (!opt_no_gpg_verify && !opt_oci)
opt_do_gpg_verify = TRUE;
config = get_config_from_opts (dir, remote_name, &changed);
@@ -416,11 +428,11 @@ gboolean
flatpak_complete_add_remote (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
context = g_option_context_new ("");
g_option_context_add_main_entries (context, common_options, NULL);
if (!flatpak_option_context_parse (context, add_options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, add_options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR, NULL, NULL, NULL))
return FALSE;
switch (completion->argc)
@@ -442,7 +454,8 @@ gboolean
flatpak_builtin_modify_remote (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
g_autoptr(FlatpakDir) preferred_dir = NULL;
g_autoptr(GKeyFile) config = NULL;
g_autoptr(GBytes) gpg_data = NULL;
const char *remote_name;
@@ -453,7 +466,8 @@ flatpak_builtin_modify_remote (int argc, char **argv, GCancellable *cancellable,
g_option_context_add_main_entries (context, common_options, NULL);
if (!flatpak_option_context_parse (context, modify_options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, modify_options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, cancellable, error))
return FALSE;
if (argc < 2)
@@ -461,26 +475,26 @@ flatpak_builtin_modify_remote (int argc, char **argv, GCancellable *cancellable,
remote_name = argv[1];
if (!ostree_repo_remote_get_url (flatpak_dir_get_repo (dir), remote_name, NULL, NULL))
return flatpak_fail (error, _("No remote %s"), remote_name);
if (!flatpak_resolve_duplicate_remotes (dirs, remote_name, &preferred_dir, cancellable, error))
return FALSE;
if (opt_update_metadata)
{
g_autoptr(GError) local_error = NULL;
g_print (_("Updating extra metadata from remote summary for %s\n"), remote_name);
if (!flatpak_dir_update_remote_configuration (dir, remote_name, cancellable, &local_error))
if (!flatpak_dir_update_remote_configuration (preferred_dir, remote_name, cancellable, &local_error))
{
g_printerr (_("Error updating extra metadata for '%s': %s\n"), remote_name, local_error->message);
return flatpak_fail (error, _("Could not update extra metadata for %s"), remote_name);
}
/* Reload changed configuration */
if (!flatpak_dir_recreate_repo (dir, cancellable, error))
if (!flatpak_dir_recreate_repo (preferred_dir, cancellable, error))
return FALSE;
}
config = get_config_from_opts (dir, remote_name, &changed);
config = get_config_from_opts (preferred_dir, remote_name, &changed);
if (opt_gpg_import != NULL)
{
@@ -493,19 +507,20 @@ flatpak_builtin_modify_remote (int argc, char **argv, GCancellable *cancellable,
if (!changed)
return TRUE;
return flatpak_dir_modify_remote (dir, remote_name, config, gpg_data, cancellable, error);
return flatpak_dir_modify_remote (preferred_dir, remote_name, config, gpg_data, cancellable, error);
}
gboolean
flatpak_complete_modify_remote (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
int i;
context = g_option_context_new ("");
g_option_context_add_main_entries (context, common_options, NULL);
if (!flatpak_option_context_parse (context, modify_options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, modify_options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, NULL, NULL))
return FALSE;
switch (completion->argc)
@@ -517,13 +532,16 @@ flatpak_complete_modify_remote (FlatpakCompletion *completion)
flatpak_complete_options (completion, modify_options);
flatpak_complete_options (completion, user_entries);
{
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (i = 0; remotes[i] != NULL; i++)
flatpak_complete_word (completion, "%s ", remotes[i]);
}
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
int j;
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (j = 0; remotes[j] != NULL; j++)
flatpak_complete_word (completion, "%s ", remotes[j]);
}
break;
}

View File

@@ -50,6 +50,7 @@ static char **opt_gpg_file;
static gboolean opt_oci = FALSE;
static char **opt_gpg_key_ids;
static char *opt_gpg_homedir;
static char *opt_from_commit;
static GOptionEntry options[] = {
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, N_("Export runtime instead of app"), NULL },
@@ -60,7 +61,7 @@ static GOptionEntry options[] = {
{ "oci", 0, 0, G_OPTION_ARG_NONE, &opt_oci, N_("Export oci image instead of flatpak bundle"), NULL },
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_key_ids, N_("GPG Key ID to sign the OCI image with"), N_("KEY-ID") },
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, N_("GPG Homedir to use when looking for keyrings"), N_("HOMEDIR") },
{ "from-commit", 0, 0, G_OPTION_ARG_STRING, &opt_from_commit, N_("OSTree commit to create a delta bundle from"), N_("COMMIT") },
{ NULL }
};
@@ -109,6 +110,7 @@ read_gpg_data (GCancellable *cancellable,
static gboolean
build_bundle (OstreeRepo *repo, GFile *file,
const char *name, const char *full_branch,
const char *from_commit,
GCancellable *cancellable, GError **error)
{
GVariantBuilder metadata_builder;
@@ -269,7 +271,7 @@ build_bundle (OstreeRepo *repo, GFile *file,
if (!ostree_repo_static_delta_generate (repo,
OSTREE_STATIC_DELTA_GENERATE_OPT_LOWLATENCY,
/* from */ NULL,
from_commit,
commit_checksum,
metadata,
params,
@@ -420,26 +422,6 @@ build_oci (OstreeRepo *repo, GFile *dir,
flatpak_oci_export_annotations (manifest->annotations, manifest_desc->annotations);
if (opt_gpg_key_ids)
{
g_autoptr(FlatpakOciSignature) sig = flatpak_oci_signature_new (manifest_desc->digest, ref);
g_autoptr(GBytes) sig_bytes = flatpak_json_to_bytes (FLATPAK_JSON (sig));
g_autoptr(GBytes) res = NULL;
g_autofree char *signature_digest = NULL;
res = flatpak_oci_sign_data (sig_bytes, (const char **)opt_gpg_key_ids, opt_gpg_homedir, error);
if (res == NULL)
return FALSE;
signature_digest = flatpak_oci_registry_store_blob (registry, res, cancellable, error);
if (signature_digest == NULL)
return FALSE;
g_hash_table_replace (manifest_desc->annotations,
g_strdup ("org.flatpak.signature-digest"),
g_strdup (signature_digest));
}
index = flatpak_oci_registry_load_index (registry, NULL, NULL, NULL, NULL);
if (index == NULL)
index = flatpak_oci_index_new ();
@@ -521,7 +503,7 @@ flatpak_builtin_build_bundle (int argc, char **argv, GCancellable *cancellable,
}
else
{
if (!build_bundle (repo, file, name, full_branch, cancellable, error))
if (!build_bundle (repo, file, name, full_branch, opt_from_commit, cancellable, error))
return FALSE;
}

View File

@@ -57,6 +57,156 @@ static GOptionEntry options[] = {
{ NULL }
};
#define OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "(uayttay)"
#define OSTREE_STATIC_DELTA_FALLBACK_FORMAT "(yaytt)"
#define OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT "(a{sv}tayay" OSTREE_COMMIT_GVARIANT_STRING "aya" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")"
static char *
_ostree_get_relative_static_delta_path (const char *from,
const char *to,
const char *target)
{
guint8 csum_to[OSTREE_SHA256_DIGEST_LEN];
char to_b64[44];
guint8 csum_to_copy[OSTREE_SHA256_DIGEST_LEN];
GString *ret = g_string_new ("deltas/");
ostree_checksum_inplace_to_bytes (to, csum_to);
ostree_checksum_b64_inplace_from_bytes (csum_to, to_b64);
ostree_checksum_b64_inplace_to_bytes (to_b64, csum_to_copy);
g_assert (memcmp (csum_to, csum_to_copy, OSTREE_SHA256_DIGEST_LEN) == 0);
if (from != NULL)
{
guint8 csum_from[OSTREE_SHA256_DIGEST_LEN];
char from_b64[44];
ostree_checksum_inplace_to_bytes (from, csum_from);
ostree_checksum_b64_inplace_from_bytes (csum_from, from_b64);
g_string_append_c (ret, from_b64[0]);
g_string_append_c (ret, from_b64[1]);
g_string_append_c (ret, '/');
g_string_append (ret, from_b64 + 2);
g_string_append_c (ret, '-');
}
g_string_append_c (ret, to_b64[0]);
g_string_append_c (ret, to_b64[1]);
if (from == NULL)
g_string_append_c (ret, '/');
g_string_append (ret, to_b64 + 2);
if (target != NULL)
{
g_string_append_c (ret, '/');
g_string_append (ret, target);
}
return g_string_free (ret, FALSE);
}
static GVariant *
new_bytearray (const guchar *data,
gsize len)
{
gpointer data_copy = g_memdup (data, len);
GVariant *ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy,
len, FALSE, g_free, data_copy);
return ret;
}
static gboolean
rewrite_delta (OstreeRepo *src_repo,
const char *src_commit,
OstreeRepo *dst_repo,
const char *dst_commit,
GVariant *dst_commitv,
const char *from,
GError **error)
{
g_autoptr(GFile) src_delta_file = NULL;
g_autoptr(GFile) dst_delta_file = NULL;
g_autofree char *src_detached_key = _ostree_get_relative_static_delta_path (from, src_commit, "commitmeta");
g_autofree char *dst_detached_key = _ostree_get_relative_static_delta_path (from, dst_commit, "commitmeta");
g_autofree char *src_delta_dir = _ostree_get_relative_static_delta_path (from, src_commit, NULL);
g_autofree char *dst_delta_dir = _ostree_get_relative_static_delta_path (from, dst_commit, NULL);
g_autofree char *src_superblock_path = _ostree_get_relative_static_delta_path (from, src_commit, "superblock");
g_autofree char *dst_superblock_path = _ostree_get_relative_static_delta_path (from, dst_commit, "superblock");
GMappedFile *mfile = NULL;
g_auto(GVariantBuilder) superblock_builder = FLATPAK_VARIANT_BUILDER_INITIALIZER;
g_autoptr(GVariant) src_superblock = NULL;
g_autoptr(GVariant) dst_superblock = NULL;
g_autoptr(GBytes) bytes = NULL;
g_autoptr(GVariant) dst_detached = NULL;
g_autoptr(GVariant) src_metadata = NULL;
g_autoptr(GVariant) src_recurse = NULL;
g_autoptr(GVariant) src_parts = NULL;
g_auto(GVariantDict) dst_metadata_dict = FLATPAK_VARIANT_DICT_INITIALIZER;
int i;
src_delta_file = g_file_resolve_relative_path (ostree_repo_get_path (src_repo), src_superblock_path);
mfile = g_mapped_file_new (flatpak_file_get_path_cached (src_delta_file), FALSE, NULL);
if (mfile == NULL)
return TRUE; /* No superblock, not an error */
bytes = g_mapped_file_get_bytes (mfile);
g_mapped_file_unref (mfile);
src_superblock = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), bytes, FALSE));
src_metadata = g_variant_get_child_value (src_superblock, 0);
src_recurse = g_variant_get_child_value (src_superblock, 5);
src_parts = g_variant_get_child_value (src_superblock, 6);
if (g_variant_n_children (src_recurse) != 0)
return flatpak_fail (error, "Recursive deltas not supported, ignoring");
g_variant_builder_init (&superblock_builder, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT));
g_variant_dict_init (&dst_metadata_dict, src_metadata);
g_variant_dict_remove (&dst_metadata_dict, src_detached_key);
if (ostree_repo_read_commit_detached_metadata (dst_repo, dst_commit, &dst_detached, NULL, NULL))
g_variant_dict_insert_value (&dst_metadata_dict, dst_detached_key, dst_detached);
g_variant_builder_add_value (&superblock_builder, g_variant_dict_end (&dst_metadata_dict));
g_variant_builder_add_value (&superblock_builder, g_variant_get_child_value (src_superblock, 1)); /* timestamp */
g_variant_builder_add_value (&superblock_builder, from ? ostree_checksum_to_bytes_v (from) : new_bytearray ((guchar *)"", 0));
g_variant_builder_add_value (&superblock_builder, ostree_checksum_to_bytes_v (dst_commit));
g_variant_builder_add_value (&superblock_builder, dst_commitv);
g_variant_builder_add_value (&superblock_builder, src_recurse);
g_variant_builder_add_value (&superblock_builder, src_parts);
g_variant_builder_add_value (&superblock_builder, g_variant_get_child_value (src_superblock, 7)); /* fallback */
dst_superblock = g_variant_ref_sink (g_variant_builder_end (&superblock_builder));
if (!glnx_shutil_mkdir_p_at (ostree_repo_get_dfd (dst_repo), dst_delta_dir, 0755, NULL, error))
return FALSE;
for (i = 0; i < g_variant_n_children (src_parts); i++)
{
g_autofree char *src_part_path = g_strdup_printf ("%s/%d", src_delta_dir, i);
g_autofree char *dst_part_path = g_strdup_printf ("%s/%d", dst_delta_dir, i);
if (!glnx_file_copy_at (ostree_repo_get_dfd (src_repo),
src_part_path,
NULL,
ostree_repo_get_dfd (dst_repo),
dst_part_path,
GLNX_FILE_COPY_OVERWRITE | GLNX_FILE_COPY_NOXATTRS,
NULL, error))
return FALSE;
}
dst_delta_file = g_file_resolve_relative_path (ostree_repo_get_path (dst_repo), dst_superblock_path);
if (!flatpak_variant_save (dst_delta_file, dst_superblock, NULL, error))
return FALSE;
return TRUE;
}
gboolean
flatpak_builtin_build_commit_from (int argc, char **argv, GCancellable *cancellable, GError **error)
{
@@ -224,6 +374,7 @@ flatpak_builtin_build_commit_from (int argc, char **argv, GCancellable *cancella
g_autoptr(GFile) dst_parent_root = NULL;
g_autoptr(GFile) src_ref_root = NULL;
g_autoptr(GVariant) src_commitv = NULL;
g_autoptr(GVariant) dst_commitv = NULL;
g_autoptr(OstreeMutableTree) mtree = NULL;
g_autoptr(GFile) dst_root = NULL;
g_autoptr(GVariant) commitv_metadata = NULL;
@@ -319,6 +470,9 @@ flatpak_builtin_build_commit_from (int argc, char **argv, GCancellable *cancella
g_print ("%s: %s\n", dst_ref, commit_checksum);
if (!ostree_repo_load_commit (dst_repo, commit_checksum, &dst_commitv, NULL, error))
return FALSE;
/* This doesn't copy the detached metadata. I'm not sure if this is a problem.
* The main thing there is commit signatures, and we can't copy those, as the commit hash changes.
*/
@@ -357,6 +511,23 @@ flatpak_builtin_build_commit_from (int argc, char **argv, GCancellable *cancella
{
ostree_repo_transaction_set_ref (dst_repo, NULL, dst_ref, commit_checksum);
}
/* Copy + Rewrite any deltas */
{
const char *from[2];
gsize j, n_from = 0;
if (dst_parent != NULL)
from[n_from++] = dst_parent;
from[n_from++] = NULL;
for (j = 0; j < n_from; j++)
{
g_autoptr(GError) local_error = NULL;
if (!rewrite_delta (src_repo, resolved_ref, dst_repo, commit_checksum, dst_commitv, from[j], &local_error))
g_debug ("Failed to copy delta: %s", local_error->message);
}
}
}
if (!ostree_repo_commit_transaction (dst_repo, NULL, cancellable, error))

View File

@@ -230,7 +230,7 @@ add_file_to_mtree (GFile *file,
g_file_info_set_file_type (file_info, G_FILE_TYPE_REGULAR);
g_file_info_set_attribute_uint32 (file_info, "unix::uid", 0);
g_file_info_set_attribute_uint32 (file_info, "unix::gid", 0);
g_file_info_set_attribute_uint32 (file_info, "unix::mode", 0100744);
g_file_info_set_attribute_uint32 (file_info, "unix::mode", 0100644);
raw_input = (GInputStream *) g_file_read (file, cancellable, error);
if (raw_input == NULL)
@@ -822,6 +822,12 @@ flatpak_builtin_build_export (int argc, char **argv, GCancellable *cancellable,
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
goto out;
/* This is useful only if the target is a "bare" rep, but this happens
in flatpak-builder when commiting to the cache repo. For other repos
this is a no-op */
if (!ostree_repo_scan_hardlinks (repo, cancellable, error))
goto out;
mtree = ostree_mutable_tree_new ();
if (!flatpak_mtree_create_root (repo, mtree, cancellable, error))
@@ -891,7 +897,7 @@ flatpak_builtin_build_export (int argc, char **argv, GCancellable *cancellable,
metadata_dict_v = g_variant_ref_sink (g_variant_dict_end (&metadata_dict));
/* required for the metadata and the AppStream commits */
/* The timestamp is used for the commit metadata and AppStream data */
if (opt_timestamp != NULL)
{
if (!g_time_val_from_iso8601 (opt_timestamp, &ts))
@@ -954,7 +960,7 @@ flatpak_builtin_build_export (int argc, char **argv, GCancellable *cancellable,
if (opt_update_appstream &&
!flatpak_repo_generate_appstream (repo, (const char **) opt_gpg_key_ids, opt_gpg_homedir,
ts.tv_sec, cancellable, error))
(opt_timestamp != NULL) ? ts.tv_sec : 0, cancellable, error))
return FALSE;
if (!opt_no_update_summary &&

View File

@@ -95,7 +95,7 @@ import_oci (OstreeRepo *repo, GFile *file,
oci_digest = desc->parent.digest;
versioned = flatpak_oci_registry_load_versioned (registry,
versioned = flatpak_oci_registry_load_versioned (registry, NULL,
oci_digest, NULL,
cancellable, error);
if (versioned == NULL)
@@ -115,8 +115,8 @@ import_oci (OstreeRepo *repo, GFile *file,
return NULL;
}
commit_checksum = flatpak_pull_from_oci (repo, registry, oci_digest, manifest,
NULL, target_ref, NULL, NULL, NULL, cancellable, error);
commit_checksum = flatpak_pull_from_oci (repo, registry, NULL, oci_digest, manifest,
NULL, target_ref, NULL, NULL, cancellable, error);
if (commit_checksum == NULL)
return NULL;

View File

@@ -381,7 +381,6 @@ flatpak_complete_build_init (FlatpakCompletion *completion)
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) user_dir = NULL;
g_autoptr(FlatpakDir) system_dir = NULL;
g_autoptr(GError) error = NULL;
int i;
context = g_option_context_new ("");
@@ -407,6 +406,7 @@ flatpak_complete_build_init (FlatpakCompletion *completion)
case 4: /* SDK */
user_dir = flatpak_dir_get_user ();
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (user_dir, NULL, NULL, opt_arch,
FLATPAK_KINDS_RUNTIME, &error);
if (refs == NULL)
@@ -421,6 +421,7 @@ flatpak_complete_build_init (FlatpakCompletion *completion)
system_dir = flatpak_dir_get_system_default ();
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (system_dir, NULL, NULL, opt_arch,
FLATPAK_KINDS_RUNTIME, &error);
if (refs == NULL)
@@ -438,6 +439,7 @@ flatpak_complete_build_init (FlatpakCompletion *completion)
case 5: /* BRANCH */
user_dir = flatpak_dir_get_user ();
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (user_dir, completion->argv[3], NULL, opt_arch,
FLATPAK_KINDS_RUNTIME, &error);
if (refs == NULL)
@@ -452,6 +454,7 @@ flatpak_complete_build_init (FlatpakCompletion *completion)
system_dir = flatpak_dir_get_system_default ();
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (system_dir, completion->argv[3], NULL, opt_arch,
FLATPAK_KINDS_RUNTIME, &error);
if (refs == NULL)

View File

@@ -39,40 +39,26 @@ static char *opt_build_dir;
static char **opt_bind_mounts;
static char *opt_sdk_dir;
static char *opt_metadata;
static gboolean opt_log_session_bus;
static gboolean opt_log_system_bus;
static gboolean opt_die_with_parent;
static gboolean opt_with_appdir;
static gboolean opt_readonly;
static GOptionEntry options[] = {
{ "runtime", 'r', 0, G_OPTION_ARG_NONE, &opt_runtime, N_("Use Platform runtime rather than Sdk"), NULL },
{ "readonly", 0, 0, G_OPTION_ARG_NONE, &opt_readonly, N_("Make destination readonly"), NULL },
{ "bind-mount", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_mounts, N_("Add bind mount"), N_("DEST=SRC") },
{ "build-dir", 0, 0, G_OPTION_ARG_STRING, &opt_build_dir, N_("Start build in this directory"), N_("DIR") },
{ "sdk-dir", 0, 0, G_OPTION_ARG_STRING, &opt_sdk_dir, N_("Where to look for custom sdk dir (defaults to 'usr')"), N_("DIR") },
{ "metadata", 0, 0, G_OPTION_ARG_STRING, &opt_metadata, N_("Use alternative file for the metadata"), N_("FILE") },
{ "die-with-parent", 'p', 0, G_OPTION_ARG_NONE, &opt_die_with_parent, N_("Kill processes when the parent process dies"), NULL },
{ "with-appdir", 0, 0, G_OPTION_ARG_NONE, &opt_with_appdir, N_("Export application homedir directory to build"), NULL },
{ "log-session-bus", 0, 0, G_OPTION_ARG_NONE, &opt_log_session_bus, N_("Log session bus calls"), NULL },
{ "log-system-bus", 0, 0, G_OPTION_ARG_NONE, &opt_log_system_bus, N_("Log system bus calls"), NULL },
{ NULL }
};
static void
add_args (GPtrArray *argv_array, ...)
{
va_list args;
const gchar *arg;
va_start (args, argv_array);
while ((arg = va_arg (args, const gchar *)))
g_ptr_array_add (argv_array, g_strdup (arg));
va_end (args);
}
static void
clear_fd (gpointer data)
{
int *fd_p = data;
if (fd_p != NULL && *fd_p != -1)
close (*fd_p);
}
/* Unset FD_CLOEXEC on the array of fds passed in @user_data */
static void
child_setup (gpointer user_data)
@@ -97,6 +83,8 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
g_autoptr(GVariant) runtime_deploy_data = NULL;
g_autoptr(FlatpakDeploy) extensionof_deploy = NULL;
g_autoptr(GFile) var = NULL;
g_autoptr(GFile) var_tmp = NULL;
g_autoptr(GFile) var_lib = NULL;
g_autoptr(GFile) usr = NULL;
g_autoptr(GFile) res_deploy = NULL;
g_autoptr(GFile) res_files = NULL;
@@ -112,9 +100,8 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
g_autofree char *extension_tmpfs_point = NULL;
g_autoptr(GKeyFile) metakey = NULL;
g_autoptr(GKeyFile) runtime_metakey = NULL;
g_autoptr(GPtrArray) argv_array = NULL;
g_autoptr(GArray) fd_array = NULL;
g_auto(GStrv) envp = NULL;
g_autoptr(FlatpakBwrap) bwrap = NULL;
g_auto(GStrv) minimal_envp = NULL;
gsize metadata_size;
const char *directory = NULL;
const char *command = "/bin/sh";
@@ -244,7 +231,11 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
}
var = g_file_get_child (res_deploy, "var");
if (!flatpak_mkdir_p (var, cancellable, error))
var_tmp = g_file_get_child (var, "tmp");
if (!flatpak_mkdir_p (var_tmp, cancellable, error))
return FALSE;
var_lib = g_file_get_child (var, "lib");
if (!flatpak_mkdir_p (var_lib, cancellable, error))
return FALSE;
res_files = g_file_get_child (res_deploy, "files");
@@ -319,10 +310,9 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
extension_point = g_build_filename (bare_extension_point, x_subdir_suffix, NULL);
}
argv_array = g_ptr_array_new_with_free_func (g_free);
fd_array = g_array_new (FALSE, TRUE, sizeof (int));
g_array_set_clear_func (fd_array, clear_fd);
g_ptr_array_add (argv_array, g_strdup (flatpak_get_bwrap ()));
minimal_envp = flatpak_run_get_minimal_env (TRUE, FALSE);
bwrap = flatpak_bwrap_new (minimal_envp);
flatpak_bwrap_add_args (bwrap, flatpak_get_bwrap (), NULL);
run_flags =
FLATPAK_RUN_FLAG_DEVEL | FLATPAK_RUN_FLAG_NO_SESSION_HELPER |
@@ -339,40 +329,46 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
if (!flatpak_context_get_needs_system_bus_proxy (arg_context))
run_flags |= FLATPAK_RUN_FLAG_NO_SYSTEM_BUS_PROXY;
if (opt_log_session_bus)
run_flags |= FLATPAK_RUN_FLAG_LOG_SESSION_BUS;
if (opt_log_system_bus)
run_flags |= FLATPAK_RUN_FLAG_LOG_SYSTEM_BUS;
/* Never set up an a11y bus for builds */
run_flags |= FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY;
if (!flatpak_run_setup_base_argv (argv_array, fd_array, runtime_files, app_id_dir, runtime_ref_parts[2],
if (!flatpak_run_setup_base_argv (bwrap, runtime_files, app_id_dir, runtime_ref_parts[2],
run_flags, error))
return FALSE;
add_args (argv_array,
custom_usr ? "--bind" : "--ro-bind", flatpak_file_get_path_cached (runtime_files), "/usr",
NULL);
flatpak_bwrap_add_args (bwrap,
(custom_usr && !opt_readonly) ? "--bind" : "--ro-bind", flatpak_file_get_path_cached (runtime_files), "/usr",
NULL);
if (!custom_usr)
add_args (argv_array,
"--lock-file", "/usr/.ref",
NULL);
flatpak_bwrap_add_args (bwrap,
"--lock-file", "/usr/.ref",
NULL);
if (app_files)
add_args (argv_array,
app_files_ro ? "--ro-bind" : "--bind", flatpak_file_get_path_cached (app_files), "/app",
NULL);
flatpak_bwrap_add_args (bwrap,
(app_files_ro || opt_readonly) ? "--ro-bind" : "--bind", flatpak_file_get_path_cached (app_files), "/app",
NULL);
else
add_args (argv_array,
"--dir", "/app",
NULL);
flatpak_bwrap_add_args (bwrap,
"--dir", "/app",
NULL);
if (extension_tmpfs_point)
add_args (argv_array,
"--tmpfs", extension_tmpfs_point,
NULL);
flatpak_bwrap_add_args (bwrap,
"--tmpfs", extension_tmpfs_point,
NULL);
if (extension_point)
add_args (argv_array,
"--bind", flatpak_file_get_path_cached (res_files), extension_point,
NULL);
flatpak_bwrap_add_args (bwrap,
"--bind", flatpak_file_get_path_cached (res_files), extension_point,
NULL);
if (extension_point)
dest = extension_point;
@@ -381,12 +377,24 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
else
dest = g_strdup ("/usr");
add_args (argv_array,
flatpak_bwrap_add_args (bwrap,
"--setenv", "FLATPAK_DEST", dest,
"--setenv", "FLATPAK_ID", id,
"--setenv", "FLATPAK_ARCH", runtime_ref_parts[2],
NULL);
/* Persist some stuff in /var. We can't persist everything because that breaks /var things
* from the host to work. For example the /home -> /var/home on atomic.
* The interesting things to contain during the build is /var/tmp (for tempfiles shared during builds)
* and things like /var/lib/rpm, if the installation uses packages.
*/
flatpak_bwrap_add_args (bwrap,
"--bind", flatpak_file_get_path_cached (var_lib), "/var/lib",
NULL);
flatpak_bwrap_add_args (bwrap,
"--bind", flatpak_file_get_path_cached (var_tmp), "/var/tmp",
NULL);
app_context = flatpak_app_compute_permissions (metakey,
runtime_metakey,
error);
@@ -396,15 +404,13 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
flatpak_context_allow_host_fs (app_context);
flatpak_context_merge (app_context, arg_context);
envp = flatpak_run_get_minimal_env (TRUE, FALSE);
envp = flatpak_run_apply_env_vars (envp, app_context);
flatpak_run_apply_env_vars (bwrap, app_context);
if (!custom_usr && !(is_extension && !is_app_extension) &&
!flatpak_run_add_extension_args (argv_array, fd_array, &envp, runtime_metakey, runtime_ref, FALSE, &runtime_extensions, cancellable, error))
!flatpak_run_add_extension_args (bwrap, runtime_metakey, runtime_ref, FALSE, &runtime_extensions, cancellable, error))
return FALSE;
if (!flatpak_run_add_app_info_args (argv_array,
fd_array,
if (!flatpak_run_add_app_info_args (bwrap,
app_files, NULL, NULL,
runtime_files, runtime_deploy_data, runtime_extensions,
id, NULL,
@@ -414,15 +420,10 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
error))
return FALSE;
if (!flatpak_run_add_environment_args (argv_array, fd_array, &envp, app_info_path, run_flags, id,
if (!flatpak_run_add_environment_args (bwrap, app_info_path, run_flags, id,
app_context, app_id_dir, NULL, cancellable, error))
return FALSE;
/* After setup_base to avoid conflicts with /var symlinks */
add_args (argv_array,
"--bind", flatpak_file_get_path_cached (var), "/var",
NULL);
for (i = 0; opt_bind_mounts != NULL && opt_bind_mounts[i] != NULL; i++)
{
char *split = strchr (opt_bind_mounts[i], '=');
@@ -434,27 +435,28 @@ flatpak_builtin_build (int argc, char **argv, GCancellable *cancellable, GError
}
*split++ = 0;
add_args (argv_array,
"--bind", split, opt_bind_mounts[i],
NULL);
flatpak_bwrap_add_args (bwrap,
"--bind", split, opt_bind_mounts[i],
NULL);
}
if (opt_build_dir != NULL)
{
add_args (argv_array,
"--chdir", opt_build_dir,
NULL);
flatpak_bwrap_add_args (bwrap,
"--chdir", opt_build_dir,
NULL);
}
g_ptr_array_add (argv_array, g_strdup (command));
for (i = 2; i < rest_argc; i++)
g_ptr_array_add (argv_array, g_strdup (argv[rest_argv_start + i]));
flatpak_bwrap_add_args (bwrap, command, NULL);
flatpak_bwrap_append_argsv (bwrap,
&argv[rest_argv_start + 2],
rest_argc - 2);
g_ptr_array_add (argv_array, NULL);
g_ptr_array_add (bwrap->argv, NULL);
/* Ensure we unset O_CLOEXEC */
child_setup (fd_array);
if (execvpe (flatpak_get_bwrap (), (char **) argv_array->pdata, envp) == -1)
child_setup (bwrap->fds);
if (execvpe (flatpak_get_bwrap (), (char **) bwrap->argv->pdata, bwrap->envp) == -1)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
_("Unable to start app"));

View File

@@ -198,14 +198,19 @@ gboolean
flatpak_builtin_config (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
context = g_option_context_new (_("[KEY [VALUE]] - Manage configuration"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR,
&dirs, cancellable, error))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
if (opt_get)
return get_config (argc, argv, dir, cancellable, error);
else if (opt_set)
@@ -215,7 +220,7 @@ flatpak_builtin_config (int argc, char **argv, GCancellable *cancellable, GError
else if (opt_list)
return list_config (argc, argv, dir, cancellable, error);
else
return flatpak_fail (error, _("Must specify one on --list, --get, --set or --unset"));
return flatpak_fail (error, _("Must specify one of --list, --get, --set or --unset"));
return TRUE;
}
@@ -224,16 +229,16 @@ gboolean
flatpak_complete_config (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR, NULL, NULL, NULL))
return FALSE;
switch (completion->argc)
{
case 0:
case 1: /* REMOTE */
case 1: /* KEY */
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, options);
flatpak_complete_options (completion, user_entries);

View File

@@ -30,6 +30,7 @@
#include "libglnx/libglnx.h"
#include "flatpak-builtins.h"
#include "flatpak-builtins-utils.h"
static gboolean opt_force;
@@ -43,7 +44,8 @@ gboolean
flatpak_builtin_delete_remote (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
g_autoptr(FlatpakDir) preferred_dir = NULL;
const char *remote_name;
context = g_option_context_new (_("NAME - Delete a remote repository"));
@@ -51,7 +53,8 @@ flatpak_builtin_delete_remote (int argc, char **argv, GCancellable *cancellable,
g_option_context_add_main_entries (context, delete_options, NULL);
if (!flatpak_option_context_parse (context, NULL, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, NULL, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, cancellable, error))
return FALSE;
if (argc < 2)
@@ -62,7 +65,10 @@ flatpak_builtin_delete_remote (int argc, char **argv, GCancellable *cancellable,
if (argc > 2)
return usage_error (context, _("Too many arguments"), error);
if (!flatpak_dir_remove_remote (dir, opt_force, remote_name,
if (!flatpak_resolve_duplicate_remotes (dirs, remote_name, &preferred_dir, cancellable, error))
return FALSE;
if (!flatpak_dir_remove_remote (preferred_dir, opt_force, remote_name,
cancellable, error))
return FALSE;
@@ -73,11 +79,12 @@ gboolean
flatpak_complete_delete_remote (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
int i;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, delete_options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, delete_options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, NULL, NULL))
return FALSE;
switch (completion->argc)
@@ -88,13 +95,16 @@ flatpak_complete_delete_remote (FlatpakCompletion *completion)
flatpak_complete_options (completion, delete_options);
flatpak_complete_options (completion, user_entries);
{
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (i = 0; remotes[i] != NULL; i++)
flatpak_complete_word (completion, "%s ", remotes[i]);
}
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
int j;
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (j = 0; remotes[j] != NULL; j++)
flatpak_complete_word (completion, "%s ", remotes[j]);
}
break;
}

View File

@@ -29,7 +29,7 @@
#include <glib/gi18n.h>
#include "libglnx/libglnx.h"
#include "document-portal/xdp-dbus.h"
#include "flatpak-document-dbus.h"
#include <gio/gunixfdlist.h>

View File

@@ -29,7 +29,7 @@
#include <glib/gi18n.h>
#include "libglnx/libglnx.h"
#include "document-portal/xdp-dbus.h"
#include "flatpak-document-dbus.h"
#include <gio/gunixfdlist.h>

View File

@@ -29,7 +29,7 @@
#include <glib/gi18n.h>
#include "libglnx/libglnx.h"
#include "document-portal/xdp-dbus.h"
#include "flatpak-document-dbus.h"
#include "flatpak-builtins.h"
#include "flatpak-utils.h"

View File

@@ -29,7 +29,7 @@
#include <glib/gi18n.h>
#include "libglnx/libglnx.h"
#include "document-portal/xdp-dbus.h"
#include "flatpak-document-dbus.h"
#include <gio/gunixfdlist.h>

View File

@@ -0,0 +1,360 @@
/*
* Copyright © 2017 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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <glib/gi18n.h>
#include "libglnx/libglnx.h"
#include "flatpak-builtins.h"
#include "flatpak-builtins-utils.h"
#include "flatpak-utils.h"
#include "flatpak-table-printer.h"
static char *opt_arch;
static char *opt_commit;
static gboolean opt_runtime;
static gboolean opt_app;
static gboolean opt_show_ref;
static gboolean opt_show_commit;
static gboolean opt_show_parent;
static gboolean opt_show_metadata;
static gboolean opt_log;
static GOptionEntry options[] = {
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, N_("Arch to install for"), N_("ARCH") },
{ "commit", 0, 0, G_OPTION_ARG_STRING, &opt_commit, N_("Commit to show info for"), N_("COMMIT") },
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, N_("Look for runtime with the specified name"), NULL },
{ "app", 0, 0, G_OPTION_ARG_NONE, &opt_app, N_("Look for app with the specified name"), NULL },
{ "log", 0, 0, G_OPTION_ARG_NONE, &opt_log, N_("Display log"), NULL },
{ "show-ref", 'r', 0, G_OPTION_ARG_NONE, &opt_show_ref, N_("Show ref"), NULL },
{ "show-commit", 'c', 0, G_OPTION_ARG_NONE, &opt_show_commit, N_("Show commit"), NULL },
{ "show-parent", 'p', 0, G_OPTION_ARG_NONE, &opt_show_parent, N_("Show parent"), NULL },
{ "show-metadata", 'm', 0, G_OPTION_ARG_NONE, &opt_show_metadata, N_("Show metadata"), NULL },
{ NULL }
};
static void
maybe_print_space (gboolean *first)
{
if (*first)
*first = FALSE;
else
g_print (" ");
}
static gchar *
format_timestamp (guint64 timestamp)
{
GDateTime *dt;
gchar *str;
dt = g_date_time_new_from_unix_utc (timestamp);
if (dt == NULL)
return g_strdup ("?");
str = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S +0000");
g_date_time_unref (dt);
return str;
}
gboolean
flatpak_builtin_info_remote (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GPtrArray) dirs = NULL;
g_autoptr(FlatpakDir) preferred_dir = NULL;
g_autoptr(GVariant) commit_v = NULL;
g_autoptr(GVariant) commit_metadata = NULL;
const char *remote;
const char *pref;
g_autofree char *default_branch = NULL;
FlatpakKinds kinds;
FlatpakKinds matched_kinds;
g_autofree char *id = NULL;
g_autofree char *arch = NULL;
g_autofree char *branch = NULL;
g_auto(GStrv) parts = NULL;
FlatpakKinds kind;
g_autofree char *ref = NULL;
g_autofree char *commit = NULL;
g_autofree char *parent = NULL;
const char *on = "";
const char *off = "";
gboolean friendly = TRUE;
const char *xa_metadata = NULL;
const char *collection_id = NULL;
g_autoptr(GKeyFile) metakey = NULL;
guint64 installed_size = 0;
guint64 download_size = 0;
g_autofree char *formatted_installed_size = NULL;
g_autofree char *formatted_download_size = NULL;
const gchar *subject;
const gchar *body;
guint64 timestamp;
g_autofree char *formatted_timestamp = NULL;
context = g_option_context_new (_(" REMOTE REF - Show information about an application or runtime in a remote"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, cancellable, error))
return FALSE;
if (!opt_app && !opt_runtime)
opt_app = opt_runtime = TRUE;
if (argc < 3)
return usage_error (context, _("REMOTE and REF must be specified"), error);
remote = argv[1];
pref = argv[2];
if (!flatpak_resolve_duplicate_remotes (dirs, remote, &preferred_dir, cancellable, error))
return FALSE;
default_branch = flatpak_dir_get_remote_default_branch (preferred_dir, remote);
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
if (!flatpak_split_partial_ref_arg (pref, kinds, opt_arch, NULL,
&matched_kinds, &id, &arch, &branch, error))
return FALSE;
ref = flatpak_dir_find_remote_ref (preferred_dir, remote, id, branch, default_branch, arch,
matched_kinds, &kind, cancellable, error);
if (ref == NULL)
return FALSE;
commit_v = flatpak_dir_fetch_remote_commit (preferred_dir, remote, ref, opt_commit, &commit, cancellable, error);
if (commit_v == NULL)
return FALSE;
if (flatpak_fancy_output ())
{
on = FLATPAK_ANSI_BOLD_ON;
off = FLATPAK_ANSI_BOLD_OFF; /* bold off */
}
if (opt_show_ref || opt_show_commit || opt_show_parent || opt_show_metadata)
friendly = FALSE;
if (friendly)
{
g_variant_get (commit_v, "(a{sv}aya(say)&s&stayay)", NULL, NULL, NULL,
&subject, &body, NULL, NULL, NULL);
parent = ostree_commit_get_parent (commit_v);
timestamp = ostree_commit_get_timestamp (commit_v);
commit_metadata = g_variant_get_child_value (commit_v, 0);
g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
if (xa_metadata == NULL)
g_printerr (_("Warning: Commit has no flatpak metadata\n"));
else
{
metakey = g_key_file_new ();
if (!g_key_file_load_from_data (metakey, xa_metadata, -1, 0, error))
return FALSE;
}
#ifdef FLATPAK_ENABLE_P2P
g_variant_lookup (commit_metadata, "ostree.collection-binding", "&s", &collection_id);
#endif
if (g_variant_lookup (commit_metadata, "xa.installed-size", "t", &installed_size))
installed_size = GUINT64_FROM_BE (installed_size);
if (g_variant_lookup (commit_metadata, "xa.download-size", "t", &download_size))
download_size = GUINT64_FROM_BE (download_size);
parts = g_strsplit (ref, "/", 0);
formatted_installed_size = g_format_size (installed_size);
formatted_download_size = g_format_size (download_size);
formatted_timestamp = format_timestamp (timestamp);
g_print ("%s%s%s %s\n", on, _("Ref:"), off, ref);
g_print ("%s%s%s %s\n", on, _("ID:"), off, parts[1]);
g_print ("%s%s%s %s\n", on, _("Arch:"), off, parts[2]);
g_print ("%s%s%s %s\n", on, _("Branch:"), off, parts[3]);
if (collection_id != NULL)
g_print ("%s%s%s %s\n", on, _("Collection ID:"), off, collection_id);
g_print ("%s%s%s %s\n", on, _("Date:"), off, formatted_timestamp);
g_print ("%s%s%s %s\n", on, _("Subject:"), off, subject);
g_print ("%s%s%s %s\n", on, _("Commit:"), off, commit);
g_print ("%s%s%s %s\n", on, _("Parent:"), off, parent ? parent : "-");
g_print ("%s%s%s %s\n", on, _("Download size:"), off, formatted_download_size);
g_print ("%s%s%s %s\n", on, _("Installed size:"), off, formatted_installed_size);
if (strcmp (parts[0], "app") == 0 && metakey != NULL)
{
g_autofree char *runtime = NULL;
runtime = g_key_file_get_string (metakey, "Application", "runtime", error);
g_print ("%s%s%s %s\n", on, _("Runtime:"), off, runtime ? runtime : "-");
}
if (opt_log)
{
g_autofree char *p = g_strdup (parent);
g_print ("%s%s%s", on, _("History:\n"), off);
while (p)
{
g_autofree char *p_parent = NULL;
const gchar *p_subject;
guint64 p_timestamp;
g_autofree char *p_formatted_timestamp = NULL;
g_autoptr(GVariant) p_commit_v = NULL;
p_commit_v = flatpak_dir_fetch_remote_commit (preferred_dir, remote, ref, p, NULL, cancellable, NULL);
if (p_commit_v == NULL)
break;
p_parent = ostree_commit_get_parent (p_commit_v);
p_timestamp = ostree_commit_get_timestamp (p_commit_v);
p_formatted_timestamp = format_timestamp (p_timestamp);
g_variant_get (p_commit_v, "(a{sv}aya(say)&s&stayay)", NULL, NULL, NULL,
&p_subject, NULL, NULL, NULL, NULL);
g_print ("%s%s%s %s\n", on, _(" Subject:"), off, p_subject);
g_print ("%s%s%s %s\n", on, _(" Date:"), off, p_formatted_timestamp);
g_print ("%s%s%s %s\n", on, _(" Commit:"), off, p);
g_free (p);
p = g_steal_pointer (&p_parent);
if (p)
g_print ("\n");
}
}
}
else
{
g_autoptr(GVariant) c_v = g_variant_ref (commit_v);
g_autofree char *c = g_strdup (commit);
do
{
g_autofree char *p = ostree_commit_get_parent (c_v);
gboolean first = TRUE;
if (opt_show_ref)
{
maybe_print_space (&first);
g_print ("%s", ref);
}
if (opt_show_commit)
{
maybe_print_space (&first);
g_print ("%s", c);
}
if (opt_show_parent)
{
maybe_print_space (&first);
g_print ("%s", p ? p : "-");
}
if (!first)
g_print ("\n");
if (opt_show_metadata)
{
g_autoptr(GVariant) c_m = NULL;
c_m = g_variant_get_child_value (c_v, 0);
g_variant_lookup (c_m, "xa.metadata", "&s", &xa_metadata);
if (xa_metadata == NULL)
g_printerr (_("Warning: Commit %s has no flatpak metadata\n"), c);
else
g_print ("%s", xa_metadata);
}
g_free (c);
c = g_steal_pointer (&p);
g_variant_unref (c_v);
c_v = NULL;
if (c && opt_log)
c_v = flatpak_dir_fetch_remote_commit (preferred_dir, remote, ref, c, NULL, cancellable, NULL);
}
while (c_v != NULL);
}
return TRUE;
}
gboolean
flatpak_complete_info_remote (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakKinds kinds;
int i;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, NULL, NULL))
return FALSE;
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
switch (completion->argc)
{
case 0:
case 1: /* REMOTE */
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, options);
flatpak_complete_options (completion, user_entries);
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
int j;
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (j = 0; remotes[j] != NULL; j++)
flatpak_complete_word (completion, "%s ", remotes[j]);
}
break;
default: /* REF */
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
flatpak_complete_partial_ref (completion, kinds, opt_arch, dir, completion->argv[1]);
}
break;
}
return TRUE;
}

View File

@@ -32,6 +32,7 @@
#include "flatpak-builtins.h"
#include "flatpak-utils.h"
#include "flatpak-builtins-utils.h"
#include "flatpak-run.h"
static gboolean opt_user;
static gboolean opt_system;
@@ -40,9 +41,11 @@ static gboolean opt_show_commit;
static gboolean opt_show_origin;
static gboolean opt_show_size;
static gboolean opt_show_metadata;
static gboolean opt_show_permissions;
static gboolean opt_show_extensions;
static char *opt_arch;
static char **opt_installations;
static char *opt_file_access;
static GOptionEntry options[] = {
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, N_("Arch to use"), N_("ARCH") },
@@ -54,6 +57,8 @@ static GOptionEntry options[] = {
{ "show-origin", 'o', 0, G_OPTION_ARG_NONE, &opt_show_origin, N_("Show origin"), NULL },
{ "show-size", 's', 0, G_OPTION_ARG_NONE, &opt_show_size, N_("Show size"), NULL },
{ "show-metadata", 'm', 0, G_OPTION_ARG_NONE, &opt_show_metadata, N_("Show metadata"), NULL },
{ "show-permissions", 'M', 0, G_OPTION_ARG_NONE, &opt_show_permissions, N_("Show permissions"), NULL },
{ "file-access", 0, 0, G_OPTION_ARG_FILENAME, &opt_file_access, N_("Query file access"), N_("PATH") },
{ "show-extensions", 'e', 0, G_OPTION_ARG_NONE, &opt_show_extensions, N_("Show extensions"), NULL },
{ NULL }
};
@@ -68,6 +73,22 @@ maybe_print_space (gboolean *first)
g_print (" ");
}
static gchar *
format_timestamp (guint64 timestamp)
{
GDateTime *dt;
gchar *str;
dt = g_date_time_new_from_unix_utc (timestamp);
if (dt == NULL)
return g_strdup ("?");
str = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S +0000");
g_date_time_unref (dt);
return str;
}
gboolean
flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError **error)
{
@@ -147,20 +168,56 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
metakey = flatpak_deploy_get_metadata (deploy);
if (opt_show_ref || opt_show_origin || opt_show_commit || opt_show_size || opt_show_metadata)
if (opt_show_ref || opt_show_origin || opt_show_commit || opt_show_size || opt_show_metadata || opt_show_permissions || opt_file_access)
friendly = FALSE;
if (friendly)
{
const char *latest = flatpak_dir_read_latest (dir, origin, ref, NULL, NULL, NULL);
g_autoptr(GVariant) commit_v = NULL;
g_autoptr(GVariant) commit_metadata = NULL;
guint64 timestamp;
g_autofree char *formatted_timestamp = NULL;
const gchar *subject = NULL;
const gchar *body = NULL;
g_autofree char *parent = NULL;
const char *latest;
const char *xa_metadata = NULL;
const char *collection_id = NULL;
latest = flatpak_dir_read_latest (dir, origin, ref, NULL, NULL, NULL);
if (latest == NULL)
latest = _("ref not present in origin");
if (ostree_repo_load_commit (flatpak_dir_get_repo (dir), commit, &commit_v, NULL, NULL))
{
g_variant_get (commit_v, "(a{sv}aya(say)&s&stayay)", NULL, NULL, NULL,
&subject, &body, NULL, NULL, NULL);
parent = ostree_commit_get_parent (commit_v);
timestamp = ostree_commit_get_timestamp (commit_v);
formatted_timestamp = format_timestamp (timestamp);
commit_metadata = g_variant_get_child_value (commit_v, 0);
g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
if (xa_metadata == NULL)
g_printerr (_("Warning: Commit has no flatpak metadata\n"));
#ifdef FLATPAK_ENABLE_P2P
g_variant_lookup (commit_metadata, "ostree.collection-binding", "&s", &collection_id);
#endif
}
g_print ("%s%s%s %s\n", on, _("Ref:"), off, ref);
g_print ("%s%s%s %s\n", on, _("ID:"), off, parts[1]);
g_print ("%s%s%s %s\n", on, _("Arch:"), off, parts[2]);
g_print ("%s%s%s %s\n", on, _("Branch:"), off, parts[3]);
g_print ("%s%s%s %s\n", on, _("Origin:"), off, origin ? origin : "-");
if (collection_id)
g_print ("%s%s%s %s\n", on, _("Collection ID:"), off, collection_id);
if (formatted_timestamp)
g_print ("%s%s%s %s\n", on, _("Date:"), off, formatted_timestamp);
if (subject)
g_print ("%s%s%s %s\n", on, _("Subject:"), off, subject);
if (strcmp (commit, latest) != 0)
{
g_print ("%s%s%s %s\n", on, _("Active commit:"), off, commit);
@@ -170,6 +227,7 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
g_print ("%s%s%s %s\n", on, _("Commit:"), off, commit);
if (alt_id)
g_print ("%s%s%s %s\n", on, _("alt-id:"), off, alt_id);
g_print ("%s%s%s %s\n", on, _("Parent:"), off, parent ? parent : "-");
g_print ("%s%s%s %s\n", on, _("Location:"), off, path);
g_print ("%s%s%s %s\n", on, _("Installed size:"), off, formatted);
if (strcmp (parts[0], "app") == 0)
@@ -231,6 +289,42 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
g_print ("%s", data);
}
if (opt_show_permissions || opt_file_access)
{
g_autoptr(FlatpakContext) context = NULL;
g_autoptr(GKeyFile) keyfile = NULL;
g_autofree gchar *contents = NULL;
context = flatpak_context_load_for_deploy (deploy, error);
if (context == NULL)
return FALSE;
if (opt_show_permissions)
{
keyfile = g_key_file_new ();
flatpak_context_save_metadata (context, TRUE, keyfile);
contents = g_key_file_to_data (keyfile, NULL, error);
if (contents == NULL)
return FALSE;
g_print ("%s", contents);
}
if (opt_file_access)
{
g_autoptr(FlatpakExports) exports = flatpak_context_get_exports (context, parts[1]);
FlatpakFilesystemMode mode;
mode = flatpak_exports_path_get_mode (exports, opt_file_access);
if (mode == 0)
g_print ("hidden\n");
else if (mode == FLATPAK_FILESYSTEM_MODE_READ_ONLY)
g_print ("read-only\n");
else
g_print ("read-write\n");
}
}
}
if (opt_show_extensions)
@@ -289,39 +383,18 @@ gboolean
flatpak_complete_info (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) user_dir = NULL;
g_autoptr(FlatpakDir) system_dir = NULL;
g_autoptr(GPtrArray) system_dirs = NULL;
g_autoptr(GPtrArray) dirs = NULL;
g_autoptr(GError) error = NULL;
gboolean search_all = FALSE;
FlatpakKinds kinds;
int i, j;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ALL_DIRS, &dirs, NULL, NULL))
return FALSE;
kinds = FLATPAK_KINDS_APP | FLATPAK_KINDS_RUNTIME;
if (!opt_user && !opt_system && opt_installations == NULL)
search_all = TRUE;
if (opt_user || search_all)
user_dir = flatpak_dir_get_user ();
if (search_all)
{
system_dirs = flatpak_dir_get_system_list (NULL, &error);
if (system_dirs == NULL)
{
flatpak_completion_debug ("find system installations error: %s", error->message);
return FALSE;
}
}
if (opt_system)
system_dir = flatpak_dir_get_system_default ();
switch (completion->argc)
{
case 0:
@@ -329,47 +402,16 @@ flatpak_complete_info (FlatpakCompletion *completion)
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, options);
if (user_dir)
for (i = 0; i < dirs->len; i++)
{
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (user_dir, NULL, NULL, opt_arch,
FlatpakDir *dir = g_ptr_array_index (dirs, i);
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (dir, NULL, NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find local refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
for (j = 0; refs != NULL && refs[j] != NULL; j++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
}
if (system_dirs)
{
for (i = 0; i < system_dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (system_dirs, i);
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (dir, NULL, NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find local refs error: %s", error->message);
for (j = 0; refs != NULL && refs[j] != NULL; j++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[j], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
}
}
if (system_dir)
{
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (system_dir, NULL, NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find local refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
g_auto(GStrv) parts = flatpak_decompose_ref (refs[j], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
@@ -377,47 +419,16 @@ flatpak_complete_info (FlatpakCompletion *completion)
break;
case 2: /* BRANCH */
if (user_dir)
for (i = 0; i < dirs->len; i++)
{
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (user_dir, completion->argv[1], NULL, opt_arch,
FlatpakDir *dir = g_ptr_array_index (dirs, i);
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (dir, completion->argv[1], NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find remote refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
for (j = 0; refs != NULL && refs[j] != NULL; j++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[3]);
}
}
if (system_dirs)
{
for (i = 0; i < system_dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (system_dirs, i);
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (dir, completion->argv[1], NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find remote refs error: %s", error->message);
for (j = 0; refs != NULL && refs[j] != NULL; j++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[j], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[3]);
}
}
}
if (system_dir)
{
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (system_dir, completion->argv[1], NULL, opt_arch,
kinds, &error);
if (refs == NULL)
flatpak_completion_debug ("find remote refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
g_auto(GStrv) parts = flatpak_decompose_ref (refs[j], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[3]);
}

View File

@@ -51,6 +51,7 @@ static gboolean opt_app;
static gboolean opt_bundle;
static gboolean opt_from;
static gboolean opt_yes;
static gboolean opt_reinstall;
static GOptionEntry options[] = {
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, N_("Arch to install for"), N_("ARCH") },
@@ -66,6 +67,7 @@ static GOptionEntry options[] = {
{ "gpg-file", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_gpg_file, N_("Check bundle signatures with GPG key from FILE (- for stdin)"), N_("FILE") },
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, N_("Only install this subpath"), N_("PATH") },
{ "assumeyes", 'y', 0, G_OPTION_ARG_NONE, &opt_yes, N_("Automatically answer yes for all questions"), NULL },
{ "reinstall", 0, 0, G_OPTION_ARG_NONE, &opt_reinstall, N_("Uninstall first if already installed"), NULL },
{ NULL }
};
@@ -286,7 +288,7 @@ install_bundle (FlatpakDir *dir,
return FALSE;
transaction = flatpak_transaction_new (dir, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, opt_reinstall);
if (!flatpak_transaction_add_install_bundle (transaction, file, gpg_data, error))
return FALSE;
@@ -333,7 +335,7 @@ handle_suggested_remote_name (FlatpakDir *dir, GBytes *data, GError **error)
return TRUE;
if (opt_yes ||
flatpak_yes_no_prompt (_("The remote '%s', at location %s contains additional applications.\nDo you want to install other applications from here?"),
flatpak_yes_no_prompt (_("The remote '%s', at location %s contains additional applications.\nShould the remote be kept for future installations?"),
suggested_name, url))
{
if (opt_yes)
@@ -440,7 +442,7 @@ install_from (FlatpakDir *dir,
g_print (_("Installing: %s\n"), slash + 1);
transaction = flatpak_transaction_new (clone, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, opt_reinstall);
if (!flatpak_transaction_add_install (transaction, remote, ref, (const char **)opt_subpaths, error))
return FALSE;
@@ -458,8 +460,10 @@ gboolean
flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
const char *remote;
g_autofree char *remote_url = NULL;
char **prefs = NULL;
int i, n_prefs;
g_autofree char *target_branch = NULL;
@@ -470,9 +474,13 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
context = g_option_context_new (_("LOCATION/REMOTE [REF...] - Install applications or runtimes"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR,
&dirs, cancellable, error))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
if (!opt_bundle && !opt_from && argc >= 2)
{
if (flatpak_file_arg_has_suffix (argv[1], ".flatpakref"))
@@ -490,7 +498,15 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
if (argc < 3)
return usage_error (context, _("REMOTE and REF must be specified"), error);
remote = argv[1];
if (g_path_is_absolute (argv[1]) ||
g_str_has_prefix (argv[1], "./"))
{
g_autoptr(GFile) remote_file = g_file_new_for_commandline_arg (argv[1]);
remote_url = g_file_get_uri (remote_file);
remote = remote_url;
}
else
remote = argv[1];
prefs = &argv[2];
n_prefs = argc - 2;
@@ -505,7 +521,7 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
transaction = flatpak_transaction_new (dir, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, opt_reinstall);
for (i = 0; i < n_prefs; i++)
{
@@ -550,14 +566,18 @@ gboolean
flatpak_complete_install (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
FlatpakKinds kinds;
int i;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR, &dirs, NULL, NULL))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
switch (completion->argc)

View File

@@ -34,15 +34,9 @@
#include "flatpak-table-printer.h"
static gboolean opt_show_details;
static gboolean opt_user;
static gboolean opt_system;
static gboolean opt_show_disabled;
static char **opt_installations;
static GOptionEntry options[] = {
{ "user", 0, 0, G_OPTION_ARG_NONE, &opt_user, N_("Show user installations"), NULL },
{ "system", 0, 0, G_OPTION_ARG_NONE, &opt_system, N_("Show system-wide installations"), NULL },
{ "installation", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_installations, N_("Show specific system-wide installations"), NULL },
{ "show-details", 'd', 0, G_OPTION_ARG_NONE, &opt_show_details, N_("Show remote details"), NULL },
{ "show-disabled", 0, 0, G_OPTION_ARG_NONE, &opt_show_disabled, N_("Show disabled remotes"), NULL },
{ NULL }
@@ -59,46 +53,13 @@ flatpak_builtin_list_remotes (int argc, char **argv, GCancellable *cancellable,
context = g_option_context_new (_(" - List remote repositories"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, cancellable, error))
return FALSE;
if (argc > 1)
return usage_error (context, _("Too many arguments"), error);
if (!opt_user && !opt_system && opt_installations == NULL)
{
/* Default: All system and user remotes */
opt_user = opt_system = TRUE;
}
dirs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
if (opt_user)
g_ptr_array_add (dirs, flatpak_dir_get_user ());
if (opt_system)
g_ptr_array_add (dirs, flatpak_dir_get_system_default ());
if (opt_installations != NULL)
{
int i = 0;
for (i = 0; opt_installations[i] != NULL; i++)
{
FlatpakDir *installation_dir = NULL;
/* Already included the default system installation. */
if (opt_system && g_strcmp0 (opt_installations[i], "default") == 0)
continue;
installation_dir = flatpak_dir_get_system_by_id (opt_installations[i], cancellable, error);
if (installation_dir == NULL)
return FALSE;
g_ptr_array_add (dirs, installation_dir);
}
}
printer = flatpak_table_printer_new ();
j = 0;
@@ -107,6 +68,9 @@ flatpak_builtin_list_remotes (int argc, char **argv, GCancellable *cancellable,
{
flatpak_table_printer_set_column_title (printer, j++, _("Title"));
flatpak_table_printer_set_column_title (printer, j++, _("URL"));
#ifdef FLATPAK_ENABLE_P2P
flatpak_table_printer_set_column_title (printer, j++, _("Collection ID"));
#endif
flatpak_table_printer_set_column_title (printer, j++, _("Priority"));
}
flatpak_table_printer_set_column_title (printer, j++, _("Options"));
@@ -116,8 +80,6 @@ flatpak_builtin_list_remotes (int argc, char **argv, GCancellable *cancellable,
FlatpakDir *dir = g_ptr_array_index (dirs, j);
g_auto(GStrv) remotes = NULL;
flatpak_log_dir_access (dir);
remotes = flatpak_dir_list_remotes (dir, cancellable, error);
if (remotes == NULL)
return FALSE;
@@ -128,6 +90,9 @@ flatpak_builtin_list_remotes (int argc, char **argv, GCancellable *cancellable,
gboolean disabled;
g_autofree char *remote_url = NULL;
g_autofree char *title = NULL;
#ifdef FLATPAK_ENABLE_P2P
g_autofree char *collection_id = NULL;
#endif
int prio;
g_autofree char *prio_as_string = NULL;
gboolean gpg_verify = TRUE;
@@ -151,6 +116,14 @@ flatpak_builtin_list_remotes (int argc, char **argv, GCancellable *cancellable,
else
flatpak_table_printer_add_column (printer, "-");
#ifdef FLATPAK_ENABLE_P2P
collection_id = flatpak_dir_get_remote_collection_id (dir, remote_name);
if (collection_id != NULL)
flatpak_table_printer_add_column (printer, collection_id);
else
flatpak_table_printer_add_column (printer, "-");
#endif
prio = flatpak_dir_get_remote_prio (dir, remote_name);
prio_as_string = g_strdup_printf ("%d", prio);
flatpak_table_printer_add_column (printer, prio_as_string);
@@ -158,9 +131,7 @@ flatpak_builtin_list_remotes (int argc, char **argv, GCancellable *cancellable,
flatpak_table_printer_add_column (printer, ""); /* Options */
if ((opt_user && opt_system) || (opt_user && opt_installations != NULL)
|| (opt_system && opt_installations != NULL)
|| (opt_installations != NULL && g_strv_length (opt_installations) > 1))
if (dirs->len > 1)
{
g_autofree char *dir_id = flatpak_dir_get_name (dir);
flatpak_table_printer_append_with_comma (printer, dir_id);
@@ -194,16 +165,16 @@ gboolean
flatpak_complete_list_remotes (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, NULL, NULL, NULL))
return FALSE;
switch (completion->argc)
{
case 0:
case 1: /* REMOTE */
case 1:
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, options);
flatpak_complete_options (completion, user_entries);

View File

@@ -34,18 +34,12 @@
#include "flatpak-table-printer.h"
static gboolean opt_show_details;
static gboolean opt_user;
static gboolean opt_system;
static gboolean opt_runtime;
static gboolean opt_app;
static gboolean opt_all;
static char **opt_installations;
static char *opt_arch;
static GOptionEntry options[] = {
{ "user", 0, 0, G_OPTION_ARG_NONE, &opt_user, N_("Show user installations"), NULL },
{ "system", 0, 0, G_OPTION_ARG_NONE, &opt_system, N_("Show system-wide installations"), NULL },
{ "installation", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_installations, N_("Show specific system-wide installations"), NULL },
{ "show-details", 'd', 0, G_OPTION_ARG_NONE, &opt_show_details, N_("Show extra information"), NULL },
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, N_("List installed runtimes"), NULL },
{ "app", 0, 0, G_OPTION_ARG_NONE, &opt_app, N_("List installed applications"), NULL },
@@ -278,87 +272,22 @@ print_table_for_refs (gboolean print_apps, GPtrArray* refs_array, const char *ar
}
static gboolean
print_installed_refs (gboolean app, gboolean runtime, gboolean print_system, gboolean print_user, char **installations, const char *arch, GCancellable *cancellable, GError **error)
print_installed_refs (gboolean app, gboolean runtime, GPtrArray *dirs, const char *arch, GCancellable *cancellable, GError **error)
{
g_autoptr(GPtrArray) refs_array = NULL;
gboolean print_all = !print_user && !print_system && (installations == NULL);
int i;
refs_array = g_ptr_array_new_with_free_func ((GDestroyNotify) refs_data_free);
if (print_user || print_all)
{
g_autoptr(FlatpakDir) user_dir = NULL;
g_auto(GStrv) user_app = NULL;
g_auto(GStrv) user_runtime = NULL;
user_dir =flatpak_dir_get_user ();
flatpak_log_dir_access (user_dir);
if (!find_refs_for_dir (user_dir, app ? &user_app : NULL, runtime ? &user_runtime : NULL, cancellable, error))
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
g_auto(GStrv) apps = NULL;
g_auto(GStrv) runtimes = NULL;
if (!find_refs_for_dir (dir, app ? &apps : NULL, runtime ? &runtimes : NULL, cancellable, error))
return FALSE;
g_ptr_array_add (refs_array, refs_data_new (user_dir, user_app, user_runtime));
}
if (print_all)
{
g_autoptr(GPtrArray) system_dirs = NULL;
int i;
system_dirs = flatpak_dir_get_system_list (cancellable, error);
if (system_dirs == NULL)
return FALSE;
for (i = 0; i < system_dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (system_dirs, i);
g_auto(GStrv) apps = NULL;
g_auto(GStrv) runtimes = NULL;
flatpak_log_dir_access (dir);
if (!find_refs_for_dir (dir, app ? &apps : NULL, runtime ? &runtimes : NULL, cancellable, error))
return FALSE;
g_ptr_array_add (refs_array, refs_data_new (dir, apps, runtimes));
}
}
else
{
if (print_system)
{
g_autoptr(FlatpakDir) system_dir = NULL;
g_auto(GStrv) system_app = NULL;
g_auto(GStrv) system_runtime = NULL;
system_dir = flatpak_dir_get_system_default ();
flatpak_log_dir_access (system_dir);
if (!find_refs_for_dir (system_dir, app ? &system_app : NULL, runtime ? &system_runtime : NULL, cancellable, error))
return FALSE;
g_ptr_array_add (refs_array, refs_data_new (system_dir, system_app, system_runtime));
}
if (installations != NULL)
{
g_auto(GStrv) installation_apps = NULL;
g_auto(GStrv) installation_runtimes = NULL;
int i = 0;
for (i = 0; installations[i] != NULL; i++)
{
g_autoptr(FlatpakDir) system_dir = NULL;
/* Already included the default system installation. */
if (print_system && g_strcmp0 (installations[i], "default") == 0)
continue;
system_dir = flatpak_dir_get_system_by_id (installations[i], cancellable, error);
flatpak_log_dir_access (system_dir);
if (system_dir == NULL)
return FALSE;
if (!find_refs_for_dir (system_dir, app ? &installation_apps : NULL, runtime ? &installation_runtimes : NULL, cancellable, error))
return FALSE;
g_ptr_array_add (refs_array, refs_data_new (system_dir, installation_apps, installation_runtimes));
}
}
g_ptr_array_add (refs_array, refs_data_new (dir, apps, runtimes));
}
if (!print_table_for_refs (app, refs_array, arch, cancellable, error))
@@ -371,11 +300,14 @@ gboolean
flatpak_builtin_list (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GPtrArray) dirs = NULL;
context = g_option_context_new (_(" - List installed apps and/or runtimes"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ALL_DIRS,
&dirs, cancellable, error))
return FALSE;
if (argc > 1)
@@ -388,9 +320,7 @@ flatpak_builtin_list (int argc, char **argv, GCancellable *cancellable, GError *
}
if (!print_installed_refs (opt_app, opt_runtime,
opt_system,
opt_user,
opt_installations,
dirs,
opt_arch,
cancellable, error))
return FALSE;
@@ -403,5 +333,6 @@ flatpak_complete_list (FlatpakCompletion *completion)
{
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, options);
flatpak_complete_options (completion, user_entries);
return TRUE;
}

View File

@@ -30,6 +30,7 @@
#include "libglnx/libglnx.h"
#include "flatpak-builtins.h"
#include "flatpak-builtins-utils.h"
#include "flatpak-utils.h"
#include "flatpak-table-printer.h"
@@ -50,11 +51,33 @@ static GOptionEntry options[] = {
{ NULL }
};
typedef struct RemoteDirPair {
gchar *remote_name;
FlatpakDir *dir;
} RemoteDirPair;
static void
remote_dir_pair_free (RemoteDirPair *pair)
{
g_free (pair->remote_name);
g_object_unref (pair->dir);
g_free (pair);
}
static RemoteDirPair *
remote_dir_pair_new (const char *remote_name, FlatpakDir *dir)
{
RemoteDirPair *pair = g_new (RemoteDirPair, 1);
pair->remote_name = g_strdup (remote_name);
pair->dir = g_object_ref (dir);
return pair;
}
gboolean
flatpak_builtin_ls_remote (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
GHashTableIter refs_iter;
GHashTableIter iter;
gpointer refs_key;
@@ -66,15 +89,15 @@ flatpak_builtin_ls_remote (int argc, char **argv, GCancellable *cancellable, GEr
int i;
const char **arches = flatpak_get_arches ();
const char *opt_arches[] = {NULL, NULL};
g_auto(GStrv) remotes = NULL;
gboolean has_remote;
g_autoptr(GHashTable) pref_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GHashTable) refs_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, (GDestroyNotify)g_hash_table_unref, g_free);
g_autoptr(GHashTable) refs_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, (GDestroyNotify)g_hash_table_unref, (GDestroyNotify)remote_dir_pair_free);
context = g_option_context_new (_(" REMOTE - Show available runtimes and applications"));
context = g_option_context_new (_(" [REMOTE] - Show available runtimes and applications"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, cancellable, error))
return FALSE;
if (!opt_app && !opt_runtime)
@@ -83,33 +106,58 @@ flatpak_builtin_ls_remote (int argc, char **argv, GCancellable *cancellable, GEr
if (argc > 2)
return usage_error (context, _("Too many arguments"), error);
if (argc < 2)
{
has_remote = FALSE;
remotes = flatpak_dir_list_remotes (dir, cancellable, error);
if (remotes == NULL)
return FALSE;
}
else
{
has_remote = TRUE;
remotes = g_new (char *, 2);
remotes[0] = g_strdup(argv[1]);
remotes[1] = NULL;
}
has_remote = (argc == 2);
for (i = 0; remotes[i] != NULL; i++)
if (has_remote)
{
g_autoptr(FlatpakDir) preferred_dir = NULL;
g_autoptr(GHashTable) refs = NULL;
const char *remote_name = remotes[i];
RemoteDirPair *remote_dir_pair = NULL;
if (!flatpak_dir_list_remote_refs (dir,
remote_name,
if (!flatpak_resolve_duplicate_remotes (dirs, argv[1], &preferred_dir, cancellable, error))
return FALSE;
if (!flatpak_dir_list_remote_refs (preferred_dir,
argv[1],
&refs,
cancellable, error))
return FALSE;
g_hash_table_insert (refs_hash, g_steal_pointer (&refs), g_strdup (remote_name));
remote_dir_pair = remote_dir_pair_new (argv[1], preferred_dir);
g_hash_table_insert (refs_hash, g_steal_pointer (&refs), remote_dir_pair);
}
else
{
int i;
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
g_auto(GStrv) remotes = NULL;
int j;
remotes = flatpak_dir_list_remotes (dir, cancellable, error);
if (remotes == NULL)
return FALSE;
for (j = 0; remotes[j] != NULL; j++)
{
g_autoptr(GHashTable) refs = NULL;
RemoteDirPair *remote_dir_pair = NULL;
const char *remote_name = remotes[j];
if (flatpak_dir_get_remote_disabled (dir, remote_name))
continue;
if (!flatpak_dir_list_remote_refs (dir,
remote_name,
&refs,
cancellable, error))
return FALSE;
remote_dir_pair = remote_dir_pair_new (remote_name, dir);
g_hash_table_insert (refs_hash, g_steal_pointer (&refs), remote_dir_pair);
}
}
}
if (opt_arch != NULL)
@@ -137,14 +185,25 @@ flatpak_builtin_ls_remote (int argc, char **argv, GCancellable *cancellable, GEr
while (g_hash_table_iter_next (&refs_iter, &refs_key, &refs_value))
{
GHashTable *refs = refs_key;
char *remote = refs_value;
RemoteDirPair *remote_dir_pair = refs_value;
const char *remote = remote_dir_pair->remote_name;
FlatpakDir *dir = remote_dir_pair->dir;
g_autoptr(GHashTable) names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_iter_init (&iter, refs);
while (g_hash_table_iter_next (&iter, &key, &value))
{
char *ref = key;
char *partial_ref = flatpak_make_valid_id_prefix (strchr (ref, '/') + 1);
char *partial_ref;
const char *slash = strchr (ref, '/');
if (slash == NULL)
{
g_debug ("Invalid remote ref %s", ref);
continue;
}
partial_ref = flatpak_make_valid_id_prefix (slash + 1);
g_hash_table_insert (pref_hash, partial_ref, ref);
}
@@ -170,6 +229,9 @@ flatpak_builtin_ls_remote (int argc, char **argv, GCancellable *cancellable, GEr
if (deploy_data == NULL)
continue;
if (g_strcmp0 (flatpak_deploy_data_get_origin (deploy_data), remote) != 0)
continue;
if (g_strcmp0 (flatpak_deploy_data_get_commit (deploy_data), checksum) == 0)
continue;
}
@@ -270,12 +332,13 @@ gboolean
flatpak_complete_ls_remote (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
int i;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, NULL, NULL))
return FALSE;
switch (completion->argc)
@@ -286,13 +349,16 @@ flatpak_complete_ls_remote (FlatpakCompletion *completion)
flatpak_complete_options (completion, options);
flatpak_complete_options (completion, user_entries);
{
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (i = 0; remotes[i] != NULL; i++)
flatpak_complete_word (completion, "%s ", remotes[i]);
}
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
int j;
g_auto(GStrv) remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
if (remotes == NULL)
return FALSE;
for (j = 0; remotes[j] != NULL; j++)
flatpak_complete_word (completion, "%s ", remotes[j]);
}
break;
}

View File

@@ -43,7 +43,8 @@ gboolean
flatpak_builtin_make_current_app (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
g_autoptr(GFile) deploy_base = NULL;
const char *pref;
const char *default_branch = NULL;
@@ -57,9 +58,13 @@ flatpak_builtin_make_current_app (int argc, char **argv, GCancellable *cancellab
context = g_option_context_new (_("APP BRANCH - Make branch of application current"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR,
&dirs, cancellable, error))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
if (argc < 2)
return usage_error (context, _("APP must be specified"), error);
@@ -109,15 +114,19 @@ gboolean
flatpak_complete_make_current_app (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
g_autoptr(GError) error = NULL;
g_auto(GStrv) refs = NULL;
int i;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR, &dirs, NULL, NULL))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
switch (completion->argc)
{
case 0:

View File

@@ -45,30 +45,36 @@ flatpak_builtin_override (int argc, char **argv, GCancellable *cancellable, GErr
g_autoptr(GOptionContext) context = NULL;
const char *app;
g_autoptr(FlatpakContext) arg_context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
g_autoptr(GKeyFile) metakey = NULL;
g_autoptr(FlatpakContext) overrides = NULL;
g_autoptr(GError) my_error = NULL;
context = g_option_context_new (_("APP - Override settings for application"));
context = g_option_context_new (_("[APP] - Override settings [for application]"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
arg_context = flatpak_context_new ();
g_option_context_add_group (context, flatpak_context_get_options (arg_context));
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR,
&dirs, cancellable, error))
return FALSE;
if (argc < 2)
return usage_error (context, _("APP must be specified"), error);
dir = g_ptr_array_index (dirs, 0);
if (argc > 2)
return usage_error (context, _("Too many arguments"), error);
app = argv[1];
if (!flatpak_is_valid_name (app, &my_error))
return flatpak_fail (error, _("'%s' is not a valid application name: %s"), app, my_error->message);
if (argc >= 2)
{
app = argv[1];
if (!flatpak_is_valid_name (app, &my_error))
return flatpak_fail (error, _("'%s' is not a valid application name: %s"), app, my_error->message);
}
else
app = NULL;
metakey = flatpak_load_override_keyfile (app, flatpak_dir_is_user (dir), &my_error);
if (metakey == NULL)
@@ -99,8 +105,7 @@ gboolean
flatpak_complete_override (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) user_dir = NULL;
g_autoptr(FlatpakDir) system_dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
g_autoptr(GError) error = NULL;
int i;
g_autoptr(FlatpakContext) arg_context = NULL;
@@ -111,7 +116,7 @@ flatpak_complete_override (FlatpakCompletion *completion)
g_option_context_add_group (context, flatpak_context_get_options (arg_context));
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, NULL, NULL))
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, NULL, NULL))
return FALSE;
switch (completion->argc)
@@ -122,33 +127,21 @@ flatpak_complete_override (FlatpakCompletion *completion)
flatpak_complete_options (completion, options);
flatpak_context_complete (arg_context, completion);
user_dir = flatpak_dir_get_user ();
{
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (user_dir, NULL, NULL, NULL,
FLATPAK_KINDS_APP, &error);
if (refs == NULL)
flatpak_completion_debug ("find local refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
}
system_dir = flatpak_dir_get_system_default ();
{
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (system_dir, NULL, NULL, NULL,
FLATPAK_KINDS_APP, &error);
if (refs == NULL)
flatpak_completion_debug ("find local refs error: %s", error->message);
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
}
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
int j;
g_auto(GStrv) refs = flatpak_dir_find_installed_refs (dir, NULL, NULL, NULL,
FLATPAK_KINDS_APP, &error);
if (refs == NULL)
flatpak_completion_debug ("find local refs error: %s", error->message);
for (j = 0; refs != NULL && refs[j] != NULL; j++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[j], NULL);
if (parts)
flatpak_complete_word (completion, "%s ", parts[1]);
}
}
break;

View File

@@ -162,6 +162,7 @@ flatpak_builtin_repo (int argc, char **argv,
g_autoptr(GFile) location = NULL;
g_autoptr(GVariant) meta = NULL;
g_autoptr(OstreeRepo) repo = NULL;
const char *ostree_metadata_ref = NULL;
g_autofree char *ostree_metadata_checksum = NULL;
context = g_option_context_new (_("LOCATION - Repository maintenance"));
@@ -181,7 +182,8 @@ flatpak_builtin_repo (int argc, char **argv,
#ifdef FLATPAK_ENABLE_P2P
/* Try loading the metadata from the ostree-metadata branch first. If that
* fails, fall back to the summary file. */
if (!ostree_repo_resolve_rev (repo, OSTREE_REPO_METADATA_REF,
ostree_metadata_ref = OSTREE_REPO_METADATA_REF;
if (!ostree_repo_resolve_rev (repo, ostree_metadata_ref,
TRUE, &ostree_metadata_checksum, error))
return FALSE;
#endif /* FLATPAK_ENABLE_P2P */
@@ -191,7 +193,10 @@ flatpak_builtin_repo (int argc, char **argv,
g_autoptr(GVariant) commit_v = NULL;
if (!ostree_repo_load_commit (repo, ostree_metadata_checksum, &commit_v, NULL, error))
return FALSE;
{
g_prefix_error (error, "Error getting repository metadata from %s ref: ", ostree_metadata_ref);
return FALSE;
}
meta = g_variant_get_child_value (commit_v, 0);
}
@@ -201,7 +206,10 @@ flatpak_builtin_repo (int argc, char **argv,
summary = flatpak_repo_load_summary (repo, error);
if (summary == NULL)
return FALSE;
{
g_prefix_error (error, "Error getting repository metadata from summary file: ");
return FALSE;
}
meta = g_variant_get_child_value (summary, 1);
}

View File

@@ -44,6 +44,7 @@ static gboolean opt_devel;
static gboolean opt_log_session_bus;
static gboolean opt_log_system_bus;
static gboolean opt_log_a11y_bus;
static gboolean opt_no_a11y_bus;
static gboolean opt_file_forwarding;
static char *opt_runtime;
static char *opt_runtime_version;
@@ -58,6 +59,7 @@ static GOptionEntry options[] = {
{ "log-session-bus", 0, 0, G_OPTION_ARG_NONE, &opt_log_session_bus, N_("Log session bus calls"), NULL },
{ "log-system-bus", 0, 0, G_OPTION_ARG_NONE, &opt_log_system_bus, N_("Log system bus calls"), NULL },
{ "log-a11y-bus", 0, 0, G_OPTION_ARG_NONE, &opt_log_a11y_bus, N_("Log accessibility bus calls"), NULL },
{ "no-a11y-bus", 0, 0, G_OPTION_ARG_NONE, &opt_no_a11y_bus, N_("Don't proxy accessibility bus calls"), NULL },
{ "file-forwarding", 0, 0, G_OPTION_ARG_NONE, &opt_file_forwarding, N_("Enable file forwarding"), NULL },
{ NULL }
};
@@ -179,7 +181,8 @@ flatpak_builtin_run (int argc, char **argv, GCancellable *cancellable, GError **
(opt_log_session_bus ? FLATPAK_RUN_FLAG_LOG_SESSION_BUS : 0) |
(opt_log_system_bus ? FLATPAK_RUN_FLAG_LOG_SYSTEM_BUS : 0) |
(opt_log_a11y_bus ? FLATPAK_RUN_FLAG_LOG_A11Y_BUS : 0) |
(opt_file_forwarding ? FLATPAK_RUN_FLAG_FILE_FORWARDING : 0),
(opt_file_forwarding ? FLATPAK_RUN_FLAG_FILE_FORWARDING : 0) |
(opt_no_a11y_bus ? FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY : 0),
opt_command,
&argv[rest_argv_start + 1],
rest_argc - 1,

View File

@@ -0,0 +1,338 @@
/*
* Copyright © 2017 Patrick Griffis
*
* 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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Patrick Griffis <tingping@tingping.se>
*/
#include "config.h"
#include <glib/gi18n.h>
#include <appstream-glib.h>
#include "flatpak-builtins.h"
#include "flatpak-builtins-utils.h"
#include "flatpak-dir.h"
#include "flatpak-table-printer.h"
#include "flatpak-utils.h"
/* Appstream data expires after a day */
#define FLATPAK_APPSTREAM_TTL 86400
static GPtrArray *
get_remote_stores (GPtrArray *dirs, GCancellable *cancellable)
{
GError *error = NULL;
GPtrArray *ret = g_ptr_array_new_with_free_func (g_object_unref);
const char **arches = flatpak_get_arches ();
guint i,j,k;
for (i = 0; i < dirs->len; ++i)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
g_autofree char *install_path = NULL;
g_auto(GStrv) remotes = NULL;
flatpak_log_dir_access (dir);
install_path = g_file_get_path (flatpak_dir_get_path (dir));
remotes = flatpak_dir_list_enumerated_remotes (dir, cancellable, &error);
if (error)
{
g_warning ("%s", error->message);
g_clear_error (&error);
continue;
}
else if (remotes == NULL)
continue;
for (j = 0; remotes[j]; ++j)
{
g_autoptr(AsStore) store = as_store_new ();
#if AS_CHECK_VERSION(0, 6, 1)
// We want to see multiple versions/branches of same app-id's, e.g. org.gnome.Platform
as_store_set_add_flags (store, as_store_get_add_flags (store) | AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
#endif
for (k = 0; arches[k]; ++k)
{
g_autofree char *appstream_path = g_build_filename (install_path, "appstream", remotes[j],
arches[k], "active", "appstream.xml.gz",
NULL);
g_autoptr(GFile) appstream_file = g_file_new_for_path (appstream_path);
as_store_from_file (store, appstream_file, NULL, cancellable, &error);
if (error)
{
// We want to ignore this error as it is harmless and valid
// NOTE: appstream-glib doesn't have granular file-not-found error
if (!g_str_has_suffix (error->message, "No such file or directory"))
g_warning ("%s", error->message);
g_clear_error (&error);
continue;
}
}
g_object_set_data_full (G_OBJECT(store), "remote-name", g_strdup (remotes[j]), g_free);
g_ptr_array_add (ret, g_steal_pointer (&store));
}
}
return ret;
}
static void
clear_app_arches (AsApp *app)
{
GPtrArray *arches = as_app_get_architectures (app);
g_ptr_array_set_size (arches, 0);
}
typedef struct MatchResult {
AsApp *app;
GPtrArray *remotes;
guint score;
} MatchResult;
static void
match_result_free (MatchResult *result)
{
g_object_unref (result->app);
g_ptr_array_unref (result->remotes);
g_free (result);
}
static MatchResult *
match_result_new (AsApp *app, guint score)
{
MatchResult *result = g_new (MatchResult, 1);
result->app = g_object_ref (app);
result->remotes = g_ptr_array_new_with_free_func (g_free);
result->score = score;
clear_app_arches (result->app);
return result;
}
static void
match_result_add_remote (MatchResult *self, const char *remote)
{
guint i;
for (i = 0; i < self->remotes->len; ++i)
{
const char *remote_entry = g_ptr_array_index (self->remotes, i);
if (!strcmp (remote, remote_entry))
return;
}
g_ptr_array_add (self->remotes, g_strdup(remote));
}
static int
compare_by_score (MatchResult *a, MatchResult *b, gpointer user_data)
{
// Reverse order, higher score comes first
return (int)b->score - (int)a->score;
}
#if !AS_CHECK_VERSION(0, 6, 1)
/* Roughly copied directly from appstream-glib */
static const gchar *
as_app_fix_unique_nullable (const gchar *tmp)
{
if (tmp == NULL || tmp[0] == '\0')
return "*";
return tmp;
}
static char *
as_app_get_unique_id (AsApp *app)
{
const gchar *id_str = NULL;
const gchar *kind_str = NULL;
AsAppKind kind = as_app_get_kind (app);
if (kind != AS_APP_KIND_UNKNOWN)
kind_str = as_app_kind_to_string (kind);
id_str = as_app_get_id_no_prefix (app);
return g_strdup_printf ("%s/%s",
as_app_fix_unique_nullable (kind_str),
as_app_fix_unique_nullable (id_str));
}
static gboolean
as_app_equal (AsApp *app1, AsApp *app2)
{
if (app1 == app2)
return TRUE;
g_autofree char *app1_id = as_app_get_unique_id (app1);
g_autofree char *app2_id = as_app_get_unique_id (app2);
return strcmp (app1_id, app2_id) == 0;
}
#endif
static int
compare_apps (MatchResult *a, AsApp *b)
{
/* For now we want to ignore arch when comparing applications
* It may be valuable to show runtime arches in the future though.
* This is a naughty hack but for our purposes totally fine.
*/
clear_app_arches (b);
return !as_app_equal (a->app, b);
}
static const char *
get_comment_localized (AsApp *app)
{
const char * const * languages = g_get_language_names ();
gsize i;
for (i = 0; languages[i]; ++i)
{
const char *comment = as_app_get_comment (app, languages[i]);
if (comment != NULL)
return comment;
}
return NULL;
}
static void
print_app (MatchResult *res, FlatpakTablePrinter *printer)
{
AsRelease *release = as_app_get_release_default (res->app);
const char *version = release ? as_release_get_version (release) : NULL;
const char *id = as_app_get_id_filename (res->app);
guint i;
flatpak_table_printer_add_column (printer, id);
flatpak_table_printer_add_column (printer, version);
#if AS_CHECK_VERSION(0, 6, 1)
flatpak_table_printer_add_column (printer, as_app_get_branch (res->app));
#endif
flatpak_table_printer_add_column (printer, g_ptr_array_index (res->remotes, 0));
for (i = 1; i < res->remotes->len; ++i)
flatpak_table_printer_append_with_comma (printer, g_ptr_array_index (res->remotes, i));
flatpak_table_printer_add_column (printer, get_comment_localized (res->app));
flatpak_table_printer_finish_row (printer);
}
gboolean
flatpak_builtin_search (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GPtrArray) dirs = NULL;
g_autoptr(GOptionContext) context = g_option_context_new (_("TEXT - Search remote apps/runtimes for text"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
const char **arches = flatpak_get_arches ();
int i;
if (!flatpak_option_context_parse (context, NULL, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, &dirs, cancellable, error))
return FALSE;
if (argc < 2)
return usage_error (context, _("TEXT must be specified"), error);
for (i = 0; arches[i] != NULL; i++)
{
if (!update_appstream (dirs, NULL, arches[i], FLATPAK_APPSTREAM_TTL, TRUE, cancellable, error))
return FALSE;
}
const char *search_text = argv[1];
GSList *matches = NULL;
guint j;
// We want a store for each remote so we keep the remote information
// as AsApp doesn't currently contain that information
g_autoptr(GPtrArray) remote_stores = get_remote_stores (dirs, cancellable);
for (j = 0; j < remote_stores->len; ++j)
{
AsStore *store = g_ptr_array_index (remote_stores, j);
GPtrArray *apps = as_store_get_apps (store);
guint i;
for (i = 0; i < apps->len; ++i)
{
AsApp *app = g_ptr_array_index (apps, i);
guint score = as_app_search_matches (app, search_text);
if (score == 0)
{
const char *app_id = as_app_get_id_filename (app);
if (strcasestr (app_id, search_text) != NULL)
score = 50;
else
continue;
}
// Avoid duplicate entries, but show multiple remotes
GSList *list_entry = g_slist_find_custom (matches, app,
(GCompareFunc)compare_apps);
MatchResult *result = NULL;
if (list_entry != NULL)
result = list_entry->data;
else
{
result = match_result_new (app, score);
matches = g_slist_insert_sorted_with_data (matches, result,
(GCompareDataFunc)compare_by_score, NULL);
}
match_result_add_remote (result,
g_object_get_data (G_OBJECT(store), "remote-name"));
}
}
if (matches != NULL)
{
FlatpakTablePrinter *printer = flatpak_table_printer_new ();
int col = 0;
flatpak_table_printer_set_column_title (printer, col++, _("Application ID"));
flatpak_table_printer_set_column_title (printer, col++, _("Version"));
#if AS_CHECK_VERSION(0, 6, 1)
flatpak_table_printer_set_column_title (printer, col++, _("Branch"));
#endif
flatpak_table_printer_set_column_title (printer, col++, _("Remotes"));
flatpak_table_printer_set_column_title (printer, col++, _("Description"));
g_slist_foreach (matches, (GFunc)print_app, printer);
flatpak_table_printer_print (printer);
flatpak_table_printer_free (printer);
g_slist_free_full (matches, (GDestroyNotify)match_result_free);
}
else
{
g_print ("%s\n", _("No matches found"));
}
return TRUE;
}
gboolean
flatpak_complete_search (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, NULL, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS, NULL, NULL, NULL))
return FALSE;
flatpak_complete_options (completion, global_entries);
flatpak_complete_options (completion, user_entries);
return TRUE;
}

View File

@@ -54,7 +54,8 @@ gboolean
flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
char **prefs = NULL;
int i, j, n_prefs;
const char *default_branch = NULL;
@@ -69,9 +70,13 @@ flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GEr
context = g_option_context_new (_("REF... - Uninstall an application"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR,
&dirs, cancellable, error))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
if (argc < 2)
return usage_error (context, _("Must specify at least one REF"), error);
@@ -156,7 +161,7 @@ flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GEr
{
const char *ref = (char *)g_ptr_array_index (uninstall_refs, i);
const char *pref = strchr (ref, '/') + 1;
g_print ("Uninstalling %s\n", pref);
g_print (_("Uninstalling: %s\n"), pref);
if (!flatpak_dir_uninstall (dir, ref, flags,
cancellable, error))
return FALSE;
@@ -169,13 +174,17 @@ gboolean
flatpak_complete_uninstall (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
FlatpakKinds kinds;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR, &dirs, NULL, NULL))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
switch (completion->argc)

View File

@@ -66,56 +66,6 @@ static GOptionEntry options[] = {
{ NULL }
};
static gboolean
update_appstream (FlatpakDir *dir, const char *remote, GCancellable *cancellable, GError **error)
{
gboolean changed;
gboolean res;
if (opt_arch == NULL)
opt_arch = (char *)flatpak_get_arch ();
if (remote == NULL)
{
g_auto(GStrv) remotes = NULL;
int i;
remotes = flatpak_dir_list_remotes (dir, cancellable, error);
if (remotes == NULL)
return FALSE;
for (i = 0; remotes[i] != NULL; i++)
{
g_autoptr(GError) local_error = NULL;
FlatpakTerminalProgress terminal_progress = { 0 };
if (flatpak_dir_get_remote_disabled (dir, remotes[i]))
continue;
g_print (_("Updating appstream for remote %s\n"), remotes[i]);
g_autoptr(OstreeAsyncProgress) progress = flatpak_progress_new (flatpak_terminal_progress_cb, &terminal_progress);
if (!flatpak_dir_update_appstream (dir, remotes[i], opt_arch, &changed,
progress, cancellable, &local_error))
g_printerr (_("Error updating: %s\n"), local_error->message);
ostree_async_progress_finish (progress);
flatpak_terminal_progress_end (&terminal_progress);
}
}
else
{
FlatpakTerminalProgress terminal_progress = { 0 };
g_autoptr(OstreeAsyncProgress) progress = flatpak_progress_new (flatpak_terminal_progress_cb, &terminal_progress);
res = flatpak_dir_update_appstream (dir, remote, opt_arch, &changed,
progress, cancellable, error);
ostree_async_progress_finish (progress);
if (!res)
return FALSE;
flatpak_terminal_progress_end (&terminal_progress);
}
return TRUE;
}
gboolean
flatpak_builtin_update (int argc,
char **argv,
@@ -123,21 +73,26 @@ flatpak_builtin_update (int argc,
GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
char **prefs = NULL;
int i, j, n_prefs;
int i, j, k, n_prefs;
const char *default_branch = NULL;
FlatpakKinds kinds;
g_autoptr(FlatpakTransaction) transaction = NULL;
g_autoptr(GPtrArray) transactions = NULL;
context = g_option_context_new (_("[REF...] - Update applications or runtimes"));
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
if (!flatpak_option_context_parse (context, options, &argc, &argv,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS,
&dirs, cancellable, error))
return FALSE;
if (opt_arch == NULL)
opt_arch = (char *)flatpak_get_arch ();
if (opt_appstream)
return update_appstream (dir, argc >= 2 ? argv[1] : NULL, cancellable, error);
return update_appstream (dirs, argc >= 2 ? argv[1] : NULL, opt_arch, 0, FALSE, cancellable, error);
prefs = &argv[1];
n_prefs = argc - 1;
@@ -149,8 +104,16 @@ flatpak_builtin_update (int argc,
n_prefs = 1;
}
transaction = flatpak_transaction_new (dir, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
transactions = g_ptr_array_new_with_free_func ((GDestroyNotify)flatpak_transaction_free);
for (k = 0; k < dirs->len; k++)
{
FlatpakTransaction *transaction = flatpak_transaction_new (g_ptr_array_index (dirs, k),
opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related, FALSE);
g_ptr_array_add (transactions, transaction);
}
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
g_print (_("Looking for updates...\n"));
@@ -176,64 +139,70 @@ flatpak_builtin_update (int argc,
return FALSE;
}
if (kinds & FLATPAK_KINDS_APP)
for (k = 0; k < dirs->len; k++)
{
g_auto(GStrv) refs = NULL;
FlatpakDir *dir = g_ptr_array_index (dirs, k);
FlatpakTransaction *transaction = g_ptr_array_index (transactions, k);
if (!flatpak_dir_list_refs (dir, "app", &refs,
cancellable,
error))
return FALSE;
for (i = 0; refs != NULL && refs[i] != NULL; i++)
if (kinds & FLATPAK_KINDS_APP)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], error);
if (parts == NULL)
g_auto(GStrv) refs = NULL;
if (!flatpak_dir_list_refs (dir, "app", &refs,
cancellable,
error))
return FALSE;
if (id != NULL && strcmp (parts[1], id) != 0)
continue;
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], error);
if (parts == NULL)
return FALSE;
if (arch != NULL && strcmp (parts[2], arch) != 0)
continue;
if (id != NULL && strcmp (parts[1], id) != 0)
continue;
if (branch != NULL && strcmp (parts[3], branch) != 0)
continue;
if (arch != NULL && strcmp (parts[2], arch) != 0)
continue;
found = TRUE;
if (!flatpak_transaction_add_update (transaction, refs[i], (const char **)opt_subpaths, opt_commit, error))
return FALSE;
if (branch != NULL && strcmp (parts[3], branch) != 0)
continue;
found = TRUE;
if (!flatpak_transaction_add_update (transaction, refs[i], (const char **)opt_subpaths, opt_commit, error))
return FALSE;
}
}
}
if (kinds & FLATPAK_KINDS_RUNTIME)
{
g_auto(GStrv) refs = NULL;
if (!flatpak_dir_list_refs (dir, "runtime", &refs,
cancellable,
error))
return FALSE;
for (i = 0; refs != NULL && refs[i] != NULL; i++)
if (kinds & FLATPAK_KINDS_RUNTIME)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], error);
g_auto(GStrv) refs = NULL;
if (parts == NULL)
if (!flatpak_dir_list_refs (dir, "runtime", &refs,
cancellable,
error))
return FALSE;
if (id != NULL && strcmp (parts[1], id) != 0)
continue;
for (i = 0; refs != NULL && refs[i] != NULL; i++)
{
g_auto(GStrv) parts = flatpak_decompose_ref (refs[i], error);
if (arch != NULL && strcmp (parts[2], arch) != 0)
continue;
if (parts == NULL)
return FALSE;
if (branch != NULL && strcmp (parts[3], branch) != 0)
continue;
if (id != NULL && strcmp (parts[1], id) != 0)
continue;
found = TRUE;
if (!flatpak_transaction_add_update (transaction, refs[i], (const char **)opt_subpaths, opt_commit, error))
return FALSE;
if (arch != NULL && strcmp (parts[2], arch) != 0)
continue;
if (branch != NULL && strcmp (parts[3], branch) != 0)
continue;
found = TRUE;
if (!flatpak_transaction_add_update (transaction, refs[i], (const char **)opt_subpaths, opt_commit, error))
return FALSE;
}
}
}
@@ -245,11 +214,22 @@ flatpak_builtin_update (int argc,
}
}
if (!flatpak_transaction_update_metadata (transaction, n_prefs == 0, cancellable, error))
return FALSE;
for (k = 0; k < dirs->len; k++)
{
FlatpakTransaction *transaction = g_ptr_array_index (transactions, k);
if (!flatpak_transaction_run (transaction, FALSE, cancellable, error))
return FALSE;
if (!flatpak_transaction_is_empty (transaction))
{
if (!flatpak_transaction_update_metadata (transaction, n_prefs == 0, cancellable, error))
return FALSE;
if (!flatpak_transaction_run (transaction, FALSE, cancellable, error))
return FALSE;
}
}
if (n_prefs == 0)
return update_appstream (dirs, NULL, opt_arch, 0, FALSE, cancellable, error);
return TRUE;
}
@@ -258,13 +238,17 @@ gboolean
flatpak_complete_update (FlatpakCompletion *completion)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
FlatpakDir *dir;
FlatpakKinds kinds;
context = g_option_context_new ("");
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
FLATPAK_BUILTIN_FLAG_ONE_DIR, &dirs, NULL, NULL))
return FALSE;
dir = g_ptr_array_index (dirs, 0);
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
switch (completion->argc)

View File

@@ -326,3 +326,205 @@ flatpak_load_gpg_keys (char **gpg_import,
return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output_stream));
}
gboolean
flatpak_resolve_duplicate_remotes (GPtrArray *dirs,
const char *remote_name,
FlatpakDir **out_dir,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GPtrArray) dirs_with_remote = NULL;
int chosen = 0;
int i;
dirs_with_remote = g_ptr_array_new ();
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
g_auto(GStrv) remotes = NULL;
int j = 0;
remotes = flatpak_dir_list_remotes (dir, cancellable, error);
if (remotes == NULL)
return FALSE;
for (j = 0; remotes[j] != NULL; j++)
{
const char *this_remote = remotes[j];
if (g_strcmp0 (remote_name, this_remote) == 0)
g_ptr_array_add (dirs_with_remote, dir);
}
}
if (dirs_with_remote->len == 1)
chosen = 1;
else if (dirs_with_remote->len > 1)
{
g_print (_("Remote %s found in multiple installations:\n"), remote_name);
for (i = 0; i < dirs_with_remote->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs_with_remote, i);
g_autofree char *dir_name = flatpak_dir_get_name (dir);
g_print("%d) %s\n", i + 1, dir_name);
}
chosen = flatpak_number_prompt (0, dirs_with_remote->len, _("Which do you want to use (0 to abort)?"));
if (chosen == 0)
return flatpak_fail (error, _("No remote chosen to resolve %s which exists in multiple installations"), remote_name);
}
if (out_dir)
{
if (dirs_with_remote->len == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Remote \"%s\" not found", remote_name);
return FALSE;
}
else
*out_dir = g_object_ref (g_ptr_array_index (dirs_with_remote, chosen - 1));
}
return TRUE;
}
/* Returns: the time in seconds since the file was modified, or %G_MAXUINT64 on error */
static guint64
get_file_age (GFile *file)
{
guint64 now;
guint64 mtime;
g_autoptr(GFileInfo) info = NULL;
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_TIME_MODIFIED,
G_FILE_QUERY_INFO_NONE,
NULL,
NULL);
if (info == NULL)
return G_MAXUINT64;
mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
now = (guint64) g_get_real_time () / G_USEC_PER_SEC;
if (mtime > now)
return G_MAXUINT64;
return (guint64) (now - mtime);
}
static void
no_progress_cb (OstreeAsyncProgress *progress, gpointer user_data)
{
}
gboolean
update_appstream (GPtrArray *dirs,
const char *remote,
const char *arch,
guint64 ttl,
gboolean quiet,
GCancellable *cancellable,
GError **error)
{
gboolean changed;
gboolean res;
int i, j;
g_return_val_if_fail (dirs != NULL, FALSE);
g_return_val_if_fail (arch != NULL, FALSE);
if (remote == NULL)
{
g_auto(GStrv) remotes = NULL;
for (j = 0; j < dirs->len; j++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, j);
remotes = flatpak_dir_list_remotes (dir, cancellable, error);
if (remotes == NULL)
return FALSE;
for (i = 0; remotes[i] != NULL; i++)
{
g_autoptr(GError) local_error = NULL;
g_autoptr(OstreeAsyncProgress) progress = NULL;
g_autoptr(GFile) ts_file = NULL;
g_autofree char *ts_file_path = NULL;
g_autofree char *subdir = NULL;
guint64 ts_file_age;
subdir = g_strdup_printf ("appstream/%s/%s/.timestamp", remotes[i], arch);
ts_file = g_file_resolve_relative_path (flatpak_dir_get_path (dir), subdir);
ts_file_path = g_file_get_path (ts_file);
ts_file_age = get_file_age (ts_file);
if (ts_file_age < ttl)
{
g_debug ("%s age %" G_GUINT64_FORMAT " is less than ttl %" G_GUINT64_FORMAT, ts_file_path, ts_file_age, ttl);
continue;
}
else
g_debug ("%s age %" G_GUINT64_FORMAT " is greater than ttl %" G_GUINT64_FORMAT, ts_file_path, ts_file_age, ttl);
if (flatpak_dir_get_remote_disabled (dir, remotes[i]) ||
flatpak_dir_get_remote_noenumerate (dir, remotes[i]) ||
!flatpak_dir_check_for_appstream_update (dir, remotes[i], arch))
continue;
if (flatpak_dir_is_user (dir))
{
if (quiet)
g_debug (_("Updating appstream data for user remote %s\n"), remotes[i]);
else
g_print (_("Updating appstream data for user remote %s\n"), remotes[i]);
}
else
{
if (quiet)
g_debug (_("Updating appstream data for remote %s\n"), remotes[i]);
else
g_print (_("Updating appstream data for remote %s\n"), remotes[i]);
}
progress = ostree_async_progress_new_and_connect (no_progress_cb, NULL);
if (!flatpak_dir_update_appstream (dir, remotes[i], arch, &changed,
progress, cancellable, &local_error))
g_printerr (_("Error updating: %s\n"), local_error->message);
ostree_async_progress_finish (progress);
}
}
}
else
{
gboolean found = FALSE;
for (j = 0; j < dirs->len; j++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, j);
if (flatpak_dir_has_remote (dir, remote))
{
g_autoptr(OstreeAsyncProgress) progress = NULL;
found = TRUE;
/* Early bail out check */
if (!flatpak_dir_check_for_appstream_update (dir, remote, arch))
continue;
progress = ostree_async_progress_new_and_connect (no_progress_cb, NULL);
res = flatpak_dir_update_appstream (dir, remote, arch, &changed,
progress, cancellable, error);
ostree_async_progress_finish (progress);
if (!res)
return FALSE;
}
}
if (!found)
return flatpak_fail (error, _("Remote \"%s\" not found"), remote);
}
return TRUE;
}

View File

@@ -46,4 +46,18 @@ FlatpakDir * flatpak_find_installed_pref (const char *pref,
GCancellable *cancellable,
GError **error);
gboolean flatpak_resolve_duplicate_remotes (GPtrArray *dirs,
const char *remote_name,
FlatpakDir **out_dir,
GCancellable *cancellable,
GError **error);
gboolean update_appstream (GPtrArray *dirs,
const char *remote,
const char *arch,
guint64 ttl,
gboolean quiet,
GCancellable *cancellable,
GError **error);
#endif /* __FLATPAK_BUILTINS_UTILS_H__ */

View File

@@ -31,7 +31,10 @@ G_BEGIN_DECLS
typedef enum {
FLATPAK_BUILTIN_FLAG_NO_DIR = 1 << 0,
FLATPAK_BUILTIN_FLAG_NO_REPO = 1 << 1,
FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO = 1 << 1,
FLATPAK_BUILTIN_FLAG_ONE_DIR = 1 << 2,
FLATPAK_BUILTIN_FLAG_STANDARD_DIRS = 1 << 3,
FLATPAK_BUILTIN_FLAG_ALL_DIRS = 1 << 4,
} FlatpakBuiltinFlags;
gboolean flatpak_option_context_parse (GOptionContext *context,
@@ -39,7 +42,7 @@ gboolean flatpak_option_context_parse (GOptionContext *context,
int *argc,
char ***argv,
FlatpakBuiltinFlags flags,
FlatpakDir **out_dir,
GPtrArray **out_dirs,
GCancellable *cancellable,
GError **error);
@@ -59,6 +62,7 @@ BUILTINPROTO (add_remote)
BUILTINPROTO (modify_remote)
BUILTINPROTO (delete_remote)
BUILTINPROTO (ls_remote)
BUILTINPROTO (info_remote)
BUILTINPROTO (list_remotes)
BUILTINPROTO (install)
BUILTINPROTO (update)
@@ -85,6 +89,7 @@ BUILTINPROTO (document_list)
BUILTINPROTO (override)
BUILTINPROTO (repo)
BUILTINPROTO (config)
BUILTINPROTO (search)
#undef BUILTINPROTO

View File

@@ -40,7 +40,8 @@ static gboolean opt_default_arch;
static gboolean opt_supported_arches;
static gboolean opt_gl_drivers;
static gboolean opt_user;
static char *opt_installation;
static gboolean opt_system;
static char **opt_installations;
static gboolean is_in_complete;
@@ -66,6 +67,10 @@ static FlatpakCommand commands[] = {
{ "info", N_("Show info for installed app or runtime"), flatpak_builtin_info, flatpak_complete_info },
{ "config", N_("Configure flatpak"), flatpak_builtin_config, flatpak_complete_config },
/* translators: please keep the leading newline and space */
{ N_("\n Finding applications and runtimes") },
{ "search", N_("Search for remote apps/runtimes"), flatpak_builtin_search, flatpak_complete_search },
/* translators: please keep the leading newline and space */
{ N_("\n Running applications") },
{ "run", N_("Run an application"), flatpak_builtin_run, flatpak_complete_run },
@@ -88,6 +93,7 @@ static FlatpakCommand commands[] = {
{ "remote-delete", N_("Delete a configured remote"), flatpak_builtin_delete_remote, flatpak_complete_delete_remote },
{ "remote-list", NULL, flatpak_builtin_list_remotes, flatpak_complete_list_remotes, TRUE },
{ "remote-ls", N_("List contents of a configured remote"), flatpak_builtin_ls_remote, flatpak_complete_ls_remote },
{ "remote-info", N_("Show information about a remote app or runtime"), flatpak_builtin_info_remote, flatpak_complete_info_remote },
/* translators: please keep the leading newline and space */
{ N_("\n Build applications") },
@@ -95,7 +101,7 @@ static FlatpakCommand commands[] = {
{ "build", N_("Run a build command inside the build dir"), flatpak_builtin_build, flatpak_complete_build },
{ "build-finish", N_("Finish a build dir for export"), flatpak_builtin_build_finish, flatpak_complete_build_finish },
{ "build-export", N_("Export a build dir to a repository"), flatpak_builtin_build_export, flatpak_complete_build_export },
{ "build-bundle", N_("Create a bundle file from a build directory"), flatpak_builtin_build_bundle, flatpak_complete_build_bundle },
{ "build-bundle", N_("Create a bundle file from a ref in a local repository"), flatpak_builtin_build_bundle, flatpak_complete_build_bundle },
{ "build-import-bundle", N_("Import a bundle file"), flatpak_builtin_build_import, flatpak_complete_build_import },
{ "build-sign", N_("Sign an application or runtime"), flatpak_builtin_build_sign, flatpak_complete_build_sign },
{ "build-update-repo", N_("Update the summary file in a repository"), flatpak_builtin_build_update_repo, flatpak_complete_build_update_repo },
@@ -133,8 +139,8 @@ static GOptionEntry empty_entries[] = {
GOptionEntry user_entries[] = {
{ "user", 0, 0, G_OPTION_ARG_NONE, &opt_user, N_("Work on user installations"), NULL },
{ "system", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_user, N_("Work on system-wide installations (default)"), NULL },
{ "installation", 0, 0, G_OPTION_ARG_STRING, &opt_installation, N_("Work on a specific system-wide installation"), N_("NAME") },
{ "system", 0, 0, G_OPTION_ARG_NONE, &opt_system, N_("Work on system-wide installations (default)"), NULL },
{ "installation", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_installations, N_("Work on specific system-wide installation(s)"), N_("NAME") },
{ NULL }
};
@@ -146,7 +152,7 @@ message_handler (const gchar *log_domain,
{
/* Make this look like normal console output */
if (log_level & G_LOG_LEVEL_DEBUG)
g_printerr ("XA: %s\n", message);
g_printerr ("F: %s\n", message);
else
g_printerr ("%s: %s\n", g_get_prgname (), message);
}
@@ -216,11 +222,32 @@ flatpak_option_context_parse (GOptionContext *context,
int *argc,
char ***argv,
FlatpakBuiltinFlags flags,
FlatpakDir **out_dir,
GPtrArray **out_dirs,
GCancellable *cancellable,
GError **error)
{
g_autoptr(FlatpakDir) dir = NULL;
g_autoptr(GPtrArray) dirs = NULL;
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_DIR) &&
!(flags & FLATPAK_BUILTIN_FLAG_ONE_DIR) &&
!(flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS) &&
!(flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS))
g_assert_not_reached ();
if (flags & FLATPAK_BUILTIN_FLAG_NO_DIR &&
(flags & FLATPAK_BUILTIN_FLAG_ONE_DIR ||
flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS ||
flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS))
g_assert_not_reached ();
if (flags & FLATPAK_BUILTIN_FLAG_ONE_DIR &&
(flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS ||
flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS))
g_assert_not_reached ();
if (flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS &&
flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS)
g_assert_not_reached ();
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_DIR))
g_option_context_add_main_entries (context, user_entries, NULL);
@@ -277,29 +304,102 @@ flatpak_option_context_parse (GOptionContext *context,
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_DIR))
{
if (opt_user)
dir = flatpak_dir_get_user ();
else if (opt_installation == NULL)
dir = flatpak_dir_get_system_default ();
else
dirs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
int i;
if (!(flags & FLATPAK_BUILTIN_FLAG_ONE_DIR))
{
dir = flatpak_dir_get_system_by_id (opt_installation, cancellable, error);
if (dir == NULL)
return FALSE;
/*
* FLATPAK_BUILTIN_FLAG_STANDARD_DIRS or FLATPAK_BUILTIN_FLAG_ALL_DIRS
* must be set.
*/
if (opt_user || (!opt_system && opt_installations == NULL))
g_ptr_array_add (dirs, flatpak_dir_get_user ());
if (opt_system || (!opt_user && opt_installations == NULL))
g_ptr_array_add (dirs, flatpak_dir_get_system_default ());
if (opt_installations != NULL)
{
for (i = 0; opt_installations[i] != NULL; i++)
{
FlatpakDir *installation_dir = NULL;
/* Already included the default system installation */
if (opt_system && g_strcmp0 (opt_installations[i], "default") == 0)
continue;
installation_dir = flatpak_dir_get_system_by_id (opt_installations[i], cancellable, error);
if (installation_dir == NULL)
return FALSE;
g_ptr_array_add (dirs, installation_dir);
}
}
if (flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS &&
opt_installations == NULL && !opt_user && !opt_system)
{
g_autoptr(GPtrArray) system_dirs = NULL;
g_ptr_array_set_size (dirs, 0);
g_ptr_array_add (dirs, flatpak_dir_get_user ());
system_dirs = flatpak_dir_get_system_list (cancellable, error);
if (system_dirs == NULL)
return FALSE;
for (i = 0; i < system_dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (system_dirs, i);
g_ptr_array_add (dirs, g_object_ref (dir));
}
}
}
else /* FLATPAK_BUILTIN_FLAG_ONE_DIR */
{
FlatpakDir *dir;
if (opt_system || (!opt_user && opt_installations == NULL))
dir = flatpak_dir_get_system_default ();
else if (opt_user)
dir = flatpak_dir_get_user ();
else if (opt_installations != NULL)
{
if (g_strv_length (opt_installations) > 1)
return usage_error (context, _("The --installation option was used multiple times "
"for a command that works on one installation"), error);
dir = flatpak_dir_get_system_by_id (opt_installations[0], cancellable, error);
if (dir == NULL)
return FALSE;
}
else
g_assert_not_reached ();
g_ptr_array_add (dirs, dir);
}
if (!flatpak_dir_ensure_path (dir, cancellable, error))
return FALSE;
for (i = 0; i < dirs->len; i++)
{
FlatpakDir *dir = g_ptr_array_index (dirs, i);
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_REPO) &&
!flatpak_dir_ensure_repo (dir, cancellable, error))
return FALSE;
if (flags & FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO)
{
if (!flatpak_dir_maybe_ensure_repo (dir, cancellable, error))
return FALSE;
}
else
{
if (!flatpak_dir_ensure_repo (dir, cancellable, error))
return FALSE;
}
flatpak_log_dir_access (dir);
flatpak_log_dir_access (dir);
}
}
if (out_dir)
*out_dir = g_steal_pointer (&dir);
if (out_dirs)
*out_dirs = g_steal_pointer (&dirs);
return TRUE;
}

View File

@@ -53,6 +53,7 @@ struct FlatpakTransaction {
GHashTable *refs;
GPtrArray *system_dirs;
GList *ops;
GPtrArray *added_origin_remotes;
gboolean no_interaction;
gboolean no_pull;
@@ -60,8 +61,15 @@ struct FlatpakTransaction {
gboolean no_static_deltas;
gboolean add_deps;
gboolean add_related;
gboolean reinstall;
};
static gboolean
remote_name_is_file (const char *remote_name)
{
return remote_name != NULL &&
g_str_has_prefix (remote_name, "file://");
}
/* Check if the ref is in the dir, or in the system dir, in case its a
* user-dir or another system-wide installation. We want to avoid depending
@@ -157,6 +165,12 @@ flatpak_transaction_operation_free (FlatpakTransactionOp *self)
g_free (self);
}
gboolean
flatpak_transaction_is_empty (FlatpakTransaction *self)
{
return self->ops == NULL;
}
FlatpakTransaction *
flatpak_transaction_new (FlatpakDir *dir,
gboolean no_interaction,
@@ -164,12 +178,14 @@ flatpak_transaction_new (FlatpakDir *dir,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean add_deps,
gboolean add_related)
gboolean add_related,
gboolean reinstall)
{
FlatpakTransaction *t = g_new0 (FlatpakTransaction, 1);
t->dir = g_object_ref (dir);
t->refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
t->added_origin_remotes = g_ptr_array_new_with_free_func (g_free);
t->no_interaction = no_interaction;
t->no_pull = no_pull;
@@ -177,6 +193,7 @@ flatpak_transaction_new (FlatpakDir *dir,
t->no_static_deltas = no_static_deltas;
t->add_deps = add_deps;
t->add_related = add_related;
t->reinstall = reinstall;
return t;
}
@@ -187,6 +204,8 @@ flatpak_transaction_free (FlatpakTransaction *self)
g_list_free_full (self->ops, (GDestroyNotify)flatpak_transaction_operation_free);
g_object_unref (self->dir);
g_ptr_array_unref (self->added_origin_remotes);
if (self->system_dirs != NULL)
g_ptr_array_free (self->system_dirs, TRUE);
@@ -454,6 +473,28 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
g_autofree char *remote_metadata = NULL;
g_autoptr(GKeyFile) metakey = NULL;
g_autoptr(GError) local_error = NULL;
g_autofree char *origin_remote = NULL;
if (remote_name_is_file (remote))
{
g_auto(GStrv) parts = NULL;
parts = g_strsplit (ref, "/", -1);
origin_remote = flatpak_dir_create_origin_remote (self->dir,
remote, /* uri */
parts[1],
"Local repo",
ref,
NULL,
NULL,
NULL, error);
if (origin_remote == NULL)
return FALSE;
g_ptr_array_add (self->added_origin_remotes, g_strdup (origin_remote));
remote = origin_remote;
}
pref = strchr (ref, '/') + 1;
@@ -476,10 +517,20 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
else if (kind == FLATPAK_TRANSACTION_OP_KIND_INSTALL)
{
g_assert (remote != NULL);
if (dir_ref_is_installed (self->dir, ref, NULL, NULL))
if (!self->reinstall &&
dir_ref_is_installed (self->dir, ref, &origin, NULL))
{
g_printerr (_("%s already installed, skipping\n"), pref);
return TRUE;
if (strcmp (remote, origin) == 0)
{
g_printerr (_("%s already installed, skipping\n"), pref);
return TRUE;
}
else
{
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
_("%s is already installed from other remote (%s)"), pref, origin);
return FALSE;
}
}
}
@@ -652,6 +703,7 @@ flatpak_transaction_run (FlatpakTransaction *self,
{
GList *l;
gboolean succeeded = TRUE;
int i;
self->ops = g_list_reverse (self->ops);
@@ -659,7 +711,7 @@ flatpak_transaction_run (FlatpakTransaction *self,
{
FlatpakTransactionOp *op = l->data;
g_autoptr(GError) local_error = NULL;
gboolean res;
gboolean res = TRUE;
const char *pref;
const char *opname;
FlatpakTransactionOpKind kind;
@@ -690,11 +742,15 @@ flatpak_transaction_run (FlatpakTransaction *self,
{
g_autoptr(OstreeAsyncProgress) progress = flatpak_progress_new (flatpak_terminal_progress_cb, &terminal_progress);
opname = _("install");
g_print (_("Installing: %s from %s\n"), pref, op->remote);
res = flatpak_dir_install (self->dir,
if (flatpak_dir_is_user (self->dir))
g_print (_("Installing for user: %s from %s\n"), pref, op->remote);
else
g_print (_("Installing: %s from %s\n"), pref, op->remote);
res = flatpak_dir_install (self->dir ,
self->no_pull,
self->no_deploy,
self->no_static_deltas,
self->reinstall,
op->ref, op->remote,
(const char **)op->subpaths,
progress,
@@ -714,7 +770,10 @@ flatpak_transaction_run (FlatpakTransaction *self,
cancellable, &local_error);
if (target_commit != NULL)
{
g_print (_("Updating: %s from %s\n"), pref, op->remote);
if (flatpak_dir_is_user (self->dir))
g_print (_("Updating for user: %s from %s\n"), pref, op->remote);
else
g_print (_("Updating: %s from %s\n"), pref, op->remote);
g_autoptr(OstreeAsyncProgress) progress = flatpak_progress_new (flatpak_terminal_progress_cb, &terminal_progress);
res = flatpak_dir_update (self->dir,
self->no_pull,
@@ -759,7 +818,10 @@ flatpak_transaction_run (FlatpakTransaction *self,
{
g_autofree char *bundle_basename = g_file_get_basename (op->bundle);
opname = _("install bundle");
g_print (_("Installing: %s from bundle %s\n"), pref, bundle_basename);
if (flatpak_dir_is_user (self->dir))
g_print (_("Installing for user: %s from bundle %s\n"), pref, bundle_basename);
else
g_print (_("Installing: %s from bundle %s\n"), pref, bundle_basename);
res = flatpak_dir_install_bundle (self->dir, op->bundle,
op->remote, NULL,
cancellable, &local_error);
@@ -786,11 +848,17 @@ flatpak_transaction_run (FlatpakTransaction *self,
}
else
{
succeeded = FALSE;
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
goto out;
}
}
}
out:
for (i = 0; i < self->added_origin_remotes->len; i++)
flatpak_dir_prune_origin_remote (self->dir, g_ptr_array_index (self->added_origin_remotes, i));
return succeeded;
}

View File

@@ -34,7 +34,8 @@ FlatpakTransaction *flatpak_transaction_new (FlatpakDir *dir,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean add_deps,
gboolean add_related);
gboolean add_related,
gboolean reinstall);
void flatpak_transaction_free (FlatpakTransaction *self);
gboolean flatpak_transaction_update_metadata (FlatpakTransaction *self,
gboolean all_remotes,
@@ -58,6 +59,7 @@ gboolean flatpak_transaction_add_update (FlatpakTransaction *self,
const char **subpaths,
const char *commit,
GError **error);
gboolean flatpak_transaction_is_empty (FlatpakTransaction *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakTransaction, flatpak_transaction_free)

View File

@@ -8,7 +8,7 @@ dn=$(dirname $0)
pkg_install sudo which attr fuse \
libubsan libasan libtsan \
elfutils git gettext-devel \
elfutils git gettext-devel libappstream-glib-devel \
/usr/bin/{update-mime-database,update-desktop-database,gtk-update-icon-cache}
pkg_install_testing ostree-devel ostree
pkg_install_if_os fedora gjs parallel clang

View File

@@ -1,6 +1,6 @@
noinst_LTLIBRARIES += libflatpak-common.la
dbus_built_sources = common/flatpak-dbus.c common/flatpak-dbus.h
dbus_built_sources = common/flatpak-dbus.c common/flatpak-dbus.h common/flatpak-document-dbus.c common/flatpak-document-dbus.h
systemd_dbus_built_sources = common/flatpak-systemd-dbus.c common/flatpak-systemd-dbus.h
common/flatpak-dbus.c: data/org.freedesktop.Flatpak.xml Makefile
@@ -9,7 +9,16 @@ common/flatpak-dbus.c: data/org.freedesktop.Flatpak.xml Makefile
--interface-prefix org.freedesktop.Flatpak. \
--c-namespace Flatpak \
--generate-c-code $(builddir)/common/flatpak-dbus \
$(srcdir)/data/org.freedesktop.Flatpak.xml \
$(srcdir)/data/org.freedesktop.Flatpak.xml \
$(NULL)
common/flatpak-document-dbus.c: data/org.freedesktop.portal.Documents.xml Makefile
mkdir -p $(builddir)/common
$(AM_V_GEN) $(GDBUS_CODEGEN) \
--interface-prefix org.freedesktop.portal. \
--c-namespace XdpDbus \
--generate-c-code $(builddir)/common/flatpak-document-dbus \
$(srcdir)/data/org.freedesktop.portal.Documents.xml \
$(NULL)
common/flatpak-systemd-dbus.c: data/org.freedesktop.systemd1.xml Makefile
@@ -35,10 +44,16 @@ CLEANFILES += $(nodist_libflatpak_common_la_SOURCES)
libflatpak_common_la_SOURCES = \
common/flatpak-common-types.h \
common/flatpak-bwrap.c \
common/flatpak-bwrap.h \
common/flatpak-dir.c \
common/flatpak-dir.h \
common/flatpak-run.c \
common/flatpak-run.h \
common/flatpak-context.c \
common/flatpak-context.h \
common/flatpak-exports.c \
common/flatpak-exports.h \
common/flatpak-portal-error.c \
common/flatpak-portal-error.h \
common/flatpak-utils.c \
@@ -47,13 +62,6 @@ libflatpak_common_la_SOURCES = \
common/flatpak-table-printer.h \
common/flatpak-chain-input-stream.c \
common/flatpak-chain-input-stream.h \
common/gvdb/gvdb-reader.h \
common/gvdb/gvdb-format.h \
common/gvdb/gvdb-reader.c \
common/gvdb/gvdb-builder.h \
common/gvdb/gvdb-builder.c \
common/flatpak-db.c \
common/flatpak-db.h \
common/flatpak-json.c \
common/flatpak-json.h \
common/flatpak-json-oci.c \

187
common/flatpak-bwrap.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* Copyright © 2014-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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/personality.h>
#include <grp.h>
#include <unistd.h>
#include <gio/gunixfdlist.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include "libglnx/libglnx.h"
#include "flatpak-bwrap.h"
#include "flatpak-utils.h"
static void
clear_fd (gpointer data)
{
int *fd_p = data;
if (fd_p != NULL && *fd_p != -1)
close (*fd_p);
}
FlatpakBwrap *
flatpak_bwrap_new (char **env)
{
FlatpakBwrap *bwrap = g_new0 (FlatpakBwrap, 1);
bwrap->argv = g_ptr_array_new_with_free_func (g_free);
bwrap->fds = g_array_new (FALSE, TRUE, sizeof (int));
g_array_set_clear_func (bwrap->fds, clear_fd);
if (env)
bwrap->envp = g_strdupv (env);
else
bwrap->envp = g_get_environ ();
return bwrap;
}
void
flatpak_bwrap_free (FlatpakBwrap *bwrap)
{
g_ptr_array_unref (bwrap->argv);
g_array_unref (bwrap->fds);
g_strfreev (bwrap->envp);
g_free (bwrap);
}
void
flatpak_bwrap_set_env (FlatpakBwrap *bwrap,
const char *variable,
const char *value,
gboolean overwrite)
{
bwrap->envp = g_environ_setenv (bwrap->envp, variable, value, overwrite);
}
void
flatpak_bwrap_unset_env (FlatpakBwrap *bwrap,
const char *variable)
{
bwrap->envp = g_environ_unsetenv (bwrap->envp, variable);
}
void
flatpak_bwrap_add_args (FlatpakBwrap *bwrap, ...)
{
va_list args;
const gchar *arg;
va_start (args, bwrap);
while ((arg = va_arg (args, const gchar *)))
g_ptr_array_add (bwrap->argv, g_strdup (arg));
va_end (args);
}
void
flatpak_bwrap_append_argsv (FlatpakBwrap *bwrap,
char **args,
int len)
{
int i;
if (len < 0)
len = g_strv_length (args);
for (i = 0; i < len; i++)
g_ptr_array_add (bwrap->argv, g_strdup (args[i]));
}
void
flatpak_bwrap_append_args (FlatpakBwrap *bwrap,
GPtrArray *other_array)
{
flatpak_bwrap_append_argsv (bwrap,
(char **)other_array->pdata,
other_array->len);
}
void
flatpak_bwrap_add_args_data_fd (FlatpakBwrap *bwrap,
const char *op,
int fd,
const char *path_optional)
{
g_autofree char *fd_str = g_strdup_printf ("%d", fd);
g_array_append_val (bwrap->fds, fd);
flatpak_bwrap_add_args (bwrap,
op, fd_str, path_optional,
NULL);
}
/* Given a buffer @content of size @content_size, generate a fd (memfd if available)
* of the data. The @name parameter is used by memfd_create() as a debugging aid;
* it has no semantic meaning. The bwrap command line will inject it into the target
* container as @path.
*/
gboolean
flatpak_bwrap_add_args_data (FlatpakBwrap *bwrap,
const char *name,
const char *content,
gssize content_size,
const char *path,
GError **error)
{
g_auto(GLnxTmpfile) args_tmpf = { 0, };
if (!flatpak_buffer_to_sealed_memfd_or_tmpfile (&args_tmpf, name, content, content_size, error))
return FALSE;
flatpak_bwrap_add_args_data_fd (bwrap, "--bind-data", glnx_steal_fd (&args_tmpf.fd), path);
return TRUE;
}
/* This resolves the target here rather than in bwrap, because it may
* not resolve in bwrap setup due to absolute symlinks conflicting
* with /newroot root. For example, dest could be inside
* ~/.var/app/XXX where XXX is an absolute symlink. However, in the
* usecases here the destination file often doesn't exist, so we
* only resolve the directory part.
*/
void
flatpak_bwrap_add_bind_arg (FlatpakBwrap *bwrap,
const char *type,
const char *src,
const char *dest)
{
g_autofree char *dest_dirname = g_path_get_dirname (dest);
g_autofree char *dest_dirname_real = realpath (dest_dirname, NULL);
if (dest_dirname_real)
{
g_autofree char *dest_basename = g_path_get_basename (dest);
g_autofree char *dest_real = g_build_filename (dest_dirname_real, dest_basename, NULL);
flatpak_bwrap_add_args (bwrap, type, src, dest_real, NULL);
}
}

63
common/flatpak-bwrap.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright © 2014-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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#ifndef __FLATPAK_BWRAP_H__
#define __FLATPAK_BWRAP_H__
typedef struct {
GPtrArray *argv;
GArray *fds;
GStrv envp;
} FlatpakBwrap;
FlatpakBwrap *flatpak_bwrap_new (char **env);
void flatpak_bwrap_free (FlatpakBwrap *bwrap);
void flatpak_bwrap_set_env (FlatpakBwrap *bwrap,
const char *variable,
const char *value,
gboolean overwrite);
void flatpak_bwrap_unset_env (FlatpakBwrap *bwrap,
const char *variable);
void flatpak_bwrap_add_args (FlatpakBwrap *bwrap,
...);
void flatpak_bwrap_append_argsv (FlatpakBwrap *bwrap,
char **args,
int len);
void flatpak_bwrap_append_args (FlatpakBwrap *bwrap,
GPtrArray *other_array);
void flatpak_bwrap_add_args_data_fd (FlatpakBwrap *bwrap,
const char *op,
int fd,
const char *path_optional);
gboolean flatpak_bwrap_add_args_data (FlatpakBwrap *bwrap,
const char *name,
const char *content,
gssize content_size,
const char *path,
GError **error);
void flatpak_bwrap_add_bind_arg (FlatpakBwrap *bwrap,
const char *type,
const char *src,
const char *dest);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakBwrap, flatpak_bwrap_free)
#endif /* __FLATPAK_BWRAP_H__ */

View File

@@ -28,7 +28,6 @@ typedef enum {
typedef struct FlatpakDir FlatpakDir;
typedef struct FlatpakDeploy FlatpakDeploy;
typedef struct FlatpakContext FlatpakContext;
typedef struct FlatpakOciRegistry FlatpakOciRegistry;
typedef struct _FlatpakOciManifest FlatpakOciManifest;

2007
common/flatpak-context.c Normal file
View File

File diff suppressed because it is too large Load Diff

128
common/flatpak-context.h Normal file
View File

@@ -0,0 +1,128 @@
/*
* Copyright © 2014-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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#ifndef __FLATPAK_CONTEXT_H__
#define __FLATPAK_CONTEXT_H__
#include "libglnx/libglnx.h"
#include "dbus-proxy/flatpak-proxy.h"
#include "flatpak-utils.h"
#include "flatpak-exports.h"
typedef struct FlatpakContext FlatpakContext;
typedef enum {
FLATPAK_CONTEXT_SHARED_NETWORK = 1 << 0,
FLATPAK_CONTEXT_SHARED_IPC = 1 << 1,
} FlatpakContextShares;
typedef enum {
FLATPAK_CONTEXT_SOCKET_X11 = 1 << 0,
FLATPAK_CONTEXT_SOCKET_WAYLAND = 1 << 1,
FLATPAK_CONTEXT_SOCKET_PULSEAUDIO = 1 << 2,
FLATPAK_CONTEXT_SOCKET_SESSION_BUS = 1 << 3,
FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS = 1 << 4,
FLATPAK_CONTEXT_SOCKET_FALLBACK_X11 = 1 << 5, /* For backwards compat, also set SOCKET_X11 */
} FlatpakContextSockets;
typedef enum {
FLATPAK_CONTEXT_DEVICE_DRI = 1 << 0,
FLATPAK_CONTEXT_DEVICE_ALL = 1 << 1,
FLATPAK_CONTEXT_DEVICE_KVM = 1 << 2,
} FlatpakContextDevices;
typedef enum {
FLATPAK_CONTEXT_FEATURE_DEVEL = 1 << 0,
FLATPAK_CONTEXT_FEATURE_MULTIARCH = 1 << 1,
} FlatpakContextFeatures;
struct FlatpakContext
{
FlatpakContextShares shares;
FlatpakContextShares shares_valid;
FlatpakContextSockets sockets;
FlatpakContextSockets sockets_valid;
FlatpakContextDevices devices;
FlatpakContextDevices devices_valid;
FlatpakContextFeatures features;
FlatpakContextFeatures features_valid;
GHashTable *env_vars;
GHashTable *persistent;
GHashTable *filesystems;
GHashTable *session_bus_policy;
GHashTable *system_bus_policy;
GHashTable *generic_policy;
};
extern const char *flatpak_context_sockets[];
extern const char *flatpak_context_devices[];
extern const char *flatpak_context_features[];
extern const char *flatpak_context_shares[];
FlatpakContext *flatpak_context_new (void);
void flatpak_context_free (FlatpakContext *context);
void flatpak_context_merge (FlatpakContext *context,
FlatpakContext *other);
GOptionGroup *flatpak_context_get_options (FlatpakContext *context);
void flatpak_context_complete (FlatpakContext *context,
FlatpakCompletion *completion);
gboolean flatpak_context_load_metadata (FlatpakContext *context,
GKeyFile *metakey,
GError **error);
void flatpak_context_save_metadata (FlatpakContext *context,
gboolean flatten,
GKeyFile *metakey);
void flatpak_context_allow_host_fs (FlatpakContext *context);
void flatpak_context_set_session_bus_policy (FlatpakContext *context,
const char *name,
FlatpakPolicy policy);
void flatpak_context_set_system_bus_policy (FlatpakContext *context,
const char *name,
FlatpakPolicy policy);
void flatpak_context_to_args (FlatpakContext *context,
GPtrArray *args);
void flatpak_context_add_bus_filters (FlatpakContext *context,
const char *app_id,
gboolean session_bus,
GPtrArray *dbus_proxy_argv);
gboolean flatpak_context_get_needs_session_bus_proxy (FlatpakContext *context);
gboolean flatpak_context_get_needs_system_bus_proxy (FlatpakContext *context);
gboolean flatpak_context_allows_features (FlatpakContext *context,
FlatpakContextFeatures features);
FlatpakContext *flatpak_context_load_for_deploy (FlatpakDeploy *deploy,
GError **error);
FlatpakContext *flatpak_context_load_for_app (const char *app_id,
GError **error);
FlatpakExports *flatpak_context_get_exports (FlatpakContext *context,
const char *app_id);
void flatpak_context_append_bwrap_filesystem (FlatpakContext *context,
FlatpakBwrap *bwrap,
const char *app_id,
GFile *app_id_dir,
FlatpakExports **exports_out);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakContext, flatpak_context_free)
#endif /* __FLATPAK_CONTEXT_H__ */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +0,0 @@
/* flatpak-db.h
*
* Copyright © 2015 Red Hat, Inc
*
* This file 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 of the
* License, or (at your option) any later version.
*
* This file 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 program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#ifndef FLATPAK_DB_H
#define FLATPAK_DB_H
#include <string.h>
#include "libglnx/libglnx.h"
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct FlatpakDb FlatpakDb;
typedef struct _FlatpakDbEntry FlatpakDbEntry;
#define FLATPAK_TYPE_DB (flatpak_db_get_type ())
#define FLATPAK_DB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FLATPAK_TYPE_DB, FlatpakDb))
#define FLATPAK_IS_DB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FLATPAK_TYPE_DB))
GType flatpak_db_get_type (void);
FlatpakDb * flatpak_db_new (const char *path,
gboolean fail_if_not_found,
GError **error);
char ** flatpak_db_list_ids (FlatpakDb *self);
char ** flatpak_db_list_apps (FlatpakDb *self);
char ** flatpak_db_list_ids_by_app (FlatpakDb *self,
const char *app);
char ** flatpak_db_list_ids_by_value (FlatpakDb *self,
GVariant *data);
FlatpakDbEntry *flatpak_db_lookup (FlatpakDb *self,
const char *id);
GString * flatpak_db_print_string (FlatpakDb *self,
GString *string);
char * flatpak_db_print (FlatpakDb *self);
gboolean flatpak_db_is_dirty (FlatpakDb *self);
void flatpak_db_set_entry (FlatpakDb *self,
const char *id,
FlatpakDbEntry *entry);
void flatpak_db_update (FlatpakDb *self);
GBytes * flatpak_db_get_content (FlatpakDb *self);
const char * flatpak_db_get_path (FlatpakDb *self);
gboolean flatpak_db_save_content (FlatpakDb *self,
GError **error);
void flatpak_db_save_content_async (FlatpakDb *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean flatpak_db_save_content_finish (FlatpakDb *self,
GAsyncResult *res,
GError **error);
void flatpak_db_set_path (FlatpakDb *self,
const char *path);
FlatpakDbEntry *flatpak_db_entry_ref (FlatpakDbEntry *entry);
void flatpak_db_entry_unref (FlatpakDbEntry *entry);
GVariant * flatpak_db_entry_get_data (FlatpakDbEntry *entry);
const char ** flatpak_db_entry_list_apps (FlatpakDbEntry *entry);
const char ** flatpak_db_entry_list_permissions (FlatpakDbEntry *entry,
const char *app);
gboolean flatpak_db_entry_has_permission (FlatpakDbEntry *entry,
const char *app,
const char *permission);
gboolean flatpak_db_entry_has_permissions (FlatpakDbEntry *entry,
const char *app,
const char **permissions);
GString * flatpak_db_entry_print_string (FlatpakDbEntry *entry,
GString *string);
FlatpakDbEntry *flatpak_db_entry_new (GVariant *data);
FlatpakDbEntry *flatpak_db_entry_modify_data (FlatpakDbEntry *entry,
GVariant *data);
FlatpakDbEntry *flatpak_db_entry_set_app_permissions (FlatpakDbEntry *entry,
const char *app,
const char **permissions);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDb, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDbEntry, flatpak_db_entry_unref)
G_END_DECLS
#endif /* FLATPAK_DB_H */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,7 @@
#include "libglnx/libglnx.h"
#include <flatpak-common-types.h>
#include <flatpak-context.h>
#define FLATPAK_TYPE_DIR flatpak_dir_get_type ()
#define FLATPAK_DIR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FLATPAK_TYPE_DIR, FlatpakDir))
@@ -88,9 +89,10 @@ typedef enum {
FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE = 1 << 0,
FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY = 1 << 1,
FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL = 1 << 2,
FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL = 1 << 3,
} FlatpakHelperDeployFlags;
#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE|FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY|FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL)
#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE|FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY|FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL|FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL)
typedef enum {
FLATPAK_HELPER_UNINSTALL_FLAGS_NONE = 0,
@@ -133,6 +135,7 @@ typedef enum {
FLATPAK_DIR_STORAGE_TYPE_HARD_DISK,
FLATPAK_DIR_STORAGE_TYPE_SDCARD,
FLATPAK_DIR_STORAGE_TYPE_MMC,
FLATPAK_DIR_STORAGE_TYPE_NETWORK,
} FlatpakDirStorageType;
GQuark flatpak_dir_error_quark (void);
@@ -144,8 +147,10 @@ GQuark flatpak_dir_error_quark (void);
typedef void OstreeRepoFinderResult;
typedef void** OstreeRepoFinderResultv;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderResult, void)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, void, NULL)
static inline void no_op (gpointer data) {}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderResult, no_op)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, no_op, NULL)
#endif /* !FLATPAK_ENABLE_P2P */
/**
@@ -316,6 +321,9 @@ gboolean flatpak_dir_recreate_repo (FlatpakDir *self,
gboolean flatpak_dir_ensure_repo (FlatpakDir *self,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_maybe_ensure_repo (FlatpakDir *self,
GCancellable *cancellable,
GError **error);
char * flatpak_dir_get_config (FlatpakDir *self,
const char *key,
GError **error);
@@ -335,6 +343,17 @@ gboolean flatpak_dir_deploy_appstream (FlatpakDir *self,
gboolean *out_changed,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_find_latest_rev (FlatpakDir *self,
const char *remote,
const char *ref,
const char *checksum_or_latest,
char **out_rev,
OstreeRepoFinderResult ***out_results,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_check_for_appstream_update (FlatpakDir *self,
const char *remote,
const char *arch);
gboolean flatpak_dir_update_appstream (FlatpakDir *self,
const char *remote,
const char *arch,
@@ -430,12 +449,14 @@ gboolean flatpak_dir_deploy_install (FlatpakDir *self,
const char *ref,
const char *origin,
const char **subpaths,
gboolean reinstall,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_install (FlatpakDir *self,
gboolean no_pull,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean reinstall,
const char *ref,
const char *remote_name,
const char **subpaths,
@@ -540,6 +561,8 @@ char *flatpak_dir_create_origin_remote (FlatpakDir *self,
const char *collection_id,
GCancellable *cancellable,
GError **error);
void flatpak_dir_prune_origin_remote (FlatpakDir *self,
const char *remote);
gboolean flatpak_dir_create_remote_for_ref_file (FlatpakDir *self,
GBytes *data,
const char *default_arch,
@@ -560,6 +583,8 @@ GKeyFile * flatpak_dir_parse_repofile (FlatpakDir *self,
char *flatpak_dir_find_remote_by_uri (FlatpakDir *self,
const char *uri,
const char *collection_id);
gboolean flatpak_dir_has_remote (FlatpakDir *self,
const char *remote_name);
char **flatpak_dir_list_remotes (FlatpakDir *self,
GCancellable *cancellable,
GError **error);
@@ -612,6 +637,13 @@ char * flatpak_dir_fetch_remote_default_branch (FlatpakDir *self,
const char *remote,
GCancellable *cancellable,
GError **error);
GVariant * flatpak_dir_fetch_remote_commit (FlatpakDir *self,
const char *remote_name,
const char *ref,
const char *opt_commit,
char **out_commit,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_update_remote_configuration (FlatpakDir *self,
const char *remote,
GCancellable *cancellable,

530
common/flatpak-exports.c Normal file
View File

@@ -0,0 +1,530 @@
/*
* Copyright © 2014-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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/personality.h>
#include <grp.h>
#include <unistd.h>
#include <gio/gunixfdlist.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include "libglnx/libglnx.h"
#include "flatpak-exports.h"
#include "flatpak-run.h"
#include "flatpak-proxy.h"
#include "flatpak-utils.h"
#include "flatpak-dir.h"
#include "flatpak-systemd-dbus.h"
#include "lib/flatpak-error.h"
/* We don't want to export paths pointing into these, because they are readonly
(so we can't create mountpoints there) and don't match whats on the host anyway */
const char *dont_export_in[] = {
"/lib", "/lib32", "/lib64", "/bin", "/sbin", "/usr", "/etc", "/app", "/dev", NULL
};
static char *
make_relative (const char *base, const char *path)
{
GString *s = g_string_new ("");
while (*base != 0)
{
while (*base == '/')
base++;
if (*base != 0)
g_string_append (s, "../");
while (*base != '/' && *base != 0)
base++;
}
while (*path == '/')
path++;
g_string_append (s, path);
return g_string_free (s, FALSE);
}
#define FAKE_MODE_DIR -1 /* Ensure a dir, either on tmpfs or mapped parent */
#define FAKE_MODE_TMPFS 0
#define FAKE_MODE_SYMLINK G_MAXINT
typedef struct {
char *path;
gint mode;
} ExportedPath;
struct _FlatpakExports {
GHashTable *hash;
FlatpakFilesystemMode host_fs;
};
static void
exported_path_free (ExportedPath *exported_path)
{
g_free (exported_path->path);
g_free (exported_path);
}
FlatpakExports *
flatpak_exports_new (void)
{
FlatpakExports *exports = g_new0 (FlatpakExports, 1);
exports->hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GFreeFunc)exported_path_free);
return exports;
}
void
flatpak_exports_free (FlatpakExports *exports)
{
g_hash_table_destroy (exports->hash);
g_free (exports);
}
/* Returns TRUE if the location of this export
is not visible due to parents being exported */
static gboolean
path_parent_is_mapped (const char **keys,
guint n_keys,
GHashTable *hash_table,
const char *path)
{
guint i;
gboolean is_mapped = FALSE;
/* The keys are sorted so shorter (i.e. parents) are first */
for (i = 0; i < n_keys; i++)
{
const char *mounted_path = keys[i];
ExportedPath *ep = g_hash_table_lookup (hash_table, mounted_path);
if (flatpak_has_path_prefix (path, mounted_path) &&
(strcmp (path, mounted_path) != 0))
{
/* FAKE_MODE_DIR has same mapped value as parent */
if (ep->mode == FAKE_MODE_DIR)
continue;
is_mapped = ep->mode != FAKE_MODE_TMPFS;
}
}
return is_mapped;
}
static gboolean
path_is_mapped (const char **keys,
guint n_keys,
GHashTable *hash_table,
const char *path,
gboolean *is_readonly_out)
{
guint i;
gboolean is_mapped = FALSE;
gboolean is_readonly = FALSE;
/* The keys are sorted so shorter (i.e. parents) are first */
for (i = 0; i < n_keys; i++)
{
const char *mounted_path = keys[i];
ExportedPath *ep = g_hash_table_lookup (hash_table, mounted_path);
if (flatpak_has_path_prefix (path, mounted_path))
{
/* FAKE_MODE_DIR has same mapped value as parent */
if (ep->mode == FAKE_MODE_DIR)
continue;
if (ep->mode == FAKE_MODE_SYMLINK)
is_mapped = strcmp (path, mounted_path) == 0;
else
is_mapped = ep->mode != FAKE_MODE_TMPFS;
if (is_mapped)
is_readonly = ep->mode == FLATPAK_FILESYSTEM_MODE_READ_ONLY;
else
is_readonly = FALSE;
}
}
*is_readonly_out = is_readonly;
return is_mapped;
}
static gint
compare_eps (const ExportedPath *a,
const ExportedPath *b)
{
return g_strcmp0 (a->path, b->path);
}
/* This differs from g_file_test (path, G_FILE_TEST_IS_DIR) which
returns true if the path is a symlink to a dir */
static gboolean
path_is_dir (const char *path)
{
struct stat s;
if (lstat (path, &s) != 0)
return FALSE;
return S_ISDIR (s.st_mode);
}
static gboolean
path_is_symlink (const char *path)
{
struct stat s;
if (lstat (path, &s) != 0)
return FALSE;
return S_ISLNK (s.st_mode);
}
void
flatpak_exports_append_bwrap_args (FlatpakExports *exports,
FlatpakBwrap *bwrap)
{
guint n_keys;
g_autofree const char **keys = (const char **)g_hash_table_get_keys_as_array (exports->hash, &n_keys);
g_autoptr(GList) eps = NULL;
GList *l;
eps = g_hash_table_get_values (exports->hash);
eps = g_list_sort (eps, (GCompareFunc)compare_eps);
g_qsort_with_data (keys, n_keys, sizeof (char *), (GCompareDataFunc) flatpak_strcmp0_ptr, NULL);
for (l = eps; l != NULL; l = l->next)
{
ExportedPath *ep = l->data;
const char *path = ep->path;
if (ep->mode == FAKE_MODE_SYMLINK)
{
if (!path_parent_is_mapped (keys, n_keys, exports->hash, path))
{
g_autofree char *resolved = flatpak_resolve_link (path, NULL);
if (resolved)
{
g_autofree char *parent = g_path_get_dirname (path);
g_autofree char *relative = make_relative (parent, resolved);
flatpak_bwrap_add_args (bwrap, "--symlink", relative, path, NULL);
}
}
}
else if (ep->mode == FAKE_MODE_TMPFS)
{
/* Mount a tmpfs to hide the subdirectory, but only if there
is a pre-existing dir we can mount the path on. */
if (path_is_dir (path))
{
if (!path_parent_is_mapped (keys, n_keys, exports->hash, path))
/* If the parent is not mapped, it will be a tmpfs, no need to mount another one */
flatpak_bwrap_add_args (bwrap, "--dir", path, NULL);
else
flatpak_bwrap_add_args (bwrap, "--tmpfs", path, NULL);
}
}
else if (ep->mode == FAKE_MODE_DIR)
{
if (path_is_dir (path))
flatpak_bwrap_add_args (bwrap, "--dir", path, NULL);
}
else
{
flatpak_bwrap_add_args (bwrap,
(ep->mode == FLATPAK_FILESYSTEM_MODE_READ_ONLY) ? "--ro-bind" : "--bind",
path, path, NULL);
}
}
if (exports->host_fs != 0)
{
if (g_file_test ("/usr", G_FILE_TEST_IS_DIR))
flatpak_bwrap_add_args (bwrap,
(exports->host_fs == FLATPAK_FILESYSTEM_MODE_READ_ONLY) ? "--ro-bind" : "--bind",
"/usr", "/run/host/usr", NULL);
if (g_file_test ("/etc", G_FILE_TEST_IS_DIR))
flatpak_bwrap_add_args (bwrap,
(exports->host_fs == FLATPAK_FILESYSTEM_MODE_READ_ONLY) ? "--ro-bind" : "--bind",
"/etc", "/run/host/etc", NULL);
}
}
/* Returns 0 if not visible */
FlatpakFilesystemMode
flatpak_exports_path_get_mode (FlatpakExports *exports,
const char *path)
{
guint n_keys;
g_autofree const char **keys = (const char **)g_hash_table_get_keys_as_array (exports->hash, &n_keys);
g_autofree char *canonical = NULL;
gboolean is_readonly = FALSE;
g_auto(GStrv) parts = NULL;
int i;
g_autoptr(GString) path_builder = g_string_new ("");
struct stat st;
g_qsort_with_data (keys, n_keys, sizeof (char *), (GCompareDataFunc) flatpak_strcmp0_ptr, NULL);
path = canonical = flatpak_canonicalize_filename (path);
parts = g_strsplit (path+1, "/", -1);
/* A path is visible in the sandbox if no parent
* path element that is mapped in the sandbox is
* a symlink, and the final element is mapped.
* If any parent is a symlink we resolve that and
* continue with that instead.
*/
for (i = 0; parts[i] != NULL; i++)
{
g_string_append (path_builder, "/");
g_string_append (path_builder, parts[i]);
if (path_is_mapped (keys, n_keys, exports->hash, path_builder->str, &is_readonly))
{
if (lstat (path_builder->str, &st) != 0)
{
if (errno == ENOENT && parts[i+1] == NULL && !is_readonly)
{
/* Last element was mapped but isn't there, this is
* OK (used for the save case) if we the parent is
* mapped and writable, as the app can then create
* the file here.
*/
break;
}
return 0;
}
if (S_ISLNK (st.st_mode))
{
g_autofree char *resolved = flatpak_resolve_link (path_builder->str, NULL);
g_autoptr(GString) path2_builder = NULL;
int j;
if (resolved == NULL)
return 0;
path2_builder = g_string_new (resolved);
for (j = i + 1; parts[j] != NULL; j++)
{
g_string_append (path2_builder, "/");
g_string_append (path2_builder, parts[j]);
}
return flatpak_exports_path_get_mode (exports, path2_builder->str);
}
}
else if (parts[i+1] == NULL)
return 0; /* Last part was not mapped */
}
if (is_readonly)
return FLATPAK_FILESYSTEM_MODE_READ_ONLY;
return FLATPAK_FILESYSTEM_MODE_READ_WRITE;
}
gboolean
flatpak_exports_path_is_visible (FlatpakExports *exports,
const char *path)
{
return flatpak_exports_path_get_mode (exports, path) > 0;
}
static gboolean
never_export_as_symlink (const char *path)
{
/* Don't export /tmp as a symlink even if it is on the host, because
that will fail with the pre-existing directory we created for /tmp,
and anyway, it being a symlink is not useful in the sandbox */
if (strcmp (path, "/tmp") == 0)
return TRUE;
return FALSE;
}
static void
do_export_path (FlatpakExports *exports,
const char *path,
gint mode)
{
ExportedPath *old_ep = g_hash_table_lookup (exports->hash, path);
ExportedPath *ep;
ep = g_new0 (ExportedPath, 1);
ep->path = g_strdup (path);
if (old_ep != NULL)
ep->mode = MAX (old_ep->mode, mode);
else
ep->mode = mode;
g_hash_table_replace (exports->hash, ep->path, ep);
}
/* We use level to avoid infinite recursion */
static gboolean
_exports_path_expose (FlatpakExports *exports,
int mode,
const char *path,
int level)
{
g_autofree char *canonical = NULL;
struct stat st;
char *slash;
int i;
if (level > 40) /* 40 is the current kernel ELOOP check */
{
g_debug ("Expose too deep, bail");
return FALSE;
}
if (!g_path_is_absolute (path))
{
g_debug ("Not exposing relative path %s", path);
return FALSE;
}
/* Check if it exists at all */
if (lstat (path, &st) != 0)
return FALSE;
/* Don't expose weird things */
if (!(S_ISDIR (st.st_mode) ||
S_ISREG (st.st_mode) ||
S_ISLNK (st.st_mode) ||
S_ISSOCK (st.st_mode)))
return FALSE;
path = canonical = flatpak_canonicalize_filename (path);
for (i = 0; dont_export_in[i] != NULL; i++)
{
/* Don't expose files in non-mounted dirs like /app or /usr, as
they are not the same as on the host, and we generally can't
create the parents for them anyway */
if (flatpak_has_path_prefix (path, dont_export_in[i]))
{
g_debug ("skipping export for path %s", path);
return FALSE;
}
}
/* Handle any symlinks prior to the target itself. This includes path itself,
because we expose the target of the symlink. */
slash = canonical;
do
{
slash = strchr (slash + 1, '/');
if (slash)
*slash = 0;
if (path_is_symlink (path) && !never_export_as_symlink (path))
{
g_autofree char *resolved = flatpak_resolve_link (path, NULL);
g_autofree char *new_target = NULL;
if (resolved)
{
if (slash)
new_target = g_build_filename (resolved, slash + 1, NULL);
else
new_target = g_strdup (resolved);
if (_exports_path_expose (exports, mode, new_target, level + 1))
{
do_export_path (exports, path, FAKE_MODE_SYMLINK);
return TRUE;
}
}
return FALSE;
}
if (slash)
*slash = '/';
}
while (slash != NULL);
do_export_path (exports, path, mode);
return TRUE;
}
void
flatpak_exports_add_path_expose (FlatpakExports *exports,
FlatpakFilesystemMode mode,
const char *path)
{
_exports_path_expose (exports, mode, path, 0);
}
void
flatpak_exports_add_path_tmpfs (FlatpakExports *exports,
const char *path)
{
_exports_path_expose (exports, FAKE_MODE_TMPFS, path, 0);
}
void
flatpak_exports_add_path_expose_or_hide (FlatpakExports *exports,
FlatpakFilesystemMode mode,
const char *path)
{
if (mode == 0)
flatpak_exports_add_path_tmpfs (exports, path);
else
flatpak_exports_add_path_expose (exports, mode, path);
}
void
flatpak_exports_add_path_dir (FlatpakExports *exports,
const char *path)
{
_exports_path_expose (exports, FAKE_MODE_DIR, path, 0);
}
void
flatpak_exports_add_home_expose (FlatpakExports *exports,
FlatpakFilesystemMode mode)
{
exports->host_fs = mode;
}

62
common/flatpak-exports.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright © 2014-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 <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#ifndef __FLATPAK_EXPORTS_H__
#define __FLATPAK_EXPORTS_H__
#include "libglnx/libglnx.h"
#include "flatpak-utils.h"
#include "flatpak-bwrap.h"
/* In numerical order of more privs */
typedef enum {
FLATPAK_FILESYSTEM_MODE_READ_ONLY = 1,
FLATPAK_FILESYSTEM_MODE_READ_WRITE = 2,
FLATPAK_FILESYSTEM_MODE_CREATE = 3,
} FlatpakFilesystemMode;
typedef struct _FlatpakExports FlatpakExports;
void flatpak_exports_free (FlatpakExports *exports);
FlatpakExports *flatpak_exports_new (void);
void flatpak_exports_append_bwrap_args (FlatpakExports *exports,
FlatpakBwrap *bwrap);
void flatpak_exports_add_home_expose (FlatpakExports *exports,
FlatpakFilesystemMode mode);
void flatpak_exports_add_path_expose (FlatpakExports *exports,
FlatpakFilesystemMode mode,
const char *path);
void flatpak_exports_add_path_tmpfs (FlatpakExports *exports,
const char *path);
void flatpak_exports_add_path_expose_or_hide (FlatpakExports *exports,
FlatpakFilesystemMode mode,
const char *path);
void flatpak_exports_add_path_dir (FlatpakExports *exports,
const char *path);
gboolean flatpak_exports_path_is_visible (FlatpakExports *exports,
const char *path);
FlatpakFilesystemMode flatpak_exports_path_get_mode (FlatpakExports *exports,
const char *path);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakExports, flatpak_exports_free);
#endif /* __FLATPAK_EXPORTS_H__ */

View File

@@ -401,13 +401,16 @@ flatpak_oci_index_new (void)
}
static FlatpakOciManifestDescriptor *
manifest_desc_for_desc (FlatpakOciDescriptor *src_descriptor)
manifest_desc_for_desc (FlatpakOciDescriptor *src_descriptor, const char *ref)
{
FlatpakOciManifestDescriptor *desc;
desc = flatpak_oci_manifest_descriptor_new ();
flatpak_oci_descriptor_copy (src_descriptor, &desc->parent);
g_hash_table_replace (desc->parent.annotations,
g_strdup ("org.opencontainers.image.ref.name"),
g_strdup (ref));
return desc;
}
@@ -426,14 +429,14 @@ flatpak_oci_index_add_manifest (FlatpakOciIndex *self,
int count;
if (desc->annotations != NULL)
m_ref = g_hash_table_lookup (desc->annotations, "org.opencontainers.image.ref.name");
m_ref = g_hash_table_lookup (desc->annotations, "org.flatpak.ref");
if (m_ref != NULL)
flatpak_oci_index_remove_manifest (self, m_ref);
count = flatpak_oci_index_get_n_manifests (self);
m = manifest_desc_for_desc (desc);
m = manifest_desc_for_desc (desc, m_ref);
self->manifests = g_renew (FlatpakOciManifestDescriptor *, self->manifests, count + 2);
self->manifests[count] = m;
self->manifests[count+1] = NULL;
@@ -703,7 +706,7 @@ flatpak_oci_export_annotations (GHashTable *source,
GHashTable *dest)
{
const char *keys[] = {
"org.opencontainers.image.ref.name",
"org.flatpak.ref",
"org.flatpak.installed-size",
"org.flatpak.download-size",
"org.flatpak.metadata",
@@ -750,7 +753,7 @@ flatpak_oci_add_annotations_for_commit (GHashTable *annotations,
GVariant *commit_data)
{
if (ref)
add_annotation (annotations,"org.opencontainers.image.ref.name", ref);
add_annotation (annotations,"org.flatpak.ref", ref);
if (commit)
add_annotation (annotations,"org.flatpak.commit", commit);
@@ -809,7 +812,7 @@ flatpak_oci_parse_commit_annotations (GHashTable *annotations,
GHashTableIter iter;
gpointer _key, _value;
oci_ref = g_hash_table_lookup (annotations, "org.opencontainers.image.ref.name");
oci_ref = g_hash_table_lookup (annotations, "org.flatpak.ref");
if (oci_ref != NULL && out_ref != NULL && *out_ref == NULL)
*out_ref = g_strdup (oci_ref);
@@ -939,3 +942,108 @@ flatpak_oci_signature_new (const char *digest, const char *ref)
return signature;
}
G_DEFINE_TYPE (FlatpakOciIndexResponse, flatpak_oci_index_response, FLATPAK_TYPE_JSON);
static void
flatpak_oci_index_image_free (FlatpakOciIndexImage *self)
{
g_free (self->digest);
g_free (self->mediatype);
g_free (self->os);
g_free (self->architecture);
g_strfreev (self->tags);
if (self->annotations)
g_hash_table_destroy (self->annotations);
if (self->labels)
g_hash_table_destroy (self->labels);
g_free (self);
}
static void
flatpak_oci_index_image_list_free (FlatpakOciIndexImageList *self)
{
int i;
g_free (self->digest);
g_free (self->mediatype);
g_strfreev (self->tags);
for (i = 0; self->images != NULL && self->images[i] != NULL; i++)
flatpak_oci_index_image_free (self->images[i]);
g_free (self->images);
g_free (self);
}
static void
flatpak_oci_index_repository_free (FlatpakOciIndexRepository *self)
{
int i;
g_free (self->name);
for (i = 0; self->images != NULL && self->images[i] != NULL; i++)
flatpak_oci_index_image_free (self->images[i]);
g_free (self->images);
for (i = 0; self->lists != NULL && self->lists[i] != NULL; i++)
flatpak_oci_index_image_list_free (self->lists[i]);
g_free (self->lists);
g_free (self);
}
static void
flatpak_oci_index_response_finalize (GObject *object)
{
FlatpakOciIndexResponse *self = (FlatpakOciIndexResponse *) object;
int i;
g_free (self->registry);
for (i = 0; self->results != NULL && self->results[i] != NULL; i++)
flatpak_oci_index_repository_free (self->results[i]);
g_free (self->results);
G_OBJECT_CLASS (flatpak_oci_index_response_parent_class)->finalize (object);
}
static void
flatpak_oci_index_response_class_init (FlatpakOciIndexResponseClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
FlatpakJsonClass *json_class = FLATPAK_JSON_CLASS (klass);
static FlatpakJsonProp image_props[] = {
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexImage, digest, "Digest"),
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexImage, mediatype, "MediaType"),
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexImage, os, "OS"),
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexImage, architecture, "Architecture"),
FLATPAK_JSON_STRMAP_PROP(FlatpakOciIndexImage, annotations, "Annotations"),
FLATPAK_JSON_STRMAP_PROP(FlatpakOciIndexImage, labels, "Labels"),
FLATPAK_JSON_STRV_PROP (FlatpakOciIndexImage, tags, "Tags"),
FLATPAK_JSON_LAST_PROP
};
static FlatpakJsonProp lists_props[] = {
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexImageList, digest, "Digest"),
FLATPAK_JSON_STRUCTV_PROP (FlatpakOciIndexImageList, images, "Images", image_props),
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexImageList, mediatype, "MediaType"),
FLATPAK_JSON_STRV_PROP (FlatpakOciIndexImageList, tags, "Tags"),
FLATPAK_JSON_LAST_PROP
};
static FlatpakJsonProp results_props[] = {
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexRepository, name, "Name"),
FLATPAK_JSON_STRUCTV_PROP (FlatpakOciIndexRepository, images, "Images", image_props),
FLATPAK_JSON_STRUCTV_PROP (FlatpakOciIndexRepository, lists, "Lists", lists_props),
FLATPAK_JSON_LAST_PROP
};
static FlatpakJsonProp props[] = {
FLATPAK_JSON_STRING_PROP (FlatpakOciIndexResponse, registry, "Registry"),
FLATPAK_JSON_STRUCTV_PROP (FlatpakOciIndexResponse, results, "Results", results_props),
FLATPAK_JSON_LAST_PROP
};
object_class->finalize = flatpak_oci_index_response_finalize;
json_class->props = props;
}
static void
flatpak_oci_index_response_init (FlatpakOciIndexResponse *self)
{
}

View File

@@ -272,4 +272,47 @@ struct _FlatpakOciSignatureClass
FlatpakOciSignature *flatpak_oci_signature_new (const char *digest, const char *ref);
#define FLATPAK_TYPE_OCI_INDEX_RESPONSE flatpak_oci_index_response_get_type ()
G_DECLARE_FINAL_TYPE (FlatpakOciIndexResponse, flatpak_oci_index_response, FLATPAK, OCI_INDEX_RESPONSE, FlatpakJson)
typedef struct
{
char *digest;
char *mediatype;
char *os;
char *architecture;
GHashTable *annotations;
GHashTable *labels;
char **tags;
} FlatpakOciIndexImage;
typedef struct
{
char *digest;
char *mediatype;
char **tags;
FlatpakOciIndexImage **images;
} FlatpakOciIndexImageList;
typedef struct
{
char *name;
FlatpakOciIndexImage **images;
FlatpakOciIndexImageList **lists;
} FlatpakOciIndexRepository;
struct _FlatpakOciIndexResponse
{
FlatpakJson parent;
char *registry;
FlatpakOciIndexRepository **results;
};
struct _FlatpakOciIndexResponseClass
{
FlatpakJsonClass parent_class;
};
#endif /* __FLATPAK_JSON_OCI_H__ */

View File

@@ -46,6 +46,7 @@ struct FlatpakOciRegistry
gboolean for_write;
gboolean valid;
gboolean is_docker;
char *uri;
int tmp_dfd;
@@ -122,9 +123,9 @@ flatpak_oci_registry_set_property (GObject *object,
static void
flatpak_oci_registry_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
FlatpakOciRegistry *self = FLATPAK_OCI_REGISTRY (object);
@@ -192,10 +193,10 @@ flatpak_oci_registry_get_uri (FlatpakOciRegistry *self)
FlatpakOciRegistry *
flatpak_oci_registry_new (const char *uri,
gboolean for_write,
int tmp_dfd,
GCancellable *cancellable,
GError **error)
gboolean for_write,
int tmp_dfd,
GCancellable *cancellable,
GError **error)
{
FlatpakOciRegistry *oci_registry;
@@ -306,7 +307,7 @@ remote_load_file (SoupSession *soup_session,
uri_s = soup_uri_to_string (uri, FALSE);
bytes = flatpak_load_http_uri (soup_session,
uri_s, etag, etag_out,
uri_s, FLATPAK_HTTP_FLAGS_ACCEPT_OCI, etag, etag_out,
NULL, NULL,
cancellable, error);
if (bytes == NULL)
@@ -353,7 +354,7 @@ parse_json (GBytes *bytes, GCancellable *cancellable, GError **error)
}
static gboolean
verify_oci_version (GBytes *oci_layout_bytes, GCancellable *cancellable, GError **error)
verify_oci_version (GBytes *oci_layout_bytes, gboolean *not_json, GCancellable *cancellable, GError **error)
{
const char *version;
g_autoptr(JsonNode) node = NULL;
@@ -361,8 +362,12 @@ verify_oci_version (GBytes *oci_layout_bytes, GCancellable *cancellable, GError
node = parse_json (oci_layout_bytes, cancellable, error);
if (node == NULL)
return FALSE;
{
*not_json = TRUE;
return FALSE;
}
*not_json = FALSE;
oci_layout = json_node_get_object (node);
version = json_object_get_string_member (oci_layout, "imageLayoutVersion");
@@ -384,15 +389,16 @@ verify_oci_version (GBytes *oci_layout_bytes, GCancellable *cancellable, GError
static gboolean
flatpak_oci_registry_ensure_local (FlatpakOciRegistry *self,
gboolean for_write,
GCancellable *cancellable,
GError **error)
gboolean for_write,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GFile) dir = g_file_new_for_uri (self->uri);
glnx_autofd int local_dfd = -1;
int dfd;
g_autoptr(GError) local_error = NULL;
g_autoptr(GBytes) oci_layout_bytes = NULL;
gboolean not_json;
if (self->dfd != -1)
dfd = self->dfd;
@@ -450,7 +456,7 @@ flatpak_oci_registry_ensure_local (FlatpakOciRegistry *self,
return FALSE;
}
}
else if (!verify_oci_version (oci_layout_bytes, cancellable, error))
else if (!verify_oci_version (oci_layout_bytes, &not_json, cancellable, error))
return FALSE;
if (self->dfd == -1 && local_dfd != -1)
@@ -461,9 +467,9 @@ flatpak_oci_registry_ensure_local (FlatpakOciRegistry *self,
static gboolean
flatpak_oci_registry_ensure_remote (FlatpakOciRegistry *self,
gboolean for_write,
GCancellable *cancellable,
GError **error)
gboolean for_write,
GCancellable *cancellable,
GError **error)
{
g_autoptr(SoupURI) baseuri = NULL;
g_autoptr(GBytes) oci_layout_bytes = NULL;
@@ -484,12 +490,25 @@ flatpak_oci_registry_ensure_remote (FlatpakOciRegistry *self,
return FALSE;
}
oci_layout_bytes = remote_load_file (self->soup_session, baseuri, "oci-layout", NULL, NULL, cancellable, error);
if (oci_layout_bytes == NULL)
return FALSE;
oci_layout_bytes = remote_load_file (self->soup_session, baseuri, "oci-layout", NULL, NULL, cancellable, NULL);
if (oci_layout_bytes != NULL)
{
g_autoptr(GError) local_error = NULL;
gboolean not_json;
if (!verify_oci_version (oci_layout_bytes, cancellable, error))
return FALSE;
if (!verify_oci_version (oci_layout_bytes, &not_json, cancellable, &local_error))
{
if (not_json)
self->is_docker = TRUE;
else
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
}
}
else
self->is_docker = TRUE;
self->base_uri = g_steal_pointer (&baseuri);
@@ -498,8 +517,8 @@ flatpak_oci_registry_ensure_remote (FlatpakOciRegistry *self,
static gboolean
flatpak_oci_registry_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
GCancellable *cancellable,
GError **error)
{
FlatpakOciRegistry *self = FLATPAK_OCI_REGISTRY (initable);
gboolean res;
@@ -632,9 +651,14 @@ splice_update_checksum (GOutputStream *out,
}
static char *
get_digest_subpath (const char *digest,
get_digest_subpath (FlatpakOciRegistry *self,
const char *repository,
gboolean is_manifest,
const char *digest,
GError **error)
{
g_autoptr(GString) s = g_string_new ("");
if (!g_str_has_prefix (digest, "sha256:"))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
@@ -642,7 +666,30 @@ get_digest_subpath (const char *digest,
return NULL;
}
return g_strdup_printf ("blobs/sha256/%s", digest + strlen ("sha256:"));
if (self->is_docker)
g_string_append (s, "v2/");
if (repository)
{
g_string_append (s, repository);
g_string_append (s, "/");
}
if (self->is_docker)
{
if (is_manifest)
g_string_append (s, "manifests/");
else
g_string_append (s, "blobs/");
g_string_append (s, digest);
}
else
{
g_string_append (s, "blobs/sha256/");
g_string_append (s, digest + strlen ("sha256:"));
}
return g_string_free (g_steal_pointer (&s), FALSE);
}
static char *
@@ -661,6 +708,8 @@ checksum_fd (int fd, GCancellable *cancellable, GError **error)
int
flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
const char *repository,
gboolean manifest,
const char *digest,
FlatpakLoadUriProgress progress_cb,
gpointer user_data,
@@ -672,7 +721,7 @@ flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
g_assert (self->valid);
subpath = get_digest_subpath (digest, error);
subpath = get_digest_subpath (self, repository, manifest, digest, error);
if (subpath == NULL)
return -1;
@@ -713,7 +762,9 @@ flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
if (fd == -1)
return -1;
if (!flatpak_download_http_uri (self->soup_session, uri_s, out_stream,
if (!flatpak_download_http_uri (self->soup_session, uri_s,
FLATPAK_HTTP_FLAGS_ACCEPT_OCI,
out_stream,
progress_cb, user_data,
cancellable, error))
return -1;
@@ -741,13 +792,16 @@ flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
gboolean
flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
FlatpakOciRegistry *source_registry,
const char *repository,
gboolean manifest,
const char *digest,
FlatpakLoadUriProgress progress_cb,
gpointer user_data,
GCancellable *cancellable,
GError **error)
{
g_autofree char *subpath = NULL;
g_autofree char *src_subpath = NULL;
g_autofree char *dst_subpath = NULL;
g_auto(GLnxTmpfile) tmpf = { 0 };
g_autoptr(GOutputStream) out_stream = NULL;
struct stat stbuf;
@@ -762,12 +816,16 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
return FALSE;
}
subpath = get_digest_subpath (digest, error);
if (subpath == NULL)
src_subpath = get_digest_subpath (source_registry, repository, manifest, digest, error);
if (src_subpath == NULL)
return FALSE;
dst_subpath = get_digest_subpath (self, NULL, manifest, digest, error);
if (dst_subpath == NULL)
return FALSE;
/* Check if its already available */
if (fstatat (self->dfd, subpath, &stbuf, AT_SYMLINK_NOFOLLOW) == 0)
if (fstatat (self->dfd, dst_subpath, &stbuf, AT_SYMLINK_NOFOLLOW) == 0)
return TRUE;
if (!glnx_open_tmpfile_linkable_at (self->dfd, "blobs/sha256",
@@ -779,7 +837,7 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
{
glnx_autofd int src_fd = -1;
src_fd = local_open_file (source_registry->dfd, subpath, NULL, cancellable, error);
src_fd = local_open_file (source_registry->dfd, src_subpath, NULL, cancellable, error);
if (src_fd == -1)
return FALSE;
@@ -791,18 +849,19 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
g_autoptr(SoupURI) uri = NULL;
g_autofree char *uri_s = NULL;
uri = soup_uri_new_with_base (source_registry->base_uri, subpath);
uri = soup_uri_new_with_base (source_registry->base_uri, src_subpath);
if (uri == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
"Invalid relative url %s", subpath);
"Invalid relative url %s", src_subpath);
return FALSE;
}
out_stream = g_unix_output_stream_new (tmpf.fd, FALSE);
uri_s = soup_uri_to_string (uri, FALSE);
if (!flatpak_download_http_uri (source_registry->soup_session, uri_s, out_stream,
if (!flatpak_download_http_uri (source_registry->soup_session, uri_s,
FLATPAK_HTTP_FLAGS_ACCEPT_OCI, out_stream,
progress_cb, user_data,
cancellable, error))
return FALSE;
@@ -826,7 +885,7 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
if (!glnx_link_tmpfile_at (&tmpf,
GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST,
self->dfd, subpath,
self->dfd, dst_subpath,
error))
return FALSE;
@@ -835,9 +894,11 @@ flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
GBytes *
flatpak_oci_registry_load_blob (FlatpakOciRegistry *self,
const char *digest,
GCancellable *cancellable,
GError **error)
const char *repository,
gboolean manifest,
const char *digest,
GCancellable *cancellable,
GError **error)
{
g_autofree char *subpath = NULL;
g_autoptr(GBytes) bytes = NULL;
@@ -845,11 +906,13 @@ flatpak_oci_registry_load_blob (FlatpakOciRegistry *self,
g_assert (self->valid);
subpath = get_digest_subpath (digest, error);
subpath = get_digest_subpath (self, repository, manifest, digest, error);
if (subpath == NULL)
return NULL;
bytes = flatpak_oci_registry_load_file (self, subpath, NULL, NULL, cancellable, error);
if (bytes == NULL)
return NULL;
json_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, bytes);
@@ -902,6 +965,7 @@ flatpak_oci_registry_store_json (FlatpakOciRegistry *self,
FlatpakOciVersioned *
flatpak_oci_registry_load_versioned (FlatpakOciRegistry *self,
const char *repository,
const char *digest,
gsize *out_size,
GCancellable *cancellable,
@@ -911,7 +975,7 @@ flatpak_oci_registry_load_versioned (FlatpakOciRegistry *self,
g_assert (self->valid);
bytes = flatpak_oci_registry_load_blob (self, digest, cancellable, error);
bytes = flatpak_oci_registry_load_blob (self, repository, TRUE, digest, cancellable, error);
if (bytes == NULL)
return NULL;
@@ -1820,3 +1884,264 @@ flatpak_oci_verify_signature (OstreeRepo *repo,
return g_steal_pointer (&json);
}
static const char *
get_image_ref (FlatpakOciIndexImage *img)
{
return g_hash_table_lookup (img->annotations, "org.flatpak.ref");
}
typedef struct {
char *repository;
FlatpakOciIndexImage *image;
} ImageInfo;
static gint
compare_image_by_ref (ImageInfo *a,
ImageInfo *b)
{
const char *a_ref = get_image_ref (a->image);
const char *b_ref = get_image_ref (b->image);
return g_strcmp0 (a_ref, b_ref);
}
GVariant *
flatpak_oci_index_fetch_summary (SoupSession *soup_session,
const char *uri,
const char *etag,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GBytes) res = NULL;
g_autofree char *new_etag = NULL;
g_autoptr(FlatpakJson) json = NULL;
FlatpakOciIndexResponse *response;
g_autoptr(SoupURI) registry_uri = NULL;
g_autofree char *registry_uri_s = NULL;
int i;
g_autoptr(GArray) images = g_array_new (FALSE, TRUE, sizeof (ImageInfo));
g_autoptr(GVariantBuilder) refs_builder = NULL;
g_autoptr(GVariantBuilder) additional_metadata_builder = NULL;
g_autoptr(GVariantBuilder) summary_builder = NULL;
g_autoptr(GVariant) summary = NULL;
g_autoptr(GVariantBuilder) ref_data_builder = NULL;
g_autoptr(GString) index_uri = g_string_new (uri);
g_autoptr(SoupURI) soup_uri = NULL;
g_autofree char *query_uri = NULL;
if (!g_str_has_suffix (index_uri->str, "/"))
g_string_append_c (index_uri, '/');
if (!g_str_has_suffix (uri, "/index/"))
g_string_append (index_uri, "index/");
g_string_append (index_uri, "/static");
soup_uri = soup_uri_new (index_uri->str);
soup_uri_set_query_from_fields (soup_uri,
"os", "linux",
"tag", "latest",
"annotation:org.flatpak.ref:exists", "1",
NULL);
query_uri = soup_uri_to_string (soup_uri, FALSE);
res = flatpak_load_http_uri (soup_session,
query_uri,
0, etag,
&new_etag, NULL, NULL,
cancellable, error);
if (res == NULL)
return NULL;
json = flatpak_json_from_bytes (res, FLATPAK_TYPE_OCI_INDEX_RESPONSE, error);
if (json == NULL)
return NULL;
response = (FlatpakOciIndexResponse *)json;
registry_uri = soup_uri_new_with_base (soup_uri, response->registry);
registry_uri_s = soup_uri_to_string (registry_uri, FALSE);
for (i = 0; response->results != NULL && response->results[i] != NULL; i++)
{
FlatpakOciIndexRepository *r = response->results[i];
int j;
ImageInfo info = { r->name };
for (j = 0; r->images != NULL && r->images[j] != NULL; j++)
{
info.image = r->images[j];
g_array_append_val (images, info);
}
for (j = 0; r->lists != NULL && r->lists[j] != NULL; j++)
{
FlatpakOciIndexImageList *list = r->lists[j];
int k;
for (k = 0; list->images != NULL && list->images[k] != NULL; k++)
{
info.image = list->images[k];
g_array_append_val (images, info);
}
}
}
refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))"));
ref_data_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{s(tts)}"));
additional_metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
/* The summary has to be sorted by ref */
g_array_sort (images, (GCompareFunc)compare_image_by_ref);
for (i = 0; i < images->len; i++)
{
ImageInfo *info = &g_array_index (images, ImageInfo, i);
FlatpakOciIndexImage *image = info->image;
const char *ref = get_image_ref (image);
const char *fake_commit;
guint64 installed_size = 0;
guint64 download_size = 0;
const char *installed_size_str;
const char *download_size_str;
const char *metadata_contents = NULL;
g_autoptr(GVariantBuilder) ref_metadata_builder = NULL;
if (ref == NULL)
continue;
metadata_contents = g_hash_table_lookup (image->annotations, "org.flatpak.metadata");
if (metadata_contents == NULL && !g_str_has_prefix (ref, "appstream/"))
continue; /* Not a flatpak, skip */
if (!g_str_has_prefix (image->digest, "sha256:"))
{
g_debug ("Ignoring digest type %s", image->digest);
continue;
}
fake_commit = image->digest + strlen ("sha256:");
installed_size_str = g_hash_table_lookup (image->annotations, "org.flatpak.installed-size");
if (installed_size_str)
installed_size = g_ascii_strtoull (installed_size_str, NULL, 10);
download_size_str = g_hash_table_lookup (image->annotations, "org.flatpak.download-size");
if (download_size_str)
download_size = g_ascii_strtoull (download_size_str, NULL, 10);
ref_metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (ref_metadata_builder, "{sv}", "xa.oci-repository",
g_variant_new_string (info->repository));
g_variant_builder_add_value (refs_builder,
g_variant_new ("(s(t@ay@a{sv}))", ref,
0,
ostree_checksum_to_bytes_v (fake_commit),
g_variant_builder_end (ref_metadata_builder)));
g_variant_builder_add (ref_data_builder, "{s(tts)}",
ref,
GUINT64_TO_BE (installed_size),
GUINT64_TO_BE (download_size),
metadata_contents ? metadata_contents : "");
}
g_variant_builder_add (additional_metadata_builder, "{sv}", "xa.cache",
g_variant_new_variant (g_variant_builder_end (ref_data_builder)));
if (new_etag)
g_variant_builder_add (additional_metadata_builder, "{sv}", "xa.oci-etag",
g_variant_new_string (new_etag));
g_variant_builder_add (additional_metadata_builder, "{sv}", "xa.oci-registry-uri",
g_variant_new_string (registry_uri_s));
summary_builder = g_variant_builder_new (OSTREE_SUMMARY_GVARIANT_FORMAT);
g_variant_builder_add_value (summary_builder, g_variant_builder_end (refs_builder));
g_variant_builder_add_value (summary_builder, g_variant_builder_end (additional_metadata_builder));
summary = g_variant_ref_sink (g_variant_builder_end (summary_builder));
return g_steal_pointer (&summary);
}
gboolean
flatpak_oci_index_verify_ref (SoupSession *soup_session,
const char *uri,
const char *ref,
const char *digest,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GBytes) res = NULL;
g_autoptr(FlatpakJson) json = NULL;
g_autoptr(SoupURI) soup_uri = NULL;
g_autofree char *query_uri = NULL;
FlatpakOciIndexResponse *response;
int i;
g_autoptr(GString) index_uri = g_string_new (uri);
if (!g_str_has_suffix (index_uri->str, "/"))
g_string_append_c (index_uri, '/');
if (!g_str_has_suffix (uri, "/index/"))
g_string_append (index_uri, "index/");
g_string_append (index_uri, "/dynamic");
soup_uri = soup_uri_new (index_uri->str);
soup_uri_set_query_from_fields (soup_uri,
"os", "linux",
"annotation:org.flatpak.ref", ref,
NULL);
query_uri = soup_uri_to_string (soup_uri, FALSE);
res = flatpak_load_http_uri (soup_session,
query_uri,
0, NULL, NULL, NULL, NULL,
cancellable, error);
if (res == NULL)
return FALSE;
json = flatpak_json_from_bytes (res, FLATPAK_TYPE_OCI_INDEX_RESPONSE, error);
if (json == NULL)
return FALSE;
response = (FlatpakOciIndexResponse *)json;
for (i = 0; response->results != NULL && response->results[i] != NULL; i++)
{
FlatpakOciIndexRepository *r = response->results[i];
int j;
for (j = 0; r->images != NULL && r->images[j] != NULL; j++)
{
FlatpakOciIndexImage *image = r->images[j];
const char *image_ref = get_image_ref (image);
if (image_ref != NULL &&
g_strcmp0 (image_ref, ref) == 0 &&
g_strcmp0 (digest, image->digest) == 0)
return TRUE;
}
for (j = 0; r->lists != NULL && r->lists[j] != NULL; j++)
{
FlatpakOciIndexImageList *list = r->lists[j];
int k;
for (k = 0; list->images != NULL && list->images[k] != NULL; k++)
{
FlatpakOciIndexImage *image = list->images[k];
const char *image_ref = get_image_ref (image);
if (image_ref != NULL &&
g_strcmp0 (image_ref, ref) == 0 &&
g_strcmp0 (digest, image->digest) == 0)
return TRUE;
}
}
}
return flatpak_fail (error, "No matching image for %s\n", ref);
}

View File

@@ -71,12 +71,16 @@ gboolean flatpak_oci_registry_save_index (FlatpakOciRegi
GCancellable *cancellable,
GError **error);
int flatpak_oci_registry_download_blob (FlatpakOciRegistry *self,
const char *repository,
gboolean manifest,
const char *digest,
FlatpakLoadUriProgress progress_cb,
gpointer user_data,
GCancellable *cancellable,
GError **error);
GBytes * flatpak_oci_registry_load_blob (FlatpakOciRegistry *self,
const char *repository,
gboolean manifest,
const char *digest,
GCancellable *cancellable,
GError **error);
@@ -86,6 +90,8 @@ char * flatpak_oci_registry_store_blob (FlatpakOciRegi
GError **error);
gboolean flatpak_oci_registry_mirror_blob (FlatpakOciRegistry *self,
FlatpakOciRegistry *source_registry,
const char *repository,
gboolean manifest,
const char *digest,
FlatpakLoadUriProgress progress_cb,
gpointer user_data,
@@ -96,6 +102,7 @@ FlatpakOciDescriptor * flatpak_oci_registry_store_json (FlatpakOciRegi
GCancellable *cancellable,
GError **error);
FlatpakOciVersioned * flatpak_oci_registry_load_versioned (FlatpakOciRegistry *self,
const char *repository,
const char *digest,
gsize *out_size,
GCancellable *cancellable,
@@ -126,4 +133,17 @@ FlatpakOciSignature *flatpak_oci_verify_signature (OstreeRepo *repo,
GBytes *signature,
GError **error);
GVariant *flatpak_oci_index_fetch_summary (SoupSession *soup_session,
const char *uri,
const char *etag,
GCancellable *cancellable,
GError **error);
gboolean flatpak_oci_index_verify_ref (SoupSession *soup_session,
const char *uri,
const char *ref,
const char *digest,
GCancellable *cancellable,
GError **error);
#endif /* __FLATPAK_OCI_REGISTRY_H__ */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -22,9 +22,11 @@
#define __FLATPAK_RUN_H__
#include "libglnx/libglnx.h"
#include "dbus-proxy/flatpak-proxy.h"
#include "flatpak-common-types.h"
#include "flatpak-context.h"
#include "flatpak-bwrap.h"
#include "flatpak-utils.h"
#include "flatpak-exports.h"
gboolean flatpak_run_in_transient_unit (const char *app_id,
GError **error);
@@ -95,40 +97,6 @@ gboolean flatpak_run_in_transient_unit (const char *app_id,
#define FLATPAK_METADATA_KEY_PRIORITY "priority"
#define FLATPAK_METADATA_KEY_REF "ref"
extern const char *flatpak_context_sockets[];
extern const char *flatpak_context_devices[];
extern const char *flatpak_context_features[];
extern const char *flatpak_context_shares[];
FlatpakContext *flatpak_context_new (void);
void flatpak_context_free (FlatpakContext *context);
void flatpak_context_merge (FlatpakContext *context,
FlatpakContext *other);
GOptionGroup *flatpak_context_get_options (FlatpakContext *context);
void flatpak_context_complete (FlatpakContext *context,
FlatpakCompletion *completion);
gboolean flatpak_context_load_metadata (FlatpakContext *context,
GKeyFile *metakey,
GError **error);
void flatpak_context_save_metadata (FlatpakContext *context,
gboolean flatten,
GKeyFile *metakey);
void flatpak_context_allow_host_fs (FlatpakContext *context);
void flatpak_context_set_session_bus_policy (FlatpakContext *context,
const char *name,
FlatpakPolicy policy);
void flatpak_context_set_system_bus_policy (FlatpakContext *context,
const char *name,
FlatpakPolicy policy);
void flatpak_context_to_args (FlatpakContext *context,
GPtrArray *args);
gboolean flatpak_context_get_needs_session_bus_proxy (FlatpakContext *context);
gboolean flatpak_context_get_needs_system_bus_proxy (FlatpakContext *context);
FlatpakContext *flatpak_context_load_for_app (const char *app_id,
GError **error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakContext, flatpak_context_free)
typedef enum {
FLATPAK_RUN_FLAG_DEVEL = (1 << 0),
@@ -147,29 +115,14 @@ typedef enum {
FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY = (1 << 13),
} FlatpakRunFlags;
typedef struct _FlatpakExports FlatpakExports;
void flatpak_exports_free (FlatpakExports *exports);
gboolean flatpak_exports_path_is_visible (FlatpakExports *exports,
const char *path);
FlatpakExports *flatpak_exports_from_context (FlatpakContext *context,
const char *app_id);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakExports, flatpak_exports_free);
gboolean flatpak_run_add_extension_args (GPtrArray *argv_array,
GArray *fd_array,
char ***envp_p,
gboolean flatpak_run_add_extension_args (FlatpakBwrap *bwrap,
GKeyFile *metakey,
const char *full_ref,
gboolean use_ld_so_cache,
char **extensions_out,
GCancellable *cancellable,
GError **error);
gboolean flatpak_run_add_environment_args (GPtrArray *argv_array,
GArray *fd_array,
char ***envp_p,
gboolean flatpak_run_add_environment_args (FlatpakBwrap *bwrap,
const char *app_info_path,
FlatpakRunFlags flags,
const char *app_id,
@@ -179,29 +132,26 @@ gboolean flatpak_run_add_environment_args (GPtrArray *argv_array,
GCancellable *cancellable,
GError **error);
char ** flatpak_run_get_minimal_env (gboolean devel, gboolean use_ld_so_cache);
char ** flatpak_run_apply_env_default (char **envp, gboolean use_ld_so_cache);
char ** flatpak_run_apply_env_appid (char **envp,
void flatpak_run_apply_env_default (FlatpakBwrap *bwrap, gboolean use_ld_so_cache);
void flatpak_run_apply_env_appid (FlatpakBwrap *bwrap,
GFile *app_dir);
char ** flatpak_run_apply_env_vars (char **envp,
FlatpakContext *context);
void flatpak_run_apply_env_vars (FlatpakBwrap *bwrap,
FlatpakContext *context);
FlatpakContext *flatpak_app_compute_permissions (GKeyFile *app_metadata,
GKeyFile *runtime_metadata,
GError **error);
GFile *flatpak_get_data_dir (const char *app_id);
GFile *flatpak_ensure_data_dir (const char *app_id,
GCancellable *cancellable,
GError **error);
gboolean flatpak_run_setup_base_argv (GPtrArray *argv_array,
GArray *fd_array,
gboolean flatpak_run_setup_base_argv (FlatpakBwrap *bwrap,
GFile *runtime_files,
GFile *app_id_dir,
const char *arch,
FlatpakRunFlags flags,
GError **error);
gboolean flatpak_run_add_app_info_args (GPtrArray *argv_array,
GArray *fd_array,
gboolean flatpak_run_add_app_info_args (FlatpakBwrap *bwrap,
GFile *app_files,
GVariant *app_deploy_data,
const char *app_extensions,

View File

@@ -226,10 +226,15 @@ flatpak_table_printer_print (FlatpakTablePrinter *printer)
for (j = 0; j < row->len; j++)
{
Cell *cell = g_ptr_array_index (row, j);
if (cell->align < 0)
g_print ("%s%-*s", (j == 0) ? "" : " ", widths[j], cell->text);
if (flatpak_fancy_output ())
{
if (cell->align < 0)
g_print ("%s%-*s", (j == 0) ? "" : " ", widths[j], cell->text);
else
g_print ("%s%*s%-*s", (j == 0) ? "" : " ", lwidths[j] - cell->align, "", widths[j] - (lwidths[j] - cell->align), cell->text);
}
else
g_print ("%s%*s%-*s", (j == 0) ? "" : " ", lwidths[j] - cell->align, "", widths[j] - (lwidths[j] - cell->align), cell->text);
g_print ("%s%s", cell->text, (j < row->len - 1) ? "\t" : "");
}
g_print ("\n");
}

View File

@@ -38,6 +38,7 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
@@ -503,6 +504,52 @@ flatpak_get_gl_drivers (void)
return (const char **)drivers;
}
static gboolean
flatpak_get_have_intel_gpu (void)
{
static int have_intel = -1;
if (have_intel == -1)
have_intel = g_file_test ("/sys/module/i915", G_FILE_TEST_EXISTS);
return have_intel;
}
static const char *
flatpak_get_gtk_theme (void)
{
static char *gtk_theme;
if (g_once_init_enter (&gtk_theme))
{
/* The schema may not be installed so check first */
GSettingsSchemaSource *source = g_settings_schema_source_get_default ();
g_autoptr(GSettingsSchema) schema = NULL;
if (source == NULL)
g_once_init_leave (&gtk_theme, g_strdup (""));
else
{
schema = g_settings_schema_source_lookup (source,
"org.gnome.desktop.interface", FALSE);
if (schema == NULL)
g_once_init_leave (&gtk_theme, g_strdup (""));
else
{
/* GSettings is used to store the theme if you use Wayland or GNOME.
* TODO: Check XSettings Net/ThemeName for other desktops.
* We don't care about any other method (like settings.ini) because they
* aren't passed through the sandbox anyway. */
g_autoptr(GSettings) settings = g_settings_new ("org.gnome.desktop.interface");
g_once_init_leave (&gtk_theme, g_settings_get_string (settings, "gtk-theme"));
}
}
}
return (const char*)gtk_theme;
}
gboolean
flatpak_is_in_sandbox (void)
{
@@ -2492,6 +2539,54 @@ gboolean flatpak_file_rename (GFile *from,
return TRUE;
}
/* If memfd_create() is available, generate a sealed memfd with contents of
* @str. Otherwise use an O_TMPFILE @tmpf in anonymous mode, write @str to
* @tmpf, and lseek() back to the start. See also similar uses in e.g.
* rpm-ostree for running dracut.
*/
gboolean
flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf,
const char *name,
const char *str,
size_t len,
GError **error)
{
if (len == -1)
len = strlen (str);
glnx_autofd int memfd = memfd_create (name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
int fd; /* Unowned */
if (memfd != -1)
{
fd = memfd;
}
else
{
/* We use an anonymous fd (i.e. O_EXCL) since we don't want
* the target container to potentially be able to re-link it.
*/
if (!G_IN_SET (errno, ENOSYS, EOPNOTSUPP))
return glnx_throw_errno_prefix (error, "memfd_create");
if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error))
return FALSE;
fd = tmpf->fd;
}
if (ftruncate (fd, len) < 0)
return glnx_throw_errno_prefix (error, "ftruncate");
if (glnx_loop_write (fd, str, len) < 0)
return glnx_throw_errno_prefix (error, "write");
if (lseek (fd, 0, SEEK_SET) < 0)
return glnx_throw_errno_prefix (error, "lseek");
if (memfd != -1)
{
if (fcntl (memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) < 0)
return glnx_throw_errno_prefix (error, "fcntl(F_ADD_SEALS)");
/* The other values can stay default */
tmpf->fd = glnx_steal_fd (&memfd);
tmpf->initialized = TRUE;
}
return TRUE;
}
gboolean
flatpak_open_in_tmpdir_at (int tmpdir_fd,
int mode,
@@ -3821,15 +3916,20 @@ extract_appstream (OstreeRepo *repo,
component_id_text_node = flatpak_xml_find (component_id, NULL, NULL);
component_id_text = g_strstrip (g_strdup (component_id_text_node->text));
if (!g_str_has_prefix (component_id_text, id) ||
!g_str_has_suffix (component_id_text, ".desktop"))
/* .desktop suffix in component ID is suggested, not required
(unless app ID actually ends in .desktop) */
if (g_str_has_suffix (component_id_text, ".desktop") &&
!g_str_has_suffix (id, ".desktop"))
component_id_text[strlen (component_id_text) - strlen (".desktop")] = 0;
if (!g_str_has_prefix (component_id_text, id))
{
component = component->next_sibling;
continue;
}
g_print ("Extracting icons for component %s\n", component_id_text);
component_id_text[strlen (component_id_text) - strlen (".desktop")] = 0;
if (!copy_icon (component_id_text, root, dest, "64x64", &my_error))
{
@@ -4225,6 +4325,16 @@ flatpak_extension_matches_reason (const char *extension_id,
return FALSE;
}
else if (strcmp (reason, "active-gtk-theme") == 0)
{
const char *gtk_theme = flatpak_get_gtk_theme ();
return (strcmp (gtk_theme, extension_basename) == 0);
}
else if (strcmp (reason, "have-intel-gpu") == 0)
{
/* Used for Intel VAAPI driver extension */
return flatpak_get_have_intel_gpu ();
}
return FALSE;
}
@@ -4954,8 +5064,8 @@ oci_layer_progress (guint64 downloaded_bytes,
gboolean
flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
FlatpakOciRegistry *registry,
const char *oci_repository,
const char *digest,
const char *signature_digest,
FlatpakOciPullProgress progress_cb,
gpointer progress_user_data,
GCancellable *cancellable,
@@ -4969,14 +5079,10 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
g_autoptr(FlatpakOciIndex) index = NULL;
int i;
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, digest, NULL, NULL, cancellable, error))
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, oci_repository, TRUE, digest, NULL, NULL, cancellable, error))
return FALSE;
if (signature_digest &&
!flatpak_oci_registry_mirror_blob (dst_registry, registry, signature_digest, NULL, NULL, cancellable, error))
return FALSE;
versioned = flatpak_oci_registry_load_versioned (dst_registry, digest, &versioned_size, cancellable, error);
versioned = flatpak_oci_registry_load_versioned (dst_registry, NULL, digest, &versioned_size, cancellable, error);
if (versioned == NULL)
return FALSE;
@@ -4991,7 +5097,7 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
if (manifest->config.digest != NULL)
{
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, manifest->config.digest, NULL, NULL, cancellable, error))
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, oci_repository, FALSE, manifest->config.digest, NULL, NULL, cancellable, error))
return FALSE;
}
@@ -5011,7 +5117,7 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
{
FlatpakOciDescriptor *layer = manifest->layers[i];
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, layer->digest,
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, oci_repository, FALSE, layer->digest,
oci_layer_progress, &progress_data,
cancellable, error))
return FALSE;
@@ -5029,11 +5135,6 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
flatpak_oci_export_annotations (manifest->annotations, manifest_desc->annotations);
if (signature_digest)
g_hash_table_replace (manifest_desc->annotations,
g_strdup ("org.flatpak.signature-digest"),
g_strdup (signature_digest));
flatpak_oci_index_add_manifest (index, manifest_desc);
if (!flatpak_oci_registry_save_index (dst_registry, index, cancellable, error))
@@ -5046,11 +5147,11 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
char *
flatpak_pull_from_oci (OstreeRepo *repo,
FlatpakOciRegistry *registry,
const char *oci_repository,
const char *digest,
FlatpakOciManifest *manifest,
const char *remote,
const char *ref,
const char *signature_digest,
FlatpakOciPullProgress progress_cb,
gpointer progress_user_data,
GCancellable *cancellable,
@@ -5069,58 +5170,11 @@ flatpak_pull_from_oci (OstreeRepo *repo,
g_autoptr(GVariantBuilder) metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
g_autoptr(GVariant) metadata = NULL;
GHashTable *annotations;
gboolean gpg_verify = FALSE;
int i;
g_assert (ref != NULL);
g_assert (g_str_has_prefix (digest, "sha256:"));
if (remote &&
!ostree_repo_remote_get_gpg_verify (repo, remote,
&gpg_verify, error))
return NULL;
if (gpg_verify)
{
g_autoptr(GBytes) signature_bytes = NULL;
g_autoptr(FlatpakOciSignature) signature = NULL;
if (signature_digest == NULL)
{
flatpak_fail (error, "GPG verification enabled, but no OCI signature found");
return NULL;
}
signature_bytes = flatpak_oci_registry_load_blob (registry, signature_digest, cancellable, error);
if (signature_bytes == NULL)
return NULL;
signature = flatpak_oci_verify_signature (repo, remote, signature_bytes, error);
if (signature == NULL)
return NULL;
if (g_strcmp0 (signature->critical.type, FLATPAK_OCI_SIGNATURE_TYPE_FLATPAK) != 0)
{
flatpak_fail (error, "Invalid signature type %s", signature->critical.type);
return NULL;
}
if (g_strcmp0 (signature->critical.image.digest, digest) != 0)
{
flatpak_fail (error, "Invalid signature digest %s", signature->critical.image.digest);
return NULL;
}
if (g_strcmp0 (signature->critical.identity.ref, ref) != 0)
{
flatpak_fail (error, "Invalid signature ref %s", signature->critical.identity.ref);
return NULL;
}
/* Success! It is valid */
g_debug ("Verified OCI signature for %s %s", signature->critical.identity.ref, digest);
}
annotations = flatpak_oci_manifest_get_annotations (manifest);
if (annotations)
flatpak_oci_parse_commit_annotations (annotations, &timestamp,
@@ -5173,7 +5227,8 @@ flatpak_pull_from_oci (OstreeRepo *repo,
opts.autocreate_parents = TRUE;
opts.ignore_unsupported_content = TRUE;
layer_fd = flatpak_oci_registry_download_blob (registry, layer->digest,
layer_fd = flatpak_oci_registry_download_blob (registry, oci_repository, FALSE,
layer->digest,
oci_layer_progress, &progress_data,
cancellable, error);
if (layer_fd == -1)
@@ -5444,7 +5499,7 @@ flatpak_number_prompt (int min, int max, const char *prompt, ...)
{
char buf[512];
va_list var_args;
gchar *s;
g_autofree char *s = NULL;
va_start (var_args, prompt);
s = g_strdup_vprintf (prompt, var_args);
@@ -5635,6 +5690,7 @@ flatpak_create_soup_session (const char *user_agent)
GBytes *
flatpak_load_http_uri (SoupSession *soup_session,
const char *uri,
FlatpakHTTPFlags flags,
const char *etag,
char **out_etag,
FlatpakLoadUriProgress progress,
@@ -5648,6 +5704,7 @@ flatpak_load_http_uri (SoupSession *soup_session,
g_autoptr(GMainLoop) loop = NULL;
g_autoptr(GString) content = g_string_new ("");
LoadUriData data = { NULL };
SoupMessage *m;
g_debug ("Loading %s using libsoup", uri);
@@ -5666,11 +5723,13 @@ flatpak_load_http_uri (SoupSession *soup_session,
if (request == NULL)
return NULL;
m = soup_request_http_get_message (request);
if (etag)
{
SoupMessage *m = soup_request_http_get_message (request);
soup_message_headers_replace (m->request_headers, "If-None-Match", etag);
}
soup_message_headers_replace (m->request_headers, "If-None-Match", etag);
if (flags & FLATPAK_HTTP_FLAGS_ACCEPT_OCI)
soup_message_headers_replace (m->request_headers, "Accept",
"application/vnd.oci.image.manifest.v1+json");
soup_request_send_async (SOUP_REQUEST(request),
cancellable,
@@ -5699,6 +5758,7 @@ flatpak_load_http_uri (SoupSession *soup_session,
gboolean
flatpak_download_http_uri (SoupSession *soup_session,
const char *uri,
FlatpakHTTPFlags flags,
GOutputStream *out,
FlatpakLoadUriProgress progress,
gpointer user_data,
@@ -5709,6 +5769,7 @@ flatpak_download_http_uri (SoupSession *soup_session,
g_autoptr(GMainLoop) loop = NULL;
g_autoptr(GMainContext) context = NULL;
LoadUriData data = { NULL };
SoupMessage *m;
g_debug ("Loading %s using libsoup", uri);
@@ -5727,6 +5788,11 @@ flatpak_download_http_uri (SoupSession *soup_session,
if (request == NULL)
return FALSE;
m = soup_request_http_get_message (request);
if (flags & FLATPAK_HTTP_FLAGS_ACCEPT_OCI)
soup_message_headers_replace (m->request_headers, "Accept",
"application/vnd.oci.image.manifest.v1+json");
soup_request_send_async (SOUP_REQUEST(request),
cancellable,
load_uri_callback, &data);
@@ -6568,7 +6634,11 @@ progress_cb (OstreeAsyncProgress *progress, gpointer user_data)
}
/* The download progress goes up to 97% */
new_progress = 5 + ((total_transferred / (gdouble) total) * 92);
if (total > 0) {
new_progress = 5 + ((total_transferred / (gdouble) total) * 92);
} else {
new_progress = 97;
}
/* And the writing of the objects adds 3% to the progress */
new_progress += get_write_progress (outstanding_writes);

View File

@@ -29,9 +29,9 @@
#include <gio/gunixfdlist.h>
#include <libsoup/soup.h>
#include "flatpak-dbus.h"
#include "flatpak-document-dbus.h"
#include <ostree.h>
#include <json-glib/json-glib.h>
#include "document-portal/xdp-dbus.h"
typedef enum {
FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV = 1 << 0,
@@ -375,11 +375,11 @@ typedef void (*FlatpakOciPullProgress) (guint64 total_size, guint64 pulled_size,
char * flatpak_pull_from_oci (OstreeRepo *repo,
FlatpakOciRegistry *registry,
const char *oci_repository,
const char *digest,
FlatpakOciManifest *manifest,
const char *remote,
const char *ref,
const char *signature_digest,
FlatpakOciPullProgress progress_cb,
gpointer progress_data,
GCancellable *cancellable,
@@ -387,8 +387,8 @@ char * flatpak_pull_from_oci (OstreeRepo *repo,
gboolean flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
FlatpakOciRegistry *registry,
const char *oci_repository,
const char *digest,
const char *signature_digest,
FlatpakOciPullProgress progress_cb,
gpointer progress_data,
GCancellable *cancellable,
@@ -487,6 +487,13 @@ gboolean flatpak_open_in_tmpdir_at (int tmpdir_fd,
GCancellable *cancellable,
GError **error);
gboolean
flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf,
const char *name,
const char *str,
size_t len,
GError **error);
static inline void
flatpak_temp_dir_destroy (void *p)
{
@@ -643,8 +650,15 @@ gboolean flatpak_yes_no_prompt (const char *prompt, ...) G_GNUC_PRINTF(1, 2);
long flatpak_number_prompt (int min, int max, const char *prompt, ...) G_GNUC_PRINTF(3, 4);
SoupSession * flatpak_create_soup_session (const char *user_agent);
typedef enum {
FLATPAK_HTTP_FLAGS_NONE = 0,
FLATPAK_HTTP_FLAGS_ACCEPT_OCI = 1<<0,
} FlatpakHTTPFlags;
GBytes * flatpak_load_http_uri (SoupSession *soup_session,
const char *uri,
FlatpakHTTPFlags flags,
const char *etag,
char **out_etag,
FlatpakLoadUriProgress progress,
@@ -653,6 +667,7 @@ GBytes * flatpak_load_http_uri (SoupSession *soup_session,
GError **error);
gboolean flatpak_download_http_uri (SoupSession *soup_session,
const char *uri,
FlatpakHTTPFlags flags,
GOutputStream *out,
FlatpakLoadUriProgress progress,
gpointer user_data,

View File

@@ -1,2 +0,0 @@
libgvdb.a
libgvdb-shared.a

View File

@@ -1,7 +0,0 @@
DO NOT MODIFY ANY FILE IN THIS DIRECTORY
(except maybe the Makefile.am)
This directory is the result of a git subtree merge with the 'gvdb'
module on git.gnome.org. Please apply fixes to the 'gvdb' module and
perform a git merge.

View File

@@ -1,537 +0,0 @@
/*
* Copyright © 2010 Codethink Limited
*
* This library 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 of the licence, 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 <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "gvdb-builder.h"
#include "gvdb-format.h"
#include <glib.h>
#include <fcntl.h>
#if !defined(G_OS_WIN32) || !defined(_MSC_VER)
#include <unistd.h>
#endif
#include <string.h>
struct _GvdbItem
{
gchar *key;
guint32 hash_value;
guint32_le assigned_index;
GvdbItem *parent;
GvdbItem *sibling;
GvdbItem *next;
/* one of:
* this:
*/
GVariant *value;
/* this: */
GHashTable *table;
/* or this: */
GvdbItem *child;
};
static void
gvdb_item_free (gpointer data)
{
GvdbItem *item = data;
g_free (item->key);
if (item->value)
g_variant_unref (item->value);
if (item->table)
g_hash_table_unref (item->table);
g_slice_free (GvdbItem, item);
}
GHashTable *
gvdb_hash_table_new (GHashTable *parent,
const gchar *name_in_parent)
{
GHashTable *table;
table = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, gvdb_item_free);
if (parent)
{
GvdbItem *item;
item = gvdb_hash_table_insert (parent, name_in_parent);
gvdb_item_set_hash_table (item, table);
}
return table;
}
static guint32
djb_hash (const gchar *key)
{
guint32 hash_value = 5381;
while (*key)
hash_value = hash_value * 33 + *(signed char *)key++;
return hash_value;
}
GvdbItem *
gvdb_hash_table_insert (GHashTable *table,
const gchar *key)
{
GvdbItem *item;
item = g_slice_new0 (GvdbItem);
item->key = g_strdup (key);
item->hash_value = djb_hash (key);
g_hash_table_insert (table, g_strdup (key), item);
return item;
}
void
gvdb_hash_table_insert_string (GHashTable *table,
const gchar *key,
const gchar *value)
{
GvdbItem *item;
item = gvdb_hash_table_insert (table, key);
gvdb_item_set_value (item, g_variant_new_string (value));
}
void
gvdb_item_set_value (GvdbItem *item,
GVariant *value)
{
g_return_if_fail (!item->value && !item->table && !item->child);
item->value = g_variant_ref_sink (value);
}
void
gvdb_item_set_hash_table (GvdbItem *item,
GHashTable *table)
{
g_return_if_fail (!item->value && !item->table && !item->child);
item->table = g_hash_table_ref (table);
}
void
gvdb_item_set_parent (GvdbItem *item,
GvdbItem *parent)
{
GvdbItem **node;
g_return_if_fail (g_str_has_prefix (item->key, parent->key));
g_return_if_fail (!parent->value && !parent->table);
g_return_if_fail (!item->parent && !item->sibling);
for (node = &parent->child; *node; node = &(*node)->sibling)
if (strcmp ((*node)->key, item->key) > 0)
break;
item->parent = parent;
item->sibling = *node;
*node = item;
}
typedef struct
{
GvdbItem **buckets;
gint n_buckets;
} HashTable;
static HashTable *
hash_table_new (gint n_buckets)
{
HashTable *table;
table = g_slice_new (HashTable);
table->buckets = g_new0 (GvdbItem *, n_buckets);
table->n_buckets = n_buckets;
return table;
}
static void
hash_table_free (HashTable *table)
{
g_free (table->buckets);
g_slice_free (HashTable, table);
}
static void
hash_table_insert (gpointer key,
gpointer value,
gpointer data)
{
guint32 hash_value, bucket;
HashTable *table = data;
GvdbItem *item = value;
hash_value = djb_hash (key);
bucket = hash_value % table->n_buckets;
item->next = table->buckets[bucket];
table->buckets[bucket] = item;
}
static guint32_le
item_to_index (GvdbItem *item)
{
if (item != NULL)
return item->assigned_index;
return guint32_to_le (-1u);
}
typedef struct
{
GQueue *chunks;
guint64 offset;
gboolean byteswap;
} FileBuilder;
typedef struct
{
gsize offset;
gsize size;
gpointer data;
} FileChunk;
static gpointer
file_builder_allocate (FileBuilder *fb,
guint alignment,
gsize size,
struct gvdb_pointer *pointer)
{
FileChunk *chunk;
if (size == 0)
return NULL;
fb->offset += (-fb->offset) & (alignment - 1);
chunk = g_slice_new (FileChunk);
chunk->offset = fb->offset;
chunk->size = size;
chunk->data = g_malloc (size);
pointer->start = guint32_to_le (fb->offset);
fb->offset += size;
pointer->end = guint32_to_le (fb->offset);
g_queue_push_tail (fb->chunks, chunk);
return chunk->data;
}
static void
file_builder_add_value (FileBuilder *fb,
GVariant *value,
struct gvdb_pointer *pointer)
{
GVariant *variant, *normal;
gpointer data;
gsize size;
if (fb->byteswap)
{
value = g_variant_byteswap (value);
variant = g_variant_new_variant (value);
g_variant_unref (value);
}
else
variant = g_variant_new_variant (value);
normal = g_variant_get_normal_form (variant);
g_variant_unref (variant);
size = g_variant_get_size (normal);
data = file_builder_allocate (fb, 8, size, pointer);
g_variant_store (normal, data);
g_variant_unref (normal);
}
static void
file_builder_add_string (FileBuilder *fb,
const gchar *string,
guint32_le *start,
guint16_le *size)
{
FileChunk *chunk;
gsize length;
length = strlen (string);
chunk = g_slice_new (FileChunk);
chunk->offset = fb->offset;
chunk->size = length;
chunk->data = g_malloc (length);
memcpy (chunk->data, string, length);
*start = guint32_to_le (fb->offset);
*size = guint16_to_le (length);
fb->offset += length;
g_queue_push_tail (fb->chunks, chunk);
}
static void
file_builder_allocate_for_hash (FileBuilder *fb,
gsize n_buckets,
gsize n_items,
guint bloom_shift,
gsize n_bloom_words,
guint32_le **bloom_filter,
guint32_le **hash_buckets,
struct gvdb_hash_item **hash_items,
struct gvdb_pointer *pointer)
{
guint32_le bloom_hdr, table_hdr;
guchar *data;
gsize size;
g_assert (n_bloom_words < (1u << 27));
bloom_hdr = guint32_to_le (bloom_shift << 27 | n_bloom_words);
table_hdr = guint32_to_le (n_buckets);
size = sizeof bloom_hdr + sizeof table_hdr +
n_bloom_words * sizeof (guint32_le) +
n_buckets * sizeof (guint32_le) +
n_items * sizeof (struct gvdb_hash_item);
data = file_builder_allocate (fb, 4, size, pointer);
#define chunk(s) (size -= (s), data += (s), data - (s))
memcpy (chunk (sizeof bloom_hdr), &bloom_hdr, sizeof bloom_hdr);
memcpy (chunk (sizeof table_hdr), &table_hdr, sizeof table_hdr);
*bloom_filter = (guint32_le *) chunk (n_bloom_words * sizeof (guint32_le));
*hash_buckets = (guint32_le *) chunk (n_buckets * sizeof (guint32_le));
*hash_items = (struct gvdb_hash_item *) chunk (n_items *
sizeof (struct gvdb_hash_item));
g_assert (size == 0);
#undef chunk
memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le));
/* NOTE - the code to actually fill in the bloom filter here is missing.
* Patches welcome!
*
* http://en.wikipedia.org/wiki/Bloom_filter
* http://0pointer.de/blog/projects/bloom.html
*/
}
static void
file_builder_add_hash (FileBuilder *fb,
GHashTable *table,
struct gvdb_pointer *pointer)
{
guint32_le *buckets, *bloom_filter;
struct gvdb_hash_item *items;
HashTable *mytable;
GvdbItem *item;
guint32 index;
gint bucket;
mytable = hash_table_new (g_hash_table_size (table));
g_hash_table_foreach (table, hash_table_insert, mytable);
index = 0;
for (bucket = 0; bucket < mytable->n_buckets; bucket++)
for (item = mytable->buckets[bucket]; item; item = item->next)
item->assigned_index = guint32_to_le (index++);
file_builder_allocate_for_hash (fb, mytable->n_buckets, index, 5, 0,
&bloom_filter, &buckets, &items, pointer);
index = 0;
for (bucket = 0; bucket < mytable->n_buckets; bucket++)
{
buckets[bucket] = guint32_to_le (index);
for (item = mytable->buckets[bucket]; item; item = item->next)
{
struct gvdb_hash_item *entry = items++;
const gchar *basename;
g_assert (index == guint32_from_le (item->assigned_index));
entry->hash_value = guint32_to_le (item->hash_value);
entry->parent = item_to_index (item->parent);
entry->unused = 0;
if (item->parent != NULL)
basename = item->key + strlen (item->parent->key);
else
basename = item->key;
file_builder_add_string (fb, basename,
&entry->key_start,
&entry->key_size);
if (item->value != NULL)
{
g_assert (item->child == NULL && item->table == NULL);
file_builder_add_value (fb, item->value, &entry->value.pointer);
entry->type = 'v';
}
if (item->child != NULL)
{
guint32 children = 0, i = 0;
guint32_le *offsets;
GvdbItem *child;
g_assert (item->table == NULL);
for (child = item->child; child; child = child->sibling)
children++;
offsets = file_builder_allocate (fb, 4, 4 * children,
&entry->value.pointer);
entry->type = 'L';
for (child = item->child; child; child = child->sibling)
offsets[i++] = child->assigned_index;
g_assert (children == i);
}
if (item->table != NULL)
{
entry->type = 'H';
file_builder_add_hash (fb, item->table, &entry->value.pointer);
}
index++;
}
}
hash_table_free (mytable);
}
static FileBuilder *
file_builder_new (gboolean byteswap)
{
FileBuilder *builder;
builder = g_slice_new (FileBuilder);
builder->chunks = g_queue_new ();
builder->offset = sizeof (struct gvdb_header);
builder->byteswap = byteswap;
return builder;
}
static GString *
file_builder_serialise (FileBuilder *fb,
struct gvdb_pointer root)
{
struct gvdb_header header = { { 0, }, };
GString *result;
if (fb->byteswap)
{
header.signature[0] = GVDB_SWAPPED_SIGNATURE0;
header.signature[1] = GVDB_SWAPPED_SIGNATURE1;
}
else
{
header.signature[0] = GVDB_SIGNATURE0;
header.signature[1] = GVDB_SIGNATURE1;
}
result = g_string_new (NULL);
header.root = root;
g_string_append_len (result, (gpointer) &header, sizeof header);
while (!g_queue_is_empty (fb->chunks))
{
FileChunk *chunk = g_queue_pop_head (fb->chunks);
if (result->len != chunk->offset)
{
gchar zero[8] = { 0, };
g_assert (chunk->offset > result->len);
g_assert (chunk->offset - result->len < 8);
g_string_append_len (result, zero, chunk->offset - result->len);
g_assert (result->len == chunk->offset);
}
g_string_append_len (result, chunk->data, chunk->size);
g_free (chunk->data);
g_slice_free (FileChunk, chunk);
}
g_queue_free (fb->chunks);
g_slice_free (FileBuilder, fb);
return result;
}
GBytes *
gvdb_table_get_content (GHashTable *table,
gboolean byteswap)
{
struct gvdb_pointer root;
FileBuilder *fb;
GString *str;
GBytes *res;
fb = file_builder_new (byteswap);
file_builder_add_hash (fb, table, &root);
str = file_builder_serialise (fb, root);
res = g_bytes_new_take (str->str, str->len);
g_string_free (str, FALSE);
return res;
}
gboolean
gvdb_table_write_contents (GHashTable *table,
const gchar *filename,
gboolean byteswap,
GError **error)
{
GBytes *content;
gboolean status;
content = gvdb_table_get_content (table, byteswap);
status = g_file_set_contents (filename, g_bytes_get_data (content, NULL), g_bytes_get_size (content), error);
g_bytes_unref (content);
return status;
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright © 2010 Codethink Limited
*
* This library 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 of the licence, 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 <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __gvdb_builder_h__
#define __gvdb_builder_h__
#include <gio/gio.h>
typedef struct _GvdbItem GvdbItem;
G_GNUC_INTERNAL
GHashTable * gvdb_hash_table_new (GHashTable *parent,
const gchar *key);
G_GNUC_INTERNAL
GvdbItem * gvdb_hash_table_insert (GHashTable *table,
const gchar *key);
G_GNUC_INTERNAL
void gvdb_hash_table_insert_string (GHashTable *table,
const gchar *key,
const gchar *value);
G_GNUC_INTERNAL
void gvdb_item_set_value (GvdbItem *item,
GVariant *value);
G_GNUC_INTERNAL
void gvdb_item_set_hash_table (GvdbItem *item,
GHashTable *table);
G_GNUC_INTERNAL
void gvdb_item_set_parent (GvdbItem *item,
GvdbItem *parent);
G_GNUC_INTERNAL
gboolean gvdb_table_write_contents (GHashTable *table,
const gchar *filename,
gboolean byteswap,
GError **error);
G_GNUC_INTERNAL
GBytes * gvdb_table_get_content (GHashTable *table,
gboolean byteswap);
#endif /* __gvdb_builder_h__ */

View File

@@ -1,85 +0,0 @@
/*
* Copyright © 2010 Codethink Limited
*
* This library 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 of the licence, 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 <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __gvdb_format_h__
#define __gvdb_format_h__
#include <glib.h>
typedef struct { guint16 value; } guint16_le;
typedef struct { guint32 value; } guint32_le;
struct gvdb_pointer {
guint32_le start;
guint32_le end;
};
struct gvdb_hash_header {
guint32_le n_bloom_words;
guint32_le n_buckets;
};
struct gvdb_hash_item {
guint32_le hash_value;
guint32_le parent;
guint32_le key_start;
guint16_le key_size;
gchar type;
gchar unused;
union
{
struct gvdb_pointer pointer;
gchar direct[8];
} value;
};
struct gvdb_header {
guint32 signature[2];
guint32_le version;
guint32_le options;
struct gvdb_pointer root;
};
static inline guint32_le guint32_to_le (guint32 value) {
guint32_le result = { GUINT32_TO_LE (value) };
return result;
}
static inline guint32 guint32_from_le (guint32_le value) {
return GUINT32_FROM_LE (value.value);
}
static inline guint16_le guint16_to_le (guint16 value) {
guint16_le result = { GUINT16_TO_LE (value) };
return result;
}
static inline guint16 guint16_from_le (guint16_le value) {
return GUINT16_FROM_LE (value.value);
}
#define GVDB_SIGNATURE0 1918981703
#define GVDB_SIGNATURE1 1953390953
#define GVDB_SWAPPED_SIGNATURE0 GUINT32_SWAP_LE_BE (GVDB_SIGNATURE0)
#define GVDB_SWAPPED_SIGNATURE1 GUINT32_SWAP_LE_BE (GVDB_SIGNATURE1)
#endif /* __gvdb_format_h__ */

View File

@@ -1,718 +0,0 @@
/*
* Copyright © 2010 Codethink Limited
*
* This library 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 of the licence, 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 <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "gvdb-reader.h"
#include "gvdb-format.h"
#include <string.h>
struct _GvdbTable {
GBytes *bytes;
const gchar *data;
gsize size;
gboolean byteswapped;
gboolean trusted;
const guint32_le *bloom_words;
guint32 n_bloom_words;
guint bloom_shift;
const guint32_le *hash_buckets;
guint32 n_buckets;
struct gvdb_hash_item *hash_items;
guint32 n_hash_items;
};
static const gchar *
gvdb_table_item_get_key (GvdbTable *file,
const struct gvdb_hash_item *item,
gsize *size)
{
guint32 start, end;
start = guint32_from_le (item->key_start);
*size = guint16_from_le (item->key_size);
end = start + *size;
if G_UNLIKELY (start > end || end > file->size)
return NULL;
return file->data + start;
}
static gconstpointer
gvdb_table_dereference (GvdbTable *file,
const struct gvdb_pointer *pointer,
gint alignment,
gsize *size)
{
guint32 start, end;
start = guint32_from_le (pointer->start);
end = guint32_from_le (pointer->end);
if G_UNLIKELY (start > end || end > file->size || start & (alignment - 1))
return NULL;
*size = end - start;
return file->data + start;
}
static void
gvdb_table_setup_root (GvdbTable *file,
const struct gvdb_pointer *pointer)
{
const struct gvdb_hash_header *header;
guint32 n_bloom_words;
guint32 n_buckets;
gsize size;
header = gvdb_table_dereference (file, pointer, 4, &size);
if G_UNLIKELY (header == NULL || size < sizeof *header)
return;
size -= sizeof *header;
n_bloom_words = guint32_from_le (header->n_bloom_words);
n_buckets = guint32_from_le (header->n_buckets);
n_bloom_words &= (1u << 27) - 1;
if G_UNLIKELY (n_bloom_words * sizeof (guint32_le) > size)
return;
file->bloom_words = (gpointer) (header + 1);
size -= n_bloom_words * sizeof (guint32_le);
file->n_bloom_words = n_bloom_words;
if G_UNLIKELY (n_buckets > G_MAXUINT / sizeof (guint32_le) ||
n_buckets * sizeof (guint32_le) > size)
return;
file->hash_buckets = file->bloom_words + file->n_bloom_words;
size -= n_buckets * sizeof (guint32_le);
file->n_buckets = n_buckets;
if G_UNLIKELY (size % sizeof (struct gvdb_hash_item))
return;
file->hash_items = (gpointer) (file->hash_buckets + n_buckets);
file->n_hash_items = size / sizeof (struct gvdb_hash_item);
}
/**
* gvdb_table_new_from_bytes:
* @bytes: the #GBytes with the data
* @trusted: if the contents of @bytes are trusted
* @error: %NULL, or a pointer to a %NULL #GError
* @returns: a new #GvdbTable
*
* Creates a new #GvdbTable from the contents of @bytes.
*
* This call can fail if the header contained in @bytes is invalid.
*
* You should call gvdb_table_free() on the return result when you no
* longer require it.
**/
GvdbTable *
gvdb_table_new_from_bytes (GBytes *bytes,
gboolean trusted,
GError **error)
{
const struct gvdb_header *header;
GvdbTable *file;
file = g_slice_new0 (GvdbTable);
file->bytes = g_bytes_ref (bytes);
file->data = g_bytes_get_data (bytes, &file->size);
file->trusted = trusted;
if (file->size < sizeof (struct gvdb_header))
goto invalid;
header = (gpointer) file->data;
if (header->signature[0] == GVDB_SIGNATURE0 &&
header->signature[1] == GVDB_SIGNATURE1 &&
guint32_from_le (header->version) == 0)
file->byteswapped = FALSE;
else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 &&
header->signature[1] == GVDB_SWAPPED_SIGNATURE1 &&
guint32_from_le (header->version) == 0)
file->byteswapped = TRUE;
else
goto invalid;
gvdb_table_setup_root (file, &header->root);
return file;
invalid:
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "invalid gvdb header");
g_bytes_unref (file->bytes);
g_slice_free (GvdbTable, file);
return NULL;
}
/**
* gvdb_table_new:
* @filename: a filename
* @trusted: if the contents of @bytes are trusted
* @error: %NULL, or a pointer to a %NULL #GError
* @returns: a new #GvdbTable
*
* Creates a new #GvdbTable using the #GMappedFile for @filename as the
* #GBytes.
**/
GvdbTable *
gvdb_table_new (const gchar *filename,
gboolean trusted,
GError **error)
{
GMappedFile *mapped;
GvdbTable *table;
GBytes *bytes;
mapped = g_mapped_file_new (filename, FALSE, error);
if (!mapped)
return NULL;
bytes = g_mapped_file_get_bytes (mapped);
table = gvdb_table_new_from_bytes (bytes, trusted, error);
g_mapped_file_unref (mapped);
g_bytes_unref (bytes);
g_prefix_error (error, "%s: ", filename);
return table;
}
static gboolean
gvdb_table_bloom_filter (GvdbTable *file,
guint32 hash_value)
{
guint32 word, mask;
if (file->n_bloom_words == 0)
return TRUE;
word = (hash_value / 32) % file->n_bloom_words;
mask = 1 << (hash_value & 31);
mask |= 1 << ((hash_value >> file->bloom_shift) & 31);
return (guint32_from_le (file->bloom_words[word]) & mask) == mask;
}
static gboolean
gvdb_table_check_name (GvdbTable *file,
struct gvdb_hash_item *item,
const gchar *key,
guint key_length)
{
const gchar *this_key;
gsize this_size;
guint32 parent;
this_key = gvdb_table_item_get_key (file, item, &this_size);
if G_UNLIKELY (this_key == NULL || this_size > key_length)
return FALSE;
key_length -= this_size;
if G_UNLIKELY (memcmp (this_key, key + key_length, this_size) != 0)
return FALSE;
parent = guint32_from_le (item->parent);
if (key_length == 0 && parent == 0xffffffffu)
return TRUE;
if G_LIKELY (parent < file->n_hash_items && this_size > 0)
return gvdb_table_check_name (file,
&file->hash_items[parent],
key, key_length);
return FALSE;
}
static const struct gvdb_hash_item *
gvdb_table_lookup (GvdbTable *file,
const gchar *key,
gchar type)
{
guint32 hash_value = 5381;
guint key_length;
guint32 bucket;
guint32 lastno;
guint32 itemno;
if G_UNLIKELY (file->n_buckets == 0 || file->n_hash_items == 0)
return NULL;
for (key_length = 0; key[key_length]; key_length++)
hash_value = (hash_value * 33) + ((signed char *) key)[key_length];
if (!gvdb_table_bloom_filter (file, hash_value))
return NULL;
bucket = hash_value % file->n_buckets;
itemno = guint32_from_le (file->hash_buckets[bucket]);
if (bucket == file->n_buckets - 1 ||
(lastno = guint32_from_le(file->hash_buckets[bucket + 1])) > file->n_hash_items)
lastno = file->n_hash_items;
while G_LIKELY (itemno < lastno)
{
struct gvdb_hash_item *item = &file->hash_items[itemno];
if (hash_value == guint32_from_le (item->hash_value))
if G_LIKELY (gvdb_table_check_name (file, item, key, key_length))
if G_LIKELY (item->type == type)
return item;
itemno++;
}
return NULL;
}
static gboolean
gvdb_table_list_from_item (GvdbTable *table,
const struct gvdb_hash_item *item,
const guint32_le **list,
guint *length)
{
gsize size;
*list = gvdb_table_dereference (table, &item->value.pointer, 4, &size);
if G_LIKELY (*list == NULL || size % 4)
return FALSE;
*length = size / 4;
return TRUE;
}
/**
* gvdb_table_get_names:
* @table: a #GvdbTable
* @length: the number of items returned, or %NULL
*
* Gets a list of all names contained in @table.
*
* No call to gvdb_table_get_table(), gvdb_table_list() or
* gvdb_table_get_value() will succeed unless it is for one of the
* names returned by this function.
*
* Note that some names that are returned may still fail for all of the
* above calls in the case of the corrupted file. Note also that the
* returned strings may not be utf8.
*
* Returns: a %NULL-terminated list of strings, of length @length
**/
gchar **
gvdb_table_get_names (GvdbTable *table,
gint *length)
{
gchar **names;
gint n_names;
gint filled;
gint total;
gint i;
/* We generally proceed by iterating over the list of items in the
* hash table (in order of appearance) recording them into an array.
*
* Each item has a parent item (except root items). The parent item
* forms part of the name of the item. We could go fetching the
* parent item chain at the point that we encounter each item but then
* we would need to implement some sort of recursion along with checks
* for self-referential items.
*
* Instead, we do a number of passes. Each pass will build up one
* level of names (starting from the root). We continue to do passes
* until no more items are left. The first pass will only add root
* items and each further pass will only add items whose direct parent
* is an item added in the immediately previous pass. It's also
* possible that items get filled if they follow their parent within a
* particular pass.
*
* At most we will have a number of passes equal to the depth of the
* tree. Self-referential items will never be filled in (since their
* parent will have never been filled in). We continue until we have
* a pass that fills in no additional items.
*
* This takes an O(n) algorithm and turns it into O(n*m) where m is
* the depth of the tree, but in all sane cases the tree won't be very
* deep and the constant factor of this algorithm is lower (and the
* complexity of coding it, as well).
*/
n_names = table->n_hash_items;
names = g_new0 (gchar *, n_names + 1);
/* 'names' starts out all-NULL. On each pass we record the number
* of items changed from NULL to non-NULL in 'filled' so we know if we
* should repeat the loop. 'total' counts the total number of items
* filled. If 'total' ends up equal to 'n_names' then we know that
* 'names' has been completely filled.
*/
total = 0;
do
{
/* Loop until we have filled no more entries */
filled = 0;
for (i = 0; i < n_names; i++)
{
const struct gvdb_hash_item *item = &table->hash_items[i];
const gchar *name;
gsize name_length;
guint32 parent;
/* already got it on a previous pass */
if (names[i] != NULL)
continue;
parent = guint32_from_le (item->parent);
if (parent == 0xffffffffu)
{
/* it's a root item */
name = gvdb_table_item_get_key (table, item, &name_length);
if (name != NULL)
{
names[i] = g_strndup (name, name_length);
filled++;
}
}
else if (parent < n_names && names[parent] != NULL)
{
/* It's a non-root item whose parent was filled in already.
*
* Calculate the name of this item by combining it with
* its parent name.
*/
name = gvdb_table_item_get_key (table, item, &name_length);
if (name != NULL)
{
const gchar *parent_name = names[parent];
gsize parent_length;
gchar *fullname;
parent_length = strlen (parent_name);
fullname = g_malloc (parent_length + name_length + 1);
memcpy (fullname, parent_name, parent_length);
memcpy (fullname + parent_length, name, name_length);
fullname[parent_length + name_length] = '\0';
names[i] = fullname;
filled++;
}
}
}
total += filled;
}
while (filled && total < n_names);
/* If the table was corrupted then 'names' may have holes in it.
* Collapse those.
*/
if G_UNLIKELY (total != n_names)
{
GPtrArray *fixed_names;
fixed_names = g_ptr_array_new ();
for (i = 0; i < n_names; i++)
if (names[i] != NULL)
g_ptr_array_add (fixed_names, names[i]);
g_free (names);
n_names = fixed_names->len;
g_ptr_array_add (fixed_names, NULL);
names = (gchar **) g_ptr_array_free (fixed_names, FALSE);
}
if (length)
*length = n_names;
return names;
}
/**
* gvdb_table_list:
* @file: a #GvdbTable
* @key: a string
* @returns: a %NULL-terminated string array
*
* List all of the keys that appear below @key. The nesting of keys
* within the hash file is defined by the program that created the hash
* file. One thing is constant: each item in the returned array can be
* concatenated to @key to obtain the full name of that key.
*
* It is not possible to tell from this function if a given key is
* itself a path, a value, or another hash table; you are expected to
* know this for yourself.
*
* You should call g_strfreev() on the return result when you no longer
* require it.
**/
gchar **
gvdb_table_list (GvdbTable *file,
const gchar *key)
{
const struct gvdb_hash_item *item;
const guint32_le *list;
gchar **strv;
guint length;
guint i;
if ((item = gvdb_table_lookup (file, key, 'L')) == NULL)
return NULL;
if (!gvdb_table_list_from_item (file, item, &list, &length))
return NULL;
strv = g_new (gchar *, length + 1);
for (i = 0; i < length; i++)
{
guint32 itemno = guint32_from_le (list[i]);
if (itemno < file->n_hash_items)
{
const struct gvdb_hash_item *item;
const gchar *string;
gsize strsize;
item = file->hash_items + itemno;
string = gvdb_table_item_get_key (file, item, &strsize);
if (string != NULL)
strv[i] = g_strndup (string, strsize);
else
strv[i] = g_malloc0 (1);
}
else
strv[i] = g_malloc0 (1);
}
strv[i] = NULL;
return strv;
}
/**
* gvdb_table_has_value:
* @file: a #GvdbTable
* @key: a string
* @returns: %TRUE if @key is in the table
*
* Checks for a value named @key in @file.
*
* Note: this function does not consider non-value nodes (other hash
* tables, for example).
**/
gboolean
gvdb_table_has_value (GvdbTable *file,
const gchar *key)
{
static const struct gvdb_hash_item *item;
gsize size;
item = gvdb_table_lookup (file, key, 'v');
if (item == NULL)
return FALSE;
return gvdb_table_dereference (file, &item->value.pointer, 8, &size) != NULL;
}
static GVariant *
gvdb_table_value_from_item (GvdbTable *table,
const struct gvdb_hash_item *item)
{
GVariant *variant, *value;
gconstpointer data;
GBytes *bytes;
gsize size;
data = gvdb_table_dereference (table, &item->value.pointer, 8, &size);
if G_UNLIKELY (data == NULL)
return NULL;
bytes = g_bytes_new_from_bytes (table->bytes, ((gchar *) data) - table->data, size);
variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, bytes, table->trusted);
value = g_variant_get_variant (variant);
g_variant_unref (variant);
g_bytes_unref (bytes);
return value;
}
/**
* gvdb_table_get_value:
* @file: a #GvdbTable
* @key: a string
* @returns: a #GVariant, or %NULL
*
* Looks up a value named @key in @file.
*
* If the value is not found then %NULL is returned. Otherwise, a new
* #GVariant instance is returned. The #GVariant does not depend on the
* continued existence of @file.
*
* You should call g_variant_unref() on the return result when you no
* longer require it.
**/
GVariant *
gvdb_table_get_value (GvdbTable *file,
const gchar *key)
{
const struct gvdb_hash_item *item;
GVariant *value;
if ((item = gvdb_table_lookup (file, key, 'v')) == NULL)
return NULL;
value = gvdb_table_value_from_item (file, item);
if (value && file->byteswapped)
{
GVariant *tmp;
tmp = g_variant_byteswap (value);
g_variant_unref (value);
value = tmp;
}
return value;
}
/**
* gvdb_table_get_raw_value:
* @table: a #GvdbTable
* @key: a string
* @returns: a #GVariant, or %NULL
*
* Looks up a value named @key in @file.
*
* This call is equivalent to gvdb_table_get_value() except that it
* never byteswaps the value.
**/
GVariant *
gvdb_table_get_raw_value (GvdbTable *table,
const gchar *key)
{
const struct gvdb_hash_item *item;
if ((item = gvdb_table_lookup (table, key, 'v')) == NULL)
return NULL;
return gvdb_table_value_from_item (table, item);
}
/**
* gvdb_table_get_table:
* @file: a #GvdbTable
* @key: a string
* @returns: a new #GvdbTable, or %NULL
*
* Looks up the hash table named @key in @file.
*
* The toplevel hash table in a #GvdbTable can contain reference to
* child hash tables (and those can contain further references...).
*
* If @key is not found in @file then %NULL is returned. Otherwise, a
* new #GvdbTable is returned, referring to the child hashtable as
* contained in the file. This newly-created #GvdbTable does not depend
* on the continued existence of @file.
*
* You should call gvdb_table_free() on the return result when you no
* longer require it.
**/
GvdbTable *
gvdb_table_get_table (GvdbTable *file,
const gchar *key)
{
const struct gvdb_hash_item *item;
GvdbTable *new;
item = gvdb_table_lookup (file, key, 'H');
if (item == NULL)
return NULL;
new = g_slice_new0 (GvdbTable);
new->bytes = g_bytes_ref (file->bytes);
new->byteswapped = file->byteswapped;
new->trusted = file->trusted;
new->data = file->data;
new->size = file->size;
gvdb_table_setup_root (new, &item->value.pointer);
return new;
}
/**
* gvdb_table_free:
* @file: a #GvdbTable
*
* Frees @file.
**/
void
gvdb_table_free (GvdbTable *file)
{
g_bytes_unref (file->bytes);
g_slice_free (GvdbTable, file);
}
/**
* gvdb_table_is_valid:
* @table: a #GvdbTable
* @returns: %TRUE if @table is still valid
*
* Checks if the table is still valid.
*
* An on-disk GVDB can be marked as invalid. This happens when the file
* has been replaced. The appropriate action is typically to reopen the
* file.
**/
gboolean
gvdb_table_is_valid (GvdbTable *table)
{
return !!*table->data;
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright © 2010 Codethink Limited
*
* This library 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 of the licence, 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 <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __gvdb_reader_h__
#define __gvdb_reader_h__
#include <glib.h>
typedef struct _GvdbTable GvdbTable;
G_BEGIN_DECLS
G_GNUC_INTERNAL
GvdbTable * gvdb_table_new_from_bytes (GBytes *bytes,
gboolean trusted,
GError **error);
G_GNUC_INTERNAL
GvdbTable * gvdb_table_new (const gchar *filename,
gboolean trusted,
GError **error);
G_GNUC_INTERNAL
void gvdb_table_free (GvdbTable *table);
G_GNUC_INTERNAL
gchar ** gvdb_table_get_names (GvdbTable *table,
gint *length);
G_GNUC_INTERNAL
gchar ** gvdb_table_list (GvdbTable *table,
const gchar *key);
G_GNUC_INTERNAL
GvdbTable * gvdb_table_get_table (GvdbTable *table,
const gchar *key);
G_GNUC_INTERNAL
GVariant * gvdb_table_get_raw_value (GvdbTable *table,
const gchar *key);
G_GNUC_INTERNAL
GVariant * gvdb_table_get_value (GvdbTable *table,
const gchar *key);
G_GNUC_INTERNAL
gboolean gvdb_table_has_value (GvdbTable *table,
const gchar *key);
G_GNUC_INTERNAL
gboolean gvdb_table_is_valid (GvdbTable *table);
G_END_DECLS
#endif /* __gvdb_reader_h__ */

View File

@@ -1,32 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<Project xmlns='http://usefulinc.com/ns/doap#'
xmlns:foaf='http://xmlns.com/foaf/0.1/'
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:gnome='http://api.gnome.org/doap-extensions#'>
<name xml:lang='en'>gvdb</name>
<shortdesc xml:lang='en'>GVariant Database file</shortdesc>
<description xml:lang='en'>
A simple database file format that stores a mapping from strings to
GVariant values in a way that is extremely efficient for lookups.
The database is written once and can not be modified.
Included here is reader code and a first-pass implementation of a
writer (that does not currently produce particularly optimised
output).
It is intended that this code be used by copy-pasting into your
project or by making use of git-merge(1).
</description>
<maintainer>
<foaf:Person>
<foaf:name>Ryan Lortie</foaf:name>
<foaf:mbox rdf:resource='mailto:desrt@desrt.ca'/>
<gnome:userid>ryanl</gnome:userid>
</foaf:Person>
</maintainer>
</Project>

View File

@@ -14,10 +14,10 @@ AC_PREREQ([2.63])
# on the unstable (ie master), interface age = 0
m4_define([flatpak_major_version], [0])
m4_define([flatpak_minor_version], [9])
m4_define([flatpak_micro_version], [99])
m4_define([flatpak_minor_version], [11])
m4_define([flatpak_micro_version], [3])
m4_define([flatpak_extra_version], [])
m4_define([flatpak_interface_age], [98])
m4_define([flatpak_interface_age], [0])
m4_define([flatpak_binary_age],
[m4_eval(10000 * flatpak_major_version + 100 * flatpak_minor_version + flatpak_micro_version)])
m4_define([flatpak_version],
@@ -31,7 +31,8 @@ AC_INIT([Flatpak],
GLIB_REQS=2.44
SYSTEM_BWRAP_REQS=0.1.8
OSTREE_REQS=2017.12
OSTREE_REQS=2017.14
OSTREE_P2P_REQS=2018.2
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
@@ -222,10 +223,10 @@ fi
PKG_CHECK_MODULES(OSTREE, [ostree-1 >= $OSTREE_REQS])
PKG_CHECK_MODULES(FUSE, [fuse])
PKG_CHECK_MODULES(JSON, [json-glib-1.0])
PKG_CHECK_MODULES(APPSTREAM_GLIB, [appstream-glib >= 0.5.10])
AC_ARG_ENABLE([seccomp],
AC_HELP_STRING([--disable-seccomp],
[Disable seccomp]),
@@ -259,7 +260,7 @@ AC_ARG_ENABLE([p2p],
[Enable unstable peer to peer support [default=no]])],,
[enable_p2p=no])
AS_IF([test x$enable_p2p = xyes],[
PKG_CHECK_MODULES(OSTREE, [ostree-1 >= $OSTREE_REQS])
PKG_CHECK_MODULES(OSTREE, [ostree-1 >= $OSTREE_P2P_REQS])
ostree_features=$($PKG_CONFIG --variable=features ostree-1)
AS_CASE(["$ostree_features"],

View File

@@ -1,13 +1,10 @@
introspectiondir = $(datadir)/dbus-1/interfaces
introspection_DATA = \
data/org.freedesktop.impl.portal.PermissionStore.xml \
data/org.freedesktop.portal.Documents.xml \
data/org.freedesktop.Flatpak.xml \
$(NULL)
EXTRA_DIST += \
data/org.freedesktop.portal.Documents.xml \
data/org.freedesktop.impl.portal.PermissionStore.xml \
data/org.freedesktop.systemd1.xml \
data/org.freedesktop.Flatpak.xml \
$(NULL)

View File

@@ -1,163 +0,0 @@
<!DOCTYPE node PUBLIC
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!--
Copyright (C) 2015 Red Hat, Inc.
This library 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 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, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
Author: Alexander Larsson <alexl@redhat.com>
-->
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<!--
org.freedesktop.impl.portal.PermissionStore:
@short_description: Database to store permissions
The permission store can be used by portals to store permissions
that sandboxed applications have to various resources, such as
files outside the sandbox.
Since the resources managed by portals can be varied, the permission
store is fairly free-form: there can be multiple tables; resources are
identified by an ID, as are applications, and permissions are stored as
string arrays. None of these strings are interpreted by the permission
store in any way.
In addition, the permission store allows to associate extra data
(in the form of a GVariant) with each resource.
-->
<interface name='org.freedesktop.impl.portal.PermissionStore'>
<property name="version" type="u" access="read"/>
<!--
Lookup:
@table: the name of the table to use
@id: the resource ID to look up
@permissions: map from application ID to permissions
@data: data that is associated with the resource
Looks up the entry for a resource in one of the tables and returns
all associated application permissions and data.
-->
<method name="Lookup">
<arg name='table' type='s' direction='in'/>
<arg name='id' type='s' direction='in'/>
<arg name='permissions' type='a{sas}' direction='out'/>
<arg name='data' type='v' direction='out'/>
</method>
<!--
Set:
@table: the name of the table to use
@create: whether to create the table if it does not exist
@id: the resource ID to modify
@app_permissions: map from application ID to permissions
@data: data to associate with the resource
Writes the entry for a resource in the given table.
-->
<method name="Set">
<arg name='table' type='s' direction='in'/>
<arg name='create' type='b' direction='in'/>
<arg name='id' type='s' direction='in'/>
<arg name='app_permissions' type='a{sas}' direction='in'/>
<arg name='data' type='v' direction='in'/>
</method>
<!--
Delete:
@table: the name of the table to use
@id: the resource ID to delete
Removes the entry for a resource in the given table.
-->
<method name="Delete">
<arg name='table' type='s' direction='in'/>
<arg name='id' type='s' direction='in'/>
</method>
<!--
SetValue:
@table: the name of the table to use
@create: whether to create the table if it does not exist
@id: the resource ID to modify
@data: data to associate with the resource
Sets just the data for a resource in the given table.
-->
<method name="SetValue">
<arg name='table' type='s' direction='in'/>
<arg name='create' type='b' direction='in'/>
<arg name='id' type='s' direction='in'/>
<arg name='data' type='v' direction='in'/>
</method>
<!--
SetPermission:
@table: the name of the table to use
@create: whether to create the table if it does not exist
@id: the resource ID to modify
@app: the application ID to modify
@permissions: permissions to set
Sets the permissions for an application and a resource
in the given table.
-->
<method name="SetPermission">
<arg name='table' type='s' direction='in'/>
<arg name='create' type='b' direction='in'/>
<arg name='id' type='s' direction='in'/>
<arg name='app' type='s' direction='in'/>
<arg name='permissions' type='as' direction='in'/>
</method>
<!--
List:
@table: the name of the table to use
@ids: IDs of all resources that are present in the table
Returns all the resources that are present in the table.
-->
<method name="List">
<arg name='table' type='s' direction='in'/>
<arg name='ids' type='as' direction='out'/>
</method>
<!--
Changed:
@table: the name of the table
@ids: IDs of the changed resource
@deleted: whether the resource was deleted
@data: the data that is associated the resource
@permissions: the permissions that are associated with the resource
The Changed signal is emitted when the entry for a resource
is modified or deleted. If the entry was deleted, then @data
and @permissions contain the last values that were found in the
database. If the entry was modified, they contain the new values.
-->
<signal name="Changed">
<arg name='table' type='s' direction='out'/>
<arg name='id' type='s' direction='out'/>
<arg name='deleted' type='b' direction='out'/>
<arg name='data' type='v' direction='out'/>
<arg name='permissions' type='a{sas}' direction='out'/>
</signal>
</interface>
</node>

View File

@@ -72,6 +72,7 @@
access to the file.
-->
<method name="Add">
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
<arg type='h' name='o_path_fd' direction='in'/>
<arg type='b' name='reuse_existing' direction='in'/>
<arg type='b' name='persistent' direction='in'/>
@@ -89,6 +90,7 @@
Creates an entry in the document store for writing a new file.
-->
<method name="AddNamed">
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
<arg type='h' name='o_path_parent_fd' direction='in'/>
<arg type='ay' name='filename' direction='in'/>
<arg type='b' name='reuse_existing' direction='in'/>
@@ -124,6 +126,7 @@
This method was added in version 2 of the org.freedesktop.portal.Documents interface.
-->
<method name="AddFull">
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
<arg type='ah' name='o_path_fds' direction='in'/>
<arg type='u' name='flags' direction='in'/>
<arg type='s' name='app_id' direction='in'/>
@@ -132,6 +135,43 @@
<arg type='a{sv}' name='extra_out' direction='out'/>
</method>
<!--
AddNamedFull:
@o_path_fds: open file descriptor for the parent directory
@filename: the basename for the file
@flags: flags, 1 == reuse_existing, 2 == persistent, 3 == as-needed-by-app
@app_id: an application ID, or empty string
@permissions: the permissions to grant, possible values are 'read', 'write', 'grant-permissions' and 'delete'
@doc_id: the ID of the file in the document store
@extra_info: Extra info returned
Creates an entry in the document store for writing a new file.
If the as-needed-by-app flag is given, file will only be added to
the document store if the application does not already have access to it.
For file that is not added to the document store, the doc_id will
contain an empty string.
Additionally, if app_id is specified, it will be given the permissions
listed in GrantPermission.
The method also returns some extra info that can be used to avoid
multiple roundtrips. For now it only contains as "mountpoint", the
fuse mountpoint of the document portal.
This method was added in version 3 of the org.freedesktop.portal.Documents interface.
-->
<method name="AddNamedFull">
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
<arg type='h' name='o_path_fd' direction='in'/>
<arg type='ay' name='filename' direction='in'/>
<arg type='u' name='flags' direction='in'/>
<arg type='s' name='app_id' direction='in'/>
<arg type='as' name='permissions' direction='in'/>
<arg type='s' name='doc_id' direction='out'/>
<arg type='a{sv}' name='extra_out' direction='out'/>
</method>
<!--
GrantPermissions:
@doc_id: the ID of the file in the document store

View File

@@ -173,10 +173,11 @@
typedef struct FlatpakProxyClient FlatpakProxyClient;
/* We start looking ignoring the first cr-lf
since there is no previous line initially */
#define AUTH_END_INIT_OFFSET 2
#define AUTH_END_STRING "\r\nBEGIN\r\n"
#define FIND_AUTH_END_CONTINUE -1
#define FIND_AUTH_END_ABORT -2
#define AUTH_LINE_SENTINEL "\r\n"
#define AUTH_BEGIN "BEGIN"
typedef enum {
EXPECTED_REPLY_NONE,
@@ -258,7 +259,7 @@ struct FlatpakProxyClient
FlatpakProxy *proxy;
gboolean authenticated;
int auth_end_offset;
GByteArray *auth_buffer;
ProxySide client_side;
ProxySide bus_side;
@@ -372,6 +373,7 @@ flatpak_proxy_client_finalize (GObject *object)
client->proxy->clients = g_list_remove (client->proxy->clients, client);
g_clear_object (&client->proxy);
g_byte_array_free (client->auth_buffer, TRUE);
g_hash_table_destroy (client->rewrite_reply);
g_hash_table_destroy (client->get_owner_reply);
g_hash_table_destroy (client->unique_id_policy);
@@ -407,7 +409,7 @@ flatpak_proxy_client_init (FlatpakProxyClient *client)
init_side (client, &client->client_side);
init_side (client, &client->bus_side);
client->auth_end_offset = AUTH_END_INIT_OFFSET;
client->auth_buffer = g_byte_array_new ();
client->rewrite_reply = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
client->get_owner_reply = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
client->unique_id_policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
@@ -2315,51 +2317,92 @@ got_buffer_from_side (ProxySide *side, Buffer *buffer)
got_buffer_from_bus (client, side, buffer);
}
#define _DBUS_ISASCII(c) ((c) != '\0' && (((c) & ~0x7f) == 0))
static gboolean
auth_line_is_valid (guint8 *line, guint8 *line_end)
{
guint8 *p;
for (p = line; p < line_end; p++)
{
if (!_DBUS_ISASCII(*p))
return FALSE;
/* Technically, the dbus spec allows all ASCII characters, but for robustness we also
fail if we see any control characters. Such low values will appear in potential attacks,
but will never happen in real sasl (where all binary data is hex encoded). */
if (*p < ' ')
return FALSE;
}
/* For robustness we require the first char of the line to be an upper case letter.
This is not technically required by the dbus spec, but all commands are upper
case, and there is no provisioning for whitespace before the command, so in practice
this is true, and this means we're not confused by e.g. initial whitespace. */
if (line[0] < 'A' || line[0] > 'Z')
return FALSE;
return TRUE;
}
static gboolean
auth_line_is_begin (guint8 *line)
{
guint8 next_char;
if (!g_str_has_prefix ((char *)line, AUTH_BEGIN))
return FALSE;
/* dbus-daemon accepts either nothing, or a whitespace followed by anything as end of auth */
next_char = line[strlen (AUTH_BEGIN)];
return (next_char == 0 ||
next_char == ' ' ||
next_char == '\t');
}
static gssize
find_auth_end (FlatpakProxyClient *client, Buffer *buffer)
{
guchar *match;
int i;
goffset offset = 0;
gsize original_size = client->auth_buffer->len;
/* First try to match any leftover at the start */
if (client->auth_end_offset > 0)
/* Add the new data to the remaining data from last iteration */
g_byte_array_append (client->auth_buffer, buffer->data, buffer->pos);
while (TRUE)
{
gsize left = strlen (AUTH_END_STRING) - client->auth_end_offset;
gsize to_match = MIN (left, buffer->pos);
/* Matched at least up to to_match */
if (memcmp (buffer->data, &AUTH_END_STRING[client->auth_end_offset], to_match) == 0)
guint8 *line_start = client->auth_buffer->data + offset;
gsize remaining_data = client->auth_buffer->len - offset;
guint8 *line_end;
line_end = memmem (line_start, remaining_data,
AUTH_LINE_SENTINEL, strlen (AUTH_LINE_SENTINEL));
if (line_end) /* Found end of line */
{
client->auth_end_offset += to_match;
offset = (line_end + strlen (AUTH_LINE_SENTINEL) - line_start);
/* Matched all */
if (client->auth_end_offset == strlen (AUTH_END_STRING))
return to_match;
if (!auth_line_is_valid (line_start, line_end))
return FIND_AUTH_END_ABORT;
/* Matched to end of buffer */
return -1;
*line_end = 0;
if (auth_line_is_begin (line_start))
return offset - original_size;
/* continue with next line */
}
/* Did not actually match at start */
client->auth_end_offset = -1;
}
/* Look for whole match inside buffer */
match = memmem (buffer, buffer->pos,
AUTH_END_STRING, strlen (AUTH_END_STRING));
if (match != NULL)
return match - buffer->data + strlen (AUTH_END_STRING);
/* Record longest prefix match at the end */
for (i = MIN (strlen (AUTH_END_STRING) - 1, buffer->pos); i > 0; i--)
{
if (memcmp (buffer->data + buffer->pos - i, AUTH_END_STRING, i) == 0)
else
{
client->auth_end_offset = i;
break;
/* No end-of-line in this buffer */
g_byte_array_remove_range (client->auth_buffer, 0, offset);
/* Abort if more than 16k before newline, similar to what dbus-daemon does */
if (client->auth_buffer->len >= 16*1024)
return FIND_AUTH_END_ABORT;
return FIND_AUTH_END_CONTINUE;
}
}
return -1;
}
static gboolean
@@ -2418,6 +2461,14 @@ side_in_cb (GSocket *socket, GIOCondition condition, gpointer user_data)
if (extra_data > 0)
side->extra_input_data = g_bytes_new (buffer->data + buffer->size, extra_data);
}
else if (auth_end == FIND_AUTH_END_ABORT)
{
buffer_unref (buffer);
if (client->proxy->log_messages)
g_print ("Invalid AUTH line, aborting\n");
side_closed (side);
break;
}
}
got_buffer_from_side (side, buffer);

View File

@@ -24,6 +24,7 @@ man1 = \
flatpak-remote-delete.1 \
flatpak-remote-modify.1 \
flatpak-remote-ls.1 \
flatpak-remote-info.1 \
flatpak-install.1 \
flatpak-config.1 \
flatpak-update.1 \
@@ -48,6 +49,7 @@ man1 = \
flatpak-build-sign.1 \
flatpak-build-commit-from.1 \
flatpak-repo.1 \
flatpak-search.1 \
$(NULL)
man5 = \
@@ -94,4 +96,3 @@ flatpak-docs.html: flatpak-docs.xml $(xml_files) xmlto-config.xsl
$(AM_V_GEN) $(XMLTO) $(XMLTO_FLAGS) --skip-validation xhtml-nochunks -m $(srcdir)/xmlto-config.xsl $<
endif # DOCBOOK_DOCS_ENABLED

View File

@@ -61,6 +61,11 @@
autobuilder, and can be properly signed with the official
key.
</para>
<para>
Any deltas that affect the original commit and that match parent
commits in the destination repository are copied and rewritten
for the new commit id.
</para>
</refsect1>
<refsect1>
@@ -129,7 +134,7 @@
<term><option>--update-appstream</option></term>
<listitem><para>
Run appstream-builder and to update the appstream branch after build.
Update the appstream branch after the build.
</para></listitem>
</varlistentry>

View File

@@ -173,11 +173,19 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--timestamp=DATE</option></term>
<listitem><para>
Use the specified ISO 8601 formatted date in the commit metadata and, if <option>--update-appstream</option> is used, the appstream data.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--update-appstream</option></term>
<listitem><para>
Run appstream-builder and to update the appstream branch after build.
Update the appstream branch after the build.
</para></listitem>
</varlistentry>

View File

@@ -122,7 +122,7 @@
<listitem><para>
Expose a well known socket to the application. This updates
the [Context] group in the metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>
@@ -133,7 +133,7 @@
<listitem><para>
Don't expose a well known socket to the application. This updates
the [Context] group in the metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>

View File

@@ -101,7 +101,7 @@
<term><option>--update-appstream</option></term>
<listitem><para>
Run appstream-builder and to update the appstream branch after build.
Update the appstream branch after the build.
</para></listitem>
</varlistentry>

View File

@@ -2,7 +2,7 @@
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="flatpak-build-export">
<refentry id="flatpak-build-sign">
<refentryinfo>
<title>flatpak build-sign</title>

View File

@@ -140,7 +140,7 @@
<listitem><para>
Expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>
@@ -151,7 +151,7 @@
<listitem><para>
Don't expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>
@@ -345,6 +345,16 @@ key=v1;v2;
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--readonly</option></term>
<listitem><para>
Mount the normally writable destination directories read-only. This can
be useful if you want to run something in the sandbox but guarantee that
it doesn't affect the build results. For example tests.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--metadata=FILE</option></term>
@@ -356,7 +366,25 @@ key=v1;v2;
</para></listitem>
</varlistentry>
</variablelist>
<varlistentry>
<term><option>--log-session-bus</option></term>
<listitem><para>
Log session bus traffic. This can be useful to see what access you need to allow in
your D-Bus policy.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--log-system-bus</option></term>
<listitem><para>
Log system bus traffic. This can be useful to see what access you need to allow in
your D-Bus policy.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>

View File

@@ -19,40 +19,44 @@
</chapter>
<chapter>
<title>Commands</title>
<xi:include href="@srcdir@/flatpak-install.xml"/>
<xi:include href="@srcdir@/flatpak-update.xml"/>
<xi:include href="@srcdir@/flatpak-uninstall.xml"/>
<xi:include href="@srcdir@/flatpak-list.xml"/>
<xi:include href="@srcdir@/flatpak-info.xml"/>
<xi:include href="@srcdir@/flatpak-run.xml"/>
<xi:include href="@srcdir@/flatpak-override.xml"/>
<xi:include href="@srcdir@/flatpak-make-current.xml"/>
<xi:include href="@srcdir@/flatpak-enter.xml"/>
<xi:include href="@srcdir@/flatpak-document-export.xml"/>
<xi:include href="@srcdir@/flatpak-document-unexport.xml"/>
<xi:include href="@srcdir@/flatpak-document-info.xml"/>
<xi:include href="@srcdir@/flatpak-document-list.xml"/>
<xi:include href="@srcdir@/flatpak-remotes.xml"/>
<xi:include href="@srcdir@/flatpak-remote-add.xml"/>
<xi:include href="@srcdir@/flatpak-remote-modify.xml"/>
<xi:include href="@srcdir@/flatpak-remote-delete.xml"/>
<xi:include href="@srcdir@/flatpak-remote-ls.xml"/>
<xi:include href="@srcdir@/flatpak-build-init.xml"/>
<xi:include href="@srcdir@/flatpak-build.xml"/>
<xi:include href="@srcdir@/flatpak-build-finish.xml"/>
<xi:include href="@srcdir@/flatpak-build-export.xml"/>
<xi:include href="@srcdir@/flatpak-build-bundle.xml"/>
<xi:include href="@srcdir@/flatpak-build-commit-from.xml"/>
<xi:include href="@srcdir@/flatpak-build-export.xml"/>
<xi:include href="@srcdir@/flatpak-build-finish.xml"/>
<xi:include href="@srcdir@/flatpak-build-import-bundle.xml"/>
<xi:include href="@srcdir@/flatpak-build-init.xml"/>
<xi:include href="@srcdir@/flatpak-build-sign.xml"/>
<xi:include href="@srcdir@/flatpak-build-update-repo.xml"/>
<xi:include href="@srcdir@/flatpak-build-commit-from.xml"/>
<xi:include href="@srcdir@/flatpak-build.xml"/>
<xi:include href="@srcdir@/flatpak-config.xml"/>
<xi:include href="@srcdir@/flatpak-document-export.xml"/>
<xi:include href="@srcdir@/flatpak-document-info.xml"/>
<xi:include href="@srcdir@/flatpak-document-list.xml"/>
<xi:include href="@srcdir@/flatpak-document-unexport.xml"/>
<xi:include href="@srcdir@/flatpak-enter.xml"/>
<xi:include href="@srcdir@/flatpak-info.xml"/>
<xi:include href="@srcdir@/flatpak-install.xml"/>
<xi:include href="@srcdir@/flatpak-list.xml"/>
<xi:include href="@srcdir@/flatpak-make-current.xml"/>
<xi:include href="@srcdir@/flatpak-override.xml"/>
<xi:include href="@srcdir@/flatpak-remote-add.xml"/>
<xi:include href="@srcdir@/flatpak-remote-delete.xml"/>
<xi:include href="@srcdir@/flatpak-remote-info.xml"/>
<xi:include href="@srcdir@/flatpak-remote-ls.xml"/>
<xi:include href="@srcdir@/flatpak-remote-modify.xml"/>
<xi:include href="@srcdir@/flatpak-remotes.xml"/>
<xi:include href="@srcdir@/flatpak-repo.xml"/>
<xi:include href="@srcdir@/flatpak-run.xml"/>
<xi:include href="@srcdir@/flatpak-search.xml"/>
<xi:include href="@srcdir@/flatpak-uninstall.xml"/>
<xi:include href="@srcdir@/flatpak-update.xml"/>
</chapter>
<chapter>
<title>File Formats</title>
<xi:include href="@srcdir@/flatpak-metadata.xml"/>
<xi:include href="@srcdir@/flatpak-flatpakrepo.xml"/>
<xi:include href="@srcdir@/flatpak-flatpakref.xml"/>
<xi:include href="@srcdir@/flatpak-remote.xml"/>
<xi:include href="@srcdir@/flatpak-installation.xml"/>
<xi:include href="@srcdir@/flatpak-metadata.xml"/>
<xi:include href="@srcdir@/flatpak-remote.xml"/>
</chapter>
</reference>

View File

@@ -70,10 +70,15 @@
will list the alternatives.
</para>
<para>
By default this looks for both apps and runtime with the given <arg choice="plain">REF</arg> in
By default this looks for both apps and runtimes with the given <arg choice="plain">REF</arg> in
the specified <arg choice="plain">REMOTE</arg>, but you can limit this by using the --app or
--runtime option, or by supplying the initial element in the REF.
</para>
<para>
If <arg choice="plain">REMOTE</arg> is a uri or a path (absolute or relative starting with ./)
to a local repository, then that repository will be used as the source, and a temporary remote
will be created for the lifetime of the <arg choice="plain">REF</arg>.
</para>
<para>
The alternative form of the command (<arg>--from</arg> or
<arg>--bundle</arg> allows you to

View File

@@ -76,7 +76,7 @@
</varlistentry>
<varlistentry>
<term><option>StorageType</option> (string)</term>
<listitem><para>The type of storage used for this installation. Possible values include: mmc, sdcard, harddisk.</para></listitem>
<listitem><para>The type of storage used for this installation. Possible values include: network, mmc, sdcard, harddisk.</para></listitem>
</varlistentry>
</variablelist>
</refsect2>

View File

@@ -142,7 +142,7 @@
<term><option>sockets</option> (list)</term>
<listitem><para>
List of well-known sockets to make available in the sandbox.
Possible sockets: x11, wayland, pulseaudio, session-bus, system-bus.
Possible sockets: x11, wayland, fallback-x11, pulseaudio, session-bus, system-bus.
When making a socket available, flatpak also sets
well-known environment variables like DISPLAY or
DBUS_SYSTEM_BUS_ADDRESS to let the application

View File

@@ -32,7 +32,7 @@
<cmdsynopsis>
<command>flatpak override</command>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">APP</arg>
<arg choice="opt">APP</arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -49,6 +49,10 @@
on a particular instance by specifying extra arguments to
flatpak run, or every time by using flatpak override.
</para>
<para>
If the application id is not specified then the overrides affect all applications,
but the per-application overrides can override the global overrides.
</para>
<para>
Unless overridden with the --user or --installation options, this command
changes the default system-wide installation.
@@ -126,7 +130,7 @@
<listitem><para>
Expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>
@@ -137,7 +141,7 @@
<listitem><para>
Don't expose a well-known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>

View File

@@ -246,9 +246,9 @@
<para>
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-modify-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-delete-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-list-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remote-modify</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remote-delete</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-flatpakrepo</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

View File

@@ -44,8 +44,10 @@
<arg choice="plain">NAME</arg> is the name of an existing remote.
</para>
<para>
Unless overridden with the --user or --installation options, this command
changes the default system-wide installation.
Unless overridden with the --system, --user, or --installation options,
this command uses either the default system-wide installation or the
per-user one, depending on which has the specified
<arg choice="plain">REMOTE</arg>.
</para>
</refsect1>
@@ -140,9 +142,9 @@
<para>
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-add-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-modify-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-list-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<citerefentry><refentrytitle>flatpak-remote-add</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remote-modify</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

233
doc/flatpak-remote-info.xml Normal file
View File

@@ -0,0 +1,233 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="flatpak-remote-info">
<refentryinfo>
<title>flatpak remote-info</title>
<productname>flatpak</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Alexander</firstname>
<surname>Larsson</surname>
<email>alexl@redhat.com</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>flatpak remote-info</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>flatpak-remote-info</refname>
<refpurpose>Show information about an application or runtime in a remote</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>flatpak remote-info</command>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">REMOTE</arg>
<arg choice="plain">REF</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
Shows information about the runtime or application <arg choice="plain">REF</arg> from the
remote repository with the name <arg choice="plain">REMOTE</arg>.
You can find all configured remote repositories with flatpak remotes.
</para>
<para>
By default, the output is formatted in a friendly format.
If you specify one of the options --show-ref, --show-commit,
--show-parent, or --show-metadata, the output is instead formatted
in a machine-readable format.
</para>
<para>
Unless overridden with the --system, --user, or --installation options,
this command uses either the default system-wide installation or the
per-user one, depending on which has the specified
<arg choice="plain">REMOTE</arg>.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>-h</option></term>
<term><option>--help</option></term>
<listitem><para>
Show help options and exit.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--user</option></term>
<listitem><para>
Use the per-user configuration.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--system</option></term>
<listitem><para>
Use the default system-wide configuration.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--installation=NAME</option></term>
<listitem><para>
Use a system-wide installation specified by <arg choice="plain">NAME</arg>
among those defined in <filename>/etc/flatpak/installations.d/</filename>.
Using <arg choice="plain">--installation=default</arg> is equivalent to using
<arg choice="plain">--system</arg>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--runtime</option></term>
<listitem><para>
Assume that <arg choice="plain">REF</arg> is a runtime if not explicitly specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--app</option></term>
<listitem><para>
Assume that <arg choice="plain">REF</arg> is an app if not explicitly specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--arch=ARCH</option></term>
<listitem><para>
The default architecture to look for, if not given explicitly in the <arg choice="plain">REF</arg>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--commit=COMMIT</option></term>
<listitem><para>
Show information about the specific commit, rather than the latest version.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--log</option></term>
<listitem><para>
Display a log of previous versions.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-r</option></term>
<term><option>--show-ref</option></term>
<listitem><para>
Show the matched ref.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-c</option></term>
<term><option>--show-commit</option></term>
<listitem><para>
Show the commit id.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-p</option></term>
<term><option>--show-parent</option></term>
<listitem><para>
Show the parent commit id.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-m</option></term>
<term><option>--show-metadata</option></term>
<listitem><para>
Show the metadata.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option></term>
<term><option>--verbose</option></term>
<listitem><para>
Print debug information during command processing.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--ostree-verbose</option></term>
<listitem><para>
Print OSTree debug information during command processing.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
<command>$ flatpak --user remote-info flathub org.gnome.gedit</command>
</para>
<programlisting>
Ref: app/org.gnome.gedit/x86_64/stable
ID: org.gnome.gedit
Arch: x86_64
Branch: stable
Date: 2017-07-31 16:05:22 +0000
Subject: Build org.gnome.gedit at 3ec291fc1ce4d78220527fa79576f4cc1481ebe5
Commit: 3de7e9dde3bb8382aad9dfbbff20eccd9bf2100bc1887a3619ec0372e8066bf7
Parent: -
Download size: 3,4 MB
Installed size: 11,1 MB
Runtime: org.gnome.Platform/x86_64/3.24
</programlisting>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<citerefentry><refentrytitle>flatpak-remote-ls</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@@ -32,7 +32,7 @@
<cmdsynopsis>
<command>flatpak remote-ls</command>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">REMOTE</arg>
<arg choice="opt">REMOTE</arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -41,12 +41,15 @@
<para>
Shows runtimes and applications that are available in the
remote repository with the name <arg choice="plain">REMOTE</arg>.
You can find all configured remote repositories with flatpak remote-list.
remote repository with the name <arg choice="plain">REMOTE</arg>,
or all remotes if one isn't specified. You can find all configured
remote repositories with <citerefentry><refentrytitle>flatpak-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
</para>
<para>
Unless overridden with the --user or --installation options, this command
uses the default system-wide configuration.
Unless overridden with the --system, --user, or --installation options,
this command uses either the default system-wide installation or the
per-user one, depending on which has the specified
<arg choice="plain">REMOTE</arg>.
</para>
</refsect1>
@@ -190,7 +193,7 @@ org.freedesktop.glxgears
<para>
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remote-list</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<citerefentry><refentrytitle>flatpak-remotes</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

View File

@@ -44,8 +44,10 @@
<arg choice="plain">NAME</arg> is the name for the remote.
</para>
<para>
Unless overridden with the --user or --installation options, this command
changes the default system-wide installation.
Unless overridden with the --system, --user, or --installation options,
this command uses either the default system-wide installation or the
per-user one, depending on which has the specified
<arg choice="plain">REMOTE</arg>.
</para>
</refsect1>

View File

@@ -96,7 +96,7 @@
<term><option>--show-details</option></term>
<listitem><para>
Show more information each repository in addition to the name.
Show more information for each repository in addition to the name.
</para></listitem>
</varlistentry>
@@ -151,8 +151,8 @@ testrepo Test Repository http://209.132.179.91/repo/ no-gpg-verify
<para>
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-add-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-delete-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<citerefentry><refentrytitle>flatpak-remote-add</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>flatpak-remote-delete</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

View File

@@ -181,7 +181,7 @@
<listitem><para>
Expose a well known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>
@@ -192,7 +192,7 @@
<listitem><para>
Don't expose a well known socket to the application. This overrides to
the Context section from the application metadata.
SOCKET must be one of: x11, wayland, pulseaudio, system-bus, session-bus.
SOCKET must be one of: x11, wayland, fallback-x11, pulseaudio, system-bus, session-bus.
This option can be used multiple times.
</para></listitem>
</varlistentry>

102
doc/flatpak-search.xml Normal file
View File

@@ -0,0 +1,102 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="flatpak-search">
<refentryinfo>
<title>flatpak search</title>
<productname>flatpak</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Patrick</firstname>
<surname>Griffis</surname>
<email>tingping@tingping.se</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>flatpak search</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>flatpak-search</refname>
<refpurpose>Search for applications and runtimes</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>flatpak search</command>
<arg choice="plain">TEXT</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
Searches for applications and runtimes matching
<arg choice="plain">TEXT</arg>. Note that this uses appstream data
that can be updated with <citerefentry><refentrytitle>flatpak-update</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
The appstream data is updated automatically only if it's at least a day old.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--user</option></term>
<listitem><para>
Only search through remotes in the per-user installation.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--system</option></term>
<listitem><para>
Only search through remotes in the default system-wide installation.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--installation=NAME</option></term>
<listitem><para>
Show a system-wide installation by <arg choice="plain">NAME</arg> among
those defined in <filename>/etc/flatpak/installations.d/</filename>.
Using <arg choice="plain">--installation=default</arg> is equivalent to using
<arg choice="plain">--system</arg>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option></term>
<term><option>--help</option></term>
<listitem><para>
Show help options and exit.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option></term>
<term><option>--verbose</option></term>
<listitem><para>
Print debug information during command processing.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>

View File

@@ -41,8 +41,7 @@
<para>
Uninstalls an application or runtime. <arg choice="plain">REF</arg> is a reference to the
application or runtime to install. If no <arg choice="plain">REF</arg> is given, everything
is updated.
application or runtime to uninstall.
</para>
<para>
Each <arg choice="plain">REF</arg> arguments is a full or partial indentifier in the
@@ -147,7 +146,7 @@
<term><option>--runtime</option></term>
<listitem><para>
Only look for an runtime with the given name.
Only look for a runtime with the given name.
</para></listitem>
</varlistentry>

View File

@@ -34,6 +34,12 @@
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="opt" rep="repeat">REF</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>flatpak update</command>
<arg choice="opt" rep="repeat">OPTION</arg>
<arg choice="plain">--appstream</arg>
<arg choice="opt">REMOTE</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -41,8 +47,8 @@
<para>
Updates applications and runtimes. <arg choice="plain">REF</arg> is a reference to the
application or runtime to install. If no <arg choice="plain">REF</arg> is given, everything
is updated.
application or runtime to update. If no <arg choice="plain">REF</arg> is given, everything
is updated, as well as appstream info for all remotes.
</para>
<para>
Each <arg choice="plain">REF</arg> arguments is a full or partial indentifier in the
@@ -53,9 +59,9 @@
will list the alternatives.
</para>
<para>
By default this looks for both apps and runtime with the given <arg choice="plain">REF</arg> in
the specified <arg choice="plain">REMOTE</arg>, but you can limit this by using the --app or
--runtime option, or by supplying the initial element in the REF.
By default this looks for both apps and runtimes with the given <arg choice="plain">REF</arg>,
but you can limit this by using the --app or --runtime option, or by supplying the initial
element in the REF.
</para>
<para>
Normally, this command updates the application to the tip
@@ -70,8 +76,8 @@
version, with the --commit option.
</para>
<para>
Unless overridden with the --user or the --installation option, this command updates
the default system-wide installation.
Unless overridden with the --user, --system or --installation option, this command updates
any matching refs in the standard system-wide installation and the per-user one.
</para>
</refsect1>
@@ -156,7 +162,7 @@
<term><option>--no-pull</option></term>
<listitem><para>
Don't download the latest version, deploy it whatever is locally available.
Don't download the latest version, deploy whatever is locally available.
</para></listitem>
</varlistentry>
@@ -188,7 +194,7 @@
<term><option>--appstream</option></term>
<listitem><para>
Update appstream for the remote.
Update appstream for <arg choice="plain">REMOTE</arg>, or all remotes if no remote is specified.
</para></listitem>
</varlistentry>
@@ -196,7 +202,7 @@
<term><option>--runtime</option></term>
<listitem><para>
Only look for an runtime with the given name.
Only look for a runtime with the given name.
</para></listitem>
</varlistentry>

View File

@@ -102,7 +102,7 @@
<term><option>--verbose</option></term>
<listitem><para>
Print debug information during command processing.
Print debug information during command processing. Use -vv for more detail.
</para></listitem>
</varlistentry>
@@ -200,6 +200,19 @@
</variablelist>
<para>Commands for finding applications and runtimes:</para>
<variablelist>
<varlistentry>
<term><citerefentry><refentrytitle>flatpak-search</refentrytitle><manvolnum>1</manvolnum></citerefentry></term>
<listitem><para>
Search for applications and runtimes.
</para></listitem>
</varlistentry>
</variablelist>
<para>Commands for running applications:</para>
<variablelist>
@@ -305,6 +318,13 @@
List contents of a configured remote repository.
</para></listitem>
</varlistentry>
<varlistentry>
<term><citerefentry><refentrytitle>flatpak-remote-info</refentrytitle><manvolnum>1</manvolnum></citerefentry></term>
<listitem><para>
Show information about a ref in a configured remote repository.
</para></listitem>
</varlistentry>
</variablelist>
<para>Commands for building applications:</para>
@@ -342,7 +362,7 @@
<term><citerefentry><refentrytitle>flatpak-build-bundle</refentrytitle><manvolnum>1</manvolnum></citerefentry></term>
<listitem><para>
Create a bundle file from a build directory.
Create a bundle file from a ref in a local repository.
</para></listitem>
</varlistentry>
<varlistentry>

View File

@@ -1,43 +0,0 @@
libexec_PROGRAMS += \
xdg-document-portal \
$(NULL)
xdp_dbus_built_sources = document-portal/xdp-dbus.c document-portal/xdp-dbus.h
BUILT_SOURCES += $(xdp_dbus_built_sources)
document-portal/xdp-dbus.c: data/org.freedesktop.portal.Documents.xml Makefile
mkdir -p $(builddir)/document-portal
$(AM_V_GEN) $(GDBUS_CODEGEN) \
--interface-prefix org.freedesktop.portal. \
--c-namespace XdpDbus \
--generate-c-code $(builddir)/document-portal/xdp-dbus \
--annotate "org.freedesktop.portal.Documents.Add()" org.gtk.GDBus.C.UnixFD "yes" \
--annotate "org.freedesktop.portal.Documents.AddFull()" org.gtk.GDBus.C.UnixFD "yes" \
$(srcdir)/data/org.freedesktop.portal.Documents.xml \
$(NULL)
document-portal/%-dbus.h: document-portal/%-dbus.c
@true # Built as a side-effect of the rules for the .c
service_in_files += document-portal/xdg-document-portal.service.in
systemduserunit_DATA += document-portal/xdg-document-portal.service
service_in_files += document-portal/org.freedesktop.portal.Documents.service.in
dbus_service_DATA += document-portal/org.freedesktop.portal.Documents.service
nodist_xdg_document_portal_SOURCES = \
$(xdp_dbus_built_sources) \
$(ps_dbus_built_sources) \
$(NULL)
xdg_document_portal_SOURCES = \
document-portal/xdp-main.c \
document-portal/xdp-enums.h \
document-portal/xdp-util.h \
document-portal/xdp-util.c \
document-portal/xdp-fuse.h \
document-portal/xdp-fuse.c \
$(NULL)
xdg_document_portal_LDADD = $(AM_LDADD) $(BASE_LIBS) $(FUSE_LIBS) libflatpak-common.la
xdg_document_portal_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) $(FUSE_CFLAGS) -I$(srcdir)/document-portal -I$(builddir)/document-portal -I$(srcdir)/permission-store -I$(builddir)/permission-store -DFLATPAK_COMPILATION

View File

@@ -1,4 +0,0 @@
[D-BUS Service]
Name=org.freedesktop.portal.Documents
Exec=@libexecdir@/xdg-document-portal
SystemdService=xdg-document-portal.service

View File

@@ -1,7 +0,0 @@
[Unit]
Description=flatpak document portal service
[Service]
BusName=org.freedesktop.portal.Documents
ExecStart=@libexecdir@/xdg-document-portal
Type=dbus

View File

@@ -1,25 +0,0 @@
#ifndef XDP_ENUMS_H
#define XDP_ENUMS_H
G_BEGIN_DECLS
typedef enum {
XDP_PERMISSION_FLAGS_READ = (1 << 0),
XDP_PERMISSION_FLAGS_WRITE = (1 << 1),
XDP_PERMISSION_FLAGS_GRANT_PERMISSIONS = (1 << 2),
XDP_PERMISSION_FLAGS_DELETE = (1 << 3),
XDP_PERMISSION_FLAGS_ALL = ((1 << 4) - 1)
} XdpPermissionFlags;
typedef enum {
XDP_ADD_FLAGS_REUSE_EXISTING = (1 << 0),
XDP_ADD_FLAGS_PERSISTENT = (1 << 1),
XDP_ADD_FLAGS_AS_NEEDED_BY_APP = (1 << 2),
XDP_ADD_FLAGS_FLAGS_ALL = ((1 << 3) - 1)
} XdpAddFullFlags;
G_END_DECLS
#endif /* XDP_ENUMS_H */

Some files were not shown because too many files have changed in this diff Show More