mirror of
https://github.com/flatpak/flatpak.git
synced 2026-03-16 14:08:33 -04:00
Update Ukrainian translation
This commit is contained in:
25
.gitignore
vendored
25
.gitignore
vendored
@@ -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
84
CODE_OF_CONDUCT.md
Normal 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 people’s 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 someone’s 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 venues–online and in-person–as 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/)
|
||||
@@ -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
120
NEWS
@@ -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
|
||||
=======================
|
||||
|
||||
|
||||
23
README.md
23
README.md
@@ -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
|
||||
|
||||
@@ -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)\"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
360
app/flatpak-builtins-info-remote.c
Normal file
360
app/flatpak-builtins-info-remote.c
Normal 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;
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
338
app/flatpak-builtins-search.c
Normal file
338
app/flatpak-builtins-search.c
Normal 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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
187
common/flatpak-bwrap.c
Normal 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
63
common/flatpak-bwrap.h
Normal 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__ */
|
||||
@@ -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
2007
common/flatpak-context.c
Normal file
File diff suppressed because it is too large
Load Diff
128
common/flatpak-context.h
Normal file
128
common/flatpak-context.h
Normal 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__ */
|
||||
1224
common/flatpak-db.c
1224
common/flatpak-db.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
1397
common/flatpak-dir.c
1397
common/flatpak-dir.c
File diff suppressed because it is too large
Load Diff
@@ -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
530
common/flatpak-exports.c
Normal 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
62
common/flatpak-exports.h
Normal 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__ */
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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, ¬_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, ¬_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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
3316
common/flatpak-run.c
3316
common/flatpak-run.c
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 (>k_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 (>k_theme, g_strdup (""));
|
||||
else
|
||||
{
|
||||
schema = g_settings_schema_source_lookup (source,
|
||||
"org.gnome.desktop.interface", FALSE);
|
||||
|
||||
if (schema == NULL)
|
||||
g_once_init_leave (>k_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 (>k_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, ×tamp,
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
2
common/gvdb/.gitignore
vendored
2
common/gvdb/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
libgvdb.a
|
||||
libgvdb-shared.a
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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>
|
||||
15
configure.ac
15
configure.ac
@@ -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"],
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
233
doc/flatpak-remote-info.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
102
doc/flatpak-search.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -1,4 +0,0 @@
|
||||
[D-BUS Service]
|
||||
Name=org.freedesktop.portal.Documents
|
||||
Exec=@libexecdir@/xdg-document-portal
|
||||
SystemdService=xdg-document-portal.service
|
||||
@@ -1,7 +0,0 @@
|
||||
[Unit]
|
||||
Description=flatpak document portal service
|
||||
|
||||
[Service]
|
||||
BusName=org.freedesktop.portal.Documents
|
||||
ExecStart=@libexecdir@/xdg-document-portal
|
||||
Type=dbus
|
||||
@@ -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
Reference in New Issue
Block a user