diff --git a/doc/flatpak-support.rst b/doc/flatpak-support.rst new file mode 100644 index 0000000000..32bcf35636 --- /dev/null +++ b/doc/flatpak-support.rst @@ -0,0 +1,95 @@ +Flatpak Support in IoT Reference OS Kit +####################################### + +IoT Reference OS Kit supports installing and running applications packaged +as `flatpaks `_. + +Flatpak in a Nutshell +---------------------- + +Flatpak is a framework for building, distributing, and managing applications. +It conceptually splits the software stack into + +* a runtime: the core/common bits, +* an SDK: bits necessary for building software for a runtime, +* the applications themselves + +Flatpak decouples the life-cycle of the application from that of the +underlying distro. By doing so it enables updating the distro and the +(flatpak) applications independently from each other. + +Additionally flatpak provides application sandboxing out of the box and +relies largely on `ostree `_ for providing +an infrastructure for application (binary) version control, distribution +and deployment. + +For more information and details see the corresponding documentation of +flatpak and ostree. + +Basic Flatpak Support +--------------------- + +Basic flatpak support includes recipes for flatpak and its runtime and +buildtime dependencies as well as Yocto helper classes for building +flatpak-enabled versions of images. It can be enabled by the *flatpak* +distro feature. Since it has additional prerequisites, the easiest way +to enable it is to include :file:`meta-flatpak/conf/distro/include/flatpak.inc` +in your build configuration. + +Flatpak Image Variants +---------------------- + +When the *flatpak* distro feature is enabled ``meta-flatpak`` defines +two flatpak-specific image variants: + +* *flatpak-runtime*: a flatpak-enabled image to be used on a target device +* *flatpak-sdk*: a *flatpak SDK runtime* to be used on a (development) host + +The *flatpak-runtime* variant adds flatpak, ostree, etc., all the necessary +runtime bits to run flatpak, to the image. With such an image on a target +device you should be able to invoke flatpak to carry out the normal flatpak +operations, including defining flatpak remotes, installing, uninstalling and +running flatpak applications. + +The *flatpak-sdk* variant adds the compiler toolchain, developement packages +debug symbols, version control software, etc., in short everything you might +need to compile and turn your applications into flatpaks intended to be +installed on the *flatpak-runtime* image variant. + +You can refer to these image variants by appending their name to that +of the base image. For instance you can build both of these variants for +*refkit-image-gateway* by running: + +``` +bitbake -c refkit-image-gateway-flatpak-runtime refkit-image-gateway-flatpak-sdk +``` + +Extra Flatpak-based Functionality - Flatpak Session +--------------------------------------------------- + +In addition to stock flatpak support, *meta-flatpak* provides support +for running a set of flatpaks from a common remote using a dedicated +user, monitoring the remote for updates and/or new applications and +automatically installing and activating those. + +Support for this extra set of functionality is controlled by the +*flatpak-session* distro feature. The easiest way to enable it is to +include :file:`meta-flatpak/conf/distro/include/flatpak.inc` in your +build configuration. + +See the comment section in :file:`meta-flatpak/classes/flatpak-config.bbclass` +for more details about the necessary steps or configuration you need to go +through to have a *flatpak session* set up for a remote on your device. + +Caveats +------- + +In addition to the basic flatpak dependencies a *flatpak-runtime* variant +also pulls into the image a systemd service which is used to activate a +'fake' flatpak runtime. This is basically a few files and bind mounts that +are used to emulate an flatpak-installed *flatpak runtime* for the image +itself. If you don't want it in your image, you can exclude it by putting +an appropriately crafted _remove for your image in your build configuration. +Note however, that either this fake runtime or the real flatpak runtime for +the image needs to be installed, otherwise you cannot install and run +flatpaks compiled for your image. diff --git a/doc/howtos/yocto-compatible.rst b/doc/howtos/yocto-compatible.rst new file mode 100644 index 0000000000..67c349f738 --- /dev/null +++ b/doc/howtos/yocto-compatible.rst @@ -0,0 +1,190 @@ +Yocto Compatible 2.0 +==================== + +The main goal of the next revision of the Yocto compliance program, +called "Yocto Compatible 2.0", is to increase inter-operability of +different layers. One key aspect is that a layer must not change a +build configuration merely because it gets added to a build. Instead, +only some explicit build configuration change (like setting distro +flags or including a .inc file provided by the layer) may cause the +build to change. + +All meta-refkit layers are "Yocto Compatible 2.0". In addition to +that, it is guaranteed that including :file:`refkit-config.inc` will +also not change the build. It merely provides support for choosing +some of the distro features implemented in intel-iot-refkit, without +actually turning them on. That choice is still left to the developer +or distro. + +The "Layer Overview and Reuse" section in :file:`introduction.rst` +explains how to use this. This document is about the implementation. + + +Implementation +============== + +Optional ``.bbappends`` +----------------------- + +:file:`refkit-config.inc` contains global distro settings, including +"normal" re-configuration of recipes via ``PACKAGECONFIG`` +changes. Everything that goes beyond that needs to be in a +``.bbappend``. Often these are workarounds or new recipe features that +long-term might be more suitable for inclusion into the upstream +recipe. + +Such ``.bbappends`` go into ``meta-refkit-core`` (when they are common +to multiple profiles) or individual profile layers. Normally a layer +can only provide ``.bbappends`` for recipes that are known to be +available. A fatal error aborts parsing when no ``.bb`` file is found +for a ``.bbappend``, to catch cases where the original ``.bb`` was +renamed and the ``.bbappend`` must be updated. + +``meta-refkit-core/bbappends`` contains a directory hierarchy that +matches the structure of upstream layers that are used in +``intel-iot-refkit``. ``BBFILES_DYNAMIC`` instead of the normal +``BBFILES`` is used to enable ``.bbappend`` files only when the +corresponding layer is present in a build, so one still gets the error +when the ``.bb`` file changes, but not when the entire layer is +missing. + +Avoiding Signature Changes +-------------------------- + +:file:`refkit-config.inc` and ``.bbappend`` files must not change the +build when not explicitly enabled via distro features. This is checked by +comparing task signatures. + +There are several different techniques for avoiding task signature +changes, listed here in order of increasing complexity. Use the simplest +approach that works. + +#. conditional ``_append/remove`` + + :file:`refkit-config.inc` defines certain distro features (for + example, ``refkit-config``) which get turned into overrides with + ``df-`` as prefix. By adding those overrides to ``_append`` or + ``_remove``, one can limit that change to configurations where + the feature is active:: + + do_install_append_df-refkit-config () { + ... + } + + Combining multiple overrides applies when all overrides are set + ("and" semantic):: + + do_install_append_df-refkit-firewall_df-refkit-gateway () { + ... + } + + Repeating the variable with different conditions applies the change + when one or more conditions are met ("or" semantic). But beware + that values will be appended more than once when more than one + condition is true. This may be acceptable in some cases, like this + one:: + + EXTRA_OECONF_append_df-refkit-gateway = " --enable-foo" + EXTRA_OECONF_append_df-refkit-industrial = " --enable-foo" + +#. conditional setting of variables + + Setting a variable with an override suffix chooses that value when + the overrides are active:: + + PACKAGECONFIG_pn-foo_df-refkit-config = "bar" + + As before, multiple overrides can be combined again ("and" + semantic). Assignments with more or more important overrides are + chosen over less specific assignments (see the bitbake manual for + details). + + When repeating the same assignment for different cases ("or" + semantic), a helper variable may be useful to avoid repeating code. + Use ``refkit_`` or ``REFKIT_`` as prefix for those:: + + REFKIT_PACKAGECONFIG_FOO = "bar" + PACKAGECONFIG_pn-foo_df-refkit-gateway = "${REFKIT_PACKAGECONFIG_FOO}" + PACKAGECONFIG_pn-foo_df-refkit-industrial = "${REFKIT_PACKAGECONFIG_FOO}" + +#. conditional includes + + Manipulating varflags or some operations (like ``addtask``) do not support + overrides. Such changes can be placed in a .inc file alongside a ``.bbappend`` + and then get included conditionally:: + + require ${@oe.utils.all_distro_features(d, 'refkit-gateway refkit-firewall', 'gateway-and-firewall.inc') } + require ${@oe.utils.any_distro_features(d, 'refkit-gateway refkit-industrial', 'gateway-or-industrial.inc') } + require ${@oe.utils.all_distro_features(d, 'refkit-config', 'config1.inc config2.inc') } + + As shown here, one can check for one or more distro features and + include one or more files at once. The semantic depends on the + function ("or" for ``any_distro_features()``, "and" for + ``all_distro_features()``). When only one feature is listed, + both functions behave the same. When the condition is not satisfied, + these functions return the empty string and nothing gets included. + + They can also be used in a boolean context:: + + if oe.utils.all_distro_features(d, 'refkit-config'): + bb.note('refkit-config is in DISTRO_FEATURES') + + More complex ``${@ }`` expressions are also possible. The two functions + above are merely helper functions that cover the common cases. + + Beware that includes are executed while parsing. Checking for + distro features in a ``.bbappend`` is safe because distro features + are finalized before parsing recipes. For changes affecting the + base configuration, conditional variable changes with overrides + have to be used because these conditions are then checked each time the + variables are used. + + Checking recipe variables is not safe because those might still be + changed later (for example, in another ``.bbappend``). + +#. anonymous Python methods + + Anonymous python methods embedded into a ``.bbappend`` can make + arbitrary changes to the recipe after checking for some condition. + In contrast to conditional includes, anonymous Python methods + are executed at the end of parsing and thus can typically check + recipe variables. The only caveat is that another method might + still change those variables. + + This can be used to replace the ``addtask`` directive without + having to create a separate ``.inc`` file:: + + python () { + if bb.utils.contains('IMAGE_FEATURES', 'ostree', True, False, d) and \ + oe.utils.all_distro_features(d, 'ostree'): + bb.build.addtask('do_ostree_prepare_rootfs', 'do_image_wic', 'do_image', d) + } + + +Testing +======= + +``oe-selftest -r refkit_poky.TestRefkitPokySignatures`` applies the +``yocto-compatible-layer.py`` test script to all ``meta-refkit`` +layers against a base configuration which mirrors the ``Poky`` +distribution. The output in case of a failure contains differences +between task signatures, which usually highlights were some undesired +change is happening. + +``oe-selftest`` can be run in a local build configuration, without +affecting the build itself. See ``oe-selftest --list-tests`` for a +full list of tests that can be run this way. + +The compatibility tests do not guarantee that actual builds will work, +because they only check syntax, dependencies and task +signatures. Actual building is covered by ``oe-selftest -r +refkit_poky.TestRefkitPokyBuilds`` for two build configurations: + +test_common_poky_config + Building ``refkit-image-common`` using just the plain ``Poky`` + distribution settings (for example, without ``systemd``). + +test_common_refkit_config + Building ``refkit-image-common`` using the ``Poky`` + distribution settings plus :file:``enable-refkit-config.inc``, + i.e. all refkit distro features set. diff --git a/meta-flatpak/classes/flatpak-config.bbclass b/meta-flatpak/classes/flatpak-config.bbclass index 094d76316c..188cd82e5a 100644 --- a/meta-flatpak/classes/flatpak-config.bbclass +++ b/meta-flatpak/classes/flatpak-config.bbclass @@ -63,3 +63,31 @@ FLATPAK_BUILD ?= "${DISTRO}/${FLATPAK_PN}/build/${BUILD_ID}" # This is the GPG key id of our repository signing key. If you set this to # empty, signing is disabled altogether. FLATPAK_GPGID ?= "refkit-signing@key" + +# We can pre-populate the image during build with a set of pre-declared +# flatpak repositories and associated dedicated flatpak-session users. +# These repositories will be monitored for flatpaks and any new or updated +# flatpaks which are tagged for automatic installation will be pulled in +# and started within the appropriate flatpak session. +# +# To declare such a remote/repository, you need to +# 1) give the remote a unique name +# 2) provide a remote URL and a GPG public key for signature checking +# 3) associate a user with the remote +# +# The variable FLATPAK_APP_REPOS lists the names of the remotes to pre- +# declare and put into the image. For every remote you have to provide +# +# 1) the remote HTTP URL in ${TOPDIR}/conf/.url +# 2) the remote GPG signing public key in ${TOPDIR}/conf/.key +# 3) provide passwd- and group entries for the associated user in +# ${TOPDIR}/conf/flatpak-passwd and +# ${TOPDIR}/conf/flatpak-group +# The GECOS for the associated entry must be of the form +# 'flatpak user for ', where is the remote name. By +# convention the user's login ID is also , but this is +# not strictly necessary. +# +# By default we do not have any pre-declared application repositories, +# so FLATPAK_APP_REPOS defaults to empty. +FLATPAK_APP_REPOS ?= "" diff --git a/meta-flatpak/classes/flatpak-image-variants.bbclass b/meta-flatpak/classes/flatpak-image-variants.bbclass index 153088e78a..0b1461de9e 100644 --- a/meta-flatpak/classes/flatpak-image-variants.bbclass +++ b/meta-flatpak/classes/flatpak-image-variants.bbclass @@ -8,6 +8,8 @@ IMAGE_FEATURES[validitems] += " \ FEATURE_PACKAGES_flatpak = " \ packagegroup-flatpak \ + ${@bb.utils.contains('DISTRO_FEATURES', 'flatpak-session', \ + 'packagegroup-flatpak-session', '', d)} \ " # diff --git a/meta-flatpak/conf/distro/include/flatpak-session.inc b/meta-flatpak/conf/distro/include/flatpak-session.inc new file mode 100644 index 0000000000..7a69c52cec --- /dev/null +++ b/meta-flatpak/conf/distro/include/flatpak-session.inc @@ -0,0 +1,3 @@ +REFKIT_DEFAULT_DISTRO_FEATURES += " \ + flatpak-session \ +" diff --git a/meta-flatpak/conf/layer.conf b/meta-flatpak/conf/layer.conf index 607087c2f8..f3200c2915 100644 --- a/meta-flatpak/conf/layer.conf +++ b/meta-flatpak/conf/layer.conf @@ -14,3 +14,12 @@ LAYERDEPENDS_flatpak-layer = "core openembedded-layer filesystems-layer" # Set a variable for easy access to the top directory of the flatpak layer. FLATPAK_LAYERDIR = '${@os.path.normpath("${LAYERDIR}")}' + +# Pick up our passwd and group fragments for users associated with +# pre-declared remotes/repositories, if we have any. +USERADD_UID_TABLES_append_refkit-config = " \ + ${@ d.getVar('TOPDIR') + '/conf/flatpak-passwd' \ + if d.getVar('FLATPAK_APP_REPOS') else ''}" +USERADD_GID_TABLES_append_refkit-config = " \ + ${@ d.getVar('TOPDIR') + '/conf/flatpak-group' \ + if d.getVar('FLATPAK_APP_REPOS') else ''}" diff --git a/meta-flatpak/recipes-core/packagegroups/packagegroup-flatpak-session.bb b/meta-flatpak/recipes-core/packagegroups/packagegroup-flatpak-session.bb new file mode 100644 index 0000000000..d03fae5f81 --- /dev/null +++ b/meta-flatpak/recipes-core/packagegroups/packagegroup-flatpak-session.bb @@ -0,0 +1,10 @@ +SUMMARY = "IoT Reference OS Kit Basic Flatpak Session/Application Support" +LICENSE = "MIT" + +inherit packagegroup + +RDEPENDS_${PN} = "\ + packagegroup-flatpak \ + flatpak-utils \ + flatpak-predefined-repos \ +" diff --git a/meta-flatpak/recipes-flatpak/flatpak-predefined-repos/flatpak-predefined-repos.bb b/meta-flatpak/recipes-flatpak/flatpak-predefined-repos/flatpak-predefined-repos.bb new file mode 100644 index 0000000000..932ef5a7e6 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-predefined-repos/flatpak-predefined-repos.bb @@ -0,0 +1,55 @@ +DESCRIPTION = "Repository/remo URLs and signing keys for pre-declared flatpak session/application repositories." +HOMEPAGE = "http://127.0.0.1/" +LICENSE = "BSD-3-Clause" + +LIC_FILES_CHKSUM = "file://LICENSE-BSD;md5=f9f435c1bd3a753365e799edf375fc42" + +SRC_URI = " \ + git://git@github.com/klihub/flatpak-predefined-repos.git;protocol=https;branch=master \ +" + +SRCREV = "1181642d571d575783760247792c45635e6d3ebf" + +S = "${WORKDIR}/git" + +inherit autotools flatpak-config + +# For each repo named we expect a .url and .key file (containing +# the repo URL and the repo pubic GPG key), and passwd/group entries for +# the associated users. +# +# Turn the space-separated repo name list into a comma-separated one and +# pass it to configure. +EXTRA_OECONF += " \ + --with-repos=${@','.join(d.getVar('FLATPAK_APP_REPOS').split())} \ +" + +# Inherit useradd only if we have pre-declared repositories. Otherwise +# useradd would bail out with a parse-time error when we don't set +# USERADD_PARAM_${PN} when we don't have pre-declared repos to put into +# the image. +inherit ${@'useradd' if d.getVar('FLATPAK_APP_REPOS') else ''} + +# Ask for the creation of the users/groups associated with the pre-declared +# remotes/repositories. Turn the space-separated list into a semi-colon- +# separated one. +USERADD_PACKAGES = "${PN}" +USERADD_PARAM_${PN} = "${@';'.join(d.getVar('FLATPAK_APP_REPOS').split())}" + +FILES_${PN} = " \ + ${sysconfdir}/flatpak-session/* \ +" + +do_configure_prepend () { + if [ -n "${FLATPAK_APP_REPOS}" ]; then + mkdir -p ${S}/repos + + for _r in ${FLATPAK_APP_REPOS}; do + echo "Copying URL- and key-file for remote/repository $_r..." + cp ${TOPDIR}/conf/$_r.url ${S}/repos + cp ${TOPDIR}/conf/$_r.key ${S}/repos + done + else + echo "No predefined flatpak application remotes/repos." + fi +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/AUTHORS b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/AUTHORS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/COPYING b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/COPYING new file mode 100644 index 0000000000..e69de29bb2 diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/ChangeLog b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/LICENSE-BSD b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/LICENSE-BSD new file mode 100644 index 0000000000..a52ad554df --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/LICENSE-BSD @@ -0,0 +1,26 @@ +Copyright (c) 2012, 2013, Intel Corporation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/Makefile.am b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/Makefile.am new file mode 100644 index 0000000000..15d3b63be0 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/Makefile.am @@ -0,0 +1,6 @@ +SUBDIRS = . src +doc_DATA = AUTHORS ChangeLog NEWS README + +# cleanup +clean-local: + rm -f *~ diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/NEWS b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/README b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/README new file mode 100644 index 0000000000..c6a50c4225 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/README @@ -0,0 +1,26 @@ +flatpak-utils is a collection of extra utilities for Intel IoT RefKit. + +Currently flatpak-utils contains two extra binaries for dealing with +'flatpak sessions'. A 'flatpak session' is an automatically started +login session which runs one or more flatpak applications from a single +flatpak provide/remote. Each such remote has a dedicated user associated +with it and the flatpak applications are run within the login session +of that dedicated user. + +There is currently a single binary provided which can be run in three +different modes: + +- systemd generator + + A systemd generator used to generate a systemd service for each + configured flatpak session during system initialization. + +- session daemon + + A daemon used to run within each flatpak session to start the + flatpaks for that session. + +- update daemon + + A daemon used to monitor remotes, pull in available updates, + and restart any affected flatpak sessions. diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/bootstrap b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/bootstrap new file mode 100755 index 0000000000..ac327fd870 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/bootstrap @@ -0,0 +1,21 @@ +#!/bin/bash + +aclocal -I m4 && \ + autoheader && \ + libtoolize --copy --force && \ + autoconf && \ + automake --add-missing --copy + +status=$? + +if [ $status == 0 ]; then + if [ -n "$1" ]; then + [ "$1" == "configure" ] && shift || : + ./configure $* + status=$? + fi +else + echo "Failed to bootstrap." +fi + +exit $status diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/git-version-gen b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/git-version-gen new file mode 100755 index 0000000000..f38082dffd --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/git-version-gen @@ -0,0 +1,154 @@ +#!/bin/sh +# Print a version string. +scriptversion=2008-04-08.07 + +# Copyright (C) 2007-2008 Free Software Foundation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. +# It may be run two ways: +# - from a git repository in which the "git describe" command below +# produces useful output (thus requiring at least one signed tag) +# - from a non-git-repo directory containing a .tarball-version file, which +# presumes this script is invoked like "./git-version-gen .tarball-version". + +# In order to use intra-version strings in your project, you will need two +# separate generated version string files: +# +# .tarball-version - present only in a distribution tarball, and not in +# a checked-out repository. Created with contents that were learned at +# the last time autoconf was run, and used by git-version-gen. Must not +# be present in either $(srcdir) or $(builddir) for git-version-gen to +# give accurate answers during normal development with a checked out tree, +# but must be present in a tarball when there is no version control system. +# Therefore, it cannot be used in any dependencies. GNUmakefile has +# hooks to force a reconfigure at distribution time to get the value +# correct, without penalizing normal development with extra reconfigures. +# +# .version - present in a checked-out repository and in a distribution +# tarball. Usable in dependencies, particularly for files that don't +# want to depend on config.h but do want to track version changes. +# Delete this file prior to any autoconf run where you want to rebuild +# files to pick up a version string change; and leave it stale to +# minimize rebuild time after unrelated changes to configure sources. +# +# It is probably wise to add these two files to .gitignore, so that you +# don't accidentally commit either generated file. +# +# Use the following line in your configure.ac, so that $(VERSION) will +# automatically be up-to-date each time configure is run (and note that +# since configure.ac no longer includes a version string, Makefile rules +# should not depend on configure.ac for version updates). +# +# AC_INIT([GNU project], +# m4_esyscmd([build-aux/git-version-gen .tarball-version]), +# [bug-project@example]) +# +# Then use the following lines in your Makefile.am, so that .version +# will be present for dependencies, and so that .tarball-version will +# exist in distribution tarballs. +# +# BUILT_SOURCES = $(top_srcdir)/.version +# $(top_srcdir)/.version: +# echo $(VERSION) > $@-t && mv $@-t $@ +# dist-hook: +# echo $(VERSION) > $(distdir)/.tarball-version + +case $# in + 1) ;; + *) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;; +esac + +tarball_version_file=$1 +nl=' +' + +# First see if there is a tarball-only version file. +# then try "git describe", then default. +if test -f $tarball_version_file +then + v=`cat $tarball_version_file` || exit 1 + case $v in + *$nl*) v= ;; # reject multi-line output + [0-9]*) ;; + *) v= ;; + esac + test -z "$v" \ + && echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2 +fi + +if test -n "$v" +then + : # use $v +elif test -d .git \ + && v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \ + || git describe --abbrev=4 HEAD 2>/dev/null` \ + && case $v in + v[0-9]*) ;; + *) (exit 1) ;; + esac +then + # Is this a new git that lists number of commits since the last + # tag or the previous older version that did not? + # Newer: v6.10-77-g0f8faeb + # Older: v6.10-g0f8faeb +# case $v in +# *-*-*) : git describe is okay three part flavor ;; +# *-*) +# : git describe is older two part flavor +# # Recreate the number of commits and rewrite such that the +# # result is the same as if we were using the newer version +# # of git describe. +# vtag=`echo "$v" | sed 's/-.*//'` +# numcommits=`git rev-list "$vtag"..HEAD | wc -l` +# v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; +# ;; +# esac + + # Change the first '-' to a '.', so version-comparing tools work properly. + # Remove the "g" in git describe's output string, to save a byte. +# v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`; + : +else + #v=UNKNOWN + v="0.0.0" +fi + +v=`echo "$v" |sed 's/^v//'` + +# Don't declare a version "dirty" merely because a time stamp has changed. +git status > /dev/null 2>&1 + +dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty= +case "$dirty" in + '') ;; + *) # Append the suffix only if there isn't one already. + case $v in + *-dirty) ;; + *) v="$v-dirty" ;; + esac ;; +esac + +# Omit the trailing newline, so that m4_esyscmd can use the result directly. +echo "$v" | tr -d '\012' + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/shave-libtool.in b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/shave-libtool.in new file mode 100644 index 0000000000..0f7fb12b67 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/shave-libtool.in @@ -0,0 +1,109 @@ +#!/bin/sh +# +# Copyright (c) 2009, Damien Lespiau +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the real libtool to use +LIBTOOL="$1" +shift + +# if 1, don't print anything, the underlaying wrapper will do it +pass_though=0 + +# scan the arguments, keep the right ones for libtool, and discover the mode +preserved_args= + +# have we seen the --tag option of libtool in the command line ? +tag_seen=0 + +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + preserved_args="$preserved_args $opt" + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + --tag=*) + tag_seen=1 + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args '$opt'" + ;; + esac +done + +case "$mode" in +compile) + # shave will be called and print the actual CC/CXX/LINK line + preserved_args="$preserved_args --shave-mode=$mode" + pass_though=1 + ;; +link) + preserved_args="$preserved_args --shave-mode=$mode" + Q=" LINK " + ;; +*) + # let's u + # echo "*** libtool: Unimplemented mode: $mode, fill a bug report" + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +# automake does not add a --tag switch to its libtool invocation when +# assembling a .s file and rely on libtool to infer the right action based +# on the compiler name. As shave is using CC to hook a wrapper, libtool gets +# confused. Let's detect these cases and add a --tag=CC option. +tag="" +if test $tag_seen -eq 0 -a x"$mode" = xcompile; then + tag="--tag=CC" +fi + +if test -z $V; then + if test $pass_though -eq 0; then + echo "$Q$output" + fi + eval "$LIBTOOL --silent $tag $preserved_args" +else + echo $LIBTOOL $tag $preserved_args + eval "$LIBTOOL $tag $preserved_args" +fi diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/shave.in b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/shave.in new file mode 100644 index 0000000000..5150a4fff1 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/build-aux/shave.in @@ -0,0 +1,133 @@ +#!/bin/sh +# +# Copyright (c) 2009, Damien Lespiau +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the tool to wrap (cc, cxx, ar, ranlib, ..) +tool="$1" +shift + +# the reel tool (to call) +REEL_TOOL="$1" +shift + +pass_through=0 +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --shave-mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + -out:*|/out:*) + lt_output="${opt#-out:}" + preserved_args="$preserved_args $opt" + ;; + *.l) + if [ "$tool" = "lex" ]; then + lt_output="$opt" + fi + preserved_args="$preserved_args $opt" + ;; + *.y) + if [ "$tool" = "yacc" ]; then + lt_output="$opt" + fi + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args '$opt'" + ;; + esac +done + +# mode=link is handled in the libtool wrapper +case "$mode,$tool" in +link,*) + pass_through=1 + ;; +*,cxx) + Q=" CXX " + ;; +*,ccas) + Q=" AS " + ;; +*,cc) + Q=" CC " + ;; +*,fc) + Q=" FC " + ;; +*,f77) + Q=" F77 " + ;; +*,objc) + Q=" OBJC " + ;; +*,mcs) + Q=" MCS " + ;; +*,lex) + Q=" LEX " + ;; +*,yacc) + Q=" YACC " + ;; +*,cc_for_build) + Q=" HOSTCC " + ;; +*,*) + # should not happen + Q=" CC " + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_through -eq 0; then + echo "$Q$output" + fi + eval "$REEL_TOOL $preserved_args" +else + echo $REEL_TOOL $preserved_args + eval "$REEL_TOOL $preserved_args" +fi diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/configure.ac b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/configure.ac new file mode 100644 index 0000000000..a0e2b02b62 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/configure.ac @@ -0,0 +1,123 @@ + +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) + +AC_INIT([flatpak-utils], m4_esyscmd([build-aux/git-version-gen .tarball-version])) + +AC_CONFIG_SRCDIR([src]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADER([src/config.h]) +AM_INIT_AUTOMAKE([-Wno-portability subdir-objects foreign]) + +AC_SUBST(ACLOCAL_AMFLAGS, "-I m4") + +m4_define(version_major, `echo $VERSION | cut -d. -f1 | cut -d- -f1`) +m4_define(version_minor, `echo $VERSION | cut -d. -f2 | cut -d- -f1`) +m4_define(version_patch, `echo $VERSION | cut -d. -f3 | cut -d- -f1`) + +AC_SUBST(VERSION) +AC_SUBST(VERSION_MAJOR, version_major) +AC_SUBST(VERSION_MINOR, version_minor) +AC_SUBST(VERSION_PATCH, version_patch) +AC_SUBST(VERSION_FULL, version_major.version_minor.version_patch) + +IOT_VERSION_INFO="0:0:0" +AC_SUBST(IOT_VERSION_INFO) + +# Disable static libraries. +AC_DISABLE_STATIC + +# Checks for programs. +AC_PROG_CC +AC_PROG_CC_C99 +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_CC_C_O +AM_PROG_LIBTOOL + +# Guesstimate native compiler if we're cross-compiling. +if test "$cross_compiling" != "no"; then + AC_MSG_NOTICE([Looks like we're being cross-compiled...]) + if test -z "$CC_FOR_BUILD"; then + CC_FOR_BUILD=cc + fi +else + AC_MSG_NOTICE([Looks like we're doing a native compilation...]) + CC_FOR_BUILD='$(CC)' +fi +AC_SUBST(CC_FOR_BUILD) +UNSHAVED_CC_FOR_BUILD="$CC_FOR_BUILD" + +# Make first invocation of PKG_CHECK_MODULES 'if-then-else-fi'-safe. +PKG_PROG_PKG_CONFIG + +# Checks for header files. +AC_PATH_X +AC_CHECK_HEADERS([stdio.h stdlib.h errno.h fcntl.h sys/types.h sys/stat.h]) + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. + +# Check and enable extra compiler warnings if they are supported. +AC_ARG_ENABLE(extra-warnings, + [ --enable-extra-warnings enable extra compiler warnings], + [extra_warnings=$enableval], [extra_warnings=auto]) + +WARNING_CFLAGS="" +warncflags="-Wall -Wextra" +if test "$extra_warnings" != "no"; then + save_CPPFLAGS="$CPPFLAGS" + for opt in $warncflags; do + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])], + [WARNING_CFLAGS="$WARNING_CFLAGS $opt"]) + done + CPPFLAGS="$save_CPPFLAGS" +fi + +AC_SUBST(WARNING_CFLAGS) + +# Allow overriding systemds' unitdir. +AC_ARG_WITH([systemdunitdir], + AC_HELP_STRING([--with-systemdunitdir=DIR], [systemd unit directory]), + [with_systemdunitdir=${withval}], + [with_systemdunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"]) + +if test -n "${with_systemdunitdir}"; then + SYSTEMD_UNITDIR="${with_systemdunitdir}" + AC_SUBST(SYSTEMD_UNITDIR) +fi + +# Check for flatpak libraries. +PKG_CHECK_MODULES(FLATPAK, flatpak) + +# Allow substitution for LIBDIR and SYSCONFDIR. +AC_MSG_CHECKING([libdir]) +AC_MSG_RESULT([$libdir]) +AC_SUBST(LIBDIR, [$libdir]) +AC_MSG_CHECKING([sysconfdir]) +AC_MSG_RESULT([$sysconfdir]) +AC_SUBST(SYSCONFDIR, [$sysconfdir]) + +# Shave by default. +SHAVE_INIT([build-aux], [enable]) + +# Generate output. +AC_CONFIG_FILES([ + build-aux/shave + build-aux/shave-libtool + Makefile + src/Makefile + ]) +AC_OUTPUT + +# Display the configuration. +echo "----- configuration -----" +echo "Extra C warnings flags: $WARNING_CFLAGS" +echo "Cross-compiling: $cross_compiling" +if test "$cross_compiling" != "no"; then + echo " * native compiler: $UNSHAVED_CC_FOR_BUILD" +fi +echo "Systemd unitdir: $SYSTEMD_UNITDIR" diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/m4/shave.m4 b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/m4/shave.m4 new file mode 100644 index 0000000000..94aec1f6ec --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/m4/shave.m4 @@ -0,0 +1,113 @@ +dnl Make automake/libtool output more friendly to humans +dnl +dnl Copyright (c) 2009, Damien Lespiau +dnl +dnl Permission is hereby granted, free of charge, to any person +dnl obtaining a copy of this software and associated documentation +dnl files (the "Software"), to deal in the Software without +dnl restriction, including without limitation the rights to use, +dnl copy, modify, merge, publish, distribute, sublicense, and/or sell +dnl copies of the Software, and to permit persons to whom the +dnl Software is furnished to do so, subject to the following +dnl conditions: +dnl +dnl The above copyright notice and this permission notice shall be +dnl included in all copies or substantial portions of the Software. +dnl +dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +dnl EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +dnl OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +dnl NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +dnl HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +dnl WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +dnl OTHER DEALINGS IN THE SOFTWARE. +dnl +dnl SHAVE_INIT([shavedir],[default_mode]) +dnl +dnl shavedir: the directory where the shave scripts are, it defaults to +dnl $(top_builddir) +dnl default_mode: (enable|disable) default shave mode. This parameter +dnl controls shave's behaviour when no option has been +dnl given to configure. It defaults to disable. +dnl +dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just +dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and +dnl LIBTOOL, you don't want the configure tests to have these variables +dnl re-defined. +dnl * This macro requires GNU make's -s option. + +AC_DEFUN([_SHAVE_ARG_ENABLE], +[ + AC_ARG_ENABLE([shave], + AS_HELP_STRING( + [--enable-shave], + [use shave to make the build pretty [[default=$1]]]),, + [enable_shave=$1] + ) +]) + +AC_DEFUN([SHAVE_INIT], +[ + dnl you can tweak the default value of enable_shave + m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)]) + + if test x"$enable_shave" = xyes; then + dnl where can we find the shave scripts? + m4_if([$1],, + [shavedir="$ac_pwd"], + [shavedir="$ac_pwd/$1"]) + AC_SUBST(shavedir) + + dnl make is now quiet + AC_SUBST([MAKEFLAGS], [-s]) + AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`']) + + dnl we need sed + AC_CHECK_PROG(SED,sed,sed,false) + + dnl substitute libtool + SHAVE_SAVED_LIBTOOL=$LIBTOOL + LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'" + AC_SUBST(LIBTOOL) + + dnl substitute cc/cxx + SHAVE_SAVED_CCAS=$CCAS + SHAVE_SAVED_CC=$CC + SHAVE_SAVED_CXX=$CXX + SHAVE_SAVED_FC=$FC + SHAVE_SAVED_F77=$F77 + SHAVE_SAVED_OBJC=$OBJC + SHAVE_SAVED_MCS=$MCS + SHAVE_SAVED_LEX=$LEX + SHAVE_SAVED_YACC=$YACC + SHAVE_SAVED_CC_FOR_BUILD=$CC_FOR_BUILD + CCAS="${SHELL} ${shavedir}/shave ccas ${SHAVE_SAVED_CCAS}" + CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}" + CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}" + FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}" + F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}" + OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}" + MCS="${SHELL} ${shavedir}/shave mcs ${SHAVE_SAVED_MCS}" + LEX="${SHELL} ${shavedir}/shave lex ${SHAVE_SAVED_LEX}" + YACC="${SHELL} ${shavedir}/shave yacc ${SHAVE_SAVED_YACC}" + CC_FOR_BUILD="${SHELL} ${shavedir}/shave cc_for_build ${SHAVE_SAVED_CC_FOR_BUILD}" + AC_SUBST(CCAS) + AC_SUBST(CC) + AC_SUBST(CXX) + AC_SUBST(FC) + AC_SUBST(F77) + AC_SUBST(OBJC) + AC_SUBST(MCS) + AC_SUBST(LEX) + AC_SUBST(YACC) + + V=@ + else + V=1 + fi + Q='$(V:1=)' + AC_SUBST(V) + AC_SUBST(Q) +]) + diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/Makefile.am b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/Makefile.am new file mode 100644 index 0000000000..196afe1d31 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/Makefile.am @@ -0,0 +1,48 @@ +SUBDIRS = . +AM_CFLAGS = $(WARNING_CFLAGS) $(AM_CPPFLAGS) $(PATHDEFS) +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/src \ + -I$(top_builddir) -I$(top_builddir)/src +PATHDEFS = -DSYSCONFDIR=\"${sysconfdir}\" \ + -DLIBDIR=\"${libdir}\" \ + -DLIBEXECDIR=\"${libexecdir}\" + +generator_PROGRAMS = flatpak-session-enable +generatordir = @SYSTEMD_UNITDIR@/system-generators + +systemd_DATA = flatpak-session@.service \ + flatpak-sessions.target \ + flatpak-update.service +systemddir = @SYSTEMD_UNITDIR@/system + +bin_PROGRAMS = + +############################################# +# flatpak-service-generator +# + +bin_PROGRAMS += flatpak-session + +flatpak_session_SOURCES = \ + flatpak-session.c \ + config.c \ + log.c \ + mainloop.c \ + remote.c \ + filesystem.c \ + flatpak.c + +flatpak_session_CFLAGS = \ + $(AM_CFLAGS) \ + $(PATHDEFS) \ + $(FLATPAK_CFLAGS) + +flatpak_session_LDADD = \ + $(FLATPAK_LIBS) \ + -lm + +flatpak-session-enable: flatpak-session + rm -f $@ && ln $< $@ + +# cleanup +clean-local: + -rm -f *~ diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/config.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/config.c new file mode 100644 index 0000000000..11e6d225df --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/config.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#define _GNU_SOURCE +#include + +#include "flatpak-session.h" + +static __attribute__((noreturn)) +void print_usage(const char *argv0, int exit_code, const char *fmt, ...) +{ + va_list ap; + + if (fmt && *fmt) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + } + + fprintf(stderr, "usage: %s [common-options] {command} [command-options]}\n" + "\n" + "The possible commands are:\n" + " generate: act as a systemd generator\n" + " Discover all repositories with an associated session user.\n" + " For all repositories found, generate and enable a systemd\n" + " service for starting up the session and populating it with\n" + " applications. %s will be used to start\n" + " the applications within the session. This is the default\n" + " behavior if the executable binary is %s.\n" + " start: start session applications\n" + " Start applications. Discover all applications originating\n" + " from the repository associated with the current user. Start\n" + " all applications which are not marked exempt from auto-\n" + " starting within the current session.\n" + " stop: stop a session (by sending SIGTERM)\n" + " Stop the session for the current or given user. Discover the\n" + " instance (%s) used to start the session\n" + " and send it SIGTERM. That instance is expected to stop all\n" + " applications running within its session, then exit itself.\n" + " list: list sessions\n" + " List all known sessions, all running sessions, or the session\n" + " session associated with the given user/repository.\n" + " signal: send a signal to a session\n" + " Same as stop but the signal can be specified.\n" + "\n" + "The possible common options are:\n" + " -u, --allow-unsigned allow unverifiable (unsigned) remotes\n" + " -n, --dry-run just print, don't generate anything\n" + " -v, --verbose increase logging verbosity\n" + " -d, --debug enable debug messages\n" + " -h, --help print this help message\n" + "\n" + "The possible options for start are:\n" + " -r, --restart-status use n for forced restart exit status\n" + "\n" + "The possible options for update are:\n" + " -o, --one-shot don't daemonize and poll updates\n" + " -i, --poll-interval ival use the given interval for polling\n" + " -s, --start-signal signal sessions after initial update\n", + /* usage */argv0, + /* generate */FPAK_SESSION_PATH, FPAK_SYSTEMD_GENERATOR, + /* stop */FPAK_SESSION_PATH); + + exit(exit_code); +} + + +static inline int is_systemd_generator(const char *argv0) +{ + const char *p; + + if ((p = strrchr(argv0, '/')) == NULL) + p = argv0; + else + p++; + + return !strcmp(p, FPAK_SYSTEMD_GENERATOR); +} + + +static void set_defaults(context_t *c, char **argv) +{ + memset(c, 0, sizeof(*c)); + c->sigfd = -1; + c->argv0 = argv[0]; + c->gpg_verify = 1; + + if (is_systemd_generator(argv[0])) + c->action = ACTION_GENERATE; + else + c->action = ACTION_START; +} + + +static int parse_interval(const char *argv0, const char *val) +{ +# define SUFFIX(_e, _s, _l, _p) \ + (!strcmp(_e, _s) || (_l && !strcmp(_e, _l)) || (_p && !strcmp(_e, _p))) + char *end; + double d; + int interval; + + + d = strtod(val, &end); + + if (end != NULL && *end != '\0') { + if (SUFFIX(end, "s", "sec", "secs")) + interval = d < 30 ? 30 : (int)d; + else if (SUFFIX(end, "m", "min", "mins")) + interval = (int)(d * 60); + else if (SUFFIX(end, "h", "hour", "hours")) + interval = (int)(d * 60 * 60); + else if (SUFFIX(end, "d", "day", "days")) + interval = (int)(d * 24 * 60 * 60); + else + print_usage(argv0, EINVAL, "invalid poll interval '%s'", val); + } + else + interval = (int)d; + + if (interval < FPAK_POLL_MIN_INTERVAL) + interval = FPAK_POLL_MIN_INTERVAL; + + return interval; + +# undef SUFFIX +} + + +static void parse_common_options(context_t *c, int argc, char **argv) +{ +# define OPTIONS "-uvndh" + static struct option options[] = { + { "allow-unsigned", no_argument, NULL, 'u' }, + { "verbose" , no_argument, NULL, 'v' }, + { "dry-run" , no_argument, NULL, 'n' }, + { "debug" , no_argument, NULL, 'd' }, + { "help" , no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } + }; + + int opt, m; + + while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { + switch (opt) { + case 'u': + c->gpg_verify = 0; + break; + + case 'n': + c->dry_run = 1; + break; + + case 'v': + m = log_get_mask(); + m = (((m << 1) | 0x1) & ~FPAK_LOG_DEBUG) | (m & FPAK_LOG_DEBUG); + log_set_mask(m); + break; + + case 'd': + log_set_mask(log_get_mask() | FPAK_LOG_DEBUG); + break; + + case 'h': + print_usage(argv[0], 0, ""); + + case 1: + optind--; /* we'll need to rescan it as a command argument */ + return; + + case '?': + print_usage(argv[0], EINVAL, "invalid option"); + break; + } + } +#undef OPTIONS +} + + +static void parse_action(context_t *c, int argc, char **argv) +{ + static struct { + const char *name; + action_t action; + } actions[] = { + { "generate", ACTION_GENERATE }, + { "update" , ACTION_UPDATE }, + { "start" , ACTION_START }, + { "stop" , ACTION_STOP }, + { "list" , ACTION_LIST }, + { "signal" , ACTION_SIGNAL }, + { NULL, 0 }, + }, *a; + const char *action; + + if (c->action == ACTION_GENERATE) + return; + + if (optind >= argc) + return; + + action = argv[optind]; + + if (action[0] == '-' || action[0] == '/') + return; + + for (a = actions; a->name != NULL; a++) { + if (!strcmp(action, a->name)) { + c->action = a->action; + optind++; + return ; + } + } + + print_usage(argv[0], EINVAL, "unknown action '%s'", action); +} + + +static void parse_generate_options(context_t *c, int argc, char **argv) +{ + if (optind + 2 > argc - 1) + print_usage(argv[0], EINVAL, + "missing systemd generator directory arguments"); + + if (argv[optind ][0] == '-' || + argv[optind+1][0] == '-' || + argv[optind+2][0] == '-') { + print_usage(argv[0], EINVAL, + "can't mix options with systemd generator directories"); + } + + c->service_dir = argv[optind]; + optind += 3; + + if (optind <= argc - 1) + print_usage(argv[0], EINVAL, + "unknown options starting at '%s'", argv[optind]); +} + + +static int parse_signal(const char *argv0, const char *sigstr) +{ +#define NSIGNAL (sizeof(signals) / sizeof(signals[0])) + struct signals { + const char *sigstr; + int signo; + int reject : 1; + } signals[] = { +# define ACCEPT(_sig) [SIG##_sig] = { #_sig, SIG##_sig, 0 } +# define REJECT(_sig) [SIG##_sig] = { #_sig, SIG##_sig, 1 } + ACCEPT(HUP) , ACCEPT(INT) , ACCEPT(QUIT) , + REJECT(ILL) , REJECT(TRAP) , REJECT(ABRT) , + REJECT(BUS) , REJECT(FPE) , REJECT(KILL) , + ACCEPT(USR1) , REJECT(SEGV) , ACCEPT(USR2) , + ACCEPT(PIPE) , ACCEPT(ALRM) , ACCEPT(TERM) , + REJECT(STKFLT), REJECT(CHLD) , ACCEPT(CONT) , + REJECT(STOP) , ACCEPT(TSTP) , ACCEPT(TTIN) , + ACCEPT(TTOU) , ACCEPT(URG) , ACCEPT(XCPU) , + ACCEPT(XFSZ) , ACCEPT(VTALRM), ACCEPT(PROF) , + ACCEPT(WINCH) , ACCEPT(IO) , ACCEPT(PWR) , + { NULL, -1, 0 } +# undef ACCEPT +# undef REJECT + }, *s; + + const char *p = sigstr; + char *e; + int signo; + + if ('0' <= *p && *p <= '9') { + signo = strtoul(p, &e, 10); + + if (e && *e != '\0') + goto invalid_signal; + } + else { + if (!strncmp(p, "SIG", 3)) + p += 3; + + for (signo = 0, s = signals + 1; !signo && s < signals + NSIGNAL; s++) { + if (!strcmp(p, s->sigstr)) + signo = s->signo; + } + } + + if (signo < 0 || signo > (int)NSIGNAL) + goto invalid_signal; + + s = signals + signo; + + if (s->reject) + goto reject_signal; + + return signo; + + invalid_signal: + print_usage(argv0, EINVAL, "invalid signal '%s'", sigstr); + return -1; + + reject_signal: + print_usage(argv0, EINVAL, "unusable signal '%s'", sigstr); + return -1; + +#undef NSIGNAL +} + + +static void parse_start_options(context_t *c, int argc, char **argv) +{ +# define OPTIONS "w:r:" + static struct option options[] = { + { "restart-status", required_argument, NULL, 'r' }, + { NULL, 0, NULL, 0 }, + }; + + int opt; + char *e; + + c->remote_uid = geteuid(); + c->forced_restart = 69; + + if (c->remote_uid == 0) + print_usage(argv[0], EINVAL, "cannot start session as root"); + + if (optind >= argc) + return; + + while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { + switch (opt) { + case 'r': + c->forced_restart = strtol(optarg, &e, 10); + + if (e && *e) { + print_usage(argv[0], EINVAL, "invalid restart status '%s'", + optarg); + } + break; + + case '?': + print_usage(argv[0], EINVAL, "invalid start option"); + break; + } + } + +# undef OPTIONS +} + + +static uid_t parse_remote(const char *argv0, const char *remote) +{ + uid_t uid; + + uid = remote_user_id(remote, NULL, 0); + + if (uid == INVALID_UID) + print_usage(argv0, EINVAL, + "failed to resolve user for remote '%s'", remote); + else + return uid; +} + + +static void parse_stop_options(context_t *c, int argc, char **argv) +{ +# define OPTIONS "r:s:" + static struct option options[] = { + { "remote", required_argument, NULL, 'r' }, + { "signal", required_argument, NULL, 's' }, + { NULL, 0, NULL, 0 }, + }; + + int opt; + + c->remote_uid = geteuid(); + + if (optind >= argc) + return; + + while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { + switch (opt) { + case 'r': + c->remote_uid = parse_remote(c->argv0, optarg); + break; + + case 's': + c->signal = parse_signal(c->argv0, optarg); + break; + + case '?': + print_usage(argv[0], EINVAL, "invalid 'stop' option '%c'", opt); + break; + } + } +# undef OPTIONS +} + + +static void parse_list_options(context_t *c, int argc, char **argv) +{ + const char *remote; + + if (optind > argc - 1) + c->remote_uid = geteuid(); + else if (optind == argc - 1) { + remote = optarg; + + if (!strcmp(remote, "all") || !strcmp(remote, ".")) + c->remote_uid = 0; + else + c->remote_uid = parse_remote(c->argv0, remote); + } + else + print_usage(argv[0], EINVAL, "too many arguments for 'list'"); +} + + +static void parse_signal_options(context_t *c, int argc, char **argv) +{ +# define OPTIONS "r:s:" + static struct option options[] = { + { "remote", required_argument, NULL, 'r' }, + { "signal", required_argument, NULL, 's' }, + { NULL, 0, NULL, 0 }, + }; + + int opt; + + c->remote_uid = geteuid(); + c->signal = SIGTERM; + + if (optind >= argc) + return; + + while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { + switch (opt) { + case 'r': + c->remote_uid = parse_remote(c->argv0, optarg); + break; + + case 's': + c->signal = parse_signal(c->argv0, optarg); + break; + + case '?': + print_usage(argv[0], EINVAL, "invalid 'signal' option '%c'", opt); + break; + } + } +# undef OPTIONS +} + + +static void parse_update_options(context_t *c, int argc, char **argv) +{ +# define OPTIONS "oi:" + static struct option options[] = { + { "one-shot" , no_argument , NULL, 'o' }, + { "poll-interval", required_argument, NULL, 'i' }, + { NULL, 0, NULL, 0 }, + }; + + int opt; + + if (c->poll_interval <= 0) + c->poll_interval = FPAK_POLL_MIN_INTERVAL; + + if (optind >= argc) + return; + + while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) { + switch (opt) { + case 'o': + c->poll_interval = -1; + break; + + case 'i': + c->poll_interval = parse_interval(c->argv0, optarg); + break; + + case '?': + print_usage(argv[0], EINVAL, "invalid 'update' option"); + break; + } + } +# undef OPTIONS +} + + +void config_parse_cmdline(context_t *c, int argc, char **argv) +{ + set_defaults(c, argv); + log_open(c); + + parse_common_options(c, argc, argv); + parse_action(c, argc, argv); + + switch (c->action) { + case ACTION_GENERATE: parse_generate_options(c, argc, argv); break; + case ACTION_UPDATE: parse_update_options(c, argc, argv); break; + case ACTION_START: parse_start_options(c, argc, argv); break; + case ACTION_STOP: parse_stop_options(c, argc, argv); break; + case ACTION_SIGNAL: parse_signal_options(c, argc, argv); break; + case ACTION_LIST: parse_list_options(c, argc, argv); break; + default: + break; + } + + log_open(c); +} + diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/filesystem.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/filesystem.c new file mode 100644 index 0000000000..35828d92c1 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/filesystem.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flatpak-session.h" + + +int fsys_prepare_session(context_t *c) +{ + char *dir = fsys_mkpath(NULL, 0, "%s/%s.wants", + c->service_dir, FPAK_SYSTEMD_TARGET); + + log_info("creating service directory %s...", dir); + + if (c->dry_run) + return 0; + else + return fsys_mkdirp(0755, dir); +} + + +char *fsys_mkpath(char *path, size_t size, const char *fmt, ...) +{ + static char buf[PATH_MAX]; + va_list ap; + int n; + + if (path == NULL) { + path = buf; + size = sizeof(buf); + } + else if (size > PATH_MAX) + size = PATH_MAX; + + va_start(ap, fmt); + n = vsnprintf(path, size, fmt, ap); + va_end(ap); + + if (n < 0 || n >= (int)size) + goto nametoolong; + + return path; + + nametoolong: + errno = ENAMETOOLONG; + return NULL; +} + + +int fsys_mkdir(const char *path, mode_t mode) +{ + const char *p; + char *q, buf[PATH_MAX]; + int n, undo[PATH_MAX / 2]; + struct stat st; + + if (path == NULL || path[0] == '\0') { + errno = path ? EINVAL : EFAULT; + return -1; + } + + log_debug("checking/creating '%s'...", path); + + p = path; + q = buf; + n = 0; + while (1) { + if (q - buf >= (ptrdiff_t)sizeof(buf) - 1) { + errno = ENAMETOOLONG; + goto cleanup; + } + + if (*p && *p != '/') { + *q++ = *p++; + continue; + } + + *q = '\0'; + + if (q != buf) { + log_debug("checking/creating '%s'...", buf); + + if (stat(buf, &st) < 0) { + if (errno != ENOENT) + goto cleanup; + + if (mkdir(buf, mode) < 0) + goto cleanup; + + undo[n++] = q - buf; + } + else { + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + goto cleanup; + } + } + } + + while (*p == '/') + p++; + + if (!*p) + break; + + *q++ = '/'; + } + + return 0; + + cleanup: + while (--n >= 0) { + buf[undo[n]] = '\0'; + log_debug("cleaning up '%s'...", buf); + rmdir(buf); + } + + return -1; +} + + +int fsys_mkdirp(mode_t mode, const char *fmt, ...) +{ + va_list ap; + char path[PATH_MAX]; + int n; + + va_start(ap, fmt); + n = vsnprintf(path, sizeof(path), fmt, ap); + va_end(ap); + + if (n < 0 || n >= (int)sizeof(path)) + goto nametoolong; + + return fsys_mkdir(path, mode); + + nametoolong: + errno = ENAMETOOLONG; + return -1; +} + + +int fsys_symlink(const char *path, const char *dst) +{ + struct stat stp, std; + + if (lstat(path, &stp) < 0) + return -1; + + if (!S_ISLNK(stp.st_mode)) + return 0; + + if (dst == NULL) + return 1; + + if (stat(path, &std) < 0) + return 0; + + if (stat(path, &stp) < 0) + return -1; + + if (stp.st_dev == std.st_dev && stp.st_ino == std.st_ino) + return 1; + else + return 0; +} + + +char *fsys_service_path(context_t *c, const char *usr, char *path, size_t size) +{ + const char *srvdir = SYSTEMD_SERVICEDIR; + const char *session = FPAK_SYSTEMD_SESSION; + + UNUSED_ARG(c); + UNUSED_ARG(usr); + + return fsys_mkpath(path, size, "%s/%s", srvdir, session); +} + + +char *fsys_service_link(context_t *c, const char *usr, char *path, size_t size) +{ + const char *session = FPAK_SYSTEMD_SESSION, *s; + char *d; + int l, n; + + d = path; + l = (int)size; + + n = snprintf(d, l, "%s/%s.wants/", c->service_dir, FPAK_SYSTEMD_TARGET); + + if (n < 0) + return NULL; + if (n >= l) + goto overflow; + + d += n; + l -= n; + + s = strchr(session, '@'); + + if (s != NULL) { + n = snprintf(d, l, "%.*s", (int)(s - session + 1), session); + + if (n < 0) + return NULL; + if (n >= l) + goto overflow; + + d += n; + l -= n; + s++; + + n = snprintf(d, l, "%s", usr); + + if (n < 0) + return NULL; + if (n >= l) + goto overflow; + + d += n; + l -= n; + } + + n = snprintf(d, l, "%s", s); + + if (n < 0) + return NULL; + if (n >= l) + goto overflow; + + return path; + + overflow: + errno = EOVERFLOW; + return NULL; +} + + +int fs_scan_proc(const char *exe, uid_t uid, + int (*cb)(pid_t pid, void *user_data), void *user_data) +{ + DIR *dp; + struct dirent *de; + struct stat st; + char file[PATH_MAX], *bin; + int n, status; + + if ((dp = opendir("/proc")) == NULL) + return -1; + + while ((de = readdir(dp)) != NULL) { + if (!('0' <= de->d_name[0] && de->d_name[0] <= '9')) + continue; + + snprintf(file, sizeof(file), "/proc/%s/exe", de->d_name); + + if (lstat(file, &st) != 0) + continue; + + if (uid != (uid_t)-1 && st.st_uid != uid) + continue; + + if ((n = readlink(file, file, sizeof(file))) < 0) + continue; + + file[n] = '\0'; + + if (exe[0] == '/') { + bin = file; + } + else { + if ((bin = strrchr(file, '/')) != NULL) + bin++; + else + bin = file; + } + + if (!strcmp(exe, bin)) { + status = cb((pid_t)strtoul(de->d_name, NULL, 10), user_data); + + if (status == 0) + break; + + if (status < 0) + goto fail; + } + } + + closedir(dp); + + return 0; + + fail: + closedir(dp); + + return -1; +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session.c new file mode 100644 index 0000000000..3eb6ba2284 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "flatpak-session.h" + + +static int generate_session(context_t *c, remote_t *r) +{ + char srv[PATH_MAX], lnk[PATH_MAX]; + + if (!fsys_service_path(c, r->user, srv, sizeof(srv)) || + !fsys_service_link(c, r->user, lnk, sizeof(lnk))) + return -1; + + log_info("remote %s: generating session (user %s)", r->name, r->user); + + if (c->dry_run) { + log_info("symlinking %s -> %s", lnk, srv); + return 0; + } + + unlink(lnk); + + if (symlink(srv, lnk) < 0) + return -1; + + return 0; +} + + +static void action_generate(context_t *c) +{ + remote_t *r; + + if (fpak_init(c, FPAK_DISCOVER_REMOTES) < 0) + log_fatal("failed to initialize flatpak library"); + + if (fsys_prepare_session(c) < 0) + log_fatal("failed to prepare filesystem for session generation"); + + fpak_foreach_remote(c, r) { + if (generate_session(c, r) < 0) + log_error("remote %s: failed to generate session", r->name); + } +} + + +static void remote_pending_cb(context_t *c) +{ + if (fpak_update_apps(c) < 0) + log_error("failed to update applications"); +} + + +static void action_update(context_t *c) +{ + if (fpak_init(c, FPAK_DISCOVER_APPS) < 0) + log_fatal("failed to initialize flatpak library"); + + if (fpak_poll_updates(c)) + if (fpak_update_apps(c) < 0) + log_error("failed to update applications"); + + if (c->poll_interval > 0) + if (fpak_track_remote_updates(c, remote_pending_cb) < 0) + log_fatal("failed to track remote updates"); +} + + +static void local_updates_cb(context_t *c) +{ + if (fpak_reload_apps(c) < 0) + log_error("failed to reload local updates"); + if (fpak_reload_session(c) < 0) + log_error("failed to reload session for %d", c->remote_uid); +} + + +static void action_start(context_t *c) +{ + if (fpak_init(c, FPAK_DISCOVER_APPS) < 0) + log_fatal("failed to initialize flatpak library"); + + if (fpak_start_session(c) < 0) + log_fatal("failed to start session for user %d", c->remote_uid); + + if (fpak_track_local_updates(c, local_updates_cb) < 0) + log_error("failed to track local updates"); +} + + +int main(int argc, char *argv[]) +{ + context_t ctx, *c = &ctx; + + config_parse_cmdline(c, argc, argv); + + if (mainloop_needed(c)) + mainloop_create(c); + + switch (c->action) { + case ACTION_GENERATE: action_generate(c); break; + case ACTION_UPDATE: action_update(c); break; + case ACTION_START: action_start(c); break; + default: + log_error("internal error: unknown action (%d)", c->action); + exit(1); + } + +#if 0 + switch (c->action) { + case ACTION_STOP: stop_session(c); break; + case ACTION_LIST: list_session(c); break; + case ACTION_SIGNAL: signal_session(c); break; + default: + log_error("internal error: unknown action (%d)", c->action); + exit(1); + } +#endif + + if (c->ml != NULL) + mainloop_run(c); + + exit(c->exit_code); +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session.h b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session.h new file mode 100644 index 0000000000..38e425dc13 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FLATPAK_SESSION_H__ +#define __FLATPAK_SESSION_H__ + +#include +#include +#include +#include + +#include "config.h" + +/* default system path definitions */ +#ifndef SYSCONFDIR +# define SYSCONFDIR "/etc" +#endif + +#ifndef LIBDIR +# define LIBDIR "/usr/lib" +#endif + +#ifndef LIBEXECDIR +# define LIBEXECDIR "/usr/libexec" +#endif + +#ifndef SYSTEMD_SERVICEDIR +# define SYSTEMD_SERVICEDIR LIBDIR"/systemd/system" +#endif + +/* default repo URL and key dir */ +#ifndef FPAK_REPOS_DIR +# define FPAK_REPOS_DIR SYSCONFDIR"/flatpak-session" +#endif + +/* default systemd service, target, and generator */ +#ifndef FPAK_SYSTEMD_SESSION +# define FPAK_SYSTEMD_SESSION "flatpak-session@.service" +#endif + +#ifndef FPAK_SYSTEMD_TARGET +# define FPAK_SYSTEMD_TARGET "flatpak-sessions.target" +#endif + +#ifndef FPAK_SYSTEMD_GENERATOR +# define FPAK_SYSTEMD_GENERATOR "flatpak-session-enable" +#endif + +/* flatpak session binary path */ +#ifndef FPAK_SESSION_PATH +# define FPAK_SESSION_PATH "/usr/bin/flatpak-session" +#endif + +/* default path to systemd user slice top directory */ +#ifndef SYSTEMD_USER_SLICE +# define SYSTEMD_USER_SLICE "/sys/fs/cgroup/systemd/user.slice" +#endif + +/* root directory used by flatpak in application-specific namespaces */ +#ifndef FLATPAK_APP_ROOT +# define FLATPAK_APP_ROOT "/newroot/app" +#endif + +/* gecos prefix we look for to identify remote-specific users */ +#ifndef FPAK_GECOS_PREFIX +# define FPAK_GECOS_PREFIX "flatpak user for " +#endif + +/* section and key names for our extra flatpak metadata */ +#define FPAK_SECTION_REFKIT "Application" /* reuse existing section */ +#define FPAK_KEY_INSTALL "X-Install" /* autoinstall application */ +#define FPAK_KEY_START "X-Start" /* autostart application */ +#define FPAK_KEY_URGENCY "X-Urgency" /* update urgency */ + +/* timers, intervals */ +#define FPAK_UPDATE_LOWPASS_TIMER 15 /* update monitor lowpass filter */ +#define FPAK_POLL_MIN_INTERVAL 15 /* minimum polling interval */ + +/* forward declaration of types */ +typedef struct context_s context_t; +typedef struct remote_s remote_t; +typedef struct application_s application_t; + +/* actions (modes of operation) */ +typedef enum { + ACTION_UNKNOWN = -1, + ACTION_GENERATE, /* generate systemd services for remotes */ + ACTION_UPDATE, /* update flatpaks managed by us */ + ACTION_START, /* start flatpaks for/in a session */ + ACTION_STOP, /* stop flatpaks for/in a session */ + ACTION_SIGNAL, /* signal flatpaks in a session */ + ACTION_LIST, /* list flatpaks */ +} action_t; + +struct context_s { + FlatpakInstallation *f; /* flatpak (system) context */ + remote_t *remotes; /* remotes of interest */ + int nremote; /* number of remotes */ + application_t *apps; /* flatpaks (applications) of interest */ + int napp; /* number of flatpaks */ + GMainLoop *ml; /* main loop, if we need one */ + GFileMonitor *lm; /* flatpak monitor for local changes */ + int lmcn; /* monitor gobject connection */ + unsigned int lmlpt; /* monitor lowpass filter timer */ + unsigned int rpt; /* remote polling timer */ + sigset_t signals; /* signals we catch */ + int sigfd; /* signalfd */ + GIOChannel *sigio; /* I/O channel for sigfd */ + guint sigw; /* watch source id for sigio */ + int exit_code; /* status to exit with */ + + struct { /* various notification callbacks */ + void (*r_up)(context_t *c); /* remote updates available */ + void (*l_up)(context_t *c); /* local updates available */ + } notify; + + /* configuration/command line */ + const char *argv0; /* our binary */ + action_t action; /* action/mode we're running in */ + const char *service_dir; /* systemd generator output directory */ + int forced_restart; /* exit status for forced restart */ + uid_t remote_uid; /* remote to stop/signal session for */ + int poll_interval; /* remote monitor polling interval */ + int signal; /* signal to send */ + int dry_run : 1; /* just show actions, don't execute them */ + int gpg_verify : 1; /* ignore unverifiable remotes */ +}; + +/* a remote repository (associated with a session/user and applications) */ +struct remote_s { + char *name; /* flatpak remote name */ + char *url; /* remote repository URL */ + char *user; /* associated user to run session */ + uid_t uid; /* and its user id */ +}; + +/* a flatpak (application) */ +struct application_s { + char *origin; /* remote repository of origin */ + char *name; /* flatpak application name */ + char *head; /* current latest commit */ + int install : 1; /* automatically install */ + int start : 1; /* automatically start within session */ + int urgent : 1; /* urgent update */ + int pending : 1; /* pending remote updates */ + int updated : 1; /* locally updated */ +}; + + +/* + * miscallaneous macros + */ +#define INVALID_UID ((uid_t)-1) +#define UNUSED_ARG(_arg) (void)(_arg) + +/* + * declarations, function prototypes + */ + +/* config.c */ +void config_parse_cmdline(context_t *c, int argc, char **argv); + +/* mainloop.c */ +int mainloop_needed(context_t *c); +void mainloop_create(context_t *c); +void mainloop_destroy(context_t *c); +void mainloop_run(context_t *c); +void mainloop_quit(context_t *c, int exit_status); +unsigned int mainloop_add_timer(context_t *c, int secs, int (*cb)(void *), + void *user_data); +void mainloop_del_timer(context_t *c, unsigned int id); +unsigned int timer_add(context_t *c, int secs, int (*cb)(void *), + void *user_data); +void timer_del(context_t *c, unsigned int id); + +/* remote.c */ +uid_t remote_user_id(const char *remote, char *usrbuf, size_t size); +char *remote_user_name(uid_t uid, char *usrbuf, size_t size); + +/* filesystem.c */ +int fsys_prepare_session(context_t *c); +char *fsys_mkpath(char *path, size_t size, const char *fmt, ...); +int fsys_mkdir(const char *path, mode_t mode); +int fsys_mkdirp(mode_t mode, const char *fmt, ...); +int fsys_symlink(const char *path, const char *dst); +char *fsys_service_path(context_t *c, const char *usr, char *path, size_t size); +char *fsys_service_link(context_t *c, const char *usr, char *path, size_t size); +int fs_scan_proc(const char *exe, uid_t uid, + int (*cb)(pid_t pid, void *user_data), void *user_data); + +/* flatpak.c */ +typedef enum { + FPAK_DISCOVER_REMOTES = 0x1, + FPAK_DISCOVER_APPS = 0x2, +} fpak_flag_t; + +int fpak_init(context_t *c, int flags); +int fpak_install_remotes(context_t *c, const char *dir); +int fpak_create_remote(context_t *c, const char *name, const char *url, + const char *key, int keylen); +int fpak_discover_remotes(context_t *c); +int fpak_discover_apps(context_t *c); +int fpak_start_app(context_t *c, application_t *a); +int fpak_start_session(context_t *c); +char *fpak_app_systemd_scope(uid_t uid, pid_t session, const char *app, + char *scope, size_t size); +int fpak_poll_updates(context_t *c); +int fpak_update_apps(context_t *c); +int fpak_reload_apps(context_t *c); +int fpak_reload_session(context_t *c); +remote_t *fpak_lookup_remote(context_t *c, const char *name); +remote_t *fpak_remote_for_uid(context_t *c, uid_t uid); +application_t *fpak_lookup_app(context_t *c, const char *name); +int fpak_track_remote_updates(context_t *c, void (*cb)(context_t *)); +int fpak_track_local_updates(context_t *c, void (*cb)(context_t *)); + +#define fpak_foreach_remote(_c, _r) \ + for (_r = _c->remotes; _r && _r->name; _r++) + +#define fpak_foreach_app(_c, _a) \ + for (_a = _c->apps; _a && _a->name; _a++) + +/* log.c */ +typedef enum { + FPAK_LOG_NONE = 0x00, + FPAK_LOG_FATAL = 0x01, + FPAK_LOG_ERROR = 0x02, + FPAK_LOG_WARNING = 0x04, + FPAK_LOG_INFO = 0x08, + FPAK_LOG_DEBUG = 0x10, + FPAK_LOG_ALL = 0x1f, +} fpak_log_level_t; + +int log_set_mask(int mask); +int log_get_mask(void); +void log_open(context_t *c); +void log_close(void); +void log_msg(int lvl, const char *function, const char *file, int line, + const char *fmt, ...); + +#define __LOC__ __FUNCTION__, __FILE__, __LINE__ + +#define log_fatal(_fmt, _args...) log_msg(FPAK_LOG_FATAL , __LOC__, \ + _fmt, ## _args), exit(1) +#define log_error(_fmt, _args...) log_msg(FPAK_LOG_ERROR , __LOC__, \ + _fmt, ## _args) +#define log_warn(_fmt, _args...) log_msg(FPAK_LOG_WARNING, __LOC__, \ + _fmt, ## _args) +#define log_info(_fmt, _args...) log_msg(FPAK_LOG_INFO , __LOC__, \ + _fmt, ## _args) +#define log_debug(_fmt, _args...) log_msg(FPAK_LOG_DEBUG , __LOC__, \ + _fmt, ## _args) + +#endif /* __FLATPAK_SESSION_H__ */ diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session@.service b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session@.service new file mode 100644 index 0000000000..3593d20c8a --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-session@.service @@ -0,0 +1,18 @@ +[Unit] +Description=Automatic flatpak login session for user/remote %i. +After=systemd-user-sessions.service network.service +Before=flatpak-update.service + +[Service] +User=%i +WorkingDirectory=~ +StandardInput=null +StandardOutput=journal +StandardError=journal +PAMName=login +RestartForceExitStatus=69 +Type=simple +ExecStart=/usr/bin/flatpak-session -vvv start -r 69 + +[Install] +WantedBy=multi-user.target diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-sessions.target b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-sessions.target new file mode 100644 index 0000000000..1089c6c32d --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-sessions.target @@ -0,0 +1,18 @@ +# +# Target for autostarting flatpak sessions. +# +# This target is used to collect services that create sessions for users +# corresponding to flatpak remotes and starts flatpaks from the remotes +# in the corresponding user sessions. +# + +[Unit] +Description=Flatpak Sessions +Documentation=man:systemd.special(7) +Conflicts=rescue.service rescue.target +After=network.target +AllowIsolate=no +RefuseManualStart=no + +[Install] +WantedBy=multi-user.target diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-update.service b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-update.service new file mode 100644 index 0000000000..24a2154d62 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak-update.service @@ -0,0 +1,12 @@ +[Unit] +Description=Monitor and pull in available updates for flatpaks. +After=systemd-user-sessions.service network.service + +[Service] +StandardInput=null +StandardOutput=journal +StandardError=journal +ExecStart=/usr/bin/flatpak-session -vvv update --poll-interval 5m + +[Install] +WantedBy=multi-user.target diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak.c new file mode 100644 index 0000000000..a4ea54ce6e --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/flatpak.c @@ -0,0 +1,993 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "flatpak-session.h" + + +static GKeyFile *meta_load(FlatpakInstalledRef *ref); +static GKeyFile *meta_fetch(context_t *c, FlatpakRemoteRef *rref); +static void meta_free(GKeyFile *m); +static const char *meta_get(GKeyFile *m, const char *sec, const char *key, + const char *def); +#define meta_str meta_get +static int meta_int(GKeyFile *m, const char *sec, const char *key, int def); +static int meta_bool(GKeyFile *m, const char *sec, const char *key, int def); + + +int fpak_create_remote(context_t *c, const char *name, const char *url, + const char *key, int keylen) +{ + FlatpakRemote *r; + GError *e; + GBytes *key_bytes; + + e = NULL; + r = flatpak_installation_get_remote_by_name(c->f, name, NULL, &e); + + if (r != NULL) + goto out; + + g_error_free(e); + e = NULL; + + log_info("flatpak: creating remote '%s' (%s)", name, url); + + r = flatpak_remote_new(name); + + if (r == NULL) + return -1; + + flatpak_remote_set_url(r, url); + flatpak_remote_set_gpg_verify(r, TRUE); + flatpak_remote_set_noenumerate(r, FALSE); + flatpak_remote_set_gpg_key(r, key_bytes = g_bytes_new(key, keylen)); + g_bytes_unref(key_bytes); + + if (!flatpak_installation_modify_remote(c->f, r, NULL, &e)) + goto failed; + + out: + g_object_unref(r); + return 0; + + failed: + log_error("flatpak: failed to install remote %s (%s: %d: %s)", + name, g_quark_to_string(e->domain), e->code, e->message); + g_object_unref(r); + g_error_free(e); + + return -1; +} + + +static void strip_whitespace(char *url, int len) +{ + char *p = url; + int n; + + for (p = url; isspace(*p) && p < url + len; p++) + ; + + if (p != url) { + n = p - url; + len -= n; + memmove(url, p, len); + } + + while (len > 0 && isspace(url[len - 1])) + url[--len] = '\0'; +} + + +static ssize_t read_url_and_key(int urlfd, char *url, size_t urlsize, + int keyfd, char *key, size_t keysize) +{ + int len, n; + struct stat st; + + if (fstat(urlfd, &st) < 0) + return -1; + + if (st.st_size > (int)urlsize - 1) + return -1; + + len = 0; + while (len < st.st_size) { + n = read(urlfd, url + len, st.st_size - len); + + if (n < 0) { + if (errno != EINTR) + return -1; + else + continue; + } + + len += n; + } + url[len] = '\0'; + + if (len > 0) + strip_whitespace(url, len - 1); + + if (fstat(keyfd, &st) < 0) + return -1; + + if (st.st_size > (int)keysize) + return -1; + + len = 0; + while (len < st.st_size) { + n = read(keyfd, key + len, st.st_size - len); + + if (n < 0) { + if (errno != EINTR) + return -1; + else + continue; + } + + len += n; + } + + return len; +} + + +int fpak_install_remotes(context_t *c, const char *dir) +{ + DIR *dp; + struct dirent *de; + char *suff, name[PATH_MAX], path[PATH_MAX]; + int keyfd, urlfd, keylen, len; + char key[4096], url[1024 + PATH_MAX]; + + dp = opendir(dir); + + if (dp == NULL) + return errno == ENOENT ? 0 : -1; + + while ((de = readdir(dp)) != NULL) { + if (de->d_type != DT_REG) + continue; + + if ((suff = strrchr(de->d_name, '.')) == NULL) + continue; + + if (strcmp(suff + 1, "url") != 0) + continue; + + len = (int)(suff - de->d_name); + snprintf(name, sizeof(name), "%.*s", len, de->d_name); + + snprintf(path, sizeof(path), "%s/%s.url", dir, name); + urlfd = open(path, O_RDONLY); + snprintf(path, sizeof(path), "%s/%s.key", dir, name); + keyfd = open(path, O_RDONLY); + + keylen = read_url_and_key(urlfd, url, sizeof(url), + keyfd, key, sizeof(key)); + + close(urlfd); + close(keyfd); + + if (keylen > 0) + fpak_create_remote(c, name, url, key, keylen); + else + log_error("flatpak: failed to read URL or key for remote %s", name); + } + + closedir(dp); + + return 0; +} + + +int fpak_init(context_t *c, int flags) +{ + GError *e; + + if (c->f != NULL) + return 0; + + e = NULL; + c->f = flatpak_installation_new_system(NULL, &e); + + if (c->f == NULL) + goto init_failed; + + fpak_install_remotes(c, FPAK_REPOS_DIR); + flatpak_installation_drop_caches(c->f, NULL, &e); + + if (flags & (FPAK_DISCOVER_REMOTES | FPAK_DISCOVER_APPS)) + if (fpak_discover_remotes(c) < 0) + goto fail; + + if (flags & FPAK_DISCOVER_APPS) + if (fpak_discover_apps(c) < 0) + goto fail; + + return 0; + + init_failed: + log_fatal("flatpak: failed to initialize library (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + + fail: + return -1; +} + + +int fpak_discover_remotes(context_t *c) +{ + remote_t *r; + const char *name, *url; + uid_t uid; + GPtrArray *refs; + FlatpakRemote *ref; + GError *e; + int i; + + if (c->remotes != NULL) + return 0; + + e = NULL; + refs = flatpak_installation_list_remotes(c->f, NULL, &e); + + if (refs == NULL) + goto list_failed; + + c->remotes = calloc(refs->len + 1, sizeof(*c->remotes)); + + if (c->remotes == NULL) + log_fatal("flatpak: failed to allocate remotes"); + + r = c->remotes; + for (i = 0; i < (int)refs->len; i++) { + ref = g_ptr_array_index(refs, i); + name = flatpak_remote_get_name(ref); + url = flatpak_remote_get_url(ref); + + if (flatpak_remote_get_disabled(ref)) { + log_warn("flatpak: skipping disabled remote '%s'", name); + continue; + } + + if (c->gpg_verify && !flatpak_remote_get_gpg_verify(ref)) { + log_warn("flatpak: skipping unverifiable remote '%s'", name); + continue; + } + + if ((uid = remote_user_id(name, NULL, 0)) == INVALID_UID) { + log_warn("flatpak: skipping remote without user '%s'", name); + continue; + } + + if (c->remote_uid > 0 && uid != c->remote_uid) { + log_debug("flatpak: skipping other remote '%s'", name); + continue; + } + + r->name = strdup(name); + r->url = strdup(url); + r->user = strdup(remote_user_name(uid, NULL, 0)); + r->uid = uid; + + if (r->name == NULL || r->url == NULL || r->user == NULL) + log_fatal("flatpak: failed to allocate remote"); + + log_info("flatpak: discovered remote '%s' (%s)", r->name, r->url); + + c->nremote++; + r++; + + } + + g_ptr_array_unref(refs); + + return 0; + + list_failed: + log_error("flatpak: failed to query remotes (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + return -1; +} + + +static int update_urgent(const char *urgency) +{ + return !!(!strcmp(urgency, "critical") || !strcmp(urgency, "important")); +} + + +int fpak_discover_apps(context_t *c) +{ + application_t *a; + GKeyFile *m; + const char *origin, *name, *head, *urgency; + GPtrArray *refs; + FlatpakInstalledRef *ref; + FlatpakRefKind knd; + GError *e; + int install, start, urgent; + int i; + + if (c->apps != NULL) + return 0; + + if (fpak_discover_remotes(c) < 0) + return -1; + + knd = FLATPAK_REF_KIND_APP; + e = NULL; + refs = flatpak_installation_list_installed_refs_by_kind(c->f, knd, NULL, &e); + + if (refs == NULL) + goto list_failed; + + c->apps = calloc(refs->len + 1, sizeof(*c->apps)); + + if (c->apps == NULL) + log_fatal("flatpak: failed to allocate applications"); + + a = c->apps; + for (i = 0; i < (int)refs->len; i++) { + ref = g_ptr_array_index(refs, i); + origin = flatpak_installed_ref_get_origin(ref); + name = flatpak_ref_get_name(FLATPAK_REF(ref)); + head = flatpak_ref_get_commit(FLATPAK_REF(ref)); + + if (fpak_lookup_remote(c, origin) == NULL) { + log_debug("flatpak: skipping app '%s' without remote", name); + continue; + } + + if ((m = meta_load(ref)) == NULL) + goto meta_failed; + install = meta_bool(m, FPAK_SECTION_REFKIT, FPAK_KEY_INSTALL, 1); + start = meta_bool(m, FPAK_SECTION_REFKIT, FPAK_KEY_START , 1); + urgency = meta_str (m, FPAK_SECTION_REFKIT, FPAK_KEY_URGENCY, "-"); + urgent = update_urgent(urgency); + meta_free(m); + + a->origin = strdup(origin); + a->name = strdup(name); + a->head = strdup(head); + a->install = install; + a->start = start; + a->urgent = urgent; + + if (a->origin == NULL || a->name == NULL || a->head == NULL) + log_fatal("flatpak: failed to allocate app"); + + c->napp++; + a++; + } + + g_ptr_array_unref(refs); + + return 0; + + list_failed: + log_error("flatpak: failed to query applications (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + return -1; + + meta_failed: + log_error("flatpak: failed to load metadata for '%s'", name); + return -1; +} + + +int fpak_start_app(context_t *c, application_t *a) +{ + GError *e; + int status; + + log_info("flatpak: starting application %s", a->name); + + if (c->dry_run) + return 0; + + sigprocmask(SIG_UNBLOCK, &c->signals, NULL); + e = NULL; + if (!flatpak_installation_launch(c->f, a->name, NULL, NULL, NULL, NULL, &e)) + status = -1; + else + status = 0; + sigprocmask(SIG_BLOCK, &c->signals, NULL); + + if (!status) + return 0; + else { + log_error("flatpak: failed to start '%s' (%s: %d: %s)", a->name, + g_quark_to_string(e->domain), e->code, e->message); + return -1; + } +} + + +int fpak_start_session(context_t *c) +{ + remote_t *r; + application_t *a; + + r = fpak_remote_for_uid(c, c->remote_uid); + + if (r == NULL) + goto no_remote; + + fpak_foreach_app(c, a) { + if (strcmp(a->origin, r->name)) + continue; + + fpak_start_app(c, a); + } + + return 0; + + no_remote: + log_error("flatpak: no remote associated with uid %d", c->remote_uid); + return -1; +} + + +int fpak_reload_session(context_t *c) +{ + application_t *a; + + fpak_foreach_app(c, a) { + if (a->updated) { + log_info("flatpak: %s had updates, should be restarted", a->name); + a->updated = 0; + } + } + + if (c->forced_restart) + exit(c->forced_restart); + + return 0; +} + + +static void progress_cb(const char *status, guint pcnt, gboolean estim, + gpointer user_data) +{ + application_t *a = user_data; + + if (estim) + return; + + log_info("flatpak: %s/%s, %s, %d %% done", a->origin, a->name, status, pcnt); +} + + +int fpak_update_apps(context_t *c) +{ + application_t *a; + FlatpakInstalledRef *u; + const char *name, *origin, *urgency; + GKeyFile *m; + int install, start, urgent; + FlatpakRefKind rk = FLATPAK_REF_KIND_APP; + GError *e; + + fpak_foreach_app(c, a) { + if (!a->pending) + continue; + + name = a->name; + origin = a->origin; + e = NULL; + + log_info("flatpak: %s '%s'", a->head ? "updating" : "installing", name); + + if (c->dry_run) + continue; + + if (a->head != NULL) + u = flatpak_installation_update(c->f, 0, rk, name, NULL, NULL, + progress_cb, a, NULL, &e); + else + u = flatpak_installation_install(c->f, origin, rk, name, NULL, NULL, + progress_cb, a, NULL, &e); + + if (u == NULL) { + if (e && e->code) + log_warn("flatpak: failed to update '%s' (%s: %d: %s)", name, + g_quark_to_string(e->domain), e->code, e->message); + continue; + } + + if ((m = meta_load(u)) == NULL) { + log_warn("flatpak: failed to load metadata for '%s'", name); + goto next; + } + start = meta_bool(m, FPAK_SECTION_REFKIT, FPAK_KEY_START , 1); + install = meta_bool(m, FPAK_SECTION_REFKIT, FPAK_KEY_INSTALL, 1); + urgency = meta_str (m, FPAK_SECTION_REFKIT, FPAK_KEY_URGENCY, "-"); + urgent = update_urgent(urgency); + meta_free(m); + + a->start = start; + a->install = install; + a->urgent = urgent; + + free(a->head); + a->head = strdup(flatpak_ref_get_commit(FLATPAK_REF(u))); + + if (!install) { + /* XXX TODO: I think this will fail if app is running... */ + if (!flatpak_installation_uninstall(c->f, rk, name, NULL, NULL, + progress_cb, a, NULL, &e)) + log_warn("flatpak: failed to uninstall '%s' (%s: %d: %s)", name, + g_quark_to_string(e->domain), e->code, e->message); + } + + next: + g_object_unref(u); + a->pending = 0; + } + + return 0; +} + + +int fpak_reload_apps(context_t *c) +{ + application_t *a; + const char *name, *head; + FlatpakInstalledRef *u; + GError *e; + + e = NULL; + flatpak_installation_drop_caches(c->f, NULL, &e); + + fpak_foreach_app(c, a) { + name = a->name; + e = NULL; + u = flatpak_installation_get_current_installed_app(c->f, name, NULL, &e); + + if (u == NULL) + continue; + + head = flatpak_ref_get_commit(FLATPAK_REF(u)); + if (strcmp(a->head, head)) { + log_info("flatpak: '%s' updated (%s -> %s)", name, a->head, head); + + free(a->head); + a->head = strdup(head); + a->updated = 1; + } + else { + log_info("flatpak: '%s' did not change", name); + a->updated = 0; + } + + g_object_unref(u); + } + + return 0; +} + + +remote_t *fpak_lookup_remote(context_t *c, const char *name) +{ + remote_t *r; + + if (c->remotes == NULL) + return NULL; + + for (r = c->remotes; r->name; r++) + if (!strcmp(r->name, name)) + return r; + + return NULL; +} + + +remote_t *fpak_remote_for_uid(context_t *c, uid_t uid) +{ + remote_t *r; + + if (c->remotes == NULL) + return NULL; + + for (r = c->remotes; r->name; r++) + if (r->uid == uid) + return r; + + return NULL; +} + + +application_t *fpak_lookup_app(context_t *c, const char *name) +{ + application_t *a; + + if (c->apps == NULL) + return NULL; + + for (a = c->apps; a->name; a++) + if (!strcmp(a->name, name)) + return a; + + return NULL; +} + + +int fpak_poll_updates(context_t *c) +{ + remote_t *r; + application_t *a; + GPtrArray *refs; + FlatpakRemoteRef *ref; + const char *origin, *name, *head, *urgency; + GKeyFile *m; + GError *e; + int i, install, urgent, updates; + + updates = 0; + + fpak_foreach_remote(c, r) { + name = r->name; + + log_info("flatpak: polling remote '%s' for updates...", name); + + e = NULL; + refs = flatpak_installation_list_remote_refs_sync(c->f, name, NULL, &e); + + if (refs == NULL) { + log_error("flatpak: failed to query updates for %s (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + continue; + } + + origin = name; + for (i = 0; i < (int)refs->len; i++) { + ref = g_ptr_array_index(refs, i); + + if (flatpak_ref_get_kind(FLATPAK_REF(ref)) != FLATPAK_REF_KIND_APP) + continue; + + name = flatpak_ref_get_name(FLATPAK_REF(ref)); + head = flatpak_ref_get_commit(FLATPAK_REF(ref)); + + if ((m = meta_fetch(c, ref)) == NULL) { + log_error("flatpak: failed to fetch metadata for '%s'", name); + continue; + } + install = meta_bool(m, FPAK_SECTION_REFKIT, FPAK_KEY_INSTALL, 1); + urgency = meta_get (m, FPAK_SECTION_REFKIT, FPAK_KEY_URGENCY, "-"); + urgent = update_urgent(urgency); + meta_free(m); + + a = fpak_lookup_app(c, name); + + if (a == NULL) { + if (!install) + continue; + + log_info("flatpak: pending new app '%s'", name); + + c->apps = realloc(c->apps, (c->napp + 2) * sizeof(*c->apps)); + + if (c->apps == NULL) + log_fatal("flatpak: failed to allocate applications"); + + a = c->apps + c->napp; + + memset(a , 0, sizeof(*a)); /* shouldn't be necessary */ + memset(a + 1, 0, sizeof(*a)); + + a->name = strdup(name); + a->origin = strdup(origin); + a->head = NULL; + + if (a->name == NULL || a->origin == NULL) + log_fatal("flatpak: failed to allocate application"); + + a->pending = 1; + a->urgent = urgent; + + c->napp++; + updates++; + } + else { + if (a->head != NULL && strcmp(a->head, head)) { + log_info("flatpak: pending updates for app '%s'", name); + a->pending = 1; + updates++; + } + else + log_info("flatpak: %s up-to-date", name); + } + } + } + + if (!updates) + log_info("no pending updates"); + + return updates; +} + + +static int check_remote_update(gpointer user_data) +{ + context_t *c = user_data; + + if (fpak_poll_updates(c) > 0) + c->notify.r_up(c); + + return G_SOURCE_CONTINUE; +} + + +int fpak_track_remote_updates(context_t *c, void (*cb)(context_t *)) +{ + if (c->notify.r_up != NULL) + return -1; + + c->rpt = timer_add(c, c->poll_interval, check_remote_update, c); + + c->notify.r_up = cb; + + return 0; +} + + +static int notify_local_update(gpointer user_data) +{ + context_t *c = user_data; + + timer_del(c, c->lmlpt); + c->lmlpt = 0; + + c->notify.l_up(c); + + return G_SOURCE_REMOVE; +} + + +static void l_changed(GFileMonitor *m, GFile *file, GFile *other, + GFileMonitorEvent e, gpointer user_data) +{ + context_t *c = user_data; + char *fpath, *opath; + + UNUSED_ARG(m); + UNUSED_ARG(e); + + fpath = file ? g_file_get_path(file) : NULL; + opath = other ? g_file_get_path(other) : NULL; + log_debug("local change (%s, %s), arming low-pass filter timer...\n", + fpath ? fpath : "-", opath ? opath : "-"); + g_free(fpath); + g_free(opath); + + timer_del(c, c->lmlpt); + c->lmlpt = timer_add(c, FPAK_UPDATE_LOWPASS_TIMER, notify_local_update, c); +} + + +int fpak_track_local_updates(context_t *c, void (*cb)(context_t *)) +{ + GError *e; + + if (c->notify.l_up != NULL) + return -1; + + e = NULL; + c->lm = flatpak_installation_create_monitor(c->f, NULL, &e); + + if (c->lm == NULL) + goto monitor_failed; + + c->lmcn = g_signal_connect(c->lm, "changed", G_CALLBACK(l_changed), c); + + if (c->lmcn <= 0) + goto connect_failed; + + c->notify.l_up = cb; + + return 0; + + monitor_failed: + log_error("flatpak: failed to create installation monitor (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + return -1; + + connect_failed: + log_error("flatpak: failed to connect to installation monitor"); + return -1; + + return 0; +} + + +static GKeyFile *meta_load(FlatpakInstalledRef *ref) +{ + GKeyFile *m; + GBytes *b; + const void *d; + size_t l; + GError *e; + + b = NULL; + m = g_key_file_new(); + + if (m == NULL) + log_fatal("flatpak: failed to allocate metadata"); + + e = NULL; + b = flatpak_installed_ref_load_metadata(ref, NULL, &e); + + if (b == NULL) + goto fail_meta; + + d = g_bytes_get_data(b, &l); + + if (d == NULL) + goto fail_data; + + if (!g_key_file_load_from_data(m, d, l, 0, &e)) + goto fail_load; + + g_bytes_unref(b); + + return m; + + fail_load: + log_error("flatpak: failed to parse metadata (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + fail_meta: + fail_data: + g_key_file_unref(m); + g_bytes_unref(b); + return NULL; +} + + +static GKeyFile *meta_fetch(context_t *c, FlatpakRemoteRef *rref) +{ + GKeyFile *m; + GBytes *b; + const void *d; + size_t l; + FlatpakRef *ref; + const char *remote; + GError *e; + + b = NULL; + m = g_key_file_new(); + + if (m == NULL) + log_fatal("flatpak: failed to allocate metadata"); + + g_object_get(rref, "remote-name", &remote, NULL); + + ref = FLATPAK_REF(rref); + e = NULL; + b = flatpak_installation_fetch_remote_metadata_sync(c->f, remote, ref, + NULL, &e); + + if (b == NULL) + goto fail_meta; + + d = g_bytes_get_data(b, &l); + + if (d == NULL) + goto fail_data; + + if (!g_key_file_load_from_data(m, d, l, 0, &e)) + goto fail_load; + + g_bytes_unref(b); + + return m; + + fail_load: + log_error("flatpak: failed to parse metadata (%s: %d: %s)", + g_quark_to_string(e->domain), e->code, e->message); + fail_meta: + fail_data: + g_key_file_unref(m); + g_bytes_unref(b); + return NULL; +} + + +static void meta_free(GKeyFile *m) +{ + if (m != NULL) + g_key_file_unref(m); +} + + +static const char *meta_get(GKeyFile *m, const char *sec, const char *key, + const char *def) +{ + const char *val; + + if (m == NULL) + return def; + + val = g_key_file_get_value(m, sec, key, NULL); + + return val ? val : def; +} + + +static int meta_int(GKeyFile *m, const char *sec, const char *key, int def) +{ + const char *val; + char *e; + int i; + + if (m == NULL) + return def; + + val = g_key_file_get_value(m, sec, key, NULL); + + if (val == NULL) + return def; + + i = strtol(val, &e, 10); + + if (e && !*e) + return i; + + log_warn("flatpak: invalid metadata integer '%s'", val); + return def; +} + + +static int meta_bool(GKeyFile *m, const char *sec, const char *key, int def) +{ + const char *val; + + UNUSED_ARG(meta_int); + + if (m == NULL) + return !!def; + + val = g_key_file_get_value(m, sec, key, NULL); + + if (val == NULL) + return !!def; + + return !!(!strcasecmp(val, "true") || !strcasecmp(val, "yes")); +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/generator.h b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/generator.h new file mode 100644 index 0000000000..88efd2f804 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/generator.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FSG_GENERATOR_H__ +#define __FSG_GENERATOR_H__ + +#include +#include + +#include + +#include "config.h" + +#ifndef SYSCONFDIR +# define SYSCONFDIR "/etc" +#endif + +#ifndef LIBDIR +# define LIBDIR "/usr/lib" +#endif + +#ifndef LIBEXECDIR +# define LIBEXECDIR "/usr/libexec" +#endif + +#ifndef SYSTEM_SERVICEDIR +# define SYSTEM_SERVICEDIR "/usr/lib/systemd/system" +#endif + +#define PATH_TEMPLATE LIBEXECDIR"/flatpak-utils/flatpak-session.template" + +#define UNUSED_ARG(name) (void)name + +typedef struct { + FlatpakInstallation *f; + GPtrArray *remotes; + char *template; + const char *argv0; + int dry_run : 1; + const char *dir_normal; + const char *dir_early; + const char *dir_late; + const char *dir_service; + const char *path_template; +} generator_t; + + +/* config.c */ +void config_parse_cmdline(generator_t *g, int argc, char **argv); + +/* filesystem.c */ +char *fs_mkpath(char *path, size_t size, const char *fmt, ...); +int fs_mkdir(const char *path, mode_t mode); +int fs_mkdirp(mode_t mode, const char *fmt, ...); +int fs_symlink(const char *path, const char *dst); +char *fs_service_path(generator_t *g, const char *usr, char *path, size_t size); +char *fs_service_link(generator_t *g, const char *usr, char *path, size_t size); +int fs_prepare_directories(generator_t *g); + +/* flatpak.c */ +int fp_discover_remotes(generator_t *g); +uid_t fp_resolve_user(FlatpakRemote *r, char *usrbuf, size_t size); + +/* service.c */ +int service_generate_sessions(generator_t *g); + +/* template.c */ +int template_load(generator_t *g); +int template_eval(generator_t *g, const char *usr, const char *remote, + const char *out); + +/* log.c */ +#define log(fmt, args...) do { \ + dprintf(log_fd, fmt"\n" , ## args); \ + } while (0) + +#define log_info(fmt, args...) log("I: "fmt, ## args) +#define log_warning(fmt, args...) log("W: "fmt, ## args) +#define log_error(fmt, args...) log("E: "fmt, ## args) +#define log_debug(fmt, args...) log("D: "fmt, ## args) + +extern int log_fd; +extern int log_mask; + +void log_open(generator_t *g); + + +#endif /* __FSG_GENERATOR_H__ */ diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/log.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/log.c new file mode 100644 index 0000000000..0dcf8d9495 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/log.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include "flatpak-session.h" + +static int log_fd = -1; +static int log_mask = FPAK_LOG_FATAL | FPAK_LOG_ERROR; + + +int log_set_mask(int mask) +{ + int old_mask = log_mask; + + log_mask = mask; + + return old_mask; +} + + +int log_get_mask(void) +{ + return log_mask; +} + + +void log_open(context_t *c) +{ + log_close(); + + if (c->dry_run || c->action != ACTION_GENERATE) + log_fd = 1; + else + log_fd = open("/dev/kmsg", O_WRONLY); + + if (log_fd < 0) + log_fd = 1; +} + + +void log_close(void) +{ + if (log_fd > 1) + close(log_fd); + + log_fd = -1; +} + + +void log_msg(int lvl, const char *fn, const char *file, int line, + const char *format, ...) +{ + char *hdrstr, hdrbuf[256]; + int hdrlen; + va_list ap; + + UNUSED_ARG(fn); + UNUSED_ARG(file); + UNUSED_ARG(line); + + if (!(log_mask & lvl)) + return; + + switch (lvl) { + case FPAK_LOG_FATAL: hdrstr = "F: "; hdrlen = 3; break; + case FPAK_LOG_ERROR: hdrstr = "E: "; hdrlen = 3; break; + case FPAK_LOG_WARNING: hdrstr = "W: "; hdrlen = 3; break; + case FPAK_LOG_INFO: hdrstr = "I: "; hdrlen = 3; break; + default: hdrstr = "?: "; hdrlen = 3; break; + case FPAK_LOG_DEBUG: + hdrlen = snprintf(hdrstr = hdrbuf, sizeof(hdrbuf), "D: [%s] ", fn); + break; + } + + write(log_fd, hdrstr, hdrlen); + va_start(ap, format); + vdprintf(log_fd, format, ap); + va_end(ap); + write(log_fd, "\n", 1); +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/mainloop.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/mainloop.c new file mode 100644 index 0000000000..415ec8f528 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/mainloop.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "flatpak-session.h" + + +int mainloop_needed(context_t *c) +{ + switch (c->action) { + case ACTION_UPDATE: + return c->poll_interval > 0; + + case ACTION_START: + case ACTION_STOP: + return TRUE; + + default: + return FALSE; + } +} + + +void mainloop_create(context_t *c) +{ + if (c->ml != NULL) + return; + + c->ml = g_main_loop_new(NULL, FALSE); + + if (c->ml == NULL) + log_fatal("failed to create mainloop"); +} + + +void mainloop_destroy(context_t *c) +{ + g_main_loop_unref(c->ml); + c->ml = NULL; +} + + +void mainloop_run(context_t *c) +{ + g_main_loop_run(c->ml); +} + + +void mainloop_quit(context_t *c, int exit_status) +{ + g_main_loop_quit(c->ml); + + if (!c->exit_code && exit_status) + c->exit_code = exit_status; +} + + +unsigned int timer_add(context_t *c, int secs, int (*cb)(void *), + void *user_data) +{ + UNUSED_ARG(c); + + if (c->ml == NULL) + mainloop_create(c); + + return g_timeout_add(1000 * secs, cb, user_data); +} + + +void timer_del(context_t *c, unsigned int id) +{ + UNUSED_ARG(c); + + if (id) + g_source_remove(id); +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/remote.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/remote.c new file mode 100644 index 0000000000..3bc230e9f6 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/remote.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "flatpak-session.h" + + +static int chkgecos(const char *gecos, const char *remote) +{ + const char *prefix = FPAK_GECOS_PREFIX; + int len = sizeof(FPAK_GECOS_PREFIX) - 1; + + return !strncmp(gecos, prefix, len) && !strcmp(gecos + len, remote); +} + + +static uid_t search_passwd(const char *remote, char *buf, size_t size) +{ + struct passwd *pwd; + + setpwent(); + while ((pwd = getpwent()) != NULL) { + if (chkgecos(pwd->pw_gecos, remote)) { + if (buf != NULL) { + strncpy(buf, pwd->pw_name, size - 1); + buf[size - 1] = '\0'; + } + + return pwd->pw_uid; + } + } + endpwent(); + + return INVALID_UID; +} + + +uid_t remote_user_id(const char *remote, char *buf, size_t size) +{ + struct passwd *pwd; + + if (buf != NULL) + *buf = '\0'; + + if ((pwd = getpwnam(remote)) != NULL) { + if (chkgecos(pwd->pw_gecos, remote)) { + if (buf != NULL) { + strncpy(buf, pwd->pw_name, size - 1); + buf[size - 1] = '\0'; + } + + return pwd->pw_uid; + } + } + + return search_passwd(remote, buf, size); +} + + +char *remote_user_name(uid_t uid, char *buf, size_t size) +{ + static char usr[64], *name; + struct passwd *pwd; + + if (buf != NULL) + *buf = '\0'; + else { + buf = usr; + size = sizeof(usr); + } + + if ((pwd = getpwuid(uid)) != NULL) + name = pwd->pw_name; + else + name = ""; + + strncpy(buf, name, size - 1); + buf[size - 1] = '\0'; + + return buf; +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/service.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/service.c new file mode 100644 index 0000000000..89aca0386c --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/service.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "generator.h" + + +static int service_generate(generator_t *g, FlatpakRemote *r, const char *usr) +{ + char srv[PATH_MAX], lnk[PATH_MAX]; + const char *remote = flatpak_remote_get_name(r); + + log_info("generating session service for user %s (remote %s)...", + usr, remote); + + if (!fs_service_path(g, usr, srv, sizeof(srv)) || + !fs_service_link(g, usr, lnk, sizeof(lnk))) + goto fail; + + if (template_eval(g, usr, remote, srv) < 0) + goto template_fail; + + if (symlink(srv, lnk) < 0) + goto fail; + + return 0; + + template_fail: + log_error("service template evaluation failed for usr %s (remote %s)", + usr, remote); + + fail: + return -1; +} + + +int service_generate_sessions(generator_t *g) +{ + FlatpakRemote *r; + unsigned int i; + char usr[256]; + + for (i = 0; i < g->remotes->len; i++) { + r = g_ptr_array_index(g->remotes, i); + + log_warning("process remote %s...", flatpak_remote_get_name(r)); + + if (fp_resolve_user(r, usr, sizeof(usr)) == (uid_t)-1) { + log_warning("remote %s has no associated user, ignoring...", + flatpak_remote_get_name(r)); + continue; + } + + if (service_generate(g, r, usr) < 0) + log_error("failed to generate session for remote '%s'", + flatpak_remote_get_name(r)); + } + + return 0; +} + diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/template.c b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/template.c new file mode 100644 index 0000000000..0f34b94d95 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/files/flatpak-utils/src/template.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include "generator.h" + +int template_load(generator_t *g) +{ + const char *path = g->path_template; + struct stat st; + char *buf, *p; + int fd, n, l; + + if (stat(path, &st) < 0) + goto ioerror; + + if (st.st_size > 16 * 1024) + goto overflow; + + fd = open(path, O_RDONLY); + + if (fd < 0) + goto ioerror; + + buf = calloc(st.st_size + 1, 1); + p = buf; + l = st.st_size; + + while (l > 0) { + n = read(fd, p, l); + + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + else + goto ioerror; + } + + p += n; + l -= n; + } + + close(fd); + *p = '\0'; + + g->template = buf; + + return 0; + + ioerror: + log_error("failed to load template file '%s' (%d: %s)", path, + errno, strerror(errno)); + return -1; + + overflow: + log_error("template file '%s' too large", path); + return -1; + +} + + +static int print_tag(int fd, const char *tag, int len, const char *usr, + const char *remote) +{ + if (!strncmp(tag, "USER", len)) + dprintf(fd, "%s", usr); + else if (!strncmp(tag, "REMOTE", len)) + dprintf(fd, "%s", remote); + else + dprintf(fd, "", len, len, tag); + + return 0; +} + + +int template_eval(generator_t *g, const char *usr, const char *remote, + const char *out) +{ + const char *p, *b, *e, *nl, *tag; + int fd, len; + + fd = open(out, O_WRONLY|O_CREAT, 0644); + + if (fd < 0) + goto ioerror; + + p = g->template; + while (p && *p) { + b = strchr(p, '@'); + + if (b != NULL) { + e = strchr(b + 1, '@'); + nl = strchr(b + 1, '\n'); + + if (e != NULL && (nl == NULL || e < nl)) { + dprintf(fd, "%*.*s", (int)(b - p), (int)(b - p), p); + + tag = b + 1; + len = e - b - 1; + + print_tag(fd, tag, len, usr, remote); + + p = e + 1; + } + else { + if (e == NULL && nl == NULL) { + dprintf(fd, "%s", p); + p = NULL; + } + else if (e != NULL) { + dprintf(fd, "%*.*s", (int)(e - p - 1), (int)(e - p - 1), p); + p = e - 1; + } + else { + dprintf(fd, "%s", p); + p = NULL; + } + } + } + else { + dprintf(fd, "%s", p); + p = NULL; + } + } + + close(fd); + + return 0; + + ioerror: + log_error("failed to open output file '%s' (%d: %s)", out, + errno, strerror(errno)); + + return -1; +} diff --git a/meta-flatpak/recipes-flatpak/flatpak-utils/flatpak-utils_0.0.bb b/meta-flatpak/recipes-flatpak/flatpak-utils/flatpak-utils_0.0.bb new file mode 100644 index 0000000000..7619fe7364 --- /dev/null +++ b/meta-flatpak/recipes-flatpak/flatpak-utils/flatpak-utils_0.0.bb @@ -0,0 +1,34 @@ +DESCRIPTION = "Helper utilities for flatpak-based applications/services." +HOMEPAGE = "http://github.com/klihub/flatpak-utils" +LICENSE = "BSD-3-Clause" + +LIC_FILES_CHKSUM = "file://LICENSE-BSD;md5=f9f435c1bd3a753365e799edf375fc42" + +DEPENDS = "flatpak systemd" + +SRC_URI = " \ + file://flatpak-utils \ + " + +inherit autotools pkgconfig requires-systemd + +AUTO_LIBNAME_PKGS = "" + +S = "${WORKDIR}/flatpak-utils" + +EXTRA_OECONF += "--with-systemdunitdir=${systemd_unitdir}" + +FILES_${PN} = "\ + ${systemd_unitdir}/system-generators/flatpak-session-enable \ + ${bindir}/flatpak-session \ + ${libexecdir}/flatpak-utils \ + ${systemd_unitdir}/system/flatpak-sessions.target \ + ${systemd_unitdir}/system/flatpak-session@.service \ + ${systemd_unitdir}/system/flatpak-update.service \ +" + +FILES_${PN}-dbg =+ "${base_libdir}/systemd/system-generators/.debug" + +SYSTEMD_PACKAGES += "${PN}" +SYSTEMD_SERVICE_${PN} = "flatpak-sessions.target flatpak-update.service" + diff --git a/meta-iot-web b/meta-iot-web index 1e515ff48e..775f6c22c0 160000 --- a/meta-iot-web +++ b/meta-iot-web @@ -1 +1 @@ -Subproject commit 1e515ff48e9d4960e10876b846cfbd9d8b094daa +Subproject commit 775f6c22c0fb0f7cea1254364c0f352677744202 diff --git a/meta-iotqa/conf/test/refkit-image-common.manifest b/meta-iotqa/conf/test/refkit-image-common.manifest index 5427506a22..1f12a6ecc4 100644 --- a/meta-iotqa/conf/test/refkit-image-common.manifest +++ b/meta-iotqa/conf/test/refkit-image-common.manifest @@ -5,8 +5,5 @@ oeqa.runtime.connectivity.services.managerdaemon oeqa.runtime.connectivity.bluetooth.btcheck oeqa.runtime.connectivity.wifi.wifi_connect oeqa.runtime.programming.python.apprt_python -oeqa.runtime.peripherals.mraa.mraa_hello -oeqa.runtime.peripherals.mraa.mraa_gpio oeqa.runtime.multimedia.audio.alsa -oeqa.runtime.peripherals.upm.upm oeqa.runtime.sanity.nftables diff --git a/meta-iotqa/conf/test/refkit-image-gateway-flatpak-runtime.manifest b/meta-iotqa/conf/test/refkit-image-gateway-flatpak-runtime.manifest new file mode 100644 index 0000000000..e0b0843e70 --- /dev/null +++ b/meta-iotqa/conf/test/refkit-image-gateway-flatpak-runtime.manifest @@ -0,0 +1,6 @@ +# Tests for gateway profile +oeqa.runtime.programming.nodejs.apprt_nodejs +oeqa.runtime.core.iotivity.client +oeqa.runtime.multimedia.audio.pulseaudio +oeqa.runtime.sanity.flatpak +oeqa.runtime.sanity.flatpak-session diff --git a/meta-iotqa/conf/test/refkit-image-gateway.manifest b/meta-iotqa/conf/test/refkit-image-gateway.manifest index 07dbc3868a..df0ee6543a 100644 --- a/meta-iotqa/conf/test/refkit-image-gateway.manifest +++ b/meta-iotqa/conf/test/refkit-image-gateway.manifest @@ -1,4 +1,7 @@ # Tests for gateway profile -oeqa.runtime.programming.nodejs.apprt_nodejs oeqa.runtime.core.iotivity.client oeqa.runtime.multimedia.audio.pulseaudio +oeqa.runtime.peripherals.mraa.mraa_gpio +oeqa.runtime.peripherals.mraa.mraa_hello +oeqa.runtime.peripherals.upm.upm +oeqa.runtime.programming.nodejs.apprt_nodejs diff --git a/meta-iotqa/lib/oeqa/runtime/sanity/flatpak-session.py b/meta-iotqa/lib/oeqa/runtime/sanity/flatpak-session.py new file mode 100644 index 0000000000..68d769fc87 --- /dev/null +++ b/meta-iotqa/lib/oeqa/runtime/sanity/flatpak-session.py @@ -0,0 +1,26 @@ +import unittest +from oeqa.oetest import oeRuntimeTest, skipModule +from oeqa.utils.decorators import * + +def setUpModule(): + if not oeRuntimeTest.hasFeature('flatpak-session'): + skipModule("flatpak not enabled, tests skipped") + +class SanityTestFlatpakSession(oeRuntimeTest): + '''flatpak session sanity tests''' + + def test_session_files(self): + '''check if flatpak session binaries and service files exist''' + files = [ + '/usr/bin/flatpak-session', + '/usr/lib/systemd/system-generators/flatpak-session-enable', + '/usr/lib/systemd/system/flatpak-image-runtime.service', + '/usr/lib/systemd/system/flatpak-update.service', + '/usr/lib/systemd/system/flatpak-session@.service', + '/usr/lib/systemd/system/flatpak-sessions.target', + ] + for f in files: + (status, output) = self.target.run('ls %s' % f) + self.assertEqual( + status, 0, + 'flatpak session binary/file %s missing' % f) diff --git a/meta-iotqa/lib/oeqa/runtime/sanity/flatpak.py b/meta-iotqa/lib/oeqa/runtime/sanity/flatpak.py new file mode 100644 index 0000000000..c744632dbf --- /dev/null +++ b/meta-iotqa/lib/oeqa/runtime/sanity/flatpak.py @@ -0,0 +1,32 @@ +import unittest +from oeqa.oetest import oeRuntimeTest, skipModule +from oeqa.utils.decorators import * + +def setUpModule(): + if not oeRuntimeTest.hasFeature('flatpak'): + skipModule("flatpak not enabled, tests skipped") + +class SanityTestFlatpak(oeRuntimeTest): + '''flatpak sanity tests''' + + def test_flatpak_usrmerge(self): + '''check if / and /usr are properly merged''' + links = [ '/bin', '/sbin', '/lib', ] + for l in links: + (status, output) = self.target.run('readlink %s' % l) + self.assertEqual( + status, 0, + "usrmerge error: %s should be a symbolic link" % l) + + def test_basic_binaries(self): + '''check if basic flatpak binaries exist''' + binaries = [ + '/usr/bin/flatpak', + '/usr/bin/gpgme-tool', + '/usr/bin/gpg' + ] + for b in binaries: + (status, output) = self.target.run('ls %s' % b) + self.assertEqual( + status, 0, + 'flatpak basic binary %s missing' % b) diff --git a/meta-refkit-core/classes/refkit-image.bbclass b/meta-refkit-core/classes/refkit-image.bbclass index 0becc04d30..fb20176a32 100644 --- a/meta-refkit-core/classes/refkit-image.bbclass +++ b/meta-refkit-core/classes/refkit-image.bbclass @@ -145,7 +145,6 @@ REFKIT_IMAGE_FEATURES_COMMON ?= " \ connectivity \ ssh-server-openssh \ alsa \ - sensors \ ${@ 'common-test' if (d.getVar('IMAGE_MODE') or 'production') != 'production' else '' } \ " REFKIT_IMAGE_INSTALL_COMMON ?= "" diff --git a/meta-refkit-core/conf/distro/include/enable-refkit-config.inc b/meta-refkit-core/conf/distro/include/enable-refkit-config.inc index 4512e60305..6c2cac9b22 100644 --- a/meta-refkit-core/conf/distro/include/enable-refkit-config.inc +++ b/meta-refkit-core/conf/distro/include/enable-refkit-config.inc @@ -20,3 +20,6 @@ require conf/distro/include/usrmerge.inc # Enable basic flatpak support. include conf/distro/include/flatpak.inc + +# Enable this for flatpak-session/application framework support. +include conf/distro/include/flatpak-session.inc diff --git a/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py b/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py index abaa5cd2e3..b06747834a 100644 --- a/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py +++ b/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py @@ -96,7 +96,7 @@ def do_install(self, fixed_password="", tpm=False): with runqemu('refkit-installer-image', ssh=False, discard_writes=False, qemuparams='-drive if=virtio,file=%s/internal-image-%s.wic,format=raw%s' % (self.resultdir, self.image_arch, qemuparams_tpm), - runqemuparams='ovmf slirp', + runqemuparams='ovmf slirp nographic', image_fstype='wic') as qemu: # Check that we have booted, with dm-verity if enabled. cmd = "findmnt / --output SOURCE --noheadings" @@ -126,7 +126,7 @@ def do_install(self, fixed_password="", tpm=False): with runqemu('refkit-installer-image', ssh=False, overrides=overrides, qemuparams=qemuparams_tpm, - runqemuparams='ovmf slirp', + runqemuparams='ovmf slirp nographic', image_fstype='wic') as qemu: # Check that we have booted, without device mapper involved. # Can't use the simpler findmnt here. diff --git a/meta-refkit-gateway/recipes-image/images/refkit-image-gateway.bb b/meta-refkit-gateway/recipes-image/images/refkit-image-gateway.bb index 831d4a2bb3..e1ef5db79c 100644 --- a/meta-refkit-gateway/recipes-image/images/refkit-image-gateway.bb +++ b/meta-refkit-gateway/recipes-image/images/refkit-image-gateway.bb @@ -6,7 +6,12 @@ REFKIT_IMAGE_GATEWAY_EXTRA_INSTALL ?= "${REFKIT_IMAGE_INSTALL_COMMON}" REFKIT_IMAGE_EXTRA_FEATURES += "${REFKIT_IMAGE_GATEWAY_EXTRA_FEATURES}" REFKIT_IMAGE_EXTRA_INSTALL += "${REFKIT_IMAGE_GATEWAY_EXTRA_INSTALL}" -REFKIT_IMAGE_GATEWAY_EXTRA_FEATURES_append = " iotivity nodejs-runtime bluetooth-audio" +REFKIT_IMAGE_GATEWAY_EXTRA_FEATURES += " \ + bluetooth-audio \ + iotivity \ + nodejs-runtime \ + sensors \ +" # Example for customization in local.conf when building # refkit-image-gateway.bb: diff --git a/meta-refkit/conf/distro/include/refkit-ci.inc b/meta-refkit/conf/distro/include/refkit-ci.inc index e9e85dd584..0f30f4e056 100644 --- a/meta-refkit/conf/distro/include/refkit-ci.inc +++ b/meta-refkit/conf/distro/include/refkit-ci.inc @@ -94,6 +94,8 @@ REFKIT_CI_TEST_RUNS=" \ refkit-image-computervision,iot-testsuite.tar.gz,iot-testfiles.${MACHINE}.tar.gz,${MACHINE},minnowboardturbot \ refkit-image-gateway,iot-testsuite.tar.gz,iot-testfiles.${MACHINE}.tar.gz,${MACHINE},570x \ refkit-image-gateway,iot-testsuite.tar.gz,iot-testfiles.${MACHINE}.tar.gz,${MACHINE},minnowboardturbot \ + ${@bb.utils.contains('DISTRO_FEATURES', 'flatpak', \ + 'refkit-image-gateway-flatpak-runtime,iot-testsuite.tar.gz,iot-testfiles.${MACHINE}.tar.gz,${MACHINE},minnowboardturbot', '', d)} \ " # Dont use disk space monitor in CI builds, to avoid frequent diff --git a/meta-refkit/conf/distro/include/refkit-supported-recipes.txt b/meta-refkit/conf/distro/include/refkit-supported-recipes.txt index cc1e1af079..3c5c68aef2 100644 --- a/meta-refkit/conf/distro/include/refkit-supported-recipes.txt +++ b/meta-refkit/conf/distro/include/refkit-supported-recipes.txt @@ -110,8 +110,10 @@ file@core findutils@core fixesproto@core flac@core -flatpak-image-runtime@flatpak-layer flatpak@flatpak-layer +flatpak-image-runtime@flatpak-layer +flatpak-predefined-repos@flatpak-layer +flatpak-utils@flatpak-layer flex@core font-util@core fontconfig@core