diff -Nru fwupd-1.0.6/.circleci/config.yml fwupd-1.2.10/.circleci/config.yml --- fwupd-1.0.6/.circleci/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/.circleci/config.yml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,84 @@ +version: 2 +jobs: + build-s390x: + machine: + image: circleci/classic:latest + steps: + - checkout + - run: + name: "Build container" + command: OS=debian-s390x ./contrib/ci/generate_docker.py + - run: + name: "Run build script" + command: docker run --privileged -e CI=true -t -v `pwd`/dist:/build/dist fwupd-debian-s390x + + build-snap: + docker: + - image: superm1/snapcraft-edge:latest + steps: + - checkout + - run: + name: "Update apt" + command: apt update + - run: + name: "Build Snap" + command: snapcraft + - persist_to_workspace: + root: . + paths: + - "*.snap" + + publish-edge: + docker: + - image: cibuilds/snapcraft:stable + steps: + - attach_workspace: + at: . + - run: + name: "Publish to Store" + command: | + mkdir .snapcraft + echo $SNAPCRAFT_LOGIN_FILE | base64 --decode --ignore-garbage > .snapcraft/snapcraft.cfg + snapcraft push *.snap --release edge + + publish-stable: + docker: + - image: cibuilds/snapcraft:stable + steps: + - attach_workspace: + at: . + - run: + name: "Publish to Store" + command: | + mkdir .snapcraft + echo $SNAPCRAFT_LOGIN_FILE | base64 --decode --ignore-garbage > .snapcraft/snapcraft.cfg + snapcraft push *.snap --release stable + +workflows: + version: 2 + main: + jobs: + - build-s390x + - build-snap + - publish-edge: + requires: + - build-snap + filters: + branches: + only: master + deploy: + jobs: + - build-snap: + filters: + branches: + ignore: /.*/ + tags: + only: /^\d+\.\d+\.\d+$/ + - publish-stable: + requires: + - build-snap + filters: + branches: + ignore: /.*/ + tags: + only: /^\d+\.\d+\.\d+$/ diff -Nru fwupd-1.0.6/COMMITMENT fwupd-1.2.10/COMMITMENT --- fwupd-1.0.6/COMMITMENT 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/COMMITMENT 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,45 @@ +Common Cure Rights Commitment, version 1.0 + +Before filing or continuing to prosecute any legal proceeding or claim +(other than a Defensive Action) arising from termination of a Covered +License, we commit to extend to the person or entity ('you') accused +of violating the Covered License the following provisions regarding +cure and reinstatement, taken from GPL version 3. As used here, the +term 'this License' refers to the specific Covered License being +enforced. + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly + and finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you + have received notice of violation of this License (for any work) + from that copyright holder, and you cure the violation prior to 30 + days after your receipt of the notice. + +We intend this Commitment to be irrevocable, and binding and +enforceable against us and assignees of or successors to our +copyrights. + +Definitions + +'Covered License' means the GNU General Public License, version 2 +(GPLv2), the GNU Lesser General Public License, version 2.1 +(LGPLv2.1), or the GNU Library General Public License, version 2 +(LGPLv2), all as published by the Free Software Foundation. + +'Defensive Action' means a legal proceeding or claim that We bring +against you in response to a prior proceeding or claim initiated by +you or your affiliate. + +'We' means each contributor to this repository as of the date of +inclusion of this file, including subsidiaries of a corporate +contributor. + +This work is available under a Creative Commons Attribution-ShareAlike +4.0 International license. diff -Nru fwupd-1.0.6/contrib/add-capsule-header.py fwupd-1.2.10/contrib/add-capsule-header.py --- fwupd-1.0.6/contrib/add-capsule-header.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/add-capsule-header.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,71 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2019 Richard Hughes +# +# SPDX-License-Identifier: LGPL-2.1+ + +import sys +import uuid +import argparse +import struct + +CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000 +CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000 +CAPSULE_FLAGS_INITIATE_RESET = 0x00040000 + +def main(args): + + # parse GUID from command line + try: + guid = uuid.UUID(args.guid) + except ValueError as e: + print(e) + return 1 + try: + with open(args.bin, 'rb') as f: + bin_data = f.read() + except FileNotFoundError as e: + print(e) + return 1 + + # check if already has header + hdrsz = struct.calcsize('<16sIII') + if len(bin_data) >= hdrsz: + hdr = struct.unpack('<16sIII', bin_data[:hdrsz]) + imgsz = hdr[3] + if imgsz == len(bin_data): + print('Replacing existing CAPSULE_HEADER of:') + guid_mixed = uuid.UUID(bytes_le=hdr[0]) + hdrsz_old = hdr[1] + flags = hdr[2] + print('GUID: %s' % guid_mixed) + print('HdrSz: 0x%04x' % hdrsz_old) + print('Flags: 0x%04x' % flags) + print('PayloadSz: 0x%04x' % imgsz) + bin_data = bin_data[hdrsz_old:] + + # set header flags + flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET + if args.flags: + flags = int(args.flags, 16) + + # build update capsule header + imgsz = hdrsz + len(bin_data) + hdr = struct.pack('<16sIII', guid.bytes_le, hdrsz, flags, imgsz) + with open(args.cap, 'wb') as f: + f.write(hdr + bin_data) + print('Wrote capsule %s' % args.cap) + print('GUID: %s' % guid) + print('HdrSz: 0x%04x' % hdrsz) + print('Flags: 0x%04x' % flags) + print('PayloadSz: 0x%04x' % imgsz) + return 0 + +parser = argparse.ArgumentParser(description='Add capsule header on firmware') +parser.add_argument('--guid', help='GUID of the device', required=True) +parser.add_argument('--bin', help='Path to the .bin file', required=True) +parser.add_argument('--cap', help='Output capsule file path', required=True) +parser.add_argument('--flags', help='Flags, e.g. 0x40000', default=None) +args = parser.parse_args() + +sys.exit(main(args)) diff -Nru fwupd-1.0.6/contrib/ci/arch.sh fwupd-1.2.10/contrib/ci/arch.sh --- fwupd-1.0.6/contrib/ci/arch.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/arch.sh 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,7 @@ #!/bin/bash set -e set -x +shopt -s extglob VERSION=`git describe | sed 's/-/.r/;s/-/./'` [ -z $VERSION ] && VERSION=`head meson.build | grep ' version :' | cut -d \' -f2` @@ -11,7 +12,7 @@ cp ../contrib/PKGBUILD . sed -i "s,#VERSION#,$VERSION," PKGBUILD mkdir -p src/fwupd && pushd src/fwupd -ln -s ../../../* . +cp -R ../../../!(build|dist) . popd chown nobody . -R diff -Nru fwupd-1.0.6/contrib/ci/centos.sh fwupd-1.2.10/contrib/ci/centos.sh --- fwupd-1.0.6/contrib/ci/centos.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/centos.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,21 @@ +#!/bin/sh +set -e +set -x + +rm -rf build +mkdir -p build +cd build +meson .. \ + --werror \ + -Dplugin_uefi=false \ + -Dplugin_dell=false \ + -Dplugin_modem_manager=false \ + -Dplugin_synaptics=true \ + -Dplugin_flashrom=true \ + -Dintrospection=true \ + -Dgtkdoc=true \ + -Dpkcs7=false \ + -Dman=true +ninja-build -v +ninja-build test -v +cd .. diff -Nru fwupd-1.0.6/contrib/ci/check_missing_translations.sh fwupd-1.2.10/contrib/ci/check_missing_translations.sh --- fwupd-1.0.6/contrib/ci/check_missing_translations.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/check_missing_translations.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +cd po +intltool-update -m +if [ -f missing ]; then + exit 1 +fi diff -Nru fwupd-1.0.6/contrib/ci/debian_s390x.sh fwupd-1.2.10/contrib/ci/debian_s390x.sh --- fwupd-1.0.6/contrib/ci/debian_s390x.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/debian_s390x.sh 2019-07-15 18:25:54.000000000 +0000 @@ -3,6 +3,12 @@ set -x export LC_ALL=C.UTF-8 + +#evaluate using Debian's build flags +eval "$(dpkg-buildflags --export=sh)" +#filter out -Bsymbolic-functions +export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") + rm -rf build mkdir -p build cp contrib/ci/s390x_cross.txt build/ @@ -10,13 +16,20 @@ meson .. \ --cross-file s390x_cross.txt \ --werror \ + -Dplugin_flashrom=false \ -Dplugin_uefi=false \ - -Dplugin_uefi_labels=false \ -Dplugin_dell=false \ - -Dplugin_synaptics=false \ + -Dplugin_modem_manager=false \ + -Dplugin_redfish=false \ -Dintrospection=false \ -Dgtkdoc=false \ + -Dlibxmlb:introspection=false \ + -Dlibxmlb:gtkdoc=false \ -Dman=false ninja -v ninja test -v cd .. + + +#test for missing translation files +./contrib/ci/check_missing_translations.sh diff -Nru fwupd-1.0.6/contrib/ci/debian.sh fwupd-1.2.10/contrib/ci/debian.sh --- fwupd-1.0.6/contrib/ci/debian.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/debian.sh 2019-07-15 18:25:54.000000000 +0000 @@ -21,7 +21,12 @@ mv contrib/debian . sed s/quilt/native/ debian/source/format -i #generate control file -./contrib/ci/generate_debian_control.py debian/control.in debian/control +./contrib/ci/generate_debian.py + +#disable unit tests if fwupd is already installed (may cause problems) +if [ -x /usr/lib/fwupd/fwupd ]; then + export DEB_BUILD_OPTIONS=nocheck +fi #build the package EDITOR=/bin/true dch --create --package fwupd -v $VERSION "CI Build" debuild --no-lintian --preserve-envvar CI --preserve-envvar CC diff -Nru fwupd-1.0.6/contrib/ci/dependencies.xml fwupd-1.2.10/contrib/ci/dependencies.xml --- fwupd-1.0.6/contrib/ci/dependencies.xml 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/dependencies.xml 2019-07-15 18:25:54.000000000 +0000 @@ -1,14 +1,47 @@ - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + @@ -19,6 +52,9 @@ + + + @@ -30,7 +66,12 @@ - + + + + + + @@ -41,6 +82,9 @@ + + cairo-devel + cairo-devel @@ -56,6 +100,9 @@ + + cairo-gobject-devel + cairo-gobject-devel @@ -74,6 +121,9 @@ json-glib + + json-glib-devel + json-glib-devel @@ -92,34 +142,51 @@ - + - colord + libftdi + + + libftdi-devel - colord-devel + libftdi-devel + + + + + + + + + + + + pciutils + + + pciutils-devel + + + pciutils-devel - - (>= 1.0.0) - - libcolord-dev:s390x - - (>= 1.0.0) - - + - ttf-dejavu + noto-fonts + + + google-noto-sans-cjk-ttc-fonts - dejavu-sans-fonts + google-noto-sans-cjk-ttc-fonts @@ -143,19 +210,22 @@ - (>= 10.3) + (>= 11) - (>= 10.3) + (>= 11) + + + @@ -168,6 +238,9 @@ + + + @@ -183,7 +256,15 @@ + + + + + + + elfutils-libelf-devel + elfutils-libelf-devel @@ -208,6 +289,9 @@ + + freetype + freetype @@ -223,6 +307,9 @@ + + + @@ -236,35 +323,10 @@ - - - fwupdate - - - fwupdate-devel - - - - (>= 10-3) - amd64 - arm64 - armhf - i386 - - - - - - - amd64 - arm64 - armhf - i386 - - - - + + + @@ -280,6 +342,9 @@ + + + @@ -299,23 +364,51 @@ + + + - + + + gnu-efi-libs + + + + + + + - - + + amd64 + arm64 + armhf + i386 + + gnu-efi + gnu-efi - + + amd64 + arm64 + armhf + i386 + + gnu-efi + gnu-efi + + + @@ -329,6 +422,9 @@ + + glib2-devel + glib2-devel @@ -351,6 +447,9 @@ + + gobject-introspection-devel + gobject-introspection-devel @@ -365,6 +464,9 @@ + + gpgme-devel + gpgme-devel @@ -392,6 +494,9 @@ + + gnutls-devel + gnutls-devel @@ -407,6 +512,9 @@ + + gnutls-utils + gnutls-utils @@ -425,6 +533,9 @@ gtk-doc + + gtk-doc + gtk-doc @@ -442,6 +553,9 @@ + + + @@ -457,33 +571,46 @@ + + + - + - appstream-glib + libxmlb + + - libappstream-glib-devel + libxmlb-devel - (>= 0.7.4) + (>= 0.1.5) - libappstream-glib-dev:s390x + libxmlb-dev:s390x + + + libarchive-devel + libarchive-devel @@ -498,25 +625,42 @@ - + + + efivar + + + efivar-devel + + + efivar-devel + - + + amd64 + arm64 + armhf + i386 + - libcolorhug-dev:s390x - + + amd64 + arm64 + armhf + i386 + - + amd64 arm64 armhf - armel i386 @@ -527,13 +671,21 @@ amd64 arm64 armhf - armel i386 + + gcab + + + libgcab1-devel + + + libgcab1-devel + @@ -558,6 +710,9 @@ + + libgudev1-devel + libgudev1-devel @@ -573,6 +728,12 @@ + + libgusb + + + libgusb-devel + libgusb-devel @@ -604,6 +765,12 @@ + + libsmbios + + + libsmbios-devel + libsmbios-devel @@ -616,11 +783,20 @@ - + + i386 + amd64 + + + libsoup + + + libsoup-devel + libsoup-devel @@ -646,6 +822,11 @@ + + + + + @@ -685,6 +866,9 @@ + + + @@ -700,6 +884,9 @@ + + pango-devel + pango-devel @@ -725,6 +912,12 @@ + + polkit + + + polkit + polkit @@ -743,7 +936,52 @@ + + + ModemManager-glib-devel + + + ModemManager-glib-devel + + + modemmanager + + + + + libmm-glib-dev:s390x + + + + + + + + + + libqmi-devel + + + libqmi-devel + + + libqmi + + + + + libqmi-glib-dev:s390x + + + + + + + + + polkit-devel + polkit-devel @@ -758,7 +996,15 @@ + + + + + + + python34-devel + @@ -827,16 +1073,25 @@ + + + + + + + + sqlite-devel + sqlite-devel @@ -852,6 +1107,9 @@ + + + @@ -870,6 +1128,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -895,6 +1174,9 @@ + + umockdev-devel + umockdev-devel @@ -912,6 +1194,9 @@ vala + + vala + vala @@ -930,11 +1215,17 @@ + + valgrind-devel + valgrind-devel + ia64 + riscv64 + x32 mips sparc64 sh4 @@ -953,6 +1244,9 @@ + ia64 + riscv64 + x32 mips sparc64 sh4 @@ -969,9 +1263,27 @@ + + + + + + + + + + + + + + + + + + diff -Nru fwupd-1.0.6/contrib/ci/Dockerfile-centos.in fwupd-1.2.10/contrib/ci/Dockerfile-centos.in --- fwupd-1.0.6/contrib/ci/Dockerfile-centos.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/Dockerfile-centos.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +FROM centos:7 +%%%OS%%% +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 +RUN echo fubar > /etc/machine-id +RUN yum install epel-release -y +RUN echo fubar > /etc/machine-id +%%%INSTALL_DEPENDENCIES_COMMAND%%% +RUN pip3 install pillow pygobject +RUN wget https://copr.fedorainfracloud.org/coprs/jsynacek/systemd-backports-for-centos-7/repo/epel-7/jsynacek-systemd-backports-for-centos-7-epel-7.repo -O /etc/yum.repos.d/jsynacek-systemd-centos-7.repo +RUN yum --enablerepo=epel-testing -y update +RUN mkdir /build +WORKDIR /build +COPY . . +CMD ["./contrib/ci/centos.sh"] diff -Nru fwupd-1.0.6/contrib/ci/Dockerfile-debian.in fwupd-1.2.10/contrib/ci/Dockerfile-debian.in --- fwupd-1.0.6/contrib/ci/Dockerfile-debian.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/Dockerfile-debian.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,5 +1,19 @@ FROM %%%ARCH_PREFIX%%%debian:testing %%%OS%%% +RUN echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" >> /etc/apt/sources.list +RUN echo 'Package: *\n\ +Pin: release a=testing\n\ +Pin-Priority: 900\n\ +\n\ +Package: *\n\ +Pin: release a=unstable\n\ +Pin-Priority: 800\n\ +\n\ +Package: libxmlb-dev\n\ +Pin: release a=unstable\n\ +Pin-Priority: 901\n'\ + > /etc/apt/preferences +RUN cat /etc/apt/preferences RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% %%%INSTALL_DEPENDENCIES_COMMAND%%% diff -Nru fwupd-1.0.6/contrib/ci/Dockerfile-fedora.in fwupd-1.2.10/contrib/ci/Dockerfile-fedora.in --- fwupd-1.0.6/contrib/ci/Dockerfile-fedora.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/Dockerfile-fedora.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,10 +1,10 @@ -FROM fedora:26 +FROM fedora:29 %%%OS%%% ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 RUN echo fubar > /etc/machine-id -RUN dnf --enablerepo=updates-testing -y update +RUN dnf -y update RUN echo fubar > /etc/machine-id %%%INSTALL_DEPENDENCIES_COMMAND%%% RUN mkdir /build diff -Nru fwupd-1.0.6/contrib/ci/Dockerfile-flatpak.in fwupd-1.2.10/contrib/ci/Dockerfile-flatpak.in --- fwupd-1.0.6/contrib/ci/Dockerfile-flatpak.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/Dockerfile-flatpak.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,12 @@ +FROM fedora:29 +%%%OS%%% +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 +RUN echo fubar > /etc/machine-id +%%%INSTALL_DEPENDENCIES_COMMAND%%% +RUN dnf --enablerepo=updates-testing -y update +RUN mkdir /build +WORKDIR /build +COPY . . +CMD ["./contrib/ci/flatpak.py"] diff -Nru fwupd-1.0.6/contrib/ci/Dockerfile-snap.in fwupd-1.2.10/contrib/ci/Dockerfile-snap.in --- fwupd-1.0.6/contrib/ci/Dockerfile-snap.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/Dockerfile-snap.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,25 @@ +FROM ubuntu:xenial + +RUN apt-get update && \ + apt-get dist-upgrade --yes && \ + apt-get install --yes \ + curl sudo jq squashfs-tools && \ + curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core' | jq '.download_url' -r) --output core.snap && \ + mkdir -p /snap/core && unsquashfs -d /snap/core/current core.snap && rm core.snap && \ + curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/snapcraft?channel=edge' | jq '.download_url' -r) --output snapcraft.snap && \ + mkdir -p /snap/snapcraft && unsquashfs -d /snap/snapcraft/current snapcraft.snap && rm snapcraft.snap && \ + apt remove --yes --purge curl jq squashfs-tools && \ + apt-get autoclean --yes && \ + apt-get clean --yes + +COPY contrib/ci/snapcraft-wrapper /snap/bin/snapcraft +ENV PATH=/snap/bin:$PATH + +LABEL maintainer="Mario Limonciello " +RUN apt-get update && apt-get install -y \ + curl \ + git \ + jq \ + openssh-client \ + wget +WORKDIR /root/project diff -Nru fwupd-1.0.6/contrib/ci/Dockerfile-ubuntu.in fwupd-1.2.10/contrib/ci/Dockerfile-ubuntu.in --- fwupd-1.0.6/contrib/ci/Dockerfile-ubuntu.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/Dockerfile-ubuntu.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,5 +1,6 @@ FROM ubuntu:devel %%%OS%%% +ENV CC clang-6.0 RUN echo fubar > /etc/machine-id %%%ARCH_SPECIFIC_COMMAND%%% %%%INSTALL_DEPENDENCIES_COMMAND%%% diff -Nru fwupd-1.0.6/contrib/ci/fedora.sh fwupd-1.2.10/contrib/ci/fedora.sh --- fwupd-1.0.6/contrib/ci/fedora.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/fedora.sh 2019-07-15 18:25:54.000000000 +0000 @@ -7,15 +7,17 @@ mkdir -p build && pushd build rm -rf * meson .. \ + -Db_sanitize=address \ -Dgtkdoc=true \ -Dman=true \ -Dtests=true \ -Dplugin_dummy=true \ + -Dplugin_flashrom=true \ + -Dplugin_modem_manager=false \ -Dplugin_thunderbolt=true \ -Dplugin_uefi=true \ -Dplugin_dell=true \ - -Dplugin_synaptics=true \ - -Dplugin_colorhug=true $@ + -Dplugin_synaptics=true $@ ninja-build dist popd VERSION=`meson introspect build --projectinfo | jq -r .version` @@ -47,14 +49,25 @@ #install RPM packages dnf install -y $HOME/rpmbuild/RPMS/*/*.rpm +mkdir -p dist cp $HOME/rpmbuild/RPMS/*/*.rpm dist -# run the installed tests if [ "$CI" = "true" ]; then sed "s,^BlacklistPlugins=test,BlacklistPlugins=," -i /etc/fwupd/daemon.conf + + # set up enough PolicyKit and D-Bus to run the daemon mkdir -p /run/dbus mkdir -p /var ln -s /var/run /run dbus-daemon --system --fork + /usr/lib/polkit-1/polkitd & + sleep 5 + + # run the daemon startup to check it can start + /usr/libexec/fwupd/fwupd --immediate-exit --verbose + + # run the installed tests whilst the daemon debugging + /usr/libexec/fwupd/fwupd --verbose & + sleep 10 gnome-desktop-testing-runner fwupd fi diff -Nru fwupd-1.0.6/contrib/ci/flatpak.py fwupd-1.2.10/contrib/ci/flatpak.py --- fwupd-1.0.6/contrib/ci/flatpak.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/flatpak.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +import subprocess +import os +import json +import shutil + +def prepare (target): + #clone the flatpak json + cmd = ['git', 'submodule', 'update', '--remote', 'contrib/flatpak'] + subprocess.run (cmd, check=True) + + #clone the submodules for that + cmd = ['git', 'submodule', 'update', '--init', '--remote', 'shared-modules/'] + subprocess.run (cmd, cwd='contrib/flatpak', check=True) + + #parse json + if os.path.isdir ('build'): + shutil.rmtree ('build') + data = {} + with open ('contrib/flatpak/org.freedesktop.fwupd.json', 'r') as rfd: + data = json.load (rfd, strict=False) + platform = 'runtime/%s/x86_64/%s' % (data['runtime'], data['runtime-version']) + sdk = 'runtime/%s/x86_64/%s' % (data['sdk'], data['runtime-version']) + num_modules = len (data['modules']) + + #update to build from master + data["branch"] = "master" + for index in range(0, num_modules): + module = data['modules'][index] + if type (module) != dict or not 'name' in module: + continue + name = module['name'] + if not 'fwupd' in name: + continue + data['modules'][index]['sources'][0].pop ('url') + data['modules'][index]['sources'][0].pop ('sha256') + data['modules'][index]['sources'][0]['type'] = 'dir' + data['modules'][index]['sources'][0]['skip'] = [".git"] + data['modules'][index]['sources'][0]['path'] = ".." + + #write json + os.mkdir('build') + with open (target, 'w') as wfd: + json.dump(data, wfd, indent=4) + os.symlink ('../contrib/flatpak/shared-modules','build/shared-modules') + + # install the runtimes (parsed from json!) + repo = 'flathub' + repo_url = 'https://dl.flathub.org/repo/flathub.flatpakrepo' + print ("Installing dependencies") + cmd = ['flatpak', 'remote-add', '--if-not-exists', repo, repo_url] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'install', '--assumeyes', repo, sdk] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'install', '--assumeyes', repo, platform] + subprocess.run (cmd, check=True) + + +def build (target): + cmd = ['flatpak-builder', '--repo=repo', '--force-clean', '--disable-rofiles-fuse', 'build-dir', target] + subprocess.run (cmd, check=True) + cmd = ['flatpak', 'build-bundle', 'repo', 'fwupd.flatpak', 'org.freedesktop.fwupd'] + subprocess.run (cmd, check=True) + +if __name__ == '__main__': + t = os.path.join ('build', 'org.freedesktop.fwupd.json') + prepare (t) + build (t) + +# to run from the builddir: +# sudo flatpak-builder --run build-dir org.freedesktop.fwupd.json /app/libexec/fwupd/fwupdtool get-devices + +# install the single file bundle +# flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo +# flatpak install fwupd.flatpak + +# to run a shell in the same environment that flatpak sees: +# flatpak run --command=sh --devel org.freedesktop.fwupd + +# to run fwupdtool as root: +# sudo flatpak run org.freedesktop.fwupd --verbose get-devices diff -Nru fwupd-1.0.6/contrib/ci/generate_debian_control.py fwupd-1.2.10/contrib/ci/generate_debian_control.py --- fwupd-1.0.6/contrib/ci/generate_debian_control.py 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/generate_debian_control.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -#!/usr/bin/python3 -# -# Copyright (C) 2017 Dell Inc. -# -# Licensed under the GNU General Public License Version 2 -# -# 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 2 of the License, 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. -# -import os -import sys -import xml.etree.ElementTree as etree - -def parse_control_dependencies(requested_type): - TARGET=os.getenv('OS') - deps = [] - dep = '' - - if TARGET == '': - print("Missing OS environment variable") - sys.exit(1) - OS = TARGET - SUBOS = '' - if TARGET: - split = TARGET.split('-') - if len(split) >= 2: - OS = split[0] - SUBOS = split[1] - else: - import lsb_release - OS = lsb_release.get_distro_information()['ID'].lower() - import platform - SUBOS = platform.machine() - - tree = etree.parse(os.path.join(directory, "dependencies.xml")) - root = tree.getroot() - for child in root: - if not "type" in child.attrib or not "id" in child.attrib: - continue - for distro in child: - if not "id" in distro.attrib: - continue - if distro.attrib["id"] != OS: - continue - control = distro.find("control") - if control is None: - continue - packages = distro.findall("package") - for package in packages: - if SUBOS: - if not 'variant' in package.attrib: - continue - if package.attrib['variant'] != SUBOS: - continue - if package.text: - dep = package.text - else: - dep = child.attrib["id"] - if child.attrib["type"] == requested_type and dep: - version = control.find('version') - if version is not None: - dep = "%s %s" % (dep, version.text) - inclusions = control.findall('inclusive') - if inclusions: - for i in range(0, len(inclusions)): - prefix = '' - suffix = ' ' - if i == 0: - prefix = " [" - if i == len(inclusions) - 1: - suffix = "]" - dep = "%s%s%s%s" % (dep, prefix, inclusions[i].text, suffix) - exclusions = control.findall('exclusive') - if exclusions: - for i in range(0, len(exclusions)): - prefix = '!' - suffix = ' ' - if i == 0: - prefix = " [!" - if i == len(exclusions) - 1: - suffix = "]" - dep = "%s%s%s%s" % (dep, prefix, exclusions[i].text, suffix) - deps.append(dep) - return deps - -directory = os.path.dirname(sys.argv[0]) -if (len(sys.argv) < 3): - print("Missing input and output file") - sys.exit(1) - -deps = parse_control_dependencies("build") - -input = sys.argv[1] -if not os.path.exists(input): - print("Missing input file %s" % input) - sys.exit(1) - -with open(input, 'r') as rfd: - lines = rfd.readlines() - -deps.sort() -output = sys.argv[2] -with open(output, 'w') as wfd: - for line in lines: - if line.startswith("Build-Depends: %%%DYNAMIC%%%"): - wfd.write("Build-Depends:\n") - for i in range(0, len(deps)): - wfd.write("\t%s,\n" % deps[i]) - else: - wfd.write(line) diff -Nru fwupd-1.0.6/contrib/ci/generate_debian.py fwupd-1.2.10/contrib/ci/generate_debian.py --- fwupd-1.0.6/contrib/ci/generate_debian.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/generate_debian.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,148 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2017 Dell, Inc. +# +# SPDX-License-Identifier: LGPL-2.1+ +# +import os +import sys +import xml.etree.ElementTree as etree + +def parse_control_dependencies(requested_type): + TARGET=os.getenv('OS') + deps = [] + dep = '' + + if TARGET == '': + print("Missing OS environment variable") + sys.exit(1) + OS = TARGET + SUBOS = '' + if TARGET: + split = TARGET.split('-') + if len(split) >= 2: + OS = split[0] + SUBOS = split[1] + else: + import lsb_release + OS = lsb_release.get_distro_information()['ID'].lower() + import platform + SUBOS = platform.machine() + + tree = etree.parse(os.path.join(os.path.dirname (sys.argv[0]), "dependencies.xml")) + root = tree.getroot() + for child in root: + if not "type" in child.attrib or not "id" in child.attrib: + continue + for distro in child: + if not "id" in distro.attrib: + continue + if distro.attrib["id"] != OS: + continue + control = distro.find("control") + if control is None: + continue + packages = distro.findall("package") + for package in packages: + if SUBOS: + if not 'variant' in package.attrib: + continue + if package.attrib['variant'] != SUBOS: + continue + if package.text: + dep = package.text + else: + dep = child.attrib["id"] + if child.attrib["type"] == requested_type and dep: + version = control.find('version') + if version is not None: + dep = "%s %s" % (dep, version.text) + inclusions = control.findall('inclusive') + if inclusions: + for i in range(0, len(inclusions)): + prefix = '' + suffix = ' ' + if i == 0: + prefix = " [" + if i == len(inclusions) - 1: + suffix = "]" + dep = "%s%s%s%s" % (dep, prefix, inclusions[i].text, suffix) + exclusions = control.findall('exclusive') + if exclusions: + for i in range(0, len(exclusions)): + prefix = '!' + suffix = ' ' + if i == 0: + prefix = " [!" + if i == len(exclusions) - 1: + suffix = "]" + dep = "%s%s%s%s" % (dep, prefix, exclusions[i].text, suffix) + deps.append(dep) + return deps + +def update_debian_control(target): + control_in = os.path.join(target, 'control.in') + control_out = os.path.join(target, 'control') + + if not os.path.exists(control_in): + print("Missing file %s" % control_in) + sys.exit(1) + + with open(control_in, 'r') as rfd: + lines = rfd.readlines() + + deps = parse_control_dependencies("build") + deps.sort() + with open(control_out, 'w') as wfd: + for line in lines: + if line.startswith("Build-Depends: %%%DYNAMIC%%%"): + wfd.write("Build-Depends:\n") + for i in range(0, len(deps)): + wfd.write("\t%s,\n" % deps[i]) + else: + wfd.write(line) + +def update_debian_copyright (directory): + copyright_in = os.path.join(directory, 'copyright.in') + copyright_out = os.path.join(directory, 'copyright') + + if not os.path.exists(copyright_in): + print("Missing file %s" % copyright_in) + sys.exit(1) + + # Assume all files are remaining LGPL-2.1+ + copyrights = [] + for root, dirs, files in os.walk('.'): + for file in files: + target = os.path.join (root, file) + #skip translations and license file + if target.startswith('./po/') or file == "COPYING": + continue + try: + with open(target, 'r') as rfd: + #read about the first few lines of the file only + lines = rfd.readlines(220) + except UnicodeDecodeError: + continue + for line in lines: + if 'Copyright (C) ' in line: + parts = line.split ('Copyright (C)')[1].strip() #split out the copyright header + partition = parts.partition(' ')[2] # remove the year string + copyrights += ["%s" % partition] + copyrights = "\n\t ".join(sorted(set(copyrights))) + with open(copyright_in, 'r') as rfd: + lines = rfd.readlines() + + with open(copyright_out, 'w') as wfd: + for line in lines: + if line.startswith("%%%DYNAMIC%%%"): + wfd.write("Files: *\n") + wfd.write("Copyright: %s\n" % copyrights) + wfd.write("License: LGPL-2.1+\n") + wfd.write("\n") + else: + wfd.write(line) + +directory = os.path.join (os.getcwd(), 'debian') +update_debian_control(directory) +update_debian_copyright(directory) diff -Nru fwupd-1.0.6/contrib/ci/generate_docker.py fwupd-1.2.10/contrib/ci/generate_docker.py --- fwupd-1.0.6/contrib/ci/generate_docker.py 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/generate_docker.py 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,8 @@ #!/usr/bin/python3 # -# Copyright (C) 2017-2018 Dell Inc. +# Copyright (C) 2017-2018 Dell, Inc. # -# Licensed under the GNU General Public License Version 2 -# -# 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 2 of the License, 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. +# SPDX-License-Identifier: LGPL-2.1+ # import os import subprocess @@ -79,14 +65,16 @@ with open(out.name, 'w') as wfd: for line in lines: if line.startswith("FROM %%%ARCH_PREFIX%%%"): - if OS == "debian" and SUBOS == "i386": + if (OS == "debian" or OS == "ubuntu") and SUBOS == "i386": replace = SUBOS + "/" else: replace = '' wfd.write(line.replace("%%%ARCH_PREFIX%%%", replace)) elif line == "%%%INSTALL_DEPENDENCIES_COMMAND%%%\n": - if OS == "fedora": + if OS == "fedora" or OS == 'flatpak': wfd.write("RUN dnf --enablerepo=updates-testing -y install \\\n") + elif OS == "centos": + wfd.write("RUN yum -y install \\\n") elif OS == "debian" or OS == "ubuntu": wfd.write("RUN apt update -qq && \\\n") wfd.write("\tapt install -yq --no-install-recommends\\\n") @@ -108,4 +96,10 @@ else: wfd.write(line) wfd.flush() - subprocess.check_call(["docker", "build", "-t", "fwupd-%s" % TARGET, "-f", "./%s" % os.path.basename(out.name), "."]) + args = ["docker", "build", "-t", "fwupd-%s" % TARGET] + if 'http_proxy' in os.environ: + args += ['--build-arg=http_proxy=%s' % os.environ['http_proxy']] + if 'https_proxy' in os.environ: + args += ['--build-arg=https_proxy=%s' % os.environ['https_proxy']] + args += [ "-f", "./%s" % os.path.basename(out.name), "."] + subprocess.check_call(args) diff -Nru fwupd-1.0.6/contrib/ci/README.md fwupd-1.2.10/contrib/ci/README.md --- fwupd-1.0.6/contrib/ci/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -9,11 +9,12 @@ ------ * A fully packaged RPM build with all plugins enabled -* Compiled under gcc +* Compiled under gcc with AddressSanitizer * Tests with -Werror enabled * Tests with the built in local test suite for all plugins. * All packages are installed * An installed testing run with the "test" plugin and pulling from LVFS. +* With modem manager disabled Debian testing (x86_64) ------ @@ -52,9 +53,12 @@ ------ * Not packaged +* Tests for missing translation files +* No redfish support * Compiled under gcc * Tests with -Werror enabled * Runs local test suite using qemu-user +* Modem manager disabled Arch Linux (x86_64) ---------- @@ -66,6 +70,14 @@ * Tests with the built in local test suite for all plugins. * All packages are installed +Flatpak +---------- +* A flatpak bundle with all plugins enabled +* Compiled under gcc with the org.gnome.Sdk/x86_64/3.28 runtime +* Builds without the daemon, so only fwupdtool is available +* No GPG, PKCS-7, GObjectIntrospection, systemd or ConsoleKit support +* No tests + Adding a new target =================== Dockerfiles are generated dynamically by the python script ```generate_dockerfile.py```. @@ -78,7 +90,7 @@ The child elements represent individual dependencies for all distributions. * This element has an attribute ***id*** that represents the most common package name used by distributions -* This element has an attribute ***type*** that reprsents if the package is needed at build time or runtime. +* This element has an attribute ***type*** that represents if the package is needed at build time or runtime. Each dependency then has a mapping to individual distributions (___distro___). * This element has an attribute ***id*** that represents the distribution. diff -Nru fwupd-1.0.6/contrib/ci/snapcraft-wrapper fwupd-1.2.10/contrib/ci/snapcraft-wrapper --- fwupd-1.0.6/contrib/ci/snapcraft-wrapper 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/snapcraft-wrapper 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,12 @@ +#!/bin/sh +SNAP="/snap/snapcraft/current" +SNAP_NAME="$(awk '/^name:/{print $2}' $SNAP/meta/snap.yaml)" +SNAP_VERSION="$(awk '/^version:/{print $2}' $SNAP/meta/snap.yaml)" +SNAP_ARCH="amd64" + +export SNAP +export SNAP_NAME +export SNAP_VERSION +export SNAP_ARCH + +exec "$SNAP/usr/bin/python3" "$SNAP/bin/snapcraft" "$@" diff -Nru fwupd-1.0.6/contrib/ci/snap.sh fwupd-1.2.10/contrib/ci/snap.sh --- fwupd-1.0.6/contrib/ci/snap.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/snap.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,4 @@ +#!/bin/sh + +cd /build +snapcraft diff -Nru fwupd-1.0.6/contrib/ci/ubuntu.sh fwupd-1.2.10/contrib/ci/ubuntu.sh --- fwupd-1.0.6/contrib/ci/ubuntu.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/ci/ubuntu.sh 2019-07-15 18:25:54.000000000 +0000 @@ -1,69 +1,15 @@ -#!/bin/bash +#!/bin/sh set -e set -x -#although it's debian, we don't build packages -if [ "$OS" = "debian-s390x" ]; then - ./contrib/ci/debian_s390x.sh - exit 0 -fi - -#prepare -export DEBFULLNAME="CI Builder" -export DEBEMAIL="ci@travis-ci.org" -VERSION=`git describe | sed 's/-/+r/;s/-/+/'` -[ -z $VERSION ] && VERSION=`head meson.build | grep ' version :' | cut -d \' -f2` -rm -rf build/ -mkdir -p build -shopt -s extglob -cp -lR !(build|dist) build/ -pushd build -mv contrib/debian . -sed s/quilt/native/ debian/source/format -i -#generate control file -./contrib/ci/generate_debian_control.py debian/control.in debian/control -#build the package -EDITOR=/bin/true dch --create --package fwupd -v $VERSION "CI Build" -debuild --no-lintian --preserve-envvar CI --preserve-envvar CC - -#check lintian output -#suppress tags that are side effects of building in docker this way -lintian ../*changes \ - -IE \ - --pedantic \ - --no-tag-display-limit \ - --suppress-tags bad-distribution-in-changes-file \ - --suppress-tags source-contains-unsafe-symlink \ - --suppress-tags changelog-should-mention-nmu \ - --suppress-tags debian-watch-file-in-native-package \ - --suppress-tags source-nmu-has-incorrect-version-number \ - --suppress-tags no-symbols-control-file \ - --allow-root - -#if invoked outside of CI -if [ ! -f /.dockerenv ]; then - echo "Not running in a container, please manually install packages" - exit 0 -fi - -#test the packages install -PACKAGES=$(ls ../*.deb | grep -v 'fwupd-tests\|dbgsym') -dpkg -i $PACKAGES - -# run the installed tests -if [ "$CI" = "true" ]; then - dpkg -i ../fwupd-tests*.deb - service dbus restart - gnome-desktop-testing-runner fwupd - apt purge -y fwupd-tests -fi - -#test the packages remove -apt purge -y fwupd \ - fwupd-doc \ - libfwupd2 \ - libfwupd-dev - -#place built packages in dist outside docker -mkdir -p ../dist -cp $PACKAGES ../dist +#evaluate using Ubuntu's buildflags +eval "$(dpkg-buildflags --export=sh)" +#filter out -Bsymbolic-functions +export LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//") + +rm -rf build +meson build --werror +#build with clang and -Werror +ninja -C build test -v +#run static analysis (these mostly won't be critical) +ninja -C build scan-build -v diff -Nru fwupd-1.0.6/contrib/debian/compat fwupd-1.2.10/contrib/debian/compat --- fwupd-1.0.6/contrib/debian/compat 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/compat 2019-07-15 18:25:54.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru fwupd-1.0.6/contrib/debian/control.in fwupd-1.2.10/contrib/debian/control.in --- fwupd-1.0.6/contrib/debian/control.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/control.in 2019-07-15 18:25:54.000000000 +0000 @@ -6,7 +6,7 @@ Matthias Klumpp , Mario Limonciello Build-Depends: %%%DYNAMIC%%% -Standards-Version: 4.1.3 +Standards-Version: 4.3.0 Section: admin Homepage: https://github.com/hughsie/fwupd Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git @@ -22,8 +22,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -31,9 +30,13 @@ Package: fwupd Architecture: linux-any Depends: ${misc:Depends}, - ${shlibs:Depends} -Recommends: fwupdate, - python3 + ${shlibs:Depends}, + shared-mime-info +Recommends: python3, + bolt, + tpm2-tools, + tpm2-abrmd, + fwupd-signed Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), libdfu-dev (<< 0.9.7-1) @@ -45,8 +48,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -68,8 +70,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -84,8 +85,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -104,8 +104,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd @@ -121,3 +120,31 @@ . It can be used by packages using the GIRepository format to generate dynamic bindings. + +Package: fwupd-amd64-signed-template +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-i386-signed-template +Architecture: i386 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-armhf-signed-template +Architecture: armhf +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-arm64-signed-template +Architecture: arm64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. diff -Nru fwupd-1.0.6/contrib/debian/copyright fwupd-1.2.10/contrib/debian/copyright --- fwupd-1.0.6/contrib/debian/copyright 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/copyright 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: fwupd -Source: https://github.com/hughsie/fwupd - -Files: * -Copyright: 2015 Richard Hughes -License: GPL-2.0+ - -Files: libfwupd/* -Copyright: 2015 Richard Hughes -License: LGPL-2.1+ - -Files: data/tests/colorhug/firmware.metainfo.xml -Copyright: 2015 Richard Hughes -License: CC0-1.0 - -Files: debian/* -Copyright: 2015 Daniel Jared Dominguez - 2015 Mario Limonciello -License: GPL-2.0+ - -License: GPL-2.0+ - This package 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 2 of the License, or - (at your option) any later version. - . - This package 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, see - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". - -License: LGPL-2.1+ - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - . - This package 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 Lesser General Public License - along with this program. If not, see - . - On Debian systems, the complete text of the GNU Lesser General - Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". - - -License: CC0-1.0 - Creative Commons CC0 1.0 Universal - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL - SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT - RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. - CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE - INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES - RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - . - Statement of Purpose - . - The laws of most jurisdictions throughout the world automatically confer - exclusive Copyright and Related Rights (defined below) upon the creator and - subsequent owner(s) (each and all, an "owner") of an original work of - authorship and/or a database (each, a "Work"). Certain owners wish to - permanently relinquish those rights to a Work for the purpose of contributing - to a commons of creative, cultural and scientific works ("Commons") that the - public can reliably and without fear of later claims of infringement build - upon, modify, incorporate in other works, reuse and redistribute as freely as - possible in any form whatsoever and for any purposes, including without - limitation commercial purposes. These owners may contribute to the Commons to - promote the ideal of a free culture and the further production of creative, - cultural and scientific works, or to gain reputation or greater distribution - for their Work in part through the use and efforts of others. For these and/or - other purposes and motivations, and without any expectation of additional - consideration or compensation, the person associating CC0 with a Work (the - "Affirmer"), to the extent that he or she is an owner of Copyright and Related - Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly - distribute the Work under its terms, with knowledge of his or her Copyright and - Related Rights in the Work and the meaning and intended legal effect of CC0 on - those rights. - . - 1. Copyright and Related Rights. A Work made available under CC0 may be - protected by copyright and related or neighboring rights ("Copyright and - Related Rights"). Copyright and Related Rights include, but are not limited to, - the following: - i. the right to reproduce, adapt, distribute, perform, display, communicate, - and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); - iii. publicity and privacy rights pertaining to a person's image or likeness - depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, subject - to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data in a - Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal protection - of databases, and under any national implementation thereof, including any - amended or successor version of such directive); and - vii. other similar, equivalent or corresponding rights throughout the world - based on applicable law or treaty, and any national implementations thereof. - . - 2. Waiver. To the greatest extent permitted by, but not in contravention of, - applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and - unconditionally waives, abandons, and surrenders all of Affirmer's Copyright - and Related Rights and associated claims and causes of action, whether now - known or unknown (including existing as well as future claims and causes of - action), in the Work (i) in all territories worldwide, (ii) for the maximum - duration provided by applicable law or treaty (including future time - extensions), (iii) in any current or future medium and for any number of - copies, and (iv) for any purpose whatsoever, including without limitation - commercial, advertising or promotional purposes (the "Waiver"). - Affirmer makes the Waiver for the benefit of each member of the public at large - and to the detriment of Affirmer's heirs and successors, fully intending that - such Waiver shall not be subject to revocation, rescission, cancellation, - termination, or any other legal or equitable action to disrupt the quiet - enjoyment of the Work by the public as contemplated by Affirmer's express - Statement of Purpose. - . - 3. Public License Fallback. Should any part of the Waiver for any reason be - judged legally invalid or ineffective under applicable law, then the Waiver - shall be preserved to the maximum extent permitted taking into account - Affirmer's express Statement of Purpose. In addition, to the extent the Waiver - is so judged Affirmer hereby grants to each affected person a royalty-free, non - transferable, non sublicensable, non exclusive, irrevocable and unconditional - license to exercise Affirmer's Copyright and Related Rights in the Work (i) in - all territories worldwide, (ii) for the maximum duration provided by - applicable law or treaty (including future time extensions), (iii) in any - current or future medium and for any number of copies, and (iv) for any - purpose whatsoever, including without limitation commercial, advertising or - promotional purposes (the "License"). The License shall be deemed effective - as of the date CC0 was applied by Affirmer to the Work. Should any part of - the License for any reason be judged legally invalid or ineffective under - applicable law, such partial invalidity or ineffectiveness shall not - invalidate the remainder of the License, and in such case Affirmer hereby - affirms that he or she will not (i) exercise any of his or her remaining - Copyright and Related Rights in the Work or (ii) assert any associated claims - and causes of action with respect to the Work, in either case contrary to - Affirmer's express Statement of Purpose. - . - 4. Limitations and Disclaimers. - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or warranties of - any kind concerning the Work, express, implied, statutory or otherwise, - including without limitation warranties of title, merchantability, fitness for - a particular purpose, non infringement, or the absence of latent or other - defects, accuracy, or the present or absence of errors, whether or not - discoverable, all to the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons that - may apply to the Work or any use thereof, including without limitation any - person's Copyright and Related Rights in the Work. Further, Affirmer disclaims - responsibility for obtaining any necessary consents, permissions or other - rights required for any use of the Work. - d. Affirmer understands and acknowledges that Creative Commons is not a party - to this document and has no duty or obligation with respect to this CC0 or use - of the Work. diff -Nru fwupd-1.0.6/contrib/debian/copyright.in fwupd-1.2.10/contrib/debian/copyright.in --- fwupd-1.0.6/contrib/debian/copyright.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/copyright.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,140 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fwupd +Source: https://github.com/hughsie/fwupd + +%%%DYNAMIC%%% +Files: *.metainfo.xml +Copyright: Richard Hughes +License: CC0-1.0 + +Files: debian/* +Copyright: 2015 Daniel Jared Dominguez + 2015-2018 Mario Limonciello +License: LGPL-2.1+ + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + . + This package 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 Lesser General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". + + +License: CC0-1.0 + Creative Commons CC0 1.0 Universal + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL + SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT + RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. + CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE + INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES + RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + . + Statement of Purpose + . + The laws of most jurisdictions throughout the world automatically confer + exclusive Copyright and Related Rights (defined below) upon the creator and + subsequent owner(s) (each and all, an "owner") of an original work of + authorship and/or a database (each, a "Work"). Certain owners wish to + permanently relinquish those rights to a Work for the purpose of contributing + to a commons of creative, cultural and scientific works ("Commons") that the + public can reliably and without fear of later claims of infringement build + upon, modify, incorporate in other works, reuse and redistribute as freely as + possible in any form whatsoever and for any purposes, including without + limitation commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of creative, + cultural and scientific works, or to gain reputation or greater distribution + for their Work in part through the use and efforts of others. For these and/or + other purposes and motivations, and without any expectation of additional + consideration or compensation, the person associating CC0 with a Work (the + "Affirmer"), to the extent that he or she is an owner of Copyright and Related + Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly + distribute the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect of CC0 on + those rights. + . + 1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited to, + the following: + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, subject + to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data in a + Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal protection + of databases, and under any national implementation thereof, including any + amended or successor version of such directive); and + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + . + 2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). + Affirmer makes the Waiver for the benefit of each member of the public at large + and to the detriment of Affirmer's heirs and successors, fully intending that + such Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express + Statement of Purpose. + . + 3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express Statement of Purpose. In addition, to the extent the Waiver + is so judged Affirmer hereby grants to each affected person a royalty-free, non + transferable, non sublicensable, non exclusive, irrevocable and unconditional + license to exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in any + current or future medium and for any number of copies, and (iv) for any + purpose whatsoever, including without limitation commercial, advertising or + promotional purposes (the "License"). The License shall be deemed effective + as of the date CC0 was applied by Affirmer to the Work. Should any part of + the License for any reason be judged legally invalid or ineffective under + applicable law, such partial invalidity or ineffectiveness shall not + invalidate the remainder of the License, and in such case Affirmer hereby + affirms that he or she will not (i) exercise any of his or her remaining + Copyright and Related Rights in the Work or (ii) assert any associated claims + and causes of action with respect to the Work, in either case contrary to + Affirmer's express Statement of Purpose. + . + 4. Limitations and Disclaimers. + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or warranties of + any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness for + a particular purpose, non infringement, or the absence of latent or other + defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons that + may apply to the Work or any use thereof, including without limitation any + person's Copyright and Related Rights in the Work. Further, Affirmer disclaims + responsibility for obtaining any necessary consents, permissions or other + rights required for any use of the Work. + d. Affirmer understands and acknowledges that Creative Commons is not a party + to this document and has no duty or obligation with respect to this CC0 or use + of the Work. diff -Nru fwupd-1.0.6/contrib/debian/docs fwupd-1.2.10/contrib/debian/docs --- fwupd-1.0.6/contrib/debian/docs 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/docs 2019-07-15 18:25:54.000000000 +0000 @@ -1 +1 @@ -NEWS + diff -Nru fwupd-1.0.6/contrib/debian/fwupd.install fwupd-1.2.10/contrib/debian/fwupd.install --- fwupd-1.0.6/contrib/debian/fwupd.install 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/fwupd.install 2019-07-15 18:25:54.000000000 +0000 @@ -4,12 +4,17 @@ usr/share/bash-completion usr/share/fwupd/* usr/share/dbus-1/* +usr/share/icons/* usr/share/polkit-1/* usr/share/locale usr/share/metainfo/* usr/lib/*/fwupd +usr/lib/*/fwupdagent +usr/lib/*/fwupdoffline +usr/lib/*/fwupdtool usr/share/man/man1/* lib/systemd/system/* +lib/systemd/system-shutdown/* var/lib/fwupd lib/udev/rules.d/* data/daemon.conf etc/fwupd diff -Nru fwupd-1.0.6/contrib/debian/fwupd.postinst fwupd-1.2.10/contrib/debian/fwupd.postinst --- fwupd-1.0.6/contrib/debian/fwupd.postinst 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/fwupd.postinst 2019-07-15 18:25:54.000000000 +0000 @@ -6,4 +6,6 @@ if dpkg-maintscript-helper supports rm_conffile 2>/dev/null; then dpkg-maintscript-helper rm_conffile \ /etc/fwupd.conf 1.0.0~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" fi diff -Nru fwupd-1.0.6/contrib/debian/fwupd-tests.install fwupd-1.2.10/contrib/debian/fwupd-tests.install --- fwupd-1.0.6/contrib/debian/fwupd-tests.install 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/fwupd-tests.install 2019-07-15 18:25:54.000000000 +0000 @@ -4,3 +4,5 @@ #https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872458 usr/share/installed-tests/* usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so +debian/lintian/fwupd-tests usr/share/lintian/overrides +etc/fwupd/remotes.d/fwupd-tests.conf diff -Nru fwupd-1.0.6/contrib/debian/fwupd-tests.postinst fwupd-1.2.10/contrib/debian/fwupd-tests.postinst --- fwupd-1.0.6/contrib/debian/fwupd-tests.postinst 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/fwupd-tests.postinst 2019-07-15 18:25:54.000000000 +0000 @@ -12,4 +12,12 @@ echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi fi + if [ -f /etc/fwupd/remotes.d/fwupd-tests.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + else + echo "To enable test suite, enable fwupd-tests remote" + fi + + fi fi diff -Nru fwupd-1.0.6/contrib/debian/gen_signing_changelog fwupd-1.2.10/contrib/debian/gen_signing_changelog --- fwupd-1.0.6/contrib/debian/gen_signing_changelog 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/gen_signing_changelog 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Generate a changelog file for the signed fwupdate package, based on +# a changelog.in file and other state + +DIR=$1 +SOURCE=$2 +ARCH=$3 +IN="${DIR}/changelog.in" +OUT="${DIR}/changelog" + +# Parse out fields from our changelg entry - want the signing-template +# one to match all the important details where we can +DISTRIBUTION="$(dpkg-parsechangelog | sed -ne 's/^Distribution: \(.*\)/\1/p')" +URGENCY="$(dpkg-parsechangelog | sed -ne 's/^Urgency: \(.*\)/\1/p')" +MAINT="$(dpkg-parsechangelog | sed -ne 's/^Maintainer: \(.*\)/\1/p')" +DATE="$(dpkg-parsechangelog | sed -ne 's/^Date: \(.*\)/\1/p')" + +# If the version ends in "+bXXX", this is a binNMU. We don't want a new +# source package to look like that, so change it to ".bXXX" instead +VERSION="$(dpkg-parsechangelog | sed -ne 's/^Version: \(.*\)/\1/p')" +MANGLED_VERSION="$(echo $VERSION | sed -r 's/-/\+/;s/\+(b[[:digit:]]+)$/.\1/')" + +printf "%s-%s-signed (%s) %s; urgency=%s\n" "${SOURCE}" "${ARCH}" "${MANGLED_VERSION}" "${DISTRIBUTION}" "${URGENCY}" > $OUT +printf "\n" >> $OUT +printf " * Update to %s version %s\n" "${SOURCE}" "${VERSION}" >> $OUT +printf "\n" >> $OUT +printf " -- %s %s\n" "${MAINT}" "${DATE}" >> $OUT +printf "\n" >> $OUT + +cat $IN >> $OUT +rm -f $IN diff -Nru fwupd-1.0.6/contrib/debian/gen_signing_json fwupd-1.2.10/contrib/debian/gen_signing_json --- fwupd-1.0.6/contrib/debian/gen_signing_json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/gen_signing_json 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Generate a json file to go in the the fwupd-signed template +# package. Describes exactly what needs to be signed, and how. + +DIR=$1 +SOURCE=$2 +ARCH=$3 +OUT="$DIR/files.json" + +# What file are we looking to sign? +BINARY=$(find debian/tmp -name '*.efi' | xargs basename) + +# Actually needs full path within the binary deb +BINARY="usr/lib/${SOURCE}/efi/${BINARY}" + +rm -f $OUT + +printf '{\n' >> $OUT +printf ' "packages": {\n' >> $OUT +printf ' "%s": {\n' "${SOURCE}" >> $OUT +printf ' "trusted_certs": [],\n' >> $OUT +printf ' "files": [ \n' >> $OUT +printf ' {"sig_type": "efi", "file": "%s"}\n' "${BINARY}" >> $OUT +printf ' ]\n' >> $OUT +printf ' }\n' >> $OUT +printf ' }\n' >> $OUT +printf '}\n' >> $OUT + diff -Nru fwupd-1.0.6/contrib/debian/gir1.2-fwupd-2.0.install fwupd-1.2.10/contrib/debian/gir1.2-fwupd-2.0.install --- fwupd-1.0.6/contrib/debian/gir1.2-fwupd-2.0.install 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/gir1.2-fwupd-2.0.install 2019-07-15 18:25:54.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/girepository-1.0/Fwupd-2.0.typelib +usr/lib/*/girepository-1.0/*.typelib diff -Nru fwupd-1.0.6/contrib/debian/libfwupd2.install fwupd-1.2.10/contrib/debian/libfwupd2.install --- fwupd-1.0.6/contrib/debian/libfwupd2.install 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/libfwupd2.install 2019-07-15 18:25:54.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/libfwup*.so.* +usr/lib/*/*.so.* diff -Nru fwupd-1.0.6/contrib/debian/libfwupd-dev.install fwupd-1.2.10/contrib/debian/libfwupd-dev.install --- fwupd-1.0.6/contrib/debian/libfwupd-dev.install 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/libfwupd-dev.install 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,5 @@ -usr/include/fwupd-1/fwupd.h -usr/include/fwupd-1/libfwupd -usr/lib/*/libfwupd*.so -usr/lib/*/pkgconfig/fwupd.pc -usr/share/gir-1.0/Fwupd*.gir +usr/include/* +usr/lib/*/*.so +usr/lib/*/pkgconfig/*.pc +usr/share/gir-1.0/*.gir usr/share/vala/vapi diff -Nru fwupd-1.0.6/contrib/debian/lintian/fwupd fwupd-1.2.10/contrib/debian/lintian/fwupd --- fwupd-1.0.6/contrib/debian/lintian/fwupd 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/lintian/fwupd 2019-07-15 18:25:54.000000000 +0000 @@ -2,5 +2,9 @@ fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/fwupd-offline-update.service fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/fwupd.service fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/system-update.target.wants/fwupd-offline-update.service -#CAs is the right word, not Case -fwupd binary: spelling-error-in-binary usr/lib/fwupd/fwupd CAs Case +#see debian bug 896012 +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_upower.so +#EFI applications are PE executables +fwupd: executable-not-elf-or-script usr/lib/fwupd/efi/*.efi +fwupd: portable-executable-missing-security-features usr/lib/fwupd/efi/*.efi ASLR DEP/NX +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so diff -Nru fwupd-1.0.6/contrib/debian/lintian/fwupd-tests fwupd-1.2.10/contrib/debian/lintian/fwupd-tests --- fwupd-1.0.6/contrib/debian/lintian/fwupd-tests 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/lintian/fwupd-tests 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +#see debian bug 896012 +fwupd-tests: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so diff -Nru fwupd-1.0.6/contrib/debian/README.Debian fwupd-1.2.10/contrib/debian/README.Debian --- fwupd-1.0.6/contrib/debian/README.Debian 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/README.Debian 2019-07-15 18:25:54.000000000 +0000 @@ -1,7 +1,18 @@ -fwupd for Debian ----------------- +signed vs unsigned fwupd programs +------------------------------------ -fwupd is still heavily in development. As of this date, the functionality -it provides is not yet available on most systems. +fwupd 1.1.0 is configured to understand when to use a signed version +of the EFI binary. If the signed version isn't installed but secure +boot is turned on, it will avoid copying to the EFI system partition. + +This allows supporting secure boot even if not turned on at install, or +changed later after install. + +In Ubuntu, both fwupd-signed and fwupd are seeded in the default +installation. Nothing is installed to the ESP until it's needed. + +In Debian, the package name for the signed version is slightly +different due to different infrastructure. fwupd-signed-$ARCH and +fwupd should both be installed and then things will work similarly +to what's described above. - -- Daniel Jared Dominguez Wed, 20 May 2015 17:16:02 -0500 diff -Nru fwupd-1.0.6/contrib/debian/rules fwupd-1.2.10/contrib/debian/rules --- fwupd-1.0.6/contrib/debian/rules 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/rules 2019-07-15 18:25:54.000000000 +0000 @@ -3,6 +3,7 @@ export LC_ALL := C.UTF-8 export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_STRIP=-Wl,-Bsymbolic-functions #GPGME needs this for proper building on 32 bit archs ifeq "$(DEB_HOST_ARCH_BITS)" "32" @@ -10,36 +11,80 @@ endif ifneq ($(CI),) - export CI=--werror + export CI=--werror --wrap-mode=default +endif + +SB_STYLE := debian +deb_version := $(shell dpkg-parsechangelog --show-field Version) +ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) + SB_STYLE := ubuntu + tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz +else + TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template endif %: - dh $@ --with gir,systemd + dh $@ --with gir override_dh_auto_clean: rm -fr debian/build +ifeq (ubuntu,$(SB_STYLE)) + rm -rf debian/fwupd-images +endif override_dh_auto_configure: - if pkg-config --exists fwup; then \ - export UEFI="-Dplugin_uefi=true"; \ + if pkg-config --exists libsmbios_c; then \ + export DELL="-Dplugin_dell=true"; \ else \ - export UEFI="-Dplugin_uefi=false"; \ + export DELL="-Dplugin_dell=false"; \ fi; \ - if pkg-config --exists libsmbios_c; then \ - export DELL="-Dplugin_dell=true -Dplugin_synaptics=true"; \ + if pkg-config --exists efivar; then \ + export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true"; \ + else \ + export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false"; \ + fi; \ + if [ ! -z "$$CI" ]; then \ + export FLASHROM="-Dplugin_flashrom=true"; \ else \ - export DELL="-Dplugin_dell=false -Dplugin_synaptics=false"; \ + export FLASHROM="-Dplugin_flashrom=false"; \ fi; \ - dh_auto_configure -- $$UEFI $$DELL $$CI -Dplugin_dummy=true --libexecdir=/usr/lib + dh_auto_configure -- $$UEFI $$DELL $$FLASHROM $$CI -Dplugin_dummy=true --libexecdir=/usr/lib override_dh_install: find debian/tmp/usr -type f -name "*a" -print | xargs rm -f sed -i 's,wheel,sudo,' ./debian/tmp/usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules dh_install - dh_missing --fail-missing + #install the EFI binaries if needed + if [ -d debian/tmp/usr/lib/fwupd/efi/ ]; then \ + dh_install -pfwupd usr/lib/fwupd/efi ;\ + dh_install -pfwupd usr/lib/fwupd/fwupdate; \ + fi + #if build with meson subproject in CI need to install this too + if [ ! -z "$$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ + dh_install -pfwupd usr/lib/xb-tool ;\ + fi + if [ ! -z "$$CI" ] && [ -f debian/tmp/usr/sbin/flashrom ]; then \ + dh_install -pfwupd usr/sbin/flashrom ;\ + fi + dh_missing -a --fail-missing #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf + +ifeq (debian,$(SB_STYLE)) + # Generate the template source for the Debian signing service to use + mkdir -p $(TMPLDIR)/source-template/debian + cp -a debian/signing-template/* $(TMPLDIR)/source-template/debian + cp debian/README.Debian $(TMPLDIR)/source-template/debian + find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNARCH,$(DEB_HOST_ARCH)," + find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNVERSION,$(deb_version)," + for file in $$(find $(TMPLDIR)/source-template/debian -type f -name *SIGNARCH*); do file1=$$(echo $$file | sed "s,SIGNARCH,$(DEB_HOST_ARCH),"); mv -v $$file $$file1; done + install -m 0755 debian/fwupd.postinst $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postinst + install -m 0755 debian/fwupd.postrm $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postrm + ./debian/gen_signing_changelog $(TMPLDIR)/source-template/debian fwupd $(DEB_HOST_ARCH) + ./debian/gen_signing_json $(TMPLDIR) fwupd ${DEB_HOST_ARCH} +endif override_dh_strip_nondeterminism: dh_strip_nondeterminism -Xfirmware-example.xml.gz @@ -48,3 +93,18 @@ if [ -x /usr/bin/valgrind ] ; then \ dh_auto_test; \ fi + +override_dh_builddeb: + dh_builddeb +ifeq (ubuntu,$(SB_STYLE)) + if [ -d debian/tmp/usr/lib/fwupd/efi/ ]; then \ + mkdir -p debian/fwupd-images/$(deb_version) ;\ + cp debian/tmp/usr/lib/fwupd/efi/fwupd*.efi debian/fwupd-images/$(deb_version) ;\ + echo $(deb_version) > debian/fwupd-images/$(deb_version)/version ;\ + tar -C debian/fwupd-images -czvf ../$(tar_name) . ;\ + dpkg-distaddfile $(tar_name) raw-uefi - ;\ + fi +endif + +override_dh_shlibdeps: + dh_shlibdeps $$DHSLIBS diff -Nru fwupd-1.0.6/contrib/debian/signing-template/changelog.in fwupd-1.2.10/contrib/debian/signing-template/changelog.in --- fwupd-1.0.6/contrib/debian/signing-template/changelog.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/changelog.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,5 @@ +fwupd-SIGNARCH-signed (1) unstable; urgency=medium + + * Add template source package for signing + + -- Steve McIntyre <93sam@debian.org> Sat, 07 Apr 2018 12:44:55 +0100 diff -Nru fwupd-1.0.6/contrib/debian/signing-template/compat fwupd-1.2.10/contrib/debian/signing-template/compat --- fwupd-1.0.6/contrib/debian/signing-template/compat 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/compat 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +9 diff -Nru fwupd-1.0.6/contrib/debian/signing-template/control fwupd-1.2.10/contrib/debian/signing-template/control --- fwupd-1.0.6/contrib/debian/signing-template/control 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/control 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,24 @@ +Source: fwupd-SIGNARCH-signed +Priority: optional +Maintainer: Debian EFI +Uploaders: Daniel Jared Dominguez , Steve McIntyre <93sam@debian.org>, Mario Limonciello +Build-Depends: debhelper (>= 9.0.0), sbsigntool [amd64 arm64 armhf i386], fwupd (= SIGNVERSION) [SIGNARCH] +Standards-Version: 4.1.3 +Section: libs +Homepage: https://github.com/hughsie/fwupd +Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git +Vcs-Browser: https://salsa.debian.org/efi-team/fwupd + +Package: fwupd-SIGNARCH-signed +Section: admin +Architecture: SIGNARCH +Provides: fwupd-signed +Depends: ${shlibs:Depends}, ${misc:Depends}, fwupd (= SIGNVERSION) +Description: Tools to manage UEFI firmware updates (signed) + fwupd provides functionality to update system firmware. It has been + initially designed to update firmware using UEFI capsule updates, but + it is designed to be extensible to other firmware update standards. + . + This package contains just the signed version of the fwupd binary, + needed if your system has UEFI Secure Boot enabled. It depends on the + normal fwupd package for everything else. diff -Nru fwupd-1.0.6/contrib/debian/signing-template/copyright fwupd-1.2.10/contrib/debian/signing-template/copyright --- fwupd-1.0.6/contrib/debian/signing-template/copyright 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/copyright 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,33 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fwupd +Source: https://github.com/hughsie/fwupd + +Files: * +Copyright: 2015 Richard Hughes +License: LGPL-2.1+ + +Files: data/tests/colorhug/firmware.metainfo.xml +Copyright: 2015 Richard Hughes +License: CC0-1.0 + +Files: debian/* +Copyright: 2015 Daniel Jared Dominguez + 2015 Mario Limonciello +License: LGPL-2.1+ + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + . + This package 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 Lesser General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". diff -Nru fwupd-1.0.6/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install fwupd-1.2.10/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install --- fwupd-1.0.6/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/fwupd-SIGNARCH-signed.install 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +*.efi.signed /usr/lib/fwupd/efi diff -Nru fwupd-1.0.6/contrib/debian/signing-template/README.source fwupd-1.2.10/contrib/debian/signing-template/README.source --- fwupd-1.0.6/contrib/debian/signing-template/README.source 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/README.source 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,4 @@ +This source package is generated by the Debian signing service from a +template built by the fwupd package. It should never be updated directly. + + -- Steve McIntyre <93sam@debian.org> Sat, 07 Apr 2018 12:44:55 +0100 diff -Nru fwupd-1.0.6/contrib/debian/signing-template/rules fwupd-1.2.10/contrib/debian/signing-template/rules --- fwupd-1.0.6/contrib/debian/signing-template/rules 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/rules 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,15 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +PACKAGE_NAME := fwupd +SIG_PKG_NAME := fwupd-SIGNARCH-signed +SIGNATURE_DIR := debian/signatures/$(PACKAGE_NAME) +BINARY := $(shell find /usr/lib/fwupd/efi -name '*.efi' | xargs basename) + +%: + dh $@ + +override_dh_auto_build: + cp /usr/lib/fwupd/efi/$(BINARY) . + sbattach --attach $(SIGNATURE_DIR)/usr/lib/fwupd/efi/$(BINARY).sig $(BINARY) + mv $(BINARY) $(BINARY).signed diff -Nru fwupd-1.0.6/contrib/debian/signing-template/source/format fwupd-1.2.10/contrib/debian/signing-template/source/format --- fwupd-1.0.6/contrib/debian/signing-template/source/format 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/signing-template/source/format 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +3.0 (native) diff -Nru fwupd-1.0.6/contrib/debian/source/lintian-overrides fwupd-1.2.10/contrib/debian/source/lintian-overrides --- fwupd-1.0.6/contrib/debian/source/lintian-overrides 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/debian/source/lintian-overrides 2019-07-15 18:25:54.000000000 +0000 @@ -1,2 +1,4 @@ #github doesn't have these -fwupd source: debian-watch-may-check-gpg-signature +fwupd source: debian-watch-does-not-check-gpg-signature +#to make CI happy until libxmlb lands +fwupd source: source-is-missing diff -Nru fwupd-1.0.6/contrib/firmware-packager/firmware-packager fwupd-1.2.10/contrib/firmware-packager/firmware-packager --- fwupd-1.0.6/contrib/firmware-packager/firmware-packager 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/firmware-packager/firmware-packager 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # # Copyright (C) 2017 Max Ehrlich max.ehr@gmail.com # -# Licensed under the GNU General Public License Version 2 -# -# 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 2 of the License, 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. +# SPDX-License-Identifier: LGPL-2.1+ # import argparse @@ -38,14 +24,14 @@ firmware_metainfo_template = """ - {firmware_id} + org.{developer_name}.guid{firmware_id} {firmware_name} {firmware_summary} {firmware_description} - {device_unique_id} + {device_guid} {firmware_homepage} CC0-1.0 @@ -64,7 +50,9 @@ def make_firmware_metainfo(firmware_info, dst): - firmware_metainfo = firmware_metainfo_template.format(**vars(firmware_info), timestamp=time.time()) + local_info = vars(firmware_info) + local_info["firmware_id"] = local_info["device_guid"][0:8] + firmware_metainfo = firmware_metainfo_template.format(**local_info, timestamp=time.time()) with open(os.path.join(dst, 'firmware.metainfo.xml'), 'w') as f: f.write(firmware_metainfo) @@ -82,7 +70,17 @@ def create_firmware_cab(exe, folder): with cd(folder): - command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml'] + if os.name == "nt": + directive = os.path.join (folder, "directive") + with open (directive, 'w') as wfd: + wfd.write('.OPTION EXPLICIT\r\n') + wfd.write('.Set CabinetNameTemplate=firmware.cab\r\n') + wfd.write('.Set DiskDirectory1=.\r\n') + wfd.write('firmware.bin\r\n') + wfd.write('firmware.metainfo.xml\r\n') + command = ['makecab.exe', '/f', directive] + else: + command = ['gcab', '--create', 'firmware.cab', 'firmware.bin', 'firmware.metainfo.xml'] subprocess.check_call(command) @@ -107,18 +105,17 @@ shutil.copy(os.path.join(dir, 'firmware.cab'), args.out) parser = argparse.ArgumentParser(description='Create fwupd packaged from windows executables') -parser.add_argument('--firmware-id', help='ID for the firmware package, can be a customized (e.g. net.queuecumber.DellTBT.firmware)', required=True) parser.add_argument('--firmware-name', help='Name of the firmware package can be customized (e.g. DellTBT)', required=True) parser.add_argument('--firmware-summary', help='One line description of the firmware package') parser.add_argument('--firmware-description', help='Longer description of the firmware package') -parser.add_argument('--device-unique-id', help='Unique ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices`', required=True) +parser.add_argument('--device-guid', help='GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`', required=True) parser.add_argument('--firmware-homepage', help='Website for the firmware provider') parser.add_argument('--contact-info', help='Email address of the firmware developer') -parser.add_argument('--developer-name', help='Name of the firmware developer') +parser.add_argument('--developer-name', help='Name of the firmware developer', required=True) parser.add_argument('--release-version', help='Version number of the firmware package', required=True) parser.add_argument('--release-description', help='Description of the firmware release') -parser.add_argument('--exe', help='Executable file to extract firmware from') -parser.add_argument('--bin', help='Path to the .bin file inside the executable to use as the firmware image', required=True) +parser.add_argument('--exe', help='(optional) Executable file to extract firmware from') +parser.add_argument('--bin', help='Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image', required=True) parser.add_argument('--out', help='Output cab file path', required=True) args = parser.parse_args() diff -Nru fwupd-1.0.6/contrib/firmware-packager/meson.build fwupd-1.2.10/contrib/firmware-packager/meson.build --- fwupd-1.0.6/contrib/firmware-packager/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/firmware-packager/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,2 +1,4 @@ -install_data('firmware-packager', - install_dir : 'share/fwupd') +if get_option('firmware-packager') + install_data('firmware-packager', + install_dir : 'share/fwupd') +endif diff -Nru fwupd-1.0.6/contrib/firmware-packager/README.md fwupd-1.2.10/contrib/firmware-packager/README.md --- fwupd-1.0.6/contrib/firmware-packager/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/firmware-packager/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -26,24 +26,22 @@ ## Documentation -`--firmware-id` ID for the firmware package, can be a customized [fwupd.org](http://fwupd.org/vendors.html) recommends using "a reverse-DNS prefix similar to java" and to "always use a .firmware suffix" (e.g. net.queuecumber.DellTBT.firmware) **REQUIRED** - `--firmware-name` Short name of the firmware package can be customized (e.g. DellTBT) **REQUIRED** `--firmware-summary` One line description of the firmware package (e.g. Dell thunderbolt firmware) `--firmware-description` Longer description of the firmware package. Theoretically this can include HTML but I haven't tried it -`--device-unique-id` Unique ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED** +`--device-guid` GUID ID of the device this firmware will run on, this *must* match the output from `fwupdmgr get-devices` (e.g. 72533768-6a6c-5c06-994a-367374336810) **REQUIRED** `--firmware-homepage` Website for the firmware provider (e.g. http://www.dell.com) `-contact-info` Email address of the firmware developer (e.g. someone@something.net) -`--developer-name` Name of the firmware developer (e.g. John Smith) +`--developer-name` Name of the firmware developer (e.g. Dell) **REQUIRED** `--release-version` Version number of the firmware package (e.g. 4.21.01.002) **REQUIRED** -`--release-description` Description of the firmware release, again this can theoretically include HTML but I didnt try it. +`--release-description` Description of the firmware release, again this can theoretically include HTML but I didn't try it. `--exe` Executable file to extract firmware from (e.g. `dell-thunderbolt-firmware.exe`) **REQUIRED** diff -Nru fwupd-1.0.6/contrib/fix_translations.py fwupd-1.2.10/contrib/fix_translations.py --- fwupd-1.0.6/contrib/fix_translations.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/fix_translations.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ + +import sys +import os +import subprocess + +def _do_msgattrib(fn): + argv = ['msgattrib', + '--no-location', + '--translated', + '--no-wrap', + '--sort-output', + fn, + '--output-file=' + fn] + ret = subprocess.run(argv) + if ret.returncode != 0: + return + +def _do_nukeheader(fn): + clean_lines = [] + with open(fn) as f: + lines = f.readlines() + for line in lines: + if line.startswith('"POT-Creation-Date:'): + continue + if line.startswith('"PO-Revision-Date:'): + continue + if line.startswith('"Last-Translator:'): + continue + clean_lines.append(line) + with open(fn, 'w') as f: + f.writelines(clean_lines) + +def _process_file(fn): + _do_msgattrib(fn) + _do_nukeheader(fn) + +if __name__ == '__main__': + if len(sys.argv) == 1: + print('path required') + sys.exit(1) + try: + dirname = sys.argv[1] + for fn in os.listdir(dirname): + if fn.endswith('.po'): + _process_file(os.path.join(dirname, fn)) + except NotADirectoryError as _: + print('path required') + sys.exit(2) diff -Nru fwupd-1.0.6/contrib/fwupd.spec.in fwupd-1.2.10/contrib/fwupd.spec.in --- fwupd-1.0.6/contrib/fwupd.spec.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/fwupd.spec.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,8 +1,7 @@ %global glib2_version 2.45.8 -%global libappstream_version 0.6.13 +%global libxmlb_version 0.1.3 %global libgusb_version 0.2.11 %global libsoup_version 2.51.92 -%global colord_version 1.2.12 %global systemd_version 231 %global json_glib_version 1.1.1 @@ -11,32 +10,43 @@ %global enable_ci 0 %global enable_tests 1 %global enable_dummy 1 +%global __meson_wrap_mode default -# fwupdate is only available on these arches +# fwupd.efi is only available on these arches %ifarch x86_64 aarch64 %global have_uefi 1 %endif -# libsmbios is only available on x86, and fwupdate is available on just x86_64 +# redfish is only available on this arch +%ifarch x86_64 +%global have_redfish 1 +%endif + +# libsmbios is only available on x86 %ifarch x86_64 %global have_dell 1 %endif +# only available recently +%if 0%{?fedora} >= 30 +%global have_modem_manager 1 +%endif + Summary: Firmware update daemon Name: fwupd Version: #VERSION# Release: 0.#BUILD#%{?alphatag}%{?dist} -License: GPLv2+ +License: LGPLv2+ URL: https://github.com/hughsie/fwupd Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz BuildRequires: gettext BuildRequires: glib2-devel >= %{glib2_version} -BuildRequires: libappstream-glib-devel >= %{libappstream_version} +BuildRequires: libxmlb-devel >= %{libxmlb_version} +BuildRequires: libgcab1-devel BuildRequires: libgudev1-devel BuildRequires: libgusb-devel >= %{libgusb_version} BuildRequires: libsoup-devel >= %{libsoup_version} -BuildRequires: colord-devel >= %{colord_version} BuildRequires: polkit-devel >= 0.103 BuildRequires: sqlite-devel BuildRequires: gpgme-devel @@ -44,53 +54,64 @@ BuildRequires: libarchive-devel BuildRequires: gobject-introspection-devel BuildRequires: gcab +%ifarch %{valgrind_arches} BuildRequires: valgrind BuildRequires: valgrind-devel +%endif BuildRequires: elfutils-libelf-devel BuildRequires: gtk-doc -BuildRequires: libuuid-devel BuildRequires: gnutls-devel BuildRequires: gnutls-utils BuildRequires: meson BuildRequires: help2man BuildRequires: json-glib-devel >= %{json_glib_version} BuildRequires: vala +BuildRequires: bash-completion + +%if 0%{?have_modem_manager} +BuildRequires: ModemManager-glib-devel >= 1.10.0 +BuildRequires: libqmi-devel >= 1.22.0 +%endif + +%if 0%{?have_redfish} +BuildRequires: efivar-devel >= 33 +%endif %if 0%{?have_uefi} +BuildRequires: efivar-devel >= 33 BuildRequires: python3 python3-cairo python3-gobject python3-pillow BuildRequires: pango-devel BuildRequires: cairo-devel cairo-gobject-devel BuildRequires: freetype BuildRequires: fontconfig -BuildRequires: dejavu-sans-fonts -BuildRequires: adobe-source-han-sans-cn-fonts +BuildRequires: google-noto-sans-cjk-ttc-fonts +BuildRequires: gnu-efi-devel +BuildRequires: pesign %endif %if 0%{?have_dell} -BuildRequires: efivar-devel +BuildRequires: efivar-devel >= 33 BuildRequires: libsmbios-devel >= 2.3.0 %endif -%if 0%{?have_uefi} -BuildRequires: fwupdate-devel >= 7 -%endif - Requires(post): systemd Requires(preun): systemd Requires(postun): systemd Requires: glib2%{?_isa} >= %{glib2_version} -Requires: libappstream-glib%{?_isa} >= %{libappstream_version} +Requires: libxmlb%{?_isa} >= %{libxmlb_version} Requires: libgusb%{?_isa} >= %{libgusb_version} Requires: libsoup%{?_isa} >= %{libsoup_version} -Requires: fwupd-labels = %{version}-%{release} Requires: bubblewrap +Requires: shared-mime-info Recommends: python3 +Recommends: tpm2-tools tpm2-abrmd Obsoletes: fwupd-sign < 0.1.6 Obsoletes: libebitdo < 0.7.5-3 -Obsoletes: libdfu < 0.9.8-1 +Obsoletes: libdfu < 1.0.0 +Obsoletes: fwupd-labels < 1.1.0-1 %description fwupd is a daemon to allow session software to update device firmware. @@ -99,20 +120,11 @@ Summary: Development package for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} Obsoletes: libebitdo-devel < 0.7.5-3 -Obsoletes: libdfu-devel < 0.9.8-1 +Obsoletes: libdfu-devel < 1.0.0 %description devel Files for development with %{name}. -%package labels -Summary: Rendered labels for display during system firmware updates. -# BuildArch: noarch is disabled as we can get "different" .BMP files even when -# running the build on the same architecture due to the randomness introduced -# by the TTF files. - -%description labels -Rendered labels for display during system firmware updates. - %package tests Summary: Data files for installed tests BuildArch: noarch @@ -121,7 +133,7 @@ Data files for installed tests. %prep -%setup -q +%autosetup -p1 %build @@ -130,7 +142,6 @@ --werror \ %endif -Dgtkdoc=true \ - -Dman=true \ %if 0%{?enable_tests} -Dtests=true \ %else @@ -141,13 +152,19 @@ %else -Dplugin_dummy=false \ %endif + -Dplugin_flashrom=true \ -Dplugin_thunderbolt=true \ +%if 0%{?have_redfish} + -Dplugin_redfish=true \ +%else + -Dplugin_redfish=false \ +%endif %if 0%{?have_uefi} -Dplugin_uefi=true \ - -Dplugin_uefi_labels=true \ + -Dplugin_nvme=true \ %else -Dplugin_uefi=false \ - -Dplugin_uefi_labels=false \ + -Dplugin_nvme=false \ %endif %if 0%{?have_dell} -Dplugin_dell=true \ @@ -156,7 +173,12 @@ -Dplugin_dell=false \ -Dplugin_synaptics=false \ %endif - -Dplugin_colorhug=true +%if 0%{?have_modem_manager} + -Dplugin_modem_manager=true \ +%else + -Dplugin_modem_manager=false \ +%endif + -Dman=true %meson_build @@ -168,41 +190,79 @@ %install %meson_install +# sign fwupd.efi loader +%if 0%{?have_uefi} +%ifarch x86_64 +%global efiarch x64 +%endif +%ifarch aarch64 +%global efiarch aa64 +%endif +%global fwup_efi_fn $RPM_BUILD_ROOT%{_libexecdir}/fwupd/efi/fwupd%{efiarch}.efi +%pesign -s -i %{fwup_efi_fn} -o %{fwup_efi_fn}.signed +%endif + mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg +# delete most files from the subproject +rm ${RPM_BUILD_ROOT}%{_includedir}/libflashrom.h +rm ${RPM_BUILD_ROOT}%{_libdir}/libflashrom.so +rm ${RPM_BUILD_ROOT}%{_libdir}/pkgconfig/libflashrom.pc +rm ${RPM_BUILD_ROOT}%{_sbindir}/flashrom + %find_lang %{name} %post -/sbin/ldconfig %systemd_post fwupd.service %preun %systemd_preun fwupd.service %postun -/sbin/ldconfig %systemd_postun_with_restart fwupd.service +%systemd_postun_with_restart pesign.service %files -f %{name}.lang -%doc README.md AUTHORS NEWS +%doc README.md AUTHORS %license COPYING %config(noreplace)%{_sysconfdir}/fwupd/daemon.conf +%if 0%{?have_uefi} %config(noreplace)%{_sysconfdir}/fwupd/uefi.conf +%endif +%if 0%{?have_redfish} +%config(noreplace)%{_sysconfdir}/fwupd/redfish.conf +%endif %dir %{_libexecdir}/fwupd %{_libexecdir}/fwupd/fwupd +%{_libexecdir}/fwupd/fwupdtool +%{_libexecdir}/fwupd/fwupdagent +%{_libexecdir}/fwupd/fwupdoffline +%if 0%{?have_uefi} +%{_libexecdir}/fwupd/efi/*.efi +%{_libexecdir}/fwupd/efi/*.efi.signed +%{_libexecdir}/fwupd/fwupdate +%endif %{_bindir}/dfu-tool %{_bindir}/fwupdmgr %dir %{_sysconfdir}/fwupd %dir %{_sysconfdir}/fwupd/remotes.d -%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd.conf +%if 0%{?have_dell} +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/dell-esrt.conf +%endif %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/lvfs.conf %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/lvfs-testing.conf %config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor.conf +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/vendor-directory.conf %config(noreplace)%{_sysconfdir}/pki/fwupd %{_sysconfdir}/pki/fwupd-metadata %{_sysconfdir}/dbus-1/system.d/org.freedesktop.fwupd.conf %{_datadir}/bash-completion/completions/fwupdmgr -%{_datadir}/fwupd/remotes.d/fwupd/metadata.xml +%{_datadir}/bash-completion/completions/fwupdtool +%{_datadir}/bash-completion/completions/fwupdagent +%{_datadir}/fwupd/metainfo/org.freedesktop.fwupd*.metainfo.xml +%if 0%{?have_dell} +%{_datadir}/fwupd/remotes.d/dell-esrt/metadata.xml +%endif %{_datadir}/fwupd/remotes.d/vendor/firmware/README.md %{_datadir}/dbus-1/interfaces/org.freedesktop.fwupd.xml %{_datadir}/polkit-1/actions/org.freedesktop.fwupd.policy @@ -211,6 +271,7 @@ %{_datadir}/man/man1/dfu-tool.1.gz %{_datadir}/man/man1/fwupdmgr.1.gz %{_datadir}/metainfo/org.freedesktop.fwupd.metainfo.xml +%{_datadir}/icons/hicolor/scalable/apps/org.freedesktop.fwupd.svg %{_datadir}/fwupd/firmware-packager %{_unitdir}/fwupd-offline-update.service %{_unitdir}/fwupd.service @@ -222,21 +283,40 @@ %{_libdir}/libfwupd*.so.* %{_libdir}/girepository-1.0/Fwupd-2.0.typelib /usr/lib/udev/rules.d/*.rules +/usr/lib/systemd/system-shutdown/fwupd.shutdown %dir %{_libdir}/fwupd-plugins-3 %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so %{_libdir}/fwupd-plugins-3/libfu_plugin_colorhug.so %{_libdir}/fwupd-plugins-3/libfu_plugin_csr.so %if 0%{?have_dell} %{_libdir}/fwupd-plugins-3/libfu_plugin_dell.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_dell_esrt.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_dell_dock.so %{_libdir}/fwupd-plugins-3/libfu_plugin_dfu.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ebitdo.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_fastboot.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_flashrom.so +%if 0%{?have_modem_manager} +%{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so +%endif %{_libdir}/fwupd-plugins-3/libfu_plugin_nitrokey.so +%if 0%{?have_uefi} +%{_libdir}/fwupd-plugins-3/libfu_plugin_nvme.so +%endif +%if 0%{?have_redfish} +%{_libdir}/fwupd-plugins-3/libfu_plugin_redfish.so +%endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_rts54hid.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_rts54hub.so %{_libdir}/fwupd-plugins-3/libfu_plugin_steelseries.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_superio.so %if 0%{?have_dell} %{_libdir}/fwupd-plugins-3/libfu_plugin_synapticsmst.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_synaptics_prometheus.so %if 0%{?enable_dummy} %{_libdir}/fwupd-plugins-3/libfu_plugin_test.so %endif @@ -248,7 +328,15 @@ %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_unifying.so %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_raw.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_wacom_usb.so %ghost %{_localstatedir}/lib/fwupd/gnupg +%if 0%{?have_uefi} +%{_datadir}/locale/*/LC_IMAGES/fwupd* +%endif + +# eww, but just until the Fedora package ships these... +%{_libdir}/libflashrom.so.1* %files devel %{_datadir}/gir-1.0/Fwupd-2.0.gir @@ -258,19 +346,15 @@ %{_libdir}/libfwupd*.so %{_libdir}/pkgconfig/fwupd.pc -%files labels -%if 0%{?have_uefi} -%{_datadir}/locale/*/LC_IMAGES/fwupd* -%endif - %files tests %dir %{_datadir}/installed-tests/fwupd -%{_datadir}/installed-tests/fwupd/firmware-example.xml.gz -%{_datadir}/installed-tests/fwupd/firmware-example.xml.gz.asc +%{_datadir}/installed-tests/fwupd/fwupd-tests.xml %{_datadir}/installed-tests/fwupd/*.test %{_datadir}/installed-tests/fwupd/*.cab %{_datadir}/installed-tests/fwupd/*.sh %{_datadir}/installed-tests/fwupd/*.py* +%dir %{_sysconfdir}/fwupd/remotes.d +%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf %changelog * #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# diff -Nru fwupd-1.0.6/contrib/nvme-parse.py fwupd-1.2.10/contrib/nvme-parse.py --- fwupd-1.0.6/contrib/nvme-parse.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/nvme-parse.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,128 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ + +import csv +import binascii +import os +import struct +import glob +from collections import namedtuple + +class Record(object): + def __init__(self, filename, cns): + self.filename = filename + self.cns = cns + +def load_pci_ids(): + pci_vendors = {} + pci_vendors[0x1987] = 'Freescale' + for ln in open('/usr/share/hwdata/pci.ids').read().split('\n'): + if ln.startswith('#'): + continue + if ln.startswith('\t'): + continue + data = ln.split(' ') + if len(data) != 2: + continue + pci_vendors[int(data[0], 16)] = data[1].split(' ')[0] + if data[0] == 'ffff': + break + return pci_vendors + +def _data_to_utf8(s): + return s.decode('utf-8', 'replace').replace('\0', ' ') + +def main(): + + # open files + records = [] + for fn in glob.glob('tests/nvme/*'): + blob = open(fn, 'rb').read() + if len(blob) != 4096: + print('WARNING: ignoring %s of size %i' % (fn, len(blob))) + continue + Cns = namedtuple('Cns', + 'vid ssvid sn mn fr rab ieee cmic mdts cntlid ver ' \ + 'rtd3r rtd3e oaes ctratt rrls rsvd102 oacs acl aerl ' \ + 'frmw lpa elpe npss avscc apsta wctemp cctemp mtfa ' \ + 'hmpre hmmin tnvmcap unvmcap rpmbs edstt dsto fwug ' \ + 'kas hctma mntmt mxtmt sanicap hmminds hmmaxd ' \ + 'nsetidmax rsvd340 anatt anacap anagrpmax nanagrpid ' \ + 'rsvd352 sqes cqes maxcmd nn oncs fuses fna vwc awun ' \ + 'awupf nvscc nwpc acwu rsvd534 sgls mnan rsvd544 ' \ + 'subnqn rsvd1024 ioccsz iorcsz icdoff ctrattr msdbd ' \ + 'rsvd1804 psd vs') + try: + cns = Cns._make(struct.unpack(' 0: + s1ro_cnt += 1 + if (r.cns.frmw & 0x10) >> 4: + fawr_cnt += 1 + nfws = (r.cns.frmw & 0x0e) >> 1 + if nfws in nfws_map: + nfws_map[nfws] += 1 + continue + nfws_map[nfws] = 1 + print('s1ro=%i/%i' % (s1ro_cnt, len(records))) + print('fawr=%i/%i' % (fawr_cnt, len(records))) + nfws = sorted(nfws_map.items(), key=lambda k: k[0], reverse=True) + for nfws, cnt in nfws: + print('nfws[%i]=%i' % (nfws, cnt)) + + # vendor popularity + vids = {} + for r in records: + if r.cns.vid not in vids: + vids[r.cns.vid] = 1 + continue + vids[r.cns.vid] += 1 + vids = sorted(vids.items(), key=lambda k: k[1], reverse=True) + pci_vendors = load_pci_ids() + for vid, cnt in vids: + name = '0x%04x' % vid + if vid in pci_vendors: + name = pci_vendors[vid] + print('%s,%i' % (name, cnt)) + + # vendor records + vs_records = [] + for r in records: + if r.cns.vs: + vs_records.append(r) + print('nr_vs=%i' % len(vs_records)) + +main() diff -Nru fwupd-1.0.6/contrib/PKGBUILD fwupd-1.2.10/contrib/PKGBUILD --- fwupd-1.0.6/contrib/PKGBUILD 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/PKGBUILD 2019-07-15 18:25:54.000000000 +0000 @@ -8,14 +8,16 @@ arch=('i686' 'x86_64') url='https://github.com/hughsie/fwupd' license=('GPL2') -depends=('appstream-glib' 'fwupdate' 'colord') +depends=('libgusb' 'modemmanager') +optdepends=('tpm2-abrmd' 'tpm2-tools') makedepends=('meson' 'valgrind' 'gobject-introspection' 'gtk-doc' 'python-pillow' 'git' - 'python-cairo' 'ttf-dejavu' 'adobe-source-han-sans-cn-fonts' 'python-gobject' 'vala') + 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala' + 'libsoup' 'polkit' 'gcab') build() { cd ${pkgname} if [ -n "$CI" ]; then - export CI="--werror" + export CI="--werror --wrap-mode=default" fi arch-meson -D b_lto=false $CI ../build diff -Nru fwupd-1.0.6/contrib/README.md fwupd-1.2.10/contrib/README.md --- fwupd-1.0.6/contrib/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/contrib/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -17,7 +17,7 @@ To build the RPMs run this command (from the root of your git checkout): ``` -docker run -t -v `pwd`:/build fwupd-fedora +docker run --privileged -t -v `pwd`:/build fwupd-fedora ``` RPMs will be made available in your working directory when complete. @@ -37,9 +37,9 @@ To build the DEBs run one of these commands (from the root of your git checkout): ``` -docker run -t -v `pwd`:/build fwupd-debian-x86_64 -docker run -t -v `pwd`:/build fwupd-debian-i386 -docker run -t -v `pwd`:/build fwupd-ubuntu-x86_64 +docker run --privileged -t -v `pwd`:/build fwupd-debian-x86_64 +docker run --privileged -t -v `pwd`:/build fwupd-debian-i386 +docker run --privileged -t -v `pwd`:/build fwupd-ubuntu-x86_64 ``` DEBs will be made available in your working directory when complete. diff -Nru fwupd-1.0.6/contrib/simple_client.py fwupd-1.2.10/contrib/simple_client.py --- fwupd-1.0.6/contrib/simple_client.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/simple_client.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,126 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1+ +"""A simple fwupd frontend""" +import sys +import os +import gi +from gi.repository import GLib +gi.require_version('Fwupd', '2.0') +from gi.repository import Fwupd #pylint: disable=wrong-import-position + +class Progress(): + """Class to track the signal changes of progress events""" + def __init__(self): + self.device = None + self.status = None + self.percent = 0 + self.erase = 0 + + def device_changed(self, new_device): + """Indicate new device string to track""" + if self.device != new_device: + self.device = new_device + print("\nUpdating %s" % self.device) + + def status_changed(self, percent, status): + """Indicate new status string or % complete to track""" + if self.status != status or self.percent != percent: + for i in range(0, self.erase): + sys.stdout.write("\b \b") + self.status = status + self.percent = percent + status_str = "[" + for i in range(0, 50): + if i < percent/2: + status_str += '*' + else: + status_str += ' ' + status_str += "] %d%% %s" %(percent, status) + status_str.erase = len(status_str) + sys.stdout.write(status_str) + sys.stdout.flush() + if 'idle' in status: + sys.stdout.write("\n") + +def parse_args(): + """Parse arguments for this client""" + import argparse + parser = argparse.ArgumentParser(description="Interact with fwupd daemon") + parser.add_argument("--allow-older", action="store_true", + help="Install older payloads(default False)") + parser.add_argument("--allow-reinstall", action="store_true", + help="Reinstall payloads(default False)") + parser.add_argument("command", choices=["get-devices", + "get-details", + "install"], help="What to do") + parser.add_argument('cab', nargs='?', help='CAB file') + parser.add_argument('deviceid', nargs='?', + help='DeviceID to operate on(optional)') + args = parser.parse_args() + return args + +def get_devices(client): + """Use fwupd client to fetch devices""" + devices = client.get_devices() + for item in devices: + print(item.to_string()) + +def get_details(client, cab): + """Use fwupd client to fetch details for a CAB file""" + devices = client.get_details(cab, None) + for device in devices: + print(device.to_string()) + +def status_changed(client, spec, progress): #pylint: disable=unused-argument + """Signal emitted by fwupd daemon indicating status changed""" + progress.status_changed(client.get_percentage(), + Fwupd.status_to_string(client.get_status())) + +def device_changed(client, device, progress): #pylint: disable=unused-argument + """Signal emitted by fwupd daemon indicating active device changed""" + progress.device_changed(device.get_name()) + +def install(client, cab, target, older, reinstall): + """Use fwupd client to install CAB file to applicable devices""" + # FWUPD_DEVICE_ID_ANY + if not target: + target = '*' + flags = Fwupd.InstallFlags.NONE + if older: + flags |= Fwupd.InstallFlags.ALLOW_OLDER + if reinstall: + flags |= Fwupd.InstallFlags.ALLOW_REINSTALL + progress = Progress() + parent = super(client.__class__, client) + parent.connect('device-changed', device_changed, progress) + parent.connect('notify::percentage', status_changed, progress) + parent.connect('notify::status', status_changed, progress) + try: + client.install(target, cab, flags, None) + except GLib.Error as glib_err: #pylint: disable=catching-non-exception + progress.status_changed(0, 'idle') + print("%s" % glib_err) + sys.exit(1) + +def check_cab(cab): + """Check that CAB file exists""" + if not cab: + print("Need to specify payload") + sys.exit(1) + if not os.path.isfile(cab): + print("%s doesn't exist or isn't a file" % cab) + sys.exit(1) + +if __name__ == '__main__': + ARGS = parse_args() + CLIENT = Fwupd.Client() + CLIENT.connect() + + if ARGS.command == "get-devices": + get_devices(CLIENT) + elif ARGS.command == "get-details": + check_cab(ARGS.cab) + get_details(CLIENT, ARGS.cab) + elif ARGS.command == "install": + check_cab(ARGS.cab) + install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall) diff -Nru fwupd-1.0.6/contrib/snap/activate-shutdown/fwupd-activate.service fwupd-1.2.10/contrib/snap/activate-shutdown/fwupd-activate.service --- fwupd-1.0.6/contrib/snap/activate-shutdown/fwupd-activate.service 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/activate-shutdown/fwupd-activate.service 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,12 @@ +[Unit] +Description=Activate fwupd updates +RequiresMountsFor=/snap/fwupd/current + +[Service] +Type=oneshot +RemainAfterExit=true +ExecStop=/snap/bin/fwupd.fwupdtool activate +SuccessExitStatus=0 2 + +[Install] +WantedBy=multi-user.target diff -Nru fwupd-1.0.6/contrib/snap/activate-shutdown/Makefile fwupd-1.2.10/contrib/snap/activate-shutdown/Makefile --- fwupd-1.0.6/contrib/snap/activate-shutdown/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/activate-shutdown/Makefile 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,9 @@ +build: + true +install: + install -d ${DESTDIR}/etc/systemd/system/ + install -m0644 fwupd-activate.service ${DESTDIR}/etc/systemd/system + # fixes up shutdown activation script for classic snap + sed -i "s,/libexec/fwupd/,/snap/bin/fwupd.," \ + ${SNAPCRAFT_STAGE}/lib/systemd/system-shutdown/fwupd.shutdown + diff -Nru fwupd-1.0.6/contrib/snap/dfu-tool.wrapper fwupd-1.2.10/contrib/snap/dfu-tool.wrapper --- fwupd-1.0.6/contrib/snap/dfu-tool.wrapper 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/dfu-tool.wrapper 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$SNAP/fwupd-command" $SNAP/bin/dfu-tool $@ diff -Nru fwupd-1.0.6/contrib/snap/fix-bash-completion/Makefile fwupd-1.2.10/contrib/snap/fix-bash-completion/Makefile --- fwupd-1.0.6/contrib/snap/fix-bash-completion/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fix-bash-completion/Makefile 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,10 @@ +build: + true +install: + #fixes up fwupdtool -> fwupd.fwupdtool + sed -i "s,\(complete -F _fwupd[a-z]*\) \(fwupd.*\),\1 fwupd.\2,; \ + s,\(command.*\)\(fwupdtool\),\1fwupd.\2," \ + ${SNAPCRAFT_STAGE}/share/bash-completion/completions/* + # fixes up dbus service for classic snap + sed -i 's!SystemdService=\(.*\)!SystemdService=snap.fwupd.fwupd.service!' \ + ${SNAPCRAFT_STAGE}/share/dbus-1/system-services/org.freedesktop.fwupd.service diff -Nru fwupd-1.0.6/contrib/snap/fwupd-command fwupd-1.2.10/contrib/snap/fwupd-command --- fwupd-1.0.6/contrib/snap/fwupd-command 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fwupd-command 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,41 @@ +#!/bin/sh + +export XDG_CACHE_HOME=$SNAP_USER_COMMON/.cache +mkdir -p $XDG_CACHE_HOME +export GIO_MODULE_DIR=$XDG_CACHE_HOME/gio-modules +export XDG_DATA_DIRS="$SNAP/usr/share" + +#determine architecture +if [ "$SNAP_ARCH" = "amd64" ]; then + ARCH="x86_64-linux-gnu" +elif [ "$SNAP_ARCH" = "armhf" ]; then + ARCH="arm-linux-gnueabihf" +elif [ "$SNAP_ARCH" = "arm64" ]; then + ARCH="aarch64-linux-gnu" +else + ARCH="$SNAP_ARCH-linux-gnu" +fi + +# don't update between versions, we want to preserve previous data +[ ! -d "$SNAP_USER_DATA/etc" ] && cp -R "$SNAP/etc" "$SNAP_USER_DATA" +[ ! -d "$SNAP_USER_DATA/var" ] && cp -R "$SNAP/var" "$SNAP_USER_DATA" + +# re-generate gio modules in local cache +needs_update=true +if [ -f $SNAP_USER_DATA/.last_revision ]; then + . $SNAP_USER_DATA/.last_revision 2>/dev/null +fi +if [ "$SNAP_DESKTOP_LAST_REVISION" = "$SNAP_REVISION" ]; then + needs_update=false +fi +if [ $needs_update = true ]; then + if [ -f $SNAP/usr/lib/$ARCH/glib-2.0/gio-querymodules ]; then + rm -rf $GIO_MODULE_DIR + mkdir -p $GIO_MODULE_DIR + ln -s $SNAP/usr/lib/$ARCH/gio/modules/*.so $GIO_MODULE_DIR + $SNAP/usr/lib/$ARCH/glib-2.0/gio-querymodules $GIO_MODULE_DIR + fi + echo "SNAP_DESKTOP_LAST_REVISION=$SNAP_REVISION" > $SNAP_USER_DATA/.last_revision +fi + +exec "$@" diff -Nru fwupd-1.0.6/contrib/snap/fwupdmgr.wrapper fwupd-1.2.10/contrib/snap/fwupdmgr.wrapper --- fwupd-1.0.6/contrib/snap/fwupdmgr.wrapper 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fwupdmgr.wrapper 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$SNAP/fwupd-command" $SNAP/bin/fwupdmgr $@ diff -Nru fwupd-1.0.6/contrib/snap/fwupdtool.wrapper fwupd-1.2.10/contrib/snap/fwupdtool.wrapper --- fwupd-1.0.6/contrib/snap/fwupdtool.wrapper 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fwupdtool.wrapper 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$SNAP/fwupd-command" $SNAP/libexec/fwupd/fwupdtool $@ diff -Nru fwupd-1.0.6/contrib/snap/fwupd.wrapper fwupd-1.2.10/contrib/snap/fwupd.wrapper --- fwupd-1.0.6/contrib/snap/fwupd.wrapper 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fwupd.wrapper 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$SNAP/fwupd-command" $SNAP/libexec/fwupd/fwupd $@ diff -Nru fwupd-1.0.6/contrib/snap/fwup-efi-signed/download-fwupd fwupd-1.2.10/contrib/snap/fwup-efi-signed/download-fwupd --- fwupd-1.0.6/contrib/snap/fwup-efi-signed/download-fwupd 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fwup-efi-signed/download-fwupd 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,36 @@ +#! /usr/bin/python3 + +import re +import shutil +from urllib.parse import urlparse, urlunparse +from urllib.request import urlopen + +import apt +import apt_pkg + +ARCH_TO_EFI_NAME = { + 'amd64': 'x64', + 'i386': 'ia32', + 'arm64': 'aa64', + 'armhf': 'arm', +} +arch = apt_pkg.config['Apt::Architecture'] +efi_name = ARCH_TO_EFI_NAME[arch] +cache = apt.Cache() +fwupd_efi = cache["fwupd"].candidate +pool_parsed = urlparse(fwupd_efi.uri) +dists_dir = "/dists/devel/main/uefi/fwupd-%s/current/" % ( + fwupd_efi.architecture) + +DOWNLOAD_LIST = { + "fwupd%s.efi.signed" %efi_name: "fwupd%s.efi.signed" % efi_name, + "version": "fwupd%s.efi.signed.version" % efi_name +} +for base in DOWNLOAD_LIST: + dists_parsed = list(pool_parsed) + dists_parsed[2] = re.sub(r"/pool/.*", dists_dir + base, dists_parsed[2]) + dists_uri = urlunparse(dists_parsed) + target = DOWNLOAD_LIST[base] + print("Downloading %s to %s..." % (dists_uri, target)) + with urlopen(dists_uri) as dists, open(target, "wb") as out: + shutil.copyfileobj(dists, out) diff -Nru fwupd-1.0.6/contrib/snap/fwup-efi-signed/Makefile fwupd-1.2.10/contrib/snap/fwup-efi-signed/Makefile --- fwupd-1.0.6/contrib/snap/fwup-efi-signed/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/fwup-efi-signed/Makefile 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,34 @@ +DEB_HOST_ARCH=$(shell dpkg-architecture -q DEB_HOST_ARCH) +EFI_NAME := UNKNOWN-EFI-NAME + +ifeq ($(DEB_HOST_ARCH),amd64) +EFI_NAME := x64 +endif + +ifeq ($(DEB_HOST_ARCH),i386) +EFI_NAME := ia32 +endif + +ifeq ($(DEB_HOST_ARCH),arm64) +EFI_NAME := aa64 +endif + +ifeq ($(DEB_HOST_ARCH),armhf) +EFI_NAME := arm +endif + +SIGNED := \ + fwupd$(EFI_NAME).efi.signed + +all: $(SIGNED) + +$(SIGNED): + ./download-fwupd + +install: $(SIGNED) + install -d $(DESTDIR)/libexec/fwupd/efi + install -m0644 $(SIGNED) $(SIGNED).version \ + $(DESTDIR)/libexec/fwupd/efi + +clean: + rm -f $(SIGNED) $(SIGNED).version diff -Nru fwupd-1.0.6/contrib/snap/libefivar-fixpkgconfig/Makefile fwupd-1.2.10/contrib/snap/libefivar-fixpkgconfig/Makefile --- fwupd-1.0.6/contrib/snap/libefivar-fixpkgconfig/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/libefivar-fixpkgconfig/Makefile 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,10 @@ +build: + true + +install: + sed -i 's!libdir=\(.*\)!libdir=${SNAPCRAFT_STAGE}\1!' ${SNAPCRAFT_STAGE}/lib/pkgconfig/efiboot.pc + sed -i 's!includedir=\(.*\)!includedir=${SNAPCRAFT_STAGE}\1!' ${SNAPCRAFT_STAGE}/lib/pkgconfig/efiboot.pc + sed -i 's!Cflags:\(.*\)!Cflags:\1 -L$$\{libdir\}!' ${SNAPCRAFT_STAGE}/lib/pkgconfig/efiboot.pc + sed -i 's!libdir=\(.*\)!libdir=${SNAPCRAFT_STAGE}\1!' ${SNAPCRAFT_STAGE}/lib/pkgconfig/efivar.pc + sed -i 's!includedir=\(.*\)!includedir=${SNAPCRAFT_STAGE}\1!' ${SNAPCRAFT_STAGE}/lib/pkgconfig/efivar.pc + sed -i 's!Cflags:\(.*\)!Cflags:\1 -L$$\{libdir\}!' ${SNAPCRAFT_STAGE}/lib/pkgconfig/efivar.pc diff -Nru fwupd-1.0.6/contrib/snap/README.md fwupd-1.2.10/contrib/snap/README.md --- fwupd-1.0.6/contrib/snap/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,31 @@ +# Snap support + +Snaps are containerised software packages that are simple to create and install. They auto-update and are safe to run. And because they bundle their dependencies, they work on all major Linux systems without modification. + +## stable vs unstable +Two yaml files are distributed: + +* snapcraft.yaml +This uses tarball releases for all dependencies and what is currently in tree for fwupd. + +* snapcraft-master.yaml +This uses git for most dependencies and may be considered unstable. + +# Building + +Builds can be performed using snapcraft: + +``` +# snapcraft cleanbuild +``` + +# Installing + +A "classic" snap is produced, and locally built snaps can be installed like this: + +``` +# snap install fwupd_daily_amd64.snap --dangerous --classic +``` + +The `--dangerous` flag is because snaps built locally are not signed. +Snaps distributed by a store will not need this flag. diff -Nru fwupd-1.0.6/contrib/snap/snapcraft-master.yaml fwupd-1.2.10/contrib/snap/snapcraft-master.yaml --- fwupd-1.0.6/contrib/snap/snapcraft-master.yaml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/snapcraft-master.yaml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,344 @@ +name: fwupd +version-script: cat $SNAPCRAFT_STAGE/version +version: 'daily' +summary: A standalone version of fwupd to install newer firmware updates +description: | + This is a tool that can be used to install firmware updates on devices + not yet supported by the version of fwupd distributed with the OS. + +grade: devel +confinement: classic + +architectures: + - amd64 + +apps: + dfu-tool: + command: dfu-tool.wrapper + fwupdtool: + command: fwupdtool.wrapper + completer: + share/bash-completion/completions/fwupdtool + fwupd: + command: fwupd.wrapper + daemon: simple + fwupdmgr: + command: fwupdmgr.wrapper + completer: + share/bash-completion/completions/fwupdmgr + +parts: + libefivar-dev: + plugin: make + make-parameters: + - prefix=/ + - libdir=/lib + source: https://github.com/rhboot/efivar.git + source-type: git + build-packages: + - libpopt-dev + prime: + - -include + - -bin + - -share/man + - -lib/pkgconfig + #adjust the paths from libefivar + libefivar-fixpkgconfig: + plugin: make + source: contrib/snap/libefivar-fixpkgconfig + make-parameters: + - SNAPCRAFT_STAGE=$SNAPCRAFT_STAGE + after: [libefivar-dev] + libsmbios: + plugin: autotools + source: https://github.com/dell/libsmbios + source-type: git + build-packages: + - libxml2-dev + - pkg-config + - autoconf + - automake + - libtool + - autopoint + prime: + - -include/ + - -lib/pkgconfig + - -lib/python3.5 + - -sbin/ + - -share/ + - -etc/ + - -lib/*.a + meson: + plugin: python + source: https://github.com/mesonbuild/meson.git + source-tag: 0.47.2 + build-packages: + - ninja-build + prime: + - -bin + - -etc + - -lib + - -share + - -usr + gudev: + plugin: autotools + source: https://gitlab.gnome.org/GNOME/libgudev.git + source-type: git + configflags: + - --disable-umockdev + build-packages: + - libglib2.0-dev + - pkg-config + - libudev-dev + - gtk-doc-tools + - gnome-common + prime: + - -include + - -lib/girepository-1.0 + - -lib/pkgconfig + - -share/ + # this is for the library only, we don't care about the daemon "in-snap" + modemmanager: + plugin: autotools + source: https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git + #not yet tagged + #source-tag: 1.10.0 + after: [gudev, gettext] + # build without these; system daemon needs them + configflags: + - --without-mbim + - --without-qmi + prime: + - -include + - -etc + - -sbin + - -bin + - -share + - -lib/*.*a + - -lib/pkgconfig + - -lib/ModemManager + - -lib/systemd + - -lib/udev + - -lib/girepository-1.0 + libqmi: + plugin: autotools + source: https://gitlab.freedesktop.org/mobile-broadband/libqmi.git + #not yet tagged + #source-tag: 1.10.0 + after: [gudev, gettext, modemmanager] + # build without these; system daemon needs them + configflags: + - --without-udev + prime: + - -include + - -etc + - -sbin + - -bin + - -share + - -lib/*.*a + - -lib/pkgconfig + - -lib/ModemManager + - -lib/systemd + - -lib/udev + - -lib/girepository-1.0 + libusb: + plugin: autotools + source: https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2 + configflags: + - --disable-static + prime: + - -include/ + - -lib/pkgconfig + gusb: + plugin: meson + source: https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz + meson-parameters: [--prefix=/, + -Dtests=false, + -Dvapi=false, + -Ddocs=false] + build-packages: + - libgirepository1.0-dev + prime: + - -bin/ + - -include + - -share + - -lib/*/pkgconfig + - -lib/*/girepository-1.0 + after: [meson, libusb] + gnu-efi: + plugin: make + source: http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2 + make-parameters: + - PREFIX=/usr + make-install-var: INSTALLROOT + prime: + - -usr/include/ + - -usr/lib + #fetch the latest version of the signed bootloader + #this might not match our fwupdx64.efi, but it's better than nothing + fwup-efi-signed: + build-packages: + - python3-apt + plugin: make + source: contrib/snap/fwup-efi-signed + #needed for UEFI plugin to build UX labels + build-introspection: + plugin: nil + stage-packages: + - python3-gi + - python3-gi-cairo + - python3-pil + prime: + - -etc + - -usr + - -lib + - -var + #0.19.8.1 adds support for GETTEXTDATADIRS which is needed by meson's msgfmthelper + gettext: + source: https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.xz + plugin: autotools + build-packages: + - bison + - libunistring-dev + - libxml2-dev + configflags: + - --prefix=/usr + - --disable-static + - --disable-curses + - --disable-java + - --enable-relocatable + - --without-emacs + - --without-included-glib + - --without-included-libunistring + - --without-included-libxml + stage-packages: + - libunistring0 + - libxml2 + - libgomp1 + prime: + - -**/*.a + - -**/*.la + - -usr/bin + - -usr/include + - -usr/lib/gettext + - -usr/share + fwupd: + plugin: meson + meson-parameters: [--prefix=/, + -Defi-includedir=$SNAPCRAFT_STAGE/usr/include/efi, + -Defi-ldsdir=$SNAPCRAFT_STAGE/usr/lib, + -Defi-libdir=$SNAPCRAFT_STAGE/usr/lib, + -Dtests=false, + -Ddaemon=true, + -Dgtkdoc=false, + -Dintrospection=false, + -Dman=false, + -Dplugin_modem_manager=true, + -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + -Dlibxmlb:gtkdoc=false, + -Dlibxmlb:introspection=false, + -Dpkcs7=false] + source: . + source-type: git + override-build: | + snapcraftctl build + echo $(git describe HEAD --always) > $SNAPCRAFT_STAGE/version + build-packages: + - bash-completion + - gcab + - gnutls-dev + - libarchive-dev + - libcairo-dev + - libelf-dev + - libgcab-dev + - libglib2.0-dev + - libgpgme11-dev + - libjson-glib-dev + - libpango1.0-dev + - libpolkit-gobject-1-dev + - libsoup2.4-dev + - libsqlite3-dev + - locales + - pkg-config + - uuid-dev + stage-packages: + - libgcab-1.0-0 + - libarchive13 + - libassuan0 + - liblcms2-2 + - libelf1 + - libgpgme11 + - libjson-glib-1.0-0 + - libpolkit-gobject-1-0 + - libsoup2.4-1 + - glib-networking + - libglib2.0-bin + prime: + # we explicitly don't want /usr/bin/gpgconf + # this will cause gpgme to error finding it + # but that also avoids trying to use non-existent + # /usr/bin/gpg2 + - -usr/bin + - -usr/sbin + - -usr/share/man + - -usr/share/GConf + - -etc/X11 + - -etc/ldap + - -etc/logcheck + - -usr/lib/dconf + - -usr/lib/gcc + - -usr/lib/glib-networking + - -usr/lib/gnupg2 + - -usr/lib/sasl2 + - -usr/lib/systemd + - -usr/lib/*/audit + - -usr/share/glib-2.0/schemas + - -usr/share/X11 + - -include + - -lib/udev + - -lib/*/pkgconfig + - -usr/share/lintian + - -usr/share/pkgconfig + - -usr/share/installed-tests + - -usr/share/polkit-1 + - -usr/share/vala + - -usr/share/doc + - -usr/share/gnupg2 + - -usr/share/info + - -usr/share/gir-1.0 + - -usr/share/upstart + - -usr/lib/*/pkgconfig + after: [gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext, modemmanager, libqmi] + fix-bash-completion: + plugin: make + source: contrib/snap/fix-bash-completion + after: [fwupd] + activate-shutdown: + plugin: make + source: contrib/snap/activate-shutdown + after: [fwupd] + update-mime: + plugin: make + source: contrib/snap/update-mime + stage-packages: + - shared-mime-info + - gsettings-desktop-schemas + - libxml2 + prime: + - -usr/bin + - -usr/share/doc + - -usr/share/doc-base + - -usr/share/man + - -usr/share/lintian + - -usr/share/pkgconfig + - -usr/share/GConf + after: [fwupd] + fwupd-wrappers: + plugin: dump + source: contrib/snap + stage: + - dfu-tool.wrapper + - fwupd-command + - fwupdtool.wrapper + - fwupd.wrapper + - fwupdmgr.wrapper diff -Nru fwupd-1.0.6/contrib/snap/update-mime/Makefile fwupd-1.2.10/contrib/snap/update-mime/Makefile --- fwupd-1.0.6/contrib/snap/update-mime/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/snap/update-mime/Makefile 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,5 @@ +build: + true +install: + update-mime-database ../install/usr/share/mime + glib-compile-schemas ../install/usr/share/glib-2.0/schemas diff -Nru fwupd-1.0.6/contrib/standalone-installer/assets/header.py fwupd-1.2.10/contrib/standalone-installer/assets/header.py --- fwupd-1.0.6/contrib/standalone-installer/assets/header.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/standalone-installer/assets/header.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,319 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2017 Dell, Inc. +# +# SPDX-License-Identifier: LGPL-2.1+ +# +from base64 import b64decode +import io +import os +import subprocess +import sys +import shutil +import tempfile +import zipfile +TAG = b'#\x00' + +def parse_args(): + import argparse + parser = argparse.ArgumentParser(description="Self extracting firmware updater") + parser.add_argument("--directory", help="Directory to extract to") + parser.add_argument("--cleanup", action='store_true', help="Remove tools when done with installation") + parser.add_argument("--verbose", action='store_true', help="Run the tool in verbose mode") + parser.add_argument("--allow-reinstall", action='store_true', help="Allow re-installing existing firmware versions") + parser.add_argument("--allow-older", action='store_true', help="Allow downgrading firmware versions") + parser.add_argument("command", choices=["install", "extract"], help="Command to run") + args = parser.parse_args() + return args + +def error (msg): + print(msg) + sys.exit(1) + +def bytes_slicer(length, source): + start = 0 + stop = length + while start < len(source): + yield source[start:stop] + start = stop + stop += length + +def get_zip(): + script = os.path.realpath (__file__) + bytes_out = io.BytesIO() + with open(script, 'rb') as source: + for line in source: + if not line.startswith(TAG): + continue + bytes_out.write(b64decode(line[len(TAG):-1])) + return bytes_out + +def unzip (destination): + zipf = get_zip () + source = zipfile.ZipFile (zipf, 'r') + for item in source.namelist(): + # extract handles the sanitization + source.extract (item, destination) + +def copy_cabs (source, target): + if not os.path.exists (target): + os.makedirs (target) + cabs = [] + for root, dirs, files in os.walk (source): + for f in files: + if (f.endswith ('.cab')): + origf = os.path.join(root, f) + shutil.copy (origf, target) + cabs.append (os.path.join (target, f)) + return cabs + + +def install_snap (directory, verbose, allow_reinstall, allow_older, uninstall): + app = 'fwupd' + common = '/root/snap/%s/common' % app + + #check if snap is installed + with open(os.devnull, 'w') as devnull: + subprocess.run (['snap'], check=True, stdout=devnull, stderr=devnull) + + #check existing installed + cmd = ['snap', 'list', app] + with open(os.devnull, 'w') as devnull: + if verbose: + print(cmd) + ret = subprocess.run (cmd, stdout=devnull, stderr=devnull) + if ret.returncode == 0: + cmd = ['snap', 'remove', app] + if verbose: + print(cmd) + subprocess.run (cmd, check=True) + + # install the snap + cmd = ['snap', 'ack', os.path.join (directory, 'fwupd.assert')] + if verbose: + print(cmd) + subprocess.run (cmd, check=True) + cmd = ['snap', 'install', '--classic', os.path.join (directory, 'fwupd.snap')] + if verbose: + print(cmd) + subprocess.run (cmd, check=True) + + # copy the CAB files + cabs = copy_cabs (directory, common) + + # run the snap + for cab in cabs: + cmd = ["%s.fwupdmgr" % app, 'install', cab] + if allow_reinstall: + cmd += ["--allow-reinstall"] + if allow_older: + cmd += ["--allow-older"] + if verbose: + cmd += ["--verbose"] + print(cmd) + subprocess.run (cmd) + + #remove copied cabs + for f in cabs: + os.remove(f) + + #cleanup + if uninstall: + cmd = ['snap', 'remove', app] + if verbose: + print(cmd) + subprocess.run (cmd) + +def install_flatpak (directory, verbose, allow_reinstall, allow_older, uninstall): + app = 'org.freedesktop.fwupd' + common = '%s/.var/app/%s' % (os.getenv ('HOME'), app) + + with open(os.devnull, 'w') as devnull: + if not verbose: + output = devnull + else: + output = None + #look for dependencies + dep = 'org.gnome.Platform/x86_64/3.30' + repo = 'flathub' + repo_url = 'https://flathub.org/repo/flathub.flatpakrepo' + cmd = ['flatpak', 'info', dep] + if verbose: + print(cmd) + ret = subprocess.run (cmd, stdout=output, stderr=output) + #not installed + if ret.returncode != 0: + #look for remotes + cmd = ['flatpak', 'remote-info', repo, dep] + if verbose: + print(cmd) + ret = subprocess.run (cmd, stdout=output, stderr=output) + #not enabled, enable it + if ret.returncode != 0: + cmd = ['flatpak', 'remote-add', repo, repo_url] + if verbose: + print(cmd) + ret = subprocess.run (cmd, stderr=output) + # install dep + cmd = ['flatpak', 'install', repo, dep] + if verbose: + print(cmd) + ret = subprocess.run (cmd) + + #check existing installed + cmd = ['flatpak', 'info', app] + if verbose: + print(cmd) + ret = subprocess.run (cmd, stdout=output, stderr=output) + if ret.returncode == 0: + cmd = ['flatpak', 'remove', app] + if verbose: + print(cmd) + subprocess.run (cmd, check=True) + + #install the flatpak + cmd = ['flatpak', 'install', os.path.join (directory, 'fwupd.flatpak')] + if verbose: + print(cmd) + subprocess.run (cmd, check=True) + + # copy the CAB files + cabs = copy_cabs (directory, common) + + #run command + for cab in cabs: + cmd = ['flatpak', 'run', app, 'install', cab] + if allow_reinstall: + cmd += ["--allow-reinstall"] + if allow_older: + cmd += ["--allow-older"] + if verbose: + cmd += ["--verbose"] + print(cmd) + subprocess.run (cmd) + + #remove copied cabs + for f in cabs: + os.remove(f) + + #cleanup + if uninstall: + cmd = ['flatpak', 'remove', app] + if verbose: + print(cmd) + subprocess.run (cmd) + +# Check which package to use +# - return False to use packaged version +# - return True for snap/flatpak +def use_included_version(minimum_version): + try: + import apt + except ModuleNotFoundError: + return True + cache = apt.Cache() + pkg = cache.get("fwupd") + version = pkg.installed + if not version: + return True + if minimum_version: + if minimum_version > version: + print("fwupd %s is already installed but this package requires %s" % + (version.version, minimum_version)) + else: + print("New enough fwupd already installed") + return False + else: + print("fwupd %s is installed and must be removed" % version.version) + return remove_packaged_version(pkg, cache) + +def remove_packaged_version(pkg, cache): + res = False + while not res: + res = input("Remove now (Y/N)? ") + if res.lower() == 'n': + return False + if res.lower() == 'y': + break + res = False + pkg.mark_delete() + res = cache.commit() + if not res: + raise Exception("Need to remove packaged version") + return res + +def install_builtin(directory, verbose, allow_reinstall, allow_older): + cabs = [] + for root, dirs, files in os.walk (directory): + for f in files: + if f.endswith('.cab'): + cabs.append(os.path.join(root, f)) + #run command + for cab in cabs: + cmd = ['fwupdmgr', 'install', cab] + if allow_reinstall: + cmd += ["--allow-reinstall"] + if allow_older: + cmd += ["--allow-older"] + if verbose: + cmd += ["--verbose"] + print(cmd) + subprocess.run(cmd) + +def run_installation (directory, verbose, allow_reinstall, allow_older, uninstall): + try_snap = False + try_flatpak = False + + #determine if a minimum version was specified + minimum_path = os.path.join(directory, "minimum") + minimum = None + if os.path.exists(minimum_path): + with open(minimum_path, "r") as rfd: + minimum = rfd.read() + + if use_included_version(minimum): + install_builtin(directory, verbose, allow_reinstall, allow_older) + return + + # determine what self extracting binary has + if os.path.exists (os.path.join (directory, 'fwupd.snap')) and \ + os.path.exists (os.path.join (directory, 'fwupd.assert')): + try_snap = True + if os.path.exists (os.path.join (directory, 'fwupd.flatpak')): + try_flatpak = True + + if try_snap: + try: + install_snap (directory, verbose, allow_reinstall, allow_older, uninstall) + return True + except Exception as _: + if verbose: + print ("Snap installation failed") + if not try_flatpak: + error ("Snap installation failed") + if try_flatpak: + install_flatpak (directory, verbose, allow_reinstall, allow_older, uninstall) + +if __name__ == '__main__': + args = parse_args() + if 'extract' in args.command: + if args.allow_reinstall: + error ("allow-reinstall argument doesn't make sense with command %s" % args.command) + if args.allow_older: + error ("allow-older argument doesn't make sense with command %s" % args.command) + if args.cleanup: + error ("Cleanup argument doesn't make sense with command %s" % args.command) + if args.directory is None: + error ("No directory specified") + if not os.path.exists (args.directory): + print ("Creating %s" % args.directory) + os.makedirs (args.directory) + unzip (args.directory) + else: + if args.directory: + error ("Directory argument %s doesn't make sense with command %s" % (args.directory, args.command)) + if os.getuid() != 0: + error ("This tool must be run as root") + with tempfile.TemporaryDirectory (prefix='fwupd') as target: + unzip (target) + run_installation (target, args.verbose, args.allow_reinstall, args.allow_older, args.cleanup) diff -Nru fwupd-1.0.6/contrib/standalone-installer/make.py fwupd-1.2.10/contrib/standalone-installer/make.py --- fwupd-1.0.6/contrib/standalone-installer/make.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/standalone-installer/make.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,138 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2017 Dell, Inc. +# +# SPDX-License-Identifier: LGPL-2.1+ +# +from base64 import b64encode +import io +import os +import subprocess +import shutil +import sys +import tempfile +import zipfile +from assets.header import TAG + +def error (msg): + print(msg) + sys.exit(1) + +def parse_args(): + import argparse + parser = argparse.ArgumentParser(description="Generate a standalone firmware updater") + parser.add_argument("--disable-snap-download", action='store_true', help="Don't download support for snap") + parser.add_argument("--disable-flatpak-download", action='store_true', help="Don't download support for flatpak") + parser.add_argument("--snap-channel", help="Channel to download snap from (optional)") + parser.add_argument("--minimum", help="Use already installed fwupd version if at least this version") + parser.add_argument("cab", help="CAB file or directory containing CAB files to automatically install") + parser.add_argument('target', help='target file to create') + args = parser.parse_args() + return args + +def bytes_slicer(length, source): + start = 0 + stop = length + while start < len(source): + yield source[start:stop] + start = stop + stop += length + +def generate_installer (directory, target): + asset_base = os.path.join (os.path.dirname(os.path.realpath(__file__)), + "assets") + + #header + shutil.copy (os.path.join (asset_base, "header.py"), target) + + #zip file + buffer = io.BytesIO() + archive = zipfile.ZipFile(buffer, "a") + for root, dirs, files in os.walk (directory): + for f in files: + source = os.path.join(root, f) + archive_fname = source.split (directory) [1] + archive.write(source, archive_fname) + if 'DEBUG' in os.environ: + print (archive.namelist()) + archive.close() + + with open (target, 'ab') as bytes_out: + encoded = b64encode(buffer.getvalue()) + for section in bytes_slicer(64, encoded): + bytes_out.write(TAG) + bytes_out.write(section) + bytes_out.write(b'\n') + +def download_snap (directory, channel): + cmd = ['snap', 'download', 'fwupd'] + if channel is not None: + cmd += ['--channel', channel] + if 'DEBUG' in os.environ: + print(cmd) + subprocess.run (cmd, cwd=directory, check=True) + for f in os.listdir (directory): + # the signatures associated with the snap + if f.endswith(".assert"): + shutil.move (os.path.join(directory, f), os.path.join(directory, 'fwupd.assert')) + # the snap binary itself + elif f.endswith(".snap"): + shutil.move (os.path.join(directory, f), os.path.join(directory, 'fwupd.snap')) + +def download_cab_file (directory, uri): + cmd = ['wget', uri] + if 'DEBUG' in os.environ: + print(cmd) + subprocess.run (cmd, cwd=directory, check=True) + +def download_flatpak (directory): + dep = 'org.freedesktop.fwupd' + flatpak_dir = os.path.join(os.getenv('HOME'),'.local', 'share', 'flatpak') + verbose = 'DEBUG' in os.environ + + #check if we have installed locally already or not + if not os.path.exists (os.path.join (flatpak_dir, 'app', dep)): + # install into local user's repo + cmd = ['flatpak', 'install', '--user', + 'https://www.flathub.org/repo/appstream/org.freedesktop.fwupd.flatpakref', '--no-deps', '-y'] + if verbose: + print(cmd) + subprocess.run (cmd, cwd=directory, check=True) + + # generate a bundle + repo = os.path.join(flatpak_dir, 'repo') + cmd = ['flatpak', 'build-bundle', repo, 'fwupd.flatpak', dep, 'stable'] + if verbose: + print(cmd) + subprocess.run (cmd, cwd=directory, check=True) + +if __name__ == '__main__': + args = parse_args() + + if not args.cab.startswith("http"): + local = args.cab + + with tempfile.TemporaryDirectory (prefix='fwupd') as directory: + if local: + if not os.path.exists (local): + error ("%s doesn't exist" % local) + if not os.path.isdir(local): + shutil.copy (local, directory) + else: + for root, dirs, files in os.walk(local): + for f in files: + shutil.copy (os.path.join(root, f), directory) + else: + download_cab_file (directory, args.cab) + + if not args.disable_snap_download: + download_snap (directory, args.snap_channel) + + if not args.disable_flatpak_download: + download_flatpak (directory) + + if args.minimum: + with open(os.path.join(directory, "minimum"), "w") as wfd: + wfd.write(args.minimum) + + generate_installer (directory, args.target) diff -Nru fwupd-1.0.6/contrib/standalone-installer/README.md fwupd-1.2.10/contrib/standalone-installer/README.md --- fwupd-1.0.6/contrib/standalone-installer/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/standalone-installer/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,9 @@ +# Standalone installer + +This is a script that will build a standalone installer around the fwupd snap or flatpak. +This can be used for distributing updates that use fwupd on machines without networking and the needed tools. + +For usage instructions, view: +``` +./make.py --help +``` diff -Nru fwupd-1.0.6/contrib/vscode/build.sh fwupd-1.2.10/contrib/vscode/build.sh --- fwupd-1.0.6/contrib/vscode/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/vscode/build.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,32 @@ +#!/bin/sh +# Copyright (C) 2018 Dell, Inc. + +SOURCE=$(dirname $0) +ROOT=$1 +if [ -z "$ROOT" ]; then + ROOT=`pwd` +fi + +# build in tree +rm -rf build ${ROOT}/dist +meson build --prefix=${ROOT}/dist -Dsystemd=false -Dudevdir=${ROOT}/dist +ninja -C build install + +#create helper scripts +TEMPLATE=${SOURCE}/launcher.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,libexec/fwupd/fwupd," \ + ${TEMPLATE} > ${ROOT}/dist/fwupd.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,libexec/fwupd/fwupdtool," \ + ${TEMPLATE} > ${ROOT}/dist/fwupdtool.sh +sed "s,#ROOT#,${ROOT},; s,#EXECUTABLE#,bin/fwupdmgr," \ + ${TEMPLATE} > ${ROOT}/dist/fwupdmgr.sh +chmod +x ${ROOT}/dist/*.sh + +#create debugging targets +TARGET=${ROOT}/.vscode +mkdir -p ${TARGET} +if [ -f ${TARGET}/launch.json ]; then + echo "${TARGET}/launch.json already exists, not overwriting" +else + cp ${SOURCE}/launch.json ${TARGET} +fi diff -Nru fwupd-1.0.6/contrib/vscode/launcher.sh fwupd-1.2.10/contrib/vscode/launcher.sh --- fwupd-1.0.6/contrib/vscode/launcher.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/vscode/launcher.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +export ROOT=#ROOT# +export FWUPD_LOCALSTATEDIR=${ROOT}/dist +export FWUPD_SYSCONFDIR=${ROOT}/dist/etc +if [ -n "${DEBUG}" ]; then + DEBUG="gdbserver localhost:9091" +fi +${DEBUG} ${ROOT}/dist/#EXECUTABLE# "$@" diff -Nru fwupd-1.0.6/contrib/vscode/launch.json fwupd-1.2.10/contrib/vscode/launch.json --- fwupd-1.0.6/contrib/vscode/launch.json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/vscode/launch.json 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,68 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "gdbserver (fwupdtool)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/libexec/fwupd/fwupdtool", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "gdbserver (fwupd)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/libexec/fwupd/fwupd", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "gdbserver (fwupdmgr)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/bin/fwupdmgr", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "miDebuggerServerAddress": "localhost:9091", + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + ] +} diff -Nru fwupd-1.0.6/contrib/vscode/README.md fwupd-1.2.10/contrib/vscode/README.md --- fwupd-1.0.6/contrib/vscode/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/contrib/vscode/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,39 @@ +# Using Visual Studio Code to debug + +This directory contains a collection of scripts and assets to make debugging using Visual Studio Code easier. + +## Preparing +First install the following applications locally: +* GDB Server +* GDB +* Visual Studio Code + +In Visual Studio code, visit the extension store and install *C/C++* which is an extension provided by Microsoft. +Configure Visual Studio code to open the folder representing the root of the fwupd checkout. + +## Building +Run `./contrib/debugging/build.sh` to build fwupd with all default options and create helper scripts pre-configured for debugger use. +The application will be placed into `./dist` and helper scripts will be created for `fwupdtool`, `fwupdmgr`, and `fwupd`. + +## Running +To run any of the applications, execute the appropriate helper script in `./dist`. + +## Debugging +To debug any of the applications, launch the helper script with the environment variable `DEBUG` set. +For example to debug `fwupdtool get-devices` the command to launch would be: + +``` +sudo DEBUG=1 ./dist/fwupdtool.sh get-devices +``` + +This will configure `gdbserver` to listen on a local port waiting for a debugger to connect. + +## Using Visual Studio code +During build time a set of launch targets will have been created for use with Visual Studio Code. + +Press the debugging button on the left and 3 targets will be listed at the top. +* gdbserver (fwupdtool) +* gdbserver (fwupd) +* gdbserver (fwupdmgr) + +Select the appropriate target and press the green arrow to connect to `gdbserver` and start debugging. diff -Nru fwupd-1.0.6/CONTRIBUTING.md fwupd-1.2.10/CONTRIBUTING.md --- fwupd-1.0.6/CONTRIBUTING.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/CONTRIBUTING.md 2019-07-15 18:25:54.000000000 +0000 @@ -18,7 +18,7 @@ * Prefer descriptive names over abbreviations (unless well-known) and shortening of names. e.g `device` not `dev` - * Single statments inside if/else should not be enclosed by '{}' + * Single statements inside if/else should not be enclosed by '{}' * Use comments to explain why something is being done, but also avoid over-documenting the obvious. Here is an example of useless comment: diff -Nru fwupd-1.0.6/COPYING fwupd-1.2.10/COPYING --- fwupd-1.0.6/COPYING 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/COPYING 2019-07-15 18:25:54.000000000 +0000 @@ -1,221 +1,397 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. -Activities other than copying, distribution and modification are not + Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - a) You must cause the modified files to carry prominent notices + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, +identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of +on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. +entire whole, and thus to each and every part regardless of who wrote +it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or -collective works based on the Program. +collective works based on the Library. -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not compelled to copy the source along with the object code. - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. - 5. You are not required to accept this License, since you have not + 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are +distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying -the Program or works based on it. +the Library or works based on it. - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to +You are not responsible for enforcing compliance by third parties with this License. - - 7. If, as a consequence of a court judgment or allegation of patent + + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. +refrain entirely from distribution of the Library. -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is +integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that @@ -226,114 +402,101 @@ This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - 8. If the distribution and/or use of the Program is restricted in + 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. NO WARRANTY - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. - + Copyright (C) - 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 2 of the License, or - (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU 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. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if +school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. - , 1 April 1989 + , 1 April 1990 Ty Coon, President of Vice -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +That's all there is to it! diff -Nru fwupd-1.0.6/data/90-fwupd-devices.rules fwupd-1.2.10/data/90-fwupd-devices.rules --- fwupd-1.0.6/data/90-fwupd-devices.rules 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/90-fwupd-devices.rules 2019-07-15 18:25:54.000000000 +0000 @@ -1,12 +1,8 @@ ######################################################################## # Copyright (C) 2015 Richard Hughes # -# Licensed under the GNU General Public License Version 2 +# SPDX-License-Identifier: LGPL-2.1+ # -# 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 2 of the License, or -# (at your option) any later version. # VIA USB 3.0 VL811 Hub SUBSYSTEM=="usb", DRIVER=="hub", ATTRS{idVendor}=="2109", ATTRS{idProduct}=="0810", ENV{FWUPD_GUID}="adbb9034-b577-42c2-a661-1ee4f49ef64c", ENV{FWUPD_VENDOR}="VIA", ENV{FWUPD_MODEL}="USB 3.0 VL811 Hub" @@ -25,3 +21,6 @@ # PCI cards with ROM SUBSYSTEM=="pci", TEST=="/sys$devpath/rom", ENV{FWUPD_GUID}="$attr{vendor}:$attr{device}" + +# NVMe hardware +SUBSYSTEM=="nvme", ENV{ID_VENDOR_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=pci" diff -Nru fwupd-1.0.6/data/bash-completion/fwupdagent fwupd-1.2.10/data/bash-completion/fwupdagent --- fwupd-1.0.6/data/bash-completion/fwupdagent 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/bash-completion/fwupdagent 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,37 @@ +_fwupdagent_cmd_list=( + 'get-devices' +) + +_fwupdagent_opts=( + '--verbose' +) + +_show_modifiers() +{ + COMPREPLY+=( $(compgen -W '${_fwupdagent_opts[@]}' -- "$cur") ) +} + +_fwupdagent() +{ + local cur prev command + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + command=${COMP_WORDS[1]} + + case $command in + *) + #find first command + if [[ ${COMP_CWORD} = 1 ]]; then + COMPREPLY=( $(compgen -W '${_fwupdagent_cmd_list[@]}' -- "$cur") ) + #modifiers for all commands + else + _show_modifiers + fi + ;; + esac + + return 0 +} + +complete -F _fwupdagent fwupdagent diff -Nru fwupd-1.0.6/data/bash-completion/fwupdmgr fwupd-1.2.10/data/bash-completion/fwupdmgr --- fwupd-1.0.6/data/bash-completion/fwupdmgr 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/bash-completion/fwupdmgr 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,26 @@ _fwupdmgr_cmd_list=( - 'build-firmware' + 'activate' 'clear-history' 'clear-offline' 'clear-results' + 'disable-remote' 'downgrade' + 'enable-remote' + 'get-approved-firmware' 'get-details' 'get-devices' 'get-history' 'get-releases' 'get-remotes' 'get-results' + 'get-topology' 'get-updates' - 'hwids' 'install' - 'install-prepared' + 'modify-config' 'modify-remote' - 'monitor' 'refresh' 'report-history' - 'smbios-dump' + 'set-approved-firmware' 'unlock' 'update' 'verify' @@ -33,9 +35,12 @@ '--allow-older' '--force' '--assume-yes' + '--no-history' '--no-unreported-check' '--no-metadata-check' '--no-reboot-check' + '--show-all-devices' + '--sign' ) _show_modifiers() @@ -69,14 +74,14 @@ command=${COMP_WORDS[1]} case $command in - clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update) + activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update) if [[ "$prev" = "$command" ]]; then _show_device_ids else _show_modifiers fi ;; - get-details|smbios-dump) + get-details) #browse for file if [[ "$prev" = "$command" ]]; then _filedir @@ -107,35 +112,39 @@ local keys keys="$(command fwupdmgr get-remotes | command awk -v pattern="Remote ID:.*${prev}$" '$0~pattern{show=1; next}/Remote/{show=0}{gsub(/:.*/,"")}show')" COMPREPLY+=( $(compgen -W "${keys}" -- "$cur") ) + #modifiers + else + _show_modifiers fi ;; - refresh) - #find first file + enable-remote) + #find remotes + if [[ "$prev" = "$command" ]]; then + _show_remotes + #modifiers + else + _show_modifiers + fi + ;; + disable-remote) + #find remotes if [[ "$prev" = "$command" ]]; then - _filedir - #find second file - elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then - _filedir - #find remote ID - elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then _show_remotes + #modifiers else _show_modifiers fi ;; - build-firmware) - #file in + refresh) + #find first file if [[ "$prev" = "$command" ]]; then _filedir - #file out + #find second file elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then _filedir - #script + #find remote ID elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then - _filedir - #output - elif [[ "$prev" = "${COMP_WORDS[4]}" ]]; then - _filedir + _show_remotes else _show_modifiers fi diff -Nru fwupd-1.0.6/data/bash-completion/fwupdtool.in fwupd-1.2.10/data/bash-completion/fwupdtool.in --- fwupd-1.0.6/data/bash-completion/fwupdtool.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/bash-completion/fwupdtool.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,111 @@ +_fwupdtool_cmd_list=( + 'activate' + 'build-firmware' + 'get-updates' + 'get-details' + 'get-devices' + 'get-history' + 'get-plugins' + 'get-topology' + 'hwids' + 'update' + 'install' + 'install-blob' + 'monitor' + 'self-sign' + 'smbios-dump' + 'attach' + 'detach' + 'verify-update' + 'watch' +) + +_fwupdtool_opts=( + '--verbose' + '--enable-json-state' + '--allow-reinstall' + '--allow-older' + '--force' + '--show-all-devices' + '--plugin-whitelist' + '--prepare' + '--cleanup' +) + +_show_plugins() +{ + local plugins + plugins="$(command @libexecdir@/fwupdtool get-plugins 2>/dev/null)" + COMPREPLY+=( $(compgen -W "${plugins}" -- "$cur") ) +} + +_show_modifiers() +{ + COMPREPLY+=( $(compgen -W '${_fwupdtool_opts[@]}' -- "$cur") ) +} + +_fwupdtool() +{ + local cur prev command + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + command=${COMP_WORDS[1]} + + case $prev in + --plugin-whitelist) + _show_plugins + return 0 + ;; + esac + + case $command in + get-details|install|install-blob) + #find files + if [[ "$prev" = "$command" ]]; then + _filedir + #modifiers + else + _show_modifiers + fi + ;; + attach|detach|activate|verify-update) + if [[ "$prev" = "$command" ]]; then + _show_device_ids + #modifiers + else + _show_modifiers + fi + ;; + build-firmware) + #file in + if [[ "$prev" = "$command" ]]; then + _filedir + #file out + elif [[ "$prev" = "${COMP_WORDS[2]}" ]]; then + _filedir + #script + elif [[ "$prev" = "${COMP_WORDS[3]}" ]]; then + _filedir + #output + elif [[ "$prev" = "${COMP_WORDS[4]}" ]]; then + _filedir + else + _show_modifiers + fi + ;; + *) + #find first command + if [[ ${COMP_CWORD} = 1 ]]; then + COMPREPLY=( $(compgen -W '${_fwupdtool_cmd_list[@]}' -- "$cur") ) + #modifiers for all commands + else + _show_modifiers + fi + ;; + esac + + return 0 +} + +complete -F _fwupdtool fwupdtool diff -Nru fwupd-1.0.6/data/bash-completion/meson.build fwupd-1.2.10/data/bash-completion/meson.build --- fwupd-1.0.6/data/bash-completion/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/bash-completion/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,5 +1,30 @@ -install_data([ - 'fwupdmgr', - ], - install_dir : 'share/bash-completion/completions/', -) +if bashcomp.found() + tgt = bashcomp.get_pkgconfig_variable('completionsdir', + define_variable: [ 'prefix', prefix ], + ) + + +if get_option('daemon') + install_data(['fwupdmgr'], + install_dir : tgt, + ) +endif + +if get_option('agent') + install_data(['fwupdagent'], + install_dir : tgt, + ) +endif + +# replace @libexecdir@ +fwupdtool_path = join_paths(libexecdir, 'fwupd') +con2 = configuration_data() +con2.set('libexecdir', fwupdtool_path) +configure_file( + input : 'fwupdtool.in', + output : 'fwupdtool', + configuration : con2, + install: true, + install_dir: tgt) + +endif diff -Nru fwupd-1.0.6/data/builder/README.md fwupd-1.2.10/data/builder/README.md --- fwupd-1.0.6/data/builder/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/builder/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -37,7 +37,7 @@ then the plugin can write to this directory and the startup.sh script will be able to access it as the chroot-ed `/boot`. -Firmware `.cab` files using this funtionality should list the `.tar` file: +Firmware `.cab` files using this functionality should list the `.tar` file: diff -Nru fwupd-1.0.6/data/daemon.conf fwupd-1.2.10/data/daemon.conf --- fwupd-1.0.6/data/daemon.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/daemon.conf 2019-07-15 18:25:54.000000000 +0000 @@ -10,3 +10,15 @@ # Maximum archive size that can be loaded in Mb, with 0 for the default ArchiveSizeMax=0 + +# Idle time in seconds to shut down the daemon -- note some plugins might +# inhibit the auto-shutdown, for instance thunderbolt. +# +# A value of 0 specifies 'never' +IdleTimeout=7200 + +# Comma separated list of domains to log in verbose mode +# If unset, no domains +# If set to FuValue, FuValue domain (same as --domain-verbose=FuValue) +# If set to *, all domains (same as --verbose) +VerboseDomains= diff -Nru fwupd-1.0.6/data/fwupd-offline-update.service.in fwupd-1.2.10/data/fwupd-offline-update.service.in --- fwupd-1.0.6/data/fwupd-offline-update.service.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/fwupd-offline-update.service.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,8 +1,13 @@ [Unit] Description=Updates device firmware whilst offline Documentation=man:fwupdmgr -OnFailure=reboot.target -ConditionPathExists=/var/lib/fwupd/pending.db +ConditionPathExists=@localstatedir@/lib/fwupd/pending.db +DefaultDependencies=false +Requires=sysinit.target dbus.socket +After=sysinit.target system-update-pre.target dbus.socket systemd-journald.socket +Before=shutdown.target system-update.target [Service] -ExecStart=@bindir@/fwupdmgr install-prepared +Type=oneshot +ExecStart=@libexecdir@/fwupd/fwupdoffline +FailureAction=reboot diff -Nru fwupd-1.0.6/data/fwupd.service.in fwupd-1.2.10/data/fwupd.service.in --- fwupd-1.0.6/data/fwupd.service.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/fwupd.service.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,20 +1,16 @@ [Unit] Description=Firmware update daemon -Documentation=http://www.fwupd.org/ +Documentation=https://fwupd.org/ After=dbus.service -Before=gdm.service +Before=display-manager.service [Service] Type=dbus BusName=org.freedesktop.fwupd ExecStart=@libexecdir@/fwupd/fwupd -MemoryDenyWriteExecute=yes PrivateTmp=yes -ProtectControlGroups=yes ProtectHome=yes -ProtectKernelModules=yes ProtectSystem=full RestrictAddressFamilies=AF_NETLINK AF_UNIX -RestrictRealtime=yes -ReadWritePaths=@localstatedir@/lib/fwupd @sysconfdir@/fwupd/remotes.d -@bootdir@ SystemCallFilter=~@mount +@dynamic_options@ diff -Nru fwupd-1.0.6/data/fwupd.shutdown.in fwupd-1.2.10/data/fwupd.shutdown.in --- fwupd-1.0.6/data/fwupd.shutdown.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/fwupd.shutdown.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,7 @@ +#!/bin/sh + +# no history database exists +[ -f @localstatedir@/lib/fwupd/pending.db ] || exit 0 + +# activate firmware when we have a read-only filesysten +@libexecdir@/fwupd/fwupdtool activate Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/data/installed-tests/firmware-example.xml.gz and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/data/installed-tests/firmware-example.xml.gz differ diff -Nru fwupd-1.0.6/data/installed-tests/firmware-example.xml.gz.asc fwupd-1.2.10/data/installed-tests/firmware-example.xml.gz.asc --- fwupd-1.0.6/data/installed-tests/firmware-example.xml.gz.asc 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/firmware-example.xml.gz.asc 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.14 (GNU/Linux) - -iQEcBAABAgAGBQJZQqy+AAoJEEim2A5FOLrCjuEH/1wIRvQ9FIUqQ2wV5pQRjF99 -wTd1+VtQCPHkBXvMnrF2cnhNhr13lN8BhuY3kgT9TGQCPNM+8akNvDLKWiR/39rP -z+v6KpgaYA5kghFskvW4t/1lQ+Jj+PKExb1bAusexdVvRD1iEDZ0q8u/DRGwrjYn -GFbHD3K91B4nIzYQVHa8+9gRRH2uKa2U9foH3++e/PAPQCoGHa6gxV3zM05AiEpA -Am5G5u8v5WnL9W9H53unj9M47iAlzdxStzK4poshlJoNITLw9SLl6rmrgMYLHVfD -QyZTM8jSjFc+V1swslLNMVCkCWfx3ClzkEff50HKua/BxMxxJscShX43On59cik= -=XhuO ------END PGP SIGNATURE----- diff -Nru fwupd-1.0.6/data/installed-tests/fwupdmgr.sh fwupd-1.2.10/data/installed-tests/fwupdmgr.sh --- fwupd-1.0.6/data/installed-tests/fwupdmgr.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/fwupdmgr.sh 2019-07-15 18:25:54.000000000 +0000 @@ -9,8 +9,8 @@ rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- -echo "Refreshing with dummy metadata..." -fwupdmgr refresh ${dirname}/firmware-example.xml.gz ${dirname}/firmware-example.xml.gz.asc lvfs +echo "Enabling fwupd-tests remote..." +fwupdmgr enable-remote fwupd-tests rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- @@ -20,7 +20,7 @@ # --- echo "Getting devices (should be one)..." -fwupdmgr get-devices +fwupdmgr get-devices --no-unreported-check rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi # --- diff -Nru fwupd-1.0.6/data/installed-tests/fwupd-tests.xml fwupd-1.2.10/data/installed-tests/fwupd-tests.xml --- fwupd-1.0.6/data/installed-tests/fwupd-tests.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/fwupd-tests.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,77 @@ + + + + fakedevice.firmware + FakeDevice Firmware + Firmware for the ACME Corp Integrated Webcam + ACME Corp + GPL-2.0+ +

Updating the firmware on your webcam device improves performance and adds new features.

+ http://www.acme.com/ + + + 17 + 1163 + ./fakedevice124.cab + fc0aabcf98bf3546c91270f2941f0acd0395dd79 + 2b8546ba805ad10bf8a2e5ad539d53f303812ba5 +

Fixes another bug with the flux capacitor to prevent time going backwards.

+
+ + 17 + 1153 + ./fakedevice123.cab + bc3c32f42cf33fe5aade64f999417251fd8208d3 + 7998cd212721e068b2411135e1f90d0ad436d730 +

Fixes a bug with the flux capacitor to avoid year 2038 overflow.

+
+
+ + b585990a-003e-5270-89d5-3705a17f9a43 + +
+ + com.hughski.ColorHug2.firmware + ColorHug2 + Firmware for the Hughski ColorHug2 Colorimeter + Hughski Limited + GPL-2.0+ +

Updating the firmware on your ColorHug2 device improves performance and adds new features.

+ http://www.hughski.com/ + + + 16384 + 19592 + hughski-colorhug2-2.0.7.cab + 490be5c0b13ca4a3f169bf8bc682ba127b8f7b96 + 658851e6f27c4d87de19cd66b97b610d100efe09 +

This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

+
+
+ + 2082b5e0-7a64-478a-b1b2-e3404fab6dad + +
+ + com.hughski.ColorHug.firmware + ColorHug + Firmware for the Hughski ColorHug Colorimeter + Hughski Limited + GPL-2.0+ +

Updating the firmware on your ColorHug device improves performance and adds new features.

+ http://www.hughski.com/ + + + 16384 + 18054 + hughski-colorhug-1.2.6.cab + 570a4259af0c7670f3883e84d2f4e6ff7de572c2 + 111784ffadfd5dd43f05655b266b5142230195b6 +

This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.

+
+
+ + 40338ceb-b966-4eae-adae-9c32edfcc484 + +
+
diff -Nru fwupd-1.0.6/data/installed-tests/hardware.py fwupd-1.2.10/data/installed-tests/hardware.py --- fwupd-1.0.6/data/installed-tests/hardware.py 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/hardware.py 2019-07-15 18:25:54.000000000 +0000 @@ -2,7 +2,8 @@ # pylint: disable=wrong-import-position,too-many-locals,unused-argument,wrong-import-order # # Copyright (C) 2017 Richard Hughes -# Licensed under the GNU General Public License Version 2 +# +# SPDX-License-Identifier: LGPL-2.1+ import gi import os @@ -39,10 +40,11 @@ return cachefn class Test: - def __init__(self, name, guid): + def __init__(self, name, guid, has_runtime=True): self.files = [] self.name = name self.guid = guid + self.has_runtime = has_runtime def run(self): @@ -67,13 +69,14 @@ client.install(dev.get_id(), fn_cache, flags, cancellable) # verify version - dev = _get_by_device_guid(client, self.guid) - if not dev: - raise GLib.Error('Device did not come back: ' + name) - if not dev.get_version(): - raise GLib.Error('No version set after flash for: ' + name) - if dev.get_version() != ver: - raise GLib.Error('Got: ' + dev.get_version() + ', expected: ' + ver) + if self.has_runtime: + dev = _get_by_device_guid(client, self.guid) + if not dev: + raise GLib.Error('Device did not come back: ' + self.name) + if not dev.get_version(): + raise GLib.Error('No version set after flash for: ' + self.name) + if dev.get_version() != ver: + raise GLib.Error('Got: ' + dev.get_version() + ', expected: ' + ver) # FIXME: wait for device to settle? time.sleep(2) @@ -87,7 +90,7 @@ # DFU A3BU XPLAINED Mouse test = Test('DfuXmegaA3BU-Xplained', '80478b9a-3643-5e47-ab0f-ed28abe1019d') - test.add_file('90c381f1c5932a7f9505372305a615ca000e68df-a3bu-xplained123.cab', '1.23') + test.add_file('f5bbeaba1037dce31dd12f349e8148ae35f98b61-a3bu-xplained123.cab', '1.23') test.add_file('24d838541efe0340bf67e1cc5a9b95526e4d3702-a3bu-xplained124.cab', '1.24') tests.append(test) @@ -115,12 +118,6 @@ test.add_file('0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab', '2.0.7') tests.append(test) - # Hughski ColorHugALS using 'colorhug' - test = Test('ColorHugALS', '84f40464-9272-4ef7-9399-cd95f12da696') - test.add_file('73ac1aa98130e532c727308cc6560783b10ca3a9-hughski-colorhug-als-4.0.2.cab', '4.0.2') - test.add_file('8dbdd54c712b33f72d866ce3b23b3ceed3ad494d-hughski-colorhug-als-4.0.3.cab', '4.0.3') - tests.append(test) - # Logitech Unifying Receiver (RQR12) using 'unifying' test = Test('UnifyingRQR12', '9d131a0c-a606-580f-8eda-80587250b8d6') test.add_file('6e5ab5961ec4c577bff198ebb465106e979cf686-Logitech-Unifying-RQR12.05_B0028.cab', 'RQR12.05_B0028') @@ -161,6 +158,16 @@ test.add_file('1cb9a0277f536ecd81ca1cea6fd80d60cdbbdcd8-8Bitdo-SFC30PRO_NES30PRO-4.01.cab', '4.01') tests.append(test) + # 8Bitdo SF30 Pro Gamepad + test = Test('8BitdoSF30Pro', '269b3121-097b-50d8-b9ba-d1f64f9cd241') + test.add_file('3d3a65ee2e8581647fb09d752fa7e21ee1566481-8Bitdo-SF30_Pro-SN30_Pro-1.26.cab', '1.26') + tests.append(test) + + # AIAIAI H05 + test = Test('AIAIAI-H05', '7e8318e1-27ae-55e4-a7a7-a35eff60e9bf', has_runtime=False) + test.add_file('84279d6bab52262080531acac701523604f3e649-AIAIAI-H05-1.6.cab', '1.6') + tests.append(test) + # run each test rc = 0 for test in tests: diff -Nru fwupd-1.0.6/data/installed-tests/meson.build fwupd-1.2.10/data/installed-tests/meson.build --- fwupd-1.0.6/data/installed-tests/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -13,39 +13,44 @@ install_data([ 'fwupdmgr.sh', - 'firmware-example.xml.gz', - 'firmware-example.xml.gz.asc', + 'fwupd-tests.xml', 'hardware.py', ], install_dir : 'share/installed-tests/fwupd', ) -gcab = find_program('gcab', required : false) -if gcab.found() - custom_target('installed-cab123', - input : [ - 'fakedevice123.bin', - 'fakedevice123.bin.asc', - 'fakedevice123.metainfo.xml', - ], - output : 'fakedevice123.cab', - command : [ - gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', - ], - install: true, - install_dir: join_paths('share', 'installed-tests', 'fwupd'), - ) - custom_target('installed-cab124', - input : [ - 'fakedevice124.bin', - 'fakedevice124.bin.asc', - 'fakedevice124.metainfo.xml', - ], - output : 'fakedevice124.cab', - command : [ - gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', - ], - install: true, - install_dir: join_paths('share', 'installed-tests', 'fwupd'), - ) -endif +custom_target('installed-cab123', + input : [ + 'fakedevice123.bin', + 'fakedevice123.bin.asc', + 'fakedevice123.metainfo.xml', + ], + output : 'fakedevice123.cab', + command : [ + gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', + ], + install: true, + install_dir: join_paths('share', 'installed-tests', 'fwupd'), +) +custom_target('installed-cab124', + input : [ + 'fakedevice124.bin', + 'fakedevice124.bin.asc', + 'fakedevice124.metainfo.xml', + ], + output : 'fakedevice124.cab', + command : [ + gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', + ], + install: true, + install_dir: join_paths('share', 'installed-tests', 'fwupd'), +) + +# replace @installedtestsdir@ +configure_file( + input : 'remote.conf.in', + output : 'fwupd-tests.conf', + configuration : con2, + install: true, + install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), +) diff -Nru fwupd-1.0.6/data/installed-tests/README.md fwupd-1.2.10/data/installed-tests/README.md --- fwupd-1.0.6/data/installed-tests/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,78 @@ +Installed tests +========= + +A test suite that can be used to interact with a fake device is installed when +configured with `-Ddaemon=true` and `-Dtests=true`. + +By default this test suite is disabled. + +Enabling +======= +To enable the test suite: +1. Modify `/etc/fwupd/daemon.conf` to remove the `test` plugin from `BlacklistPlugins` + ``` + # sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + ``` +2. Enable the `fwupd-tests` remote for local CAB files. + ``` + # fwupdmgr enable-remote fwupd-tests + ``` + +Using test suite +===== +When the daemon is started with the test suite enabled a fake webcam device will be created with a pending update. + +``` +Integrated Webcam™ + DeviceId: 08d460be0f1f9f128413f816022a6439e0078018 + Guid: b585990a-003e-5270-89d5-3705a17f9a43 + Summary: A fake webcam + Plugin: test + Flags: updatable|supported|registered + Vendor: ACME Corp. + VendorId: USB:0x046D + Version: 1.2.2 + VersionLowest: 1.2.0 + VersionBootloader: 0.1.2 + Icon: preferences-desktop-keyboard + Created: 2018-11-29 +``` + +## Upgrading +This can be upgraded to a firmware version `1.2.4` by using `fwupdmgr update` or any fwupd frontend. + +``` +$ fwupdmgr get-updates +Integrated Webcam™ has firmware updates: +GUID: b585990a-003e-5270-89d5-3705a17f9a43 +ID: fakedevice.firmware +Update Version: 1.2.4 +Update Name: FakeDevice Firmware +Update Summary: Firmware for the ACME Corp Integrated Webcam +Update Remote ID: fwupd-tests +Update Checksum: SHA1(fc0aabcf98bf3546c91270f2941f0acd0395dd79) +Update Location: ./fakedevice124.cab +Update Description: Fixes another bug with the flux capacitor to prevent time going backwards. + +$ fwupdmgr update +Decompressing… [***************************************] +Authenticating… [***************************************] +Updating Integrated Webcam™… ] +Verifying… [***************************************] Less than one minute remaining… +``` + +## Downgrading +It can also be downgraded to firmware version `1.2.3`. +``` +$ fwupdmgr downgrade +Choose a device: +0. Cancel +1. 08d460be0f1f9f128413f816022a6439e0078018 (Integrated Webcam™) +2. 8a21cacfb0a8d2b30c5ee9290eb71db021619f8b (XPS 13 9370 System Firmware) +3. d10c5f0ed12c6dc773f596b8ac51f8ace4355380 (XPS 13 9370 Thunderbolt Controller) +1 +Decompressing… [***************************************] +Authenticating… [***************************************] +Downgrading Integrated Webcam™… \ ] +Verifying… [***************************************] Less than one minute remaining… +``` diff -Nru fwupd-1.0.6/data/installed-tests/remote.conf.in fwupd-1.2.10/data/installed-tests/remote.conf.in --- fwupd-1.0.6/data/installed-tests/remote.conf.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/installed-tests/remote.conf.in 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,9 @@ +[fwupd Remote] +# This is a local fwupd remote that is used only for installed tests +# either from continuous integration or for fake devices from fwupd +# frontends + +Enabled=false +Title=fwupd test suite +Keyring=none +MetadataURI=file://@installedtestsdir@/fwupd-tests.xml diff -Nru fwupd-1.0.6/data/meson.build fwupd-1.2.10/data/meson.build --- fwupd-1.0.6/data/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -5,6 +5,8 @@ if get_option('tests') subdir('tests') +endif +if get_option('daemon') subdir('installed-tests') endif @@ -16,38 +18,49 @@ install_dir: join_paths(datadir, 'metainfo') ) -install_data(['org.freedesktop.fwupd.conf'], - install_dir : join_paths(sysconfdir, 'dbus-1', 'system.d') +install_data(['org.freedesktop.fwupd.svg'], + install_dir : join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps') ) -install_data(['metadata.xml'], - install_dir : join_paths(datadir, 'fwupd', 'remotes.d', 'fwupd') -) - -install_data(['90-fwupd-devices.rules'], - install_dir : join_paths(udevdir, 'rules.d') +install_data(['org.freedesktop.fwupd.conf'], + install_dir : join_paths(sysconfdir, 'dbus-1', 'system.d') ) -con2 = configuration_data() -con2.set('libexecdir', libexecdir) -con2.set('bindir', bindir) -con2.set('localstatedir', localstatedir) -con2.set('datadir', datadir) -con2.set('bootdir', get_option('bootdir')) -con2.set('sysconfdir', default_sysconfdir) - -# replace @libexecdir@ -configure_file( - input : 'org.freedesktop.fwupd.service.in', - output : 'org.freedesktop.fwupd.service', - configuration : con2, - install: true, - install_dir: join_paths(datadir, - 'dbus-1', - 'system-services'), -) +if get_option('daemon') + install_data(['90-fwupd-devices.rules'], + install_dir : join_paths(udevdir, 'rules.d') + ) +endif if get_option('systemd') + con2 = configuration_data() + con2.set('libexecdir', libexecdir) + con2.set('bindir', bindir) + con2.set('datadir', datadir) + con2.set('localstatedir', localstatedir) + + rw_directories = [] + rw_directories += join_paths (localstatedir, 'lib', 'fwupd') + rw_directories += join_paths (sysconfdir, 'fwupd') + rw_directories += join_paths (sysconfdir, 'fwupd', 'remotes.d') + if get_option('plugin_uefi') + rw_directories += ['-/boot/efi', '-/efi/EFI', '-/boot/EFI'] + endif + + dynamic_options = [] + if systemd.version().version_compare('>= 232') + dynamic_options += 'ProtectControlGroups=yes' + dynamic_options += 'ProtectKernelModules=yes' + endif + if systemd.version().version_compare('>= 231') + dynamic_options += 'RestrictRealtime=yes' +# dynamic_options += 'MemoryDenyWriteExecute=yes' + dynamic_options += ['ReadWritePaths=' + ' '.join(rw_directories)] + else + dynamic_options += ['ReadWriteDirectories=' + ' '.join(rw_directories)] + endif + con2.set('dynamic_options', '\n'.join(dynamic_options)) + # replace @bindir@ configure_file( input : 'fwupd-offline-update.service.in', @@ -56,10 +69,8 @@ install: true, install_dir: systemdunitdir, ) -endif -if get_option('systemd') - # replace @localstatedir@, @sysconfdir@ and @bootdir@ + # replace @dynamic_options@ configure_file( input : 'fwupd.service.in', output : 'fwupd.service', @@ -67,4 +78,29 @@ install: true, install_dir: systemdunitdir, ) + + # for activation + configure_file( + input : 'fwupd.shutdown.in', + output : 'fwupd.shutdown', + configuration : con2, + install: true, + install_dir: systemd.get_pkgconfig_variable('systemdshutdowndir'), + ) +endif + +if get_option('systemd') or get_option('elogind') + con2 = configuration_data() + con2.set('libexecdir', libexecdir) + + # replace @libexecdir@ + configure_file( + input : 'org.freedesktop.fwupd.service.in', + output : 'org.freedesktop.fwupd.service', + configuration : con2, + install: true, + install_dir: join_paths(datadir, + 'dbus-1', + 'system-services'), + ) endif diff -Nru fwupd-1.0.6/data/metadata.xml fwupd-1.2.10/data/metadata.xml --- fwupd-1.0.6/data/metadata.xml 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/metadata.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ - - - - - - UEFI-dummy-dev0 - - 2d47f29b-83a2-4f31-a2e8-63474f4d4c2e - - UEFI Updates - Enable UEFI Update Functionality - - - -

- Applying this update will enable the UEFI firmware reporting interface on your hardware. -

-

- You will have to restart your computer after this update is installed - to be notified of any pending firmware updates. -

-
-
-
-
- - - - com.via.VL811.firmware - - adbb9034-b577-42c2-a661-1ee4f49ef64c - - VL811 Firmware - Firmware for VIA USB 3.0 hub - VIA - http://www.via.com.tw/ - - - -

This stable release fixes the following problems with USB 3.0:

-
    -
  • Do not wake during transition to S4
  • -
  • Do not drop from Apple USB 3.0 Host during S3/S4 and Device PnP
  • -
  • Do not drop during S3/S4 when connected to native Intel and AMD Hosts
  • -
-

This stable release fixes the following problems with USB 2.0:

-
    -
  • Do not drop from Apple USB 3.0 Host during S3/S4 and Device PnP
  • -
-
-
-
-
- - - - com.via.VL811+.firmware - - 54f84d05-c917-4c50-8b35-44feabaaa323 - - VL811+ Firmware - Firmware for VIA USB 3.0 hub - VIA - http://www.via.com.tw/ - - - - - - - - com.via.VL812.firmware - - cd0314ec-b80f-4d1a-a24f-c409183a8b2d - - VL812 Firmware - Firmware for VIA USB 3.0 hub - VIA - http://www.via.com.tw/ - - - - - - - - com.via.VL812_B2.firmware - - 26470009-97a8-4028-867a-bbbac6ee7bf0 - - VL812 B2 Firmware - Firmware for VIA USB 3.0 hub - VIA - http://www.via.com.tw/ - - - - -
diff -Nru fwupd-1.0.6/data/org.freedesktop.fwupd.metainfo.xml fwupd-1.2.10/data/org.freedesktop.fwupd.metainfo.xml --- fwupd-1.0.6/data/org.freedesktop.fwupd.metainfo.xml 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/org.freedesktop.fwupd.metainfo.xml 2019-07-15 18:25:54.000000000 +0000 @@ -1,9 +1,9 @@ - + org.freedesktop.fwupd CC0-1.0 - GPL-2.0+ + LGPL-2.0+ fwupd Update device firmware on Linux @@ -21,10 +21,1260 @@

https://github.com/hughsie/fwupd/issues - - - http://www.fwupd.org/ + https://fwupd.org/ https://www.transifex.com/freedesktop/fwupd/ richard_at_hughsie.com fwupd + + moderate + + + fwupdmgr + + + + +

This release adds the following features:

+
    +
  • Add a new experimental plugin that supports libflashrom
  • +
  • Add a specific error code for the low battery case
  • +
  • Add support for 8bitdo USB Retro Receiver
  • +
  • Export new API to build objects from GVariant blobs
  • +
  • Show a warning when running in UEFI legacy mode
  • +
  • Support a UEFI quirk to disable the use of the UX capsule
  • +
+

This release fixes the following bugs:

+
    +
  • Fix installing synaptics-prometheus config updates
  • +
  • Fix the supported list of Wacom tablets
  • +
  • Never set an empty device name
  • +
  • Prompt for reboot when unlocking on the command line if applicable
  • +
  • Show devices with an UpdateError in get-devices output
  • +
  • Support empty proxy server strings
  • +
  • Try harder to find duplicate UEFI boot entries
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for Synaptics Prometheus fingerprint readers
  • +
  • Check if VersionFormat is ambiguous when adding devices
  • +
  • Check the daemon version is at least the client version
  • +
  • Export the version-format used by devices to clients
  • +
  • Set the version format for more device types
  • +
+

This release fixes the following bugs:

+
    +
  • Allow using --force to trigger a duplicate offline update
  • +
  • Be smarter about existing installed fwupd when using standalone-installer
  • +
  • Correctly identify DFU firmware that starts at offset zero
  • +
  • Display the remote warning on the console in an easy-to-read way
  • +
  • Fix a libasan failure when reading a UEFI variable
  • +
  • Never guess the version format from the version string
  • +
  • Only use class-based instance IDs for quirk matching
  • +
  • Prompt the user to shutdown if requried when installing by ID
  • +
  • Reset the forced version during DFU attach and detach
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Allow the fwupdmgr tool to modify the daemon config
  • +
+

This release fixes the following bugs:

+
    +
  • Correctly parse DFU interfaces with extra vendor-specific data
  • +
  • Do not report transient or invalid system failures
  • +
  • Fix problems with the version format checking for some updates
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a component categories to express the firmware type
  • +
  • Add support for 8BitDo M30
  • +
  • Add support for the not-child extension from Logitech
  • +
  • Shut down the daemon if the on-disk binary is replaced
  • +
+

This release fixes the following bugs:

+
    +
  • Blacklist the synapticsmst plugin when using amdgpu
  • +
  • Correct ATA activation functionality to work for all vendors
  • +
  • Implement QMI PDC active config selection for modems
  • +
  • Make an error message clearer when there are no updates available
  • +
  • Match the old or new version number when setting NEEDS_REBOOT
  • +
  • More carefully check the output from tpm2_pcrlist
  • +
  • Recreate the history database if migration failed
  • +
  • Require AC power when updating Thunderbolt devices
  • +
  • Require --force to install a release with a different version format
  • +
  • Save history from firmware installed with fwupdtool
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin to support modem hardware
  • +
  • Add support for delayed activation of docks and ATA devices
  • +
  • Add support for reading the SuperIO device checksum and writing to e-flash
  • +
  • Add the fwupdagent binary for use in shell scripts
  • +
  • Allow restricting firmware updates for enterprise use
  • +
  • Allow signing the fwupd report with a client certificate
  • +
  • Use Plymouth when updating offline firmware
  • +
+

This release fixes the following bugs:

+
    +
  • Allow forcing an offline-only update on a live system using --force
  • +
  • Allow running offline updates when in system-update.target
  • +
  • Ask to reboot after scheduling an offline firmware update
  • +
  • Correctly check the new version for devices that replug
  • +
  • Do not fail to start the daemon if tpm2_pcrlist hangs
  • +
  • Do not fail when scheduling more than one update to be run offline
  • +
  • Do not let failing to find DBus prevent fwuptool from starting
  • +
  • Do not schedule an update on battery power if it requires AC power
  • +
  • Include all device checksums in the LVFS report
  • +
  • Rename the shimx64.efi binary for known broken firmware
  • +
  • Upload the UPDATE_INFO entry for the UEFI UX capsule
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Allow a device to be updated using more than one plugin
  • +
  • Report the DeviceInstanceIDs from fwupdmgr when run as root
  • +
+

This release fixes the following bugs:

+
    +
  • Add an extra check for Dell NVMe drives to avoid false positives
  • +
  • Call composite prepare and cleanup using fwupdtool
  • +
  • Correct handling of CAB files with nested directories
  • +
  • Detect and special case Dell ATA hardware
  • +
  • Do not fail fwupdtool if dbus is unavailable
  • +
  • Do not unconditionally enable Werror for the EFI binary
  • +
  • Fill holes when reading SREC files
  • +
  • Filter the last supported payloads of certain Dell docks
  • +
  • Fix flashing failure with latest Intuos Pro tablet
  • +
  • Fix potential segfault when applying UEFI updates
  • +
  • Fix unifying regression when recovering from failed flash
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a directory remote that generates metadata
  • +
  • Add a new remote type "directory"
  • +
  • Add a plugin to update Wacom embedded EMR and AES panels
  • +
  • Add a plugin to upgrade firmware on ATA-ATAPI hardware
  • +
  • Add a quirk to use the legacy bootmgr description
  • +
  • Add flag to support manually aligning the NVMe firmware to the FWUG value
  • +
  • Add SuperIO IT89xx device support
  • +
  • Add support for Dell dock passive flow
  • +
  • Add 'update' and 'get-updates' commands to fwupdtool
  • +
  • Allow Dell dock flashing Thunderbolt over I2C
  • +
  • Check the battery percentage before flashing
  • +
  • Show a per-release source and details URL
  • +
  • Show a `UpdateMessage` and display it in tools
  • +
+

This release fixes the following bugs:

+
    +
  • Add the needs-shutdown quirk to Phison NVMe drives
  • +
  • Correct Nitrokey Storage invalid firmware version read
  • +
  • Do not check the BGRT status before uploading a UX capsule
  • +
  • Do the UEFI UX checksum calculation in fwupd
  • +
  • Fix flashing various Jabra devices
  • +
  • Fix the parser to support extended segment addresses
  • +
  • Flash the fastboot partition after downloading the file
  • +
  • Show a console warning if loading an out-of-tree plugin
  • +
  • Support FGUID to get the SKU GUID for NVMe hardware
  • +
+
+
+ + +

This release fixes the following bug:

+
    +
  • Correctly migrate the history database
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for devices that support fastboot
  • +
  • Add more standard USB identifier GUIDs
  • +
  • Add new API to get the release protocol from the metadata
  • +
  • Add the PCR0 value as the device checksum for system firmware
  • +
  • Include the device firmware checksum and update protocol in the report
  • +
+

This release fixes the following bugs:

+
    +
  • Add Dell TB18DC to the supported devices list
  • +
  • Allow replacing the last byte in the image when using 'dfu-tool replace-data'
  • +
  • Append the UEFI capsule header in userspace rather than in the loader
  • +
  • Check the device checksum as well as the content checksum during verify
  • +
  • Correctly parse format the version numbers correctly using old metadata
  • +
  • Fix a crash if AMT returns an empty response
  • +
  • Fix a regression when doing GetReleases on unsupported hardware
  • +
  • Fix the 8bitdo version number if the daemon locale is not C.UTF-8
  • +
  • Remove the Wacom DTH generation hardware from the whitelist
  • +
  • Sanitize the version if the version format has been specified
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add per-release install duration values
  • +
  • Shut down the daemon after 2h of inactivity when possible
  • +
+

This release fixes the following bugs:

+
    +
  • Fix a use-after-free when using --immediate-exit
  • +
  • Fix flashing the 8bitdo SF30
  • +
  • Fix showing the custom remote agreements
  • +
  • Include the os-release information in the release metadata
  • +
  • Speed up startup by loading less thunderbolt firmware
  • +
  • Speed up startup by using a silo index for GUID queries
  • +
  • Use less memory and fragment the heap less when starting
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin for an upcoming Dell USB-C dock
  • +
  • Add a standalone installer creation script
  • +
  • Add support for devices to show an estimated flash time
  • +
  • Add support for some new Realtek USB devices
  • +
  • Allow firmware files to depend on versions from other devices
  • +
  • Allow setting the version format from a quirk entry
  • +
  • Port from libappstream-glib to libxmlb for a large reduction in RSS
  • +
  • Stop any running daemon over dbus when using fu-tool
  • +
  • Support the Intel ME version format
  • +
+

This release fixes the following bugs:

+
    +
  • Add version format quirks for several Lenovo machines
  • +
  • Adjust panamera ESM update routine for some reported issues
  • +
  • Adjust synapticsmst EVB board handling
  • +
  • Check the amount of free space on the ESP
  • +
  • Don't show devices pending a reboot in GetUpgrades
  • +
  • Ensure that parent ID is created before creating quirked children
  • +
  • Optionally wait for replug before updating a device
  • +
  • Set the full AMT device version including the BuildNum
  • +
  • Sort the firmware sack by component priority
  • +
  • Stop showing errors when no Dell dock plugged in
  • +
  • Stop showing the current release during updates in fwupdmgr
  • +
  • Update all sub-devices for a composite update
  • +
  • Use HTTPS_PROXY if set
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • + Add a new device flag 'ignore-validation' that will + override checks +
  • +
  • Add a new plugin to enumerate EC firmware
  • +
  • Add a new plugin to update NVMe hardware
  • +
  • Add a plugin for updating using the flashrom command line tool
  • +
  • Allow the device list to take care of waiting for the device replug
  • +
  • Allow updating just one specific device from the command line
  • +
  • Allow upgrades using a self-signed fwupd.efi binary
  • +
  • Download firmware if the user specifies a URI
  • +
  • Include serial number in daemon device output when trusted
  • +
  • Notify all plugins of device removals through a new vfunc
  • +
  • Use boltd force power API if available
  • +
+

This release fixes the following bugs:

+
    +
  • Add an install hook for classic snap
  • +
  • Allow forcing installation even if no AC power is applied
  • +
  • Allow using --force to ignore version_lowest
  • +
  • Always use the same HardwareIDs as Windows
  • +
  • Check the device state before assuming a fake DFU runtime
  • +
  • Copy over parent GUIDs from other plugin donors
  • +
  • Detect location of python3 interpreter
  • +
  • Do not add udev devices after a small delay
  • +
  • Don't fail to run if compiled without GPG/PKCS7
  • +
  • Fix a segfault in fwupdtool caused by cleanup of USB plugins
  • +
  • Implement the systemd recommendations for offline updates
  • +
  • Improve performance when reading keys from the quirk database
  • +
  • Remove children of devices when the parent is removed
  • +
  • Rewrite synapticsmst to use modern error handling
  • +
  • + Rewrite the unifying plugin to use the new daemon-provided + functionality +
  • +
  • Show a time estimate on the progressbar after an update has started
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for the Synaptics Panamera hardware
  • +
  • Add validation for Alpine and Titan Ridge
  • +
  • Improve the Redfish plugin to actually work with real hardware
  • +
+

This release fixes the following bugs:

+
    +
  • Allow different plugins to add the same device
  • +
  • Allow flashing unifying devices in recovery mode
  • +
  • Allow running synapticsmst on non-Dell hardware
  • +
  • Check the ESP for sanity at startup
  • +
  • Do not hold hidraw devices open forever
  • +
  • Don't override _FORTIFY_SOURCE when building the EFI binary
  • +
  • Don't show passwords in fwupdmgr
  • +
  • Fix a potential segfault in smbios data parsing
  • +
  • Fix encoding the GUID into the capsule EFI variable
  • +
  • Fix various bugs when reading the thunderbolt version number
  • +
  • Reboot synapticsmst devices at the end of flash cycle
  • +
  • Show status messages when the daemon is initializing
  • +
  • Show the correct title when updating devices
  • +
  • Show the reasons that plugins are not run on the CLI
  • +
  • Use localedir in po/make-images
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a initial Redfish support
  • +
  • Add a tool to mimic the original fwupdate CLI interface
  • +
  • Allow devices to assign a plugin from the quirk subsystem
  • +
  • Change the quirk file structure to be more efficient
  • +
  • Merge fwupdate functionality into fwupd
  • +
  • + Run a plugin vfunc before and after all the composite devices are + updated +
  • +
  • Support more Wacom tablets
  • +
+

This release fixes the following bugs:

+
    +
  • Add release information for locked devices
  • +
  • Allow building with older meson
  • +
  • Detect the EFI system partition location at runtime
  • +
  • Do not use 8bitdo bootloader commands after a successful flash
  • +
  • Enable accessing downloaded files in flatpak and snap
  • +
  • Fix a potential buffer overflow when applying a DFU patch
  • +
  • Fix downgrading older releases to devices
  • +
  • Fix flashing devices that require a manual replug
  • +
  • Fix several small memory leaks in various places
  • +
  • Fix the retrieval of Redfish version
  • +
  • Fix unifying failure to detach when using a slow host controller
  • +
  • Set the Wacom device status when erasing and writing firmware
  • +
  • Show errors in the CLI if unable to access directory
  • +
  • Use the parent device name for Wacom sub-modules
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin to update some future Wacom tablets
  • +
  • Add 'fwupdmgr get-topology' to show logical device tree
  • +
  • Add support for creating a flatpak
  • +
  • Add support for creating a snap
  • +
  • Add support for Motorola S-record files
  • +
  • Add the Linux Foundation public GPG keys for firmware and metadata
  • +
  • Show a translated warning when the server is limiting downloads
  • +
+

This release fixes the following bugs:

+
    +
  • Add a firmware diagnostic tool called fwupdtool
  • +
  • Adjust all licensing to LGPL 2.1+
  • +
  • + Allow installing more than one firmware using 'fwupdmgr + install' +
  • +
  • Allow specifying hwids with OR relationships
  • +
  • Do not call fu_plugin_init() on blacklisted plugins
  • +
  • Do not require libcolorhug to build
  • +
  • Fix a crash in libfwupd where no device ID is set
  • +
  • Fix a potential DoS in libdfu by limiting holes to 1MiB
  • +
  • Fix a segfault that sometimes occurs during cleanup of USB plugins
  • +
  • Fix Hardware-ID{0,1,2,12} compatibility with Microsoft
  • +
  • Hide devices that aren't updatable by default in fwupdmgr
  • +
  • Search all UEFI GUIDs when matching hardware
  • +
  • Stop matching Nintendo Switch Pro in the 8bitdo plugin
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add enable-remote and disable-remote commands to fwupdmgr
  • +
  • Add fu_plugin_add_compile_version() for libraries to use
  • +
  • Allow requiring specific versions of libraries for firmware updates
  • +
  • If no remotes are enabled try to enable the LVFS
  • +
  • Show a warning with interactive prompt when enabling a remote
  • +
+

This release fixes the following bugs:

+
    +
  • Check that EFI system partition is mounted before update
  • +
  • Disable synapticsmst remote control on failure
  • +
  • Don't recoldplug thunderbolt to fix a flashing failure
  • +
  • Fix SQL error when running 'fwupdmgr clear-offline'
  • +
  • Improve the update report message
  • +
  • Only enumerate Dell Docks if the type is known
  • +
  • Only run certtool if a new enough gnutls is present
  • +
  • Prevent a client crash if the daemon somehow sends invalid data
  • +
  • Reboot after scheduling using logind not systemd
  • +
  • Use the right encoding for the label in make-images
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add bash completion for fwupdmgr
  • +
  • Add support for newest Thunderbolt chips
  • +
  • Allow all functions that take device arguments to be prompted
  • +
  • Allow devices to use the runtime version when in bootloader mode
  • +
  • Allow overriding ESP mount point via conf file
  • +
  • Delete any old fwupdate capsules and efivars when launching fwupd
  • +
  • Generate Vala bindings
  • +
+

This release fixes the following bugs:

+
    +
  • Allow ctrl-d out of the prompt for devices
  • +
  • Allow to create package out of provided binary
  • +
  • Correct handling of unknown Thunderbolt devices
  • +
  • Correctly detect new remotes that are manually copied
  • +
  • Fix a crash related to when passing device to downgrade in CLI
  • +
  • Fix running the self tests when no fwupd is installed
  • +
  • Fix Unifying signature writing and parsing for Texas bootloader
  • +
  • Only send success and failure reports to the server
  • +
  • Use a CNAME to redirect to the correct CDN for metadata
  • +
  • Use a longer timeout when powering back the Thunderbolt device
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Offer to reboot when processing an offline update
  • +
  • Report the efivar, libsmbios and fwupdate library versions
  • +
  • Report Thunderbolt safe mode and SecureBoot status
  • +
  • Show the user a URL when they report a known problem
  • +
  • Support split cabinet archives as produced by Windows Update
  • +
+

This release fixes the following bugs:

+
    +
  • Be more careful deleting and modifying device history
  • +
  • Clarify which devices don't have upgrades
  • +
  • Ensure the Thunderbolt version is xx.yy
  • +
  • Fix a daemon warning when using fwupdmgr get-results
  • +
  • Fix crash with MST flashing
  • +
  • Fix DFU detach with newer releases of libusb
  • +
  • Include the device VID and PID when generating the device-id
  • +
  • Set the RemoteId when using GetDetails
  • +
  • Stop matching 8bitdo DS4 controller VID/PID
  • +
  • Use help2man for dfu-tool and drop docbook dependencies
  • +
  • Use ngettext for any strings with plurals
  • +
  • Use the default value if ArchiveSizeMax is unspecified
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add D-Bus methods to get and modify the history information
  • +
  • Allow the user to share firmware update success or failure
  • +
  • Ask the user to refresh metadata when it is very old
  • +
  • Store firmware update success and failure to a local database
  • +
+

This release fixes the following bugs:

+
    +
  • Add a device name for locked UEFI devices
  • +
  • Allow each plugin to opt-in to the recoldplug action
  • +
  • Fix firmware downloading using gnome-software
  • +
  • Fix UX capsule reference to the one specified in efivar
  • +
  • Never add two devices to the daemon with the same ID
  • +
  • Rescan supported flags when refreshing metadata
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a new plugin to add support for CSR 'Driverless DFU'
  • +
  • Add initial SF30/SN30 Pro support
  • +
  • Support AppStream metadata with relative <location> URLs
  • +
+

This release fixes the following bugs:

+
    +
  • Add more metadata to the user-agent string
  • +
  • Block owned Dell TPM updates
  • +
  • Choose the correct component from provides matches using requirements
  • +
  • Do not try to parse huge compressed archive files
  • +
  • Fix a double-free bug in the Udev code
  • +
  • Handle Thunderbolt 'native' mode
  • +
  • + Use the new functionality in libgcab >= 1.0 to avoid writing temp + files +
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a plugin for the Nitrokey Storage device
  • +
  • Add support for the original AVR DFU protocol
  • +
  • Allow different plugins to claim the same device
  • +
  • Allow quirks to set common USB properties
  • +
  • Move a common plugin functionality out to a new shared object
  • +
  • Optionally delay the device removal for better replugging
  • +
  • Set environment variables to allow easy per-plugin debugging
  • +
  • Use a SHA1 hash for the internal DeviceID
  • +
+

This release fixes the following bugs:

+
    +
  • Add quirk for AT32UC3B1256 as used in the RubberDucky
  • +
  • Disable the dell plugin if libsmbios fails
  • +
  • Don't register for USB UDev events to later ignore them
  • +
  • Fix a possible buffer overflow when debugging ebitdo devices
  • +
  • Fix critical warning when more than one remote fails to load
  • +
  • Fix DFU attaching AVR32 devices like the XMEGA
  • +
  • Ignore useless Thunderbolt device types
  • +
  • Refactor ColorHug into a much more modern plugin
  • +
  • Release the Steelseries interface if getting the version failed
  • +
  • Remove autoconf-isms from the meson configure options
  • +
  • Show a nicer error message if the requirement fails
  • +
  • Sort the output of GetUpgrades correctly
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add support for HWID requirements
  • +
  • Add support for programming various AVR32 and XMEGA parts using DFU
  • +
  • Add the various DFU quirks for the Jabra Speak devices
  • +
  • Allow specifying the output file type for 'dfu-tool read'
  • +
  • Move the database of supported devices out into runtime loaded files
  • +
  • Support the IHEX record type 0x05
  • +
  • Use help2man to generate the man page at build time
  • +
  • Use the new quirk infrastructure for version numbers
  • +
+

This release fixes the following bugs:

+
    +
  • Catch invalid Dell dock component requests
  • +
  • Correctly output Intel HEX files with > 16bit offset addresses
  • +
  • Do not try to verify the element write if upload is unsupported
  • +
  • Fix a double-unref when updating any 8Bitdo device
  • +
  • Fix crash when enumerating with Dell dock connected but with no UEFI
  • +
  • Fix uploading large firmware files over DFU
  • +
  • Format the BCD USB revision numbers correctly
  • +
  • Guess the DFU transfer size if it is not specified
  • +
  • Include the reset timeout as wValue to fix some DFU bootloaders
  • +
  • Make the error message clearer when sans fonts are missing
  • +
  • Support devices with truncated DFU interface data
  • +
  • + Use the correct remote-specified username and passord when using + fwupdmgr +
  • +
  • Use the correct wDetachTimeOut when writing DFU firmware
  • +
  • Verify devices with legacy VIDs are actually 8Bitdo controllers
  • +
+
+
+ + +

This release breaks API and ABI to remove deprecated symbols!

+

This release adds the following features:

+
    +
  • Add a human-readable title for each remote
  • +
  • Add a method to return a list of upgrades for a specific device
  • +
  • + Add an 'Summary' and 'Icons' properties to each + device +
  • +
  • Add FuDeviceLocker to simplify device open/close lifecycles
  • +
  • Add functionality to blacklist Dell HW with problems
  • +
  • Add fu_plugin_check_supported()
  • +
  • Add fwupd_remote_get_checksum() to use in client programs
  • +
  • Add ModifyRemote as an easy way to enable and disable remotes
  • +
  • Add the plugin documentation to the main gtk-doc
  • +
  • Allow plugins to depend on each other
  • +
  • Disable the fallback USB plugin
  • +
  • Parse the SMBIOS v2 and v3 DMI tables directly
  • +
  • Support uploading the UEFI firmware splash image
  • +
  • Use the intel-wmi-thunderbolt kernel module to force power
  • +
+

This release fixes the following bugs:

+
    +
  • Only run SMI to toggle host MST GPIO on Dell systems with host MST
  • +
  • Disable unifying support if no CONFIG_HIDRAW support
  • +
  • Do not auto-open all USB devices at startup
  • +
  • Do not fail to load the daemon if cached metadata is invalid
  • +
  • Do not use system-specific information for UEFI PCI devices
  • +
  • Fix a crash when using fu_plugin_device_add_delay()
  • +
  • Fix the libdfu self test failure on s390 and ppc64
  • +
  • Fix various printing issues with the progressbar
  • +
  • Generate the LD script from the GObject introspection data
  • +
  • Never fallback to an offline update from client code
  • +
  • Only set the Dell coldplug delay when we know we need it
  • +
  • Prefer to use HWIDs to get DMI keys and DE table
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a configure switch for the LVFS remotes
  • +
  • Add a FirmwareBaseURI parameter to the remote config
  • +
  • Add a firmware builder that uses bubblewrap
  • +
  • + Add a python script to create fwupd compatible cab files from + Microsoft .exe files +
  • +
  • Add a thunderbolt plugin for new kernel interface
  • +
  • Allow plugins to get DMI data from the hardware in a safe way
  • +
  • Allow plugins to set metadata on devices created by other plugins
  • +
  • Optionally install the LVFS PKCS7 root certificate
  • +
  • Optionally use GnuTLS to verify PKCS7 certificates
  • +
+

This release fixes the following bugs:

+
    +
  • Add back options for HAVE_SYNAPTICS and HAVE_THUNDERBOLT
  • +
  • Allow configuring systemd and udev directories
  • +
  • Enable C99 support in meson.build
  • +
  • Fix an incomplete cipher when using XTEA on data not in 4 byte chunks
  • +
  • Fix minor const-correctness issues
  • +
  • Implement thunderbolt image validation
  • +
  • Remove the confusing ALLOW_OFFLINE and ALLOW_ONLINE flags
  • +
  • Show a bouncing progress bar if the percentage remains at zero
  • +
  • Use a hwid to match supported systems for synapticsmst
  • +
  • Use the new bootloader PIDs for Unifying pico receivers
  • +
  • When thunderbolt is in safe mode on a Dell recover using SMBIOS
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add DfuPatch to support forward-only firmware patching
  • +
  • Add --version option to fwupdmgr
  • +
  • Display all errors recorded by efi_error tracing
  • +
  • Make building introspection optional
  • +
  • Support embedded devices with local firmware metadata
  • +
+

This release fixes the following bugs:

+
    +
  • Check all the device GUIDs against the blacklist when added
  • +
  • Correct a memory leak in Dell plugin
  • +
  • Default to 'en' for UEFI capsule graphics
  • +
  • Don't log a warning when an unknown unifying report is parsed
  • +
  • Enable test suite via /etc/fwupd.conf
  • +
  • Fix a hang on 32 bit computers
  • +
  • Fix compilation of the policy on a variety of configurations
  • +
  • Fix UEFI crash when the product name is NULL
  • +
  • Make flashing ebitdo devices work with fu-ebitdo-tool
  • +
  • Make messages from installing capsules useful
  • +
  • Make sure the unifying percentage completion goes from 0% to 100%
  • +
  • Run the plugin coldplug methods in a predictable order
  • +
  • Test UEFI for kernel support during coldplug
  • +
  • Use new GUsb functionality to fix flashing Unifying devices
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a get-remotes command to fwupdmgr
  • +
  • Add a plugin to get the version of the AMT ME interface
  • +
  • Add Arch Linux to CI
  • +
  • Add some installed tests flashing actual hardware
  • +
  • Allow flashing Unifying devices in bootloader modes
  • +
  • Allow ordering the metadata remotes
  • +
+

This release fixes the following bugs:

+
    +
  • Do not check the runtime if the DFU device is in bootloader mode
  • +
  • Do not unlock devices when doing VerifyUpdate
  • +
  • Filter by Unifying SwId when making HID++2.0 requests
  • +
  • Fix downgrades when version_lowest is set
  • +
  • Fix the self tests when running on PPC64 big endian
  • +
  • Move the remotes parsing from the client to the server
  • +
  • Split up the Unifying HID++2.0 and HID++1.0 functionality
  • +
  • Store the metadata files rather than merging to one store
  • +
  • Use a longer timeout for some Unifying operations
  • +
  • Use the UFY DeviceID prefix for Unifying devices
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add installed tests that use the daemon
  • +
  • Add the ability to restrict firmware to specific vendors
  • +
  • Enable Travis CI for Fedora and Debian
  • +
  • Export some more API for dealing with checksums
  • +
  • Generate a images for status messages during system firmware update
  • +
  • Show progress download when refreshing metadata
  • +
+

This release fixes the following bugs:

+
    +
  • Compile with newer versions of meson
  • +
  • Ensure that firmware provides are legal GUIDs
  • +
  • Fix a common crash when refreshing metadata
  • +
  • Use the correct type signature in the D-Bus introspection file
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a 'downgrade' command to fwupdmgr
  • +
  • Add a 'get-releases' command to fwupdmgr
  • +
  • Add support for ConsoleKit2
  • +
  • Add support for Microsoft HardwareIDs
  • +
  • Allow downloading metadata from more than just the LVFS
  • +
  • Allow multiple checksums on devices and releases
  • +
+

This release fixes the following bugs:

+
    +
  • Allow to specify bindir
  • +
  • Correctly open Unifying devices with original factory firmware
  • +
  • Deprecate some of the old FwupdResult API
  • +
  • Do not copy the origin from the new metadata file
  • +
  • Do not expect a Unifying reply when issuing a REBOOT command
  • +
  • Do not re-download firmware that exists in the cache
  • +
  • Fix a problem when testing for a Dell system
  • +
  • Fix flashing new firmware to 8bitdo controllers
  • +
  • Increase minimum required AppStream-Glib version to 0.6.13
  • +
  • Make documentation and man pages optional
  • +
  • Make systemd dependency at least version 231
  • +
  • Only decompress the firmware after the signature check
  • +
  • Remove 'lib' prefix when looking for libraries
  • +
  • Return the remote ID when getting updates about hardware
  • +
  • Send the daemon the remote ID when sending firmware metadata
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • Add support for Unifying DFU features
  • +
+

This release fixes the following bugs:

+
    +
  • Do not spew a critial warning when parsing an invalid URI
  • +
  • Ensure device is closed if did not complete setup
  • +
  • Ensure steelseries device is closed if it returns an invalid packet
  • +
  • Fix man page installation location
  • +
  • Ignore spaces in the Unifying version prefix
  • +
  • Set HAVE_POLKIT_0_114 when polkit is newer than 0.114
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a config option to allow runtime disabling plugins by name
  • +
  • Add the Meson build system and remove autotools
  • +
  • Support signed Intel HEX files
  • +
+

This release fixes the following bugs:

+
    +
  • Add DFU quirk for OpenPICC and SIMtrace
  • +
  • Create directories in /var/cache as required
  • +
  • Refactor the unifying plugin now we know more about the hardware
  • +
  • Set the source origin when saving metadata
  • +
  • Support proxy servers in fwupdmgr
  • +
  • Use a 60 second timeout on all client downloads
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Adjust systemd confinement restrictions
  • +
  • Do not hardcode docbook2man path
  • +
  • Don't initialize libsmbios on unsupported systems
  • +
  • Fix a crash when enumerating devices on a Dell WLD15
  • +
  • Fix compiler warnings
  • +
  • Fix fwupdmgr timeout with missing pending database
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a set of vfuncs that are run before and after a device update
  • +
  • + Add Dell-specific functionality to allow other plugins turn on + TBT/GPIO +
  • +
  • Add support for Intel Thunderbolt devices
  • +
  • Add support for Logitech Unifying devices
  • +
  • Add support for Synaptics MST cascades hubs
  • +
  • Add support for the Altus-Metrum ChaosKey device
  • +
  • Add VerifyUpdate to update the device checksums server-side
  • +
  • + Allow the metadata to match a version of fwupd and the existing fw + version +
  • +
+

This release fixes the following bugs:

+
    +
  • Add a new method for forcing a controller to flash mode
  • +
  • Always make sure we're getting a C99 compiler
  • +
  • Close USB devices before error returns
  • +
  • Don't read data from some DfuSe targets
  • +
  • Include all debug messages when run with --verbose
  • +
  • Return the pending UEFI update when not on AC power
  • +
  • + Use a heuristic for the start address if the firmware has no DfuSe + footer +
  • +
  • Use more restrictive settings when running under systemd
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a 'replace-data' command to dfu-tool
  • +
  • Use an animated progress bar when performing DFU operations
  • +
+

This release fixes the following bugs:

+
    +
  • Add quirks for HydraBus as it does not have a DFU runtime
  • +
  • + Don't create the UEFI dummy device if the unlock will happen on + next boot +
  • +
  • Enable hardening flags on more binaries
  • +
  • Fix an assert when unlocking the dummy ESRT device
  • +
  • Fix writing firmware to devices using the ST reference bootloader
  • +
  • Match the Dell TB16 device
  • +
  • Re-get the quirks when the DfuDevice gets a new GUsbDevice
  • +
  • Show the nicely formatted target name for DfuSe devices
  • +
  • Verify devices support updating in mode they are called
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add dfu_firmware_add_symbol()
  • +
  • Allow the argument to 'dfu-tool set-release' be major.minor
  • +
  • Load the Altos USB descriptor from ELF files
  • +
  • Support writing the IHEX symbol table
  • +
+

This release fixes the following bugs:

+
    +
  • Add a fallback for older appstream-glib releases
  • +
  • Fix a possible crash when uploading firmware files using libdfu
  • +
  • Fix libfwupd self tests when a host-provided fwupd is not available
  • +
  • + Show the human-readable version in the 'dfu-tool dump' + output +
  • +
  • Write the ELF files with the correct section type
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a set-address and set-target-size commands to dfu-util
  • +
  • Add a small library for talking with 0bitdo hardware
  • +
  • Add Dell TPM and TB15/WD15 support via new Dell provider
  • +
  • Add FU_DEVICE_FLAG_NEEDS_BOOTLOADER
  • +
  • Add fwupd_client_get_status()
  • +
  • Add fwupd_result_get_unique_id()
  • +
  • Add initial ELF reading and writing support to libdfu
  • +
  • Add support for installing multiple devices from a CAB file
  • +
  • Allow providers to export percentage completion
  • +
  • Show a progress notification when installing firmware
  • +
  • Show the vendor flashing instructions when installing
  • +
+

This release fixes the following bugs:

+
    +
  • Add XPS 9250 to Dell TPM modeswitch blacklist
  • +
  • Allow blacklisting devices by their GUID
  • +
  • Conditionally enable all providers based upon installed
  • +
  • Display flashes left in results output when it gets low
  • +
  • Do not attempt to add DFU devices not in runtime mode
  • +
  • Do not use the deprecated GNOME_COMPILE_WARNINGS
  • +
  • Don't fail while checking versions or locked state
  • +
  • Embed fwupd version in generated documentation
  • +
  • Ensure the ID is set when getting local firmware details
  • +
  • Fix gtk-doc build when srcdir != builddir
  • +
  • Fix libdfu hang when parsing corrupt IHEX files
  • +
  • Ignore devices that do not add at least one GUID
  • +
  • In get-details output, display the blob filename
  • +
  • Save the unique ID in the pending database
  • +
  • Support the 'DEVO' cipher kind in libdfu
  • +
  • Switch to the Amazon S3 CDN for firmware metadata
  • +
  • Update fwupdmgr manpage for new commands and arguments
  • +
  • Use a private gnupg key store
  • +
  • Use the correct firmware when installing a composite device
  • +
  • Use the SHA1 hash of the local file data as the origin
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a GetDetailsLocal() method to eventually replace GetDetails()
  • +
  • Add fu_device_get_alternate()
  • +
  • Allow devices to have multiple assigned GUIDs
  • +
  • Allow metainfo files to match only specific revisions of devices
  • +
  • Show the DFU protocol version in 'dfu-tool list'
  • +
+

This release fixes the following bugs:

+
    +
  • Enforce allowing providers to take away flash abilities
  • +
  • Only claim the DFU interface when required
  • +
  • Only return updatable devices from GetDevices()
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a --force flag to override provider warnings
  • +
  • Add device-added, device-removed and device-changed signals
  • +
  • Add dfu_image_get_element_default()
  • +
  • Add for a new device field 'Flashes Left'
  • +
  • Add fwupd_client_connect()
  • +
  • Add the 'monitor' debugging command for fwupdmgr
  • +
  • Add the 'supported' flag to the FuDevice
  • +
+

This release fixes the following bugs:

+
    +
  • Add summary and name field for Rival SteelSeries
  • +
  • Fix a critical warning when restarting the daemon
  • +
  • Fix BE issues when reading and writing DFU files
  • +
  • Make the device display name nicer
  • +
  • Match the AppStream metadata after a device has been added
  • +
  • Remove non-interactive pinentry setting from fu-keyring
  • +
  • Return all update descriptions newer than the installed version
  • +
  • Set the device description when parsing local firmware files
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add a version plugin for SteelSeries hardware
  • +
  • Add FwupdClient and FwupdResult to libfwupd
  • +
  • Generate gtk-doc documentation for libfwupd
  • +
  • Return the device flags when getting firmware details
  • +
  • Support other checksum kinds
  • +
+

This release fixes the following bugs:

+
    +
  • Add Alienware to the version quirk table
  • +
  • Allow the test suite to run in %check
  • +
  • Do not return updates that require AC when on battery
  • +
  • Do not use /tmp for downloaded files
  • +
  • Test that GPG key import actually was successful
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add an unlock method for devices
  • +
  • Add a simple plugin infrastructure
  • +
  • Add ESRT enable method into UEFI provider
  • +
  • Install the hardcoded firmware AppStream file
  • +
+

This release fixes the following bugs:

+
    +
  • Correct the BCD version number for DFU 1.1
  • +
  • Do not use deprecated API from libappstream-glib
  • +
  • Ignore the DFU runtime on the DW1820A
  • +
  • Only read PCI OptionROM firmware when devices are manually unlocked
  • +
  • Require AC power before scheduling some types of firmware update
  • +
  • Show ignored DFU devices in dfu-util, but not in fwupd
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • + Add 'Created' and 'Modified' properties on + managed devices +
  • +
+

This release fixes the following bugs:

+
    +
  • Fix get-results for UEFI provider
  • +
  • Support vendor-specific UEFI version encodings
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Always persist ColorHug devices after replug
  • +
  • Do not misdetect different ColorHug devices
  • +
  • Only dump the profiling data when run with --verbose
  • +
+
+
+ + +

+ This release adds a new GObject library called libdfu and a command + line client called dfu-tool. This is a low-level tool used to upgrade + USB device firmware and can either be shipped in the same package as + fwupd or split off as separate subpackages. +

+

This release adds the following feature:

+
    +
  • Add support for automatically updating USB DFU-capable devices
  • +
+

This release fixes the following bugs:

+
    +
  • Emit the changed signal after doing an update
  • +
  • Export the AppStream ID when returning device results
  • +
  • Fix compile with --disable-shared
  • +
  • Use new API available in fwup 0.5
  • +
  • Use the same device identification string format as Microsoft
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Avoid seeking when reading the file magic during refresh
  • +
  • Do not assume that the compressed XML data will be NUL terminated
  • +
  • Use the correct user agent string for fwupdmgr
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Add profiling data to debug slow startup times
  • +
  • Support cabinet archives files with more than one firmware
  • +
+

This release fixes the following bugs:

+
    +
  • Add the update description to the GetDetails results
  • +
  • + Clear the in-memory firmware store only after parsing a valid XML + file +
  • +
  • Ensure D-Bus remote errors are registered at fwupdmgr startup
  • +
  • + Fix verify-update to produce components with the correct provide + values +
  • +
  • Require appstream-glib 0.5.1
  • +
  • Show the dotted-decimal representation of the UEFI version number
  • +
  • + When the version is from the 'FW' extension do not cache + the device +
  • +
+
+
+ + +

This release fixes the following bugs:

+
    +
  • Fix the error message when no devices can be updated
  • +
  • Fix reading symlink to prevent crash with some compilers
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • Raise the dep on GLib to support and use g_autoptr()
  • +
+

This release fixes the following bugs:

+
    +
  • Do not merge existing firmware metadata
  • +
  • Do not reboot if racing with the PackageKit offline update mechanism
  • +
+
+
+ + +

This release adds the following feature:

+
    +
  • Remove fwsignd, we have the LVFS now
  • +
+

This release fixes the following bugs:

+
    +
  • Add application metadata when getting the updates list
  • +
  • Depend on appstream-glib >= 0.5.0
  • +
  • Don't apply firmware if something else is processing the update
  • +
  • Install fwupd into /usr/lib/$(triplet)/fwupd instead
  • +
  • Simplify the version properties on devices to avoid complexity
  • +
  • Update the offline update service to invoke right command
  • +
  • Use the new secure metadata URI
  • +
+
+
+ + +

+ For the device verification code to work correctly you need at least + libappstream-glib 0.5.0 installed. +

+

This release adds the following features:

+
    +
  • Add a Raspberry Pi firmware provider
  • +
  • Add a simple config file to store the correct LVFS download URI
  • +
  • Make parsing the option ROM runtime optional
  • +
+

This release fixes the following bugs:

+
    +
  • Allow fwupd to be autostarted by systemd
  • +
  • + Allow no arguments to 'fwupdmgr verify-update' and use sane + defaults +
  • +
  • Devices with option ROM are always internal
  • +
  • Do not pre-convert the update description from AppStream XML
  • +
  • Fix validation of written firmware
  • +
  • Move the verification and metadata matching phase to the daemon
  • +
  • Sign the test binary with the correct key
  • +
  • Use the AppStream 0.9 firmware specification by default
  • +
+
+
+ + +

+ In this release we've moved the LVFS website to the fwupd project + and made them work really well together. To update all the firmware on + your system is now just a case of 'fwupdmgr refresh && + fwupdmgr update'. + We've also added verification of BIOS and PCI ROM firmware, which + may be useful for forensics or to verify that system updates have been + applied. +

+

This release adds the following features:

+
    +
  • Actually parse the complete PCI option ROM
  • +
  • + Add a 'fwupdmgr update' command to update all devices to + latest versions +
  • +
  • Add a simple signing server that operates on .cab files
  • +
  • + Add a 'verify' command that verifies the cryptographic hash + of device firmware +
  • +
  • Allow clients to add new firmware metadata to the system cache
  • +
  • Move GetUpdates to the daemon
  • +
  • Move the LVFS website to the fwupd project
  • +
+

This release fixes the following bugs:

+
    +
  • Accept multiple files at one time when using fwupdmgr dump-rom
  • +
  • Automatically download metadata using fwupdmgr if required
  • +
  • Do not return NULL as a gboolean
  • +
  • Don't call efibootmgr after fwupdate
  • +
  • Fallback to offline install when calling the update argument
  • +
  • Fix Intel VBIOS detection on Dell hardware
  • +
  • Reload appstream data after refreshing
  • +
  • Use the new LVFS GPG key
  • +
  • Fix build: libgusb is required even without colorhug support
  • +
+
+
+ + +

This release adds the following features:

+
    +
  • Get the firmware version from the device descriptors
  • +
  • Run the offline actions using systemd when required
  • +
  • Support OpenHardware devices using the fwupd vendor extensions
  • +
+

This release fixes the following bugs:

+
    +
  • Add an UNKNOWN status so we can return meaningful enum values
  • +
  • Coldplug the devices before acquiring the well known name
  • +
+
+
+ + + + + + +

This release adds the following features:

+
    +
  • Add a 'get-updates' command to fwupdmgr
  • +
  • Add and document the offline-update lifecycle
  • +
  • Create a libfwupd shared library
  • +
+

This release fixes the following bugs:

+
    +
  • Create runtime directories if they do not exist
  • +
  • Do not crash when there are no devices to return
  • +
+
+
+ + +

fwupd is a simple daemon to allow session software to update firmware.

+
+
+
diff -Nru fwupd-1.0.6/data/org.freedesktop.fwupd.service.in fwupd-1.2.10/data/org.freedesktop.fwupd.service.in --- fwupd-1.0.6/data/org.freedesktop.fwupd.service.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/org.freedesktop.fwupd.service.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,6 @@ [D-BUS Service] Name=org.freedesktop.fwupd -Documentation=http://www.fwupd.org/ +Documentation=https://fwupd.org/ Exec=@libexecdir@/fwupd/fwupd User=root SystemdService=fwupd.service diff -Nru fwupd-1.0.6/data/org.freedesktop.fwupd.svg fwupd-1.2.10/data/org.freedesktop.fwupd.svg --- fwupd-1.0.6/data/org.freedesktop.fwupd.svg 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/org.freedesktop.fwupd.svg 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,209 @@ + + + + Adwaita Icon Template + + + + + + + + + + + image/svg+xml + + + + GNOME Design Team + + + + + Adwaita Icon Template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fwupd + firmwareupdater + diff -Nru fwupd-1.0.6/data/pki/GPG-KEY-Linux-Foundation-Firmware fwupd-1.2.10/data/pki/GPG-KEY-Linux-Foundation-Firmware --- fwupd-1.0.6/data/pki/GPG-KEY-Linux-Foundation-Firmware 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/pki/GPG-KEY-Linux-Foundation-Firmware 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,37 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFsDBO0BCACjkrMuRgaWxP88Ubc1Xar5mxLMNXAJUzeYQVh/LnkEwytO3Ekh +GDH8Ch78269MiezkJmUGUUGyjKhqZECtZaKGp4LSl6gTPFDFHS/xKaq8L+8G/v4K +LEtZE03PKSnY2XYnf+3Kc6tmIZBB67yRg/79p3OpFd95wqyu+2c1cVkjCA1Q8XpO +bgCDfNacU3Yag6GXYlKpLmlVkYaAptjV0FrbLLBjaHvFeGAXgRUlv0PRyDjKD2XT +PEBtbg2+qTxPJIOlFgGNsJjkFL7R3mWwn00yF4jt9JMYGkpNAuFg1c/TZ1v64wlP +N6i2DsDwIMQ9S/ahJWdX/zP4JMTdpYNP91o9ABEBAAG0WkxWRlMgYSBTZXJpZXMg +b2YgTEYgUHJvamVjdHMsIExMQyAoTFZGUyBhIFNlcmllcyBvZiBMRiBQcm9qZWN0 +cywgTExDKSA8ZmlybXdhcmVAZnd1cGQub3JnPokBOAQTAQIAIgUCWwME7QIbAwYL +CQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQxjYXh6CoSeE3pQf+MlPyQzkVhdRU +fqjzu3Ba9dZ+hmsol2ooFmytd058AIO1eKie2LxnkQw4P5prFOnVWbbFi79vUEzQ +KK5xpW46nEglU14xYgv+4cMlVNWBYIVsXIIKKs2z4gM8oCA20JpVunnVbaViWTna +YwiUbTniIvLQH4RLo66Qzd0b3Z8ycK0bVbCl4RazSbWAGHMAnqm0xSQqsWRQwaHk +vxXEbjb0hfO4P/PZui5vFGr82tZUdGVKift1JlOzDMjVcmFIuYITHQyGaZ5Xsh2h +Pu9gI9Vp7OQoA7dJ+Qc5LBk3rVxN5Zx3jUSWOd7Dtvrm+ArBy/y0MCVyv9fcSvAH +vEv9T4zhE7kBDQRbAwTtAQgAwjiRDT3qinYz7b1s9SM2Y7aZG9JhWi/Zp2qGzGVX +QpVV2EK3PnAfZpyt99I63N7d/QDPqLFmTyjlv5cMb3QxVyXGBCGGz3OiWYY0NaDd +s1sp3J+TT6bHNG/Lo+vgcTRvzHvq7HbbeNssIMLr6MDAj0fZSh5UlAfQdC3qz90A +qIPGcx5AwgCwXLDqzCusz17Erc3IK/TG4r0AbRFtGx0hl2w5EOn7funw8BhnJ59w +OMsq7sXDmFff4hQjgQoDezMkA1EgzFokRY7pToLG3X1KdDXKR0edQ3+1mlJTf9XN +Zaz+ortKsugmTmzsF4DlRhq0Ok0VWuq0rzWndpFyFvIewwARAQABiQI+BBgBAgAJ +BQJbAwTtAhsuASkJEMY2F4egqEnhwF0gBBkBAgAGBQJbAwTtAAoJENTAcNuxNA6+ +1T4H/jsWVrANLKElBwZJpPOVy4Haw7UG+zk7lfwck0H8J9ShDtwhNTg03BiOONP/ +JuR8XvOxjqdUexEmAJdQCtxJgLTlI40xSlcmSEIneCamOhA/I/T+nkXFAfV65FKF ++OR3Ee122sUMXvLCcNvcbM23GIWiN/YmYFlK1PGNe3oOn4MWJ/28dbCLuEOPP4Tu +VJM/RpZ65qCnojc1meMcPJxI5iNWZtG9SmmGWDI3f7mDK+dtD06VLmPd3uc8P23t +YN0o/Jkgz2oV5GKD9t2+Ne2C5H5xZ0aE7dDVM8ErEPd3wTS+bC8GhPxHjj4A6HyA +MNZAEZSAJ4TVpzbfyOMcpSRK4yVLTAgAmTVV79EH/14s60Ya0LCtpifpvpZimbbo +xBGFaymvX7doxZyITC66JNTzT4Eixp8FNRloKWkEo6gPwA6qshlhc0HpmiqNmC+k +QNYIVeanrflV2bVzYSdsIzrZLUTd6P835YYxD1nsQGwnCqeeD0gJlV+alo0LYTRt +lFwNYxHU7BM09wu7sUEvYW5wt4TXPUrZ9jV+BM9UQLatW+S5vO41wqfTmPKGEqct +doW2ZYUgCc4aFGTOj3fA5hoK6EjAQpVdkcA7fiRYLn5AIvM4FGxIqI5khjsZUEPa +9Gpui69Y4a+x4QEIDj/WAHOOMSIg/n96e+uRdGXN4c8nr7JSASxlow== +=RFA4 +-----END PGP PUBLIC KEY BLOCK----- diff -Nru fwupd-1.0.6/data/pki/GPG-KEY-Linux-Foundation-Metadata fwupd-1.2.10/data/pki/GPG-KEY-Linux-Foundation-Metadata --- fwupd-1.0.6/data/pki/GPG-KEY-Linux-Foundation-Metadata 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/pki/GPG-KEY-Linux-Foundation-Metadata 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,37 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFsDA8IBCACgSd0NAJFEUjqcyv38If9f/FCQi2C2MQbzNt05DblHAg6eBk/V +eYM/GI+Cr9sPwxs8ZWtN0IRoQp/d7MRxe43zFT4IH2N4RVaBTgWCoRerPn09k4K/ +2fk6GWIY8lgxlKV/LinM5XkFDXv6Zf/o8Nv/i9bVO9Dv1bVh1ThgA3xy8WIzUQge +cVviEjEYG10TX+NENGgdA+aD/fMk4Wzwz6L48D+ryTiXGFnwoizifr9DIn4yIp6i +b4vTQY96VoXHSgU6JRvYjzPPME+NmmcLgW0hGJlVvi8RL+7wJPVeS0ioqPzMtonS +evrwVv5E5k87i+LS/vdVu3SIUzR9JLIXtvNNABEBAAG0WkxWRlMgYSBTZXJpZXMg +b2YgTEYgUHJvamVjdHMsIExMQyAoTFZGUyBhIFNlcmllcyBvZiBMRiBQcm9qZWN0 +cywgTExDKSA8bWV0YWRhdGFAZnd1cGQub3JnPokBOAQTAQIAIgUCWwMDwgIbAwYL +CQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQCm3O9rRvPb/wsQf7BGEkgT08Bx1v +657l//B/yniB7VGH+4plrX2OkWVzDxn+z6APcgqDMnzwatddxM7J6mm4yxA0nFKs +D5BueTItYv5zQCzX8e4TM1oaUWBr8nACK7/WSxNIC+GRUKl68v+dIbp1bhdmAYzj +wTn/uDW47Z7gtQYDJJit2MsKfu5Lwar7w+divH+6KWdaMctm2injYYIlpKCjffl8 +RZ4PgX7lN5C0s9kWDkH9iI2i5aqJaI8gZHK6EKwitmsHMJBczekymlXh4MheYCKm +IWJLh8tvK6LaVoddwfle4orhq4b7doA57H8BgJDDz+MxyjZn+GAireCMaJjtCSWv +q5bnsdnMH7kBDQRbAwPCAQgAq6hTejZZcIXnfA4Z/1c03USKnK8SeG/yqlggvpyZ +9C3hAvJITtQ7iZmz0VKOjwQtds52qnZYbOn/Fr+4Ef+cbFZRNxamZ4kf0XSAVXSv +EODMFj+BpdoDwAWhJcvyijoMV6N+gbCG+UedMNnpe25tlCRjouBSEF5KWJabejdh +iZ8ikN+HNJa5uQ68F76aDP1BOE0XiLrOZC0MZ7mvbyOi9LPXFyV2EuVj+gt7r+2x +OlSMmor7RTEAJcBK9tiew5LhNHeaqbe3xnOcpWrAaoVdIed7h5YbbetTFMWHCPGJ +raGGRSv3OrZDfQXZvOi+k6I6wWEQrsUCIiVKPefU+5xSpwARAQABiQI+BBgBAgAJ +BQJbAwPCAhsuASkJEAptzva0bz2/wF0gBBkBAgAGBQJbAwPCAAoJEL4e3StH4Ita +hvAIAIlZlrAJrbj7aQ3VkFcTJJC+68BaGNqte2S3Zv7ONLjT1kc0xSflf4c4MHef +q7WmLLsjUHocD0a8SUsR1V/Fp36qG1Yr7mfhf7dY3TwwUw9VXQoEdpEWZES/IJ4d +oPXSowk8eSbb72g4dvt9p+wlDKlsT7YHjmfn9Zct5FqcQ2kV9+900DtWlvPK8hRR +N0FibLR9GMorSFfHotFQ8AjdiXQUo+6GTb2HDJ1+aI4fpYo8NnqUs0wvCVtxrqn9 +JBzSgKkFAjHOiz/C6a0JOBtmH6tL41U7ZtUI2idQWsHiufyCTVOHRbyHoOxxFEpX +Xu3l2vckZaENNyNOGCqrIo8npFQczAf/REhK0Z8UumttRm2CQkJnkqRgLnIoJq3i +l7ljKjFi06XLJxOjLLpIFBH/yAJ5YbsYZt+XuT3WgORfHPDU3xepWGfQj4QFcsny +GWStnu6Ej/PogJyyvZ1hFpKu8g2cIp04vEebWeYHAMorvwty/p+MJnH6NeSQq5Pe +n22AuKKENtgYwulgJH0VQ0lJ5k1CcFuEuZqnXk5CUIC4tStdUS6hgn+vEkaJ5dX8 +nj/X9etEj2nnQGIL+7Dh2Z+UGaZqxSa1tjF5+7uC85K0NTq6Cpc+Bnd7Gqb+afnn +/iFHG21+hpjQmdSvpbGTabrM9gxd0iuDFXSFSttMtSC+gR5VcNQpUA== +=7Jrd +-----END PGP PUBLIC KEY BLOCK----- diff -Nru fwupd-1.0.6/data/pki/meson.build fwupd-1.2.10/data/pki/meson.build --- fwupd-1.0.6/data/pki/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/pki/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,12 +1,14 @@ if get_option('gpg') install_data([ 'GPG-KEY-Hughski-Limited', + 'GPG-KEY-Linux-Foundation-Firmware', 'GPG-KEY-Linux-Vendor-Firmware-Service', ], install_dir : join_paths(sysconfdir, 'pki', 'fwupd') ) install_data([ + 'GPG-KEY-Linux-Foundation-Metadata', 'GPG-KEY-Linux-Vendor-Firmware-Service', ], install_dir : join_paths(sysconfdir, 'pki', 'fwupd-metadata') diff -Nru fwupd-1.0.6/data/remotes.d/fwupd.conf fwupd-1.2.10/data/remotes.d/fwupd.conf --- fwupd-1.0.6/data/remotes.d/fwupd.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/fwupd.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -[fwupd Remote] - -# this remote provides metadata shipped with the fwupd package -Enabled=true -Title=Core -Keyring=none -MetadataURI=file://@datadir@/fwupd/remotes.d/fwupd/metadata.xml diff -Nru fwupd-1.0.6/data/remotes.d/lvfs.conf fwupd-1.2.10/data/remotes.d/lvfs.conf --- fwupd-1.0.6/data/remotes.d/lvfs.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/lvfs.conf 2019-07-15 18:25:54.000000000 +0000 @@ -7,3 +7,4 @@ MetadataURI=https://cdn.fwupd.org/downloads/firmware.xml.gz ReportURI=https://fwupd.org/lvfs/firmware/report OrderBefore=fwupd +ApprovalRequired=false diff -Nru fwupd-1.0.6/data/remotes.d/lvfs.metainfo.xml fwupd-1.2.10/data/remotes.d/lvfs.metainfo.xml --- fwupd-1.0.6/data/remotes.d/lvfs.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/lvfs.metainfo.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ + + + + + org.freedesktop.fwupd.remotes.lvfs + Linux Vendor Firmware Service (stable firmware) + CC0-1.0 + + + + +

+ The LVFS is a free service that operates as an independent legal + entity and has no connection with $OS_RELEASE:NAME$. + Your distributor may not have verified any of the firmware updates for + compatibility with your system or connected devices. + All firmware is provided only by the original equipment manufacturer. +

+

+ Enabling this functionality is done at your own risk, which means you + have to contact your original equipment manufacturer regarding any + problems caused by these updates. + Only problems with the update process itself should be filed at + $OS_RELEASE:BUG_REPORT_URL$. +

+
+
+
+
diff -Nru fwupd-1.0.6/data/remotes.d/lvfs-testing.conf fwupd-1.2.10/data/remotes.d/lvfs-testing.conf --- fwupd-1.0.6/data/remotes.d/lvfs-testing.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/lvfs-testing.conf 2019-07-15 18:25:54.000000000 +0000 @@ -9,3 +9,4 @@ Username= Password= OrderBefore=lvfs,fwupd +ApprovalRequired=false diff -Nru fwupd-1.0.6/data/remotes.d/lvfs-testing.metainfo.xml fwupd-1.2.10/data/remotes.d/lvfs-testing.metainfo.xml --- fwupd-1.0.6/data/remotes.d/lvfs-testing.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/lvfs-testing.metainfo.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + org.freedesktop.fwupd.remotes.lvfs-testing + Linux Vendor Firmware Service (testing firmware) + CC0-1.0 + + + + +

+ The LVFS is a free service that operates as an independent legal + entity and has no connection with $OS_RELEASE:NAME$. + Your distributor may not have verified any of the firmware updates for + compatibility with your system or connected devices. + All firmware is provided only by the original equipment manufacturer. +

+

+ This remote contains firmware which is not embargoed, but is still being + tested by the hardware vendor. + You should ensure you have a way to manually downgrade the firmware if + the firmware update fails. +

+

+ Enabling this functionality is done at your own risk, which means you + have to contact your original equipment manufacturer regarding any + problems caused by these updates. + Only problems with the update process itself should be filed at + $OS_RELEASE:BUG_REPORT_URL$. +

+
+
+
+
diff -Nru fwupd-1.0.6/data/remotes.d/meson.build fwupd-1.2.10/data/remotes.d/meson.build --- fwupd-1.0.6/data/remotes.d/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,10 +1,28 @@ -if get_option('lvfs') +if get_option('daemon') and get_option('lvfs') install_data([ 'lvfs.conf', 'lvfs-testing.conf', ], install_dir : join_paths(sysconfdir, 'fwupd', 'remotes.d') ) + i18n.merge_file( + input: 'lvfs.metainfo.xml', + output: 'org.freedesktop.fwupd.remotes.lvfs.metainfo.xml', + type: 'xml', + po_dir: join_paths(meson.source_root(), 'po'), + data_dirs: join_paths(meson.source_root(), 'po'), + install: true, + install_dir: join_paths(get_option('datadir'), 'fwupd', 'metainfo') + ) + i18n.merge_file( + input: 'lvfs-testing.metainfo.xml', + output: 'org.freedesktop.fwupd.remotes.lvfs-testing.metainfo.xml', + type: 'xml', + po_dir: join_paths(meson.source_root(), 'po'), + data_dirs: join_paths(meson.source_root(), 'po'), + install: true, + install_dir: join_paths(get_option('datadir'), 'fwupd', 'metainfo') + ) endif install_data('README.md', @@ -15,15 +33,15 @@ con2 = configuration_data() con2.set('datadir', datadir) configure_file( - input : 'fwupd.conf', - output : 'fwupd.conf', + input : 'vendor.conf', + output : 'vendor.conf', configuration : con2, install: true, install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), ) configure_file( - input : 'vendor.conf', - output : 'vendor.conf', + input : 'vendor-directory.conf', + output : 'vendor-directory.conf', configuration : con2, install: true, install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), diff -Nru fwupd-1.0.6/data/remotes.d/README.md fwupd-1.2.10/data/remotes.d/README.md --- fwupd-1.0.6/data/remotes.d/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -1,12 +1,12 @@ Vendor Firmware =============== -These are the steps to add vendor that is installed as part of an OSTree image: +These are the steps to add vendor firmware that is installed as part of an embedded image such as an OSTree or ChromeOS image: * Change `/etc/fwupd/remotes.d/vendor.conf` to have `Enabled=true` * Change `/etc/fwupd/remotes.d/vendor.conf` to have the correct `Title` * Deploy the firmware to `/usr/share/fwupd/remotes.d/vendor/firmware` -* Deploy the metadata to `/usr/share/fwupd/remotes.d/vendor/vendor.xml` +* Deploy the metadata to `/usr/share/fwupd/remotes.d/vendor/vendor.xml.gz` The metadata should be of the form: @@ -39,13 +39,27 @@ in `/etc/fwupd/remotes.d/vendor.conf` and ensure the correct public key or signing certificate is installed in the `/etc/pki/fwupd` location. +Automatic metadata generation +============================= +`fwupd` and `fwupdtool` support automatically generating metadata for a remote +by configuring it to be a *directory* type. This is very convenient if you want to dynamically add firmware from multiple packages while generating the image but there are a few deficiencies: +* There will be a performance impact of starting the daemon or tool measured by O(# CAB files) +* It's not possible to verify metadata signature and any file validation should be part of the image validation. + +To enable this: +* Change `/etc/fwupd/remotes.d/vendor-directory.conf` to have `Enabled=true` +* Change `/etc/fwupd/remotes.d/vendor.conf-directory` to have the correct `Title` +* Deploy the firmware to `/usr/share/fwupd/remotes.d/vendor/firmware` +* Change `MetadataURI` to that of the directory (Eg `/usr/share/fwupd/remotes.d/vendor/`) + + Mirroring a Repository ====================== The LVFS currently outputs XML with absolute URI locations, e.g. `http://foo/bar.cab` rather than `bar.cab` -This makes mirroring the master LVFS (or other slave instance) somewhat tricky. +This makes mirroring the master LVFS (or other private instance) somewhat tricky. To work around this issue client remotes can specify `FirmwareBaseURI` to replace the URI of the firmware before it is downloaded. diff -Nru fwupd-1.0.6/data/remotes.d/vendor.conf fwupd-1.2.10/data/remotes.d/vendor.conf --- fwupd-1.0.6/data/remotes.d/vendor.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/vendor.conf 2019-07-15 18:25:54.000000000 +0000 @@ -1,8 +1,8 @@ [fwupd Remote] - # this remote provides metadata shipped by the OS vendor and can be found in -# /usr/share/fwupd/remotes.d/vendor and /usr/share/fwupd/remotes.d/vendor/firmware +# @datadir@/fwupd/remotes.d/vendor and firmware in @datadir@/fwupd/remotes.d/vendor/firmware Enabled=false Title=Vendor Keyring=none MetadataURI=file://@datadir@/fwupd/remotes.d/vendor/vendor.xml.gz +ApprovalRequired=false diff -Nru fwupd-1.0.6/data/remotes.d/vendor-directory.conf fwupd-1.2.10/data/remotes.d/vendor-directory.conf --- fwupd-1.0.6/data/remotes.d/vendor-directory.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/remotes.d/vendor-directory.conf 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,8 @@ +[fwupd Remote] +# this remote provides dynamically generated metadata shipped by the OS vendor and can +# be found in @datadir@/fwupd/remotes.d/vendor/firmware +Enabled=false +Title=Vendor (Automatic) +Keyring=none +MetadataURI=file://@datadir@/fwupd/remotes.d/vendor/firmware +ApprovalRequired=false diff -Nru fwupd-1.0.6/data/tests/colorhug/meson.build fwupd-1.2.10/data/tests/colorhug/meson.build --- fwupd-1.0.6/data/tests/colorhug/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/tests/colorhug/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,25 @@ -gcab = find_program('gcab', required : false) -if gcab.found() - colorhug_test_firmware = custom_target('colorhug-test-firmware', - input : [ - 'firmware.bin', - 'firmware.bin.asc', - 'firmware.metainfo.xml', - ], - output : 'colorhug-als-3.0.2.cab', - command : [ - gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', - ], +colorhug_test_firmware = custom_target('colorhug-test-firmware', + input : [ + 'firmware.bin', + 'firmware.bin.asc', + 'firmware.metainfo.xml', + ], + output : 'colorhug-als-3.0.2.cab', + command : [ + gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', + ], +) + +if get_option('pkcs7') + # generate self-signed detached signature + colorhug_pkcs7_signature = custom_target('firmware.bin.p7c', + input: 'firmware.bin', + output: 'firmware.bin.p7c', + command: [certtool, '--p7-detached-sign', + '--p7-time', + '--load-privkey', pkcs7_privkey, + '--load-certificate', pkcs7_certificate, + '--infile', '@INPUT@', + '--outfile', '@OUTPUT@'], ) endif - -# generate self-signed detached signature -colorhug_pkcs7_signature = custom_target('firmware.bin.p7c', - input: 'firmware.bin', - output: 'firmware.bin.p7c', - command: [certtool, '--p7-detached-sign', - '--p7-time', - '--load-privkey', pkcs7_privkey, - '--load-certificate', pkcs7_certificate, - '--infile', '@INPUT@', - '--outfile', '@OUTPUT@'], -) diff -Nru fwupd-1.0.6/data/tests/daemon.conf fwupd-1.2.10/data/tests/daemon.conf --- fwupd-1.0.6/data/tests/daemon.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/tests/daemon.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -[fwupd] -ArchiveSizeMax=5 diff -Nru fwupd-1.0.6/data/tests/fwupd/daemon.conf fwupd-1.2.10/data/tests/fwupd/daemon.conf --- fwupd-1.0.6/data/tests/fwupd/daemon.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/tests/fwupd/daemon.conf 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +[fwupd] +ArchiveSizeMax=5 +ApprovedFirmware=deadbeef diff -Nru fwupd-1.0.6/data/tests/metadata.xml fwupd-1.2.10/data/tests/metadata.xml --- fwupd-1.0.6/data/tests/metadata.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/tests/metadata.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,14 @@ + + + + org.fwupd.8330a096d9f1af8567c7374cb8403e1ce9cf3163.device + + 2d47f29b-83a2-4f31-a2e8-63474f4d4c2e + + + +

Applying will enable UEFI firmware reporting

+
+
+
+
diff -Nru fwupd-1.0.6/data/tests/missing-hwid/meson.build fwupd-1.2.10/data/tests/missing-hwid/meson.build --- fwupd-1.0.6/data/tests/missing-hwid/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/tests/missing-hwid/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,23 +1,20 @@ -gcab = find_program('gcab', required : false) -if gcab.found() - hwid_test_firmware = custom_target('hwid-test-firmware', - input : [ - 'firmware.bin', - 'firmware.metainfo.xml', - ], - output : 'hwid-1.2.3.cab', - command : [ - gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', - ], - ) - noreqs_test_firmware = custom_target('noreqs-test-firmware', - input : [ - 'firmware.bin', - 'firmware2.metainfo.xml', - ], - output : 'noreqs-1.2.3.cab', - command : [ - gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', - ], - ) -endif +hwid_test_firmware = custom_target('hwid-test-firmware', + input : [ + 'firmware.bin', + 'firmware.metainfo.xml', + ], + output : 'hwid-1.2.3.cab', + command : [ + gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', + ], +) +noreqs_test_firmware = custom_target('noreqs-test-firmware', + input : [ + 'firmware.bin', + 'firmware2.metainfo.xml', + ], + output : 'noreqs-1.2.3.cab', + command : [ + gcab, '--create', '--nopath', '@OUTPUT@', '@INPUT@', + ], +) diff -Nru fwupd-1.0.6/data/tests/quirks.d/merged.quirk fwupd-1.2.10/data/tests/quirks.d/merged.quirk --- fwupd-1.0.6/data/tests/quirks.d/merged.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/tests/quirks.d/merged.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +[USB\VID_0A5C&PID_6412] +Flags = MERGE_ME diff -Nru fwupd-1.0.6/data/tests/quirks.d/tests.quirk fwupd-1.2.10/data/tests/quirks.d/tests.quirk --- fwupd-1.0.6/data/tests/quirks.d/tests.quirk 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/tests/quirks.d/tests.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -1,12 +1,20 @@ -[fwupd-plugin-test] +[USB\VID_0A5C&PID_6412] +Flags= ignore-runtime -USB\VID_0A5C&PID_6412=ignore-runtime +[USB\VID_FFFF&PID_FFFF] +Flags = -# this is an empty key -USB\VID_FFFF&PID_FFFF= +[ACME Inc.=True] +Test = awesome -# this is a key with a space -ACME Inc.=awesome +[CORP*] +Test = town -# this is a wildcard -CORP*=town +[DeviceInstanceId=USB\VID_0BDA&PID_1100] +Flags = clever +Name = Hub +Children = FuDevice|USB\VID_0763&PID_2806&I2C_01 + +[DeviceInstanceId=USB\VID_0763&PID_2806&I2C_01] +Name = HDMI +Flags = updatable,internal diff -Nru fwupd-1.0.6/data/tests/remotes.d/directory.conf fwupd-1.2.10/data/tests/remotes.d/directory.conf --- fwupd-1.0.6/data/tests/remotes.d/directory.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/data/tests/remotes.d/directory.conf 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,4 @@ +[fwupd Remote] +Enabled=true +Keyring=none +MetadataURI=file:///tmp/fwupd-self-test/var/cache/fwupd diff -Nru fwupd-1.0.6/data/tests/remotes.d/testing.conf fwupd-1.2.10/data/tests/remotes.d/testing.conf --- fwupd-1.0.6/data/tests/remotes.d/testing.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/data/tests/remotes.d/testing.conf 2019-07-15 18:25:54.000000000 +0000 @@ -1,3 +1,4 @@ [fwupd Remote] Enabled=true MetadataURI=file:///tmp/fwupd-self-test/testing.xml +ApprovalRequired=true diff -Nru fwupd-1.0.6/debian/changelog fwupd-1.2.10/debian/changelog --- fwupd-1.0.6/debian/changelog 2018-03-12 12:30:30.000000000 +0000 +++ fwupd-1.2.10/debian/changelog 2020-01-09 08:25:38.000000000 +0000 @@ -1,3 +1,239 @@ +fwupd (1.2.10-1ubuntu2~ubuntu18.04.3) bionic; urgency=medium + + * d/p/0001-dont-semver-conversion.patch, d/p/0001-version-handling.patch + d/p/0001-plain_support_in_version.patch: + backport regression fix that we can install firmware with the same + without --allow-reinstall in command line. the patch already merged + in upstream 1.2.X branch. (LP: #1820768) + + -- Yuan-Chen Cheng Thu, 09 Jan 2020 16:25:38 +0800 + +fwupd (1.2.10-1ubuntu2~ubuntu18.04.2) bionic; urgency=medium + + * d/p/0001-trivial-libfwupd-skip-tests-if-machine-id-is-empty-t.patch: + - Only check the vendor ID if the device has one set (LP: #1856896) + + -- Robert Ancell Thu, 19 Dec 2019 13:13:48 +1300 + +fwupd (1.2.10-1ubuntu2~ubuntu18.04.1) bionic; urgency=medium + + * Backport to bionic (LP: #1820768) + - meson-0.45-bc.patch: Fix build with meson 0.45 + + [ Steve Langasek ] + * Drop added Recommends: on bolt which is not in flavor seeds and adds a + new service. + + -- Yuan-Chen Cheng Fri, 25 Oct 2019 16:38:06 +0800 + +fwupd (1.2.10-1ubuntu2) eoan; urgency=medium + + * Backport a patch from upstream to relax expired cert checks + in self tests to fix FTBFS (LP: #184375) + * Add a patch to skip some self tests if /etc/machine-id exists + but is empty (LP: #184375) + + -- Mario Limonciello Tue, 24 Sep 2019 09:24:22 -0500 + +fwupd (1.2.10-1ubuntu1) eoan; urgency=medium + + * Merge with debian unstable. + - Remainining changes: downgrade tpm2-tools/tpm2-abrmd to Suggests. + + -- Mario Limonciello Mon, 15 Jul 2019 14:13:33 -0500 + +fwupd (1.2.10-1) unstable; urgency=medium + + * New upstream version (1.2.10) + + -- Mario Limonciello Mon, 15 Jul 2019 13:58:47 -0500 + +fwupd (1.2.9-1ubuntu1) eoan; urgency=medium + + * Merge with debian unstable. + - Remainining changes: downgrade tpm2-tools/tpm2-abrmd to Suggests. + + -- Mario Limonciello Fri, 12 Jul 2019 16:07:38 -0500 + +fwupd (1.2.9-1) unstable; urgency=medium + + * New upstream version (1.2.9) + + -- Mario Limonciello Fri, 12 Jul 2019 14:25:32 -0500 + +fwupd (1.2.6-1) unstable; urgency=medium + + * New upstream version (1.2.6) + * debian/control: + - Add new build depends related to Modem Manager + + -- Mario Limonciello Mon, 01 Apr 2019 21:18:14 -0500 + +fwupd (1.2.5-2) unstable; urgency=medium + + * debian/gen_signing_json: Update the format of the json metadata to + match new requirements: + + Move all the data under a new top-level "packages" key + + Add an empty "trusted_certs" key - our binaries do not do any + further verification with an embedded key. + + -- Steve McIntyre <93sam@debian.org> Mon, 25 Mar 2019 00:32:07 +0000 + +fwupd (1.2.5-1) unstable; urgency=medium + + * New upstream version (1.2.5) + * Drop all patches, upstream + + -- Mario Limonciello Tue, 26 Feb 2019 16:30:52 -0600 + +fwupd (1.2.4-3) unstable; urgency=medium + + * Backport a patch from master that fixes FTBFS with newer glib + + -- Mario Limonciello Fri, 15 Feb 2019 08:06:55 -0600 + +fwupd (1.2.4-2) unstable; urgency=medium + + * debian: explicitly depend on shared-mime-info + + -- Mario Limonciello Thu, 14 Feb 2019 21:21:46 -0600 + +fwupd (1.2.4-1) unstable; urgency=medium + + * New upstream version + * refresh build dependencies + * Recommends on tpm2 stack to read PCR values + + -- Mario Limonciello Wed, 06 Feb 2019 20:31:24 -0600 + +fwupd (1.1.4-1) unstable; urgency=medium + + * New upstream version + + -- Mario Limonciello Wed, 07 Nov 2018 11:30:14 -0600 + +fwupd (1.1.3-2) unstable; urgency=medium + + * Move location of fwupd-SIGNARCH-signed.install to proper directory + to fix generation of signed packages. + + -- Mario Limonciello Sat, 13 Oct 2018 14:17:07 -0500 + +fwupd (1.1.3-1) unstable; urgency=medium + + * New upstream release. + + -- Mario Limonciello Fri, 12 Oct 2018 13:18:46 -0500 + +fwupd (1.1.2-1) unstable; urgency=medium + + * New upstream release + - Fixes ESP autodetection for autofs (Closes: #906216) + - Adds missing signing bits (Closes: #906599) + * debian/rules: + - Pass -a into dh_missing (Closes: #906357) + * debian/control: + - Recommends for bolt for new thunderbolt power API + - Build depends on Noto fonts instead of Dejavu fonts + * Drop all patches. + + -- Mario Limonciello Mon, 10 Sep 2018 11:42:03 -0500 + +fwupd (1.1.1-1) unstable; urgency=medium + + * New upstream release. + - Adds support for more Synaptics and Intel hardware. + - Fixes firmware update on some UEFI implementations (Closes: #905570) + * debian/ + - contrib: debian: regenerate control on clean + - refresh debian/{control,copyright} for upstream fixes + - drop all patches, upstream. + + -- Mario Limonciello Mon, 13 Aug 2018 08:08:53 -0500 + +fwupd (1.1.0-7) unstable; urgency=medium + + * Correct another syntax error in SB signing template (Closes: #905482) + + -- Mario Limonciello Sun, 05 Aug 2018 08:34:37 -0500 + +fwupd (1.1.0-6) unstable; urgency=medium + + * correct secure boot signing template name (Closes: #905471) + + -- Mario Limonciello Sun, 05 Aug 2018 00:06:30 -0500 + +fwupd (1.1.0-5) unstable; urgency=medium + + * Fix secure boot signing template version string (Closes: #905468) + * Refresh debian/copyright (Closes: #904671) + + -- Mario Limonciello Sat, 04 Aug 2018 22:37:36 -0500 + +fwupd (1.1.0-4) unstable; urgency=medium + + * debian/rules: dynamically install EFI binaries + + -- Mario Limonciello Sat, 04 Aug 2018 19:43:44 -0500 + +fwupd (1.1.0-3) unstable; urgency=medium + + * debian/rules: use pkg-config to determine when to turn on redfish and UEFI + - Fixes FTBFS due to redfish on other architectures. + + -- Mario Limonciello Sat, 04 Aug 2018 17:04:27 -0500 + +fwupd (1.1.0-2) unstable; urgency=medium + + * Fix the filename of the signed archive used for secure boot on Ubuntu + * Only build uefi plugin on supported architectures + + -- Mario Limonciello Sat, 04 Aug 2018 11:27:24 -0500 + +fwupd (1.1.0-1) unstable; urgency=medium + + [ Steve Mcintyre ] + * Initial support for UEFI Secure Boot in Debian infrastructure + + When building, also generate a fwupdate-$ARCH-signed-template package + which contains metadata needed by the Debian signing service. This + will end up being turned into a new source package including a signed + version of the fwupdate binary. + + [ Mario Limonciello ] + * New upstream version (1.1.0) + * Drop patches merged upstream. + * debian/control: + - Add a patch from upstream that will add gnu-efi to dependencies + - No longer recommends for fwupdate as it has been merged into fwupd. + * Adjust infrastructure for fwupdate signed package to be used by fwupd signed + package + + -- Mario Limonciello Thu, 12 Jul 2018 08:28:32 -0500 + +fwupd (1.0.8-1) unstable; urgency=medium + + * New upstream version (1.0.8) + - Adds new fwupdtool + - License is now LGPL 2.1 + - Drops colorhug dependency (built in now) + - refresh symbols + + -- Mario Limonciello Thu, 07 Jun 2018 08:16:22 -0500 + +fwupd (1.0.7-1) unstable; urgency=medium + + * New upstream version (1.0.7) + * /debian changes: + - ignore library-not-linked-against-libc + - Remove unused override in debian/lintian/fwupd + - rename tag for debian/source/lintian-overrides + - Adjust to use https in debian/copyright + - Bump debian/compat to 10 + - Update control version + - update standards version + + -- Mario Limonciello Mon, 30 Apr 2018 13:11:17 -0500 + fwupd (1.0.6-2) unstable; urgency=medium [ Mario Limonciello ] @@ -46,7 +282,7 @@ fwupd (1.0.2-1) unstable; urgency=medium * New upstream version - * Drop patch for doing libsmbios on only supported architectures, + * Drop patch for doing libsmbios on only supported architectures, now upstream. -- Mario Limonciello Tue, 28 Nov 2017 09:36:57 -0600 @@ -265,7 +501,7 @@ * Correct a cleanup rule * Drop intltool build dependency * Re-enable PIE for builds - * Add additional build dependencies that will be needed for generating + * Add additional build dependencies that will be needed for generating capsule graphics * debian/control: sort build-dependencies * Drop packaging from debian/, it will be git mv'ed from contrib/ upstream diff -Nru fwupd-1.0.6/debian/compat fwupd-1.2.10/debian/compat --- fwupd-1.0.6/debian/compat 2018-03-12 11:53:58.000000000 +0000 +++ fwupd-1.2.10/debian/compat 2019-12-19 00:13:48.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru fwupd-1.0.6/debian/control fwupd-1.2.10/debian/control --- fwupd-1.0.6/debian/control 2018-03-12 12:30:30.000000000 +0000 +++ fwupd-1.2.10/debian/control 2020-01-09 08:25:38.000000000 +0000 @@ -1,33 +1,34 @@ Source: fwupd Priority: optional -Maintainer: Debian EFI +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian EFI Uploaders: Steve McIntyre <93sam@debian.org>, Daniel Jared Dominguez , Matthias Klumpp , Mario Limonciello Build-Depends: - debhelper (>= 10.3), + bash-completion, + bubblewrap, + debhelper (>= 11), dh-strip-nondeterminism, fontconfig, - fonts-dejavu, + fonts-noto, gcab, gettext (>= 0.19.8.1), gir1.2-pango-1.0, + gnu-efi [amd64 arm64 armhf i386], gnutls-bin, gnutls-dev, gobject-introspection, gtk-doc-tools, help2man, - libappstream-glib-dev (>= 0.7.4), libarchive-dev, libcairo-dev, libcairo-gobject2, - libcolord-dev (>= 1.0.0), - libcolorhug-dev, - libefivar-dev [amd64 arm64 armhf armel i386], + libefiboot-dev [amd64 arm64 armhf i386], + libefivar-dev [amd64 arm64 armhf i386], libelf-dev, libfreetype6-dev, - libfwup-dev (>= 10-3) [amd64 arm64 armhf i386], libgcab-dev, libgirepository1.0-dev, libglib2.0-dev (>= 2.45.8), @@ -35,11 +36,14 @@ libgudev-1.0-dev, libgusb-dev (>= 0.2.9), libjson-glib-dev (>= 1.1.1), + libmm-glib-dev, libpolkit-gobject-1-dev, + libqmi-glib-dev, libsmbios-dev [i386 amd64], libsoup2.4-dev, libsqlite3-dev, libtool-bin, + libxmlb-dev (>= 0.1.5), locales, meson, pkg-config, @@ -47,12 +51,13 @@ python3-gi-cairo, python3-pil, python3-requests, + shared-mime-info, systemd (>= 231), udev, umockdev, valac, - valgrind [!mips !sparc64 !sh4 !ppc64 !powerpcspe !hppa !alpha !mips64el !armhf !armel !mipsel !m68k], -Standards-Version: 4.1.3 + valgrind [!ia64 !riscv64 !x32 !mips !sparc64 !sh4 !ppc64 !powerpcspe !hppa !alpha !mips64el !armhf !armel !mipsel !m68k], +Standards-Version: 4.3.0 Section: admin Homepage: https://github.com/hughsie/fwupd Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git @@ -68,8 +73,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -77,9 +81,13 @@ Package: fwupd Architecture: linux-any Depends: ${misc:Depends}, - ${shlibs:Depends} -Recommends: fwupdate, - python3 + ${shlibs:Depends}, + shared-mime-info +Recommends: python3, + fwupd-signed +Suggests: bolt, + tpm2-tools, + tpm2-abrmd, Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), libdfu-dev (<< 0.9.7-1) @@ -91,8 +99,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -114,8 +121,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -130,8 +136,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -150,8 +155,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd @@ -167,3 +171,31 @@ . It can be used by packages using the GIRepository format to generate dynamic bindings. + +Package: fwupd-amd64-signed-template +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-i386-signed-template +Architecture: i386 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-armhf-signed-template +Architecture: armhf +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-arm64-signed-template +Architecture: arm64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. diff -Nru fwupd-1.0.6/debian/control.in fwupd-1.2.10/debian/control.in --- fwupd-1.0.6/debian/control.in 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/control.in 2019-12-19 00:13:48.000000000 +0000 @@ -1,12 +1,13 @@ Source: fwupd Priority: optional -Maintainer: Debian EFI +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian EFI Uploaders: Steve McIntyre <93sam@debian.org>, Daniel Jared Dominguez , Matthias Klumpp , Mario Limonciello Build-Depends: %%%DYNAMIC%%% -Standards-Version: 4.1.3 +Standards-Version: 4.3.0 Section: admin Homepage: https://github.com/hughsie/fwupd Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git @@ -22,8 +23,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the library used by the daemon. @@ -31,9 +31,13 @@ Package: fwupd Architecture: linux-any Depends: ${misc:Depends}, - ${shlibs:Depends} -Recommends: fwupdate, - python3 + ${shlibs:Depends}, + shared-mime-info +Recommends: python3, + fwupd-signed +Suggests: bolt, + tpm2-tools, + tpm2-abrmd, Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1), libdfu1 (<< 0.9.7-1), libdfu-dev (<< 0.9.7-1) @@ -45,8 +49,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details Package: fwupd-tests @@ -68,8 +71,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides a set of installed tests that can be run to validate @@ -84,8 +86,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides development documentation for creating a package that @@ -104,8 +105,7 @@ fwupd is a daemon to allow session software to update device firmware. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the system D-Bus interface directly. - Currently, firmware updates using the UEFI capsule format and for the - ColorHug are supported. More formats may be supported in the future. + Firmware updates are supported for a variety of technologies. See for details . This package provides the development files for libfwupd @@ -121,3 +121,31 @@ . It can be used by packages using the GIRepository format to generate dynamic bindings. + +Package: fwupd-amd64-signed-template +Architecture: amd64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-i386-signed-template +Architecture: i386 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-armhf-signed-template +Architecture: armhf +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. + +Package: fwupd-arm64-signed-template +Architecture: arm64 +Depends: ${shlibs:Depends}, ${misc:Depends}, make | build-essential | dpkg-dev +Description: Template for signed fwupd package + This package is used to control code signing by the Debian signing + service. diff -Nru fwupd-1.0.6/debian/copyright fwupd-1.2.10/debian/copyright --- fwupd-1.0.6/debian/copyright 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/copyright 2020-01-09 08:25:38.000000000 +0000 @@ -1,40 +1,35 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: fwupd Source: https://github.com/hughsie/fwupd Files: * -Copyright: 2015 Richard Hughes -License: GPL-2.0+ - -Files: libfwupd/* -Copyright: 2015 Richard Hughes +Copyright: Aleksander Morgado + Christian J. Kellner + Dell Inc. + Dell, Inc. + Google, Inc. + Intel Corporation. + Kalev Lember + Mario Limonciello + Max Ehrlich max.ehr@gmail.com + Peichen Huang + Peter Jones + Realtek Semiconductor Corporation + Red Hat, Inc. + Richard Hughes + Ryan Chang + Synaptics + Synaptics Inc License: LGPL-2.1+ -Files: data/tests/colorhug/firmware.metainfo.xml -Copyright: 2015 Richard Hughes +Files: *.metainfo.xml +Copyright: Richard Hughes License: CC0-1.0 Files: debian/* Copyright: 2015 Daniel Jared Dominguez - 2015 Mario Limonciello -License: GPL-2.0+ - -License: GPL-2.0+ - This package 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 2 of the License, or - (at your option) any later version. - . - This package 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, see - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + 2015-2018 Mario Limonciello +License: LGPL-2.1+ License: LGPL-2.1+ This package is free software; you can redistribute it and/or modify diff -Nru fwupd-1.0.6/debian/copyright.in fwupd-1.2.10/debian/copyright.in --- fwupd-1.0.6/debian/copyright.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/copyright.in 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,140 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fwupd +Source: https://github.com/hughsie/fwupd + +%%%DYNAMIC%%% +Files: *.metainfo.xml +Copyright: Richard Hughes +License: CC0-1.0 + +Files: debian/* +Copyright: 2015 Daniel Jared Dominguez + 2015-2018 Mario Limonciello +License: LGPL-2.1+ + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + . + This package 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 Lesser General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". + + +License: CC0-1.0 + Creative Commons CC0 1.0 Universal + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL + SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT + RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. + CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE + INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES + RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + . + Statement of Purpose + . + The laws of most jurisdictions throughout the world automatically confer + exclusive Copyright and Related Rights (defined below) upon the creator and + subsequent owner(s) (each and all, an "owner") of an original work of + authorship and/or a database (each, a "Work"). Certain owners wish to + permanently relinquish those rights to a Work for the purpose of contributing + to a commons of creative, cultural and scientific works ("Commons") that the + public can reliably and without fear of later claims of infringement build + upon, modify, incorporate in other works, reuse and redistribute as freely as + possible in any form whatsoever and for any purposes, including without + limitation commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of creative, + cultural and scientific works, or to gain reputation or greater distribution + for their Work in part through the use and efforts of others. For these and/or + other purposes and motivations, and without any expectation of additional + consideration or compensation, the person associating CC0 with a Work (the + "Affirmer"), to the extent that he or she is an owner of Copyright and Related + Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly + distribute the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect of CC0 on + those rights. + . + 1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited to, + the following: + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, subject + to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data in a + Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal protection + of databases, and under any national implementation thereof, including any + amended or successor version of such directive); and + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + . + 2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). + Affirmer makes the Waiver for the benefit of each member of the public at large + and to the detriment of Affirmer's heirs and successors, fully intending that + such Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express + Statement of Purpose. + . + 3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express Statement of Purpose. In addition, to the extent the Waiver + is so judged Affirmer hereby grants to each affected person a royalty-free, non + transferable, non sublicensable, non exclusive, irrevocable and unconditional + license to exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in any + current or future medium and for any number of copies, and (iv) for any + purpose whatsoever, including without limitation commercial, advertising or + promotional purposes (the "License"). The License shall be deemed effective + as of the date CC0 was applied by Affirmer to the Work. Should any part of + the License for any reason be judged legally invalid or ineffective under + applicable law, such partial invalidity or ineffectiveness shall not + invalidate the remainder of the License, and in such case Affirmer hereby + affirms that he or she will not (i) exercise any of his or her remaining + Copyright and Related Rights in the Work or (ii) assert any associated claims + and causes of action with respect to the Work, in either case contrary to + Affirmer's express Statement of Purpose. + . + 4. Limitations and Disclaimers. + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or warranties of + any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness for + a particular purpose, non infringement, or the absence of latent or other + defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons that + may apply to the Work or any use thereof, including without limitation any + person's Copyright and Related Rights in the Work. Further, Affirmer disclaims + responsibility for obtaining any necessary consents, permissions or other + rights required for any use of the Work. + d. Affirmer understands and acknowledges that Creative Commons is not a party + to this document and has no duty or obligation with respect to this CC0 or use + of the Work. diff -Nru fwupd-1.0.6/debian/docs fwupd-1.2.10/debian/docs --- fwupd-1.0.6/debian/docs 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/docs 2019-12-19 00:13:48.000000000 +0000 @@ -1 +1 @@ -NEWS + diff -Nru fwupd-1.0.6/debian/fwupd.install fwupd-1.2.10/debian/fwupd.install --- fwupd-1.0.6/debian/fwupd.install 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/fwupd.install 2019-12-19 00:13:48.000000000 +0000 @@ -4,12 +4,17 @@ usr/share/bash-completion usr/share/fwupd/* usr/share/dbus-1/* +usr/share/icons/* usr/share/polkit-1/* usr/share/locale usr/share/metainfo/* usr/lib/*/fwupd +usr/lib/*/fwupdagent +usr/lib/*/fwupdoffline +usr/lib/*/fwupdtool usr/share/man/man1/* lib/systemd/system/* +lib/systemd/system-shutdown/* var/lib/fwupd lib/udev/rules.d/* data/daemon.conf etc/fwupd diff -Nru fwupd-1.0.6/debian/fwupd.postinst fwupd-1.2.10/debian/fwupd.postinst --- fwupd-1.0.6/debian/fwupd.postinst 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/fwupd.postinst 2019-12-19 00:13:48.000000000 +0000 @@ -6,4 +6,6 @@ if dpkg-maintscript-helper supports rm_conffile 2>/dev/null; then dpkg-maintscript-helper rm_conffile \ /etc/fwupd.conf 1.0.0~ -- "$@" + dpkg-maintscript-helper rm_conffile \ + /etc/fwupd/remotes.d/fwupd.conf 1.2.7~ -- "$@" fi diff -Nru fwupd-1.0.6/debian/fwupd-tests.install fwupd-1.2.10/debian/fwupd-tests.install --- fwupd-1.0.6/debian/fwupd-tests.install 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/fwupd-tests.install 2019-12-19 00:13:48.000000000 +0000 @@ -4,3 +4,5 @@ #https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872458 usr/share/installed-tests/* usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so +debian/lintian/fwupd-tests usr/share/lintian/overrides +etc/fwupd/remotes.d/fwupd-tests.conf diff -Nru fwupd-1.0.6/debian/fwupd-tests.postinst fwupd-1.2.10/debian/fwupd-tests.postinst --- fwupd-1.0.6/debian/fwupd-tests.postinst 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/fwupd-tests.postinst 2019-12-19 00:13:48.000000000 +0000 @@ -12,4 +12,12 @@ echo "To enable test suite, modify /etc/fwupd/daemon.conf" fi fi + if [ -f /etc/fwupd/remotes.d/fwupd-tests.conf ]; then + if [ "$CI" = "true" ]; then + sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf + else + echo "To enable test suite, enable fwupd-tests remote" + fi + + fi fi diff -Nru fwupd-1.0.6/debian/gbp.conf fwupd-1.2.10/debian/gbp.conf --- fwupd-1.0.6/debian/gbp.conf 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/gbp.conf 2019-12-19 00:13:48.000000000 +0000 @@ -1,5 +1,5 @@ [DEFAULT] -debian-branch = debian +debian-branch = ubuntu upstream-tag = %(version)s [buildpackage] diff -Nru fwupd-1.0.6/debian/gen_signing_changelog fwupd-1.2.10/debian/gen_signing_changelog --- fwupd-1.0.6/debian/gen_signing_changelog 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/gen_signing_changelog 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Generate a changelog file for the signed fwupdate package, based on +# a changelog.in file and other state + +DIR=$1 +SOURCE=$2 +ARCH=$3 +IN="${DIR}/changelog.in" +OUT="${DIR}/changelog" + +# Parse out fields from our changelg entry - want the signing-template +# one to match all the important details where we can +DISTRIBUTION="$(dpkg-parsechangelog | sed -ne 's/^Distribution: \(.*\)/\1/p')" +URGENCY="$(dpkg-parsechangelog | sed -ne 's/^Urgency: \(.*\)/\1/p')" +MAINT="$(dpkg-parsechangelog | sed -ne 's/^Maintainer: \(.*\)/\1/p')" +DATE="$(dpkg-parsechangelog | sed -ne 's/^Date: \(.*\)/\1/p')" + +# If the version ends in "+bXXX", this is a binNMU. We don't want a new +# source package to look like that, so change it to ".bXXX" instead +VERSION="$(dpkg-parsechangelog | sed -ne 's/^Version: \(.*\)/\1/p')" +MANGLED_VERSION="$(echo $VERSION | sed -r 's/-/\+/;s/\+(b[[:digit:]]+)$/.\1/')" + +printf "%s-%s-signed (%s) %s; urgency=%s\n" "${SOURCE}" "${ARCH}" "${MANGLED_VERSION}" "${DISTRIBUTION}" "${URGENCY}" > $OUT +printf "\n" >> $OUT +printf " * Update to %s version %s\n" "${SOURCE}" "${VERSION}" >> $OUT +printf "\n" >> $OUT +printf " -- %s %s\n" "${MAINT}" "${DATE}" >> $OUT +printf "\n" >> $OUT + +cat $IN >> $OUT +rm -f $IN diff -Nru fwupd-1.0.6/debian/gen_signing_json fwupd-1.2.10/debian/gen_signing_json --- fwupd-1.0.6/debian/gen_signing_json 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/gen_signing_json 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Generate a json file to go in the the fwupd-signed template +# package. Describes exactly what needs to be signed, and how. + +DIR=$1 +SOURCE=$2 +ARCH=$3 +OUT="$DIR/files.json" + +# What file are we looking to sign? +BINARY=$(find debian/tmp -name '*.efi' | xargs basename) + +# Actually needs full path within the binary deb +BINARY="usr/lib/${SOURCE}/efi/${BINARY}" + +rm -f $OUT + +printf '{\n' >> $OUT +printf ' "packages": {\n' >> $OUT +printf ' "%s": {\n' "${SOURCE}" >> $OUT +printf ' "trusted_certs": [],\n' >> $OUT +printf ' "files": [ \n' >> $OUT +printf ' {"sig_type": "efi", "file": "%s"}\n' "${BINARY}" >> $OUT +printf ' ]\n' >> $OUT +printf ' }\n' >> $OUT +printf ' }\n' >> $OUT +printf '}\n' >> $OUT + diff -Nru fwupd-1.0.6/debian/gir1.2-fwupd-2.0.install fwupd-1.2.10/debian/gir1.2-fwupd-2.0.install --- fwupd-1.0.6/debian/gir1.2-fwupd-2.0.install 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/gir1.2-fwupd-2.0.install 2019-12-19 00:13:48.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/girepository-1.0/Fwupd-2.0.typelib +usr/lib/*/girepository-1.0/*.typelib diff -Nru fwupd-1.0.6/debian/libfwupd2.install fwupd-1.2.10/debian/libfwupd2.install --- fwupd-1.0.6/debian/libfwupd2.install 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/libfwupd2.install 2019-12-19 00:13:48.000000000 +0000 @@ -1 +1 @@ -usr/lib/*/libfwup*.so.* +usr/lib/*/*.so.* diff -Nru fwupd-1.0.6/debian/libfwupd2.symbols fwupd-1.2.10/debian/libfwupd2.symbols --- fwupd-1.0.6/debian/libfwupd2.symbols 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/libfwupd2.symbols 2019-12-19 00:13:48.000000000 +0000 @@ -14,6 +14,21 @@ LIBFWUPD_1.0.0@LIBFWUPD_1.0.0 1.0.0 LIBFWUPD_1.0.3@LIBFWUPD_1.0.3 1.0.3 LIBFWUPD_1.0.4@LIBFWUPD_1.0.4 1.0.4 + LIBFWUPD_1.0.7@LIBFWUPD_1.0.7 1.0.7 + LIBFWUPD_1.0.8@LIBFWUPD_1.0.8 1.0.8 + LIBFWUPD_1.1.0@LIBFWUPD_1.1.0 1.1.0 + LIBFWUPD_1.1.1@LIBFWUPD_1.1.1 1.1.1 + LIBFWUPD_1.1.2@LIBFWUPD_1.1.2 1.1.2 + LIBFWUPD_1.1.3@LIBFWUPD_1.1.3 1.1.3 + LIBFWUPD_1.2.10@LIBFWUPD_1.2.10 1.2.10 + LIBFWUPD_1.2.1@LIBFWUPD_1.2.1 1.2.1 + LIBFWUPD_1.2.2@LIBFWUPD_1.2.2 1.2.2 + LIBFWUPD_1.2.4@LIBFWUPD_1.2.4 1.2.4 + LIBFWUPD_1.2.5@LIBFWUPD_1.2.5 1.2.5 + LIBFWUPD_1.2.6@LIBFWUPD_1.2.6 1.2.6 + LIBFWUPD_1.2.7@LIBFWUPD_1.2.7 1.2.7 + LIBFWUPD_1.2.8@LIBFWUPD_1.2.8 1.2.8 + LIBFWUPD_1.2.9@LIBFWUPD_1.2.9 1.2.9 fwupd_build_history_report_json@LIBFWUPD_1.0.4 1.0.4 fwupd_build_machine_id@LIBFWUPD_1.0.4 1.0.4 fwupd_build_user_agent@LIBFWUPD_1.0.3 1.0.3 @@ -21,8 +36,10 @@ fwupd_checksum_get_best@LIBFWUPD_0.9.4 1.0.0 fwupd_checksum_get_by_kind@LIBFWUPD_0.9.4 1.0.0 fwupd_checksum_guess_kind@LIBFWUPD_0.9.3 1.0.0 + fwupd_client_activate@LIBFWUPD_1.2.6 1.2.6 fwupd_client_clear_results@LIBFWUPD_0.7.0 1.0.0 fwupd_client_connect@LIBFWUPD_0.7.1 1.0.0 + fwupd_client_get_approved_firmware@LIBFWUPD_1.2.6 1.2.6 fwupd_client_get_daemon_version@LIBFWUPD_0.9.6 1.0.0 fwupd_client_get_details@LIBFWUPD_1.0.0 1.0.0 fwupd_client_get_device_by_id@LIBFWUPD_0.9.3 1.0.0 @@ -35,12 +52,16 @@ fwupd_client_get_remotes@LIBFWUPD_0.9.3 1.0.0 fwupd_client_get_results@LIBFWUPD_0.7.0 1.0.0 fwupd_client_get_status@LIBFWUPD_0.7.3 1.0.0 + fwupd_client_get_tainted@LIBFWUPD_1.2.4 1.2.4 fwupd_client_get_type@LIBFWUPD_0.7.0 1.0.0 fwupd_client_get_upgrades@LIBFWUPD_0.9.8 1.0.0 fwupd_client_install@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_modify_config@LIBFWUPD_1.2.8 1.2.8 fwupd_client_modify_device@LIBFWUPD_1.0.4 1.0.4 fwupd_client_modify_remote@LIBFWUPD_0.9.8 1.0.0 fwupd_client_new@LIBFWUPD_0.7.0 1.0.0 + fwupd_client_self_sign@LIBFWUPD_1.2.6 1.2.6 + fwupd_client_set_approved_firmware@LIBFWUPD_1.2.6 1.2.6 fwupd_client_unlock@LIBFWUPD_0.7.0 1.0.0 fwupd_client_update_metadata@LIBFWUPD_1.0.0 1.0.0 fwupd_client_verify@LIBFWUPD_0.7.0 1.0.0 @@ -49,7 +70,10 @@ fwupd_device_add_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_add_guid@LIBFWUPD_0.9.3 1.0.0 fwupd_device_add_icon@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_add_instance_id@LIBFWUPD_1.2.5 1.2.5 fwupd_device_add_release@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_array_from_variant@LIBFWUPD_1.2.10 1.2.10 + fwupd_device_compare@LIBFWUPD_1.1.1 1.1.1 fwupd_device_flag_from_string@LIBFWUPD_0.7.0 1.0.0 fwupd_device_flag_to_string@LIBFWUPD_0.7.0 1.0.0 fwupd_device_from_variant@LIBFWUPD_1.0.0 1.0.0 @@ -62,22 +86,31 @@ fwupd_device_get_guids@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_icons@LIBFWUPD_0.9.8 1.0.0 fwupd_device_get_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_get_install_duration@LIBFWUPD_1.1.3 1.1.3 + fwupd_device_get_instance_ids@LIBFWUPD_1.2.5 1.2.5 fwupd_device_get_modified@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_name@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_get_parent@LIBFWUPD_1.0.8 1.0.8 + fwupd_device_get_parent_id@LIBFWUPD_1.0.8 1.0.8 fwupd_device_get_plugin@LIBFWUPD_1.0.0 1.0.0 fwupd_device_get_release_default@LIBFWUPD_0.9.8 1.0.0 fwupd_device_get_releases@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_get_serial@LIBFWUPD_1.1.2 1.1.2 fwupd_device_get_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_type@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_update_error@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_get_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_device_get_update_state@LIBFWUPD_0.9.8 1.0.0 fwupd_device_get_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_vendor_id@LIBFWUPD_0.9.4 1.0.0 fwupd_device_get_version@LIBFWUPD_0.9.3 1.0.0 fwupd_device_get_version_bootloader@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_get_version_format@LIBFWUPD_1.2.9 1.2.9 fwupd_device_get_version_lowest@LIBFWUPD_0.9.3 1.0.0 fwupd_device_has_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_has_guid@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_has_instance_id@LIBFWUPD_1.2.5 1.2.5 + fwupd_device_incorporate@LIBFWUPD_1.1.0 1.1.0 fwupd_device_new@LIBFWUPD_0.9.3 1.0.0 fwupd_device_remove_flag@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_created@LIBFWUPD_0.9.3 1.0.0 @@ -85,64 +118,104 @@ fwupd_device_set_flags@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_flashes_left@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_set_install_duration@LIBFWUPD_1.1.3 1.1.3 fwupd_device_set_modified@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_name@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_set_parent@LIBFWUPD_1.0.8 1.0.8 + fwupd_device_set_parent_id@LIBFWUPD_1.0.8 1.0.8 fwupd_device_set_plugin@LIBFWUPD_1.0.0 1.0.0 + fwupd_device_set_serial@LIBFWUPD_1.1.2 1.1.2 fwupd_device_set_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_update_error@LIBFWUPD_0.9.8 1.0.0 + fwupd_device_set_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_device_set_update_state@LIBFWUPD_0.9.8 1.0.0 fwupd_device_set_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_vendor_id@LIBFWUPD_0.9.4 1.0.0 fwupd_device_set_version@LIBFWUPD_0.9.3 1.0.0 fwupd_device_set_version_bootloader@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_set_version_format@LIBFWUPD_1.2.9 1.2.9 fwupd_device_set_version_lowest@LIBFWUPD_0.9.3 1.0.0 + fwupd_device_to_json@LIBFWUPD_1.2.6 1.2.6 fwupd_device_to_string@LIBFWUPD_0.9.3 1.0.0 fwupd_device_to_variant@LIBFWUPD_1.0.0 1.0.0 + fwupd_device_to_variant_full@LIBFWUPD_1.1.2 1.1.2 fwupd_error_from_string@LIBFWUPD_0.7.0 1.0.0 fwupd_error_quark@LIBFWUPD_0.1.1 1.0.0 fwupd_error_to_string@LIBFWUPD_0.7.0 1.0.0 + fwupd_get_os_release@LIBFWUPD_1.0.7 1.0.7 + fwupd_guid_from_string@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_hash_data@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_hash_string@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_is_valid@LIBFWUPD_1.2.5 1.2.5 + fwupd_guid_to_string@LIBFWUPD_1.2.5 1.2.5 fwupd_keyring_kind_from_string@LIBFWUPD_0.9.7 1.0.0 fwupd_keyring_kind_to_string@LIBFWUPD_0.9.7 1.0.0 + fwupd_release_add_category@LIBFWUPD_1.2.7 1.2.7 fwupd_release_add_checksum@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_add_flag@LIBFWUPD_1.2.6 1.2.6 fwupd_release_add_metadata@LIBFWUPD_1.0.4 1.0.4 fwupd_release_add_metadata_item@LIBFWUPD_1.0.4 1.0.4 + fwupd_release_array_from_variant@LIBFWUPD_1.2.10 1.2.10 + fwupd_release_flag_from_string@LIBFWUPD_1.2.6 1.2.6 + fwupd_release_flag_to_string@LIBFWUPD_1.2.6 1.2.6 fwupd_release_from_variant@LIBFWUPD_1.0.0 1.0.0 fwupd_release_get_appstream_id@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_categories@LIBFWUPD_1.2.7 1.2.7 fwupd_release_get_checksums@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_description@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_details_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_get_filename@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_flags@LIBFWUPD_1.2.6 1.2.6 fwupd_release_get_homepage@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_install_duration@LIBFWUPD_1.2.1 1.2.4 fwupd_release_get_license@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_metadata@LIBFWUPD_1.0.4 1.0.4 fwupd_release_get_metadata_item@LIBFWUPD_1.0.4 1.0.4 fwupd_release_get_name@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_protocol@LIBFWUPD_1.2.2 1.2.4 fwupd_release_get_remote_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_size@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_source_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_get_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_trust_flags@LIBFWUPD_0.9.8 1.0.0 fwupd_release_get_type@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_get_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_release_get_uri@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_release_get_version@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_has_category@LIBFWUPD_1.2.7 1.2.7 + fwupd_release_has_checksum@LIBFWUPD_1.2.6 1.2.6 + fwupd_release_has_flag@LIBFWUPD_1.2.6 1.2.6 fwupd_release_new@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_remove_flag@LIBFWUPD_1.2.6 1.2.6 fwupd_release_set_appstream_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_description@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_details_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_set_filename@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_flags@LIBFWUPD_1.2.6 1.2.6 fwupd_release_set_homepage@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_install_duration@LIBFWUPD_1.2.1 1.2.4 fwupd_release_set_license@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_name@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_protocol@LIBFWUPD_1.2.2 1.2.4 fwupd_release_set_remote_id@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_size@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_set_source_url@LIBFWUPD_1.2.4 1.2.4 fwupd_release_set_summary@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_trust_flags@LIBFWUPD_0.9.8 1.0.0 + fwupd_release_set_update_message@LIBFWUPD_1.2.4 1.2.4 fwupd_release_set_uri@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_vendor@LIBFWUPD_0.9.3 1.0.0 fwupd_release_set_version@LIBFWUPD_0.9.3 1.0.0 + fwupd_release_to_json@LIBFWUPD_1.2.6 1.2.6 fwupd_release_to_string@LIBFWUPD_0.9.3 1.0.0 fwupd_release_to_variant@LIBFWUPD_1.0.0 1.0.0 + fwupd_remote_array_from_variant@LIBFWUPD_1.2.10 1.2.10 fwupd_remote_build_firmware_uri@LIBFWUPD_0.9.7 1.0.0 fwupd_remote_from_variant@LIBFWUPD_1.0.0 1.0.0 fwupd_remote_get_age@LIBFWUPD_0.9.5 1.0.0 + fwupd_remote_get_agreement@LIBFWUPD_1.0.7 1.0.7 + fwupd_remote_get_approval_required@LIBFWUPD_1.2.6 1.2.6 fwupd_remote_get_checksum@LIBFWUPD_1.0.0 1.0.0 fwupd_remote_get_enabled@LIBFWUPD_0.9.3 1.0.0 fwupd_remote_get_filename_cache@LIBFWUPD_0.9.6 1.0.0 @@ -166,6 +239,7 @@ fwupd_remote_kind_to_string@LIBFWUPD_0.9.6 1.0.0 fwupd_remote_load_from_filename@LIBFWUPD_0.9.3 1.0.0 fwupd_remote_new@LIBFWUPD_0.9.3 1.0.0 + fwupd_remote_set_agreement@LIBFWUPD_1.0.7 1.0.7 fwupd_remote_set_mtime@LIBFWUPD_0.9.5 1.0.0 fwupd_remote_set_priority@LIBFWUPD_0.9.5 1.0.0 fwupd_remote_to_variant@LIBFWUPD_1.0.0 1.0.0 @@ -175,3 +249,5 @@ fwupd_trust_flag_to_string@LIBFWUPD_0.7.0 1.0.0 fwupd_update_state_from_string@LIBFWUPD_0.7.0 1.0.0 fwupd_update_state_to_string@LIBFWUPD_0.7.0 1.0.0 + fwupd_version_format_from_string@LIBFWUPD_1.2.9 1.2.9 + fwupd_version_format_to_string@LIBFWUPD_1.2.9 1.2.9 diff -Nru fwupd-1.0.6/debian/libfwupd-dev.install fwupd-1.2.10/debian/libfwupd-dev.install --- fwupd-1.0.6/debian/libfwupd-dev.install 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/libfwupd-dev.install 2019-12-19 00:13:48.000000000 +0000 @@ -1,6 +1,5 @@ -usr/include/fwupd-1/fwupd.h -usr/include/fwupd-1/libfwupd -usr/lib/*/libfwupd*.so -usr/lib/*/pkgconfig/fwupd.pc -usr/share/gir-1.0/Fwupd*.gir +usr/include/* +usr/lib/*/*.so +usr/lib/*/pkgconfig/*.pc +usr/share/gir-1.0/*.gir usr/share/vala/vapi diff -Nru fwupd-1.0.6/debian/lintian/fwupd fwupd-1.2.10/debian/lintian/fwupd --- fwupd-1.0.6/debian/lintian/fwupd 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/lintian/fwupd 2019-12-19 00:13:48.000000000 +0000 @@ -2,5 +2,9 @@ fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/fwupd-offline-update.service fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/fwupd.service fwupd binary: systemd-service-file-missing-install-key lib/systemd/system/system-update.target.wants/fwupd-offline-update.service -#CAs is the right word, not Case -fwupd binary: spelling-error-in-binary usr/lib/fwupd/fwupd CAs Case +#see debian bug 896012 +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_upower.so +#EFI applications are PE executables +fwupd: executable-not-elf-or-script usr/lib/fwupd/efi/*.efi +fwupd: portable-executable-missing-security-features usr/lib/fwupd/efi/*.efi ASLR DEP/NX +fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_modem_manager.so diff -Nru fwupd-1.0.6/debian/lintian/fwupd-tests fwupd-1.2.10/debian/lintian/fwupd-tests --- fwupd-1.0.6/debian/lintian/fwupd-tests 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/lintian/fwupd-tests 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,2 @@ +#see debian bug 896012 +fwupd-tests: library-not-linked-against-libc usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so diff -Nru fwupd-1.0.6/debian/patches/0001-dont-semver-conversion.patch fwupd-1.2.10/debian/patches/0001-dont-semver-conversion.patch --- fwupd-1.0.6/debian/patches/0001-dont-semver-conversion.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/0001-dont-semver-conversion.patch 2020-01-09 08:24:28.000000000 +0000 @@ -0,0 +1,94 @@ +commit dfa9edcc487cc174c475bdc712f3c1965bcdfac3 +Author: Richard Hughes +Date: Wed Dec 4 15:05:12 2019 +0000 + + Do not do semver conversion in fu_common_vercmp() + + We don't know the version format, and so it's impossible to do it reliably -- + just do it in the caller where we *do* know the FuDevice version format. + + Cherry-picked from 1fbcb1a1808adebbe80a9c45f156bb695b02fb43 + +--- a/src/fu-common-version.c ++++ b/src/fu-common-version.c +@@ -347,8 +347,8 @@ + + /** + * fu_common_vercmp: +- * @version_a: the release version, e.g. 1.2.3 +- * @version_b: the release version, e.g. 1.2.3.1 ++ * @version_a: the semver release version, e.g. 1.2.3 ++ * @version_b: the semver release version, e.g. 1.2.3.1 + * + * Compares version numbers for sorting. + * +@@ -360,8 +360,6 @@ + fu_common_vercmp (const gchar *version_a, const gchar *version_b) + { + guint longest_split; +- g_autofree gchar *str_a = NULL; +- g_autofree gchar *str_b = NULL; + g_auto(GStrv) split_a = NULL; + g_auto(GStrv) split_b = NULL; + +@@ -374,10 +372,8 @@ + return 0; + + /* split into sections, and try to parse */ +- str_a = fu_common_version_parse (version_a); +- str_b = fu_common_version_parse (version_b); +- split_a = g_strsplit (str_a, ".", -1); +- split_b = g_strsplit (str_b, ".", -1); ++ split_a = g_strsplit (version_a, ".", -1); ++ split_b = g_strsplit (version_b, ".", -1); + longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b)); + for (guint i = 0; i < longest_split; i++) { + gchar *endptr_a = NULL; +--- a/src/fu-install-task.c ++++ b/src/fu-install-task.c +@@ -111,10 +111,11 @@ + { + const gchar *tmp; + const gchar *version; +- const gchar *version_release; ++ const gchar *version_release_raw; + const gchar *version_lowest; + gboolean matches_guid = FALSE; + gint vercmp; ++ g_autofree gchar *version_release = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) release = NULL; +@@ -209,8 +210,8 @@ + } + + /* is this a downgrade or re-install */ +- version_release = xb_node_get_attr (release, "version"); +- if (version_release == NULL) { ++ version_release_raw = xb_node_get_attr (release, "version"); ++ if (version_release_raw == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, +@@ -273,6 +274,8 @@ + } + + /* check semver */ ++ version_release = fu_common_version_parse_from_format (version_release_raw, ++ fu_device_get_version_format (self->device)); + vercmp = fu_common_vercmp (version, version_release); + if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { + g_set_error (error, +--- a/src/fu-self-test.c ++++ b/src/fu-self-test.c +@@ -3620,10 +3620,6 @@ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0); + +- /* same, not dotted decimal */ +- g_assert_cmpint (fu_common_vercmp ("1.2.3", "0x1020003"), ==, 0); +- g_assert_cmpint (fu_common_vercmp ("0x10203", "0x10203"), ==, 0); +- + /* upgrade and downgrade */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0); diff -Nru fwupd-1.0.6/debian/patches/0001-Only-check-the-vendor-ID-if-the-device-has-one-set.patch fwupd-1.2.10/debian/patches/0001-Only-check-the-vendor-ID-if-the-device-has-one-set.patch --- fwupd-1.0.6/debian/patches/0001-Only-check-the-vendor-ID-if-the-device-has-one-set.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/0001-Only-check-the-vendor-ID-if-the-device-has-one-set.patch 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,28 @@ +From 004a0624d05211e8436060bb7af6b0c6f2d805a3 Mon Sep 17 00:00:00 2001 +From: Richard Hughes +Date: Mon, 9 Dec 2019 10:30:19 +0000 +Subject: [PATCH] Only check the vendor ID if the device has one set + +This means we don't get a weird error if the metadata sets a vendor-id, but the +device does not. +--- + src/fu-engine.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/fu-engine.c b/src/fu-engine.c +index d07843c3..814d15a6 100644 +--- a/src/fu-engine.c ++++ b/src/fu-engine.c +@@ -1058,7 +1058,8 @@ fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, + } + + /* vendor ID */ +- if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) { ++ if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0 && ++ fu_device_get_vendor_id (device) != NULL) { + const gchar *version = fu_device_get_vendor_id (device); + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { +-- +2.20.1 + diff -Nru fwupd-1.0.6/debian/patches/0001-plain_support_in_version.patch fwupd-1.2.10/debian/patches/0001-plain_support_in_version.patch --- fwupd-1.0.6/debian/patches/0001-plain_support_in_version.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/0001-plain_support_in_version.patch 2020-01-09 08:24:33.000000000 +0000 @@ -0,0 +1,32 @@ +commit a7434265e671ba330214aaab54a41ad1335015ad +Author: Richard Hughes +Date: Wed Dec 4 15:04:19 2019 +0000 + + trivial: Support 'plain' in fu_common_version_from_uintXX() + + Cherry picked from f21add626 + +diff --git a/src/fu-common-version.c b/src/fu-common-version.c +index e4a11002..0ee73f2a 100644 +--- a/src/fu-common-version.c ++++ b/src/fu-common-version.c +@@ -52,7 +52,8 @@ fu_common_version_from_uint32 (guint32 val, FwupdVersionFormat kind) + (val >> 16) & 0xffff, + val & 0xffff); + } +- if (kind == FWUPD_VERSION_FORMAT_NUMBER) { ++ if (kind == FWUPD_VERSION_FORMAT_NUMBER || ++ kind == FWUPD_VERSION_FORMAT_PLAIN) { + /* AABBCCDD */ + return g_strdup_printf ("%" G_GUINT32_FORMAT, val); + } +@@ -109,7 +110,8 @@ fu_common_version_from_uint16 (guint16 val, FwupdVersionFormat kind) + (guint) (val >> 8) & 0xff, + (guint) val & 0xff); + } +- if (kind == FWUPD_VERSION_FORMAT_NUMBER) { ++ if (kind == FWUPD_VERSION_FORMAT_NUMBER || ++ kind == FWUPD_VERSION_FORMAT_PLAIN) { + return g_strdup_printf ("%" G_GUINT16_FORMAT, val); + } + g_critical ("failed to convert version format %s: %u", diff -Nru fwupd-1.0.6/debian/patches/0001-Relax-the-certificate-time-checks-in-the-self-tests-.patch fwupd-1.2.10/debian/patches/0001-Relax-the-certificate-time-checks-in-the-self-tests-.patch --- fwupd-1.0.6/debian/patches/0001-Relax-the-certificate-time-checks-in-the-self-tests-.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/0001-Relax-the-certificate-time-checks-in-the-self-tests-.patch 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,86 @@ +From b4627629cdaadd1a75d7c650b7c5973fcd18dfb0 Mon Sep 17 00:00:00 2001 +From: Richard Hughes +Date: Thu, 1 Aug 2019 09:45:25 +0100 +Subject: [PATCH] Relax the certificate time checks in the self tests for the + legacy certificate + +One test verifies a firmware with a signature from the old LVFS which was +hosted on secure-lvfs.rhcloud.com and used the original PKCS-7 key. This key +had a two year validity (expiring today, ohh the naivety...) rather than the +newer fwupd.org key which expires in the year 2058. + +For this specific test only, disable the certificate time checks to fix CI. + +Fixes https://github.com/hughsie/fwupd/issues/1264 +--- + src/fu-keyring-pkcs7.c | 10 +++++++++- + src/fu-keyring.h | 6 ++++-- + src/fu-self-test.c | 3 ++- + 3 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/src/fu-keyring-pkcs7.c b/src/fu-keyring-pkcs7.c +index 6dc944ed..a42feaa7 100644 +--- a/src/fu-keyring-pkcs7.c ++++ b/src/fu-keyring-pkcs7.c +@@ -642,6 +642,14 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring, + for (gint i = 0; i < count; i++) { + gnutls_pkcs7_signature_info_st info; + gint64 signing_time = 0; ++ gnutls_certificate_verify_flags verify_flags = 0; ++ ++ /* use with care */ ++ if (flags & FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS) { ++ g_debug ("WARNING: disabling time checks"); ++ verify_flags |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS; ++ verify_flags |= GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS; ++ } + + /* verify the data against the detached signature */ + if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { +@@ -652,7 +660,7 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring, + 0, /* vdata_size */ + i, /* index */ + &datum, /* data */ +- 0); /* flags */ ++ verify_flags); + } + if (rc < 0) { + g_set_error (error, +diff --git a/src/fu-keyring.h b/src/fu-keyring.h +index 39819ca4..2f20e35e 100644 +--- a/src/fu-keyring.h ++++ b/src/fu-keyring.h +@@ -20,12 +20,14 @@ G_DECLARE_DERIVABLE_TYPE (FuKeyring, fu_keyring, FU, KEYRING, GObject) + * FuKeyringVerifyFlags: + * @FU_KEYRING_VERIFY_FLAG_NONE: No flags set + * @FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT: Use client certificate to verify ++ * @FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS: Disable checking of validity periods + * + * The flags to use when interacting with a keyring + **/ + typedef enum { +- FU_KEYRING_VERIFY_FLAG_NONE = 0, +- FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT = 1 << 1, ++ FU_KEYRING_VERIFY_FLAG_NONE = 0, ++ FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT = 1 << 1, ++ FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS = 1 << 2, + /*< private >*/ + FU_KEYRING_VERIFY_FLAG_LAST + } FuKeyringVerifyFlags; +diff --git a/src/fu-self-test.c b/src/fu-self-test.c +index 363f644e..24b12110 100644 +--- a/src/fu-self-test.c ++++ b/src/fu-self-test.c +@@ -2628,7 +2628,8 @@ fu_keyring_pkcs7_func (void) + g_assert_no_error (error); + g_assert_nonnull (blob_sig); + result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, +- FU_KEYRING_VERIFY_FLAG_NONE, &error); ++ FU_KEYRING_VERIFY_FLAG_DISABLE_TIME_CHECKS, ++ &error); + g_assert_no_error (error); + g_assert_nonnull (result_pass); + g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), >= , 1502871248); +-- +2.20.1 + diff -Nru fwupd-1.0.6/debian/patches/0001-trivial-libfwupd-skip-tests-if-machine-id-is-empty-t.patch fwupd-1.2.10/debian/patches/0001-trivial-libfwupd-skip-tests-if-machine-id-is-empty-t.patch --- fwupd-1.0.6/debian/patches/0001-trivial-libfwupd-skip-tests-if-machine-id-is-empty-t.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/0001-trivial-libfwupd-skip-tests-if-machine-id-is-empty-t.patch 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,38 @@ +From d0fd614bb9023ea7c8f831fc6bfe122a3dbc9032 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello +Date: Tue, 24 Sep 2019 10:29:22 -0500 +Subject: [PATCH] trivial: libfwupd: skip tests if machine-id is empty too + +Ubuntu's buildds seem to have changed and this is causing test suite +failures. +--- + libfwupd/fwupd-self-test.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Index: fwupd-1.2.10/libfwupd/fwupd-self-test.c +=================================================================== +--- fwupd-1.2.10.orig/libfwupd/fwupd-self-test.c ++++ fwupd-1.2.10/libfwupd/fwupd-self-test.c +@@ -504,6 +504,8 @@ fwupd_has_system_bus (void) + static void + fwupd_common_machine_hash_func (void) + { ++ gsize sz = 0; ++ g_autofree gchar *buf = NULL; + g_autofree gchar *mhash1 = NULL; + g_autofree gchar *mhash2 = NULL; + g_autoptr(GError) error = NULL; +@@ -512,6 +514,13 @@ fwupd_common_machine_hash_func (void) + g_test_skip ("Missing /etc/machine-id"); + return; + } ++ if (!g_file_get_contents ("/etc/machine-id", &buf, &sz, &error)) ++ return; ++ ++ if (sz == 0) { ++ g_test_skip ("Empty /etc/machine-id"); ++ return; ++ } + + mhash1 = fwupd_build_machine_id ("salt1", &error); + g_assert_no_error (error); diff -Nru fwupd-1.0.6/debian/patches/0001-version-handling.patch fwupd-1.2.10/debian/patches/0001-version-handling.patch --- fwupd-1.0.6/debian/patches/0001-version-handling.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/0001-version-handling.patch 2020-01-09 08:24:37.000000000 +0000 @@ -0,0 +1,103 @@ +commit a59d92fe11637d2a62f71bda9024481cbb9956c5 +Author: Mario Limonciello +Date: Mon Oct 14 08:44:39 2019 -0500 + + fu-engine: Read all releases and convert versions when comparing + + Fixes matching ESRT version to metadata version for UEFI + + Cherry-picked from 91d36095e12f2486c774d38eeabcc5b0ddfb0685 + +diff --git a/src/fu-common-version.c b/src/fu-common-version.c +index cd732a38..e4a11002 100644 +--- a/src/fu-common-version.c ++++ b/src/fu-common-version.c +@@ -214,6 +214,31 @@ fu_common_version_ensure_semver (const gchar *version) + */ + gchar * + fu_common_version_parse (const gchar *version) ++{ ++ return fu_common_version_parse_from_format (version, FWUPD_VERSION_FORMAT_TRIPLET); ++} ++ ++/** ++ * fu_common_version_parse_from_format ++ * @version: A version number ++ * @fmt: A FwupdVersionFormat ++ * ++ * Returns a dotted decimal version string from a version string using fmt. ++ * The supported formats are: ++ * ++ * - Dotted decimal, e.g. "1.2.3" ++ * - Base 16, a hex number *with* a 0x prefix, e.g. "0x10203" ++ * - Base 10, a string containing just [0-9], e.g. "66051" ++ * - Date in YYYYMMDD format, e.g. 20150915 ++ * ++ * Anything with a '.' or that doesn't match [0-9] or 0x[a-f,0-9] is considered ++ * a string and returned without modification. ++ * ++ * Returns: A version number, e.g. "1.0.3" ++ * ++ */ ++gchar * ++fu_common_version_parse_from_format (const gchar *version, FwupdVersionFormat fmt) + { + const gchar *version_noprefix = version; + gchar *endptr = NULL; +@@ -246,7 +271,7 @@ fu_common_version_parse (const gchar *version) + return g_strdup (version); + if (tmp == 0) + return g_strdup (version); +- return fu_common_version_from_uint32 ((guint32) tmp, FWUPD_VERSION_FORMAT_TRIPLET); ++ return fu_common_version_from_uint32 ((guint32) tmp, fmt); + } + + /** +diff --git a/src/fu-common-version.h b/src/fu-common-version.h +index 7899da2d..c25b37ac 100644 +--- a/src/fu-common-version.h ++++ b/src/fu-common-version.h +@@ -18,6 +18,8 @@ gchar *fu_common_version_from_uint32 (guint32 val, + gchar *fu_common_version_from_uint16 (guint16 val, + FwupdVersionFormat kind); + gchar *fu_common_version_parse (const gchar *version); ++gchar *fu_common_version_parse_from_format (const gchar *version, ++ FwupdVersionFormat fmt); + gchar *fu_common_version_ensure_semver (const gchar *version); + FwupdVersionFormat fu_common_version_guess_format (const gchar *version); + gboolean fu_common_version_verify_format (const gchar *version, +diff --git a/src/fu-engine.c b/src/fu-engine.c +index 814d15a6..0139c8e5 100644 +--- a/src/fu-engine.c ++++ b/src/fu-engine.c +@@ -842,14 +842,27 @@ fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) + /* try again with the system metadata */ + if (release == NULL) { + GPtrArray *guids = fu_device_get_guids (device); ++ FwupdVersionFormat fmt = fu_device_get_version_format (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autofree gchar *xpath2 = NULL; ++ g_autoptr(GPtrArray) releases = NULL; + xpath2 = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" +- "../../releases/release[@version='%s']", +- guid, version); +- release = xb_silo_query_first (self->silo, xpath2, NULL); ++ "../../releases/release", ++ guid); ++ releases = xb_silo_query (self->silo, xpath2, 0, error); ++ if (releases == NULL) ++ return FALSE; ++ for (guint j = 0; j < releases->len; j++) { ++ XbNode *rel = g_ptr_array_index (releases, j); ++ const gchar *rel_ver = xb_node_get_attr (rel, "version"); ++ g_autofree gchar *tmp_ver = fu_common_version_parse_from_format (rel_ver, fmt); ++ if (fu_common_vercmp (tmp_ver, version) == 0) { ++ release = g_object_ref (rel); ++ break; ++ } ++ } + if (release != NULL) + break; + } diff -Nru fwupd-1.0.6/debian/patches/meson-0.45-bc.patch fwupd-1.2.10/debian/patches/meson-0.45-bc.patch --- fwupd-1.0.6/debian/patches/meson-0.45-bc.patch 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/meson-0.45-bc.patch 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,47 @@ +Description: meson 0.45 backward compatibility patch + + * meson 0.45 backward compatibility patch from Mario. + +Author: Yuan-Chen Cheng + +--- +The information above should follow the Patch Tagging Guidelines, please +checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here +are templates for supplementary fields that you might want to add: + +Origin: , +Bug: +Bug-Debian: https://bugs.debian.org/ +Bug-Ubuntu: https://launchpad.net/bugs/ +Forwarded: +Reviewed-By: +Last-Update: 2019-08-01 + +--- fwupd-1.2.10.orig/meson.build ++++ fwupd-1.2.10/meson.build +@@ -1,7 +1,7 @@ + project('fwupd', 'c', + version : '1.2.10', + license : 'LGPL-2.1+', +- meson_version : '>=0.47.0', ++ meson_version : '>=0.44.0', + default_options : ['warning_level=2', 'c_std=c99'], + ) + +@@ -115,8 +115,14 @@ test_link_args = [ + '-Wl,-z,now', + ] + foreach arg: test_link_args +- if cc.has_link_argument(arg) +- global_link_args += arg ++ if meson.version().version_compare('>=0.46.0') ++ if cc.has_link_argument(arg) ++ global_link_args += arg ++ endif ++ else ++ if cc.has_argument(arg) ++ global_link_args += arg ++ endif + endif + endforeach + add_global_link_arguments( diff -Nru fwupd-1.0.6/debian/patches/series fwupd-1.2.10/debian/patches/series --- fwupd-1.0.6/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/patches/series 2020-01-09 08:25:01.000000000 +0000 @@ -0,0 +1,8 @@ +0001-Relax-the-certificate-time-checks-in-the-self-tests-.patch +0001-trivial-libfwupd-skip-tests-if-machine-id-is-empty-t.patch +meson-0.45-bc.patch +0001-Only-check-the-vendor-ID-if-the-device-has-one-set.patch +0001-dont-semver-conversion.patch +0001-version-handling.patch +0001-plain_support_in_version.patch + diff -Nru fwupd-1.0.6/debian/README.Debian fwupd-1.2.10/debian/README.Debian --- fwupd-1.0.6/debian/README.Debian 2018-03-12 11:53:58.000000000 +0000 +++ fwupd-1.2.10/debian/README.Debian 2019-12-19 00:13:48.000000000 +0000 @@ -1,7 +1,18 @@ -fwupd for Debian ----------------- +signed vs unsigned fwupd programs +------------------------------------ -fwupd is still heavily in development. As of this date, the functionality -it provides is not yet available on most systems. +fwupd 1.1.0 is configured to understand when to use a signed version +of the EFI binary. If the signed version isn't installed but secure +boot is turned on, it will avoid copying to the EFI system partition. + +This allows supporting secure boot even if not turned on at install, or +changed later after install. + +In Ubuntu, both fwupd-signed and fwupd are seeded in the default +installation. Nothing is installed to the ESP until it's needed. + +In Debian, the package name for the signed version is slightly +different due to different infrastructure. fwupd-signed-$ARCH and +fwupd should both be installed and then things will work similarly +to what's described above. - -- Daniel Jared Dominguez Wed, 20 May 2015 17:16:02 -0500 diff -Nru fwupd-1.0.6/debian/rules fwupd-1.2.10/debian/rules --- fwupd-1.0.6/debian/rules 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/rules 2019-12-19 00:13:48.000000000 +0000 @@ -3,6 +3,7 @@ export LC_ALL := C.UTF-8 export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_STRIP=-Wl,-Bsymbolic-functions #GPGME needs this for proper building on 32 bit archs ifeq "$(DEB_HOST_ARCH_BITS)" "32" @@ -10,40 +11,84 @@ endif ifneq ($(CI),) - export CI=--werror + export CI=--werror --wrap-mode=default endif regenerate_control: - OS=debian-x86_64 ./contrib/ci/generate_debian_control.py debian/control.in debian/control + OS=debian-x86_64 ./contrib/ci/generate_debian.py + +SB_STYLE := debian +deb_version := $(shell dpkg-parsechangelog --show-field Version) +ifeq (yes,$(shell dpkg-vendor --derives-from Ubuntu && echo yes)) + SB_STYLE := ubuntu + tar_name := fwupd_$(deb_version)_$(DEB_HOST_ARCH).tar.gz +else + TMPLDIR := debian/fwupd-$(DEB_HOST_ARCH)-signed-template/usr/share/code-signing/fwupd-$(DEB_HOST_ARCH)-signed-template +endif %: [ -f debian/control ] || debian/rules regenerate_control - dh $@ --with gir,systemd + dh $@ --with gir override_dh_auto_clean: regenerate_control rm -fr debian/build +ifeq (ubuntu,$(SB_STYLE)) + rm -rf debian/fwupd-images +endif override_dh_auto_configure: - if pkg-config --exists fwup; then \ - export UEFI="-Dplugin_uefi=true"; \ + if pkg-config --exists libsmbios_c; then \ + export DELL="-Dplugin_dell=true"; \ else \ - export UEFI="-Dplugin_uefi=false"; \ + export DELL="-Dplugin_dell=false"; \ fi; \ - if pkg-config --exists libsmbios_c; then \ - export DELL="-Dplugin_dell=true -Dplugin_synaptics=true"; \ + if pkg-config --exists efivar; then \ + export UEFI="-Dplugin_uefi=true -Dplugin_redfish=true -Dplugin_nvme=true"; \ + else \ + export UEFI="-Dplugin_uefi=false -Dplugin_redfish=false -Dplugin_nvme=false"; \ + fi; \ + if [ ! -z "$$CI" ]; then \ + export FLASHROM="-Dplugin_flashrom=true"; \ else \ - export DELL="-Dplugin_dell=false -Dplugin_synaptics=false"; \ + export FLASHROM="-Dplugin_flashrom=false"; \ fi; \ - dh_auto_configure -- $$UEFI $$DELL $$CI -Dplugin_dummy=true --libexecdir=/usr/lib + dh_auto_configure -- $$UEFI $$DELL $$FLASHROM $$CI -Dplugin_dummy=true --libexecdir=/usr/lib override_dh_install: find debian/tmp/usr -type f -name "*a" -print | xargs rm -f sed -i 's,wheel,sudo,' ./debian/tmp/usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules dh_install - dh_missing --fail-missing + #install the EFI binaries if needed + if [ -d debian/tmp/usr/lib/fwupd/efi/ ]; then \ + dh_install -pfwupd usr/lib/fwupd/efi ;\ + dh_install -pfwupd usr/lib/fwupd/fwupdate; \ + fi + #if build with meson subproject in CI need to install this too + if [ ! -z "$$CI" ] && [ -f debian/tmp/usr/lib/xb-tool ]; then \ + dh_install -pfwupd usr/lib/xb-tool ;\ + fi + if [ ! -z "$$CI" ] && [ -f debian/tmp/usr/sbin/flashrom ]; then \ + dh_install -pfwupd usr/sbin/flashrom ;\ + fi + dh_missing -a --fail-missing #this is placed in fwupd-tests rm -f debian/fwupd/usr/lib/*/fwupd-plugins-3/libfu_plugin_test.so + rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf + +ifeq (debian,$(SB_STYLE)) + # Generate the template source for the Debian signing service to use + mkdir -p $(TMPLDIR)/source-template/debian + cp -a debian/signing-template/* $(TMPLDIR)/source-template/debian + cp debian/README.Debian $(TMPLDIR)/source-template/debian + find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNARCH,$(DEB_HOST_ARCH)," + find $(TMPLDIR)/source-template/debian -type f | xargs sed -i "s,SIGNVERSION,$(deb_version)," + for file in $$(find $(TMPLDIR)/source-template/debian -type f -name *SIGNARCH*); do file1=$$(echo $$file | sed "s,SIGNARCH,$(DEB_HOST_ARCH),"); mv -v $$file $$file1; done + install -m 0755 debian/fwupd.postinst $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postinst + install -m 0755 debian/fwupd.postrm $(TMPLDIR)/source-template/debian/fwupd-$(DEB_HOST_ARCH)-signed.postrm + ./debian/gen_signing_changelog $(TMPLDIR)/source-template/debian fwupd $(DEB_HOST_ARCH) + ./debian/gen_signing_json $(TMPLDIR) fwupd ${DEB_HOST_ARCH} +endif override_dh_strip_nondeterminism: dh_strip_nondeterminism -Xfirmware-example.xml.gz @@ -52,3 +97,18 @@ if [ -x /usr/bin/valgrind ] ; then \ dh_auto_test; \ fi + +override_dh_builddeb: + dh_builddeb +ifeq (ubuntu,$(SB_STYLE)) + if [ -d debian/tmp/usr/lib/fwupd/efi/ ]; then \ + mkdir -p debian/fwupd-images/$(deb_version) ;\ + cp debian/tmp/usr/lib/fwupd/efi/fwupd*.efi debian/fwupd-images/$(deb_version) ;\ + echo $(deb_version) > debian/fwupd-images/$(deb_version)/version ;\ + tar -C debian/fwupd-images -czvf ../$(tar_name) . ;\ + dpkg-distaddfile $(tar_name) raw-uefi - ;\ + fi +endif + +override_dh_shlibdeps: + dh_shlibdeps $$DHSLIBS diff -Nru fwupd-1.0.6/debian/signing-template/changelog.in fwupd-1.2.10/debian/signing-template/changelog.in --- fwupd-1.0.6/debian/signing-template/changelog.in 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/changelog.in 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,5 @@ +fwupd-SIGNARCH-signed (1) unstable; urgency=medium + + * Add template source package for signing + + -- Steve McIntyre <93sam@debian.org> Sat, 07 Apr 2018 12:44:55 +0100 diff -Nru fwupd-1.0.6/debian/signing-template/compat fwupd-1.2.10/debian/signing-template/compat --- fwupd-1.0.6/debian/signing-template/compat 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/compat 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1 @@ +9 diff -Nru fwupd-1.0.6/debian/signing-template/control fwupd-1.2.10/debian/signing-template/control --- fwupd-1.0.6/debian/signing-template/control 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/control 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,24 @@ +Source: fwupd-SIGNARCH-signed +Priority: optional +Maintainer: Debian EFI +Uploaders: Daniel Jared Dominguez , Steve McIntyre <93sam@debian.org>, Mario Limonciello +Build-Depends: debhelper (>= 9.0.0), sbsigntool [amd64 arm64 armhf i386], fwupd (= SIGNVERSION) [SIGNARCH] +Standards-Version: 4.1.3 +Section: libs +Homepage: https://github.com/hughsie/fwupd +Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git +Vcs-Browser: https://salsa.debian.org/efi-team/fwupd + +Package: fwupd-SIGNARCH-signed +Section: admin +Architecture: SIGNARCH +Provides: fwupd-signed +Depends: ${shlibs:Depends}, ${misc:Depends}, fwupd (= SIGNVERSION) +Description: Tools to manage UEFI firmware updates (signed) + fwupd provides functionality to update system firmware. It has been + initially designed to update firmware using UEFI capsule updates, but + it is designed to be extensible to other firmware update standards. + . + This package contains just the signed version of the fwupd binary, + needed if your system has UEFI Secure Boot enabled. It depends on the + normal fwupd package for everything else. diff -Nru fwupd-1.0.6/debian/signing-template/copyright fwupd-1.2.10/debian/signing-template/copyright --- fwupd-1.0.6/debian/signing-template/copyright 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/copyright 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,33 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fwupd +Source: https://github.com/hughsie/fwupd + +Files: * +Copyright: 2015 Richard Hughes +License: LGPL-2.1+ + +Files: data/tests/colorhug/firmware.metainfo.xml +Copyright: 2015 Richard Hughes +License: CC0-1.0 + +Files: debian/* +Copyright: 2015 Daniel Jared Dominguez + 2015 Mario Limonciello +License: LGPL-2.1+ + +License: LGPL-2.1+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + . + This package 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 Lesser General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". diff -Nru fwupd-1.0.6/debian/signing-template/fwupd-SIGNARCH-signed.install fwupd-1.2.10/debian/signing-template/fwupd-SIGNARCH-signed.install --- fwupd-1.0.6/debian/signing-template/fwupd-SIGNARCH-signed.install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/fwupd-SIGNARCH-signed.install 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1 @@ +*.efi.signed /usr/lib/fwupd/efi diff -Nru fwupd-1.0.6/debian/signing-template/README.source fwupd-1.2.10/debian/signing-template/README.source --- fwupd-1.0.6/debian/signing-template/README.source 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/README.source 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,4 @@ +This source package is generated by the Debian signing service from a +template built by the fwupd package. It should never be updated directly. + + -- Steve McIntyre <93sam@debian.org> Sat, 07 Apr 2018 12:44:55 +0100 diff -Nru fwupd-1.0.6/debian/signing-template/rules fwupd-1.2.10/debian/signing-template/rules --- fwupd-1.0.6/debian/signing-template/rules 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/rules 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1,15 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +PACKAGE_NAME := fwupd +SIG_PKG_NAME := fwupd-SIGNARCH-signed +SIGNATURE_DIR := debian/signatures/$(PACKAGE_NAME) +BINARY := $(shell find /usr/lib/fwupd/efi -name '*.efi' | xargs basename) + +%: + dh $@ + +override_dh_auto_build: + cp /usr/lib/fwupd/efi/$(BINARY) . + sbattach --attach $(SIGNATURE_DIR)/usr/lib/fwupd/efi/$(BINARY).sig $(BINARY) + mv $(BINARY) $(BINARY).signed diff -Nru fwupd-1.0.6/debian/signing-template/source/format fwupd-1.2.10/debian/signing-template/source/format --- fwupd-1.0.6/debian/signing-template/source/format 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/debian/signing-template/source/format 2019-12-19 00:13:48.000000000 +0000 @@ -0,0 +1 @@ +3.0 (native) diff -Nru fwupd-1.0.6/debian/source/lintian-overrides fwupd-1.2.10/debian/source/lintian-overrides --- fwupd-1.0.6/debian/source/lintian-overrides 2018-03-12 11:54:04.000000000 +0000 +++ fwupd-1.2.10/debian/source/lintian-overrides 2019-12-19 00:13:48.000000000 +0000 @@ -1,2 +1,4 @@ #github doesn't have these -fwupd source: debian-watch-may-check-gpg-signature +fwupd source: debian-watch-does-not-check-gpg-signature +#to make CI happy until libxmlb lands +fwupd source: source-is-missing diff -Nru fwupd-1.0.6/docs/architecture-plan.svg fwupd-1.2.10/docs/architecture-plan.svg --- fwupd-1.0.6/docs/architecture-plan.svg 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/docs/architecture-plan.svg 2019-07-15 18:25:54.000000000 +0000 @@ -13,7 +13,7 @@ height="744.09448" id="svg2" version="1.1" - inkscape:version="0.91 r13725" + inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="architecture-plan.svg" inkscape:export-filename="/home/hughsie/Code/colord/doc/website/img/architecture-plan.png" inkscape:export-xdpi="59.99197" @@ -184,6 +184,34 @@ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> + + + + + + + ry="5" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> fwupd + x="540.91553" + y="710.87421" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell;text-align:center;text-anchor:middle">fwupd + style="fill:#fce94f;fill-opacity:1;stroke:#edd400;stroke-width:1.88976378;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> ESRT + style="fill:#fce94f;fill-opacity:1;stroke:#edd400;stroke-width:1.88976378;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> VendorcustomProvders + id="tspan1140">plugins + ry="5" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> Udev + x="269.30994" + y="810.13818" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.33333397px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell;text-align:center;text-anchor:middle">udev + style="fill:#ad7fa8;fill-opacity:1;stroke:#75507b;stroke-width:1.88976378;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> systemd + ry="5" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> pending.db + x="809.0918" + y="807.82349" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.33333397px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell;text-align:center;text-anchor:middle">pending.db + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" + sodipodi:nodetypes="cc" /> + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" + sodipodi:nodetypes="ccc" /> + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" + sodipodi:nodetypes="cc" /> + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> session + x="48.273308" + y="481.51367" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;line-height:1.25;font-family:Cantarell;-inkscape-font-specification:Cantarell">internet system - system + - - - fwupdmgr + style="fill:#729fcf;fill-opacity:1;stroke:#3465a4;stroke-width:1.88976383;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> + style="fill:#d3d7cf;fill-opacity:1;stroke:#888a85;stroke-width:1.88976383;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> downloadcache - + y="560.53821" + x="809.99036" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:'Bitstream Vera Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" + xml:space="preserve" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408">downloadcache - + style="fill:#8ae234;fill-opacity:1;stroke:#73d216;stroke-width:1.88976383;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> Internet + sodipodi:role="line">CDN - Gudev + rules + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" + sodipodi:nodetypes="cc" /> sqlite $home - gnome-softwaregnome-software + id="tspan1643">fwupdmgr + + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" + sodipodi:nodetypes="cc" /> UpdateMetadata() GetDevices() + height="60" + x="720" + y="872.36218" + ry="5" /> sysfs + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" + sodipodi:nodetypes="ccc" /> metadata + sodipodi:role="line">only metadata firmware - firmware + + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> + inkscape:export-filename="/home/hughsie/Documents/Presentations/LVFS/010-architecture-plan.png" + inkscape:export-xdpi="119.94408" + inkscape:export-ydpi="119.94408" /> AppStream XML + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LVFS + + + + + session + embargoed metadata + + + diff -Nru fwupd-1.0.6/docs/libfwupd/libfwupd-docs.xml fwupd-1.2.10/docs/libfwupd/libfwupd-docs.xml --- fwupd-1.0.6/docs/libfwupd/libfwupd-docs.xml 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/docs/libfwupd/libfwupd-docs.xml 2019-07-15 18:25:54.000000000 +0000 @@ -41,13 +41,15 @@ Functionality available to plugins. - - - - + - + + + + + + @@ -153,7 +155,7 @@
- Creating an abstact device + Creating an abstract device This section shows how you would create a device which is exported to the daemon and thus can be queried and updated by the client software. @@ -292,7 +294,7 @@ For some hardware, we might want to do an action before or after the actual firmware is squirted into the device. This could be something as simple as checking the system battery - level is over a certain theshold, or it could be as complicated as + level is over a certain threshold, or it could be as complicated as ensuring a vendor-specific GPIO is asserted when specific types of hardware are updated. @@ -332,7 +334,7 @@ Detaching to bootloader mode Some hardware can only be updated in a special bootloader mode, which - for most devices can be switched to automaticaly. + for most devices can be switched to automatically. In some cases the user to do something manually, for instance re-inserting the hardware with a secret button pressed. diff -Nru fwupd-1.0.6/docs/meson.build fwupd-1.2.10/docs/meson.build --- fwupd-1.0.6/docs/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/docs/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,3 +1 @@ -if get_option('gtkdoc') - subdir('libfwupd') -endif +subdir('libfwupd') diff -Nru fwupd-1.0.6/docs/version-format.md fwupd-1.2.10/docs/version-format.md --- fwupd-1.0.6/docs/version-format.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/docs/version-format.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,58 @@ +Version Formats +=============== + +In some circumstances fwupd has to convert from a unsigned integer version +number into something that has either been used in documentation or has been +defined in some specification. +A good example here is the UEFI ESRT table, which specifies a `uint32_t` for +the version but does not specify how this should be formatted for the user. + +As is typical in underspecified specifications, vendors have converted the +integer in different ways. For instance, Dell uses version strings like 1.2.3 +and Microsoft use versions like 1.2.3.4. + +The fwudp daemon can match specific devices and apply the correct version style +using quirk files. The version format can also be specified in the firmware +`metainfo.xml` file so that the new version is correctly shown, and so that it +matches on the LVFS website. + +The current version formats supported by fwupd and the LVFS are: + + * `plain`: Use plain integer version numbers with no dots, e.g. `AABBCCDD` + * `quad`: Use Dell-style `AA.BB.CC.DD` version numbers + * `triplet`: Use Microsoft-style `AA.BB.CCDD` version numbers + * `pair`: Use two `AABB.CCDD` version numbers + * `bcd`: Use binary coded decimal notation + * `intel-me`: Use Intel ME-style notation (`aaa+11.bbbbb.CC.DDDD`) + * `intel-me2`: Use alternate Intel ME-style-style `A.B.CC.DDDD` notation + +These can be specified in quirk files like this: + + # Vendor Modelname + [Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] + VersionFormat = intel-me2 + +...or in metainfo.xml files like this: + + + intel-me2 + + +Runtime requirements +-------------------- + +Versions of fwupd `< 1.2.0` can only support firmware updates with key values +`LVFS::VersionFormat` of `quad` and `triplet`. Additionally, on older versions +no quirk `VersionFormat` device fixups are supported. + +If want to use one of the additional version formats you should depend on a +specific version of fwupd in the firmware file: + + + org.freedesktop.fwupd + + +This is not *strictly* required, as the integer value can be used for update +calculations if the version is specified in hex (e.g. `0x12345678`) in the +`` tag, although the user might get a bit confused if the update +version does not match the update description. diff -Nru fwupd-1.0.6/.github/pull_request_template.md fwupd-1.2.10/.github/pull_request_template.md --- fwupd-1.0.6/.github/pull_request_template.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/.github/pull_request_template.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,5 @@ +Type of pull request: +- [ ] New plugin (Please include [new plugin checklist](https://github.com/hughsie/fwupd/wiki/New-plugin-checklist)) +- [ ] Code fix +- [ ] Feature +- [ ] Documentation diff -Nru fwupd-1.0.6/.gitignore fwupd-1.2.10/.gitignore --- fwupd-1.0.6/.gitignore 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/.gitignore 2019-07-15 18:25:54.000000000 +0000 @@ -1,2 +1,23 @@ /build /dist +/.vscode +/build-dir +/.flatpak-builder +/repo +*.flatpak +*.snap +/fwupd_source.tar.bz2 +/parts +/prime +/stage +/snap/.snapcraft +/libxmlb +/*.deb +/*.ddeb +/*.changes +/*.buildinfo +/fwupd*.build +/*.dsc +/*.xz +/*.gz +__pycache__ diff -Nru fwupd-1.0.6/.gitmodules fwupd-1.2.10/.gitmodules --- fwupd-1.0.6/.gitmodules 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/.gitmodules 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +[submodule "contrib/flatpak"] + path = contrib/flatpak + url = https://github.com/flathub/org.freedesktop.fwupd diff -Nru fwupd-1.0.6/.lgtm.yml fwupd-1.2.10/.lgtm.yml --- fwupd-1.0.6/.lgtm.yml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/.lgtm.yml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,23 @@ +extraction: + python: + python_setup: + version: "3" + cpp: + prepare: + packages: + - bsdtar + - python3-gi + - libcogl-pango-dev + - python3-pil + - python3-cairo + after_prepare: + - "wget -O libxmlb.zip https://github.com/hughsie/libxmlb/archive/0.1.7.zip" + - "mkdir -p subprojects/libxmlb" + - "bsdtar --strip-components=1 -xvf libxmlb.zip -C subprojects/libxmlb" + - "wget -O flashrom.zip https://github.com/hughsie/flashrom/archive/wip/hughsie/fwupd.zip" + - "mkdir -p subprojects/flashrom" + - "bsdtar --strip-components=1 -xvf flashrom.zip -C subprojects/flashrom" + index: + build_command: + - "meson setup build" + - "ninja -C build" diff -Nru fwupd-1.0.6/libfwupd/fwupd-client.c fwupd-1.2.10/libfwupd/fwupd-client.c --- fwupd-1.0.6/libfwupd/fwupd-client.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-client.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -52,6 +37,7 @@ typedef struct { FwupdStatus status; + gboolean tainted; guint percentage; gchar *daemon_version; GDBusConnection *conn; @@ -72,6 +58,7 @@ PROP_STATUS, PROP_PERCENTAGE, PROP_DAEMON_VERSION, + PROP_TAINTED, PROP_LAST }; @@ -110,7 +97,10 @@ return helper; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) +#pragma clang diagnostic pop static void fwupd_client_set_daemon_version (FwupdClient *client, const gchar *daemon_version) @@ -143,6 +133,14 @@ g_object_notify (G_OBJECT (client), "status"); } } + if (g_variant_dict_contains (dict, "Tainted")) { + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy, "Tainted"); + if (val != NULL) { + priv->tainted = g_variant_get_boolean (val); + g_object_notify (G_OBJECT (client), "tainted"); + } + } if (g_variant_dict_contains (dict, "Percentage")) { g_autoptr(GVariant) val = NULL; val = g_dbus_proxy_get_cached_property (proxy, "Percentage"); @@ -215,6 +213,7 @@ { FwupdClientPrivate *priv = GET_PRIVATE (client); g_autoptr(GVariant) val = NULL; + g_autoptr(GVariant) val2 = NULL; g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); @@ -247,72 +246,12 @@ val = g_dbus_proxy_get_cached_property (priv->proxy, "DaemonVersion"); if (val != NULL) fwupd_client_set_daemon_version (client, g_variant_get_string (val, NULL)); + val2 = g_dbus_proxy_get_cached_property (priv->proxy, "Tainted"); + if (val2 != NULL) + priv->tainted = g_variant_get_boolean (val2); return TRUE; } -static GPtrArray * -fwupd_client_parse_releases_from_variant (GVariant *val) -{ - GPtrArray *array = NULL; - gsize sz; - g_autoptr(GVariant) untuple = NULL; - - array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - untuple = g_variant_get_child_value (val, 0); - sz = g_variant_n_children (untuple); - for (guint i = 0; i < sz; i++) { - FwupdRelease *rel; - g_autoptr(GVariant) data = NULL; - data = g_variant_get_child_value (untuple, i); - rel = fwupd_release_from_variant (data); - if (rel == NULL) - continue; - g_ptr_array_add (array, rel); - } - return array; -} - -static GPtrArray * -fwupd_client_parse_devices_from_variant (GVariant *val) -{ - GPtrArray *array = NULL; - gsize sz; - g_autoptr(GVariant) untuple = NULL; - - array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - untuple = g_variant_get_child_value (val, 0); - sz = g_variant_n_children (untuple); - for (guint i = 0; i < sz; i++) { - FwupdDevice *dev; - g_autoptr(GVariant) data = NULL; - data = g_variant_get_child_value (untuple, i); - dev = fwupd_device_from_variant (data); - if (dev == NULL) - continue; - g_ptr_array_add (array, dev); - } - return array; -} - -static GPtrArray * -fwupd_client_parse_remotes_from_data (GVariant *devices) -{ - GPtrArray *remotes = NULL; - gsize sz; - g_autoptr(GVariant) untuple = NULL; - - remotes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - untuple = g_variant_get_child_value (devices, 0); - sz = g_variant_n_children (untuple); - for (guint i = 0; i < sz; i++) { - g_autoptr(GVariant) data = g_variant_get_child_value (untuple, i); - FwupdRemote *remote = fwupd_remote_from_variant (data); - g_ptr_array_add (remotes, remote); - } - - return remotes; -} - static void fwupd_client_fixup_dbus_error (GError *error) { @@ -385,7 +324,7 @@ fwupd_client_fixup_dbus_error (*error); return NULL; } - return fwupd_client_parse_devices_from_variant (val); + return fwupd_device_array_from_variant (val); } /** @@ -427,7 +366,7 @@ fwupd_client_fixup_dbus_error (*error); return NULL; } - return fwupd_client_parse_devices_from_variant (val); + return fwupd_device_array_from_variant (val); } /** @@ -516,7 +455,7 @@ fwupd_client_fixup_dbus_error (*error); return NULL; } - return fwupd_client_parse_releases_from_variant (val); + return fwupd_release_array_from_variant (val); } /** @@ -561,7 +500,7 @@ fwupd_client_fixup_dbus_error (*error); return NULL; } - return fwupd_client_parse_releases_from_variant (val); + return fwupd_release_array_from_variant (val); } /** @@ -606,7 +545,7 @@ fwupd_client_fixup_dbus_error (*error); return NULL; } - return fwupd_client_parse_releases_from_variant (val); + return fwupd_release_array_from_variant (val); } static void @@ -623,6 +562,104 @@ } /** + * fwupd_client_modify_config + * @client: A #FwupdClient + * @key: key, e.g. `BlacklistPlugins` + * @value: value, e.g. `*` + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a daemon config option. + * The daemon will only respond to this request with proper permissions + * + * Returns: %TRUE for success + * + * Since: 1.2.8 + **/ +gboolean +fwupd_client_modify_config (FwupdClient *client, const gchar *key, const gchar *value, + GCancellable *cancellable, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + /* call into daemon */ + helper = fwupd_client_helper_new (); + g_dbus_proxy_call (priv->proxy, + "ModifyConfig", + g_variant_new ("(ss)", key, value), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + fwupd_client_proxy_call_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, helper->error); + helper->error = NULL; + return FALSE; + } + return TRUE; +} + +/** + * fwupd_client_activate: + * @client: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @device_id: a device + * @error: the #GError, or %NULL + * + * Activates up a device, which normally means the device switches to a new + * firmware version. This should only be called when data loss cannot occur. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fwupd_client_activate (FwupdClient *client, GCancellable *cancellable, + const gchar *device_id, GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(FwupdClientHelper) helper = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + /* call into daemon */ + helper = fwupd_client_helper_new (); + g_dbus_proxy_call (priv->proxy, + "Activate", + g_variant_new ("(s)", device_id), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + fwupd_client_proxy_call_cb, + helper); + g_main_loop_run (helper->loop); + if (!helper->ret) { + g_propagate_error (error, helper->error); + helper->error = NULL; + return FALSE; + } + return TRUE; +} + +/** * fwupd_client_verify: * @client: A #FwupdClient * @device_id: the device ID @@ -924,7 +961,7 @@ return FALSE; /* set options */ - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "reason", g_variant_new_string ("user-action")); g_variant_builder_add (&builder, "{sv}", @@ -945,6 +982,10 @@ g_variant_builder_add (&builder, "{sv}", "force", g_variant_new_boolean (TRUE)); } + if (install_flags & FWUPD_INSTALL_FLAG_NO_HISTORY) { + g_variant_builder_add (&builder, "{sv}", + "no-history", g_variant_new_boolean (TRUE)); + } /* open file */ fd = open (filename, O_RDONLY); @@ -1070,7 +1111,7 @@ } /* return results */ - return fwupd_client_parse_devices_from_variant (helper->val); + return fwupd_device_array_from_variant (helper->val); } /** @@ -1128,6 +1169,24 @@ } /** + * fwupd_client_get_tainted: + * @client: A #FwupdClient + * + * Gets if the daemon has been tainted by 3rd party code. + * + * Returns: %TRUE if the daemon is unsupported + * + * Since: 1.2.4 + **/ +gboolean +fwupd_client_get_tainted (FwupdClient *client) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + return priv->tainted; +} + +/** * fwupd_client_update_metadata: * @client: A #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` @@ -1269,7 +1328,161 @@ fwupd_client_fixup_dbus_error (*error); return NULL; } - return fwupd_client_parse_remotes_from_data (val); + return fwupd_remote_array_from_variant (val); +} + +/** + * fwupd_client_get_approved_firmware: + * @client: A #FwupdClient + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Gets the list of approved firmware. + * + * Returns: (transfer full): list of remotes, or %NULL + * + * Since: 1.2.6 + **/ +gchar ** +fwupd_client_get_approved_firmware (FwupdClient *client, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + gchar **retval = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return NULL; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "GetApprovedFirmware", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return NULL; + } + g_variant_get (val, "(^as)", &retval); + return retval; +} + +/** + * fwupd_client_set_approved_firmware: + * @client: A #FwupdClient + * @checksums: Array of checksums + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Sets the list of approved firmware. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fwupd_client_set_approved_firmware (FwupdClient *client, + gchar **checksums, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "SetApprovedFirmware", + g_variant_new ("(^as)", checksums), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return FALSE; + } + return TRUE; +} + +/** + * fwupd_client_self_sign: + * @client: A #FwupdClient + * @value: A string to sign, typically a JSON blob + * @flags: #FwupdSelfSignFlags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Signs the data using the client self-signed certificate. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gchar * +fwupd_client_self_sign (FwupdClient *client, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + GVariantBuilder builder; + g_autoptr(GVariant) val = NULL; + gchar *retval = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return NULL; + + /* set options */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (flags & FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP) { + g_variant_builder_add (&builder, "{sv}", + "add-timestamp", g_variant_new_boolean (TRUE)); + } + if (flags & FWUPD_SELF_SIGN_FLAG_ADD_CERT) { + g_variant_builder_add (&builder, "{sv}", + "add-cert", g_variant_new_boolean (TRUE)); + } + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "SelfSign", + g_variant_new ("(sa{sv})", value, &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return NULL; + } + g_variant_get (val, "(s)", &retval); + return retval; } /** @@ -1450,6 +1663,9 @@ case PROP_STATUS: g_value_set_uint (value, priv->status); break; + case PROP_TAINTED: + g_value_set_boolean (value, priv->tainted); + break; case PROP_PERCENTAGE: g_value_set_uint (value, priv->percentage); break; @@ -1584,10 +1800,21 @@ */ pspec = g_param_spec_uint ("status", NULL, NULL, 0, FWUPD_STATUS_LAST, FWUPD_STATUS_UNKNOWN, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); /** + * FwupdClient:tainted: + * + * If the daemon is tainted by 3rd party code. + * + * Since: 1.2.4 + */ + pspec = g_param_spec_boolean ("tainted", NULL, NULL, FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_TAINTED, pspec); + + /** * FwupdClient:percentage: * * The last-reported percentage of the daemon. @@ -1596,7 +1823,7 @@ */ pspec = g_param_spec_uint ("percentage", NULL, NULL, 0, 100, 0, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_PERCENTAGE, pspec); /** @@ -1607,7 +1834,7 @@ * Since: 0.9.6 */ pspec = g_param_spec_string ("daemon-version", NULL, NULL, - NULL, G_PARAM_READABLE); + NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_DAEMON_VERSION, pspec); } diff -Nru fwupd-1.0.6/libfwupd/fwupd-client.h fwupd-1.2.10/libfwupd/fwupd-client.h --- fwupd-1.0.6/libfwupd/fwupd-client.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-client.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_CLIENT_H -#define __FWUPD_CLIENT_H +#pragma once #include #include @@ -94,6 +78,15 @@ const gchar *device_id, GCancellable *cancellable, GError **error); +gboolean fwupd_client_modify_config (FwupdClient *client, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_activate (FwupdClient *client, + GCancellable *cancellable, + const gchar *device_id, + GError **error); gboolean fwupd_client_clear_results (FwupdClient *client, const gchar *device_id, GCancellable *cancellable, @@ -131,6 +124,7 @@ GCancellable *cancellable, GError **error); FwupdStatus fwupd_client_get_status (FwupdClient *client); +gboolean fwupd_client_get_tainted (FwupdClient *client); guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); @@ -142,7 +136,17 @@ GCancellable *cancellable, GError **error); -G_END_DECLS - -#endif /* __FWUPD_CLIENT_H */ +gchar **fwupd_client_get_approved_firmware (FwupdClient *client, + GCancellable *cancellable, + GError **error); +gboolean fwupd_client_set_approved_firmware (FwupdClient *client, + gchar **checksums, + GCancellable *cancellable, + GError **error); +gchar *fwupd_client_self_sign (FwupdClient *client, + const gchar *value, + FwupdSelfSignFlags flags, + GCancellable *cancellable, + GError **error); +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-common.c fwupd-1.2.10/libfwupd/fwupd-common.c --- fwupd-1.0.6/libfwupd/fwupd-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -31,6 +16,10 @@ #include #include +#if !GLIB_CHECK_VERSION(2,54,0) +#include +#endif + /** * fwupd_checksum_guess_kind: * @checksum: A checksum @@ -60,7 +49,7 @@ } static const gchar * -_g_checksum_type_to_string (GChecksumType checksum_type) +fwupd_checksum_type_to_string_display (GChecksumType checksum_type) { if (checksum_type == G_CHECKSUM_MD5) return "MD5"; @@ -87,7 +76,9 @@ fwupd_checksum_format_for_display (const gchar *checksum) { GChecksumType kind = fwupd_checksum_guess_kind (checksum); - return g_strdup_printf ("%s(%s)", _g_checksum_type_to_string (kind), checksum); + return g_strdup_printf ("%s(%s)", + fwupd_checksum_type_to_string_display (kind), + checksum); } /** @@ -141,13 +132,17 @@ } /** - * fwupd_build_distro_hash: + * fwupd_get_os_release: * @error: A #GError or %NULL * * Loads information from the system os-release file. + * + * Returns: (transfer container) (element-type utf8 utf8): keys from os-release + * + * Since: 1.0.7 **/ -static GHashTable * -fwupd_build_distro_hash (GError **error) +GHashTable * +fwupd_get_os_release (GError **error) { GHashTable *hash; const gchar *filename = NULL; @@ -208,7 +203,7 @@ g_autoptr(GPtrArray) ids_os = g_ptr_array_new (); /* get all keys */ - hash = fwupd_build_distro_hash (NULL); + hash = fwupd_get_os_release (NULL); if (hash == NULL) return NULL; @@ -227,12 +222,13 @@ static gchar * fwupd_build_user_agent_system (void) { - struct utsname name_tmp = { 0 }; + struct utsname name_tmp; g_autofree gchar *locale = NULL; g_autofree gchar *os_release = NULL; g_autoptr(GPtrArray) ids = g_ptr_array_new_with_free_func (g_free); /* system, architecture and kernel, e.g. "Linux i686 4.14.5" */ + memset (&name_tmp, 0, sizeof(struct utsname)); if (uname (&name_tmp) >= 0) { g_ptr_array_add (ids, g_strdup_printf ("%s %s %s", name_tmp.sysname, @@ -366,6 +362,24 @@ checksums = fwupd_release_get_checksums (rel); json_builder_add_string_value (builder, fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1)); + /* identify the firmware written */ + checksums = fwupd_device_get_checksums (dev); + if (checksums->len > 0) { + json_builder_set_member_name (builder, "ChecksumDevice"); + json_builder_begin_array (builder); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + json_builder_add_string_value (builder, checksum); + } + json_builder_end_array (builder); + } + + /* include the protocol used */ + if (fwupd_release_get_protocol (rel) != NULL) { + json_builder_set_member_name (builder, "Protocol"); + json_builder_add_string_value (builder, fwupd_release_get_protocol (rel)); + } + /* set the error state of the report */ json_builder_set_member_name (builder, "UpdateState"); json_builder_add_int_value (builder, fwupd_device_get_update_state (dev)); @@ -373,6 +387,10 @@ json_builder_set_member_name (builder, "UpdateError"); json_builder_add_string_value (builder, fwupd_device_get_update_error (dev)); } + if (fwupd_release_get_update_message (rel) != NULL) { + json_builder_set_member_name (builder, "UpdateMessage"); + json_builder_add_string_value (builder, fwupd_release_get_update_message (rel)); + } /* map back to the dev type on the LVFS */ json_builder_set_member_name (builder, "Guid"); @@ -419,7 +437,7 @@ }; /* get all required os-release keys */ - hash = fwupd_build_distro_hash (error); + hash = fwupd_get_os_release (error); if (hash == NULL) return FALSE; for (guint i = 0; distro_kv[i].key != NULL; i++) { @@ -457,7 +475,7 @@ /* get a hash that represents the machine */ machine_id = fwupd_build_machine_id ("fwupd", error); if (machine_id == NULL) - return FALSE; + return NULL; /* create header */ builder = json_builder_new (); @@ -471,7 +489,7 @@ json_builder_set_member_name (builder, "Metadata"); json_builder_begin_object (builder); if (!fwupd_build_history_report_json_metadata (builder, error)) - return FALSE; + return NULL; json_builder_end_object (builder); /* add each device */ @@ -501,3 +519,305 @@ } return data; } + +#define FWUPD_GUID_NAMESPACE_DEFAULT "6ba7b810-9dad-11d1-80b4-00c04fd430c8" +#define FWUPD_GUID_NAMESPACE_MICROSOFT "70ffd812-4c7f-4c7d-0000-000000000000" + +typedef struct __attribute__((packed)) { + guint32 a; + guint16 b; + guint16 c; + guint16 d; + guint8 e[6]; +} fwupd_guid_native_t; + +/** + * fwupd_guid_to_string: + * @guid: a #fwupd_guid_t to read + * @flags: some %FwupdGuidFlags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN + * + * Returns a text GUID of mixed or BE endian for a packed buffer. + * + * Returns: A new GUID + * + * Since: 1.2.5 + **/ +gchar * +fwupd_guid_to_string (const fwupd_guid_t *guid, FwupdGuidFlags flags) +{ + fwupd_guid_native_t gnat; + + g_return_val_if_fail (guid != NULL, NULL); + + /* copy to avoid issues with aligning */ + memcpy (&gnat, guid, sizeof(gnat)); + + /* mixed is bizaar, but specified as the DCE encoding */ + if (flags & FWUPD_GUID_FLAG_MIXED_ENDIAN) { + return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + GUINT32_FROM_LE(gnat.a), + GUINT16_FROM_LE(gnat.b), + GUINT16_FROM_LE(gnat.c), + GUINT16_FROM_BE(gnat.d), + gnat.e[0], gnat.e[1], + gnat.e[2], gnat.e[3], + gnat.e[4], gnat.e[5]); + } + return g_strdup_printf ("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + GUINT32_FROM_BE(gnat.a), + GUINT16_FROM_BE(gnat.b), + GUINT16_FROM_BE(gnat.c), + GUINT16_FROM_BE(gnat.d), + gnat.e[0], gnat.e[1], + gnat.e[2], gnat.e[3], + gnat.e[4], gnat.e[5]); +} + +#if !GLIB_CHECK_VERSION(2,54,0) +static gboolean +str_has_sign (const gchar *str) +{ + return str[0] == '-' || str[0] == '+'; +} + +static gboolean +str_has_hex_prefix (const gchar *str) +{ + return str[0] == '0' && g_ascii_tolower (str[1]) == 'x'; +} + +static gboolean +g_ascii_string_to_unsigned (const gchar *str, + guint base, + guint64 min, + guint64 max, + guint64 *out_num, + GError **error) +{ + const gchar *end_ptr = NULL; + gint saved_errno = 0; + guint64 number; + + g_return_val_if_fail (str != NULL, FALSE); + g_return_val_if_fail (base >= 2 && base <= 36, FALSE); + g_return_val_if_fail (min <= max, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (str[0] == '\0') { + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "Empty string is not a number"); + return FALSE; + } + + errno = 0; + number = g_ascii_strtoull (str, (gchar **)&end_ptr, base); + saved_errno = errno; + + if (g_ascii_isspace (str[0]) || str_has_sign (str) || + (base == 16 && str_has_hex_prefix (str)) || + (saved_errno != 0 && saved_errno != ERANGE) || + end_ptr == NULL || + *end_ptr != '\0') { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "“%s” is not an unsigned number", str); + return FALSE; + } + if (saved_errno == ERANGE || number < min || number > max) { + g_autofree gchar *min_str = g_strdup_printf ("%" G_GUINT64_FORMAT, min); + g_autofree gchar *max_str = g_strdup_printf ("%" G_GUINT64_FORMAT, max); + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "Number “%s” is out of bounds [%s, %s]", + str, min_str, max_str); + return FALSE; + } + if (out_num != NULL) + *out_num = number; + return TRUE; +} +#endif /* GLIB_CHECK_VERSION(2,54,0) */ + +/** + * fwupd_guid_from_string: + * @guidstr: (nullable): a GUID, e.g. `00112233-4455-6677-8899-aabbccddeeff` + * @guid: a #fwupd_guid_t, or NULL to just check the GUID + * @flags: some %FwupdGuidFlags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN + * @error: A #GError or %NULL + * + * Converts a string GUID into its binary encoding. All string GUIDs are + * formatted as big endian but on-disk can be encoded in different ways. + * + * Returns: %TRUE for success + * + * Since: 1.2.5 + **/ +gboolean +fwupd_guid_from_string (const gchar *guidstr, + fwupd_guid_t *guid, + FwupdGuidFlags flags, + GError **error) +{ + fwupd_guid_native_t gu = { 0x0 }; + gboolean mixed_endian = flags & FWUPD_GUID_FLAG_MIXED_ENDIAN; + guint64 tmp; + g_auto(GStrv) split = NULL; + + g_return_val_if_fail (guidstr != NULL, FALSE); + + /* split into sections */ + if (strlen (guidstr) != 36) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "is not valid format"); + return FALSE; + } + split = g_strsplit (guidstr, "-", 5); + if (g_strv_length (split) != 5) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "is not valid format, no dashes"); + return FALSE; + } + if (strlen (split[0]) != 8 && strlen (split[1]) != 4 && + strlen (split[2]) != 4 && strlen (split[3]) != 4 && + strlen (split[4]) != 12) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "is not valid format, not GUID"); + return FALSE; + } + + /* parse */ + if (!g_ascii_string_to_unsigned (split[0], 16, 0, 0xffffffff, &tmp, error)) + return FALSE; + gu.a = mixed_endian ? GUINT32_TO_LE(tmp) : GUINT32_TO_BE(tmp); + if (!g_ascii_string_to_unsigned (split[1], 16, 0, 0xffff, &tmp, error)) + return FALSE; + gu.b = mixed_endian ? GUINT16_TO_LE(tmp) : GUINT16_TO_BE(tmp); + if (!g_ascii_string_to_unsigned (split[2], 16, 0, 0xffff, &tmp, error)) + return FALSE; + gu.c = mixed_endian ? GUINT16_TO_LE(tmp) : GUINT16_TO_BE(tmp); + if (!g_ascii_string_to_unsigned (split[3], 16, 0, 0xffff, &tmp, error)) + return FALSE; + gu.d = GUINT16_TO_BE(tmp); + for (guint i = 0; i < 6; i++) { + gchar buffer[3] = { 0x0 }; + memcpy (buffer, split[4] + (i * 2), 2); + if (!g_ascii_string_to_unsigned (buffer, 16, 0, 0xff, &tmp, error)) + return FALSE; + gu.e[i] = tmp; + } + if (guid != NULL) + memcpy (guid, &gu, sizeof(gu)); + + /* success */ + return TRUE; +} + +/** + * fwupd_guid_hash_data: + * @data: data to hash + * @datasz: length of @data + * @flags: some %FwupdGuidFlags, e.g. %FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT + * + * Returns a GUID for some data. This uses a hash and so even small + * differences in the @data will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash. + * + * Returns: A new GUID, or %NULL for internal error + * + * Since: 1.2.5 + **/ +gchar * +fwupd_guid_hash_data (const guint8 *data, gsize datasz, FwupdGuidFlags flags) +{ + const gchar *namespace_id = FWUPD_GUID_NAMESPACE_DEFAULT; + gsize digestlen = 20; + guint8 hash[20]; + fwupd_guid_t uu_namespace; + fwupd_guid_t uu_new; + g_autoptr(GChecksum) csum = NULL; + + g_return_val_if_fail (namespace_id != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (datasz != 0, NULL); + + /* old MS GUID */ + if (flags & FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT) + namespace_id = FWUPD_GUID_NAMESPACE_MICROSOFT; + + /* convert the namespace to binary: hardcoded BE, not @flags */ + if (!fwupd_guid_from_string (namespace_id, &uu_namespace, FWUPD_GUID_FLAG_NONE, NULL)) + return NULL; + + /* hash the namespace and then the string */ + csum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum, (guchar *) &uu_namespace, sizeof(uu_namespace)); + g_checksum_update (csum, (guchar *) data, (gssize) datasz); + g_checksum_get_digest (csum, hash, &digestlen); + + /* copy most parts of the hash 1:1 */ + memcpy (uu_new, hash, sizeof(uu_new)); + + /* set specific bits according to Section 4.1.3 */ + uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4)); + uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80); + return fwupd_guid_to_string ((const fwupd_guid_t *) &uu_new, flags); +} + +/** + * fwupd_guid_is_valid: + * @guid: string to check, e.g. `00112233-4455-6677-8899-aabbccddeeff` + * + * Checks the string is a valid GUID. + * + * Returns: %TRUE if @guid was a valid GUID, %FALSE otherwise + * + * Since: 1.2.5 + **/ +gboolean +fwupd_guid_is_valid (const gchar *guid) +{ + if (guid == NULL) + return FALSE; + if (!fwupd_guid_from_string (guid, NULL, FWUPD_GUID_FLAG_NONE, NULL)) + return FALSE; + if (g_strcmp0 (guid, "00000000-0000-0000-0000-000000000000") == 0) + return FALSE; + return TRUE; +} + +/** + * fwupd_guid_hash_string: + * @str: A source string to use as a key + * + * Returns a GUID for a given string. This uses a hash and so even small + * differences in the @str will produce radically different return values. + * + * The default implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash with a DNS namespace. + * The same result can be obtained with this simple python program: + * + * #!/usr/bin/python + * import uuid + * print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') + * + * Returns: A new GUID, or %NULL if the string was invalid + * + * Since: 1.2.5 + **/ +gchar * +fwupd_guid_hash_string (const gchar *str) +{ + if (str == NULL || str[0] == '\0') + return NULL; + return fwupd_guid_hash_data ((const guint8 *) str, strlen (str), + FWUPD_GUID_FLAG_NONE); +} diff -Nru fwupd-1.0.6/libfwupd/fwupd-common.h fwupd-1.2.10/libfwupd/fwupd-common.h --- fwupd-1.0.6/libfwupd/fwupd-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,35 +1,42 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_COMMON_H -#define __FWUPD_COMMON_H +#pragma once #include +G_BEGIN_DECLS + #define FWUPD_DBUS_PATH "/" #define FWUPD_DBUS_SERVICE "org.freedesktop.fwupd" #define FWUPD_DBUS_INTERFACE "org.freedesktop.fwupd" #define FWUPD_DEVICE_ID_ANY "*" +/** + * FwupdGuidFlags: + * @FWUPD_GUID_FLAG_NONE: No trust + * @FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT: Use the Microsoft-compatible namespace + * @FWUPD_GUID_FLAG_MIXED_ENDIAN: Use EFI mixed endian representation + * + * The flags to show how the data should be converted. + **/ +typedef enum { + FWUPD_GUID_FLAG_NONE = 0, /* Since: 1.2.5 */ + FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT = 1 << 0, /* Since: 1.2.5 */ + FWUPD_GUID_FLAG_MIXED_ENDIAN = 1 << 1, /* Since: 1.2.5 */ + /*< private >*/ + FWUPD_GUID_FLAG_LAST +} FwupdGuidFlags; + +/* GObject Introspection does not understand typedefs with sizes */ +#ifndef __GI_SCANNER__ +typedef guint8 fwupd_guid_t[16]; +#endif + const gchar *fwupd_checksum_get_best (GPtrArray *checksums); const gchar *fwupd_checksum_get_by_kind (GPtrArray *checksums, GChecksumType kind); @@ -38,7 +45,28 @@ const gchar *package_version); gchar *fwupd_build_machine_id (const gchar *salt, GError **error); +GHashTable *fwupd_get_os_release (GError **error); gchar *fwupd_build_history_report_json (GPtrArray *devices, GError **error); +#ifndef __GI_SCANNER__ +gchar *fwupd_guid_to_string (const fwupd_guid_t *guid, + FwupdGuidFlags flags); +gboolean fwupd_guid_from_string (const gchar *guidstr, + fwupd_guid_t *guid, + FwupdGuidFlags flags, + GError **error); +#else +gchar *fwupd_guid_to_string (const guint8 guid[16], + FwupdGuidFlags flags); +gboolean fwupd_guid_from_string (const gchar *guidstr, + guint8 guid[16], + FwupdGuidFlags flags, + GError **error); +#endif +gboolean fwupd_guid_is_valid (const gchar *guid); +gchar *fwupd_guid_hash_string (const gchar *str); +gchar *fwupd_guid_hash_data (const guint8 *data, + gsize datasz, + FwupdGuidFlags flags); -#endif /* __FWUPD_COMMON_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-common-private.h fwupd-1.2.10/libfwupd/fwupd-common-private.h --- fwupd-1.0.6/libfwupd/fwupd-common-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-common-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,31 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_COMMON_PRIVATE_H -#define __FWUPD_COMMON_PRIVATE_H +#pragma once #include #include "fwupd-common.h" +G_BEGIN_DECLS + gchar *fwupd_checksum_format_for_display (const gchar *checksum); -#endif /* __FWUPD_COMMON_PRIVATE_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-deprecated.h fwupd-1.2.10/libfwupd/fwupd-deprecated.h --- fwupd-1.0.6/libfwupd/fwupd-deprecated.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-deprecated.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,13 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_DEPRECATED_H -#define __FWUPD_DEPRECATED_H +#pragma once + +G_BEGIN_DECLS /* indeed, nothing */ -#endif /* __FWUPD_DEPRECATED_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-device.c fwupd-1.2.10/libfwupd/fwupd-device.c --- fwupd-1.0.6/libfwupd/fwupd-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -44,13 +29,15 @@ typedef struct { gchar *id; + gchar *parent_id; guint64 created; guint64 modified; guint64 flags; - gchar *appstream_id; GPtrArray *guids; + GPtrArray *instance_ids; GPtrArray *icons; gchar *name; + gchar *serial; gchar *summary; gchar *description; gchar *vendor; @@ -60,13 +47,23 @@ gchar *version; gchar *version_lowest; gchar *version_bootloader; + FwupdVersionFormat version_format; GPtrArray *checksums; guint32 flashes_left; + guint32 install_duration; FwupdUpdateState update_state; gchar *update_error; + gchar *update_message; GPtrArray *releases; + FwupdDevice *parent; } FwupdDevicePrivate; +enum { + PROP_0, + PROP_VERSION_FORMAT, + PROP_LAST +}; + G_DEFINE_TYPE_WITH_PRIVATE (FwupdDevice, fwupd_device, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_device_get_instance_private (o)) @@ -148,6 +145,42 @@ } /** + * fwupd_device_get_serial: + * @device: A #FwupdDevice + * + * Gets the serial number for the device. + * + * Returns: a string value, or %NULL if never set. + * + * Since: 1.1.2 + **/ +const gchar * +fwupd_device_get_serial (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->serial; +} + +/** + * fwupd_device_set_serial: + * @device: A #FwupdDevice + * @serial: the device serial number + * + * Sets the serial number for the device. + * + * Since: 1.1.2 + **/ +void +fwupd_device_set_serial (FwupdDevice *device, const gchar *serial) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->serial); + priv->serial = g_strdup (serial); +} + +/** * fwupd_device_get_id: * @device: A #FwupdDevice * @@ -184,6 +217,77 @@ } /** + * fwupd_device_get_parent_id: + * @device: A #FwupdDevice + * + * Gets the ID. + * + * Returns: the parent ID, or %NULL if unset + * + * Since: 1.0.8 + **/ +const gchar * +fwupd_device_get_parent_id (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->parent_id; +} + +/** + * fwupd_device_set_parent_id: + * @device: A #FwupdDevice + * @parent_id: the device ID, e.g. `USB:foo` + * + * Sets the parent ID. + * + * Since: 1.0.8 + **/ +void +fwupd_device_set_parent_id (FwupdDevice *device, const gchar *parent_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->parent_id); + priv->parent_id = g_strdup (parent_id); +} + +/** + * fwupd_device_get_parent: + * @device: A #FwupdDevice + * + * Gets the parent. + * + * Returns: (transfer none): the parent device, or %NULL if unset + * + * Since: 1.0.8 + **/ +FwupdDevice * +fwupd_device_get_parent (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->parent; +} + +/** + * fwupd_device_set_parent: + * @device: A #FwupdDevice + * @parent: another #FwupdDevice, or %NULL + * + * Sets the parent. Only used internally. + * + * Since: 1.0.8 + **/ +void +fwupd_device_set_parent (FwupdDevice *device, FwupdDevice *parent) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_set_object (&priv->parent, parent); +} + +/** * fwupd_device_get_guids: * @device: A #FwupdDevice * @@ -267,6 +371,69 @@ } /** + * fwupd_device_get_instance_ids: + * @device: A #FwupdDevice + * + * Gets the InstanceIDs. + * + * Returns: (element-type utf8) (transfer none): the InstanceID + * + * Since: 1.2.5 + **/ +GPtrArray * +fwupd_device_get_instance_ids (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->instance_ids; +} + +/** + * fwupd_device_has_instance_id: + * @device: A #FwupdDevice + * @instance_id: the InstanceID, e.g. `PCI\VEN_10EC&DEV_525A` + * + * Finds out if the device has this specific InstanceID. + * + * Returns: %TRUE if the InstanceID is found + * + * Since: 1.2.5 + **/ +gboolean +fwupd_device_has_instance_id (FwupdDevice *device, const gchar *instance_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FALSE); + + for (guint i = 0; i < priv->instance_ids->len; i++) { + const gchar *instance_id_tmp = g_ptr_array_index (priv->instance_ids, i); + if (g_strcmp0 (instance_id, instance_id_tmp) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fwupd_device_add_instance_id: + * @device: A #FwupdDevice + * @instance_id: the GUID, e.g. `PCI\VEN_10EC&DEV_525A` + * + * Adds the InstanceID if it does not already exist. + * + * Since: 1.2.5 + **/ +void +fwupd_device_add_instance_id (FwupdDevice *device, const gchar *instance_id) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + if (fwupd_device_has_instance_id (device, instance_id)) + return; + g_ptr_array_add (priv->instance_ids, g_strdup (instance_id)); +} + +/** * fwupd_device_get_icons: * @device: A #FwupdDevice * @@ -606,6 +773,41 @@ } /** + * fwupd_device_get_install_duration: + * @device: A #FwupdDevice + * + * Gets the time estimate for firmware installation (in seconds) + * + * Returns: the estimated time to flash this device (or 0 if unset) + * + * Since: 1.1.3 + **/ +guint32 +fwupd_device_get_install_duration (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), 0); + return priv->install_duration; +} + +/** + * fwupd_device_set_install_duration: + * @device: A #FwupdDevice + * @duration: The amount of time + * + * Sets the time estimate for firmware installation (in seconds) + * + * Since: 1.1.3 + **/ +void +fwupd_device_set_install_duration (FwupdDevice *device, guint32 duration) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + priv->install_duration = duration; +} + +/** * fwupd_device_get_plugin: * @device: A #FwupdDevice * @@ -801,17 +1003,98 @@ } /** - * fwupd_device_to_variant: + * fwupd_device_incorporate: + * @self: A #FwupdDevice + * @donor: Another #FwupdDevice + * + * Copy all properties from the donor object if they have not already been set. + * + * Since: 1.1.0 + **/ +void +fwupd_device_incorporate (FwupdDevice *self, FwupdDevice *donor) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (self); + FwupdDevicePrivate *priv_donor = GET_PRIVATE (donor); + + if (priv->flags == 0) + fwupd_device_add_flag (self, priv_donor->flags); + if (priv->created == 0) + fwupd_device_set_created (self, priv_donor->created); + if (priv->modified == 0) + fwupd_device_set_modified (self, priv_donor->modified); + if (priv->flashes_left == 0) + fwupd_device_set_flashes_left (self, priv_donor->flashes_left); + if (priv->install_duration == 0) + fwupd_device_set_install_duration (self, priv_donor->install_duration); + if (priv->update_state == 0) + fwupd_device_set_update_state (self, priv_donor->update_state); + if (priv->description == NULL) + fwupd_device_set_description (self, priv_donor->description); + if (priv->id == NULL) + fwupd_device_set_id (self, priv_donor->id); + if (priv->parent_id == NULL) + fwupd_device_set_parent_id (self, priv_donor->parent_id); + if (priv->name == NULL) + fwupd_device_set_name (self, priv_donor->name); + if (priv->serial == NULL) + fwupd_device_set_serial (self, priv_donor->serial); + if (priv->summary == NULL) + fwupd_device_set_summary (self, priv_donor->summary); + if (priv->vendor == NULL) + fwupd_device_set_vendor (self, priv_donor->vendor); + if (priv->vendor_id == NULL) + fwupd_device_set_vendor_id (self, priv_donor->vendor_id); + if (priv->plugin == NULL) + fwupd_device_set_plugin (self, priv_donor->plugin); + if (priv->update_error == NULL) + fwupd_device_set_update_error (self, priv_donor->update_error); + if (priv->update_message == NULL) + fwupd_device_set_update_message (self, priv_donor->update_message); + if (priv->version == NULL) + fwupd_device_set_version (self, priv_donor->version); + if (priv->version_lowest == NULL) + fwupd_device_set_version_lowest (self, priv_donor->version_lowest); + if (priv->version_bootloader == NULL) + fwupd_device_set_version_bootloader (self, priv_donor->version_bootloader); + if (priv->version_format == FWUPD_VERSION_FORMAT_UNKNOWN) + fwupd_device_set_version_format (self, priv_donor->version_format); + for (guint i = 0; i < priv_donor->guids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->guids, i); + fwupd_device_add_guid (self, tmp); + } + for (guint i = 0; i < priv_donor->instance_ids->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->instance_ids, i); + fwupd_device_add_instance_id (self, tmp); + } + for (guint i = 0; i < priv_donor->icons->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->icons, i); + fwupd_device_add_icon (self, tmp); + } + for (guint i = 0; i < priv_donor->checksums->len; i++) { + const gchar *tmp = g_ptr_array_index (priv_donor->checksums, i); + fwupd_device_add_checksum (self, tmp); + } + for (guint i = 0; i < priv_donor->releases->len; i++) { + FwupdRelease *tmp = g_ptr_array_index (priv_donor->releases, i); + fwupd_device_add_release (self, tmp); + } +} + +/** + * fwupd_device_to_variant_full: * @device: A #FwupdDevice + * @flags: #FwupdDeviceFlags for the call * * Creates a GVariant from the device data. + * Optionally provides additional data based upon flags * * Returns: the GVariant, or %NULL for error * - * Since: 1.0.0 + * Since: 1.1.2 **/ GVariant * -fwupd_device_to_variant (FwupdDevice *device) +fwupd_device_to_variant_full (FwupdDevice *device, FwupdDeviceFlags flags) { FwupdDevicePrivate *priv = GET_PRIVATE (device); GVariantBuilder builder; @@ -819,12 +1102,17 @@ g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); /* create an array with all the metadata in */ - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); if (priv->id != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_DEVICE_ID, g_variant_new_string (priv->id)); } + if (priv->parent_id != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_PARENT_DEVICE_ID, + g_variant_new_string (priv->parent_id)); + } if (priv->guids->len > 0) { const gchar * const *tmp = (const gchar * const *) priv->guids->pdata; g_variant_builder_add (&builder, "{sv}", @@ -915,16 +1203,44 @@ FWUPD_RESULT_KEY_FLASHES_LEFT, g_variant_new_uint32 (priv->flashes_left)); } + if (priv->install_duration > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_INSTALL_DURATION, + g_variant_new_uint32 (priv->install_duration)); + } if (priv->update_error != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_ERROR, g_variant_new_string (priv->update_error)); } + if (priv->update_message != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_UPDATE_MESSAGE, + g_variant_new_string (priv->update_message)); + } if (priv->update_state != FWUPD_UPDATE_STATE_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_STATE, g_variant_new_uint32 (priv->update_state)); } + if (priv->version_format != FWUPD_VERSION_FORMAT_UNKNOWN) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_VERSION_FORMAT, + g_variant_new_uint32 (priv->version_format)); + } + if (flags & FWUPD_DEVICE_FLAG_TRUSTED) { + if (priv->serial != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_SERIAL, + g_variant_new_string (priv->serial)); + } + if (priv->instance_ids->len > 0) { + const gchar * const *tmp = (const gchar * const *) priv->instance_ids->pdata; + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_INSTANCE_IDS, + g_variant_new_strv (tmp, priv->instance_ids->len)); + } + } /* create an array with all the metadata in */ if (priv->releases->len > 0) { @@ -943,6 +1259,22 @@ return g_variant_new ("a{sv}", &builder); } +/** + * fwupd_device_to_variant: + * @device: A #FwupdDevice + * + * Creates a GVariant from the device data omitting sensitive fields + * + * Returns: the GVariant, or %NULL for error + * + * Since: 1.0.0 + **/ +GVariant * +fwupd_device_to_variant (FwupdDevice *device) +{ + return fwupd_device_to_variant_full (device, FWUPD_DEVICE_FLAG_NONE); +} + static void fwupd_device_from_key_value (FwupdDevice *device, const gchar *key, GVariant *value) { @@ -962,6 +1294,10 @@ fwupd_device_set_id (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_PARENT_DEVICE_ID) == 0) { + fwupd_device_set_parent_id (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_FLAGS) == 0) { fwupd_device_set_flags (device, g_variant_get_uint64 (value)); return; @@ -976,13 +1312,19 @@ } if (g_strcmp0 (key, FWUPD_RESULT_KEY_GUID) == 0) { g_autofree const gchar **guids = g_variant_get_strv (value, NULL); - for (guint i = 0; guids[i] != NULL; i++) + for (guint i = 0; guids != NULL && guids[i] != NULL; i++) fwupd_device_add_guid (device, guids[i]); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_INSTANCE_IDS) == 0) { + g_autofree const gchar **instance_ids = g_variant_get_strv (value, NULL); + for (guint i = 0; instance_ids != NULL && instance_ids[i] != NULL; i++) + fwupd_device_add_instance_id (device, instance_ids[i]); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_ICON) == 0) { g_autofree const gchar **icons = g_variant_get_strv (value, NULL); - for (guint i = 0; icons[i] != NULL; i++) + for (guint i = 0; icons != NULL && icons[i] != NULL; i++) fwupd_device_add_icon (device, icons[i]); return; } @@ -998,6 +1340,10 @@ fwupd_device_set_vendor_id (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_SERIAL) == 0) { + fwupd_device_set_serial (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_SUMMARY) == 0) { fwupd_device_set_summary (device, g_variant_get_string (value, NULL)); return; @@ -1008,9 +1354,11 @@ } if (g_strcmp0 (key, FWUPD_RESULT_KEY_CHECKSUM) == 0) { const gchar *checksums = g_variant_get_string (value, NULL); - g_auto(GStrv) split = g_strsplit (checksums, ",", -1); - for (guint i = 0; split[i] != NULL; i++) - fwupd_device_add_checksum (device, split[i]); + if (checksums != NULL) { + g_auto(GStrv) split = g_strsplit (checksums, ",", -1); + for (guint i = 0; split[i] != NULL; i++) + fwupd_device_add_checksum (device, split[i]); + } return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_PLUGIN) == 0) { @@ -1033,14 +1381,26 @@ fwupd_device_set_flashes_left (device, g_variant_get_uint32 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) { + fwupd_device_set_install_duration (device, g_variant_get_uint32 (value)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_ERROR) == 0) { fwupd_device_set_update_error (device, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { + fwupd_device_set_update_message (device, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) { fwupd_device_set_update_state (device, g_variant_get_uint32 (value)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_VERSION_FORMAT) == 0) { + fwupd_device_set_version_format (device, g_variant_get_uint32 (value)); + return; + } } static void @@ -1136,6 +1496,77 @@ } /** + * fwupd_device_get_version_format: + * @device: A #FwupdDevice + * + * Gets the update state. + * + * Returns: the update state, or %FWUPD_VERSION_FORMAT_UNKNOWN if unset + * + * Since: 1.2.9 + **/ +FwupdVersionFormat +fwupd_device_get_version_format (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), FWUPD_VERSION_FORMAT_UNKNOWN); + return priv->version_format; +} + +/** + * fwupd_device_set_version_format: + * @device: A #FwupdDevice + * @version_format: the state, e.g. %FWUPD_VERSION_FORMAT_PENDING + * + * Sets the update state. + * + * Since: 1.2.9 + **/ +void +fwupd_device_set_version_format (FwupdDevice *device, FwupdVersionFormat version_format) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + priv->version_format = version_format; +} + +/** + * fwupd_device_get_update_message: + * @device: A #FwupdDevice + * + * Gets the update message. + * + * Returns: the update message, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_device_get_update_message (FwupdDevice *device) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); + return priv->update_message; +} + +/** + * fwupd_device_set_update_message: + * @device: A #FwupdDevice + * @update_message: the update message string + * + * Sets the update message. + * + * Since: 1.2.4 + **/ +void +fwupd_device_set_update_message (FwupdDevice *device, const gchar *update_message) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_free (priv->update_message); + priv->update_message = g_strdup (update_message); +} + +/** * fwupd_device_get_update_error: * @device: A #FwupdDevice * @@ -1234,6 +1665,115 @@ fwupd_pad_kv_str (str, key, fwupd_update_state_to_string (value)); } +static void +fwupd_device_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +static void +fwupd_device_json_add_int (JsonBuilder *builder, const gchar *key, guint64 num) +{ + if (num == 0) + return; + json_builder_set_member_name (builder, key); + json_builder_add_int_value (builder, num); +} + +/** + * fwupd_device_to_json: + * @device: A #FwupdDevice + * @builder: A #JsonBuilder + * + * Adds a fwupd device to a JSON builder + * + * Since: 1.2.6 + **/ +void +fwupd_device_to_json (FwupdDevice *device, JsonBuilder *builder) +{ + FwupdDevicePrivate *priv = GET_PRIVATE (device); + + g_return_if_fail (FWUPD_IS_DEVICE (device)); + g_return_if_fail (builder != NULL); + + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_NAME, priv->name); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_DEVICE_ID, priv->id); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PARENT_DEVICE_ID, + priv->parent_id); + if (priv->guids->len > 0) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_GUID); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->guids->len; i++) { + const gchar *guid = g_ptr_array_index (priv->guids, i); + json_builder_add_string_value (builder, guid); + } + json_builder_end_array (builder); + } + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SERIAL, priv->serial); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); + if (priv->flags != FWUPD_DEVICE_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_device_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } + if (priv->checksums->len > 0) { + json_builder_set_member_name (builder, "Checksums"); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (priv->checksums, i); + json_builder_add_string_value (builder, checksum); + } + json_builder_end_array (builder); + } + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VENDOR, priv->vendor); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VENDOR_ID, priv->vendor_id); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION, priv->version); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION_LOWEST, priv->version_lowest); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION_BOOTLOADER, priv->version_bootloader); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_VERSION_FORMAT, + fwupd_version_format_to_string (priv->version_format)); + fwupd_device_json_add_int (builder, FWUPD_RESULT_KEY_FLASHES_LEFT, priv->flashes_left); + if (priv->icons->len > 0) { + json_builder_set_member_name (builder, "Icons"); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->icons->len; i++) { + const gchar *icon = g_ptr_array_index (priv->icons, i); + json_builder_add_string_value (builder, icon); + } + json_builder_end_array (builder); + } + fwupd_device_json_add_int (builder, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); + fwupd_device_json_add_int (builder, FWUPD_RESULT_KEY_CREATED, priv->created); + fwupd_device_json_add_int (builder, FWUPD_RESULT_KEY_MODIFIED, priv->modified); + fwupd_device_json_add_int (builder, FWUPD_RESULT_KEY_UPDATE_STATE, priv->update_state); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error); + fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); + if (priv->releases->len > 0) { + json_builder_set_member_name (builder, "Releases"); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->releases->len; i++) { + FwupdRelease *release = g_ptr_array_index (priv->releases, i); + json_builder_begin_object (builder); + fwupd_release_to_json (release, builder); + json_builder_end_object (builder); + } + json_builder_end_array (builder); + } +} + /** * fwupd_device_to_string: * @device: A #FwupdDevice @@ -1249,6 +1789,7 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); GString *str; + g_autoptr(GHashTable) ids = NULL; g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL); @@ -1258,10 +1799,26 @@ else str = g_string_append (str, "Unknown Device\n"); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_ID, priv->id); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PARENT_DEVICE_ID, priv->parent_id); + ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + for (guint i = 0; i < priv->instance_ids->len; i++) { + const gchar *instance_id = g_ptr_array_index (priv->instance_ids, i); + g_hash_table_insert (ids, + fwupd_guid_hash_string (instance_id), + g_strdup (instance_id)); + } for (guint i = 0; i < priv->guids->len; i++) { const gchar *guid = g_ptr_array_index (priv->guids, i); - fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, guid); + const gchar *instance_id = g_hash_table_lookup (ids, guid); + if (instance_id == NULL) { + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, guid); + } else { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("%s <- %s", guid, instance_id); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_GUID, tmp); + } } + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SERIAL, priv->serial); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin); @@ -1276,6 +1833,8 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION_LOWEST, priv->version_lowest); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION_BOOTLOADER, priv->version_bootloader); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION_FORMAT, + fwupd_version_format_to_string (priv->version_format)); if (priv->flashes_left < 2) fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_FLASHES_LEFT, priv->flashes_left); if (priv->icons->len > 0) { @@ -1288,10 +1847,12 @@ g_string_truncate (tmp, tmp->len - 1); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_ICON, tmp->str); } + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_CREATED, priv->created); fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_MODIFIED, priv->modified); fwupd_pad_kv_ups (str, FWUPD_RESULT_KEY_UPDATE_STATE, priv->update_state); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); for (guint i = 0; i < priv->releases->len; i++) { FwupdRelease *release = g_ptr_array_index (priv->releases, i); g_autofree gchar *tmp = fwupd_release_to_string (release); @@ -1303,10 +1864,53 @@ } static void +fwupd_device_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FwupdDevice *self = FWUPD_DEVICE (object); + FwupdDevicePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_VERSION_FORMAT: + g_value_set_uint (value, priv->version_format); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fwupd_device_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FwupdDevice *self = FWUPD_DEVICE (object); + switch (prop_id) { + case PROP_VERSION_FORMAT: + fwupd_device_set_version_format (self, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void fwupd_device_class_init (FwupdDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + object_class->finalize = fwupd_device_finalize; + object_class->get_property = fwupd_device_get_property; + object_class->set_property = fwupd_device_set_property; + + pspec = g_param_spec_uint ("version-format", NULL, NULL, + FWUPD_VERSION_FORMAT_UNKNOWN, + FWUPD_VERSION_FORMAT_LAST, + FWUPD_VERSION_FORMAT_UNKNOWN, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_VERSION_FORMAT, pspec); } static void @@ -1314,6 +1918,7 @@ { FwupdDevicePrivate *priv = GET_PRIVATE (device); priv->guids = g_ptr_array_new_with_free_func (g_free); + priv->instance_ids = g_ptr_array_new_with_free_func (g_free); priv->icons = g_ptr_array_new_with_free_func (g_free); priv->checksums = g_ptr_array_new_with_free_func (g_free); priv->releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); @@ -1325,18 +1930,24 @@ FwupdDevice *device = FWUPD_DEVICE (object); FwupdDevicePrivate *priv = GET_PRIVATE (device); + if (priv->parent != NULL) + g_object_unref (priv->parent); g_free (priv->description); g_free (priv->id); + g_free (priv->parent_id); g_free (priv->name); + g_free (priv->serial); g_free (priv->summary); g_free (priv->vendor); g_free (priv->vendor_id); g_free (priv->plugin); g_free (priv->update_error); + g_free (priv->update_message); g_free (priv->version); g_free (priv->version_lowest); g_free (priv->version_bootloader); g_ptr_array_unref (priv->guids); + g_ptr_array_unref (priv->instance_ids); g_ptr_array_unref (priv->icons); g_ptr_array_unref (priv->checksums); g_ptr_array_unref (priv->releases); @@ -1357,30 +1968,30 @@ /** * fwupd_device_from_variant: - * @data: a #GVariant + * @value: a #GVariant * * Creates a new device using packed data. * - * Returns: (transfer full): a new #FwupdDevice, or %NULL if @data was invalid + * Returns: (transfer full): a new #FwupdDevice, or %NULL if @value was invalid * * Since: 1.0.0 **/ FwupdDevice * -fwupd_device_from_variant (GVariant *data) +fwupd_device_from_variant (GVariant *value) { FwupdDevice *dev = NULL; const gchar *type_string; g_autoptr(GVariantIter) iter = NULL; /* format from GetDetails */ - type_string = g_variant_get_type_string (data); + type_string = g_variant_get_type_string (value); if (g_strcmp0 (type_string, "(a{sv})") == 0) { dev = fwupd_device_new (); - g_variant_get (data, "(a{sv})", &iter); + g_variant_get (value, "(a{sv})", &iter); fwupd_device_set_from_variant_iter (dev, iter); } else if (g_strcmp0 (type_string, "a{sv}") == 0) { dev = fwupd_device_new (); - g_variant_get (data, "a{sv}", &iter); + g_variant_get (value, "a{sv}", &iter); fwupd_device_set_from_variant_iter (dev, iter); } else { g_warning ("type %s not known", type_string); @@ -1389,6 +2000,78 @@ } /** + * fwupd_device_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new devices using packed data. + * + * Returns: (transfer container) (element-type FwupdDevice): devices, or %NULL if @value was invalid + * + * Since: 1.2.10 + **/ +GPtrArray * +fwupd_device_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + g_autoptr(GHashTable) devices_by_id = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + devices_by_id = g_hash_table_new (g_str_hash, g_str_equal); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdDevice *dev; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + dev = fwupd_device_from_variant (data); + if (dev == NULL) + continue; + g_ptr_array_add (array, dev); + if (fwupd_device_get_id (dev) != NULL) { + g_hash_table_insert (devices_by_id, + (gpointer) fwupd_device_get_id (dev), + (gpointer) dev); + } + } + + /* set the parent on each child */ + for (guint i = 0; i < array->len; i++) { + FwupdDevice *dev = g_ptr_array_index (array, i); + const gchar *parent_id = fwupd_device_get_parent_id (dev); + if (parent_id != NULL) { + FwupdDevice *dev_tmp; + dev_tmp = g_hash_table_lookup (devices_by_id, parent_id); + fwupd_device_set_parent (dev, dev_tmp); + } + } + + return array; +} + +/** + * fwupd_device_compare: + * @device1: a #FwupdDevice + * @device2: a #FwupdDevice + * + * Comparison function for comparing two FwupdDevice objects. + * + * Returns: negative, 0 or positive + * + * Since: 1.1.1 + **/ +gint +fwupd_device_compare (FwupdDevice *device1, FwupdDevice *device2) +{ + FwupdDevicePrivate *priv1 = GET_PRIVATE (device1); + FwupdDevicePrivate *priv2 = GET_PRIVATE (device2); + g_return_val_if_fail (FWUPD_IS_DEVICE (device1), 0); + g_return_val_if_fail (FWUPD_IS_DEVICE (device2), 0); + return g_strcmp0 (priv1->id, priv2->id); +} + +/** * fwupd_device_new: * * Creates a new device. diff -Nru fwupd-1.0.6/libfwupd/fwupd-device.h fwupd-1.2.10/libfwupd/fwupd-device.h --- fwupd-1.0.6/libfwupd/fwupd-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_DEVICE_H -#define __FWUPD_DEVICE_H +#pragma once #include @@ -51,9 +35,18 @@ const gchar *fwupd_device_get_id (FwupdDevice *device); void fwupd_device_set_id (FwupdDevice *device, const gchar *id); +const gchar *fwupd_device_get_parent_id (FwupdDevice *device); +void fwupd_device_set_parent_id (FwupdDevice *device, + const gchar *parent_id); +FwupdDevice *fwupd_device_get_parent (FwupdDevice *device); +void fwupd_device_set_parent (FwupdDevice *device, + FwupdDevice *parent); const gchar *fwupd_device_get_name (FwupdDevice *device); void fwupd_device_set_name (FwupdDevice *device, const gchar *name); +const gchar *fwupd_device_get_serial (FwupdDevice *device); +void fwupd_device_set_serial (FwupdDevice *device, + const gchar *serial); const gchar *fwupd_device_get_summary (FwupdDevice *device); void fwupd_device_set_summary (FwupdDevice *device, const gchar *summary); @@ -69,9 +62,15 @@ const gchar *fwupd_device_get_version_bootloader (FwupdDevice *device); void fwupd_device_set_version_bootloader (FwupdDevice *device, const gchar *version_bootloader); +FwupdVersionFormat fwupd_device_get_version_format (FwupdDevice *device); +void fwupd_device_set_version_format (FwupdDevice *device, + FwupdVersionFormat version_format); guint32 fwupd_device_get_flashes_left (FwupdDevice *device); void fwupd_device_set_flashes_left (FwupdDevice *device, guint32 flashes_left); +guint32 fwupd_device_get_install_duration (FwupdDevice *device); +void fwupd_device_set_install_duration (FwupdDevice *device, + guint32 duration); guint64 fwupd_device_get_flags (FwupdDevice *device); void fwupd_device_set_flags (FwupdDevice *device, guint64 flags); @@ -105,6 +104,11 @@ const gchar *guid); GPtrArray *fwupd_device_get_guids (FwupdDevice *device); const gchar *fwupd_device_get_guid_default (FwupdDevice *device); +void fwupd_device_add_instance_id (FwupdDevice *device, + const gchar *instance_id); +gboolean fwupd_device_has_instance_id (FwupdDevice *device, + const gchar *instance_id); +GPtrArray *fwupd_device_get_instance_ids (FwupdDevice *device); void fwupd_device_add_icon (FwupdDevice *device, const gchar *icon); GPtrArray *fwupd_device_get_icons (FwupdDevice *device); @@ -115,12 +119,17 @@ const gchar *fwupd_device_get_update_error (FwupdDevice *device); void fwupd_device_set_update_error (FwupdDevice *device, const gchar *update_error); +const gchar *fwupd_device_get_update_message (FwupdDevice *device); +void fwupd_device_set_update_message (FwupdDevice *device, + const gchar *update_message); void fwupd_device_add_release (FwupdDevice *device, FwupdRelease *release); GPtrArray *fwupd_device_get_releases (FwupdDevice *device); FwupdRelease *fwupd_device_get_release_default (FwupdDevice *device); +gint fwupd_device_compare (FwupdDevice *device1, + FwupdDevice *device2); -G_END_DECLS - -#endif /* __FWUPD_DEVICE_H */ +FwupdDevice *fwupd_device_from_variant (GVariant *value); +GPtrArray *fwupd_device_array_from_variant (GVariant *value); +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-device-private.h fwupd-1.2.10/libfwupd/fwupd-device-private.h --- fwupd-1.0.6/libfwupd/fwupd-device-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-device-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,37 +1,25 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_DEVICE_PRIVATE_H -#define __FWUPD_DEVICE_PRIVATE_H +#pragma once #include +#include #include "fwupd-device.h" G_BEGIN_DECLS -FwupdDevice *fwupd_device_from_variant (GVariant *data); GVariant *fwupd_device_to_variant (FwupdDevice *device); +GVariant *fwupd_device_to_variant_full (FwupdDevice *device, + FwupdDeviceFlags flags); +void fwupd_device_incorporate (FwupdDevice *self, + FwupdDevice *donor); +void fwupd_device_to_json (FwupdDevice *device, + JsonBuilder *builder); G_END_DECLS -#endif /* __FWUPD_DEVICE_PRIVATE_H */ - diff -Nru fwupd-1.0.6/libfwupd/fwupd-enums.c fwupd-1.2.10/libfwupd/fwupd-enums.c --- fwupd-1.0.6/libfwupd/fwupd-enums.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-enums.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -72,6 +57,8 @@ return "downloading"; if (status == FWUPD_STATUS_WAITING_FOR_AUTH) return "waiting-for-auth"; + if (status == FWUPD_STATUS_SHUTDOWN) + return "shutdown"; return NULL; } @@ -114,6 +101,8 @@ return FWUPD_STATUS_DEVICE_BUSY; if (g_strcmp0 (status, "waiting-for-auth") == 0) return FWUPD_STATUS_WAITING_FOR_AUTH; + if (g_strcmp0 (status, "shutdown") == 0) + return FWUPD_STATUS_SHUTDOWN; return FWUPD_STATUS_LAST; } @@ -150,12 +139,30 @@ return "registered"; if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_REBOOT) return "needs-reboot"; + if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) + return "needs-shutdown"; if (device_flag == FWUPD_DEVICE_FLAG_REPORTED) return "reported"; if (device_flag == FWUPD_DEVICE_FLAG_NOTIFIED) return "notified"; if (device_flag == FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION) return "use-runtime-version"; + if (device_flag == FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST) + return "install-parent-first"; + if (device_flag == FWUPD_DEVICE_FLAG_IS_BOOTLOADER) + return "is-bootloader"; + if (device_flag == FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) + return "wait-for-replug"; + if (device_flag == FWUPD_DEVICE_FLAG_IGNORE_VALIDATION) + return "ignore-validation"; + if (device_flag == FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED) + return "another-write-required"; + if (device_flag == FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS) + return "no-auto-instance-ids"; + if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) + return "needs-activation"; + if (device_flag == FWUPD_DEVICE_FLAG_ENSURE_SEMVER) + return "ensure-semver"; if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN) return "unknown"; return NULL; @@ -196,12 +203,30 @@ return FWUPD_DEVICE_FLAG_REGISTERED; if (g_strcmp0 (device_flag, "needs-reboot") == 0) return FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + if (g_strcmp0 (device_flag, "needs-shutdown") == 0) + return FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; if (g_strcmp0 (device_flag, "reported") == 0) return FWUPD_DEVICE_FLAG_REPORTED; if (g_strcmp0 (device_flag, "notified") == 0) return FWUPD_DEVICE_FLAG_NOTIFIED; if (g_strcmp0 (device_flag, "use-runtime-version") == 0) return FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION; + if (g_strcmp0 (device_flag, "install-parent-first") == 0) + return FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST; + if (g_strcmp0 (device_flag, "is-bootloader") == 0) + return FWUPD_DEVICE_FLAG_IS_BOOTLOADER; + if (g_strcmp0 (device_flag, "wait-for-replug") == 0) + return FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG; + if (g_strcmp0 (device_flag, "ignore-validation") == 0) + return FWUPD_DEVICE_FLAG_IGNORE_VALIDATION; + if (g_strcmp0 (device_flag, "another-write-required") == 0) + return FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED; + if (g_strcmp0 (device_flag, "no-auto-instance-ids") == 0) + return FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS; + if (g_strcmp0 (device_flag, "needs-activation") == 0) + return FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION; + if (g_strcmp0 (device_flag, "ensure-semver") == 0) + return FWUPD_DEVICE_FLAG_ENSURE_SEMVER; return FWUPD_DEVICE_FLAG_UNKNOWN; } @@ -226,6 +251,8 @@ return "success"; if (update_state == FWUPD_UPDATE_STATE_FAILED) return "failed"; + if (update_state == FWUPD_UPDATE_STATE_FAILED_TRANSIENT) + return "failed-transient"; if (update_state == FWUPD_UPDATE_STATE_NEEDS_REBOOT) return "needs-reboot"; return NULL; @@ -252,6 +279,8 @@ return FWUPD_UPDATE_STATE_SUCCESS; if (g_strcmp0 (update_state, "failed") == 0) return FWUPD_UPDATE_STATE_FAILED; + if (g_strcmp0 (update_state, "failed-transient") == 0) + return FWUPD_UPDATE_STATE_FAILED_TRANSIENT; if (g_strcmp0 (update_state, "needs-reboot") == 0) return FWUPD_UPDATE_STATE_NEEDS_REBOOT; return FWUPD_UPDATE_STATE_UNKNOWN; @@ -344,3 +373,125 @@ return "pkcs7"; return NULL; } + +/** + * fwupd_release_flag_to_string: + * @release_flag: A #FwupdReleaseFlags, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD + * + * Converts a #FwupdReleaseFlags to a string. + * + * Return value: identifier string + * + * Since: 1.2.6 + **/ +const gchar * +fwupd_release_flag_to_string (FwupdReleaseFlags release_flag) +{ + if (release_flag == FWUPD_RELEASE_FLAG_NONE) + return "none"; + if (release_flag == FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD) + return "trusted-payload"; + if (release_flag == FWUPD_RELEASE_FLAG_TRUSTED_METADATA) + return "trusted-metadata"; + if (release_flag == FWUPD_RELEASE_FLAG_IS_UPGRADE) + return "is-upgrade"; + if (release_flag == FWUPD_RELEASE_FLAG_IS_DOWNGRADE) + return "is-downgrade"; + if (release_flag == FWUPD_RELEASE_FLAG_BLOCKED_VERSION) + return "blocked-version"; + if (release_flag == FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL) + return "blocked-approval"; + return NULL; +} + +/** + * fwupd_release_flag_from_string: + * @release_flag: A string, e.g. `trusted-payload` + * + * Converts a string to a #FwupdReleaseFlags. + * + * Return value: enumerated value + * + * Since: 1.2.6 + **/ +FwupdReleaseFlags +fwupd_release_flag_from_string (const gchar *release_flag) +{ + if (g_strcmp0 (release_flag, "trusted-payload") == 0) + return FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD; + if (g_strcmp0 (release_flag, "trusted-metadata") == 0) + return FWUPD_RELEASE_FLAG_TRUSTED_METADATA; + if (g_strcmp0 (release_flag, "is-upgrade") == 0) + return FWUPD_RELEASE_FLAG_IS_UPGRADE; + if (g_strcmp0 (release_flag, "is-downgrade") == 0) + return FWUPD_RELEASE_FLAG_IS_DOWNGRADE; + if (g_strcmp0 (release_flag, "blocked-version") == 0) + return FWUPD_RELEASE_FLAG_BLOCKED_VERSION; + if (g_strcmp0 (release_flag, "blocked-approval") == 0) + return FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL; + return FWUPD_RELEASE_FLAG_NONE; +} + +/** + * fwupd_version_format_from_string: + * @str: A string, e.g. `quad` + * + * Converts text to a display version type. + * + * Returns: A #FwupdVersionFormat, e.g. %FWUPD_VERSION_FORMAT_TRIPLET + * + * Since: 1.2.9 + **/ +FwupdVersionFormat +fwupd_version_format_from_string (const gchar *str) +{ + if (g_strcmp0 (str, "plain") == 0) + return FWUPD_VERSION_FORMAT_PLAIN; + if (g_strcmp0 (str, "pair") == 0) + return FWUPD_VERSION_FORMAT_PAIR; + if (g_strcmp0 (str, "number") == 0) + return FWUPD_VERSION_FORMAT_NUMBER; + if (g_strcmp0 (str, "triplet") == 0) + return FWUPD_VERSION_FORMAT_TRIPLET; + if (g_strcmp0 (str, "quad") == 0) + return FWUPD_VERSION_FORMAT_QUAD; + if (g_strcmp0 (str, "bcd") == 0) + return FWUPD_VERSION_FORMAT_BCD; + if (g_strcmp0 (str, "intel-me") == 0) + return FWUPD_VERSION_FORMAT_INTEL_ME; + if (g_strcmp0 (str, "intel-me2") == 0) + return FWUPD_VERSION_FORMAT_INTEL_ME2; + return FWUPD_VERSION_FORMAT_UNKNOWN; +} + +/** + * fwupd_version_format_to_string: + * @kind: A #FwupdVersionFormat, e.g. %FWUPD_VERSION_FORMAT_TRIPLET + * + * Converts a display version type to text. + * + * Returns: A string, e.g. `quad`, or %NULL if not known + * + * Since: 1.2.9 + **/ +const gchar * +fwupd_version_format_to_string (FwupdVersionFormat kind) +{ + if (kind == FWUPD_VERSION_FORMAT_PLAIN) + return "plain"; + if (kind == FWUPD_VERSION_FORMAT_NUMBER) + return "number"; + if (kind == FWUPD_VERSION_FORMAT_PAIR) + return "pair"; + if (kind == FWUPD_VERSION_FORMAT_TRIPLET) + return "triplet"; + if (kind == FWUPD_VERSION_FORMAT_QUAD) + return "quad"; + if (kind == FWUPD_VERSION_FORMAT_BCD) + return "bcd"; + if (kind == FWUPD_VERSION_FORMAT_INTEL_ME) + return "intel-me"; + if (kind == FWUPD_VERSION_FORMAT_INTEL_ME2) + return "intel-me2"; + return NULL; +} diff -Nru fwupd-1.0.6/libfwupd/fwupd-enums.h fwupd-1.2.10/libfwupd/fwupd-enums.h --- fwupd-1.0.6/libfwupd/fwupd-enums.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-enums.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_ENUMS_H -#define __FWUPD_ENUMS_H +#pragma once #include +G_BEGIN_DECLS + /** * FwupdStatus: * @FWUPD_STATUS_UNKNOWN: Unknown state @@ -39,6 +25,7 @@ * @FWUPD_STATUS_DEVICE_ERASE: Erasing a device * @FWUPD_STATUS_WAITING_FOR_AUTH: Waiting for authentication * @FWUPD_STATUS_DEVICE_BUSY: The device is busy + * @FWUPD_STATUS_SHUTDOWN: The daemon is shutting down * * The flags to show daemon status. **/ @@ -56,6 +43,7 @@ FWUPD_STATUS_DEVICE_ERASE, /* Since: 1.0.0 */ FWUPD_STATUS_WAITING_FOR_AUTH, /* Since: 1.0.0 */ FWUPD_STATUS_DEVICE_BUSY, /* Since: 1.0.1 */ + FWUPD_STATUS_SHUTDOWN, /* Since: 1.2.1 */ /*< private >*/ FWUPD_STATUS_LAST } FwupdStatus; @@ -91,6 +79,16 @@ * @FWUPD_DEVICE_FLAG_REPORTED: Has been reported to a metadata server * @FWUPD_DEVICE_FLAG_NOTIFIED: User has been notified * @FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION: Always use the runtime version rather than the bootloader + * @FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST: Install composite firmware on the parent before the child + * @FWUPD_DEVICE_FLAG_IS_BOOTLOADER: Is currently in bootloader mode + * @FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG: The hardware is waiting to be replugged + * @FWUPD_DEVICE_FLAG_IGNORE_VALIDATION: Ignore validation safety checks when flashing this device + * @FWUPD_DEVICE_FLAG_TRUSTED: Extra metadata can be exposed about this device + * @FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN: Requires system shutdown to apply firmware + * @FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED: Requires the update to be retried with a new plugin + * @FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS: Do not add instance IDs from the device baseclass + * @FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION: Device update needs to be separately activated + * @FWUPD_DEVICE_FLAG_ENSURE_SEMVER: Ensure the version is a valid semantic version, e.g. numbers separated with dots * * The device flags. **/ @@ -107,36 +105,87 @@ #define FWUPD_DEVICE_FLAG_REPORTED (1u << 9) /* Since: 1.0.4 */ #define FWUPD_DEVICE_FLAG_NOTIFIED (1u << 10) /* Since: 1.0.5 */ #define FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION (1u << 11) /* Since: 1.0.6 */ +#define FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST (1u << 12) /* Since: 1.0.8 */ +#define FWUPD_DEVICE_FLAG_IS_BOOTLOADER (1u << 13) /* Since: 1.0.8 */ +#define FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG (1u << 14) /* Since: 1.1.2 */ +#define FWUPD_DEVICE_FLAG_IGNORE_VALIDATION (1u << 15) /* Since: 1.1.2 */ +#define FWUPD_DEVICE_FLAG_TRUSTED (1u << 16) /* Since: 1.1.2 */ +#define FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN (1u << 17) /* Since: 1.2.4 */ +#define FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED (1u << 18) /* Since: 1.2.5 */ +#define FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS (1u << 19) /* Since: 1.2.5 */ +#define FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION (1u << 20) /* Since: 1.2.6 */ +#define FWUPD_DEVICE_FLAG_ENSURE_SEMVER (1u << 21) /* Since: 1.2.9 */ #define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */ typedef guint64 FwupdDeviceFlags; /** + * FwupdReleaseFlags: + * @FWUPD_RELEASE_FLAG_NONE: No flags set + * @FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD: The payload binary is trusted + * @FWUPD_RELEASE_FLAG_TRUSTED_METADATA: The payload metadata is trusted + * @FWUPD_RELEASE_FLAG_IS_UPGRADE: Is newer than the device version + * @FWUPD_RELEASE_FLAG_IS_DOWNGRADE: Is older than the device version + * @FWUPD_RELEASE_FLAG_BLOCKED_VERSION: Blocked as below device version-lowest + * @FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL: Blocked as release not approved + * + * The release flags. + **/ +#define FWUPD_RELEASE_FLAG_NONE (0u) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD (1u << 0) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_TRUSTED_METADATA (1u << 1) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_IS_UPGRADE (1u << 2) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_IS_DOWNGRADE (1u << 3) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_BLOCKED_VERSION (1u << 4) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL (1u << 5) /* Since: 1.2.6 */ +#define FWUPD_RELEASE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.2.6 */ +typedef guint64 FwupdReleaseFlags; + +/** * FwupdInstallFlags: * @FWUPD_INSTALL_FLAG_NONE: No flags set * @FWUPD_INSTALL_FLAG_OFFLINE: Schedule this for next boot * @FWUPD_INSTALL_FLAG_ALLOW_REINSTALL: Allow reinstalling the same version * @FWUPD_INSTALL_FLAG_ALLOW_OLDER: Allow downgrading firmware * @FWUPD_INSTALL_FLAG_FORCE: Force the update even if not a good idea + * @FWUPD_INSTALL_FLAG_NO_HISTORY: Do not write to the history database * * Flags to set when performing the firwmare update or install. **/ typedef enum { - FWUPD_INSTALL_FLAG_NONE = 0, /* Since: 0.7.0 */ - FWUPD_INSTALL_FLAG_OFFLINE = 1, /* Since: 0.7.0 */ - FWUPD_INSTALL_FLAG_ALLOW_REINSTALL = 2, /* Since: 0.7.0 */ - FWUPD_INSTALL_FLAG_ALLOW_OLDER = 4, /* Since: 0.7.0 */ - FWUPD_INSTALL_FLAG_FORCE = 8, /* Since: 0.7.1 */ + FWUPD_INSTALL_FLAG_NONE = 0, /* Since: 0.7.0 */ + FWUPD_INSTALL_FLAG_OFFLINE = 1 << 0, /* Since: 0.7.0 */ + FWUPD_INSTALL_FLAG_ALLOW_REINSTALL = 1 << 1, /* Since: 0.7.0 */ + FWUPD_INSTALL_FLAG_ALLOW_OLDER = 1 << 2, /* Since: 0.7.0 */ + FWUPD_INSTALL_FLAG_FORCE = 1 << 3, /* Since: 0.7.1 */ + FWUPD_INSTALL_FLAG_NO_HISTORY = 1 << 4, /* Since: 1.0.8 */ /*< private >*/ FWUPD_INSTALL_FLAG_LAST } FwupdInstallFlags; /** + * FwupdSelfSignFlags: + * @FWUPD_SELF_SIGN_FLAG_NONE: No flags set + * @FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP: Add the timestamp to the detached signature + * @FWUPD_SELF_SIGN_FLAG_ADD_CERT: Add the certificate to the detached signature + * + * Flags to set when performing the firwmare update or install. + **/ +typedef enum { + FWUPD_SELF_SIGN_FLAG_NONE = 0, /* Since: 1.2.6 */ + FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP = 1 << 0, /* Since: 1.2.6 */ + FWUPD_SELF_SIGN_FLAG_ADD_CERT = 1 << 1, /* Since: 1.2.6 */ + /*< private >*/ + FWUPD_SELF_SIGN_FLAG_LAST +} FwupdSelfSignFlags; + +/** * FwupdUpdateState: * @FWUPD_UPDATE_STATE_UNKNOWN: Unknown * @FWUPD_UPDATE_STATE_PENDING: Update is pending - * @FWUPD_UPDATE_STATE_SUCCESS: Update was successfull + * @FWUPD_UPDATE_STATE_SUCCESS: Update was successful * @FWUPD_UPDATE_STATE_FAILED: Update failed * @FWUPD_UPDATE_STATE_NEEDS_REBOOT: Waiting for a reboot to apply + * @FWUPD_UPDATE_STATE_FAILED_TRANSIENT: Update failed due to transient issue, e.g. AC power required * * The update state. **/ @@ -146,6 +195,7 @@ FWUPD_UPDATE_STATE_SUCCESS, /* Since: 0.7.0 */ FWUPD_UPDATE_STATE_FAILED, /* Since: 0.7.0 */ FWUPD_UPDATE_STATE_NEEDS_REBOOT, /* Since: 1.0.4 */ + FWUPD_UPDATE_STATE_FAILED_TRANSIENT, /* Since: 1.2.7 */ /*< private >*/ FWUPD_UPDATE_STATE_LAST } FwupdUpdateState; @@ -168,15 +218,50 @@ FWUPD_KEYRING_KIND_LAST } FwupdKeyringKind; +/** + * FwupdVersionFormat: + * @FWUPD_VERSION_FORMAT_UNKNOWN: Unknown version format + * @FWUPD_VERSION_FORMAT_PLAIN: An unidentified format text string + * @FWUPD_VERSION_FORMAT_NUMBER: A single integer version number + * @FWUPD_VERSION_FORMAT_PAIR: Two AABB.CCDD version numbers + * @FWUPD_VERSION_FORMAT_TRIPLET: Microsoft-style AA.BB.CCDD version numbers + * @FWUPD_VERSION_FORMAT_QUAD: Dell-style AA.BB.CC.DD version numbers + * @FWUPD_VERSION_FORMAT_BCD: Binary coded decimal notation + * @FWUPD_VERSION_FORMAT_INTEL_ME: Intel ME-style bitshifted notation + * @FWUPD_VERSION_FORMAT_INTEL_ME2: Intel ME-style A.B.CC.DDDD notation notation + * + * The flags used when parsing version numbers. + * + * If no verification is required then %FWUPD_VERSION_FORMAT_PLAIN should + * be used to signify an unparsable text string. + **/ +typedef enum { + FWUPD_VERSION_FORMAT_UNKNOWN, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_PLAIN, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_NUMBER, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_PAIR, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_TRIPLET, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_QUAD, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_BCD, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_INTEL_ME, /* Since: 1.2.9 */ + FWUPD_VERSION_FORMAT_INTEL_ME2, /* Since: 1.2.9 */ + /*< private >*/ + FWUPD_VERSION_FORMAT_LAST +} FwupdVersionFormat; + const gchar *fwupd_status_to_string (FwupdStatus status); FwupdStatus fwupd_status_from_string (const gchar *status); const gchar *fwupd_device_flag_to_string (FwupdDeviceFlags device_flag); FwupdDeviceFlags fwupd_device_flag_from_string (const gchar *device_flag); +const gchar *fwupd_release_flag_to_string (FwupdReleaseFlags release_flag); +FwupdReleaseFlags fwupd_release_flag_from_string (const gchar *release_flag); const gchar *fwupd_update_state_to_string (FwupdUpdateState update_state); FwupdUpdateState fwupd_update_state_from_string (const gchar *update_state); const gchar *fwupd_trust_flag_to_string (FwupdTrustFlags trust_flag); FwupdTrustFlags fwupd_trust_flag_from_string (const gchar *trust_flag); FwupdKeyringKind fwupd_keyring_kind_from_string (const gchar *keyring_kind); const gchar *fwupd_keyring_kind_to_string (FwupdKeyringKind keyring_kind); +FwupdVersionFormat fwupd_version_format_from_string (const gchar *str); +const gchar *fwupd_version_format_to_string (FwupdVersionFormat kind); -#endif /* __FWUPD_ENUMS_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-enums-private.h fwupd-1.2.10/libfwupd/fwupd-enums-private.h --- fwupd-1.0.6/libfwupd/fwupd-enums-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-enums-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,37 +1,30 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2016-2018 Richard Hughes * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_ENUMS_PRIVATE_H -#define __FWUPD_ENUMS_PRIVATE_H +#pragma once + +G_BEGIN_DECLS #define FWUPD_RESULT_KEY_APPSTREAM_ID "AppstreamId" /* s */ #define FWUPD_RESULT_KEY_CHECKSUM "Checksum" /* as */ #define FWUPD_RESULT_KEY_CREATED "Created" /* t */ #define FWUPD_RESULT_KEY_DESCRIPTION "Description" /* s */ #define FWUPD_RESULT_KEY_DEVICE_ID "DeviceId" /* s */ +#define FWUPD_RESULT_KEY_PARENT_DEVICE_ID "ParentDeviceId"/* s */ #define FWUPD_RESULT_KEY_FILENAME "Filename" /* s */ +#define FWUPD_RESULT_KEY_PROTOCOL "Protocol" /* s */ +#define FWUPD_RESULT_KEY_CATEGORIES "Categories" /* as */ #define FWUPD_RESULT_KEY_FLAGS "Flags" /* t */ #define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft" /* u */ +#define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration" /* u */ #define FWUPD_RESULT_KEY_GUID "Guid" /* as */ +#define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds" /* as */ #define FWUPD_RESULT_KEY_HOMEPAGE "Homepage" /* s */ +#define FWUPD_RESULT_KEY_DETAILS_URL "DetailsUrl" /* s */ +#define FWUPD_RESULT_KEY_SOURCE_URL "SourceUrl" /* s */ #define FWUPD_RESULT_KEY_ICON "Icon" /* as */ #define FWUPD_RESULT_KEY_LICENSE "License" /* s */ #define FWUPD_RESULT_KEY_MODIFIED "Modified" /* t */ @@ -40,9 +33,11 @@ #define FWUPD_RESULT_KEY_PLUGIN "Plugin" /* s */ #define FWUPD_RESULT_KEY_RELEASE "Release" /* a{sv} */ #define FWUPD_RESULT_KEY_REMOTE_ID "RemoteId" /* s */ +#define FWUPD_RESULT_KEY_SERIAL "Serial" /* s */ #define FWUPD_RESULT_KEY_SIZE "Size" /* t */ #define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */ #define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */ +#define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */ #define FWUPD_RESULT_KEY_UPDATE_ERROR "UpdateError" /* s */ #define FWUPD_RESULT_KEY_UPDATE_STATE "UpdateState" /* u */ #define FWUPD_RESULT_KEY_URI "Uri" /* s */ @@ -50,7 +45,8 @@ #define FWUPD_RESULT_KEY_VENDOR "Vendor" /* s */ #define FWUPD_RESULT_KEY_VENDOR "Vendor" /* s */ #define FWUPD_RESULT_KEY_VERSION_BOOTLOADER "VersionBootloader" /* s */ +#define FWUPD_RESULT_KEY_VERSION_FORMAT "VersionFormat" /* u */ #define FWUPD_RESULT_KEY_VERSION_LOWEST "VersionLowest" /* s */ #define FWUPD_RESULT_KEY_VERSION "Version" /* s */ -#endif /* __FWUPD_ENUMS_PRIVATE_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-error.c fwupd-1.2.10/libfwupd/fwupd-error.c --- fwupd-1.0.6/libfwupd/fwupd-error.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-error.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -78,6 +63,10 @@ return FWUPD_DBUS_INTERFACE ".AcPowerRequired"; if (error == FWUPD_ERROR_PERMISSION_DENIED) return FWUPD_DBUS_INTERFACE ".PermissionDenied"; + if (error == FWUPD_ERROR_BROKEN_SYSTEM) + return FWUPD_DBUS_INTERFACE ".BrokenSystem"; + if (error == FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW) + return FWUPD_DBUS_INTERFACE ".BatteryLevelTooLow"; return NULL; } @@ -122,6 +111,10 @@ return FWUPD_ERROR_AC_POWER_REQUIRED; if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".PermissionDenied") == 0) return FWUPD_ERROR_PERMISSION_DENIED; + if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".BrokenSystem") == 0) + return FWUPD_ERROR_BROKEN_SYSTEM; + if (g_strcmp0 (error, FWUPD_DBUS_INTERFACE ".BatteryLevelTooLow") == 0) + return FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW; return FWUPD_ERROR_LAST; } diff -Nru fwupd-1.0.6/libfwupd/fwupd-error.h fwupd-1.2.10/libfwupd/fwupd-error.h --- fwupd-1.0.6/libfwupd/fwupd-error.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-error.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_ERROR_H -#define __FWUPD_ERROR_H +#pragma once #include +G_BEGIN_DECLS + #define FWUPD_ERROR fwupd_error_quark() /** @@ -42,6 +28,8 @@ * @FWUPD_ERROR_SIGNATURE_INVALID: Signature was invalid * @FWUPD_ERROR_AC_POWER_REQUIRED: AC power was required * @FWUPD_ERROR_PERMISSION_DENIED: Permission was denied + * @FWUPD_ERROR_BROKEN_SYSTEM: User has configured their system in a broken way + * @FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW: The system battery level is too low * * The error code. **/ @@ -60,6 +48,8 @@ FWUPD_ERROR_SIGNATURE_INVALID, /* Since: 0.1.2 */ FWUPD_ERROR_AC_POWER_REQUIRED, /* Since: 0.8.0 */ FWUPD_ERROR_PERMISSION_DENIED, /* Since: 0.9.8 */ + FWUPD_ERROR_BROKEN_SYSTEM, /* Since: 1.2.8 */ + FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW, /* Since: 1.2.10 */ /*< private >*/ FWUPD_ERROR_LAST } FwupdError; @@ -68,4 +58,4 @@ const gchar *fwupd_error_to_string (FwupdError error); FwupdError fwupd_error_from_string (const gchar *error); -#endif /* __FWUPD_ERROR_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd.h fwupd-1.2.10/libfwupd/fwupd.h --- fwupd-1.0.6/libfwupd/fwupd.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,32 +1,16 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + /** * SECTION:fwupd * @short_description: Helper objects for accessing fwupd */ -#ifndef __FWUPD_H__ -#define __FWUPD_H__ - #define __FWUPD_H_INSIDE__ #include @@ -43,6 +27,3 @@ #endif #undef __FWUPD_H_INSIDE__ - -#endif /* __FWUPD_H__ */ - diff -Nru fwupd-1.0.6/libfwupd/fwupd.map fwupd-1.2.10/libfwupd/fwupd.map --- fwupd-1.0.6/libfwupd/fwupd.map 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd.map 2019-07-15 18:25:54.000000000 +0000 @@ -235,3 +235,139 @@ fwupd_remote_get_report_uri; local: *; } LIBFWUPD_1.0.3; + +LIBFWUPD_1.0.7 { + global: + fwupd_get_os_release; + fwupd_remote_get_agreement; + fwupd_remote_set_agreement; + local: *; +} LIBFWUPD_1.0.4; + +LIBFWUPD_1.0.8 { + global: + fwupd_device_get_parent; + fwupd_device_get_parent_id; + fwupd_device_set_parent; + fwupd_device_set_parent_id; + local: *; +} LIBFWUPD_1.0.7; + +LIBFWUPD_1.1.0 { + global: + fwupd_device_incorporate; + local: *; +} LIBFWUPD_1.0.8; + +LIBFWUPD_1.1.1 { + global: + fwupd_device_compare; + local: *; +} LIBFWUPD_1.1.0; + +LIBFWUPD_1.1.2 { + global: + fwupd_device_get_serial; + fwupd_device_set_serial; + fwupd_device_to_variant_full; + local: *; +} LIBFWUPD_1.1.1; + +LIBFWUPD_1.1.3 { + global: + fwupd_device_get_install_duration; + fwupd_device_set_install_duration; + local: *; +} LIBFWUPD_1.1.2; + +LIBFWUPD_1.2.1 { + global: + fwupd_release_get_install_duration; + fwupd_release_set_install_duration; + local: *; +} LIBFWUPD_1.1.3; + +LIBFWUPD_1.2.2 { + global: + fwupd_release_get_protocol; + fwupd_release_set_protocol; + local: *; +} LIBFWUPD_1.2.1; + +LIBFWUPD_1.2.4 { + global: + fwupd_client_get_tainted; + fwupd_device_get_update_message; + fwupd_device_set_update_message; + fwupd_release_get_details_url; + fwupd_release_get_source_url; + fwupd_release_get_update_message; + fwupd_release_set_details_url; + fwupd_release_set_source_url; + fwupd_release_set_update_message; + local: *; +} LIBFWUPD_1.2.2; + +LIBFWUPD_1.2.5 { + global: + fwupd_device_add_instance_id; + fwupd_device_get_instance_ids; + fwupd_device_has_instance_id; + fwupd_guid_from_string; + fwupd_guid_hash_data; + fwupd_guid_hash_string; + fwupd_guid_is_valid; + fwupd_guid_to_string; + local: *; +} LIBFWUPD_1.2.4; + +LIBFWUPD_1.2.6 { + global: + fwupd_client_activate; + fwupd_client_get_approved_firmware; + fwupd_client_self_sign; + fwupd_client_set_approved_firmware; + fwupd_device_to_json; + fwupd_release_add_flag; + fwupd_release_flag_from_string; + fwupd_release_flag_to_string; + fwupd_release_get_flags; + fwupd_release_has_checksum; + fwupd_release_has_flag; + fwupd_release_remove_flag; + fwupd_release_set_flags; + fwupd_release_to_json; + fwupd_remote_get_approval_required; + local: *; +} LIBFWUPD_1.2.5; + +LIBFWUPD_1.2.7 { + global: + fwupd_release_add_category; + fwupd_release_get_categories; + fwupd_release_has_category; + local: *; +} LIBFWUPD_1.2.6; + +LIBFWUPD_1.2.8 { + global: + fwupd_client_modify_config; + local: *; +} LIBFWUPD_1.2.7; + +LIBFWUPD_1.2.9 { + global: + fwupd_device_get_version_format; + fwupd_device_set_version_format; + fwupd_version_format_from_string; + fwupd_version_format_to_string; + local: *; +} LIBFWUPD_1.2.8; + +LIBFWUPD_1.2.10 { + global: + fwupd_device_array_from_variant; + fwupd_release_array_from_variant; + fwupd_remote_array_from_variant; + local: *; +} LIBFWUPD_1.2.9; diff -Nru fwupd-1.0.6/libfwupd/fwupd-release.c fwupd-1.2.10/libfwupd/fwupd-release.c --- fwupd-1.0.6/libfwupd/fwupd-release.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-release.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2015-2018 Richard Hughes * - * Copyright (C) 2015-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -45,10 +30,14 @@ typedef struct { GPtrArray *checksums; + GPtrArray *categories; GHashTable *metadata; gchar *description; gchar *filename; + gchar *protocol; gchar *homepage; + gchar *details_url; + gchar *source_url; gchar *appstream_id; gchar *license; gchar *name; @@ -58,12 +47,18 @@ gchar *version; gchar *remote_id; guint64 size; - FwupdTrustFlags trust_flags; + guint32 install_duration; + FwupdReleaseFlags flags; + gchar *update_message; } FwupdReleasePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FwupdRelease, fwupd_release, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_release_get_instance_private (o)) +/* the deprecated fwupd_release_get_trust_flags() function should only + * return the last two bits of the #FwupdReleaseFlags */ +#define FWUPD_RELEASE_TRUST_FLAGS_MASK 0x3 + /** * fwupd_release_get_remote_id: * @release: A #FwupdRelease @@ -173,6 +168,144 @@ } /** + * fwupd_release_get_update_message: + * @release: A #FwupdRelease + * + * Gets the update message. + * + * Returns: the update message, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_update_message (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->update_message; +} + +/** + * fwupd_release_set_update_message: + * @release: A #FwupdRelease + * @update_message: the update message string + * + * Sets the update message. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_update_message (FwupdRelease *release, const gchar *update_message) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->update_message); + priv->update_message = g_strdup (update_message); +} + +/** + * fwupd_release_get_protocol: + * @release: A #FwupdRelease + * + * Gets the update protocol. + * + * Returns: the update protocol, or %NULL if unset + * + * Since: 1.2.2 + **/ +const gchar * +fwupd_release_get_protocol (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->protocol; +} + +/** + * fwupd_release_set_protocol: + * @release: A #FwupdRelease + * @protocol: the update protocol, e.g. `org.usb.dfu` + * + * Sets the update protocol. + * + * Since: 1.2.2 + **/ +void +fwupd_release_set_protocol (FwupdRelease *release, const gchar *protocol) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->protocol); + priv->protocol = g_strdup (protocol); +} + +/** + * fwupd_release_get_categories: + * @release: A #FwupdRelease + * + * Gets the release categories. + * + * Returns: (element-type utf8) (transfer none): the categories, which may be empty + * + * Since: 1.2.7 + **/ +GPtrArray * +fwupd_release_get_categories (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->categories; +} + +/** + * fwupd_release_add_category: + * @release: A #FwupdRelease + * @category: the update category, e.g. `X-EmbeddedController` + * + * Adds the update category. + * + * Since: 1.2.7 + **/ +void +fwupd_release_add_category (FwupdRelease *release, const gchar *category) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_return_if_fail (category != NULL); + for (guint i = 0; i < priv->categories->len; i++) { + const gchar *category_tmp = g_ptr_array_index (priv->categories, i); + if (g_strcmp0 (category_tmp, category) == 0) + return; + } + g_ptr_array_add (priv->categories, g_strdup (category)); +} + +/** + * fwupd_release_has_category: + * @release: A #FwupdRelease + * @category: the update category, e.g. `X-EmbeddedController` + * + * Finds out if the release has the update category. + * + * Returns: %TRUE if the release matches + * + * Since: 1.2.7 + **/ +gboolean +fwupd_release_has_category (FwupdRelease *release, const gchar *category) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), FALSE); + g_return_val_if_fail (category != NULL, FALSE); + for (guint i = 0; i < priv->categories->len; i++) { + const gchar *category_tmp = g_ptr_array_index (priv->categories, i); + if (g_strcmp0 (category_tmp, category) == 0) + return TRUE; + } + return FALSE; +} + +/** * fwupd_release_get_checksums: * @release: A #FwupdRelease * @@ -214,6 +347,31 @@ } /** + * fwupd_release_has_checksum: + * @release: A #FwupdRelease + * @checksum: the update checksum + * + * Finds out if the release has the update checksum. + * + * Returns: %TRUE if the release matches + * + * Since: 1.2.6 + **/ +gboolean +fwupd_release_has_checksum (FwupdRelease *release, const gchar *checksum) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), FALSE); + g_return_val_if_fail (checksum != NULL, FALSE); + for (guint i = 0; i < priv->checksums->len; i++) { + const gchar *checksum_tmp = g_ptr_array_index (priv->checksums, i); + if (g_strcmp0 (checksum_tmp, checksum) == 0) + return TRUE; + } + return FALSE; +} + +/** * fwupd_release_get_metadata: * @release: A #FwupdRelease * @@ -371,6 +529,78 @@ } /** + * fwupd_release_get_details_url: + * @release: A #FwupdRelease + * + * Gets the URL for the online update notes. + * + * Returns: the update URL, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_details_url (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->details_url; +} + +/** + * fwupd_release_set_details_url: + * @release: A #FwupdRelease + * @details_url: the URL + * + * Sets the URL for the online update notes. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_details_url (FwupdRelease *release, const gchar *details_url) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->details_url); + priv->details_url = g_strdup (details_url); +} + +/** + * fwupd_release_get_source_url: + * @release: A #FwupdRelease + * + * Gets the URL of the source code used to build this release. + * + * Returns: the update source_url, or %NULL if unset + * + * Since: 1.2.4 + **/ +const gchar * +fwupd_release_get_source_url (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); + return priv->source_url; +} + +/** + * fwupd_release_set_source_url: + * @release: A #FwupdRelease + * @source_url: the URL + * + * Sets the URL of the source code used to build this release. + * + * Since: 1.2.4 + **/ +void +fwupd_release_set_source_url (FwupdRelease *release, const gchar *source_url) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_free (priv->source_url); + priv->source_url = g_strdup (source_url); +} + +/** * fwupd_release_get_description: * @release: A #FwupdRelease * @@ -636,7 +866,7 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_val_if_fail (FWUPD_IS_RELEASE (release), 0); - return priv->trust_flags; + return priv->flags & FWUPD_RELEASE_TRUST_FLAGS_MASK; } /** @@ -653,7 +883,133 @@ { FwupdReleasePrivate *priv = GET_PRIVATE (release); g_return_if_fail (FWUPD_IS_RELEASE (release)); - priv->trust_flags = trust_flags; + + /* only overwrite the last two bits of the flags */ + priv->flags &= ~FWUPD_RELEASE_TRUST_FLAGS_MASK; + priv->flags |= trust_flags; +} + +/** + * fwupd_release_get_flags: + * @release: A #FwupdRelease + * + * Gets the release flags. + * + * Returns: the release flags, or 0 if unset + * + * Since: 1.2.6 + **/ +FwupdReleaseFlags +fwupd_release_get_flags (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), 0); + return priv->flags; +} + +/** + * fwupd_release_set_flags: + * @release: A #FwupdRelease + * @flags: the release flags, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD + * + * Sets the release flags. + * + * Since: 1.2.6 + **/ +void +fwupd_release_set_flags (FwupdRelease *release, FwupdReleaseFlags flags) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + priv->flags = flags; +} + +/** + * fwupd_release_add_flag: + * @release: A #FwupdRelease + * @flag: the #FwupdReleaseFlags + * + * Adds a specific release flag to the release. + * + * Since: 1.2.6 + **/ +void +fwupd_release_add_flag (FwupdRelease *release, FwupdReleaseFlags flag) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + priv->flags |= flag; +} + +/** + * fwupd_release_remove_flag: + * @release: A #FwupdRelease + * @flag: the #FwupdReleaseFlags + * + * Removes a specific release flag from the release. + * + * Since: 1.2.6 + **/ +void +fwupd_release_remove_flag (FwupdRelease *release, FwupdReleaseFlags flag) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + priv->flags &= ~flag; +} + +/** + * fwupd_release_has_flag: + * @release: A #FwupdRelease + * @flag: the #FwupdReleaseFlags + * + * Finds if the release has a specific release flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 1.2.6 + **/ +gboolean +fwupd_release_has_flag (FwupdRelease *release, FwupdReleaseFlags flag) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), FALSE); + return (priv->flags & flag) > 0; +} + +/** + * fwupd_release_get_install_duration: + * @release: A #FwupdRelease + * + * Gets the time estimate for firmware installation (in seconds) + * + * Returns: the estimated time to flash this release (or 0 if unset) + * + * Since: 1.2.1 + **/ +guint32 +fwupd_release_get_install_duration (FwupdRelease *release) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_val_if_fail (FWUPD_IS_RELEASE (release), 0); + return priv->install_duration; +} + +/** + * fwupd_release_set_install_duration: + * @release: A #FwupdRelease + * @duration: The amount of time + * + * Sets the time estimate for firmware installation (in seconds) + * + * Since: 1.2.1 + **/ +void +fwupd_release_set_install_duration (FwupdRelease *release, guint32 duration) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_return_if_fail (FWUPD_IS_RELEASE (release)); + priv->install_duration = duration; } static GVariant * @@ -702,7 +1058,7 @@ g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL); /* create an array with all the metadata in */ - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); if (priv->remote_id != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_REMOTE_ID, @@ -718,6 +1074,11 @@ FWUPD_RESULT_KEY_FILENAME, g_variant_new_string (priv->filename)); } + if (priv->protocol != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_PROTOCOL, + g_variant_new_string (priv->protocol)); + } if (priv->license != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_LICENSE, @@ -743,6 +1104,14 @@ FWUPD_RESULT_KEY_DESCRIPTION, g_variant_new_string (priv->description)); } + if (priv->categories->len > 0) { + g_autofree const gchar **strv = g_new0 (const gchar *, priv->categories->len + 1); + for (guint i = 0; i < priv->categories->len; i++) + strv[i] = (const gchar *) g_ptr_array_index (priv->categories, i); + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_CATEGORIES, + g_variant_new_strv (strv, -1)); + } if (priv->checksums->len > 0) { g_autoptr(GString) str = g_string_new (""); for (guint i = 0; i < priv->checksums->len; i++) { @@ -765,6 +1134,16 @@ FWUPD_RESULT_KEY_HOMEPAGE, g_variant_new_string (priv->homepage)); } + if (priv->details_url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_DETAILS_URL, + g_variant_new_string (priv->details_url)); + } + if (priv->source_url != NULL) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_SOURCE_URL, + g_variant_new_string (priv->source_url)); + } if (priv->version != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_VERSION, @@ -775,16 +1154,21 @@ FWUPD_RESULT_KEY_VENDOR, g_variant_new_string (priv->vendor)); } - if (priv->trust_flags != 0) { + if (priv->flags != 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_TRUST_FLAGS, - g_variant_new_uint64 (priv->trust_flags)); + g_variant_new_uint64 (priv->flags)); } if (g_hash_table_size (priv->metadata) > 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_METADATA, _hash_kv_to_variant (priv->metadata)); } + if (priv->install_duration > 0) { + g_variant_builder_add (&builder, "{sv}", + FWUPD_RESULT_KEY_INSTALL_DURATION, + g_variant_new_uint32 (priv->install_duration)); + } return g_variant_new ("a{sv}", &builder); } @@ -804,6 +1188,10 @@ fwupd_release_set_filename (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_PROTOCOL) == 0) { + fwupd_release_set_protocol (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_LICENSE) == 0) { fwupd_release_set_license (release, g_variant_get_string (value, NULL)); return; @@ -824,6 +1212,12 @@ fwupd_release_set_description (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_CATEGORIES) == 0) { + g_autofree const gchar **strv = g_variant_get_strv (value, NULL); + for (guint i = 0; strv[i] != NULL; i++) + fwupd_release_add_category (release, strv[i]); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_CHECKSUM) == 0) { const gchar *checksums = g_variant_get_string (value, NULL); g_auto(GStrv) split = g_strsplit (checksums, ",", -1); @@ -839,6 +1233,14 @@ fwupd_release_set_homepage (release, g_variant_get_string (value, NULL)); return; } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_DETAILS_URL) == 0) { + fwupd_release_set_details_url (release, g_variant_get_string (value, NULL)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_SOURCE_URL) == 0) { + fwupd_release_set_source_url (release, g_variant_get_string (value, NULL)); + return; + } if (g_strcmp0 (key, FWUPD_RESULT_KEY_VERSION) == 0) { fwupd_release_set_version (release, g_variant_get_string (value, NULL)); return; @@ -848,7 +1250,15 @@ return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_TRUST_FLAGS) == 0) { - fwupd_release_set_trust_flags (release, g_variant_get_uint64 (value)); + fwupd_release_set_flags (release, g_variant_get_uint64 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) { + fwupd_release_set_install_duration (release, g_variant_get_uint32 (value)); + return; + } + if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { + fwupd_release_set_update_message (release, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_METADATA) == 0) { @@ -883,23 +1293,127 @@ } static void -fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdTrustFlags trust_flags) +fwupd_pad_kv_tfl (GString *str, const gchar *key, FwupdReleaseFlags release_flags) { g_autoptr(GString) tmp = g_string_new (""); - for (guint i = 1; i < FWUPD_TRUST_FLAG_LAST; i *= 2) { - if ((trust_flags & i) == 0) + for (guint i = 0; i < 64; i++) { + if ((release_flags & ((guint64) 1 << i)) == 0) continue; g_string_append_printf (tmp, "%s|", - fwupd_trust_flag_to_string (i)); + fwupd_release_flag_to_string ((guint64) 1 << i)); } if (tmp->len == 0) { - g_string_append (tmp, fwupd_trust_flag_to_string (0)); + g_string_append (tmp, fwupd_release_flag_to_string (0)); } else { g_string_truncate (tmp, tmp->len - 1); } fwupd_pad_kv_str (str, key, tmp->str); } +static void +fwupd_pad_kv_int (GString *str, const gchar *key, guint32 value) +{ + g_autofree gchar *tmp = NULL; + + /* ignore */ + if (value == 0) + return; + tmp = g_strdup_printf("%" G_GUINT32_FORMAT, value); + fwupd_pad_kv_str (str, key, tmp); +} + +static void +fwupd_release_json_add_string (JsonBuilder *builder, const gchar *key, const gchar *str) +{ + if (str == NULL) + return; + json_builder_set_member_name (builder, key); + json_builder_add_string_value (builder, str); +} + +static void +fwupd_release_json_add_int (JsonBuilder *builder, const gchar *key, guint64 num) +{ + if (num == 0) + return; + json_builder_set_member_name (builder, key); + json_builder_add_int_value (builder, num); +} + +/** + * fwupd_release_to_json: + * @release: A #FwupdRelease + * @builder: A #JsonBuilder + * + * Adds a fwupd release to a JSON builder + * + * Since: 1.2.6 + **/ +void +fwupd_release_to_json (FwupdRelease *release, JsonBuilder *builder) +{ + FwupdReleasePrivate *priv = GET_PRIVATE (release); + g_autoptr(GList) keys = NULL; + + g_return_if_fail (FWUPD_IS_RELEASE (release)); + g_return_if_fail (builder != NULL); + + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_VERSION, priv->version); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_FILENAME, priv->filename); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); + if (priv->categories->len > 0) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_CATEGORIES); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->categories->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->categories, i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } + if (priv->checksums->len > 0) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_CHECKSUM); + json_builder_begin_array (builder); + for (guint i = 0; i < priv->checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (priv->checksums, i); + json_builder_add_string_value (builder, checksum); + } + json_builder_end_array (builder); + } + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_LICENSE, priv->license); + fwupd_release_json_add_int (builder, FWUPD_RESULT_KEY_SIZE, priv->size); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_URI, priv->uri); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_VENDOR, priv->vendor); + if (priv->flags != FWUPD_RELEASE_FLAG_NONE) { + json_builder_set_member_name (builder, FWUPD_RESULT_KEY_FLAGS); + json_builder_begin_array (builder); + for (guint i = 0; i < 64; i++) { + const gchar *tmp; + if ((priv->flags & ((guint64) 1 << i)) == 0) + continue; + tmp = fwupd_release_flag_to_string ((guint64) 1 << i); + json_builder_add_string_value (builder, tmp); + } + json_builder_end_array (builder); + } + fwupd_release_json_add_int (builder, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); + fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); + + /* metadata */ + keys = g_hash_table_get_keys (priv->metadata); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *key = l->data; + const gchar *value = g_hash_table_lookup (priv->metadata, key); + fwupd_release_json_add_string (builder, key, value); + } +} + /** * fwupd_release_to_string: * @release: A #FwupdRelease @@ -926,6 +1440,11 @@ fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_FILENAME, priv->filename); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol); + for (guint i = 0; i < priv->categories->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->categories, i); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_CATEGORIES, tmp); + } for (guint i = 0; i < priv->checksums->len; i++) { const gchar *checksum = g_ptr_array_index (priv->checksums, i); g_autofree gchar *checksum_display = fwupd_checksum_format_for_display (checksum); @@ -935,9 +1454,13 @@ fwupd_pad_kv_siz (str, FWUPD_RESULT_KEY_SIZE, priv->size); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_URI, priv->uri); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url); + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VENDOR, priv->vendor); - fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_TRUST_FLAGS, priv->trust_flags); - + fwupd_pad_kv_tfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags); + fwupd_pad_kv_int (str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration); + if (priv->update_message != NULL) + fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message); /* metadata */ keys = g_hash_table_get_keys (priv->metadata); for (GList *l = keys; l != NULL; l = l->next) { @@ -960,6 +1483,7 @@ fwupd_release_init (FwupdRelease *release) { FwupdReleasePrivate *priv = GET_PRIVATE (release); + priv->categories = g_ptr_array_new_with_free_func (g_free); priv->checksums = g_ptr_array_new_with_free_func (g_free); priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } @@ -972,15 +1496,20 @@ g_free (priv->description); g_free (priv->filename); + g_free (priv->protocol); g_free (priv->appstream_id); g_free (priv->license); g_free (priv->name); g_free (priv->summary); g_free (priv->uri); g_free (priv->homepage); + g_free (priv->details_url); + g_free (priv->source_url); g_free (priv->vendor); g_free (priv->version); g_free (priv->remote_id); + g_free (priv->update_message); + g_ptr_array_unref (priv->categories); g_ptr_array_unref (priv->checksums); g_hash_table_unref (priv->metadata); @@ -1000,30 +1529,30 @@ /** * fwupd_release_from_variant: - * @data: a #GVariant + * @value: a #GVariant * * Creates a new release using packed data. * - * Returns: (transfer full): a new #FwupdRelease, or %NULL if @data was invalid + * Returns: (transfer full): a new #FwupdRelease, or %NULL if @value was invalid * * Since: 1.0.0 **/ FwupdRelease * -fwupd_release_from_variant (GVariant *data) +fwupd_release_from_variant (GVariant *value) { FwupdRelease *rel = NULL; const gchar *type_string; g_autoptr(GVariantIter) iter = NULL; /* format from GetDetails */ - type_string = g_variant_get_type_string (data); + type_string = g_variant_get_type_string (value); if (g_strcmp0 (type_string, "(a{sv})") == 0) { rel = fwupd_release_new (); - g_variant_get (data, "(a{sv})", &iter); + g_variant_get (value, "(a{sv})", &iter); fwupd_release_set_from_variant_iter (rel, iter); } else if (g_strcmp0 (type_string, "a{sv}") == 0) { rel = fwupd_release_new (); - g_variant_get (data, "a{sv}", &iter); + g_variant_get (value, "a{sv}", &iter); fwupd_release_set_from_variant_iter (rel, iter); } else { g_warning ("type %s not known", type_string); @@ -1032,6 +1561,38 @@ } /** + * fwupd_release_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new releases using packed data. + * + * Returns: (transfer container) (element-type FwupdRelease): releases, or %NULL if @value was invalid + * + * Since: 1.2.10 + **/ +GPtrArray * +fwupd_release_array_from_variant (GVariant *value) +{ + GPtrArray *array = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + FwupdRelease *rel; + g_autoptr(GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + rel = fwupd_release_from_variant (data); + if (rel == NULL) + continue; + g_ptr_array_add (array, rel); + } + return array; +} + +/** * fwupd_release_new: * * Creates a new release. diff -Nru fwupd-1.0.6/libfwupd/fwupd-release.h fwupd-1.2.10/libfwupd/fwupd-release.h --- fwupd-1.0.6/libfwupd/fwupd-release.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-release.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2015-2018 Richard Hughes * - * Copyright (C) 2015-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_RELEASE_H -#define __FWUPD_RELEASE_H +#pragma once #include @@ -53,9 +37,16 @@ const gchar *fwupd_release_get_uri (FwupdRelease *release); void fwupd_release_set_uri (FwupdRelease *release, const gchar *uri); +GPtrArray *fwupd_release_get_categories (FwupdRelease *release); +void fwupd_release_add_category (FwupdRelease *release, + const gchar *category); +gboolean fwupd_release_has_category (FwupdRelease *release, + const gchar *category); GPtrArray *fwupd_release_get_checksums (FwupdRelease *release); void fwupd_release_add_checksum (FwupdRelease *release, const gchar *checksum); +gboolean fwupd_release_has_checksum (FwupdRelease *release, + const gchar *checksum); GHashTable *fwupd_release_get_metadata (FwupdRelease *release); void fwupd_release_add_metadata (FwupdRelease *release, @@ -69,6 +60,9 @@ const gchar *fwupd_release_get_filename (FwupdRelease *release); void fwupd_release_set_filename (FwupdRelease *release, const gchar *filename); +const gchar *fwupd_release_get_protocol (FwupdRelease *release); +void fwupd_release_set_protocol (FwupdRelease *release, + const gchar *protocol); const gchar *fwupd_release_get_appstream_id (FwupdRelease *release); void fwupd_release_set_appstream_id (FwupdRelease *release, const gchar *appstream_id); @@ -90,17 +84,40 @@ const gchar *fwupd_release_get_homepage (FwupdRelease *release); void fwupd_release_set_homepage (FwupdRelease *release, const gchar *homepage); +const gchar *fwupd_release_get_details_url (FwupdRelease *release); +void fwupd_release_set_details_url (FwupdRelease *release, + const gchar *details_url); +const gchar *fwupd_release_get_source_url (FwupdRelease *release); +void fwupd_release_set_source_url (FwupdRelease *release, + const gchar *source_url); guint64 fwupd_release_get_size (FwupdRelease *release); void fwupd_release_set_size (FwupdRelease *release, guint64 size); const gchar *fwupd_release_get_license (FwupdRelease *release); void fwupd_release_set_license (FwupdRelease *release, const gchar *license); -FwupdTrustFlags fwupd_release_get_trust_flags (FwupdRelease *release); +FwupdTrustFlags fwupd_release_get_trust_flags (FwupdRelease *release) +G_DEPRECATED_FOR(fwupd_release_get_flags); void fwupd_release_set_trust_flags (FwupdRelease *release, - FwupdTrustFlags trust_flags); - -G_END_DECLS + FwupdTrustFlags trust_flags) +G_DEPRECATED_FOR(fwupd_release_set_flags); +FwupdReleaseFlags fwupd_release_get_flags (FwupdRelease *release); +void fwupd_release_set_flags (FwupdRelease *release, + FwupdReleaseFlags flags); +void fwupd_release_add_flag (FwupdRelease *release, + FwupdReleaseFlags flag); +void fwupd_release_remove_flag (FwupdRelease *release, + FwupdReleaseFlags flag); +gboolean fwupd_release_has_flag (FwupdRelease *release, + FwupdReleaseFlags flag); +guint32 fwupd_release_get_install_duration (FwupdRelease *release); +void fwupd_release_set_install_duration (FwupdRelease *release, + guint32 duration); +const gchar *fwupd_release_get_update_message (FwupdRelease *release); +void fwupd_release_set_update_message (FwupdRelease *release, + const gchar *update_message); -#endif /* __FWUPD_RELEASE_H */ +FwupdRelease *fwupd_release_from_variant (GVariant *value); +GPtrArray *fwupd_release_array_from_variant (GVariant *value); +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-release-private.h fwupd-1.2.10/libfwupd/fwupd-release-private.h --- fwupd-1.0.6/libfwupd/fwupd-release-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-release-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,37 +1,21 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_RELEASE_PRIVATE_H -#define __FWUPD_RELEASE_PRIVATE_H +#pragma once #include +#include #include "fwupd-release.h" G_BEGIN_DECLS -FwupdRelease *fwupd_release_from_variant (GVariant *data); GVariant *fwupd_release_to_variant (FwupdRelease *release); +void fwupd_release_to_json (FwupdRelease *release, + JsonBuilder *builder); G_END_DECLS -#endif /* __FWUPD_RELEASE_PRIVATE_H */ - diff -Nru fwupd-1.0.6/libfwupd/fwupd-remote.c fwupd-1.2.10/libfwupd/fwupd-remote.c --- fwupd-1.0.6/libfwupd/fwupd-remote.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-remote.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -51,11 +36,13 @@ gchar *username; gchar *password; gchar *title; + gchar *agreement; gchar *checksum; gchar *filename_cache; gchar *filename_cache_sig; gchar *filename_source; gboolean enabled; + gboolean approval_required; gint priority; guint64 mtime; gchar **order_after; @@ -66,6 +53,7 @@ PROP_0, PROP_ID, PROP_ENABLED, + PROP_APPROVAL_REQUIRED, PROP_LAST }; @@ -89,6 +77,23 @@ priv->title = g_strdup (title); } +/** + * fwupd_remote_set_agreement: + * @self: A #FwupdRemote + * @agreement: Agreement markup + * + * Sets the remote agreement in AppStream markup format + * + * Since: 1.0.7 + **/ +void +fwupd_remote_set_agreement (FwupdRemote *self, const gchar *agreement) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_free (priv->agreement); + priv->agreement = g_strdup (agreement); +} + static void fwupd_remote_set_checksum (FwupdRemote *self, const gchar *checksum) { @@ -272,6 +277,8 @@ return FWUPD_REMOTE_KIND_DOWNLOAD; if (g_strcmp0 (kind, "local") == 0) return FWUPD_REMOTE_KIND_LOCAL; + if (g_strcmp0 (kind, "directory") == 0) + return FWUPD_REMOTE_KIND_DIRECTORY; return FWUPD_REMOTE_KIND_UNKNOWN; } @@ -292,6 +299,8 @@ return "download"; if (kind == FWUPD_REMOTE_KIND_LOCAL) return "local"; + if (kind == FWUPD_REMOTE_KIND_DIRECTORY) + return "directory"; return NULL; } @@ -381,7 +390,14 @@ if (metadata_uri == NULL) return FALSE; if (g_str_has_prefix (metadata_uri, "file://")) { - priv->kind = FWUPD_REMOTE_KIND_LOCAL; + const gchar *filename_cache = metadata_uri; + if (g_str_has_prefix (filename_cache, "file://")) + filename_cache += 7; + fwupd_remote_set_filename_cache (self, filename_cache); + if (g_file_test (filename_cache, G_FILE_TEST_IS_DIR)) + priv->kind = FWUPD_REMOTE_KIND_DIRECTORY; + else + priv->kind = FWUPD_REMOTE_KIND_LOCAL; } else if (g_str_has_prefix (metadata_uri, "http://") || g_str_has_prefix (metadata_uri, "https://")) { priv->kind = FWUPD_REMOTE_KIND_DOWNLOAD; @@ -396,6 +412,7 @@ /* extract data */ priv->enabled = g_key_file_get_boolean (kf, group, "Enabled", NULL); + priv->approval_required = g_key_file_get_boolean (kf, group, "ApprovalRequired", NULL); priv->title = g_key_file_get_string (kf, group, "Title", NULL); /* reporting is optional */ @@ -441,14 +458,6 @@ fwupd_remote_set_filename_cache (self, filename_cache); } - /* all LOCAL remotes have to include a valid MetadataURI */ - if (priv->kind == FWUPD_REMOTE_KIND_LOCAL) { - const gchar *filename_cache = metadata_uri; - if (g_str_has_prefix (filename_cache, "file://")) - filename_cache += 7; - fwupd_remote_set_filename_cache (self, filename_cache); - } - /* load the checksum */ if (priv->filename_cache_sig != NULL && g_file_test (priv->filename_cache_sig, G_FILE_TEST_EXISTS)) { @@ -470,6 +479,25 @@ if (firmware_base_uri != NULL) fwupd_remote_set_firmware_base_uri (self, firmware_base_uri); + /* some validation around DIRECTORY types */ + if (priv->kind == FWUPD_REMOTE_KIND_DIRECTORY) { + if (priv->keyring_kind != FWUPD_KEYRING_KIND_NONE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Keyring kind %s is not supported with directory remote", + fwupd_keyring_kind_to_string (priv->keyring_kind)); + return FALSE; + } + if (firmware_base_uri != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Directory remotes don't support firmware base URI"); + return FALSE; + } + } + /* dep logic */ order_before = g_key_file_get_string (kf, group, "OrderBefore", NULL); if (order_before != NULL) @@ -738,6 +766,24 @@ } /** + * fwupd_remote_get_agreement: + * @self: A #FwupdRemote + * + * Gets the remote agreement in AppStream markup format + * + * Returns: a string, or %NULL if unset + * + * Since: 1.0.7 + **/ +const gchar * +fwupd_remote_get_agreement (FwupdRemote *self) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return priv->agreement; +} + +/** * fwupd_remote_get_checksum: * @self: A #FwupdRemote * @@ -868,6 +914,25 @@ } /** + * fwupd_remote_get_approval_required: + * @self: A #FwupdRemote + * + * Gets if firmware from the remote should be checked against the list + * of a approved checksums. + * + * Returns: a #TRUE if the remote is restricted + * + * Since: 1.2.6 + **/ +gboolean +fwupd_remote_get_approval_required (FwupdRemote *self) +{ + FwupdRemotePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FWUPD_IS_REMOTE (self), FALSE); + return priv->approval_required; +} + +/** * fwupd_remote_get_id: * @self: A #FwupdRemote * @@ -920,10 +985,14 @@ fwupd_remote_set_password (self, g_variant_get_string (value, NULL)); } else if (g_strcmp0 (key, "Title") == 0) { fwupd_remote_set_title (self, g_variant_get_string (value, NULL)); + } else if (g_strcmp0 (key, "Agreement") == 0) { + fwupd_remote_set_agreement (self, g_variant_get_string (value, NULL)); } else if (g_strcmp0 (key, FWUPD_RESULT_KEY_CHECKSUM) == 0) { fwupd_remote_set_checksum (self, g_variant_get_string (value, NULL)); } else if (g_strcmp0 (key, "Enabled") == 0) { priv->enabled = g_variant_get_boolean (value); + } else if (g_strcmp0 (key, "ApprovalRequired") == 0) { + priv->approval_required = g_variant_get_boolean (value); } else if (g_strcmp0 (key, "Priority") == 0) { priv->priority = g_variant_get_int32 (value); } else if (g_strcmp0 (key, "ModificationTime") == 0) { @@ -953,7 +1022,7 @@ g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); /* create an array with all the metadata in */ - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); if (priv->id != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_REMOTE_ID, g_variant_new_string (priv->id)); @@ -970,6 +1039,10 @@ g_variant_builder_add (&builder, "{sv}", "Title", g_variant_new_string (priv->title)); } + if (priv->agreement != NULL) { + g_variant_builder_add (&builder, "{sv}", "Agreement", + g_variant_new_string (priv->agreement)); + } if (priv->checksum != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_CHECKSUM, g_variant_new_string (priv->checksum)); @@ -1012,6 +1085,8 @@ } g_variant_builder_add (&builder, "{sv}", "Enabled", g_variant_new_boolean (priv->enabled)); + g_variant_builder_add (&builder, "{sv}", "ApprovalRequired", + g_variant_new_boolean (priv->approval_required)); return g_variant_new ("a{sv}", &builder); } @@ -1026,6 +1101,9 @@ case PROP_ENABLED: g_value_set_boolean (value, priv->enabled); break; + case PROP_APPROVAL_REQUIRED: + g_value_set_boolean (value, priv->approval_required); + break; case PROP_ID: g_value_set_string (value, priv->id); break; @@ -1046,6 +1124,9 @@ case PROP_ENABLED: priv->enabled = g_value_get_boolean (value); break; + case PROP_APPROVAL_REQUIRED: + priv->approval_required = g_value_get_boolean (value); + break; case PROP_ID: fwupd_remote_set_id (self, g_value_get_string (value)); break; @@ -1072,7 +1153,7 @@ * Since: 0.9.3 */ pspec = g_param_spec_string ("id", NULL, NULL, - NULL, G_PARAM_READWRITE); + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ID, pspec); /** @@ -1083,8 +1164,20 @@ * Since: 0.9.3 */ pspec = g_param_spec_boolean ("enabled", NULL, NULL, - FALSE, G_PARAM_READWRITE); + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ENABLED, pspec); + + /** + * FwupdRemote:approval-required: + * + * If firmware from the remote should be checked against the system + * list of approved firmware. + * + * Since: 1.2.6 + */ + pspec = g_param_spec_boolean ("approval-required", NULL, NULL, + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_APPROVAL_REQUIRED, pspec); } static void @@ -1106,6 +1199,7 @@ g_free (priv->username); g_free (priv->password); g_free (priv->title); + g_free (priv->agreement); g_free (priv->checksum); g_free (priv->filename_cache); g_free (priv->filename_cache_sig); @@ -1118,30 +1212,30 @@ /** * fwupd_remote_from_variant: - * @data: a #GVariant + * @value: a #GVariant * * Creates a new remote using packed data. * - * Returns: (transfer full): a new #FwupdRemote, or %NULL if @data was invalid + * Returns: (transfer full): a new #FwupdRemote, or %NULL if @value was invalid * * Since: 1.0.0 **/ FwupdRemote * -fwupd_remote_from_variant (GVariant *data) +fwupd_remote_from_variant (GVariant *value) { FwupdRemote *rel = NULL; const gchar *type_string; g_autoptr(GVariantIter) iter = NULL; - type_string = g_variant_get_type_string (data); + type_string = g_variant_get_type_string (value); if (g_strcmp0 (type_string, "(a{sv})") == 0) { rel = fwupd_remote_new (); - g_variant_get (data, "(a{sv})", &iter); + g_variant_get (value, "(a{sv})", &iter); fwupd_remote_set_from_variant_iter (rel, iter); fwupd_remote_set_from_variant_iter (rel, iter); } else if (g_strcmp0 (type_string, "a{sv}") == 0) { rel = fwupd_remote_new (); - g_variant_get (data, "a{sv}", &iter); + g_variant_get (value, "a{sv}", &iter); fwupd_remote_set_from_variant_iter (rel, iter); } else { g_warning ("type %s not known", type_string); @@ -1150,6 +1244,35 @@ } /** + * fwupd_remote_array_from_variant: + * @value: a #GVariant + * + * Creates an array of new devices using packed data. + * + * Returns: (transfer container) (element-type FwupdRemote): remotes, or %NULL if @value was invalid + * + * Since: 1.2.10 + **/ +GPtrArray * +fwupd_remote_array_from_variant (GVariant *value) +{ + GPtrArray *remotes = NULL; + gsize sz; + g_autoptr(GVariant) untuple = NULL; + + remotes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) { + g_autoptr(GVariant) data = g_variant_get_child_value (untuple, i); + FwupdRemote *remote = fwupd_remote_from_variant (data); + g_ptr_array_add (remotes, remote); + } + + return remotes; +} + +/** * fwupd_remote_new: * * Creates a new fwupd remote. diff -Nru fwupd-1.0.6/libfwupd/fwupd-remote.h fwupd-1.2.10/libfwupd/fwupd-remote.h --- fwupd-1.0.6/libfwupd/fwupd-remote.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-remote.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_REMOTE_H -#define __FWUPD_REMOTE_H +#pragma once #include "fwupd-enums.h" @@ -42,10 +26,20 @@ void (*_fwupd_reserved7) (void); }; +/** + * FwupdRemoteKind: + * @FWUPD_REMOTE_KIND_UNKNOWN: Unknown kind + * @FWUPD_REMOTE_KIND_DOWNLOAD: Requires files to be downloaded + * @FWUPD_REMOTE_KIND_LOCAL: Reads files from the local machine + * @FWUPD_REMOTE_KIND_DIRECTORY: Reads directory from the local machine + * + * The kind of remote. + **/ typedef enum { FWUPD_REMOTE_KIND_UNKNOWN, FWUPD_REMOTE_KIND_DOWNLOAD, FWUPD_REMOTE_KIND_LOCAL, + FWUPD_REMOTE_KIND_DIRECTORY, /* Since: 1.2.4 */ /*< private >*/ FWUPD_REMOTE_KIND_LAST } FwupdRemoteKind; @@ -56,6 +50,7 @@ FwupdRemote *fwupd_remote_new (void); const gchar *fwupd_remote_get_id (FwupdRemote *self); const gchar *fwupd_remote_get_title (FwupdRemote *self); +const gchar *fwupd_remote_get_agreement (FwupdRemote *self); const gchar *fwupd_remote_get_checksum (FwupdRemote *self); const gchar *fwupd_remote_get_username (FwupdRemote *self); const gchar *fwupd_remote_get_password (FwupdRemote *self); @@ -67,6 +62,7 @@ const gchar *fwupd_remote_get_metadata_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri_sig (FwupdRemote *self); gboolean fwupd_remote_get_enabled (FwupdRemote *self); +gboolean fwupd_remote_get_approval_required (FwupdRemote *self); gint fwupd_remote_get_priority (FwupdRemote *self); guint64 fwupd_remote_get_age (FwupdRemote *self); FwupdRemoteKind fwupd_remote_get_kind (FwupdRemote *self); @@ -75,7 +71,7 @@ const gchar *url, GError **error); -G_END_DECLS - -#endif /* __FWUPD_REMOTE_H */ +FwupdRemote *fwupd_remote_from_variant (GVariant *value); +GPtrArray *fwupd_remote_array_from_variant (GVariant *value); +G_END_DECLS diff -Nru fwupd-1.0.6/libfwupd/fwupd-remote-private.h fwupd-1.2.10/libfwupd/fwupd-remote-private.h --- fwupd-1.0.6/libfwupd/fwupd-remote-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-remote-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,32 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FWUPD_REMOTE_PRIVATE_H -#define __FWUPD_REMOTE_PRIVATE_H +#pragma once #include "fwupd-remote.h" G_BEGIN_DECLS -FwupdRemote *fwupd_remote_from_variant (GVariant *data); GVariant *fwupd_remote_to_variant (FwupdRemote *self); gboolean fwupd_remote_load_from_filename (FwupdRemote *self, const gchar *filename, @@ -34,12 +17,11 @@ GError **error); void fwupd_remote_set_priority (FwupdRemote *self, gint priority); +void fwupd_remote_set_agreement (FwupdRemote *self, + const gchar *agreement); void fwupd_remote_set_mtime (FwupdRemote *self, guint64 mtime); gchar **fwupd_remote_get_order_after (FwupdRemote *self); gchar **fwupd_remote_get_order_before (FwupdRemote *self); G_END_DECLS - -#endif /* __FWUPD_REMOTE_PRIVATE_H */ - diff -Nru fwupd-1.0.6/libfwupd/fwupd-self-test.c fwupd-1.2.10/libfwupd/fwupd-self-test.c --- fwupd-1.0.6/libfwupd/fwupd-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,34 +1,19 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include -#include #include "fwupd-client.h" #include "fwupd-common.h" #include "fwupd-enums.h" #include "fwupd-error.h" +#include "fwupd-device-private.h" #include "fwupd-release-private.h" #include "fwupd-remote-private.h" @@ -59,6 +44,60 @@ return FALSE; } +/* https://gitlab.gnome.org/GNOME/glib/issues/225 */ +static guint +_g_string_replace (GString *string, const gchar *search, const gchar *replace) +{ + gchar *tmp; + guint count = 0; + gsize search_idx = 0; + gsize replace_len; + gsize search_len; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (search != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + /* nothing to do */ + if (string->len == 0) + return 0; + + search_len = strlen (search); + replace_len = strlen (replace); + + do { + tmp = g_strstr_len (string->str + search_idx, -1, search); + if (tmp == NULL) + break; + + /* advance the counter in case @replace contains @search */ + search_idx = (gsize) (tmp - string->str); + + /* reallocate the string if required */ + if (search_len > replace_len) { + g_string_erase (string, + (gssize) search_idx, + (gssize) (search_len - replace_len)); + memcpy (tmp, replace, replace_len); + } else if (search_len < replace_len) { + g_string_insert_len (string, + (gssize) search_idx, + replace, + (gssize) (replace_len - search_len)); + /* we have to treat this specially as it could have + * been reallocated when the insertion happened */ + memcpy (string->str + search_idx, replace, replace_len); + } else { + /* just memcmp in the new string */ + memcpy (tmp, replace, replace_len); + } + search_idx += replace_len; + count++; + } while (TRUE); + + return count; +} + static void fwupd_enums_func (void) { @@ -83,6 +122,11 @@ g_assert_cmpstr (tmp, !=, NULL); g_assert_cmpint (fwupd_trust_flag_from_string (tmp), ==, i); } + for (guint i = 1; i < FWUPD_VERSION_FORMAT_LAST; i++) { + const gchar *tmp = fwupd_version_format_to_string (i); + g_assert_cmpstr (tmp, !=, NULL); + g_assert_cmpint (fwupd_version_format_from_string (tmp), ==, i); + } /* bitfield */ for (guint64 i = 1; i < FWUPD_DEVICE_FLAG_UNKNOWN; i *= 2) { @@ -187,7 +231,7 @@ g_autoptr(GError) error = NULL; remote = fwupd_remote_new (); - fn = g_build_filename (FU_SELF_TEST_REMOTES_DIR, "remotes.d", "fwupd.conf", NULL); + fn = g_build_filename (FU_LOCAL_REMOTE_DIR, "dell-esrt.conf", NULL); ret = fwupd_remote_load_from_filename (remote, fn, NULL, &error); g_assert_no_error (error); g_assert (ret); @@ -197,8 +241,8 @@ g_assert (fwupd_remote_get_metadata_uri (remote) == NULL); g_assert (fwupd_remote_get_metadata_uri_sig (remote) == NULL); g_assert (fwupd_remote_get_report_uri (remote) == NULL); - g_assert_cmpstr (fwupd_remote_get_title (remote), ==, "Core"); - g_assert_cmpstr (fwupd_remote_get_filename_cache (remote), ==, "@datadir@/fwupd/remotes.d/fwupd/metadata.xml"); + g_assert_cmpstr (fwupd_remote_get_title (remote), ==, "Enable UEFI capsule updates on Dell systems"); + g_assert_cmpstr (fwupd_remote_get_filename_cache (remote), ==, "@datadir@/fwupd/remotes.d/dell-esrt/metadata.xml"); g_assert_cmpstr (fwupd_remote_get_filename_cache_sig (remote), ==, NULL); g_assert_cmpstr (fwupd_remote_get_checksum (remote), ==, NULL); } @@ -223,10 +267,15 @@ fwupd_device_func (void) { gboolean ret; + g_autofree gchar *data = NULL; g_autofree gchar *str = NULL; g_autoptr(FwupdDevice) dev = NULL; g_autoptr(FwupdRelease) rel = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GString) str_ascii = NULL; + g_autoptr(JsonBuilder) builder = NULL; + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; /* create dummy object */ dev = fwupd_device_new (); @@ -242,7 +291,7 @@ fwupd_device_add_icon (dev, "input-mouse"); fwupd_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); rel = fwupd_release_new (); - fwupd_release_set_trust_flags (rel, FWUPD_TRUST_FLAG_PAYLOAD); + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD); fwupd_release_add_checksum (rel, "deadbeef"); fwupd_release_set_description (rel, "

Hi there!

"); fwupd_release_set_filename (rel, "firmware.bin"); @@ -259,7 +308,11 @@ g_assert (fwupd_device_has_guid (dev, "00000000-0000-0000-0000-000000000000")); g_assert (!fwupd_device_has_guid (dev, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")); - ret = fu_test_compare_lines (str, + /* convert the new non-breaking space back into a normal space: + * https://gitlab.gnome.org/GNOME/glib/commit/76af5dabb4a25956a6c41a75c0c7feeee74496da */ + str_ascii = g_string_new (str); + _g_string_replace (str_ascii, " ", " "); + ret = fu_test_compare_lines (str_ascii->str, "ColorHug2\n" " DeviceId: USB:foo\n" " Guid: 2082b5e0-7a64-478a-b1b2-e3404fab6dad\n" @@ -278,7 +331,59 @@ " Checksum: SHA1(deadbeef)\n" " Size: 1.0 kB\n" " Uri: http://foo.com\n" - " TrustFlags: payload\n", &error); + " Flags: trusted-payload\n", &error); + g_assert_no_error (error); + g_assert (ret); + + /* export to json */ + builder = json_builder_new (); + json_builder_begin_object (builder); + fwupd_device_to_json (dev, builder); + json_builder_end_object (builder); + json_root = json_builder_get_root (builder); + json_generator = json_generator_new (); + json_generator_set_pretty (json_generator, TRUE); + json_generator_set_root (json_generator, json_root); + data = json_generator_to_data (json_generator, NULL); + g_assert_nonnull (data); + ret = fu_test_compare_lines (data, + "{\n" + " \"Name\" : \"ColorHug2\",\n" + " \"DeviceId\" : \"USB:foo\",\n" + " \"Guid\" : [\n" + " \"2082b5e0-7a64-478a-b1b2-e3404fab6dad\",\n" + " \"00000000-0000-0000-0000-000000000000\"\n" + " ],\n" + " \"Flags\" : [\n" + " \"updatable\",\n" + " \"require-ac\"\n" + " ],\n" + " \"Checksums\" : [\n" + " \"beefdead\"\n" + " ],\n" + " \"Icons\" : [\n" + " \"input-gaming\",\n" + " \"input-mouse\"\n" + " ],\n" + " \"Created\" : 1,\n" + " \"Modified\" : 86400,\n" + " \"Releases\" : [\n" + " {\n" + " \"AppstreamId\" : \"org.dave.ColorHug.firmware\",\n" + " \"Description\" : \"

Hi there!

\",\n" + " \"Version\" : \"1.2.3\",\n" + " \"Filename\" : \"firmware.bin\",\n" + " \"Checksum\" : [\n" + " \"deadbeef\"\n" + " ],\n" + " \"Size\" : 1024,\n" + " \"Uri\" : \"http://foo.com\",\n" + " \"Flags\" : [\n" + " \"trusted-payload\"\n" + " ]\n" + " }\n" + " ]\n" + "}", &error); g_assert_no_error (error); g_assert (ret); } @@ -302,7 +407,7 @@ g_test_skip ("no enabled fwupd daemon"); return; } - if (as_utils_vercmp (fwupd_client_get_daemon_version (client), "1.0.0") < 0) { + if (!g_str_has_prefix (fwupd_client_get_daemon_version (client), "1.")) { g_test_skip ("running fwupd is too old"); return; } @@ -351,7 +456,7 @@ g_test_skip ("no enabled fwupd daemon"); return; } - if (as_utils_vercmp (fwupd_client_get_daemon_version (client), "1.0.0") < 0) { + if (!g_str_has_prefix (fwupd_client_get_daemon_version (client), "1.")) { g_test_skip ("running fwupd is too old"); return; } @@ -417,6 +522,58 @@ g_assert_cmpstr (mhash2, !=, mhash1); } +static void +fwupd_common_guid_func (void) +{ + g_autofree gchar *guid1 = NULL; + g_autofree gchar *guid2 = NULL; + g_autofree gchar *guid_be = NULL; + g_autofree gchar *guid_me = NULL; + fwupd_guid_t buf = { 0x0 }; + gboolean ret; + g_autoptr(GError) error = NULL; + + /* invalid */ + g_assert (!fwupd_guid_is_valid (NULL)); + g_assert (!fwupd_guid_is_valid ("")); + g_assert (!fwupd_guid_is_valid ("1ff60ab2-3905-06a1-b476")); + g_assert (!fwupd_guid_is_valid ("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b")); + g_assert (!fwupd_guid_is_valid (" 1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + g_assert (!fwupd_guid_is_valid ("00000000-0000-0000-0000-000000000000")); + + /* valid */ + g_assert (fwupd_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + + /* make valid */ + guid1 = fwupd_guid_hash_string ("python.org"); + g_assert_cmpstr (guid1, ==, "886313e1-3b8a-5372-9b90-0c9aee199e5d"); + + guid2 = fwupd_guid_hash_string ("8086:0406"); + g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486"); + + /* round-trip BE */ + ret = fwupd_guid_from_string ("00112233-4455-6677-8899-aabbccddeeff", &buf, + FWUPD_GUID_FLAG_NONE, &error); + g_assert_true (ret); + g_assert_no_error (error); + g_assert (memcmp (buf, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", sizeof(buf)) == 0); + guid_be = fwupd_guid_to_string ((const fwupd_guid_t *) &buf, FWUPD_GUID_FLAG_NONE); + g_assert_cmpstr (guid_be, ==, "00112233-4455-6677-8899-aabbccddeeff"); + + /* round-trip mixed encoding */ + ret = fwupd_guid_from_string ("00112233-4455-6677-8899-aabbccddeeff", &buf, + FWUPD_GUID_FLAG_MIXED_ENDIAN, &error); + g_assert_true (ret); + g_assert_no_error (error); + g_assert (memcmp (buf, "\x33\x22\x11\x00\x55\x44\x77\x66\x88\x99\xaa\xbb\xcc\xdd\xee\xff", sizeof(buf)) == 0); + guid_me = fwupd_guid_to_string ((const fwupd_guid_t *) &buf, FWUPD_GUID_FLAG_MIXED_ENDIAN); + g_assert_cmpstr (guid_me, ==, "00112233-4455-6677-8899-aabbccddeeff"); + + /* check failure */ + g_assert_false (fwupd_guid_from_string ("001122334455-6677-8899-aabbccddeeff", NULL, 0, NULL)); + g_assert_false (fwupd_guid_from_string ("0112233-4455-6677-8899-aabbccddeeff", NULL, 0, NULL)); +} + int main (int argc, char **argv) { @@ -429,6 +586,7 @@ /* tests go here */ g_test_add_func ("/fwupd/enums", fwupd_enums_func); g_test_add_func ("/fwupd/common{machine-hash}", fwupd_common_machine_hash_func); + g_test_add_func ("/fwupd/common{guid}", fwupd_common_guid_func); g_test_add_func ("/fwupd/release", fwupd_release_func); g_test_add_func ("/fwupd/device", fwupd_device_func); g_test_add_func ("/fwupd/remote{download}", fwupd_remote_download_func); diff -Nru fwupd-1.0.6/libfwupd/fwupd-version.h.in fwupd-1.2.10/libfwupd/fwupd-version.h.in --- fwupd-1.0.6/libfwupd/fwupd-version.h.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/fwupd-version.h.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + /** * SECTION:fwupd-version * @short_description: Obtains the version for the installed fwupd @@ -31,9 +18,6 @@ #error "Only can be included directly." #endif -#ifndef __FWUPD_VERSION_H -#define __FWUPD_VERSION_H - /** * FWUPD_MAJOR_VERSION: * @@ -75,5 +59,3 @@ (FWUPD_MAJOR_VERSION == (major) && FWUPD_MINOR_VERSION > (minor)) || \ (FWUPD_MAJOR_VERSION == (major) && FWUPD_MINOR_VERSION == (minor) && \ FWUPD_MICRO_VERSION >= (micro))) - -#endif /* __FWUPD_VERSION_H */ diff -Nru fwupd-1.0.6/libfwupd/generate-version-script.py fwupd-1.2.10/libfwupd/generate-version-script.py --- fwupd-1.0.6/libfwupd/generate-version-script.py 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/generate-version-script.py 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,15 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 # pylint: disable=invalid-name,missing-docstring # # Copyright (C) 2017 Richard Hughes # -# Licensed under the GNU General Public License Version 2 -# -# 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 2 of the License, 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, see . +# SPDX-License-Identifier: LGPL-2.1+ import sys import xml.etree.ElementTree as ET +from pkg_resources import parse_version + XMLNS = '{http://www.gtk.org/introspection/core/1.0}' XMLNS_C = '{http://www.gtk.org/introspection/c/1.0}' @@ -45,7 +34,6 @@ if 'version' not in node.attrib: print('No version for', identifier) sys.exit(1) - return version = node.attrib['version'] if version not in self.releases: self.releases[version] = [] @@ -53,36 +41,43 @@ release.append(identifier) return version + def _add_cls(self, cls): + + # add all class functions + for node in cls.findall(XMLNS + 'function'): + self._add_node(node) + + # add the constructor + for node in cls.findall(XMLNS + 'constructor'): + self._add_node(node) + + # choose the lowest version method for the _get_type symbol + version_lowest = None + if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib: + return + type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] + + # add all class methods + for node in cls.findall(XMLNS + 'method'): + version_tmp = self._add_node(node) + if version_tmp: + if not version_lowest or version_tmp < version_lowest: + version_lowest = version_tmp + + # finally add the get_type symbol + if version_lowest: + self.releases[version_lowest].append(type_name) + def import_gir(self, filename): tree = ET.parse(filename) root = tree.getroot() for ns in root.findall(XMLNS + 'namespace'): for node in ns.findall(XMLNS + 'function'): self._add_node(node) + for cls in ns.findall(XMLNS + 'record'): + self._add_cls(cls) for cls in ns.findall(XMLNS + 'class'): - - # add all class functions - for node in cls.findall(XMLNS + 'function'): - self._add_node(node) - - # add the constructor - for node in cls.findall(XMLNS + 'constructor'): - self._add_node(node) - - # choose the lowest version method for the _get_type symbol - version_lowest = None - type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] - - # add all class methods - for node in cls.findall(XMLNS + 'method'): - version_tmp = self._add_node(node) - if version_tmp: - if not version_lowest or version_tmp < version_lowest: - version_lowest = version_tmp - - # finally add the get_type symbol - if version_lowest: - self.releases[version_lowest].append(type_name) + self._add_cls(cls) def render(self): @@ -94,7 +89,7 @@ # output the version data to a file verout = '# generated automatically, do not edit!\n' oldversion = None - for version in sorted(versions): + for version in sorted(versions, key=parse_version): symbols = sorted(self.releases[version]) verout += '\n%s_%s {\n' % (self.library_name, version) verout += ' global:\n' diff -Nru fwupd-1.0.6/libfwupd/meson.build fwupd-1.2.10/libfwupd/meson.build --- fwupd-1.0.6/libfwupd/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/libfwupd/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -96,7 +96,7 @@ symbol_prefix : 'fwupd', identifier_prefix : 'Fwupd', export_packages : 'fwupd', - extra_args : '--c-include=fwupd.h', # This can be replaced with header : 'fwupd.h' once can depend on Meson 0.43.0 + header : 'fwupd.h', dependencies : [ giounix, soup, @@ -122,7 +122,7 @@ # 2. The map file is required to build the lib that the GIR is built from # # To avoid the circular dep, and to ensure we don't change exported API - # accidentaly actually check in a version of the version script to git. + # accidentally actually check in a version of the version script to git. mapfile_target = custom_target('mapfile', input: gir[0], output: 'fwupd.map', @@ -145,6 +145,7 @@ if get_option('tests') testdatadir = join_paths(meson.source_root(), 'data') + localremotetestdir = join_paths(meson.source_root(), 'plugins', 'dell-esrt') e = executable( 'fwupd-self-test', sources : [ @@ -154,9 +155,9 @@ include_directories('..'), ], dependencies : [ - appstream_glib, gio, soup, + libjsonglib, ], link_with : fwupd, c_args : [ @@ -164,6 +165,7 @@ '-DLOCALSTATEDIR="' + localstatedir + '"', '-DTESTDATADIR="' + testdatadir + '"', '-DFU_SELF_TEST_REMOTES_DIR="' + testdatadir + '"', + '-DFU_LOCAL_REMOTE_DIR="' + localremotetestdir + '"', ], ) test('fwupd-self-test', e) diff -Nru fwupd-1.0.6/meson.build fwupd-1.2.10/meson.build --- fwupd-1.0.6/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,7 +1,7 @@ project('fwupd', 'c', - version : '1.0.6', + version : '1.2.10', license : 'LGPL-2.1+', - meson_version : '>=0.37.0', + meson_version : '>=0.47.0', default_options : ['warning_level=2', 'c_std=c99'], ) @@ -48,8 +48,8 @@ lt_age = '0' lt_version = '@0@.@1@.@2@'.format(lt_current, lt_age, lt_revision) -# get suported warning flags -test_args = [ +# get supported warning flags +warning_flags = [ '-fstack-protector-strong', '-Waggregate-return', '-Wunused', @@ -76,7 +76,9 @@ '-Wmissing-parameter-type', '-Wmissing-prototypes', '-Wnested-externs', - '-Wno-error=cpp', + '-Wno-cast-function-type', + '-Wno-address-of-packed-member', # incompatible with g_autoptr() + '-Wno-unknown-pragmas', '-Wno-discarded-qualifiers', '-Wno-missing-field-initializers', '-Wno-strict-aliasing', @@ -98,24 +100,22 @@ '-Wuninitialized', '-Wunused-but-set-variable', '-Wunused-variable', + '-Wvla', '-Wwrite-strings' ] cc = meson.get_compiler('c') -foreach arg: test_args - if cc.has_argument(arg) - add_project_arguments(arg, language : 'c') - endif -endforeach +add_project_arguments(cc.get_supported_arguments(warning_flags), language : 'c') # enable full RELRO where possible # FIXME: until https://github.com/mesonbuild/meson/issues/1140 is fixed global_link_args = [] test_link_args = [ '-Wl,-z,relro', + '-Wl,-z,defs', '-Wl,-z,now', ] foreach arg: test_link_args - if cc.has_argument(arg) + if cc.has_link_argument(arg) global_link_args += arg endif endforeach @@ -130,30 +130,55 @@ # do not use deprecated symbols or defines internally add_project_arguments('-DFWUPD_DISABLE_DEPRECATED', language : 'c') +# needed for symlink() and BYTE_ORDER +add_project_arguments('-D_BSD_SOURCE', language : 'c') +add_project_arguments('-D_XOPEN_SOURCE=700', language : 'c') + +prefix = get_option('prefix') + +bindir = join_paths(prefix, get_option('bindir')) +libdir = join_paths(prefix, get_option('libdir')) +datadir = join_paths(prefix, get_option('datadir')) +libexecdir = join_paths(prefix, get_option('libexecdir')) +sysconfdir = join_paths(prefix, get_option('sysconfdir')) +localstatedir = join_paths(prefix, get_option('localstatedir')) +mandir = join_paths(prefix, get_option('mandir')) +localedir = join_paths(prefix, get_option('localedir')) + gio = dependency('gio-2.0', version : '>= 2.45.8') +if gio.version().version_compare ('>= 2.55.0') + conf.set('HAVE_GIO_2_55_0', '1') +endif gmodule = dependency('gmodule-2.0') giounix = dependency('gio-unix-2.0', version : '>= 2.45.8') -polkit = dependency('polkit-gobject-1', version : '>= 0.103') -if polkit.version().version_compare('>= 0.114') - conf.set('HAVE_POLKIT_0_114', '1') -endif gudev = dependency('gudev-1.0') if gudev.version().version_compare('>= 232') conf.set('HAVE_GUDEV_232', '1') endif -appstream_glib = dependency('appstream-glib', version : '>= 0.6.13') +libxmlb = dependency('xmlb', version : '>= 0.1.7', fallback : ['libxmlb', 'libxmlb_dep']) gusb = dependency('gusb', version : '>= 0.2.9') sqlite = dependency('sqlite3') libarchive = dependency('libarchive') libjsonglib = dependency('json-glib-1.0', version : '>= 1.1.1') -if meson.version().version_compare('>0.41.0') - valgrind = dependency('valgrind', required: false) -else - valgrind = dependency('valgrindXXX', required: false) -endif +valgrind = dependency('valgrind', required: false) soup = dependency('libsoup-2.4', version : '>= 2.51.92') +if get_option('daemon') + polkit = dependency('polkit-gobject-1', version : '>= 0.103') + if polkit.version().version_compare('>= 0.114') + conf.set('HAVE_POLKIT_0_114', '1') + endif + conf.set_quoted ('POLKIT_ACTIONDIR', polkit.get_pkgconfig_variable('actiondir')) + udevdir = get_option('udevdir') + if udevdir == '' + udev = dependency('udev') + udevdir = udev.get_pkgconfig_variable('udevdir') + endif +endif if get_option('pkcs7') - gnutls = dependency('gnutls') + gnutls = dependency('gnutls', version : '>= 3.4.4.1') + if gnutls.version().version_compare('>= 3.6.0') + conf.set('HAVE_GNUTLS_3_6_0', '1') + endif conf.set('ENABLE_PKCS7', '1') endif if get_option('gpg') @@ -162,8 +187,6 @@ conf.set('ENABLE_GPG', '1') endif libm = cc.find_library('m', required: false) -udev = dependency('udev') -uuid = dependency('uuid') libgcab = dependency('libgcab-1.0') if libgcab.version().version_compare('>= 0.8') conf.set('HAVE_GCAB_0_8', '1') @@ -171,24 +194,16 @@ if libgcab.version().version_compare('>= 1.0') conf.set('HAVE_GCAB_1_0', '1') endif - -if get_option('plugin_uefi_labels') - cairo = dependency('cairo') - fontconfig = cc.find_library('fontconfig') - freetype = cc.find_library('freetype') - r = run_command('po/test-deps') - if r.returncode() != 0 - error(r.stdout()) - endif -endif +gcab = find_program('gcab', required : true) +bashcomp = dependency('bash-completion', required: false) +python3 = find_program('python3') if valgrind.found() conf.set('HAVE_VALGRIND', '1') endif -if get_option('plugin_colorhug') - colorhug = dependency('colorhug', version : '>= 1.2.12') - conf.set('HAVE_COLORHUG', '1') +if get_option('plugin_redfish') + efivar = dependency('efivar') endif if get_option('plugin_altos') @@ -196,24 +211,62 @@ endif if get_option('plugin_uefi') - fwup = dependency('fwup', version : '>= 5') - if fwup.version().version_compare('>= 11') - conf.set('HAVE_FWUP_GET_ESP_MOUNTPOINT', '1') + cairo = dependency('cairo') + fontconfig = cc.find_library('fontconfig') + freetype = cc.find_library('freetype') + efivar = dependency('efivar', version : '>= 33') + conf.set_quoted('EFIVAR_LIBRARY_VERSION', efivar.version()) + efiboot = dependency('efiboot') + objcopy = find_program ('objcopy') + readelf = find_program ('readelf') + + efi_app_location = join_paths(libexecdir, 'fwupd', 'efi') + conf.set_quoted ('EFI_APP_LOCATION', efi_app_location) + + efi_arch = host_machine.cpu_family() + if efi_arch == 'x86' + EFI_MACHINE_TYPE_NAME = 'ia32' + gnu_efi_arch = 'ia32' + elif efi_arch == 'x86_64' + EFI_MACHINE_TYPE_NAME = 'x64' + gnu_efi_arch = 'x86_64' + elif efi_arch == 'arm' + EFI_MACHINE_TYPE_NAME = 'arm' + gnu_efi_arch = 'arm' + elif efi_arch == 'aarch64' + EFI_MACHINE_TYPE_NAME = 'aa64' + gnu_efi_arch = 'aarch64' + else + EFI_MACHINE_TYPE_NAME = '' + gnu_efi_arch = '' endif - if fwup.version().version_compare('>= 10') - conf.set('HAVE_FWUP_GET_BGRT_INFO', '1') - conf.set('HAVE_FWUP_CUSTOM_ESP', '1') + conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME) + r = run_command([python3, 'po/test-deps']) + if r.returncode() != 0 + error(r.stderr()) endif - efivar = dependency('efivar') - conf.set_quoted('EFIVAR_LIBRARY_VERSION', efivar.version()) - conf.set_quoted('LIBFWUP_LIBRARY_VERSION', fwup.version()) endif if get_option('plugin_dell') - libsmbios_c = dependency('libsmbios_c', version : '>= 2.3.0') + libsmbios_c = dependency('libsmbios_c', version : '>= 2.4.0') efivar = dependency('efivar') - fwup = dependency('fwup', version : '>= 5') conf.set('HAVE_DELL', '1') + if not get_option('plugin_uefi') + error('plugin_dell also needs plugin_uefi to work') + endif +endif + +if get_option('plugin_modem_manager') + libmm_glib = dependency('mm-glib', version : '>= 1.10.0') + add_project_arguments('-DMM_REQUIRED_VERSION="1.10.0"', language : 'c') + libqmi_glib = dependency('qmi-glib', version : '>= 1.22.0') + add_project_arguments('-DQMI_REQUIRED_VERSION="1.23.1"', language : 'c') +endif + +if get_option('plugin_nvme') + if not cc.has_header('linux/nvme_ioctl.h') + error('NVMe support requires kernel >= 4.4') + endif endif if get_option('plugin_synaptics') @@ -225,36 +278,30 @@ conf.set('HAVE_THUNDERBOLT', '1') endif +if get_option('plugin_flashrom') + libflashrom = dependency('flashrom', fallback : ['flashrom', 'flashrom_dep']) +endif + if get_option('systemd') - systemd = dependency('systemd', version : '>= 231') + systemd = dependency('systemd', version : '>= 211') conf.set('HAVE_SYSTEMD' , '1') + conf.set('HAVE_LOGIND' , '1') +endif + +if get_option('elogind') + elogind = dependency('libelogind', version : '>= 211') + conf.set('HAVE_LOGIND' , '1') endif if get_option('consolekit') conf.set('HAVE_CONSOLEKIT' , '1') endif -prefix = get_option('prefix') - -bindir = join_paths(prefix, get_option('bindir')) -libdir = join_paths(prefix, get_option('libdir')) -datadir = join_paths(prefix, get_option('datadir')) -libexecdir = join_paths(prefix, get_option('libexecdir')) -sysconfdir = join_paths(prefix, get_option('sysconfdir')) -localstatedir = join_paths(prefix, get_option('localstatedir')) -mandir = join_paths(prefix, get_option('mandir')) -localedir = join_paths(prefix, get_option('localedir')) - systemdunitdir = get_option('systemdunitdir') if systemdunitdir == '' and get_option('systemd') systemdunitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir') endif -udevdir = get_option('udevdir') -if udevdir == '' - udevdir = udev.get_pkgconfig_variable('udevdir') -endif - gnome = import('gnome') i18n = import('i18n') @@ -262,6 +309,10 @@ conf.set_quoted('BINDIR', bindir) conf.set_quoted('LIBEXECDIR', libexecdir) +conf.set_quoted('DATADIR', datadir) +conf.set_quoted('LOCALSTATEDIR', localstatedir) +conf.set_quoted('SYSCONFDIR', sysconfdir) +conf.set_quoted('PLUGINDIR', plugin_dir) conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) conf.set_quoted('PACKAGE_NAME', meson.project_name()) @@ -272,48 +323,30 @@ configuration : conf ) -default_sysconfdir = get_option('sysconfdir') -if default_sysconfdir == 'etc' - message('sysconfdir of etc makes no sense, using /etc') - default_sysconfdir = '/etc' -endif - plugin_deps = [] -plugin_deps += appstream_glib +plugin_deps += libxmlb plugin_deps += gio plugin_deps += giounix plugin_deps += gmodule plugin_deps += gusb plugin_deps += soup plugin_deps += libarchive +plugin_deps += gudev subdir('data') -subdir('docs') +if get_option('gtkdoc') + gtkdocscan = find_program('gtkdoc-scan', required : true) + subdir('docs') +endif subdir('libfwupd') subdir('po') -subdir('policy') +if get_option('daemon') + subdir('policy') +endif subdir('src') subdir('plugins') subdir('contrib') -if meson.version().version_compare('<0.41.0') - if archiver.found() - run_target('dist', - # git config tar.tar.xz.command "xz -c" - command: [ - 'git', 'archive', - '--prefix=' + meson.project_name() + '-' + meson.project_version() + '/', - 'HEAD', - '--format=tar.xz', - '--output', - meson.project_name() + '-' + meson.project_version() + '.tar.xz' - ] - ) - else - message('git not found, you will not be able to run `ninja dist`') - endif -endif - -if get_option('systemd') +if get_option('systemd') and get_option('daemon') meson.add_install_script('meson_post_install.sh', systemdunitdir, localstatedir) endif diff -Nru fwupd-1.0.6/meson_options.txt fwupd-1.2.10/meson_options.txt --- fwupd-1.0.6/meson_options.txt 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/meson_options.txt 2019-07-15 18:25:54.000000000 +0000 @@ -1,5 +1,7 @@ -option('bootdir', type : 'string', value : '/boot/efi', description : 'Directory for EFI system partition') +option('daemon', type : 'boolean', value : true, description : 'enable the fwupd daemon') +option('agent', type : 'boolean', value : true, description : 'enable the fwupd agent') option('consolekit', type : 'boolean', value : true, description : 'enable ConsoleKit support') +option('firmware-packager', type : 'boolean', value : true, description : 'enable firmware-packager installation') option('gpg', type : 'boolean', value : true, description : 'enable the GPG verification support') option('gtkdoc', type : 'boolean', value : true, description : 'enable developer documentation') option('introspection', type : 'boolean', value : true, description : 'generate GObject Introspection data') @@ -8,14 +10,23 @@ option('pkcs7', type : 'boolean', value : true, description : 'enable the PKCS7 verification support') option('plugin_altos', type : 'boolean', value : true, description : 'enable altos support') option('plugin_amt', type : 'boolean', value : true, description : 'enable Intel AMT support') -option('plugin_colorhug', type : 'boolean', value : true, description : 'enable ColorHug support') option('plugin_dell', type : 'boolean', value : true, description : 'enable Dell-specific support') option('plugin_dummy', type : 'boolean', value : false, description : 'enable the dummy device') option('plugin_synaptics', type: 'boolean', value: true, description : 'enable Synaptics MST hub support') option('plugin_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support') -option('plugin_uefi_labels', type : 'boolean', value : true, description : 'enable UEFI labels support') +option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish support') option('plugin_uefi', type : 'boolean', value : true, description : 'enable UEFI support') +option('plugin_nvme', type : 'boolean', value : true, description : 'enable NVMe support') +option('plugin_modem_manager', type : 'boolean', value : false, description : 'enable ModemManager support') +option('plugin_flashrom', type : 'boolean', value : false, description : 'enable libflashrom support') option('systemd', type : 'boolean', value : true, description : 'enable systemd support') option('systemdunitdir', type: 'string', value: '', description: 'Directory for systemd units') +option('elogind', type : 'boolean', value : false, description : 'enable elogind support') option('tests', type : 'boolean', value : true, description : 'enable tests') option('udevdir', type: 'string', value: '', description: 'Directory for udev rules') +option('efi-cc', type : 'string', value : 'gcc', description : 'the compiler to use for EFI modules') +option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') +option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') +option('efi-ldsdir', type : 'string', description : 'path to the EFI lds directory') +option('efi-includedir', type : 'string', value : '/usr/include/efi', description : 'path to the EFI header directory') +option('efi_os_dir', type: 'string', description : 'the name of OS directory in ESP') diff -Nru fwupd-1.0.6/NEWS fwupd-1.2.10/NEWS --- fwupd-1.0.6/NEWS 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/NEWS 1970-01-01 00:00:00.000000000 +0000 @@ -1,719 +0,0 @@ -Version 1.0.6 -~~~~~~~~~~~~~ -Released: 2018-03-12 - -New Features: - - Add bash completion for fwupdmgr (Mario Limonciello) - - Add support for newest Thunderbolt chips (Andrei Emeltchenko) - - Allow all functions that take device arguments to be prompted (Mario Limonciello) - - Allow devices to use the runtime version when in bootloader mode (Richard Hughes) - - Allow overriding ESP mount point via conf file (Mario Limonciello) - - Delete any old fwupdate capsules and efivars when launching fwupd (Richard Hughes) - - Generate Vala bindings (Robert Ancell) - -Bugfixes: - - Allow ctrl-d out of the prompt for devices (Mario Limonciello) - - Allow to create package out of provided binary (Andrei Emeltchenko) - - Correct handling of unknown Thunderbolt devices (Yehezkel Bernat) - - Correctly detect new remotes that are manually copied (Richard Hughes) - - Fix a crash related to when passing device to downgrade in CLI (Mario Limonciello) - - Fix running the self tests when no fwupd is installed (Richard Hughes) - - Fix Unifying signature writing and parsing for Texas bootloader (Ogier Bouvier) - - Only send success and failure reports to the server (Richard Hughes) - - Use a CNAME to redirect to the correct CDN for metadata (Richard Hughes) - - Use a longer timeout when powering back the Thunderbolt device (Richard Hughes) - -Version 1.0.5 -~~~~~~~~~~~~~ -Released: 2018-02-14 - -New Features: - - Offer to reboot when processing an offline update (Richard Hughes) - - Report the efivar, libsmbios and fwupdate library versions (Mario Limonciello) - - Report Thunderbolt safe mode and SecureBoot status (Mario Limonciello) - - Show the user a URL when they report a known problem (Richard Hughes) - - Support split cabinet archives as produced by Windows Update (Richard Hughes) - -Bugfixes: - - Be more careful deleting and modifying device history (Richard Hughes) - - Clarify which devices don't have upgrades (Mario Limonciello) - - Ensure the Thunderbolt version is xx.yy (Richard Hughes) - - Fix a daemon warning when using fwupdmgr get-results (Richard Hughes) - - Fix crasher with MST flashing (Mario Limonciello) - - Fix DFU detach with newer releases of libusb (Richard Hughes) - - Include the device VID and PID when generating the device-id (Richard Hughes) - - Set the RemoteId when using GetDetails (Richard Hughes) - - Stop matching 8bitdo DS4 controller VID/PID (Mario Limonciello) - - Use help2man for dfu-tool and drop docbook dependencies (Mario Limonciello) - - Use ngettext for any strings with plurals (Piotr Drąg) - - Use the default value if ArchiveSizeMax is unspecified (Richard Hughes) - -Version 1.0.4 -~~~~~~~~~~~~~ -Released: 2018-01-25 - -New Features: - - Add D-Bus methods to get and modify the history information (Richard Hughes) - - Allow the user to share firmware update success or failure (Richard Hughes) - - Ask the user to refresh metadata when it is very old (Richard Hughes) - - Store firmware update success and failure to a local database (Richard Hughes) - -Bugfixes: - - Add a device name for locked UEFI devices (Mario Limonciello) - - Allow each plugin to opt-in to the recoldplug action (Richard Hughes) - - Fix firmware downloading using gnome-software (Richard Hughes) - - Fix UX capsule reference to the one specified in efivar (Mario Limonciello) - - Never add two devices to the daemon with the same ID (Richard Hughes) - - Rescan supported flags when refreshing metadata (Richard Hughes) - -Version 1.0.3 -~~~~~~~~~~~~~ -Released: 2018-01-09 - -New Features: - - Add a new plugin to add support for CSR "Driverless DFU" (Richard Hughes) - - Add initial SF30/SN30 Pro support (Mario Limonciello) - - Support AppStream metadata with relative URLs (Richard Hughes) - -Bugfixes: - - Add more metadata to the user-agent string (Richard Hughes) - - Block owned Dell TPM updates (Mario Limonciello) - - Choose the correct component from provides matches using requirements (Richard Hughes) - - Do not try to parse huge compressed archive files (Richard Hughes) - - Fix a double-free bug in the Udev code (Philip Withnall) - - Handle Thunderbolt "native" mode (Yehezkel Bernat) - - Use the new functionality in libgcab >= 1.0 to avoid writing temp files (Richard Hughes) - -Version 1.0.2 -~~~~~~~~~~~~~ -Released: 2017-11-28 - -New Features: - - Add a plugin for the Nitrokey Storage device (Richard Hughes) - - Add support for the original AVR DFU protocol (Richard Hughes) - - Allow different plugins to claim the same device (Richard Hughes) - - Allow quirks to set common USB properties (Richard Hughes) - - Move a common plugin functionality out to a new shared object (Richard Hughes) - - Optionally delay the device removal for better replugging (Richard Hughes) - - Set environment variables to allow easy per-plugin debugging (Richard Hughes) - - Use a SHA1 hash for the internal DeviceID (Richard Hughes) - -Bugfixes: - - Add quirk for AT32UC3B1256 as used in the RubberDucky (Richard Hughes) - - Disable the dell plugin if libsmbios fails (Mario Limonciello) - - Don't register for USB UDev events to later ignore them (Richard Hughes) - - Fix a possible buffer overflow when debugging ebitdo devices (Richard Hughes) - - Fix critical warning when more than one remote fails to load (Richard Hughes) - - Fix DFU attaching AVR32 devices like the XMEGA (Richard Hughes) - - Ignore useless Thunderbolt device types (Mario Limonciello) - - Refactor ColorHug into a much more modern plugin (Richard Hughes) - - Release the Steelseries interface if getting the version failed (Richard Hughes) - - Remove autoconf-isms from the meson configure options (Richard Hughes) - - Show a nicer error message if the requirement fails (Richard Hughes) - - Sort the output of GetUpgrades correctly (Richard Hughes) - -Version 1.0.1 -~~~~~~~~~~~~~ -Released: 2017-11-09 - -New Features: - - Add support for HWID requirements (Richard Hughes) - - Add support for programming various AVR32 and XMEGA parts using DFU (Richard Hughes) - - Add the various DFU quirks for the Jabra Speak devices (Richard Hughes) - - Allow specifying the output file type for 'dfu-tool read' (Richard Hughes) - - Move the database of supported devices out into runtime loaded files (Richard Hughes) - - Support the IHEX record type 0x05 (Richard Hughes) - - Use help2man to generate the man page at build time (Richard Hughes) - - Use the new quirk infrastructure for version numbers (Richard Hughes) - -Bugfixes: - - Catch invalid Dell dock component requests (Mario Limonciello) - - Correctly output Intel HEX files with > 16bit offset addresses (Richard Hughes) - - Do not try to verify the element write if upload is unsupported (Richard Hughes) - - Fix a double-unref when updating any 8Bitdo device (Richard Hughes) - - Fix crash when enumerating with Dell dock connected but with no UEFI (Mario Limonciello) - - Fix uploading large firmware files over DFU (Richard Hughes) - - Format the BCD USB revision numbers correctly (Richard Hughes) - - Guess the DFU transfer size if it is not specified (Richard Hughes) - - Include the reset timeout as wValue to fix some DFU bootloaders (Richard Hughes) - - Make the error message clearer when sans fonts are missing (Mario Limonciello) - - Support devices with truncated DFU interface data (Richard Hughes) - - Use the correct remote-specified username and passord when using fwupdmgr (Richard Hughes) - - Use the correct wDetachTimeOut when writing DFU firmware (Richard Hughes) - - Verify devices with legacy VIDs are actually 8Bitdo controllers (Richard Hughes) - -Version 1.0.0 -~~~~~~~~~~~~~ -Released: 2017-10-09 - -Notes: - - This release breaks API and ABI to remove deprecated symbols - - libdfu is now not installed as a shared library - -New Features: - - Add a human-readable title for each remote (Richard Hughes) - - Add a method to return a list of upgrades for a specific device (Richard Hughes) - - Add an 'Summary' and 'Icons' properties to each device (Richard Hughes) - - Add FuDeviceLocker to simplify device open/close lifecycles (Richard Hughes) - - Add functionality to blacklist Dell HW with problems (Mario Limonciello) - - Add fu_plugin_check_supported() (Richard Hughes) - - Add fwupd_remote_get_checksum() to use in client programs (Richard Hughes) - - Add ModifyRemote as an easy way to enable and disable remotes (Richard Hughes) - - Add the plugin documentation to the main gtk-doc (Richard Hughes) - - Allow plugins to depend on each other (Richard Hughes) - - Disable the fallback USB plugin (Richard Hughes) - - Parse the SMBIOS v2 and v3 DMI tables directly (Richard Hughes) - - Support uploading the UEFI firmware splash image (Richard Hughes) - - Use the intel-wmi-thunderbolt kernel module to force power (Mario Limonciello) - -Bugfixes: - - Only run SMI to toggle host MST GPIO on Dell systems with host MST (Mario Limonciello) - - Disable unifying support if no CONFIG_HIDRAW support (Richard Hughes) - - Do not auto-open all USB devices at startup (Richard Hughes) - - Do not fail to load the daemon if cached metadata is invalid (Richard Hughes) - - Do not use system-specific infomation for UEFI PCI devices (Richard Hughes) - - Fix a crash when using fu_plugin_device_add_delay() (Richard Hughes) - - Fix the libdfu self test failure on s390 and ppc64 (Richard Hughes) - - Fix various printing issues with the progressbar (Richard Hughes) - - Generate the LD script from the GObject introspection data (Richard Hughes) - - Never fallback to an offline update from client code (Richard Hughes) - - Only set the Dell coldplug delay when we know we need it (Mario Limonciello) - - Prefer to use HWIDs to get DMI keys and DE table (Mario Limonciello) - -Version 0.9.7 -~~~~~~~~~~~~~ -Released: 2017-09-01 - -New Features: - - Add a configure switch for the LVFS remotes (Richard Hughes) - - Add a FirmwareBaseURI parameter to the remote config (Richard Hughes) - - Add a firmware builder that uses bubblewrap (Richard Hughes) - - Add a python script to create fwupd compatible cab files from Microsoft .exe files (Max Ehrlich) - - Add a thunderbolt plugin for new kernel interface (Christian Kellner, Yehezkel Bernat) - - Allow plugins to get DMI data from the hardware in a safe way (Richard Hughes) - - Allow plugins to set metadata on devices created by other plugins (Richard Hughes, Mario Limonciello) - - Optionally install the LVFS PKCS7 root certificate (Richard Hughes) - - Optionally use GnuTLS to verify PKCS7 certificates (Richard Hughes) - -Bugfixes: - - Add back options for HAVE_SYNAPTICS and HAVE_THUNDERBOLT (Mario Limonciello) - - Allow configuring systemd and udev directories (Mario Limonciello) - - Enable C99 support in meson.build (Philip Withnall) - - Fix an incomplete cipher when using XTEA on data not in 4 byte chunks (Richard Hughes) - - Fix minor const-correctness issues (Philip Withnall) - - Implement thunderbolt image validation (Yehezkel Bernat, Christian Kellner) - - Remove the confusing ALLOW_OFFLINE and ALLOW_ONLINE flags (Richard Hughes) - - Show a bouncing progress bar if the percentage remains at zero (Richard Hughes) - - Use a hwid to match supported systems for synapticsmst (Mario Limonciello) - - Use the new bootloader PIDs for Unifying pico receivers (Richard Hughes) - - When thunderbolt is in safe mode on a Dell recover using SMBIOS (Mario Limonciello) - -Version 0.9.6 -~~~~~~~~~~~~~ -Released: 2017-08-03 - -New Features: - - Add DfuPatch to support forward-only firmware patching (Richard Hughes) - - Add --version option to fwupdmgr (Richard Hughes, Mario Limonciello) - - Display all errors recorded by efi_error tracing (Mario Limonciello) - - Make building introspection optional (Patrick Ohly) - - Support embedded devices with local firmware metadata (Richard Hughes) - -Bugfixes: - - Check all the device GUIDs against the blacklist when added (Richard Hughes) - - Correct a memory leak in Dell plugin (Mario Limonciello, Richard Hughes) - - Default to "en" for UEFI capsule graphics (Mario Limonciello) - - Don't log a warning when an unknown unifying report is parsed (Richard Hughes) - - Enable test suite via /etc/fwupd.conf (Mario Limonciello) - - Fix a hang on 32 bit computers (Richard Hughes) - - Fix compilation of the policy on a variety of configurations (Mario Limonciello) - - Fix UEFI crash when the product name is NULL (Richard Hughes) - - Make flashing ebitdo devices work with fu-ebitdo-tool (Chris Lee) - - Make messages from installing capsules useful (Mario Limonciello) - - Make sure the unifying percentage completion goes from 0% to 100% (Richard Hughes) - - Run the plugin coldplug methods in a predictable order (Richard Hughes) - - Test UEFI for kernel support during coldplug (Mario Limonciello) - - Use new GUsb functionality to fix flashing Unifying devices (Richard Hughes) - -Version 0.9.5 -~~~~~~~~~~~~~ -Released: 2017-07-04 - -New Features: - - Add a get-remotes command to fwupdmgr (Richard Hughes) - - Add a plugin to get the version of the AMT ME interface (Richard Hughes) - - Add Arch Linux to CI (Bruno Pagani) - - Add some installed tests flashing actual hardware (Richard Hughes) - - Allow flashing Unifying devices in bootloader modes (Richard Hughes) - - Allow ordering the metadata remotes (Richard Hughes) - -Bugfixes: - - Do not check the runtime if the DFU device is in bootloader mode (Richard Hughes) - - Do not unlock devices when doing VerifyUpdate (Richard Hughes) - - Filter by Unifying SwId when making HID++2.0 requests (Richard Hughes) - - Fix downgrades when version_lowest is set (Richard Hughes) - - Fix the self tests when running on PPC64 big endian (Richard Hughes) - - Move the remotes parsing from the client to the server (Richard Hughes) - - Split up the Unifying HID++2.0 and HID++1.0 functionality (Richard Hughes) - - Store the metadata files rather than merging to one store (Richard Hughes) - - Use a longer timeout for some Unifying operations (Richard Hughes) - - Use the UFY DeviceID prefix for Unifying devides (Richard Hughes) - -Version 0.9.4 -~~~~~~~~~~~~~ -Released: 2017-06-15 - -New Features: - - Add installed tests that use the daemon (Richard Hughes) - - Add the ability to restrict firmware to specific vendors (Richard Hughes) - - Enable Travis CI for Fedora and Debian (Richard Hughes, Mario Limonciello) - - Export some more API for dealing with checksums (Richard Hughes) - - Generate a images for status messages during system firmware update (Peter Jones) - - Show progress download when refreshing metadata (Richard Hughes) - -Bugfixes: - - Compile with newer versions of meson (Richard Hughes, Mario Limonciello) - - Ensure that firmware provides are legal GUIDs (Richard Hughes) - - Fix a common crash when refreshing metadata (Richard Hughes) - - Use the correct type signature in the D-Bus introspection file (Richard Hughes) - -Version 0.9.3 -~~~~~~~~~~~~~ -Released: 2017-06-07 - -New Features: - - Add a 'downgrade' command to fwupdmgr (Richard Hughes) - - Add a 'get-releases' command to fwupdmgr (Richard Hughes) - - Add support for ConsoleKit2 (Eric Koegel) - - Add support for Microsoft HardwareIDs (Richard Hughes) - - Allow downloading metadata from more than just the LVFS (Richard Hughes) - - Allow multiple checksums on devices and releases (Richard Hughes) - -Bugfixes: - - Allow to specify bindir (Timo Gurr) - - Correctly open Unifying devices with original factory firmware (Richard Hughes) - - Deprecate some of the old FwupdResult API (Richard Hughes) - - Do not copy the origin from the new metadata file (Richard Hughes) - - Do not expect a Unifying reply when issuing a REBOOT command (Richard Hughes) - - Do not re-download firmware that exists in the cache (Richard Hughes) - - Fix a problem when testing for a Dell system (Mario Limonciello) - - Fix flashing new firmware to 8bitdo controllers (Richard Hughes) - - Increase minimum required AppStream-Glib version to 0.6.13 (Chris Mayo) - - Make documentation and man pages optional (Chris Mayo) - - Make systemd dependency at least version 231 (Mario Limonciello) - - Only decompress the firmware after the signature check (Richard Hughes) - - Remove 'lib' prefix when looking for libraries (Mirco Tischler) - - Return the remote ID when getting updates about hardware (Richard Hughes) - - Send the daemon the remote ID when sending firmware metadata (Richard Hughes) - -Version 0.9.2 -~~~~~~~~~~~~~ -Released: 2017-05-22 - -New Features: - - Add support for Unifying DFU features (Richard Hughes) - -Bugfixes: - - Do not spew a critial warning when parsing an invalid URI (Richard Hughes) - - Ensure device is closed if did not complete setup (Richard Hughes) - - Ensure steelseries device is closed if it returns an invalid packet (Richard Hughes) - - Fix man page installation location (Mario Limonciello) - - Ignore spaces in the Unifying version prefix (Richard Hughes) - - Set HAVE_POLKIT_0_114 when polkit is newer than 0.114 (Moritz Kiefer) - -Version 0.9.1 -~~~~~~~~~~~~~ -Released: 2017-04-28 - -New Features: - - Add a config option to allow runtime disabling plugins by name (Richard Hughes) - - Add the Meson build system and remove autotools (Richard Hughes) - - Support signed Intel HEX files (Richard Hughes) - -Bugfixes: - - Add DFU quirk for OpenPICC and SIMtrace (Richard Hughes) - - Create directories in /var/cache as required (Richard Hughes) - - Refactor the unifying plugin now we know more about the hardware (Richard Hughes) - - Set the source origin when saving metadata (Richard Hughes) - - Support proxy servers in fwupdmgr (Richard Hughes) - - Use a 60 second timeout on all client downloads (Richard Hughes) - -Version 0.8.1 -~~~~~~~~~~~~~ -Released: 2017-02-27 - -Bugfixes: - - Adjust systemd confinement restrictions (Mario Limonciello, Richard Hughes) - - Do not hardcode docbook2man path (Kai Krakow) - - Don't initialize libsmbios on unsupported systems (Mario Limonciello) - - Fix a crash when enumerating devices on a Dell WLD15 (Richard Hughes) - - Fix compiler warnings (Kai Krakow) - - Fix fwupdmgr timeout with missing pending database (Richard Hughes) - -Version 0.8.0 -~~~~~~~~~~~~~ -Released: 2017-02-08 - -New Features: - - Add a set of vfuncs that are run before and after a device update (Richard Hughes) - - Add Dell-specific functionality to allow other plugins turn on TBT/GPIO (Mario Limonciello) - - Add support for Intel Thunderbolt devices (Richard Hughes, Mario Limonciello) - - Add support for Logitech Unifying devices (Richard Hughes) - - Add support for Synaptics MST cascades hubs (Mario Limonciello) - - Add support for the Altus-Metrum ChaosKey device (Richard Hughes) - - Add VerifyUpdate to update the device checksums server-side (Richard Hughes) - - Allow the metadata to match a version of fwupd and the existing fw version (Richard Hughes) - -Bugfixes: - - Add a new method for forcing a controller to flash mode (Mario Limonciello) - - Always make sure we're getting a C99 compiler (Richard Hughes) - - Close USB devices before error returns (Tsunghan Liu) - - Don't read data from some DfuSe targets (Richard Hughes) - - Include all debug messages when run with --verbose (Richard Hughes) - - Return the pending UEFI update when not on AC power (Richard Hughes) - - Use a heuristic for the start address if the firmware has no DfuSe footer (Richard Hughes) - - Use more restrictive settings when running under systemd (Richard Hughes, Mario Limonciello) - -Version 0.7.5 -~~~~~~~~~~~~~ -Released: 2016-10-19 - -New Features: - - Add a 'replace-data' command to dfu-tool (Richard Hughes) - - Use an animated progress bar when performing DFU operations (Richard Hughes) - -Bugfixes: - - Add quirks for HydraBus as it does not have a DFU runtime (Richard Hughes) - - Don't create the UEFI dummy device if the unlock will happen on next boot (Richard Hughes) - - Enable hardening flags on more binaries (Mario Limonciello) - - Fix an assert when unlocking the dummy ESRT device (Richard Hughes) - - Fix writing firmware to devices using the ST reference bootloader (Richard Hughes) - - Match the Dell TB16 device (Mario Limonciello) - - Re-get the quirks when the DfuDevice gets a new GUsbDevice (Richard Hughes) - - Show the nicely formatted target name for DfuSe devices (Richard Hughes) - - Verify devices support updating in mode they are called (Mario Limonciello) - -Version 0.7.4 -~~~~~~~~~~~~~ -Released: 2016-09-19 - -New Features: - - Add dfu_firmware_add_symbol() (Richard Hughes) - - Allow the argument to 'dfu-tool set-release' be major.minor (Richard Hughes) - - Load the Altos USB descriptor from ELF files (Richard Hughes) - - Support writing the IHEX symbol table (Richard Hughes) - -Bugfixes: - - Add a fallback for older appstream-glib releases (Richard Hughes) - - Fix a possible crash when uploading firmware files using libdfu (Richard Hughes) - - Fix libfwupd self tests when a host-provided fwupd is not available (Richard Hughes) - - Show the human-readable version in the 'dfu-tool dump' output (Richard Hughes) - - Write the ELF files with the correct section type (Richard Hughes) - -Version 0.7.3 -~~~~~~~~~~~~~ -Released: 2016-08-29 - -New Features: - - Add a set-address and set-target-size commands to dfu-util (Richard Hughes) - - Add a small library for talking with 0bitdo hardware (Richard Hughes) - - Add Dell TPM and TB15/WD15 support via new Dell provider (Mario Limonciello) - - Add FU_DEVICE_FLAG_NEEDS_BOOTLOADER (Richard Hughes) - - Add fwupd_client_get_status() (Richard Hughes) - - Add fwupd_result_get_unique_id() (Richard Hughes) - - Add initial ELF reading and writing support to libdfu (Richard Hughes) - - Add support for installing multiple devices from a CAB file (Richard Hughes) - - Allow providers to export percentage completion (Richard Hughes) - - Show a progress notification when installing firmware (Richard Hughes) - - Show the vendor flashing instructions when installing (Richard Hughes) - -Bugfixes: - - Add XPS 9250 to Dell TPM modeswitch blacklist (Mario Limonciello) - - Allow blacklisting devices by their GUID (Richard Hughes) - - Conditionally enable all providers based upon installed (Mario Limonciello) - - Display flashes left in results output when it gets low (Mario Limonciello) - - Do not attempt to add DFU devices not in runtime mode (Richard Hughes) - - Do not use the deprecated GNOME_COMPILE_WARNINGS (Richard Hughes) - - Don't fail while checking versions or locked state (Richard Hughes) - - Embed fwupd version in generated documentation (Mario Limonciello) - - Ensure the ID is set when getting local firmware details (Richard Hughes) - - Fix gtk-doc build when srcdir != builddir (Ting-Wei Lan) - - Fix libdfu hang when parsing corrupt IHEX files (Richard Hughes) - - Ignore devices that do not add at least one GUID (Richard Hughes) - - In get-details output, display the blob filename (Mario Limonciello) - - Save the unique ID in the pending database (Richard Hughes) - - Support the 'DEVO' cipher kind in libdfu (Richard Hughes) - - Switch to the Amazon S3 CDN for firmware metadata (Richard Hughes) - - Update fwupdmgr manpage for new commands and arguments (Mario Limonciello) - - Use a private gnupg key store (Richard Hughes) - - Use the correct firmware when installing a composite device (Richard Hughes) - - Use the SHA1 hash of the local file data as the origin (Richard Hughes) - -Version 0.7.2 -~~~~~~~~~~~~~ -Released: 2016-06-13 - -New Features: - - Add a GetDetailsLocal() method to eventually replace GetDetails() (Richard Hughes) - - Add fu_device_get_alternate() (Richard Hughes) - - Allow devices to have multiple assigned GUIDs (Richard Hughes) - - Allow metainfo files to match only specific revisions of devices (Richard Hughes) - - Show the DFU protocol version in 'dfu-tool list' (Richard Hughes) - -Bugfixes: - - Enforce allowing providers to take away flash abilities (Mario Limonciello) - - Only claim the DFU interface when required (Richard Hughes) - - Only return updatable devices from GetDevices() (Richard Hughes) - -Version 0.7.1 -~~~~~~~~~~~~~ -Released: 2016-05-13 - -New Features: - - Add a --force flag to override provider warnings (Mario Limonciello) - - Add device-added, device-removed and device-changed signals (Richard Hughes) - - Add dfu_image_get_element_default() (Richard Hughes) - - Add for a new device field "Flashes Left" (Mario Limonciello) - - Add fwupd_client_connect() (Richard Hughes) - - Add the 'monitor' debugging command for fwupdmgr (Richard Hughes) - - Add the 'supported' flag to the FuDevice (Richard Hughes) - -Bugfixes: - - Add summary and name field for Rival SteelSeries (Mario Limonciello) - - Fix a critical warning when restarting the daemon (Richard Hughes) - - Fix BE issues when reading and writing DFU files (Mario Limonciello, Richard Hughes) - - Make the device display name nicer (Richard Hughes, Richard Hughes) - - Match the AppStream metadata after a device has been added (Richard Hughes) - - Remove non-interactive pinentry setting from fu-keyring (Mario Limonciello) - - Return all update descriptions newer than the installed version (Richard Hughes) - - Set the device description when parsing local firmware files (Richard Hughes) - -Version 0.7.0 -~~~~~~~~~~~~~ -Released: 2016-04-01 - -New Features: - - Add a version plugin for SteelSeries hardware (Richard Hughes) - - Add FwupdClient and FwupdResult to libfwupd (Richard Hughes) - - Generate gtk-doc documentation for libfwupd (Richard Hughes) - - Return the device flags when getting firmware details (Richard Hughes) - - Support other checksum kinds (Richard Hughes) - -Bugfixes: - - Add Alienware to the version quirk table (Mario Limonciello) - - Allow the test suite to run in %check (Richard Hughes) - - Do not return updates that require AC when on battery (Richard Hughes) - - Do not use /tmp for downloaded files (Richard Hughes) - - Test that GPG key import actually was successful (Mario Limonciello) - -Version 0.6.3 -~~~~~~~~~~~~~ -Released: 2016-03-14 - -New Features: - - Add an unlock method for devices (Richard Hughes) - - Add a simple plugin infrastructure (Richard Hughes) - - Add ESRT enable method into UEFI provider (Mario Limonciello) - - Install the hardcoded firmware AppStream file (Richard Hughes) - -Bugfixes: - - Correct the BCD version number for DFU 1.1 (Richard Hughes) - - Do not use deprecated API from libappstream-glib (Richard Hughes) - - Ignore the DFU runtime on the DW1820A (Richard Hughes) - - Only read PCI OptionROM firmware when devices are manually unlocked (Richard Hughes) - - Require AC power before scheduling some types of firmware update (Richard Hughes) - - Show ignored DFU devices in dfu-util, but not in fwupd (Richard Hughes) - -Version 0.6.2 -~~~~~~~~~~~~~ -Released: 2016-02-12 - -New Features: - - Add 'Created' and 'Modified' properties on managed devices (Richard Hughes) - -Bugfixes: - - Fix get-results for UEFI provider (Mario Limonciello) - - Support vendor-specific UEFI version encodings (Richard Hughes) - -Version 0.6.1 -~~~~~~~~~~~~~ -Released: 2016-01-19 - -Bugfixes: - - Always persist ColorHug devices after replug (Richard Hughes) - - Do not misdetect different ColorHug devices (Richard Hughes) - - Only dump the profiling data when run with --verbose (Richard Hughes) - -Version 0.6.0 -~~~~~~~~~~~~~ -Released: 2015-12-07 - -Notes: - - This release adds a new GObject library called libdfu and a command line - client called dfu-tool. This is a low-level tool used to upgrade USB device - firmware and can either be shipped in the same package as fwupd or split off - as separate subpackages. - -New Features: - - Add support for automatically updating USB DFU-capable devices (Richard Hughes) - -Bugfixes: - - Emit the changed signal after doing an update (Richard Hughes) - - Export the AppStream ID when returning device results (Richard Hughes) - - Fix compile with --disable-shared (Richard Hughes) - - Use new API available in fwup 0.5 (Richard Hughes, Mario Limonciello) - - Use the same device identification string format as Microsoft (Richard Hughes) - -Version 0.5.3 -~~~~~~~~~~~~~ -Released: 2015-11-05 - -Bugfixes: - - Avoid seeking when reading the file magic during refresh (Richard Hughes) - - Do not assume that the compressed XML data will be NUL terminated (Richard Hughes) - - Use the correct user agent string for fwupdmgr (Richard Hughes) - -Version 0.5.2 -~~~~~~~~~~~~~ -Released: 2015-10-28 - -New Features: - - Add profiling data to debug slow startup times (Richard Hughes) - - Support cabinet archives files with more than one firmware (Richard Hughes) - -Bugfixes: - - Add the update description to the GetDetails results (Richard Hughes) - - Clear the in-memory firmware store only after parsing a valid XML file (Richard Hughes) - - Ensure D-Bus remote errors are registered at fwupdmgr startup (Richard Hughes) - - Fix verify-update to produce components with the correct provide values (Richard Hughes) - - Require appstream-glib 0.5.1 (Mirco Tischler) - - Show the dotted-decimal representation of the UEFI version number (Richard Hughes) - - When the version is from the 'FW' extension do not cache the device (Richard Hughes) - -Version 0.5.1 -~~~~~~~~~~~~~ -Released: 2015-09-21 - -Bugfixes: - - Fix the error message when no devices can be updated (Richard Hughes) - - Fix reading symlink to prevent crash with some compilers (Kalev Lember) - -Version 0.5.0 -~~~~~~~~~~~~~ -Released: 2015-09-15 - -New Features: - - Raise the dep on GLib to support and use g_autoptr() (Richard Hughes) - -Bugfixes: - - Do not merge existing firmware metadata (Richard Hughes) - - Do not reboot if racing with the PackageKit offline update mechanism (Richard Hughes) - -Version 0.1.6 -~~~~~~~~~~~~~ -Released: 2015-09-10 - -New Features: - - Remove fwsignd, we have the LVFS now (Richard Hughes) - -Bugfixes: - - Add application metadata when getting the updates list (Richard Hughes) - - Depend on appstream-glib >= 0.5.0 (Richard Hughes) - - Don't apply firmware if something else is processing the update (Richard Hughes) - - Install fwupd into /usr/lib/$(triplet)/fwupd instead (Mario Limonciello) - - Simplify the version properties on devices to avoid complexity (Richard Hughes) - - Update the offline update service to invoke right command (Kalev Lember) - - Use the new secure metadata URI (Richard Hughes) - -Version 0.1.5 -~~~~~~~~~~~~~ -Released: 2015-08-12 - -Notes: - - For the device verification code to work correctly you need at least - libappstream-glib 0.5.0 installed. - -New Features: - - Add a Raspberry Pi firmware provider (Richard Hughes) - - Add a simple config file to store the correct LVFS download URI (Richard Hughes) - - Make parsing the option ROM runtime optional (Richard Hughes) - -Bugfixes: - - Allow fwupd to be autostarted by systemd (Richard Hughes) - - Allow no arguments to 'fwupdmgr verify-update' and use sane defaults (Richard Hughes) - - Devices with option ROM are always internal (Richard Hughes) - - Do not pre-convert the update description from AppStream XML (Richard Hughes) - - Fix validation of written firmware (Richard Hughes) - - Move the verification and metadata matching phase to the daemon (Richard Hughes) - - Sign the test binary with the correct key (Richard Hughes) - - Use the AppStream 0.9 firmware specification by default (Richard Hughes) - -Version 0.1.4 -~~~~~~~~~~~~~ -Released: 2015-07-25 - -Notes: - - In this release we've moved the LVFS website to the fwupd project and made - them work really well together. To update all the firmware on your system - is now just a case of "fwupdmgr refresh && fwupdmgr update" - - We've also added verification of BIOS and PCI ROM firmware, which may be - useful for forensics or to verify that system updates have been applied. - -New Features: - - Actually parse the complete PCI option ROM (Richard Hughes) - - Add a 'fwupdmgr update' command to update all devices to latest versions (Richard Hughes) - - Add a simple signing server that operates on .cab files (Richard Hughes) - - Add a 'verify' command that verifies the cryptographic hash of device firmware (Richard Hughes) - - Allow clients to add new firmware metadata to the system cache (Richard Hughes) - - Move GetUpdates to the daemon (Richard Hughes) - - Move the LVFS website to the fwupd project (Richard Hughes) - -Bugfixes: - - Accept multiple files at one time when using fwupdmgr dump-rom (Richard Hughes) - - Automatically download metadata using fwupdmgr if required (Richard Hughes) - - Do not return NULL as a gboolean (Thomas Hindoe Paaboel Andersen) - - Don't call efibootmgr after fwupdate (Mario Limonciello) - - Fallback to offline install when calling the update argument (Mario Limonciello) - - Fix Intel VBIOS detection on Dell hardware (Richard Hughes) - - Reload appstream data after refreshing (Mario Limonciello) - - Use the new LVFS GPG key (Richard Hughes) - - Fix build: libgusb is required even without colorhug support (Jussi Kukkonen) - -Version 0.1.3 -~~~~~~~~~~~~~ -Released: 2015-05-28 - -New Features: - - Get the firmware version from the device descriptors (Richard Hughes) - - Run the offline actions using systemd when required (Richard Hughes) - - Support OpenHardware devices using the fwupd vendor extensions (Richard Hughes) - -Bugfixes: - - Add an UNKNOWN status so we can return meaningful enum values (Richard Hughes) - - Coldplug the devices before acquiring the well known name (Richard Hughes) - -Version 0.1.2 -~~~~~~~~~~~~~ -Released: 2015-04-22 - - Add some guidelines for vendors to README (Richard Hughes) - - Only allow signed firmware to be upgraded without a password (Richard Hughes) - -Version 0.1.1 -~~~~~~~~~~~~~ -Released: 2015-03-23 - -New Features: - - Add a 'get-updates' command to fwupdmgr (Richard Hughes) - - Add and document the offline-update lifecycle (Richard Hughes) - - Create a libfwupd shared library (Richard Hughes) - -Bugfixes: - - Create runtime directories if they do not exist (Richard Hughes) - - Do not crash when there are no devices to return (Richard Hughes) - -Version 0.1.0 -~~~~~~~~~~~~~ -Released: 2015-03-16 - -Notes: - - fwupd is a simple daemon to allow session software to update firmware. diff -Nru fwupd-1.0.6/plugins/altos/altos.quirk fwupd-1.2.10/plugins/altos/altos.quirk --- fwupd-1.0.6/plugins/altos/altos.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/altos.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,7 @@ +# ChaosKey +[DeviceInstanceId=USB\VID_1D50&PID_60C6] +Plugin = altos +Flags = none +[DeviceInstanceId=USB\VID_FFFE&PID_000A] +Plugin = altos +Flags = is-bootloader diff -Nru fwupd-1.0.6/plugins/altos/fu-altos-device.c fwupd-1.2.10/plugins/altos/fu-altos-device.c --- fwupd-1.0.6/plugins/altos/fu-altos-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/fu-altos-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,39 +1,23 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include #include -#include #include #include #include #include +#include "fu-io-channel.h" #include "fu-altos-device.h" #include "fu-altos-firmware.h" -typedef struct -{ +struct _FuAltosDevice { + FuUsbDevice parent_instance; FuAltosDeviceKind kind; guint32 serial[9]; gchar *guid; @@ -42,15 +26,16 @@ guint64 addr_base; guint64 addr_bound; struct termios tty_termios; - gint tty_fd; -} FuAltosDevicePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (FuAltosDevice, fu_altos_device, FU_TYPE_USB_DEVICE) + FuIOChannel *io_channel; +}; -#define GET_PRIVATE(o) (fu_altos_device_get_instance_private (o)) +G_DEFINE_TYPE (FuAltosDevice, fu_altos_device, FU_TYPE_USB_DEVICE) #ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref) +#pragma clang diagnostic pop #endif /** @@ -96,40 +81,25 @@ static void fu_altos_device_finalize (GObject *object) { - FuAltosDevice *device = FU_ALTOS_DEVICE (object); - FuAltosDevicePrivate *priv = GET_PRIVATE (device); + FuAltosDevice *self = FU_ALTOS_DEVICE (object); - g_free (priv->guid); - g_free (priv->tty); - g_free (priv->version); + g_free (self->guid); + g_free (self->tty); + g_free (self->version); G_OBJECT_CLASS (fu_altos_device_parent_class)->finalize (object); } -static void -fu_altos_device_init (FuAltosDevice *device) -{ -} - -static void -fu_altos_device_class_init (FuAltosDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = fu_altos_device_finalize; -} - FuAltosDeviceKind -fu_altos_device_get_kind (FuAltosDevice *device) +fu_altos_device_get_kind (FuAltosDevice *self) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - return priv->kind; + return self->kind; } static gboolean -fu_altos_device_find_tty (FuAltosDevice *device, GError **error) +fu_altos_device_find_tty (FuAltosDevice *self, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); g_autoptr(GList) devices = NULL; g_autoptr(GUdevClient) gudev_client = g_udev_client_new (NULL); @@ -160,7 +130,7 @@ continue; /* success */ - priv->tty = g_strdup (dev_file); + self->tty = g_strdup (dev_file); return TRUE; } @@ -175,188 +145,56 @@ } static gboolean -fu_altos_device_tty_write (FuAltosDevice *device, +fu_altos_device_tty_write (FuAltosDevice *self, const gchar *data, gssize data_len, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - gint rc; - gssize idx = 0; - guint timeout_ms = 500; - struct pollfd fds; - /* lets assume this is text */ if (data_len < 0) data_len = strlen (data); - - fds.fd = priv->tty_fd; - fds.events = POLLOUT; - - g_debug ("write, with timeout %ums", timeout_ms); - while (idx < data_len) { - - /* wait for data to be allowed to write without blocking */ - rc = poll (&fds, 1, (gint) timeout_ms); - if (rc == 0) - break; - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to poll %i", - priv->tty_fd); - return FALSE; - } - - /* we can write data */ - if (fds.revents & POLLOUT) { - gssize len; - g_debug ("writing %" G_GSSIZE_FORMAT " bytes: %s", data_len, data); - len = write (priv->tty_fd, data + idx, data_len - idx); - if (len < 0) { - if (errno == EAGAIN) { - g_debug ("got EAGAIN, trying harder"); - continue; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "failed to write %" G_GSSIZE_FORMAT - " bytes to %i: %s" , - data_len, - priv->tty_fd, - strerror (errno)); - return FALSE; - } - g_debug ("wrote %" G_GSSIZE_FORMAT " bytes", len); - idx += len; - } - } - - return TRUE; + return fu_io_channel_write_raw (self->io_channel, + (const guint8 *) data, + (gsize) data_len, + 500, /* ms */ + FU_IO_CHANNEL_FLAG_NONE, + error); } static GString * -fu_altos_device_tty_read (FuAltosDevice *device, +fu_altos_device_tty_read (FuAltosDevice *self, guint timeout_ms, gssize max_size, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - gint rc; - struct pollfd fds; - g_autoptr(GString) str = g_string_new (NULL); - - fds.fd = priv->tty_fd; - fds.events = POLLIN; - - g_debug ("read, with timeout %ums", timeout_ms); - for (;;) { - /* wait for data to appear */ - rc = poll (&fds, 1, (gint) timeout_ms); - if (rc == 0) - break; - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to poll %i", - priv->tty_fd); - return NULL; - } - - /* we have data to read */ - if (fds.revents & POLLIN) { - guint8 buf[1024]; - gssize len = read (priv->tty_fd, buf, sizeof (buf)); - if (len < 0) { - if (errno == EAGAIN) { - g_debug ("got EAGAIN, trying harder"); - continue; - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "failed to read %i: %s", - priv->tty_fd, - strerror (errno)); - return NULL; - } - if (len > 0) { - g_debug ("read %" G_GSSIZE_FORMAT " bytes from device", len); - g_string_append_len (str, (gchar *) buf, len); - } - - /* check maximum size */ - if (max_size > 0 && str->len >= (guint) max_size) - break; - continue; - } - if (fds.revents & POLLERR) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "error condition"); - return NULL; - } - if (fds.revents & POLLHUP) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "connection hung up"); - return NULL; - } - if (fds.revents & POLLNVAL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "invalid request"); - return NULL; - } - } - - /* no data */ - if (str->len == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "no data received from device in %ums", - timeout_ms); + g_autoptr(GBytes) buf = NULL; + buf = fu_io_channel_read_bytes (self->io_channel, max_size, + timeout_ms, FU_IO_CHANNEL_FLAG_NONE, error); + if (buf == NULL) return NULL; - } - - /* return blob */ - return g_steal_pointer (&str); + return g_string_new_len (g_bytes_get_data (buf, NULL), g_bytes_get_size (buf)); } static gboolean -fu_altos_device_tty_open (FuAltosDevice *device, GError **error) +fu_altos_device_tty_open (FuAltosDevice *self, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); struct termios termios; g_autoptr(GString) str = NULL; /* open device */ - priv->tty_fd = open (priv->tty, O_RDWR | O_NONBLOCK); - if (priv->tty_fd < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "failed to open %s", - priv->tty); + self->io_channel = fu_io_channel_new_file (self->tty, error); + if (self->io_channel == NULL) return FALSE; - } /* get the old termios settings so we can restore later */ - if (tcgetattr (priv->tty_fd, &termios) < 0) { + if (tcgetattr (fu_io_channel_unix_get_fd (self->io_channel), &termios) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to get attributes from fd"); return FALSE; } - priv->tty_termios = termios; + self->tty_termios = termios; cfmakeraw (&termios); /* set speed */ @@ -374,7 +212,8 @@ termios.c_cc[VTIME] = 0; /* set all new data */ - if (tcsetattr (priv->tty_fd, TCSAFLUSH, &termios) < 0) { + if (tcsetattr (fu_io_channel_unix_get_fd (self->io_channel), + TCSAFLUSH, &termios) < 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -383,7 +222,7 @@ } /* dump any pending input */ - str = fu_altos_device_tty_read (device, 50, -1, NULL); + str = fu_altos_device_tty_read (self, 50, -1, NULL); if (str != NULL) g_debug ("dumping pending buffer: %s", str->str); @@ -391,51 +230,51 @@ } static gboolean -fu_altos_device_tty_close (FuAltosDevice *device, GError **error) +fu_altos_device_tty_close (FuAltosDevice *self, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - - tcsetattr (priv->tty_fd, TCSAFLUSH, &priv->tty_termios); - close (priv->tty_fd); - + tcsetattr (fu_io_channel_unix_get_fd (self->io_channel), + TCSAFLUSH, &self->tty_termios); + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); return TRUE; } static GString * -fu_altos_device_read_page (FuAltosDevice *device, guint address, GError **error) +fu_altos_device_read_page (FuAltosDevice *self, guint address, GError **error) { g_autoptr(GString) str = NULL; g_autofree gchar *cmd = g_strdup_printf ("R %x\n", address); - if (!fu_altos_device_tty_write (device, cmd, -1, error)) + if (!fu_altos_device_tty_write (self, cmd, -1, error)) return NULL; - str = fu_altos_device_tty_read (device, 1500, 256, error); + str = fu_altos_device_tty_read (self, 1500, 256, error); if (str == NULL) return NULL; return g_steal_pointer (&str); } static gboolean -fu_altos_device_write_page (FuAltosDevice *device, +fu_altos_device_write_page (FuAltosDevice *self, guint address, const guint8 *data, guint data_len, GError **error) { g_autofree gchar *cmd = g_strdup_printf ("W %x\n", address); - if (!fu_altos_device_tty_write (device, cmd, -1, error)) + if (!fu_altos_device_tty_write (self, cmd, -1, error)) return FALSE; - if (!fu_altos_device_tty_write (device, (const gchar *) data, data_len, error)) + if (!fu_altos_device_tty_write (self, (const gchar *) data, data_len, error)) return FALSE; return TRUE; } -gboolean -fu_altos_device_write_firmware (FuAltosDevice *device, +static gboolean +fu_altos_device_write_firmware (FuDevice *device, GBytes *fw, - FuAltosDeviceWriteFirmwareFlag flags, + FwupdInstallFlags flags, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); + FuAltosDevice *self = FU_ALTOS_DEVICE (device); GBytes *fw_blob; const gchar *data; const gsize data_len; @@ -445,7 +284,7 @@ g_autoptr(GString) buf = g_string_new (NULL); /* check kind */ - if (priv->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { + if (self->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -454,7 +293,7 @@ } /* check sizes */ - if (priv->addr_base == 0x0 || priv->addr_bound == 0x0) { + if (self->addr_base == 0x0 || self->addr_bound == 0x0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -463,7 +302,7 @@ } /* read in blocks of 256 bytes */ - flash_len = priv->addr_bound - priv->addr_base; + flash_len = self->addr_bound - self->addr_base; if (flash_len == 0x0 || flash_len > 0x100000) { g_set_error_literal (error, FWUPD_ERROR, @@ -478,14 +317,14 @@ return FALSE; /* check the start address */ - if (fu_altos_firmware_get_address (altos_firmware) != priv->addr_base) { + if (fu_altos_firmware_get_address (altos_firmware) != self->addr_base) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "start address not correct %" G_GUINT64_FORMAT ":" "%" G_GUINT64_FORMAT, fu_altos_firmware_get_address (altos_firmware), - priv->addr_base); + self->addr_base); return FALSE; } @@ -522,16 +361,16 @@ } /* verify data from device */ - if (!fu_altos_device_write_page (device, - priv->addr_base + i, + if (!fu_altos_device_write_page (self, + self->addr_base + i, buf_tmp, 0x100, error)) return FALSE; /* verify data written on device */ - str = fu_altos_device_read_page (device, - priv->addr_base + i, + str = fu_altos_device_read_page (self, + self->addr_base + i, error); if (str == NULL) return FALSE; @@ -541,7 +380,7 @@ FWUPD_ERROR_WRITE, "failed to verify @%x, " "not enough data returned", - (guint) (priv->addr_base + i)); + (guint) (self->addr_base + i)); return FALSE; } if (memcmp (str->str, buf_tmp, 0x100) != 0) { @@ -549,38 +388,36 @@ FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to verify @%x", - (guint) (priv->addr_base + i)); + (guint) (self->addr_base + i)); return FALSE; } /* progress */ - fu_device_set_progress_full (FU_DEVICE (device), i, flash_len); + fu_device_set_progress_full (device, i, flash_len); g_string_append_len (buf, str->str, str->len); } /* go to application mode */ - if (flags & FU_ALTOS_DEVICE_WRITE_FIRMWARE_FLAG_REBOOT) { - if (!fu_altos_device_tty_write (device, "a\n", -1, error)) - return FALSE; - } + if (!fu_altos_device_tty_write (self, "a\n", -1, error)) + return FALSE; /* progress complete */ - fu_device_set_progress_full (FU_DEVICE (device), flash_len, flash_len); + fu_device_set_progress_full (device, flash_len, flash_len); /* success */ return TRUE; } -GBytes * -fu_altos_device_read_firmware (FuAltosDevice *device, GError **error) +static GBytes * +fu_altos_device_read_firmware (FuDevice *device, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); + FuAltosDevice *self = FU_ALTOS_DEVICE (device); guint flash_len; g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(GString) buf = g_string_new (NULL); /* check kind */ - if (priv->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { + if (self->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -589,7 +426,7 @@ } /* check sizes */ - if (priv->addr_base == 0x0 || priv->addr_bound == 0x0) { + if (self->addr_base == 0x0 || self->addr_bound == 0x0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -598,7 +435,7 @@ } /* read in blocks of 256 bytes */ - flash_len = priv->addr_bound - priv->addr_base; + flash_len = self->addr_bound - self->addr_base; if (flash_len == 0x0 || flash_len > 0x100000) { g_set_error_literal (error, FWUPD_ERROR, @@ -614,18 +451,18 @@ error); if (locker == NULL) return NULL; - for (guint i = priv->addr_base; i < priv->addr_bound; i+= 0x100) { + for (guint i = self->addr_base; i < self->addr_bound; i+= 0x100) { g_autoptr(GString) str = NULL; /* request data from device */ - str = fu_altos_device_read_page (device, i, error); + str = fu_altos_device_read_page (self, i, error); if (str == NULL) return NULL; /* progress */ - fu_device_set_progress_full (FU_DEVICE (device), - i - priv->addr_base, - priv->addr_bound - priv->addr_base); + fu_device_set_progress_full (device, + i - self->addr_base, + self->addr_bound - self->addr_base); g_string_append_len (buf, str->str, str->len); } @@ -634,17 +471,16 @@ } static gboolean -fu_altos_device_probe_bootloader (FuAltosDevice *device, GError **error) +fu_altos_device_probe_bootloader (FuAltosDevice *self, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(FuDeviceLocker) locker = NULL; g_auto(GStrv) lines = NULL; g_autoptr(GString) str = NULL; /* get tty for upload */ - if (!fu_altos_device_find_tty (device, error)) + if (!fu_altos_device_find_tty (self, error)) return FALSE; - locker = fu_device_locker_new_full (device, + locker = fu_device_locker_new_full (self, (FuDeviceLockerFunc) fu_altos_device_tty_open, (FuDeviceLockerFunc) fu_altos_device_tty_close, error); @@ -652,9 +488,9 @@ return FALSE; /* get the version information */ - if (!fu_altos_device_tty_write (device, "v\n", -1, error)) + if (!fu_altos_device_tty_write (self, "v\n", -1, error)) return FALSE; - str = fu_altos_device_tty_read (device, 100, -1, error); + str = fu_altos_device_tty_read (self, 100, -1, error); if (str == NULL) return FALSE; @@ -672,25 +508,26 @@ /* we can flash firmware */ if (g_strcmp0 (lines[i], "altos-loader") == 0) { - fu_device_remove_flag (FU_DEVICE (device), + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); continue; } /* version number */ if (g_str_has_prefix (lines[i], "software-version ")) { - fu_device_set_version (FU_DEVICE (device), lines[i] + 17); + fu_device_set_version (FU_DEVICE (self), lines[i] + 17, + FWUPD_VERSION_FORMAT_TRIPLET); continue; } /* address base and bound */ if (g_str_has_prefix (lines[i], "flash-range ")) { g_auto(GStrv) addrs = g_strsplit (lines[i] + 17, " ", -1); - priv->addr_base = g_ascii_strtoull (addrs[0], NULL, 16); - priv->addr_bound = g_ascii_strtoull (addrs[1], NULL, 16); + self->addr_base = g_ascii_strtoull (addrs[0], NULL, 16); + self->addr_bound = g_ascii_strtoull (addrs[1], NULL, 16); g_debug ("base: %x, bound: %x", - (guint) priv->addr_base, - (guint) priv->addr_bound); + (guint) self->addr_base, + (guint) self->addr_bound); continue; } @@ -701,18 +538,18 @@ return TRUE; } -gboolean -fu_altos_device_probe (FuAltosDevice *device, GError **error) +static gboolean +fu_altos_device_probe (FuDevice *device, GError **error) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuAltosDevice *self = FU_ALTOS_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); /* bootloader uses tty */ - if (priv->kind == FU_ALTOS_DEVICE_KIND_BOOTLOADER) - return fu_altos_device_probe_bootloader (device, error); + if (self->kind == FU_ALTOS_DEVICE_KIND_BOOTLOADER) + return fu_altos_device_probe_bootloader (self, error); /* get version */ - if (priv->kind == FU_ALTOS_DEVICE_KIND_CHAOSKEY) { + if (self->kind == FU_ALTOS_DEVICE_KIND_CHAOSKEY) { const gchar *version_prefix = "ChaosKey-hw-1.0-sw-"; guint8 version_idx; g_autofree gchar *version = NULL; @@ -738,7 +575,8 @@ version); return FALSE; } - fu_device_set_version (FU_DEVICE (device), version + 19); + fu_device_set_version (FU_DEVICE (self), version + 19, + FWUPD_VERSION_FORMAT_TRIPLET); } /* success */ @@ -747,23 +585,21 @@ /* now with kind and usb_device set */ static void -fu_altos_device_init_real (FuAltosDevice *device) +fu_altos_device_init_real (FuAltosDevice *self) { - FuAltosDevicePrivate *priv = GET_PRIVATE (device); - /* allowed, but requires manual bootloader step */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); /* set default vendor */ - fu_device_set_vendor (FU_DEVICE (device), "altusmetrum.org"); + fu_device_set_vendor (FU_DEVICE (self), "altusmetrum.org"); /* set name */ - switch (priv->kind) { + switch (self->kind) { case FU_ALTOS_DEVICE_KIND_BOOTLOADER: - fu_device_set_name (FU_DEVICE (device), "Altos [bootloader]"); + fu_device_set_name (FU_DEVICE (self), "Altos [bootloader]"); break; case FU_ALTOS_DEVICE_KIND_CHAOSKEY: - fu_device_set_name (FU_DEVICE (device), "Altos ChaosKey"); + fu_device_set_name (FU_DEVICE (self), "Altos ChaosKey"); break; default: g_assert_not_reached (); @@ -771,16 +607,32 @@ } /* set one line summary */ - fu_device_set_summary (FU_DEVICE (device), + fu_device_set_summary (FU_DEVICE (self), "A USB hardware random number generator"); /* only the bootloader can do the update */ - if (priv->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { - fu_device_add_flag (FU_DEVICE (device), + if (self->kind != FU_ALTOS_DEVICE_KIND_BOOTLOADER) { + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } } +static void +fu_altos_device_init (FuAltosDevice *self) +{ +} + +static void +fu_altos_device_class_init (FuAltosDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->probe = fu_altos_device_probe; + klass_device->write_firmware = fu_altos_device_write_firmware; + klass_device->read_firmware = fu_altos_device_read_firmware; + object_class->finalize = fu_altos_device_finalize; +} + typedef struct { guint16 vid; guint16 pid; @@ -788,7 +640,7 @@ } FuAltosDeviceVidPid; FuAltosDevice * -fu_altos_device_new (GUsbDevice *usb_device) +fu_altos_device_new (FuUsbDevice *device) { const FuAltosDeviceVidPid vidpids[] = { { 0xfffe, 0x000a, FU_ALTOS_DEVICE_KIND_BOOTLOADER }, @@ -798,17 +650,13 @@ /* set kind */ for (guint j = 0; vidpids[j].vid != 0x0000; j++) { - if (g_usb_device_get_vid (usb_device) == vidpids[j].vid && - g_usb_device_get_pid (usb_device) == vidpids[j].pid) { - FuAltosDevice *device; - FuAltosDevicePrivate *priv; - device = g_object_new (FU_TYPE_ALTOS_DEVICE, - "usb-device", usb_device, - NULL); - priv = GET_PRIVATE (device); - priv->kind = vidpids[j].kind; - fu_altos_device_init_real (device); - return device; + if (fu_usb_device_get_vid (device) == vidpids[j].vid && + fu_usb_device_get_pid (device) == vidpids[j].pid) { + FuAltosDevice *self = g_object_new (FU_TYPE_ALTOS_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + self->kind = vidpids[j].kind; + fu_altos_device_init_real (self); + return self; } } return NULL; diff -Nru fwupd-1.0.6/plugins/altos/fu-altos-device.h fwupd-1.2.10/plugins/altos/fu-altos-device.h --- fwupd-1.0.6/plugins/altos/fu-altos-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/fu-altos-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,41 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ALTOS_DEVICE_H -#define __FU_ALTOS_DEVICE_H - -#include -#include +#pragma once #include "fu-plugin.h" G_BEGIN_DECLS #define FU_TYPE_ALTOS_DEVICE (fu_altos_device_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuAltosDevice, fu_altos_device, FU, ALTOS_DEVICE, FuUsbDevice) - -struct _FuAltosDeviceClass -{ - FuUsbDeviceClass parent_class; -}; +G_DECLARE_FINAL_TYPE (FuAltosDevice, fu_altos_device, FU, ALTOS_DEVICE, FuUsbDevice) typedef enum { FU_ALTOS_DEVICE_KIND_UNKNOWN, @@ -52,19 +28,9 @@ FU_ALTOS_DEVICE_WRITE_FIRMWARE_FLAG_LAST } FuAltosDeviceWriteFirmwareFlag; -FuAltosDevice *fu_altos_device_new (GUsbDevice *usb_device); +FuAltosDevice *fu_altos_device_new (FuUsbDevice *device); FuAltosDeviceKind fu_altos_device_kind_from_string (const gchar *kind); const gchar *fu_altos_device_kind_to_string (FuAltosDeviceKind kind); FuAltosDeviceKind fu_altos_device_get_kind (FuAltosDevice *device); -gboolean fu_altos_device_probe (FuAltosDevice *device, - GError **error); -gboolean fu_altos_device_write_firmware (FuAltosDevice *device, - GBytes *fw, - FuAltosDeviceWriteFirmwareFlag flags, - GError **error); -GBytes *fu_altos_device_read_firmware (FuAltosDevice *device, - GError **error); G_END_DECLS - -#endif /* __FU_ALTOS_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/altos/fu-altos-firmware.c fwupd-1.2.10/plugins/altos/fu-altos-firmware.c --- fwupd-1.0.6/plugins/altos/fu-altos-firmware.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/fu-altos-firmware.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -36,7 +21,10 @@ G_DEFINE_TYPE (FuAltosFirmware, fu_altos_firmware, G_TYPE_OBJECT) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf, elf_end); +#pragma clang diagnostic pop GBytes * fu_altos_firmware_get_data (FuAltosFirmware *self) diff -Nru fwupd-1.0.6/plugins/altos/fu-altos-firmware.h fwupd-1.2.10/plugins/altos/fu-altos-firmware.h --- fwupd-1.0.6/plugins/altos/fu-altos-firmware.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/fu-altos-firmware.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,28 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ALTOS_FIRMWARE_H -#define __FU_ALTOS_FIRMWARE_H - -#include +#pragma once G_BEGIN_DECLS @@ -38,5 +20,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_ALTOS_FIRMWARE_H */ diff -Nru fwupd-1.0.6/plugins/altos/fu-altos-tool.c fwupd-1.2.10/plugins/altos/fu-altos-tool.c --- fwupd-1.0.6/plugins/altos/fu-altos-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/fu-altos-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#include "config.h" - -#include "fu-altos-device.h" - -static void -fu_altos_tool_progress_cb (FuDevice *device, GParamSpec *pspec, gpointer user_data) -{ - g_print ("Written %u%%\n", fu_device_get_progress (device)); -} - -int -main (int argc, char **argv) -{ - gsize len; - g_autofree guint8 *data = NULL; - g_autoptr(FuAltosDevice) dev = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GUsbContext) usb_ctx = NULL; - - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - - /* require filename */ - if (argc != 2) { - g_print ("USAGE: %s \n", argv[0]); - return 1; - } - - /* get the device */ - usb_ctx = g_usb_context_new (&error); - if (usb_ctx == NULL) { - g_print ("Failed to open USB devices: %s\n", error->message); - return 1; - } - g_usb_context_enumerate (usb_ctx); - devices = g_usb_context_get_devices (usb_ctx); - for (guint i = 0; i < devices->len; i++) { - GUsbDevice *usb_dev_tmp = g_ptr_array_index (devices, i); - g_autoptr(FuAltosDevice) dev_tmp = fu_altos_device_new (usb_dev_tmp); - if (dev_tmp == NULL) - continue; - if (fu_altos_device_get_kind (dev_tmp) == FU_ALTOS_DEVICE_KIND_BOOTLOADER) { - dev = g_object_ref (dev_tmp); - break; - } - } - - /* nothing supported */ - if (dev == NULL) { - g_print ("No supported device plugged in!\n"); - return 1; - } - g_debug ("found %s", - fu_altos_device_kind_to_string (fu_altos_device_get_kind (dev))); - - /* open device */ - if (!fu_altos_device_probe (dev, &error)) { - g_print ("Failed to probe device: %s\n", error->message); - return 1; - } - g_print ("Device Firmware Ver: %s\n", fu_device_get_version (FU_DEVICE (dev))); - - /* load firmware file */ - if (!g_file_get_contents (argv[1], (gchar **) &data, &len, &error)) { - g_print ("Failed to load file: %s\n", error->message); - return 1; - } - - /* update with data blob */ - fw = g_bytes_new (data, len); - g_signal_connect (dev, "notify::progress", - G_CALLBACK (fu_altos_tool_progress_cb), NULL); - if (!fu_altos_device_write_firmware (dev, fw, - FU_ALTOS_DEVICE_WRITE_FIRMWARE_FLAG_NONE, - &error)) { - g_print ("Failed to write firmware: %s\n", error->message); - return 1; - } - - return 0; -} diff -Nru fwupd-1.0.6/plugins/altos/fu-plugin-altos.c fwupd-1.2.10/plugins/altos/fu-plugin-altos.c --- fwupd-1.0.6/plugins/altos/fu-plugin-altos.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/fu-plugin-altos.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,45 +1,38 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "fu-altos-device.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.altusmetrum.altos"); +} + gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { + GUsbDevice *usb_device = fu_usb_device_get_dev (device); const gchar *platform_id = NULL; g_autofree gchar *runtime_id = NULL; g_autoptr(FuAltosDevice) dev = NULL; /* get kind */ - dev = fu_altos_device_new (usb_device); + dev = fu_altos_device_new (device); if (dev == NULL) return TRUE; /* get device properties */ - if (!fu_altos_device_probe (dev, error)) + if (!fu_device_probe (FU_DEVICE (dev), error)) return FALSE; /* only the bootloader can do the update */ @@ -51,9 +44,10 @@ if (dev_runtime != NULL) { const gchar *guid = fu_device_get_guid_default (dev_runtime); g_debug ("adding runtime GUID of %s", guid); - fu_device_add_guid (FU_DEVICE (dev), guid); + fu_device_add_counterpart_guid (FU_DEVICE (dev), guid); fu_device_set_version (FU_DEVICE (dev), - fu_device_get_version (dev_runtime)); + fu_device_get_version (dev_runtime), + fu_device_get_version_format (dev_runtime)); } } else { fu_plugin_cache_add (plugin, runtime_id, dev); @@ -78,8 +72,7 @@ /* get data */ fu_device_set_status (dev, FWUPD_STATUS_DEVICE_VERIFY); - blob_fw = fu_altos_device_read_firmware (FU_ALTOS_DEVICE (dev), - error); + blob_fw = fu_device_read_firmware (dev, error); if (blob_fw == NULL) return FALSE; for (guint i = 0; checksum_types[i] != 0; i++) { @@ -98,11 +91,5 @@ GError **error) { fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); - if (!fu_altos_device_write_firmware (FU_ALTOS_DEVICE (dev), - blob_fw, - FU_ALTOS_DEVICE_WRITE_FIRMWARE_FLAG_REBOOT, - error)) { - return FALSE; - } - return TRUE; + return fu_device_write_firmware (dev, blob_fw, flags, error); } diff -Nru fwupd-1.0.6/plugins/altos/meson.build fwupd-1.2.10/plugins/altos/meson.build --- fwupd-1.0.6/plugins/altos/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,11 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginAltos"'] +install_data(['altos.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_altos', + fu_hash, sources : [ 'fu-altos-device.c', 'fu-altos-firmware.c', @@ -13,34 +18,12 @@ ], install : true, install_dir: plugin_dir, - c_args : cargs, - dependencies : [ - gudev, - libelf, - plugin_deps, - ], -) - -executable( - 'fu-altos-tool', - sources : [ - 'fu-altos-device.c', - 'fu-altos-firmware.c', - 'fu-altos-tool.c', - ], - include_directories : [ - include_directories('../..'), - include_directories('../../libfwupd'), - include_directories('../../src'), + link_with : [ + libfwupdprivate, ], + c_args : cargs, dependencies : [ - gudev, libelf, plugin_deps, ], - link_with : [ - fwupd, - libfwupdprivate, - ], - c_args : cargs, ) diff -Nru fwupd-1.0.6/plugins/altos/README.md fwupd-1.2.10/plugins/altos/README.md --- fwupd-1.0.6/plugins/altos/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/altos/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -15,6 +15,25 @@ created so userspace can communicate with the hardware. Commands the bootloader accept are as follows: +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +ELF file format. The firmware image is inserted into the `.text` section. + +This plugin supports the following protocol ID: + + * org.altusmetrum.altos + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1D50&PID_60C6&REV_0001` + * `USB\VID_1D50&PID_60C6` + * `USB\VID_1D50` + ### List Information Command: `l\n` diff -Nru fwupd-1.0.6/plugins/amt/fu-plugin-amt.c fwupd-1.2.10/plugins/amt/fu-plugin-amt.c --- fwupd-1.0.6/plugins/amt/fu-plugin-amt.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/amt/fu-plugin-amt.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,9 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2012 Intel Corporation. All rights reserved. +/* + * Copyright (C) 2012 Intel Corporation. * Copyright (C) 2017 Google, Inc. * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -26,10 +11,9 @@ #include #include #include +#include #include -#include -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" typedef struct { @@ -101,27 +85,26 @@ return TRUE; } -static gssize +static gboolean mei_recv_msg (mei_context *ctx, guchar *buffer, - gssize len, unsigned long timeout, GError **error) + gssize len, guint32 *readsz, unsigned long timeout, GError **error) { gssize rc; - - g_debug ("call read length = %zd", len); rc = read (ctx->fd, buffer, len); if (rc < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "read failed with status %zd %s", - rc, strerror(errno)); - } else { - g_debug ("read succeeded with result %zd", rc); + rc, strerror(errno)); + return FALSE; } - return rc; + if (readsz != NULL) + *readsz = rc; + return TRUE; } -static gssize +static gboolean mei_send_msg (mei_context *ctx, const guchar *buffer, gssize len, unsigned long timeout, GError **error) { @@ -133,7 +116,6 @@ tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000000; - g_debug ("call write length = %zd", len); written = write (ctx->fd, buffer, len); if (written < 0) { g_set_error (error, @@ -141,16 +123,22 @@ FWUPD_ERROR_WRITE, "write failed with status %zd %s", written, strerror(errno)); - return -errno; + return FALSE; + } + if (written != len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "only wrote %" G_GSSIZE_FORMAT " of %" G_GSSIZE_FORMAT, + written, len); + return FALSE; } FD_ZERO(&set); FD_SET(ctx->fd, &set); rc = select (ctx->fd + 1 , &set, NULL, NULL, &tv); - if (rc > 0 && FD_ISSET(ctx->fd, &set)) { - g_debug ("write success"); - return written; - } + if (rc > 0 && FD_ISSET(ctx->fd, &set)) + return TRUE; /* timed out */ if (rc == 0) { @@ -158,7 +146,7 @@ FWUPD_ERROR, FWUPD_ERROR_WRITE, "write failed on timeout with status"); - return 0; + return FALSE; } /* rc < 0 */ @@ -166,7 +154,7 @@ FWUPD_ERROR, FWUPD_ERROR_WRITE, "write failed on select with status %zd", rc); - return rc; + return FALSE; } /*************************************************************************** @@ -269,50 +257,91 @@ mei_context mei_cl; }; -static guint32 -amt_verify_code_versions (const struct amt_host_if_resp_header *resp) +static gboolean +amt_verify_code_versions (const struct amt_host_if_resp_header *resp, GError **error) { struct amt_code_versions *code_ver = (struct amt_code_versions *)resp->data; gsize code_ver_len = resp->header.length - sizeof(guint32); guint32 ver_type_cnt = code_ver_len - sizeof(code_ver->bios) - sizeof(code_ver->count); - if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) - return AMT_STATUS_INTERNAL_ERROR; + if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid offset"); + return FALSE; + } for (guint32 i = 0; i < code_ver->count; i++) { guint32 len = code_ver->versions[i].description.length; - if (len > AMT_UNICODE_STRING_LEN) - return AMT_STATUS_INTERNAL_ERROR; + if (len > AMT_UNICODE_STRING_LEN) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "string too large"); + return FALSE; + } len = code_ver->versions[i].version.length; if (code_ver->versions[i].version.string[len] != '\0' || - len != strlen(code_ver->versions[i].version.string)) - return AMT_STATUS_INTERNAL_ERROR; + len != strlen(code_ver->versions[i].version.string)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "string was invalid size"); + return FALSE; + } } - return AMT_STATUS_SUCCESS; + return TRUE; } -static guint32 -amt_verify_response_header (guint32 command, - const struct amt_host_if_msg_header *resp_hdr, - guint32 response_size) +static gboolean +amt_status_set_error (guint32 status, GError **error) { - if (response_size < sizeof(struct amt_host_if_resp_header)) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (response_size != (resp_hdr->length + - sizeof(struct amt_host_if_msg_header))) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->command != command) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->_reserved != 0) { - return AMT_STATUS_INTERNAL_ERROR; - } else if (resp_hdr->version.major != AMT_MAJOR_VERSION || - resp_hdr->version.minor < AMT_MINOR_VERSION) { - return AMT_STATUS_INTERNAL_ERROR; + if (status == AMT_STATUS_SUCCESS) + return TRUE; + if (status == AMT_STATUS_INTERNAL_ERROR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "internal error"); + return FALSE; + } + if (status == AMT_STATUS_NOT_READY) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "not ready"); + return FALSE; + } + if (status == AMT_STATUS_INVALID_AMT_MODE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid AMT mode"); + return FALSE; + } + if (status == AMT_STATUS_INVALID_MESSAGE_LENGTH) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid message length"); + return FALSE; } - return AMT_STATUS_SUCCESS; + if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Intel AMT is disabled"); + return FALSE; + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unknown error"); + return FALSE; } -static guint32 +static gboolean amt_host_if_call (mei_context *mei_cl, const guchar *command, gssize command_sz, @@ -324,72 +353,106 @@ { guint32 in_buf_sz; guint32 out_buf_sz; - gssize written; - guint32 status; struct amt_host_if_resp_header *msg_hdr; in_buf_sz = mei_cl->buf_size; *read_buf = (guint8 *) g_malloc0 (in_buf_sz); msg_hdr = (struct amt_host_if_resp_header *) *read_buf; - written = mei_send_msg (mei_cl, command, command_sz, send_timeout, error); - if (written != command_sz) - return AMT_STATUS_INTERNAL_ERROR; - - out_buf_sz = mei_recv_msg (mei_cl, *read_buf, in_buf_sz, 2000, error); - if (out_buf_sz <= 0) - return AMT_STATUS_HOST_IF_EMPTY_RESPONSE; - - status = msg_hdr->status; - if (status != AMT_STATUS_SUCCESS) - return status; - - status = amt_verify_response_header(rcmd, &msg_hdr->header, out_buf_sz); - if (status != AMT_STATUS_SUCCESS) - return status; - - if (expected_sz && expected_sz != out_buf_sz) - return AMT_STATUS_INTERNAL_ERROR; - - return AMT_STATUS_SUCCESS; + if (!mei_send_msg (mei_cl, command, command_sz, send_timeout, error)) + return FALSE; + if (!mei_recv_msg (mei_cl, *read_buf, in_buf_sz, &out_buf_sz, 2000, error)) + return FALSE; + if (out_buf_sz <= 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "empty response"); + return FALSE; + } + if (expected_sz && expected_sz != out_buf_sz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "expected %u but got %" G_GUINT32_FORMAT, + expected_sz, out_buf_sz); + return FALSE; + } + if (!amt_status_set_error (msg_hdr->status, error)) + return FALSE; + if (out_buf_sz < sizeof(struct amt_host_if_resp_header)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: too small"); + return FALSE; + } + if (out_buf_sz != (msg_hdr->header.length + + sizeof(struct amt_host_if_msg_header))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: headerlen"); + return FALSE; + } + if (msg_hdr->header.command != rcmd) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: rcmd"); + return FALSE; + } + if (msg_hdr->header._reserved != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: reserved"); + return FALSE; + } + if (msg_hdr->header.version.major != AMT_MAJOR_VERSION || + msg_hdr->header.version.minor < AMT_MINOR_VERSION) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid response: version"); + return FALSE; + } + return TRUE; } -static guint32 +static gboolean amt_get_provisioning_state (mei_context *mei_cl, guint8 *state, GError **error) { g_autofree struct amt_host_if_resp_header *response = NULL; - guint32 status; - - status = amt_host_if_call (mei_cl, - (const guchar *)&PROVISIONING_STATE_REQUEST, - sizeof(PROVISIONING_STATE_REQUEST), - (guint8 **)&response, - AMT_HOST_IF_PROVISIONING_STATE_RESPONSE, 0, - 5000, error); - if (status != AMT_STATUS_SUCCESS) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Unable to get provisioning state"); + if (!amt_host_if_call (mei_cl, + (const guchar *)&PROVISIONING_STATE_REQUEST, + sizeof(PROVISIONING_STATE_REQUEST), + (guint8 **)&response, + AMT_HOST_IF_PROVISIONING_STATE_RESPONSE, 0, + 5000, error)) { + g_prefix_error (error, "unable to get provisioning state: "); return FALSE; } - *state = response->data[0]; return TRUE; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(mei_context, mei_context_free) +#pragma clang diagnostic pop static FuDevice * fu_plugin_amt_create_device (GError **error) { - gchar guid_buf[37]; - guint32 status; guint8 state; struct amt_code_versions ver; - uuid_t uu; + fwupd_guid_t uu; + g_autofree gchar *guid_buf = NULL; g_autofree struct amt_host_if_resp_header *response = NULL; g_autoptr(FuDevice) dev = NULL; + g_autoptr(GString) version_bl = g_string_new (NULL); + g_autoptr(GString) version_fw = g_string_new (NULL); g_autoptr(mei_context) ctx = g_new0 (mei_context, 1); const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \ @@ -400,37 +463,28 @@ return NULL; /* check version */ - status = amt_host_if_call (ctx, - (const guchar *) &CODE_VERSION_REQ, - sizeof(CODE_VERSION_REQ), - (guint8 **) &response, - AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0, - 5000, - error); - if (status != AMT_STATUS_SUCCESS) - return NULL; - status = amt_verify_code_versions (response); - if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Intel AMT is disabled"); + if (!amt_host_if_call (ctx, + (const guchar *) &CODE_VERSION_REQ, + sizeof(CODE_VERSION_REQ), + (guint8 **) &response, + AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0, + 5000, + error)) { + g_prefix_error (error, "Failed to check version: "); return NULL; } - if (status != AMT_STATUS_SUCCESS) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Failed to verify code versions"); + if (!amt_verify_code_versions (response, error)) { + g_prefix_error (error, "failed to verify code versions: "); return NULL; } memcpy (&ver, response->data, sizeof(struct amt_code_versions)); dev = fu_device_new (); - fu_device_set_id (dev, "/dev/mei"); + fu_device_set_id (dev, "/dev/mei0"); fu_device_set_vendor (dev, "Intel Corporation"); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_icon (dev, "computer"); + fu_device_add_parent_guid (dev, "main-system-firmware"); if (!amt_get_provisioning_state (ctx, &state, error)) return NULL; switch (state) { @@ -452,24 +506,44 @@ /* add guid */ memcpy (&uu, &ctx->guid, 16); - uuid_unparse (uu, guid_buf); + guid_buf = fwupd_guid_to_string ((const fwupd_guid_t *) &uu, FWUPD_GUID_FLAG_NONE); fu_device_add_guid (dev, guid_buf); /* get version numbers */ for (guint i = 0; i < ver.count; i++) { if (g_strcmp0 (ver.versions[i].description.string, "AMT") == 0) { - fu_device_set_version (dev, ver.versions[i].version.string); + g_string_append (version_fw, ver.versions[i].version.string); + continue; + } + if (g_strcmp0 (ver.versions[i].description.string, "Recovery Version") == 0) { + g_string_append (version_bl, ver.versions[i].version.string); + continue; + } + if (g_strcmp0 (ver.versions[i].description.string, "Build Number") == 0) { + g_string_append_printf (version_fw, ".%s", + ver.versions[i].version.string); continue; } - if (g_strcmp0 (ver.versions[i].description.string, - "Recovery Version") == 0) { - fu_device_set_version_bootloader (dev, ver.versions[i].version.string); + if (g_strcmp0 (ver.versions[i].description.string, "Recovery Build Num") == 0) { + g_string_append_printf (version_bl, ".%s", + ver.versions[i].version.string); continue; } } + if (version_fw->len > 0) + fu_device_set_version (dev, version_fw->str, FWUPD_VERSION_FORMAT_INTEL_ME); + if (version_bl->len > 0) + fu_device_set_version_bootloader (dev, version_bl->str); + return g_steal_pointer (&dev); } +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { diff -Nru fwupd-1.0.6/plugins/amt/meson.build fwupd-1.2.10/plugins/amt/meson.build --- fwupd-1.0.6/plugins/amt/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/amt/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginAmt"'] shared_module('fu_plugin_amt', + fu_hash, sources : [ 'fu-plugin-amt.c', ], @@ -11,9 +12,11 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - uuid, ], ) diff -Nru fwupd-1.0.6/plugins/amt/README.md fwupd-1.2.10/plugins/amt/README.md --- fwupd-1.0.6/plugins/amt/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/amt/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -15,3 +15,8 @@ That tool in turn is heavily based on mei-amt-version from samples/mei in the Linux source tree and copyright Intel Corporation. + +GUID Generation +--------------- + +These devices use the existing GUID provided by the AMT host interface. diff -Nru fwupd-1.0.6/plugins/ata/ata.quirk fwupd-1.2.10/plugins/ata/ata.quirk --- fwupd-1.0.6/plugins/ata/ata.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/ata.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru fwupd-1.0.6/plugins/ata/fu-ata-device.c fwupd-1.2.10/plugins/ata/fu-ata-device.c --- fwupd-1.0.6/plugins/ata/fu-ata-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/fu-ata-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,728 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-ata-device.h" +#include "fu-chunk.h" + +#define FU_ATA_IDENTIFY_SIZE 512 /* bytes */ +#define FU_ATA_BLOCK_SIZE 512 /* bytes */ + +struct ata_tf { + guint8 dev; + guint8 command; + guint8 error; + guint8 status; + guint8 feat; + guint8 nsect; + guint8 lbal; + guint8 lbam; + guint8 lbah; +}; + +#define ATA_USING_LBA (1 << 6) +#define ATA_STAT_DRQ (1 << 3) +#define ATA_STAT_ERR (1 << 0) + +#define ATA_OP_IDENTIFY 0xec +#define ATA_OP_FLUSH_CACHE 0xe7 +#define ATA_OP_DOWNLOAD_MICROCODE 0x92 +#define ATA_OP_STANDBY_IMMEDIATE 0xe0 + +#define ATA_SUBCMD_MICROCODE_OBSOLETE 0x01 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE 0x03 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK 0x07 +#define ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS 0x0e +#define ATA_SUBCMD_MICROCODE_ACTIVATE 0x0f + +#define SG_CHECK_CONDITION 0x02 +#define SG_DRIVER_SENSE 0x08 + +#define SG_ATA_12 0xa1 +#define SG_ATA_12_LEN 12 + +#define SG_ATA_PROTO_NON_DATA (3 << 1) +#define SG_ATA_PROTO_PIO_IN (4 << 1) +#define SG_ATA_PROTO_PIO_OUT (5 << 1) + +enum { + SG_CDB2_TLEN_NODATA = 0 << 0, + SG_CDB2_TLEN_FEAT = 1 << 0, + SG_CDB2_TLEN_NSECT = 2 << 0, + + SG_CDB2_TLEN_BYTES = 0 << 2, + SG_CDB2_TLEN_SECTORS = 1 << 2, + + SG_CDB2_TDIR_TO_DEV = 0 << 3, + SG_CDB2_TDIR_FROM_DEV = 1 << 3, + + SG_CDB2_CHECK_COND = 1 << 5, +}; + +struct _FuAtaDevice { + FuUdevDevice parent_instance; + guint pci_depth; + guint usb_depth; + gint fd; + guint16 transfer_blocks; + guint8 transfer_mode; +}; + +G_DEFINE_TYPE (FuAtaDevice, fu_ata_device, FU_TYPE_UDEV_DEVICE) + +#ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop +#endif + +guint8 +fu_ata_device_get_transfer_mode (FuAtaDevice *self) +{ + return self->transfer_mode; +} + +guint16 +fu_ata_device_get_transfer_blocks (FuAtaDevice *self) +{ + return self->transfer_blocks; +} + +static gchar * +fu_ata_device_get_string (const guint16 *buf, guint start, guint end) +{ + g_autoptr(GString) str = g_string_new (NULL); + for (guint i = start; i <= end; i++) { + g_string_append_c (str, (gchar) (buf[i] >> 8)); + g_string_append_c (str, (gchar) (buf[i] & 0xff)); + } + + /* remove whitespace before returning */ + if (str->len > 0) { + g_strstrip (str->str); + if (str->str[0] == '\0') + return NULL; + } + return g_string_free (g_steal_pointer (&str), FALSE); +} + +static void +fu_ata_device_to_string (FuDevice *device, GString *str) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + g_string_append (str, " FuAtaDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", self->fd); + g_string_append_printf (str, " transfer-mode:\t0x%x\n", (guint) self->transfer_mode); + g_string_append_printf (str, " transfer-size:\t0x%x\n", (guint) self->transfer_blocks); + g_string_append_printf (str, " pci-depth:\t\t%u\n", self->pci_depth); + g_string_append_printf (str, " usb-depth:\t\t%u\n", self->usb_depth); +} + +/* https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices */ +static gchar * +fu_ata_device_pad_string_for_id (const gchar *name) +{ + GString *str = g_string_new (name); + fu_common_string_replace (str, " ", "_"); + for (guint i = str->len; i < 40; i++) + g_string_append_c (str, '_'); + return g_string_free (str, FALSE); +} + +static gchar * +fu_ata_device_get_guid_safe (const guint16 *buf, guint16 addr_start) +{ + if (!fu_common_guid_is_plausible ((guint8 *) (buf + addr_start))) + return NULL; + return fwupd_guid_to_string ((const fwupd_guid_t *) (buf + addr_start), + FWUPD_GUID_FLAG_MIXED_ENDIAN); +} + +static void +fu_ata_device_parse_id_maybe_dell (FuAtaDevice *self, const guint16 *buf) +{ + g_autofree gchar *component_id = NULL; + g_autofree gchar *guid_efi = NULL; + g_autofree gchar *guid_id = NULL; + g_autofree gchar *guid = NULL; + + /* add extra component ID if set */ + component_id = fu_ata_device_get_string (buf, 137, 140); + if (component_id == NULL || + !g_str_is_ascii (component_id) || + strlen (component_id) < 6) { + g_debug ("invalid component ID, skipping"); + return; + } + + /* do not add the FuUdevDevice instance IDs as generic firmware + * should not be used on these OEM-specific devices */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS); + + /* add instance ID *and* GUID as using no-auto-instance-ids */ + guid_id = g_strdup_printf ("STORAGE-DELL-%s", component_id); + fu_device_add_instance_id (FU_DEVICE (self), guid_id); + guid = fwupd_guid_hash_string (guid_id); + fu_device_add_guid (FU_DEVICE (self), guid); + + /* also add the EFI GUID */ + guid_efi = fu_ata_device_get_guid_safe (buf, 129); + if (guid_efi != NULL) + fu_device_add_guid (FU_DEVICE (self), guid_efi); +} + +static gboolean +fu_ata_device_parse_id (FuAtaDevice *self, const guint8 *buf, gsize sz, GError **error) +{ + FuDevice *device = FU_DEVICE (self); + guint16 xfer_min = 1; + guint16 xfer_max = 0xffff; + guint16 id[FU_ATA_IDENTIFY_SIZE/2]; + g_autofree gchar *name_pad = NULL; + g_autofree gchar *sku = NULL; + + /* check size */ + if (sz != FU_ATA_IDENTIFY_SIZE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "ID incorrect size, got 0x%02x", + (guint) sz); + return FALSE; + } + + /* read LE buffer */ + for (guint i = 0; i < sz / 2; i++) + id[i] = fu_common_read_uint16 (buf + (i * 2), G_LITTLE_ENDIAN); + + /* verify drive correctly supports DOWNLOAD_MICROCODE */ + if (!(id[83] & 1 && id[86] & 1)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "DOWNLOAD_MICROCODE not supported by device"); + return FALSE; + } + + fu_ata_device_parse_id_maybe_dell (self, id); + + /* firmware will be applied when the device restarts */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + + /* the newer, segmented transfer mode */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE || + self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS) { + xfer_min = id[234]; + if (xfer_min == 0x0 || xfer_min == 0xffff) + xfer_min = 1; + xfer_max = id[235]; + if (xfer_max == 0x0 || xfer_max == 0xffff) + xfer_max = xfer_min; + } + + /* fall back to a sane block size */ + if (self->transfer_blocks == 0x0) + self->transfer_blocks = xfer_min; + else if (self->transfer_blocks == 0xffff) + self->transfer_blocks = xfer_max; + + /* get values in case the kernel didn't */ + if (fu_device_get_serial (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 10, 19); + if (tmp != NULL) + fu_device_set_serial (device, tmp); + } + if (fu_device_get_name (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 27, 46); + if (tmp != NULL) + fu_device_set_name (device, tmp); + } + if (fu_device_get_version (device) == NULL) { + g_autofree gchar *tmp = NULL; + tmp = fu_ata_device_get_string (id, 23, 26); + if (tmp != NULL) + fu_device_set_version (device, tmp, FWUPD_VERSION_FORMAT_PLAIN); + } else { + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_PLAIN); + } + + /* 8 byte additional product identifier == SKU? */ + sku = fu_ata_device_get_string (id, 170, 173); + if (sku != NULL) + g_debug ("SKU=%s", sku); + + /* if we have vendor defined identify blocks don't add generic GUID */ + if (fu_device_get_guids (device)->len != 0) + return TRUE; + + /* add extra GUIDs if none detected from identify block */ + name_pad = fu_ata_device_pad_string_for_id (fu_device_get_name (device)); + if (name_pad != NULL && + fu_device_get_version (device) != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("IDE\\%s%s", name_pad, + fu_device_get_version (device)); + fu_device_add_instance_id (device, tmp); + } + if (name_pad != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("IDE\\0%s", name_pad); + fu_device_add_instance_id (device, tmp); + } + + /* add the name fallback */ + fu_device_add_instance_id (device, fu_device_get_name (device)); + + return TRUE; +} + +static gboolean +fu_ata_device_open (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + self->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDONLY); + if (self->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s: %s", + g_udev_device_get_device_file (udev_device), + strerror (errno)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_probe (FuUdevDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "scsi", error)) + return FALSE; + + /* look at the PCI and USB depth to work out if in an external enclosure */ + self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); + self->usb_depth = fu_udev_device_get_slot_depth (device, "usb"); + if (self->pci_depth <= 2 && self->usb_depth <= 2) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + + return TRUE; +} + +static guint64 +fu_ata_device_tf_to_pack_id (struct ata_tf *tf) +{ + guint32 lba24 = (tf->lbah << 16) | (tf->lbam << 8) | (tf->lbal); + guint32 lbah = tf->dev & 0x0f; + return (((guint64) lbah) << 24) | (guint64) lba24; +} + +static gboolean +fu_ata_device_command (FuAtaDevice *self, struct ata_tf *tf, + gint dxfer_direction, guint timeout_ms, + guint8 *dxferp, gsize dxfer_len, GError **error) +{ + guint8 cdb[SG_ATA_12_LEN] = { 0x0 }; + guint8 sb[32] = { 0x0 }; + sg_io_hdr_t io_hdr = { 0x0 }; + + /* map _TO_DEV to PIO mode */ + if (dxfer_direction == SG_DXFER_TO_DEV) + cdb[1] = SG_ATA_PROTO_PIO_OUT; + else if (dxfer_direction == SG_DXFER_FROM_DEV) + cdb[1] = SG_ATA_PROTO_PIO_IN; + else + cdb[1] = SG_ATA_PROTO_NON_DATA; + + /* libata workaround: don't demand sense data for IDENTIFY */ + if (dxfer_len > 0) { + cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS; + cdb[2] |= dxfer_direction == SG_DXFER_TO_DEV ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV; + } else { + cdb[2] = SG_CDB2_CHECK_COND; + } + + /* populate non-LBA48 CDB */ + cdb[0] = SG_ATA_12; + cdb[3] = tf->feat; + cdb[4] = tf->nsect; + cdb[5] = tf->lbal; + cdb[6] = tf->lbam; + cdb[7] = tf->lbah; + cdb[8] = tf->dev; + cdb[9] = tf->command; + fu_common_dump_raw (G_LOG_DOMAIN, "CBD", cdb, sizeof(cdb)); + if (dxfer_direction == SG_DXFER_TO_DEV && dxferp != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "outgoing_data", + dxferp, dxfer_len); + } + + /* hit hardware */ + io_hdr.interface_id = 'S'; + io_hdr.mx_sb_len = sizeof(sb); + io_hdr.dxfer_direction = dxfer_direction; + io_hdr.dxfer_len = dxfer_len; + io_hdr.dxferp = dxferp; + io_hdr.cmdp = cdb; + io_hdr.cmd_len = SG_ATA_12_LEN; + io_hdr.sbp = sb; + io_hdr.pack_id = fu_ata_device_tf_to_pack_id (tf); + io_hdr.timeout = timeout_ms; + if (ioctl (self->fd, SG_IO, &io_hdr) == -1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SG_IO not supported: %s", + strerror (errno)); + return FALSE; + } + g_debug ("ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x", + io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); + fu_common_dump_raw (G_LOG_DOMAIN, "SB", sb, sizeof(sb)); + + /* error check */ + if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad status: 0x%x", io_hdr.status); + return FALSE; + } + if (io_hdr.host_status) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad host status: 0x%x", io_hdr.host_status); + return FALSE; + } + if (io_hdr.driver_status && (io_hdr.driver_status != SG_DRIVER_SENSE)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad driver status: 0x%x", io_hdr.driver_status); + return FALSE; + } + + /* repopulate ata_tf */ + tf->error = sb[8 + 3]; + tf->nsect = sb[8 + 5]; + tf->lbal = sb[8 + 7]; + tf->lbam = sb[8 + 9]; + tf->lbah = sb[8 + 11]; + tf->dev = sb[8 + 12]; + tf->status = sb[8 + 13]; + g_debug ("ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x", + io_hdr.cmd_len, tf->status, tf->error, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->dev); + + /* io error */ + if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "I/O error, ata_op=0x%02x ata_status=0x%02x ata_error=0x%02x", + tf->command, tf->status, tf->error); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_setup (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + struct ata_tf tf = { 0x0 }; + guint8 id[FU_ATA_IDENTIFY_SIZE]; + + /* get ID block */ + tf.dev = ATA_USING_LBA; + tf.command = ATA_OP_IDENTIFY; + tf.nsect = 1; /* 512 bytes */ + if (!fu_ata_device_command (self, &tf, SG_DXFER_FROM_DEV, 1000, + id, sizeof(id), error)) { + g_prefix_error (error, "failed to IDENTIFY"); + return FALSE; + } + if (!fu_ata_device_parse_id (self, id, sizeof(id), error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_activate (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + struct ata_tf tf = { 0x0 }; + + + /* flush cache and put drive in standby to prepare to activate */ + tf.dev = ATA_USING_LBA; + tf.command = ATA_OP_FLUSH_CACHE; + if (!fu_ata_device_command (self, &tf, SG_DXFER_NONE, + 120 * 1000, /* a long time! */ + NULL, 0, error)) { + g_prefix_error (error, "failed to flush cache immediate: "); + return FALSE; + } + tf.command = ATA_OP_STANDBY_IMMEDIATE; + if (!fu_ata_device_command (self, &tf, SG_DXFER_NONE, + 120 * 1000, /* a long time! */ + NULL, 0, error)) { + g_prefix_error (error, "failed to standby immediate: "); + return FALSE; + } + + /* load the new firmware */ + tf.dev = 0xa0 | ATA_USING_LBA; + tf.command = ATA_OP_DOWNLOAD_MICROCODE; + tf.feat = ATA_SUBCMD_MICROCODE_ACTIVATE; + if (!fu_ata_device_command (self, &tf, SG_DXFER_NONE, + 120 * 1000, /* a long time! */ + NULL, 0, error)) { + g_prefix_error (error, "failed to activate firmware: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_ata_device_close (FuDevice *device, GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = 0; + return TRUE; +} + +static gboolean +fu_ata_device_fw_download (FuAtaDevice *self, + guint32 idx, + guint32 addr, + const guint8 *data, + guint32 data_sz, + GError **error) +{ + struct ata_tf tf = { 0x0 }; + guint32 block_count = data_sz / FU_ATA_BLOCK_SIZE; + guint32 buffer_offset = addr / FU_ATA_BLOCK_SIZE; + + /* write block */ + tf.dev = 0xa0 | ATA_USING_LBA; + tf.command = ATA_OP_DOWNLOAD_MICROCODE; + tf.feat = self->transfer_mode; + tf.nsect = block_count & 0xff; + tf.lbal = block_count >> 8; + tf.lbam = buffer_offset & 0xff; + tf.lbah = buffer_offset >> 8; + if (!fu_ata_device_command (self, &tf, SG_DXFER_TO_DEV, + 120 * 1000, /* a long time! */ + (guint8 *) data, data_sz, error)) { + g_prefix_error (error, "failed to write firmware @0x%0x", + (guint) addr); + return FALSE; + } + + /* check drive status */ + if (tf.nsect == 0x0) + return TRUE; + + /* drive wants more data, or thinks it is all done */ + if (tf.nsect == 0x1 || tf.nsect == 0x2) + return TRUE; + + /* the offset was set up incorrectly */ + if (tf.nsect == 0x4) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "alignment error"); + return FALSE; + } + + /* other error */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown return code 0x%02x", + tf.nsect); + return FALSE; +} + +static gboolean +fu_ata_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + guint32 chunksz = (guint32) self->transfer_blocks * FU_ATA_BLOCK_SIZE; + guint max_size = 0xffff * FU_ATA_BLOCK_SIZE; + g_autoptr(GPtrArray) chunks = NULL; + + /* only one block allowed */ + if (self->transfer_mode == ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) + max_size = 0xffff; + + /* check is valid */ + if (g_bytes_get_size (fw) > max_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is too large, maximum size is %u", + max_size); + return FALSE; + } + if (g_bytes_get_size (fw) % FU_ATA_BLOCK_SIZE != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware is not multiple of block size %i", + FU_ATA_BLOCK_SIZE); + return FALSE; + } + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, 0x00, 0x00, chunksz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_ata_device_fw_download (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) { + g_prefix_error (error, "failed to write chunk %u: ", i); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len + 1); + } + + /* success! */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + fu_device_set_progress (device, 100); + return TRUE; +} + +static gboolean +fu_ata_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuAtaDevice *self = FU_ATA_DEVICE (device); + if (g_strcmp0 (key, "AtaTransferMode") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS_ACTIVATE && + tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS && + tmp != ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNK) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "AtaTransferMode only supports " + "values 0x3, 0x7 or 0xe"); + return FALSE; + } + self->transfer_mode = (guint8) tmp; + return TRUE; + } + if (g_strcmp0 (key, "AtaTransferBlocks") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp > 0xffff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "AtaTransferBlocks only supports " + "values <= 0xffff"); + return FALSE; + } + self->transfer_blocks = (guint16) tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_ata_device_init (FuAtaDevice *self) +{ + /* we chose this default as _DOWNLOAD_CHUNKS_ACTIVATE applies the + * firmware straight away and the kernel might not like the unexpected + * ATA restart and panic */ + self->transfer_mode = ATA_SUBCMD_MICROCODE_DOWNLOAD_CHUNKS; + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "ATA Drive"); + fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); +} + +static void +fu_ata_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_ata_device_parent_class)->finalize (object); +} + +static void +fu_ata_device_class_init (FuAtaDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_ata_device_finalize; + klass_device->to_string = fu_ata_device_to_string; + klass_device->set_quirk_kv = fu_ata_device_set_quirk_kv; + klass_device->open = fu_ata_device_open; + klass_device->setup = fu_ata_device_setup; + klass_device->activate = fu_ata_device_activate; + klass_device->close = fu_ata_device_close; + klass_device->write_firmware = fu_ata_device_write_firmware; + klass_udev_device->probe = fu_ata_device_probe; +} + +FuAtaDevice * +fu_ata_device_new (FuUdevDevice *device) +{ + FuAtaDevice *self = g_object_new (FU_TYPE_ATA_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} + +FuAtaDevice * +fu_ata_device_new_from_blob (const guint8 *buf, gsize sz, GError **error) +{ + g_autoptr(FuAtaDevice) self = g_object_new (FU_TYPE_ATA_DEVICE, NULL); + if (!fu_ata_device_parse_id (self, buf, sz, error)) + return NULL; + return g_steal_pointer (&self); +} diff -Nru fwupd-1.0.6/plugins/ata/fu-ata-device.h fwupd-1.2.10/plugins/ata/fu-ata-device.h --- fwupd-1.0.6/plugins/ata/fu-ata-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/fu-ata-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_ATA_DEVICE (fu_ata_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuAtaDevice, fu_ata_device, FU, ATA_DEVICE, FuUdevDevice) + +FuAtaDevice *fu_ata_device_new (FuUdevDevice *device); +FuAtaDevice *fu_ata_device_new_from_blob (const guint8 *buf, + gsize sz, + GError **error); + +/* for self tests */ +guint8 fu_ata_device_get_transfer_mode (FuAtaDevice *self); +guint16 fu_ata_device_get_transfer_blocks (FuAtaDevice *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/ata/fu-plugin-ata.c fwupd-1.2.10/plugins/ata/fu-plugin-ata.c --- fwupd-1.0.6/plugins/ata/fu-plugin-ata.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/fu-plugin-ata.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-ata-device.h" + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (device); + g_autoptr(FuAtaDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* interesting device? */ + if (udev_device == NULL) + return TRUE; + if (g_strcmp0 (g_udev_device_get_subsystem (udev_device), "block") != 0) + return TRUE; + if (g_strcmp0 (g_udev_device_get_devtype (udev_device), "disk") != 0) + return TRUE; + if (!g_udev_device_get_property_as_boolean (udev_device, "ID_ATA_SATA")) + return TRUE; + if (!g_udev_device_get_property_as_boolean (udev_device, "ID_ATA_DOWNLOAD_MICROCODE")) + return TRUE; + + dev = fu_ata_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "block"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.t13.ata"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +gboolean +fu_plugin_activate (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_activate (device, error); +} diff -Nru fwupd-1.0.6/plugins/ata/fu-self-test.c fwupd-1.2.10/plugins/ata/fu-self-test.c --- fwupd-1.0.6/plugins/ata/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-ata-device.h" +#include "fu-test.h" + +static void +fu_ata_id_func (void) +{ + gboolean ret; + gsize sz; + g_autofree gchar *data = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAtaDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + path = fu_test_get_filename (TESTDATADIR, "StarDrive-SBFM61.2.bin"); + g_assert_nonnull (path); + ret = g_file_get_contents (path, &data, &sz, &error); + g_assert_no_error (error); + g_assert (ret); + dev = fu_ata_device_new_from_blob ((guint8 *)data, sz, &error); + g_assert_no_error (error); + g_assert_nonnull (dev); + g_assert_cmpint (fu_ata_device_get_transfer_mode (dev), ==, 0xe); + g_assert_cmpint (fu_ata_device_get_transfer_blocks (dev), ==, 0x1); + g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), ==, "A45A078A198600476509"); + g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), ==, "SATA SSD"); + g_assert_cmpstr (fu_device_get_version (FU_DEVICE (dev)), ==, "SBFM61.2"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/fwupd/id", fu_ata_id_func); + return g_test_run (); +} diff -Nru fwupd-1.0.6/plugins/ata/meson.build fwupd-1.2.10/plugins/ata/meson.build --- fwupd-1.0.6/plugins/ata/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,59 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAta"'] + +install_data([ + 'ata.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_ata', + fu_hash, + sources : [ + 'fu-plugin-ata.c', + 'fu-ata-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + libfwupdprivate, + ], + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'ata-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-ata-device.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../..'), + include_directories('../../libfwupd'), + include_directories('../../src'), + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('ata-self-test', e) +endif diff -Nru fwupd-1.0.6/plugins/ata/README.md fwupd-1.2.10/plugins/ata/README.md --- fwupd-1.0.6/plugins/ata/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ata/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,44 @@ +ATA +=== + +Introduction +------------ + +This plugin allows updating ATA/ATAPI storage hardware. Devices are enumerated +from the block devices and if ID_ATA_DOWNLOAD_MICROCODE is supported they can +be updated with appropriate firmware file. + +Updating ATA devices is more dangerous than other hardware such as DFU or NVMe +and should be tested carefully with the help of the drive vendor. + +The device GUID is read from the trimmed model string. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.t13.ata + +GUID Generation +--------------- + +These device use the Microsoft DeviceInstanceId values, e.g. + + * `IDE\VENDOR[40]REVISION[8]` + * `IDE\0VENDOR[40]` + +See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices +for more details. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|-------------------------------------------|-----------------------| +| `AtaTransferBlocks` | Blocks to transfer, or `0xffff` for max | 1.2.4 | +| `AtaTransferMode` | The transfer mode, `0x3`, `0x7` or `0xe` | 1.2.4 | Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/ata/tests/StarDrive-SBFM61.2.bin and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/ata/tests/StarDrive-SBFM61.2.bin differ diff -Nru fwupd-1.0.6/plugins/colorhug/colorhug.quirk fwupd-1.2.10/plugins/colorhug/colorhug.quirk --- fwupd-1.0.6/plugins/colorhug/colorhug.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/colorhug.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,55 @@ +# ColorHug1 +[DeviceInstanceId=USB\VID_273F&PID_1000] +Plugin = colorhug +Flags = is-bootloader +Guid = 40338ceb-b966-4eae-adae-9c32edfcc484 +FirmwareSizeMin = 0x2000 +FirmwareSizeMax = 0x8000 +CounterpartGuid = USB\VID_273F&PID_1001 +InstallDuration = 8 + +[DeviceInstanceId=USB\VID_273F&PID_1001] +Plugin = colorhug +Flags = none +Summary = An open source display colorimeter +Icon = colorimeter-colorhug +Guid = 40338ceb-b966-4eae-adae-9c32edfcc484 +CounterpartGuid = USB\VID_273F&PID_1000 +InstallDuration = 8 + +# ColorHug2 +[DeviceInstanceId=USB\VID_273F&PID_1004] +Plugin = colorhug +Flags = none +Summary = An open source display colorimeter +Icon = colorimeter-colorhug +Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad +FirmwareSizeMin = 0x2000 +FirmwareSizeMax = 0x8000 +CounterpartGuid = USB\VID_273F&PID_1005 +InstallDuration = 8 + +[DeviceInstanceId=USB\VID_273F&PID_1005] +Plugin = colorhug +Flags = is-bootloader +Guid = 2082b5e0-7a64-478a-b1b2-e3404fab6dad +CounterpartGuid = USB\VID_273F&PID_1004 +InstallDuration = 8 + +# ColorHugALS +[DeviceInstanceId=USB\VID_273F&PID_1007] +Plugin = colorhug +Flags = halfsize,none +Summary = An open source ambient light sensor +Guid = 84f40464-9272-4ef7-9399-cd95f12da696 +FirmwareSizeMin = 0x1000 +FirmwareSizeMax = 0x4000 +CounterpartGuid = USB\VID_273F&PID_1006 +InstallDuration = 5 + +[DeviceInstanceId=USB\VID_273F&PID_1006] +Plugin = colorhug +Flags = halfsize,is-bootloader +Guid = 84f40464-9272-4ef7-9399-cd95f12da696 +CounterpartGuid = USB\VID_273F&PID_1007 +InstallDuration = 5 diff -Nru fwupd-1.0.6/plugins/colorhug/fu-colorhug-common.c fwupd-1.2.10/plugins/colorhug/fu-colorhug-common.c --- fwupd-1.0.6/plugins/colorhug/fu-colorhug-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/fu-colorhug-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-colorhug-common.h" + +const gchar * +ch_strerror (ChError error_enum) +{ + if (error_enum == CH_ERROR_NONE) + return "Success"; + if (error_enum == CH_ERROR_UNKNOWN_CMD) + return "Unknown command"; + if (error_enum == CH_ERROR_WRONG_UNLOCK_CODE) + return "Wrong unlock code"; + if (error_enum == CH_ERROR_NOT_IMPLEMENTED) + return "Not implemented"; + if (error_enum == CH_ERROR_UNDERFLOW_SENSOR) + return "Underflow of sensor"; + if (error_enum == CH_ERROR_NO_SERIAL) + return "No serial"; + if (error_enum == CH_ERROR_WATCHDOG) + return "Watchdog"; + if (error_enum == CH_ERROR_INVALID_ADDRESS) + return "Invalid address"; + if (error_enum == CH_ERROR_INVALID_LENGTH) + return "Invalid length"; + if (error_enum == CH_ERROR_INVALID_CHECKSUM) + return "Invalid checksum"; + if (error_enum == CH_ERROR_INVALID_VALUE) + return "Invalid value"; + if (error_enum == CH_ERROR_UNKNOWN_CMD_FOR_BOOTLOADER) + return "Unknown command for bootloader"; + if (error_enum == CH_ERROR_OVERFLOW_MULTIPLY) + return "Overflow of multiply"; + if (error_enum == CH_ERROR_OVERFLOW_ADDITION) + return "Overflow of addition"; + if (error_enum == CH_ERROR_OVERFLOW_SENSOR) + return "Overflow of sensor"; + if (error_enum == CH_ERROR_OVERFLOW_STACK) + return "Overflow of stack"; + if (error_enum == CH_ERROR_NO_CALIBRATION) + return "No calibration"; + if (error_enum == CH_ERROR_DEVICE_DEACTIVATED) + return "Device deactivated"; + if (error_enum == CH_ERROR_INCOMPLETE_REQUEST) + return "Incomplete previous request"; + if (error_enum == CH_ERROR_SELF_TEST_SENSOR) + return "Self test failed: Sensor"; + if (error_enum == CH_ERROR_SELF_TEST_RED) + return "Self test failed: Red"; + if (error_enum == CH_ERROR_SELF_TEST_GREEN) + return "Self test failed: Green"; + if (error_enum == CH_ERROR_SELF_TEST_BLUE) + return "Self test failed: Blue"; + if (error_enum == CH_ERROR_SELF_TEST_MULTIPLIER) + return "Self test failed: Multiplier"; + if (error_enum == CH_ERROR_SELF_TEST_COLOR_SELECT) + return "Self test failed: Color Select"; + if (error_enum == CH_ERROR_SELF_TEST_TEMPERATURE) + return "Self test failed: Temperature"; + if (error_enum == CH_ERROR_INVALID_CALIBRATION) + return "Invalid calibration"; + if (error_enum == CH_ERROR_SRAM_FAILED) + return "SRAM failed"; + if (error_enum == CH_ERROR_OUT_OF_MEMORY) + return "Out of memory"; + if (error_enum == CH_ERROR_SELF_TEST_I2C) + return "Self test failed: I2C"; + if (error_enum == CH_ERROR_SELF_TEST_ADC_VDD) + return "Self test failed: ADC Vdd"; + if (error_enum == CH_ERROR_SELF_TEST_ADC_VSS) + return "Self test failed: ADC Vss"; + if (error_enum == CH_ERROR_SELF_TEST_ADC_VREF) + return "Self test failed: ADC Vref"; + if (error_enum == CH_ERROR_I2C_SLAVE_ADDRESS) + return "I2C set slave address failed"; + if (error_enum == CH_ERROR_I2C_SLAVE_CONFIG) + return "I2C set slave config failed"; + if (error_enum == CH_ERROR_SELF_TEST_EEPROM) + return "Self test failed: EEPROM"; + return NULL; +} diff -Nru fwupd-1.0.6/plugins/colorhug/fu-colorhug-common.h fwupd-1.2.10/plugins/colorhug/fu-colorhug-common.h --- fwupd-1.0.6/plugins/colorhug/fu-colorhug-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/fu-colorhug-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +typedef enum { + CH_ERROR_NONE, + CH_ERROR_UNKNOWN_CMD, + CH_ERROR_WRONG_UNLOCK_CODE, + CH_ERROR_NOT_IMPLEMENTED, + CH_ERROR_UNDERFLOW_SENSOR, + CH_ERROR_NO_SERIAL, + CH_ERROR_WATCHDOG, + CH_ERROR_INVALID_ADDRESS, + CH_ERROR_INVALID_LENGTH, + CH_ERROR_INVALID_CHECKSUM, + CH_ERROR_INVALID_VALUE, + CH_ERROR_UNKNOWN_CMD_FOR_BOOTLOADER, + CH_ERROR_NO_CALIBRATION, + CH_ERROR_OVERFLOW_MULTIPLY, + CH_ERROR_OVERFLOW_ADDITION, + CH_ERROR_OVERFLOW_SENSOR, + CH_ERROR_OVERFLOW_STACK, + CH_ERROR_DEVICE_DEACTIVATED, + CH_ERROR_INCOMPLETE_REQUEST, + CH_ERROR_SELF_TEST_SENSOR, + CH_ERROR_SELF_TEST_RED, + CH_ERROR_SELF_TEST_GREEN, + CH_ERROR_SELF_TEST_BLUE, + CH_ERROR_SELF_TEST_COLOR_SELECT, + CH_ERROR_SELF_TEST_MULTIPLIER, + CH_ERROR_INVALID_CALIBRATION, + CH_ERROR_SRAM_FAILED, + CH_ERROR_OUT_OF_MEMORY, + CH_ERROR_SELF_TEST_TEMPERATURE, + CH_ERROR_SELF_TEST_I2C, + CH_ERROR_SELF_TEST_ADC_VDD, + CH_ERROR_SELF_TEST_ADC_VSS, + CH_ERROR_SELF_TEST_ADC_VREF, + CH_ERROR_I2C_SLAVE_ADDRESS, + CH_ERROR_I2C_SLAVE_CONFIG, + CH_ERROR_SELF_TEST_EEPROM, + CH_ERROR_LAST +} ChError; + +const gchar *ch_strerror (ChError error_enum); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/colorhug/fu-colorhug-device.c fwupd-1.2.10/plugins/colorhug/fu-colorhug-device.c --- fwupd-1.0.6/plugins/colorhug/fu-colorhug-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/fu-colorhug-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,80 +1,173 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include -#include +#include "fu-chunk.h" +#include "fu-colorhug-common.h" #include "fu-colorhug-device.h" -typedef struct -{ - ChDeviceQueue *device_queue; - gboolean is_bootloader; -} FuColorhugDevicePrivate; +/** + * FU_COLORHUG_DEVICE_FLAG_HALFSIZE: + * + * Some devices have a compact memory layout and the application code starts + * earlier. + * + * Since: 1.0.3 + */ +#define FU_COLORHUG_DEVICE_FLAG_HALFSIZE "halfsize" -G_DEFINE_TYPE_WITH_PRIVATE (FuColorhugDevice, fu_colorhug_device, FU_TYPE_USB_DEVICE) +struct _FuColorhugDevice { + FuUsbDevice parent_instance; + guint16 start_addr; +}; + +G_DEFINE_TYPE (FuColorhugDevice, fu_colorhug_device, FU_TYPE_USB_DEVICE) + +#define CH_CMD_GET_FIRMWARE_VERSION 0x07 +#define CH_CMD_RESET 0x24 +#define CH_CMD_READ_FLASH 0x25 +#define CH_CMD_WRITE_FLASH 0x26 +#define CH_CMD_BOOT_FLASH 0x27 +#define CH_CMD_SET_FLASH_SUCCESS 0x28 +#define CH_CMD_ERASE_FLASH 0x29 + +#define CH_USB_HID_EP 0x0001 +#define CH_USB_HID_EP_IN (CH_USB_HID_EP | 0x80) +#define CH_USB_HID_EP_OUT (CH_USB_HID_EP | 0x00) +#define CH_USB_HID_EP_SIZE 64 +#define CH_USB_CONFIG 0x0001 +#define CH_USB_INTERFACE 0x0000 +#define CH_EEPROM_ADDR_RUNCODE 0x4000 +#define CH_EEPROM_ADDR_RUNCODE_ALS 0x2000 -#define GET_PRIVATE(o) (fu_colorhug_device_get_instance_private (o)) +#define CH_DEVICE_USB_TIMEOUT 5000 /* ms */ +#define CH_FLASH_TRANSFER_BLOCK_SIZE 0x020 /* 32 */ -static void -fu_colorhug_device_finalize (GObject *object) -{ - FuColorhugDevice *device = FU_COLORHUG_DEVICE (object); - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); +static gboolean +fu_colorhug_device_msg (FuColorhugDevice *self, guint8 cmd, + guint8 *ibuf, gsize ibufsz, + guint8 *obuf, gsize obufsz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + guint8 buf[] = { [0] = cmd, [1 ... CH_USB_HID_EP_SIZE - 1] = 0x00 }; + gsize actual_length = 0; - g_object_unref (priv->device_queue); + /* check size */ + if (ibufsz > sizeof(buf) - 1) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot process chunk of size %" G_GSIZE_FORMAT, + ibufsz); + return FALSE; + } + if (obufsz > sizeof(buf) - 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot process chunk of size %" G_GSIZE_FORMAT, + ibufsz); + return FALSE; + } - G_OBJECT_CLASS (fu_colorhug_device_parent_class)->finalize (object); -} + /* optionally copy in data */ + if (ibuf != NULL) + memcpy (buf + 1, ibuf, ibufsz); + + /* request */ + if (g_getenv ("FWUPD_COLORHUG_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "REQ", buf, ibufsz + 1); + if (!g_usb_device_interrupt_transfer (usb_device, + CH_USB_HID_EP_OUT, + buf, + sizeof(buf), + &actual_length, + CH_DEVICE_USB_TIMEOUT, + NULL, /* cancellable */ + error)) { + g_prefix_error (error, "failed to send request: "); + return FALSE; + } + if (actual_length != CH_USB_HID_EP_SIZE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "request not all sent, got %" G_GSIZE_FORMAT, + actual_length); + return FALSE; + } -static void -fu_colorhug_device_progress_cb (ChDeviceQueue *device_queue, - guint percentage, - FuColorhugDevice *device) -{ - fu_device_set_progress (FU_DEVICE (device), percentage); -} + /* read reply */ + if (!g_usb_device_interrupt_transfer (usb_device, + CH_USB_HID_EP_IN, + buf, + sizeof(buf), + &actual_length, + CH_DEVICE_USB_TIMEOUT, + NULL, /* cancellable */ + error)) { + g_prefix_error (error, "failed to get reply: "); + return FALSE; + } + if (g_getenv ("FWUPD_COLORHUG_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "RES", buf, actual_length); -gboolean -fu_colorhug_device_get_is_bootloader (FuColorhugDevice *device) -{ - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - return priv->is_bootloader; + /* old bootloaders do not return the full block */ + if (actual_length != CH_USB_HID_EP_SIZE && + actual_length != 2 && + actual_length != obufsz + 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "request not all received, got %" G_GSIZE_FORMAT, + actual_length); + return FALSE; + } + + /* check error code */ + if (buf[0] != CH_ERROR_NONE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + ch_strerror (buf[0])); + return FALSE; + } + + /* check cmd matches */ + if (buf[1] != cmd) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cmd incorrect, expected %u, got %u", + cmd, buf[1]); + return FALSE; + } + + /* copy back optional buf */ + if (obuf != NULL) + memcpy (obuf, buf + 2, obufsz); + + return TRUE; } -gboolean -fu_colorhug_device_detach (FuColorhugDevice *device, GError **error) +static gboolean +fu_colorhug_device_detach (FuDevice *device, GError **error) { - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); g_autoptr(GError) error_local = NULL; - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_RESTART); - ch_device_queue_reset (priv->device_queue, usb_device); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_colorhug_device_msg (self, CH_CMD_RESET, + NULL, 0, /* in */ + NULL, 0, /* out */ + &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, @@ -85,18 +178,17 @@ return TRUE; } -gboolean -fu_colorhug_device_attach (FuColorhugDevice *device, GError **error) +static gboolean +fu_colorhug_device_attach (FuDevice *device, GError **error) { - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); g_autoptr(GError) error_local = NULL; - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_RESTART); - ch_device_queue_boot_flash (priv->device_queue, usb_device); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_colorhug_device_msg (self, CH_CMD_BOOT_FLASH, + NULL, 0, /* in */ + NULL, 0, /* out */ + &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, @@ -108,19 +200,18 @@ } gboolean -fu_colorhug_device_set_flash_success (FuColorhugDevice *device, GError **error) +fu_colorhug_device_set_flash_success (FuColorhugDevice *self, + gboolean val, + GError **error) { - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + guint8 buf[] = { [0] = val ? 0x01 : 0x00 }; g_autoptr(GError) error_local = NULL; g_debug ("setting flash success"); - ch_device_queue_set_flash_success (priv->device_queue, - usb_device, - 0x01); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { + if (!fu_colorhug_device_msg (self, CH_CMD_SET_FLASH_SUCCESS, + buf, sizeof(buf), /* in */ + NULL, 0, /* out */ + &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, @@ -132,64 +223,56 @@ } static gboolean -fu_colorhug_device_probe (FuUsbDevice *device, GError **error) +fu_colorhug_device_erase (FuColorhugDevice *self, guint16 addr, gsize sz, GError **error) { - FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); - FuColorhugDevicePrivate *priv = GET_PRIVATE (self); - GUsbDevice *usb_device = fu_usb_device_get_dev (device); - ChDeviceMode mode; + guint8 buf[4]; + g_autoptr(GError) error_local = NULL; - /* ignore */ - mode = ch_device_get_mode (usb_device); - if (mode == CH_DEVICE_MODE_UNKNOWN || - mode == CH_DEVICE_MODE_BOOTLOADER_PLUS || - mode == CH_DEVICE_MODE_FIRMWARE_PLUS) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported with this device"); + fu_common_write_uint16 (buf + 0, addr, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf + 2, sz, G_LITTLE_ENDIAN); + if (!fu_colorhug_device_msg (self, CH_CMD_ERASE_FLASH, + buf, sizeof(buf), /* in */ + NULL, 0, /* out */ + &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to erase device: %s", + error_local->message); return FALSE; } + return TRUE; +} + +static gchar * +fu_colorhug_device_get_version (FuColorhugDevice *self, GError **error) +{ + guint8 buf[6]; + if (!fu_colorhug_device_msg (self, CH_CMD_GET_FIRMWARE_VERSION, + NULL, 0, /* in */ + buf, sizeof(buf), /* out */ + error)) { + return NULL; + } + return g_strdup_printf ("%i.%i.%i", + fu_common_read_uint16 (buf + 0, G_LITTLE_ENDIAN), + fu_common_read_uint16 (buf + 2, G_LITTLE_ENDIAN), + fu_common_read_uint16 (buf + 4, G_LITTLE_ENDIAN)); +} + +static gboolean +fu_colorhug_device_probe (FuUsbDevice *device, GError **error) +{ + FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); + + /* compact memory layout */ + if (fu_device_has_custom_flag (FU_DEVICE (device), + FU_COLORHUG_DEVICE_FLAG_HALFSIZE)) + self->start_addr = CH_EEPROM_ADDR_RUNCODE_ALS; /* add hardcoded bits */ - fu_device_add_guid (FU_DEVICE (device), ch_device_get_guid (usb_device)); - fu_device_add_icon (FU_DEVICE (device), "colorimeter-colorhug"); fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - /* set the display name */ - switch (mode) { - case CH_DEVICE_MODE_BOOTLOADER: - case CH_DEVICE_MODE_FIRMWARE: - case CH_DEVICE_MODE_LEGACY: - fu_device_set_summary (FU_DEVICE (device), - "An open source display colorimeter"); - break; - case CH_DEVICE_MODE_BOOTLOADER2: - case CH_DEVICE_MODE_FIRMWARE2: - fu_device_set_summary (FU_DEVICE (device), - "An open source display colorimeter"); - break; - case CH_DEVICE_MODE_BOOTLOADER_ALS: - case CH_DEVICE_MODE_FIRMWARE_ALS: - fu_device_set_summary (FU_DEVICE (device), - "An open source ambient light sensor"); - break; - default: - break; - } - - /* is the device in bootloader mode */ - switch (mode) { - case CH_DEVICE_MODE_BOOTLOADER: - case CH_DEVICE_MODE_BOOTLOADER2: - case CH_DEVICE_MODE_BOOTLOADER_ALS: - priv->is_bootloader = TRUE; - break; - default: - priv->is_bootloader = FALSE; - break; - } - /* success */ return TRUE; } @@ -197,8 +280,6 @@ static gboolean fu_colorhug_device_open (FuUsbDevice *device, GError **error) { - FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); - FuColorhugDevicePrivate *priv = GET_PRIVATE (self); GUsbDevice *usb_device = fu_usb_device_get_dev (device); /* got the version using the HID API */ @@ -209,108 +290,131 @@ error)) { return FALSE; } + + /* success */ + return TRUE; +} + +static gboolean +fu_colorhug_device_setup (FuDevice *device, GError **error) +{ + FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); + if (fu_device_get_version (FU_DEVICE (device)) == NULL) { - guint16 major; - guint16 micro; - guint16 minor; g_autofree gchar *version = NULL; g_autoptr(GError) error_local = NULL; - ch_device_queue_get_firmware_ver (priv->device_queue, usb_device, - &major, &minor, µ); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { + version = fu_colorhug_device_get_version (self, &error_local); + if (version != NULL) { + g_debug ("obtained fwver using API '%s'", version); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_TRIPLET); + } else { g_warning ("failed to get firmware version: %s", error_local->message); } - version = g_strdup_printf ("%i.%i.%i", major, minor, micro); - g_debug ("obtained fwver using API '%s'", version); - fu_device_set_version (FU_DEVICE (device), version); } /* success */ return TRUE; } -gboolean -fu_colorhug_device_verify_firmware (FuColorhugDevice *device, GError **error) +static guint8 +ch_colorhug_device_calculate_checksum (const guint8 *data, guint32 len) { - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - gsize len; - g_autoptr(GError) error_local = NULL; - g_autofree guint8 *data2 = NULL; - GChecksumType checksum_types[] = { - G_CHECKSUM_SHA1, - G_CHECKSUM_SHA256, - 0 }; - - /* get the firmware from the device */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY); - ch_device_queue_read_firmware (priv->device_queue, usb_device, - &data2, &len); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "failed to dump firmware: %s", - error_local->message); - return FALSE; - } - - /* get the checksum */ - for (guint i = 0; checksum_types[i] != 0; i++) { - g_autofree gchar *hash = NULL; - hash = g_compute_checksum_for_data (checksum_types[i], - (guchar *) data2, len); - fu_device_add_checksum (device, hash); - } - - return TRUE; + guint8 checksum = 0xff; + for (guint32 i = 0; i < len; i++) + checksum ^= data[i]; + return checksum; } -gboolean -fu_colorhug_device_write_firmware (FuColorhugDevice *device, GBytes *fw, GError **error) +static gboolean +fu_colorhug_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) { - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(GError) error_local = NULL; + FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); + g_autoptr(GPtrArray) chunks = NULL; - /* write firmware */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_WRITE); - ch_device_queue_set_flash_success (priv->device_queue, - usb_device, - 0x00); - ch_device_queue_write_firmware (priv->device_queue, usb_device, - g_bytes_get_data (fw, NULL), - g_bytes_get_size (fw)); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "failed to write firmware: %s", - error_local->message); + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, + self->start_addr, + 0x00, /* page_sz */ + CH_FLASH_TRANSFER_BLOCK_SIZE); + + /* don't auto-boot firmware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_colorhug_device_set_flash_success (self, FALSE, error)) return FALSE; - } - /* verify firmware */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_VERIFY); - ch_device_queue_verify_firmware (priv->device_queue, usb_device, - g_bytes_get_data (fw, NULL), - g_bytes_get_size (fw)); - if (!ch_device_queue_process (priv->device_queue, - CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, - NULL, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "failed to verify firmware: %s", - error_local->message); + /* erase flash */ + if (!fu_colorhug_device_erase (self, self->start_addr, g_bytes_get_size (fw), error)) return FALSE; + + /* write each block */ + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint8 buf[CH_FLASH_TRANSFER_BLOCK_SIZE+4]; + g_autoptr(GError) error_local = NULL; + + /* set address, length, checksum, data */ + fu_common_write_uint16 (buf + 0, chk->address, G_LITTLE_ENDIAN); + buf[2] = chk->data_sz; + buf[3] = ch_colorhug_device_calculate_checksum (chk->data, chk->data_sz); + memcpy (buf + 4, chk->data, chk->data_sz); + if (!fu_colorhug_device_msg (self, CH_CMD_WRITE_FLASH, + buf, sizeof(buf), /* in */ + NULL, 0, /* out */ + &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to write: %s", + error_local->message); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len * 2); + } + + /* verify each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint8 buf[3]; + guint8 buf_out[CH_FLASH_TRANSFER_BLOCK_SIZE+1]; + g_autoptr(GError) error_local = NULL; + + /* set address */ + fu_common_write_uint16 (buf + 0, chk->address, G_LITTLE_ENDIAN); + buf[2] = chk->data_sz; + if (!fu_colorhug_device_msg (self, CH_CMD_READ_FLASH, + buf, sizeof(buf), /* in */ + buf_out, sizeof(buf_out), /* out */ + &error_local)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read: %s", + error_local->message); + return FALSE; + } + + /* verify */ + if (memcmp (buf_out + 1, chk->data, chk->data_sz) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to verify firmware for chunk %u, " + "address 0x%0x, length 0x%0x", + i, (guint) chk->address, chk->data_sz); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, + (gsize) chunks->len + i, + (gsize) chunks->len * 2); } /* success! */ @@ -318,39 +422,32 @@ } static void -fu_colorhug_device_init (FuColorhugDevice *device) +fu_colorhug_device_init (FuColorhugDevice *self) { - FuColorhugDevicePrivate *priv = GET_PRIVATE (device); - priv->device_queue = ch_device_queue_new (); - g_signal_connect (priv->device_queue, "progress_changed", - G_CALLBACK (fu_colorhug_device_progress_cb), device); + /* this is the application code */ + self->start_addr = CH_EEPROM_ADDR_RUNCODE; + fu_device_set_remove_delay (FU_DEVICE (self), + FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); } static void fu_colorhug_device_class_init (FuColorhugDeviceClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); - object_class->finalize = fu_colorhug_device_finalize; + klass_device->write_firmware = fu_colorhug_device_write_firmware; + klass_device->attach = fu_colorhug_device_attach; + klass_device->detach = fu_colorhug_device_detach; + klass_device->setup = fu_colorhug_device_setup; klass_usb_device->open = fu_colorhug_device_open; klass_usb_device->probe = fu_colorhug_device_probe; } -/** - * fu_colorhug_device_new: - * - * Creates a new #FuColorhugDevice. - * - * Returns: (transfer full): a #FuColorhugDevice, or %NULL if not a game pad - * - * Since: 0.1.0 - **/ FuColorhugDevice * -fu_colorhug_device_new (GUsbDevice *usb_device) +fu_colorhug_device_new (FuUsbDevice *device) { - FuColorhugDevice *device = NULL; - device = g_object_new (FU_TYPE_COLORHUG_DEVICE, - "usb-device", usb_device, - NULL); - return device; + FuColorhugDevice *self = NULL; + self = g_object_new (FU_TYPE_COLORHUG_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; } diff -Nru fwupd-1.0.6/plugins/colorhug/fu-colorhug-device.h fwupd-1.2.10/plugins/colorhug/fu-colorhug-device.h --- fwupd-1.0.6/plugins/colorhug/fu-colorhug-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/fu-colorhug-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,58 +1,23 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COLORHUG_DEVICE_H -#define __FU_COLORHUG_DEVICE_H - -#include -#include +#pragma once #include "fu-plugin.h" G_BEGIN_DECLS #define FU_TYPE_COLORHUG_DEVICE (fu_colorhug_device_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuColorhugDevice, fu_colorhug_device, FU, COLORHUG_DEVICE, FuUsbDevice) - -struct _FuColorhugDeviceClass -{ - FuUsbDeviceClass parent_class; -}; +G_DECLARE_FINAL_TYPE (FuColorhugDevice, fu_colorhug_device, FU, COLORHUG_DEVICE, FuUsbDevice) -FuColorhugDevice *fu_colorhug_device_new (GUsbDevice *usb_device); -gboolean fu_colorhug_device_get_is_bootloader (FuColorhugDevice *device); +FuColorhugDevice *fu_colorhug_device_new (FuUsbDevice *device); /* object methods */ -gboolean fu_colorhug_device_detach (FuColorhugDevice *device, - GError **error); -gboolean fu_colorhug_device_attach (FuColorhugDevice *device, - GError **error); gboolean fu_colorhug_device_set_flash_success (FuColorhugDevice *device, - GError **error); -gboolean fu_colorhug_device_write_firmware (FuColorhugDevice *device, - GBytes *fw, - GError **error); -gboolean fu_colorhug_device_verify_firmware (FuColorhugDevice *device, + gboolean val, GError **error); G_END_DECLS - -#endif /* __FU_COLORHUG_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/colorhug/fu-plugin-colorhug.c fwupd-1.2.10/plugins/colorhug/fu-plugin-colorhug.c --- fwupd-1.0.6/plugins/colorhug/fu-plugin-colorhug.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/fu-plugin-colorhug.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include -#include - -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "fu-colorhug-device.h" @@ -32,20 +13,15 @@ void fu_plugin_init (FuPlugin *plugin) { - g_autofree gchar *tmp = g_strdup_printf ("%i.%i.%i", - CH_MAJOR_VERSION, - CH_MINOR_VERSION, - CH_MICRO_VERSION); - fu_plugin_add_report_metadata (plugin, "ColorhugVersion", tmp); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.hughski.colorhug"); } gboolean fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) { - FuColorhugDevice *colorhug_dev = FU_COLORHUG_DEVICE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GUsbDevice) usb_device2 = NULL; /* open device */ locker = fu_device_locker_new (device, error); @@ -53,39 +29,24 @@ return FALSE; /* switch to bootloader mode is not required */ - if (fu_colorhug_device_get_is_bootloader (colorhug_dev)) { + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { g_debug ("already in bootloader mode, skipping"); return TRUE; } /* reset */ - if (!fu_colorhug_device_detach (colorhug_dev, error)) + if (!fu_device_detach (FU_DEVICE (device), error)) return FALSE; /* wait for replug */ - g_clear_object (&locker); - usb_device2 = g_usb_context_wait_for_replug (fu_plugin_get_usb_context (plugin), - usb_device, - 10000, error); - if (usb_device2 == NULL) { - g_prefix_error (error, "device did not come back: "); - return FALSE; - } - - /* set the new device until we can use a new FuDevice */ - fu_usb_device_set_dev (FU_USB_DEVICE (colorhug_dev), usb_device2); - - /* success */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } gboolean fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) { - FuColorhugDevice *colorhug_dev = FU_COLORHUG_DEVICE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GUsbDevice) usb_device2 = NULL; /* open device */ locker = fu_device_locker_new (device, error); @@ -93,43 +54,31 @@ return FALSE; /* switch to runtime mode is not required */ - if (!fu_colorhug_device_get_is_bootloader (colorhug_dev)) { + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { g_debug ("already in runtime mode, skipping"); return TRUE; } /* reset */ - if (!fu_colorhug_device_attach (colorhug_dev, error)) + if (!fu_device_attach (device, error)) return FALSE; /* wait for replug */ - g_clear_object (&locker); - usb_device2 = g_usb_context_wait_for_replug (fu_plugin_get_usb_context (plugin), - usb_device, - 10000, error); - if (usb_device2 == NULL) { - g_prefix_error (error, "device did not come back: "); - return FALSE; - } - - /* set the new device until we can use a new FuDevice */ - fu_usb_device_set_dev (FU_USB_DEVICE (colorhug_dev), usb_device2); - - /* success */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } gboolean fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) { - FuColorhugDevice *colorhug_dev = FU_COLORHUG_DEVICE (device); + FuColorhugDevice *self = FU_COLORHUG_DEVICE (device); g_autoptr(FuDeviceLocker) locker = NULL; /* also set flash success */ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; - if (!fu_colorhug_device_set_flash_success (colorhug_dev, error)) + if (!fu_colorhug_device_set_flash_success (self, TRUE, error)) return FALSE; return TRUE; } @@ -141,60 +90,28 @@ FwupdInstallFlags flags, GError **error) { - FuColorhugDevice *colorhug_dev = FU_COLORHUG_DEVICE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GError) error_local = NULL; - - /* check this firmware is actually for this device */ - if (!ch_device_check_firmware (usb_device, - g_bytes_get_data (blob_fw, NULL), - g_bytes_get_size (blob_fw), - &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "firmware is not suitable: %s", - error_local->message); - return FALSE; - } - - /* write firmware */ - locker = fu_device_locker_new (device, error); - if (locker == NULL) - return FALSE; - return fu_colorhug_device_write_firmware (colorhug_dev, blob_fw, error); -} - -gboolean -fu_plugin_verify (FuPlugin *plugin, - FuDevice *device, - FuPluginVerifyFlags flags, - GError **error) -{ - FuColorhugDevice *colorhug_dev = FU_COLORHUG_DEVICE (device); g_autoptr(FuDeviceLocker) locker = NULL; /* write firmware */ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; - return fu_colorhug_device_verify_firmware (colorhug_dev, error); + return fu_device_write_firmware (device, blob_fw, flags, error); } gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuColorhugDevice) device = NULL; + g_autoptr(FuColorhugDevice) dev = NULL; /* open the device */ - device = fu_colorhug_device_new (usb_device); - locker = fu_device_locker_new (device, error); + dev = fu_colorhug_device_new (device); + locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; /* insert to hash */ - fu_plugin_device_add (plugin, FU_DEVICE (device)); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } diff -Nru fwupd-1.0.6/plugins/colorhug/meson.build fwupd-1.2.10/plugins/colorhug/meson.build --- fwupd-1.0.6/plugins/colorhug/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,7 +1,15 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginColorHug"'] +install_data([ + 'colorhug.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_colorhug', + fu_hash, sources : [ + 'fu-colorhug-common.c', 'fu-colorhug-device.c', 'fu-plugin-colorhug.c', ], @@ -12,9 +20,11 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - colorhug, ], ) diff -Nru fwupd-1.0.6/plugins/colorhug/README.md fwupd-1.2.10/plugins/colorhug/README.md --- fwupd-1.0.6/plugins/colorhug/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/colorhug/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -11,14 +11,21 @@ ColorHug versions 1 and 2 support a custom HID-based flashing protocol, but version 3 (ColorHug+) has now switched to DFU. -Build Requirements ------------------- +Firmware Format +--------------- -For colorhug support you need to install colord 1.2.12 or later. -* source: https://github.com/hughsie/colord -* rpms: http://people.freedesktop.org/~hughsient/fedora/ -* debs (Debian): https://tracker.debian.org/pkg/fwupd -* debs (Ubuntu): https://launchpad.net/ubuntu/+source/fwupd +The daemon will decompress the cabinet archive and extract a firmware blob in +a packed binary file format. -If you don't want or need this functionality you can use the -`--disable-colorhug` option. +This plugin supports the following protocol ID: + + * com.hughski.colorhug + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_273F&PID_1001&REV_0001` + * `USB\VID_273F&PID_1001` + * `USB\VID_273F` diff -Nru fwupd-1.0.6/plugins/csr/csr-aiaiai-h05.quirk fwupd-1.2.10/plugins/csr/csr-aiaiai-h05.quirk --- fwupd-1.0.6/plugins/csr/csr-aiaiai-h05.quirk 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/csr-aiaiai-h05.quirk 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -[FuCsrDevice] - -# AIAIAI H05 bluetooth headphones -USB\VID_0A12&PID_1337=none - -[FuUsbDevice:name] -USB\VID_0A12&PID_1337=H05 - -[FuUsbDevice:summary] -USB\VID_0A12&PID_1337=Bluetooth headphones - -[FuUsbDevice:icon] -USB\VID_0A12&PID_1337=audio-headphones - -[FuUsbDevice:vendor] -USB\VID_0A12&PID_1337=AIAIAI - -[FuUsbDevice:version] -USB\VID_0A12&PID_1337&REV_2520=1.2 diff -Nru fwupd-1.0.6/plugins/csr/csr-aiaiai-h60.quirk fwupd-1.2.10/plugins/csr/csr-aiaiai-h60.quirk --- fwupd-1.0.6/plugins/csr/csr-aiaiai-h60.quirk 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/csr-aiaiai-h60.quirk 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -[FuCsrDevice] - -# AIAIAI H60 bluetooth headphones -USB\VID_0A12&PID_4004=none - -[FuUsbDevice:name] -USB\VID_0A12&PID_4004=H60 - -[FuUsbDevice:summary] -USB\VID_0A12&PID_4004=Bluetooth headphones - -[FuUsbDevice:icon] -USB\VID_0A12&PID_4004=audio-headphones - -[FuUsbDevice:vendor] -USB\VID_0A12&PID_4004=AIAIAI diff -Nru fwupd-1.0.6/plugins/csr/csr-aiaiai.quirk fwupd-1.2.10/plugins/csr/csr-aiaiai.quirk --- fwupd-1.0.6/plugins/csr/csr-aiaiai.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/csr-aiaiai.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,15 @@ +[DeviceInstanceId=USB\VID_0A12&PID_1337] +Plugin = csr +Name = H05 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI +[DeviceInstanceId=USB\VID_0A12&PID_1337&REV_2520] +Version = 1.2 + +[DeviceInstanceId=USB\VID_0A12&PID_4004] +Plugin = csr +Name = H60 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI diff -Nru fwupd-1.0.6/plugins/csr/fu-csr-device.c fwupd-1.2.10/plugins/csr/fu-csr-device.c --- fwupd-1.0.6/plugins/csr/fu-csr-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/fu-csr-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,34 +1,35 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017-2018 Richard Hughes * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include +#include "fu-chunk.h" #include "fu-csr-device.h" #include "dfu-common.h" -#include "dfu-chunked.h" #include "dfu-firmware.h" +/** + * FU_CSR_DEVICE_QUIRK_FLAG_REQUIRE_DELAY: + * + * Respect the write timeout value when performing actions. This is sometimes + * set to a huge amount of time, and so is not used by default. + * + * Since: 1.0.3 + */ +#define FU_CSR_DEVICE_FLAG_REQUIRE_DELAY "require-delay" + +typedef enum { + FU_CSR_DEVICE_QUIRK_NONE = 0, + FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY = (1 << 0), + FU_CSR_DEVICE_QUIRK_LAST +} FuCsrDeviceQuirks; + struct _FuCsrDevice { FuUsbDevice parent_instance; @@ -39,15 +40,6 @@ G_DEFINE_TYPE (FuCsrDevice, fu_csr_device, FU_TYPE_USB_DEVICE) -#define HID_REPORT_GET 0x01 -#define HID_REPORT_SET 0x09 - -#define HID_REPORT_TYPE_INPUT 0x01 -#define HID_REPORT_TYPE_OUTPUT 0x02 -#define HID_REPORT_TYPE_FEATURE 0x03 - -#define HID_FEATURE 0x0300 - #define FU_CSR_REPORT_ID_COMMAND 0x01 #define FU_CSR_REPORT_ID_STATUS 0x02 #define FU_CSR_REPORT_ID_CONTROL 0x03 @@ -75,31 +67,16 @@ g_string_append_printf (str, " timeout:\t\t%" G_GUINT32_FORMAT "\n", self->dnload_timeout); } -static void -fu_csr_device_dump (const gchar *title, const guint8 *buf, gsize sz) -{ - if (g_getenv ("FWUPD_CSR_VERBOSE") == NULL) - return; - g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); - for (gsize i = 0; i < sz; i++) - g_print ("%02x ", buf[i]); - g_print ("\n"); -} - -void -fu_csr_device_set_quirks (FuCsrDevice *self, FuCsrDeviceQuirks quirks) -{ - self->quirks = quirks; -} - -gboolean -fu_csr_device_attach (FuCsrDevice *self, GError **error) +static gboolean +fu_csr_device_attach (FuDevice *device, GError **error) { + FuCsrDevice *self = FU_CSR_DEVICE (device); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); gsize sz = 0; guint8 buf[] = { FU_CSR_REPORT_ID_CONTROL, FU_CSR_CONTROL_RESET }; - fu_csr_device_dump ("Reset", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Reset", buf, sz); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -148,7 +125,8 @@ g_prefix_error (error, "Failed to GetStatus: "); return FALSE; } - fu_csr_device_dump ("GetStatus", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "GetStatus", buf, sz); /* check packet */ if (sz != FU_CSR_STATUS_HEADER_SIZE) { @@ -192,7 +170,8 @@ return TRUE; /* hit hardware */ - fu_csr_device_dump ("ClearStatus", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ClearStatus", buf, sz); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -243,7 +222,8 @@ g_prefix_error (error, "Failed to ReadFirmware: "); return NULL; } - fu_csr_device_dump ("ReadFirmware", buf, sz); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "ReadFirmware", buf, sz); /* too small to parse */ if (sz < FU_CSR_COMMAND_HEADER_SIZE) { @@ -280,15 +260,16 @@ sz - FU_CSR_COMMAND_HEADER_SIZE); } -GBytes * -fu_csr_device_upload (FuCsrDevice *self, GError **error) +static GBytes * +fu_csr_device_upload (FuDevice *device, GError **error) { + FuCsrDevice *self = FU_CSR_DEVICE (device); g_autoptr(GPtrArray) chunks = NULL; guint32 total_sz = 0; gsize done_sz = 0; /* notify UI */ - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_READ); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); for (guint32 i = 0; i < 0x3ffffff; i++) { @@ -298,7 +279,7 @@ /* hit hardware */ chunk = fu_csr_device_upload_chunk (self, error); if (chunk == NULL) - return FALSE; + return NULL; chunk_sz = g_bytes_get_size (chunk); /* get the total size using the CSR header */ @@ -335,7 +316,7 @@ /* add to chunk array */ done_sz += chunk_sz; g_ptr_array_add (chunks, g_steal_pointer (&chunk)); - fu_device_set_progress_full (FU_DEVICE (self), done_sz, (gsize) total_sz); + fu_device_set_progress_full (device, done_sz, (gsize) total_sz); /* we're done */ if (chunk_sz < 64 - FU_CSR_COMMAND_HEADER_SIZE) @@ -343,7 +324,6 @@ } /* notify UI */ - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_IDLE); return dfu_utils_bytes_join_array (chunks); } @@ -375,7 +355,8 @@ memcpy (buf + FU_CSR_COMMAND_HEADER_SIZE, chunk_data, chunk_sz); /* hit hardware */ - fu_csr_device_dump ("Upgrade", buf, sizeof(buf)); + if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "Upgrade", buf, sizeof(buf)); if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_CLASS, @@ -449,24 +430,19 @@ return dfu_element_get_contents (element); } -gboolean -fu_csr_device_download (FuCsrDevice *self, GBytes *blob, GError **error) +static GBytes * +fu_csr_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) { GBytes *blob_noftr; - const guint8 *data; - gsize sz = 0; - guint16 idx; g_autoptr(DfuFirmware) dfu_firmware = dfu_firmware_new (); - g_autoptr(GBytes) blob_empty = NULL; - g_autoptr(GPtrArray) packets = NULL; - - /* notify UI */ - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); /* parse the file */ - if (!dfu_firmware_parse_data (dfu_firmware, blob, + if (!dfu_firmware_parse_data (dfu_firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) - return FALSE; + return NULL; if (g_getenv ("FWUPD_CSR_VERBOSE") != NULL) { g_autofree gchar *fw_str = NULL; fw_str = dfu_firmware_to_string (dfu_firmware); @@ -477,7 +453,7 @@ FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "expected DFU firmware"); - return FALSE; + return NULL; } /* get the blob from the firmware file */ @@ -487,57 +463,59 @@ FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "firmware contained no data"); - return FALSE; + return NULL; } - /* create packets */ - data = g_bytes_get_data (blob_noftr, &sz); - packets = dfu_chunked_new (data, (guint32) sz, 0x0, 0x0, - FU_CSR_PACKET_DATA_SIZE - FU_CSR_COMMAND_HEADER_SIZE); + /* success */ + return g_bytes_ref (blob_noftr); +} + +static gboolean +fu_csr_device_download (FuDevice *device, + GBytes *blob, + FwupdInstallFlags flags, + GError **error) +{ + FuCsrDevice *self = FU_CSR_DEVICE (device); + guint16 idx; + g_autoptr(GBytes) blob_empty = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* notify UI */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + + /* create chunks */ + chunks = fu_chunk_array_new_from_bytes (blob, 0x0, 0x0, + FU_CSR_PACKET_DATA_SIZE - FU_CSR_COMMAND_HEADER_SIZE); /* send to hardware */ - for (idx = 0; idx < packets->len; idx++) { - DfuChunkedPacket *pkt = g_ptr_array_index (packets, idx); - g_autoptr(GBytes) blob_tmp = g_bytes_new_static (pkt->data, pkt->data_sz); + for (idx = 0; idx < chunks->len; idx++) { + FuChunk *chk = g_ptr_array_index (chunks, idx); + g_autoptr(GBytes) blob_tmp = g_bytes_new_static (chk->data, chk->data_sz); /* send packet */ if (!fu_csr_device_download_chunk (self, idx, blob_tmp, error)) return FALSE; /* update progress */ - fu_device_set_progress_full (FU_DEVICE (self), - (gsize) idx, (gsize) packets->len); + fu_device_set_progress_full (device, + (gsize) idx, (gsize) chunks->len); } /* all done */ blob_empty = g_bytes_new (NULL, 0); - if (!fu_csr_device_download_chunk (self, idx, blob_empty, error)) - return FALSE; - - /* notify UI */ - fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_IDLE); - - return TRUE; + return fu_csr_device_download_chunk (self, idx, blob_empty, error); } static gboolean fu_csr_device_probe (FuUsbDevice *device, GError **error) { - const gchar *quirk_str; + FuCsrDevice *self = FU_CSR_DEVICE (device); /* devices have to be whitelisted */ - quirk_str = fu_device_get_plugin_hints (FU_DEVICE (device)); - if (quirk_str == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported with this device"); - return FALSE; - } - if (g_strcmp0 (quirk_str, "require-delay") == 0) { - fu_csr_device_set_quirks (FU_CSR_DEVICE (device), - FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY); - } + if (fu_device_has_custom_flag (FU_DEVICE (device), + FU_CSR_DEVICE_FLAG_REQUIRE_DELAY)) + self->quirks = FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY; /* hardcoded */ fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); @@ -549,7 +527,6 @@ static gboolean fu_csr_device_open (FuUsbDevice *device, GError **error) { - FuCsrDevice *self = FU_CSR_DEVICE (device); GUsbDevice *usb_device = fu_usb_device_get_dev (device); /* open device and clear status */ @@ -559,6 +536,16 @@ g_prefix_error (error, "failed to claim HID interface: "); return FALSE; } + + /* success */ + return TRUE; +} + +static gboolean +fu_csr_device_setup (FuDevice *device, GError **error) +{ + FuCsrDevice *self = FU_CSR_DEVICE (device); + if (!fu_csr_device_clear_status (self, error)) return FALSE; @@ -594,17 +581,20 @@ FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); klass_device->to_string = fu_csr_device_to_string; + klass_device->write_firmware = fu_csr_device_download; + klass_device->read_firmware = fu_csr_device_upload; + klass_device->prepare_firmware = fu_csr_device_prepare_firmware; + klass_device->attach = fu_csr_device_attach; + klass_device->setup = fu_csr_device_setup; klass_usb_device->open = fu_csr_device_open; klass_usb_device->close = fu_csr_device_close; klass_usb_device->probe = fu_csr_device_probe; } FuCsrDevice * -fu_csr_device_new (GUsbDevice *usb_device) +fu_csr_device_new (FuUsbDevice *device) { - FuCsrDevice *device = NULL; - device = g_object_new (FU_TYPE_CSR_DEVICE, - "usb-device", usb_device, - NULL); - return device; + FuCsrDevice *self = g_object_new (FU_TYPE_CSR_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; } diff -Nru fwupd-1.0.6/plugins/csr/fu-csr-device.h fwupd-1.2.10/plugins/csr/fu-csr-device.h --- fwupd-1.0.6/plugins/csr/fu-csr-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/fu-csr-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017-2018 Richard Hughes * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_CSR_DEVICE_H -#define __FU_CSR_DEVICE_H - -#include -#include +#pragma once #include "fu-plugin.h" @@ -32,23 +13,6 @@ #define FU_TYPE_CSR_DEVICE (fu_csr_device_get_type ()) G_DECLARE_FINAL_TYPE (FuCsrDevice, fu_csr_device, FU, CSR_DEVICE, FuUsbDevice) -typedef enum { - FU_CSR_DEVICE_QUIRK_NONE = 0, - FU_CSR_DEVICE_QUIRK_REQUIRE_DELAY = (1 << 0), - FU_CSR_DEVICE_QUIRK_LAST -} FuCsrDeviceQuirks; - -FuCsrDevice *fu_csr_device_new (GUsbDevice *usb_device); -gboolean fu_csr_device_attach (FuCsrDevice *self, - GError **error); -gboolean fu_csr_device_download (FuCsrDevice *self, - GBytes *blob, - GError **error); -GBytes *fu_csr_device_upload (FuCsrDevice *self, - GError **error); -void fu_csr_device_set_quirks (FuCsrDevice *self, - FuCsrDeviceQuirks quirks); +FuCsrDevice *fu_csr_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_CSR_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/csr/fu-csr-tool.c fwupd-1.2.10/plugins/csr/fu-csr-tool.c --- fwupd-1.0.6/plugins/csr/fu-csr-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/fu-csr-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,388 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#include "config.h" - -#include -#include -#include - -#include "dfu-firmware.h" - -#include "fu-progressbar.h" -#include "fu-csr-device.h" - -typedef struct { - FuQuirks *quirks; - GPtrArray *cmd_array; - FuProgressbar *progressbar; -} FuCsrToolPrivate; - -static void -fu_csr_tool_private_free (FuCsrToolPrivate *priv) -{ - if (priv == NULL) - return; - g_object_unref (priv->quirks); - g_object_unref (priv->progressbar); - if (priv->cmd_array != NULL) - g_ptr_array_unref (priv->cmd_array); - g_free (priv); -} -G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCsrToolPrivate, fu_csr_tool_private_free) - -typedef gboolean (*FuCsrToolPrivateCb) (FuCsrToolPrivate *util, - gchar **values, - GError **error); - -typedef struct { - gchar *name; - gchar *arguments; - gchar *description; - FuCsrToolPrivateCb callback; -} FuCsrToolItem; - -static void -fu_csr_tool_item_free (FuCsrToolItem *item) -{ - g_free (item->name); - g_free (item->arguments); - g_free (item->description); - g_free (item); -} - -static gint -fu_csr_tool_sort_command_name_cb (FuCsrToolItem **item1, FuCsrToolItem **item2) -{ - return g_strcmp0 ((*item1)->name, (*item2)->name); -} - -static void -fu_csr_tool_add (GPtrArray *array, - const gchar *name, - const gchar *arguments, - const gchar *description, - FuCsrToolPrivateCb callback) -{ - g_auto(GStrv) names = NULL; - - g_return_if_fail (name != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (callback != NULL); - - /* add each one */ - names = g_strsplit (name, ",", -1); - for (guint i = 0; names[i] != NULL; i++) { - FuCsrToolItem *item = g_new0 (FuCsrToolItem, 1); - item->name = g_strdup (names[i]); - if (i == 0) { - item->description = g_strdup (description); - } else { - item->description = g_strdup_printf ("Alias to %s", names[0]); - } - item->arguments = g_strdup (arguments); - item->callback = callback; - g_ptr_array_add (array, item); - } -} - -static gchar * -fu_csr_tool_get_descriptions (GPtrArray *array) -{ - const gsize max_len = 31; - GString *str; - - /* print each command */ - str = g_string_new (""); - for (guint i = 0; i < array->len; i++) { - FuCsrToolItem *item = g_ptr_array_index (array, i); - gsize len; - g_string_append (str, " "); - g_string_append (str, item->name); - len = strlen (item->name) + 2; - if (item->arguments != NULL) { - g_string_append (str, " "); - g_string_append (str, item->arguments); - len += strlen (item->arguments) + 1; - } - if (len < max_len) { - for (guint j = len; j < max_len + 1; j++) - g_string_append_c (str, ' '); - g_string_append (str, item->description); - g_string_append_c (str, '\n'); - } else { - g_string_append_c (str, '\n'); - for (guint j = 0; j < max_len + 1; j++) - g_string_append_c (str, ' '); - g_string_append (str, item->description); - g_string_append_c (str, '\n'); - } - } - - /* remove trailing newline */ - if (str->len > 0) - g_string_set_size (str, str->len - 1); - - return g_string_free (str, FALSE); -} - -static gboolean -fu_csr_tool_run (FuCsrToolPrivate *priv, const gchar *command, gchar **values, GError **error) -{ - /* find command */ - for (guint i = 0; i < priv->cmd_array->len; i++) { - FuCsrToolItem *item = g_ptr_array_index (priv->cmd_array, i); - if (g_strcmp0 (item->name, command) == 0) - return item->callback (priv, values, error); - } - - /* not found */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "Command not found"); - return FALSE; -} - -static FuCsrDevice * -fu_csr_get_default_device (FuCsrToolPrivate *priv, GError **error) -{ - g_autoptr(GUsbContext) usb_context = NULL; - g_autoptr(GPtrArray) devices = NULL; - - /* get all the DFU devices */ - usb_context = g_usb_context_new (error); - if (usb_context == NULL) - return NULL; - devices = g_usb_context_get_devices (usb_context); - for (guint i = 0; i < devices->len; i++) { - GUsbDevice *usb_device = g_ptr_array_index (devices, i); - g_autoptr(FuCsrDevice) device = fu_csr_device_new (usb_device); - fu_device_set_quirks (FU_DEVICE (device), priv->quirks); - if (fu_usb_device_probe (FU_USB_DEVICE (device), NULL)) - return g_steal_pointer (&device); - } - - /* unsupported */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "no supported devices found"); - return NULL; -} - -static gboolean -fu_csr_tool_info (FuCsrToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(FuCsrDevice) device = fu_csr_get_default_device (priv, error); - g_autofree gchar *str = NULL; - if (device == NULL) - return FALSE; - if (!fu_usb_device_open (FU_USB_DEVICE (device), error)) - return FALSE; - str = fu_device_to_string (FU_DEVICE (device)); - g_print ("%s", str); - return TRUE; -} - -static void -fu_csr_tool_progress_cb (FuDevice *device, GParamSpec *pspec, FuCsrToolPrivate *priv) -{ - fu_progressbar_update (priv->progressbar, - fu_device_get_status (device), - fu_device_get_progress (device)); -} - -static gboolean -fu_csr_tool_dump (FuCsrToolPrivate *priv, gchar **values, GError **error) -{ - GUsbDevice *usb_device; - g_autoptr(DfuElement) dfu_element = dfu_element_new (); - g_autoptr(DfuFirmware) dfu_firmware = dfu_firmware_new (); - g_autoptr(DfuImage) dfu_image = dfu_image_new (); - g_autoptr(FuCsrDevice) device = NULL; - g_autoptr(GBytes) blob = NULL; - g_autoptr(GFile) file = NULL; - - /* check args */ - if (g_strv_length (values) != 1) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Invalid arguments, expected FILENAME" - " -- e.g. `firmware.hex`"); - return FALSE; - } - - /* upload from the device */ - device = fu_csr_get_default_device (priv, error); - if (device == NULL) - return FALSE; - if (!fu_usb_device_open (FU_USB_DEVICE (device), error)) - return FALSE; - g_signal_connect (device, "notify::status", - G_CALLBACK (fu_csr_tool_progress_cb), priv); - g_signal_connect (device, "notify::progress", - G_CALLBACK (fu_csr_tool_progress_cb), priv); - blob = fu_csr_device_upload (device, error); - if (blob == NULL) - return FALSE; - - /* create DFU file */ - usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - dfu_element_set_contents (dfu_element, blob); - dfu_image_add_element (dfu_image, dfu_element); - dfu_firmware_add_image (dfu_firmware, dfu_image); - dfu_firmware_set_format (dfu_firmware, DFU_FIRMWARE_FORMAT_DFU); - dfu_firmware_set_vid (dfu_firmware, g_usb_device_get_vid (usb_device)); - dfu_firmware_set_pid (dfu_firmware, g_usb_device_get_pid (usb_device)); - - /* save file */ - file = g_file_new_for_path (values[0]); - return dfu_firmware_write_file (dfu_firmware, file, error); -} - -static gboolean -fu_csr_tool_write (FuCsrToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(FuCsrDevice) device = NULL; - g_autoptr(GBytes) blob = NULL; - - /* check args */ - if (g_strv_length (values) != 1) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Invalid arguments, expected " - "FILENAME -- e.g. `firmware.hex`"); - return FALSE; - } - - /* get device */ - device = fu_csr_get_default_device (priv, error); - if (device == NULL) - return FALSE; - - /* load firmware file */ - blob = fu_common_get_contents_bytes (values[0], error); - if (blob == NULL) - return FALSE; - - /* write new firmware */ - if (!fu_usb_device_open (FU_USB_DEVICE (device), error)) - return FALSE; - g_signal_connect (device, "notify::status", - G_CALLBACK (fu_csr_tool_progress_cb), priv); - g_signal_connect (device, "notify::progress", - G_CALLBACK (fu_csr_tool_progress_cb), priv); - return fu_csr_device_download (device, blob, error); -} - -static gboolean -fu_csr_tool_attach (FuCsrToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(FuCsrDevice) device = NULL; - device = fu_csr_get_default_device (priv, error); - if (device == NULL) - return FALSE; - if (!fu_usb_device_open (FU_USB_DEVICE (device), error)) - return FALSE; - return fu_csr_device_attach (device, error); -} - -int -main (int argc, char **argv) -{ - gboolean verbose = FALSE; - g_autofree gchar *cmd_descriptions = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GOptionContext) context = NULL; - g_autoptr(FuCsrToolPrivate) priv = g_new0 (FuCsrToolPrivate, 1); - const GOptionEntry options[] = { - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - "Print verbose debug statements", NULL }, - { NULL} - }; - setlocale (LC_ALL, ""); - - priv->progressbar = fu_progressbar_new (); - fu_progressbar_set_length_percentage (priv->progressbar, 50); - fu_progressbar_set_length_status (priv->progressbar, 20); - - /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_csr_tool_item_free); - fu_csr_tool_add (priv->cmd_array, - "info", NULL, - "Show information about the device", - fu_csr_tool_info); - fu_csr_tool_add (priv->cmd_array, - "write", "FILENAME", - "Update the firmware", - fu_csr_tool_write); - fu_csr_tool_add (priv->cmd_array, - "dump", "FILENAME", - "Dump the firmware", - fu_csr_tool_dump); - fu_csr_tool_add (priv->cmd_array, - "attach", NULL, - "Attach to firmware mode", - fu_csr_tool_attach); - - /* sort by command name */ - g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) fu_csr_tool_sort_command_name_cb); - - /* get a list of the commands */ - context = g_option_context_new (NULL); - cmd_descriptions = fu_csr_tool_get_descriptions (priv->cmd_array); - g_option_context_set_summary (context, cmd_descriptions); - g_set_application_name ("CSR Debug Tool"); - g_option_context_add_main_entries (context, options, NULL); - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("%s: %s\n", "Failed to parse arguments", error->message); - return EXIT_FAILURE; - } - - /* set verbose? */ - if (verbose) - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - - /* use quirks */ - priv->quirks = fu_quirks_new (); - if (!fu_quirks_load (priv->quirks, &error)) { - g_print ("Failed to load quirks: %s\n", error->message); - return EXIT_FAILURE; - } - - /* run the specified command */ - if (!fu_csr_tool_run (priv, argv[1], (gchar**) &argv[2], &error)) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { - g_autofree gchar *tmp = NULL; - tmp = g_option_context_get_help (context, TRUE, NULL); - g_print ("%s\n\n%s", error->message, tmp); - } else { - g_print ("%s\n", error->message); - } - return EXIT_FAILURE; - } - - return 0; -} diff -Nru fwupd-1.0.6/plugins/csr/fu-plugin-csr.c fwupd-1.2.10/plugins/csr/fu-plugin-csr.c --- fwupd-1.0.6/plugins/csr/fu-plugin-csr.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/fu-plugin-csr.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,42 +1,33 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "fu-csr-device.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.qualcomm.dfu"); +} + gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { - g_autoptr(FuCsrDevice) device = NULL; + g_autoptr(FuCsrDevice) dev = NULL; g_autoptr(FuDeviceLocker) locker = NULL; - device = fu_csr_device_new (usb_device); - fu_device_set_quirks (FU_DEVICE (device), fu_plugin_get_quirks (plugin)); - locker = fu_device_locker_new (device, error); + dev = fu_csr_device_new (device); + locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; - fu_plugin_device_add (plugin, FU_DEVICE (device)); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } @@ -55,7 +46,7 @@ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; - blob_fw = fu_csr_device_upload (FU_CSR_DEVICE (device), error); + blob_fw = fu_device_read_firmware (device, error); if (blob_fw == NULL) return FALSE; for (guint i = 0; checksum_types[i] != 0; i++) { @@ -74,7 +65,7 @@ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; - if (!fu_csr_device_download (FU_CSR_DEVICE (device), blob_fw, error)) + if (!fu_device_write_firmware (device, blob_fw, flags, error)) return FALSE; - return fu_csr_device_attach (FU_CSR_DEVICE (device), error); + return fu_device_attach (device, error); } diff -Nru fwupd-1.0.6/plugins/csr/meson.build fwupd-1.2.10/plugins/csr/meson.build --- fwupd-1.0.6/plugins/csr/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,13 +1,11 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginCsr"'] -install_data([ - 'csr-aiaiai-h05.quirk', - 'csr-aiaiai-h60.quirk', - ], +install_data(['csr-aiaiai.quirk'], install_dir: join_paths(datadir, 'fwupd', 'quirks.d') ) shared_module('fu_plugin_csr', + fu_hash, sources : [ 'fu-csr-device.c', 'fu-plugin-csr.c', @@ -25,29 +23,7 @@ plugin_deps, ], link_with : [ - dfu, - ], -) - -executable( - 'fu-csr-tool', - sources : [ - 'fu-csr-device.c', - 'fu-csr-tool.c', - ], - include_directories : [ - include_directories('../..'), - include_directories('../dfu'), - include_directories('../../libfwupd'), - include_directories('../../src'), - ], - dependencies : [ - plugin_deps, - ], - link_with : [ - dfu, - fwupd, libfwupdprivate, + dfu, ], - c_args : cargs, ) diff -Nru fwupd-1.0.6/plugins/csr/README.md fwupd-1.2.10/plugins/csr/README.md --- fwupd-1.0.6/plugins/csr/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/csr/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,36 @@ +CSR Support +=========== + +Introduction +------------ + +CSR is often called “driverless DFU” and is used only by BlueCore chips from +Cambridge Silicon Radio (now owned by Qualcomm). The driverless just means that +it's DFU like, and is routed over HID. + +CSR is a ODM that makes most of the Bluetooth audio chips in vendor hardware. +The hardware vendor can enable or disable features on the CSR microcontroller +depending on licensing options (for instance echo cancellation), and there’s +even a little virtual machine to do simple vendor-specific things. + +All the CSR chips are updatable in-field, and most vendors issue updates to fix +sound quality issues or to add support for new protocols or devices. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU file format. + +This plugin supports the following protocol ID: + + * com.qualcomm.dfu + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0A12&PID_1337&REV_2520` + * `USB\VID_0A12&PID_1337` + * `USB\VID_0A12` diff -Nru fwupd-1.0.6/plugins/dell/dell.quirk fwupd-1.2.10/plugins/dell/dell.quirk --- fwupd-1.0.6/plugins/dell/dell.quirk 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/dell.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -1,8 +1,40 @@ -[fwupd-uefi-version-format] +# Realtek NIC in Dell docks +[DeviceInstanceId=USB\VID_0BDA&PID_8153] +Plugin = dell -# Dell & Alienware use AA.BB.CC.DD rather than AA.BB.CCDD -Dell Inc.=none -Alienware=none +# Dell TB16/TB18 cable +[Guid=TBT-00d4b051] +Plugin = thunderbolt +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 -[fwupd-daemon-version-format] -com.dell.uefi*.firmware=none +# Dell TB16/TB18 dock +[Guid=TBT-00d4b054] +Plugin = thunderbolt +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 + +# Dell WD15 dock +[Guid=MST-wd15-vmm3332-274] +Plugin = synapticsmst +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 + +# Dell TB16 dock +[Guid=MST-tb16-vmm3320-274] +Plugin = synapticsmst +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 +[Guid=MST-tb16-vmm3330-274] +Plugin = synapticsmst +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 + +#Dell TB18 dock +[Guid=MST-tb18-vmm3320-274] +Plugin = synapticsmst +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 +[Guid=MST-tb18-vmm3330-274] +Plugin = synapticsmst +ParentGuid = e7ca1f36-bf73-4574-afe6-a4ccacabf479 + +[SmbiosManufacturer=Dell Inc.] +UefiVersionFormat = quad + +[SmbiosManufacturer=Alienware] +UefiVersionFormat = quad diff -Nru fwupd-1.0.6/plugins/dell/fu-dell-smi.c fwupd-1.2.10/plugins/dell/fu-dell-smi.c --- fwupd-1.0.6/plugins/dell/fu-dell-smi.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/fu-dell-smi.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017 Mario Limonciello * - * Copyright (C) 2017 Mario Limonciello - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include #include "fu-dell-smi.h" /* These are for dock query capabilities */ @@ -53,7 +37,10 @@ g_free(obj); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC (FuDellSmiObj, _dell_smi_obj_free); +#pragma clang diagnostic pop /* don't actually clear if we're testing */ gboolean @@ -275,4 +262,4 @@ return FALSE; } return TRUE; -} \ No newline at end of file +} diff -Nru fwupd-1.0.6/plugins/dell/fu-dell-smi.h fwupd-1.2.10/plugins/dell/fu-dell-smi.h --- fwupd-1.0.6/plugins/dell/fu-dell-smi.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/fu-dell-smi.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017 Mario Limonciello * - * Copyright (C) 2017 Mario Limonciello - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DELL_COMMON_H -#define __FU_DELL_COMMON_H +#pragma once #include "fu-device.h" #include @@ -141,5 +125,3 @@ /* VID/PID of ethernet controller on dock */ #define DOCK_NIC_VID 0x0bda #define DOCK_NIC_PID 0x8153 - -#endif /* __FU_DELL_COMMON_H */ diff -Nru fwupd-1.0.6/plugins/dell/fu-plugin-dell.c fwupd-1.2.10/plugins/dell/fu-plugin-dell.c --- fwupd-1.0.6/plugins/dell/fu-plugin-dell.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/fu-plugin-dell.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,35 +1,19 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes - * Copyright (C) 2016 Mario Limonciello - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, or - * (at your option) any later version. + * Copyright (C) 2016 Mario Limonciello * - * 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include -#include #include #include #include #include #include +#include "fwupd-common.h" #include "fu-plugin-dell.h" #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" @@ -56,11 +40,21 @@ typedef struct _DOCK_DESCRIPTION { - const efi_guid_t guid; + const gchar * guid; const gchar * query; const gchar * desc; } DOCK_DESCRIPTION; +struct da_structure { + guint8 type; + guint8 length; + guint16 handle; + guint16 cmd_address; + guint8 cmd_code; + guint32 supported_cmds; + guint8 *tokens; +} __attribute__((packed)); + /* These are for matching the components */ #define WD15_EC_STR "2 0 2 2 0" #define TB16_EC_STR "2 0 2 1 0" @@ -70,17 +64,19 @@ #define LEGACY_CBL_STR "2 2 2 1 0" #define UNIV_CBL_STR "2 2 2 2 0" #define TBT_CBL_STR "2 2 2 3 0" +#define FUTURE_EC_STR "3 0 2 4 0" +#define FUTURE_EC_STR2 "4 0 2 4 0" /* supported dock related GUIDs */ -#define DOCK_FLASH_GUID EFI_GUID (0xE7CA1F36, 0xBF73, 0x4574, 0xAFE6, 0xA4, 0xCC, 0xAC, 0xAB, 0xF4, 0x79) -#define WD15_EC_GUID EFI_GUID (0xE8445370, 0x0211, 0x449D, 0x9FAA, 0x10, 0x79, 0x06, 0xAB, 0x18, 0x9F) -#define TB16_EC_GUID EFI_GUID (0x33CC8870, 0xB1FC, 0x4EC7, 0x948A, 0xC0, 0x74, 0x96, 0x87, 0x4F, 0xAF) -#define TB16_PC2_GUID EFI_GUID (0x1B52C630, 0x86F6, 0x4AEE, 0x9F0C, 0x47, 0x4D, 0xC6, 0xBE, 0x49, 0xB6) -#define TB16_PC1_GUID EFI_GUID (0x8FE183DA, 0xC94E, 0x4804, 0xB319, 0x0F, 0x1B, 0xA5, 0x45, 0x7A, 0x69) -#define WD15_PC1_GUID EFI_GUID (0x8BA2B709, 0x6F97, 0x47FC, 0xB7E7, 0x6A, 0x87, 0xB5, 0x78, 0xFE, 0x25) -#define LEGACY_CBL_GUID EFI_GUID (0xFECE1537, 0xD683, 0x4EA8, 0xB968, 0x15, 0x45, 0x30, 0xBB, 0x6F, 0x73) -#define UNIV_CBL_GUID EFI_GUID (0xE2BF3AAD, 0x61A3, 0x44BF, 0x91EF, 0x34, 0x9B, 0x39, 0x51, 0x5D, 0x29) -#define TBT_CBL_GUID EFI_GUID (0x6DC832FC, 0x5BB0, 0x4E63, 0xA2FF, 0x02, 0xAA, 0xBA, 0x5B, 0xC1, 0xDC) +#define DOCK_FLASH_GUID "e7ca1f36-bf73-4574-afe6-a4ccacabf479" +#define WD15_EC_GUID "e8445370-0211-449d-9faa-107906ab189f" +#define TB16_EC_GUID "33cc8870-b1fc-4ec7-948a-c07496874faf" +#define TB16_PC2_GUID "1b52c630-86f6-4aee-9f0c-474dc6be49b6" +#define TB16_PC1_GUID "8fe183da-c94e-4804-b319-0f1ba5457a69" +#define WD15_PC1_GUID "8ba2b709-6f97-47fc-b7e7-6a87b578fe25" +#define LEGACY_CBL_GUID "fece1537-d683-4ea8-b968-154530bb6f73" +#define UNIV_CBL_GUID "e2bf3aad-61a3-44bf-91ef-349b39515d29" +#define TBT_CBL_GUID "6dc832fc-5bb0-4e63-a2ff-02aaba5bc1dc" #define EC_DESC "EC" #define PC1_DESC "Port Controller 1" @@ -122,13 +118,6 @@ 0x22, /* embedded PC */}; /** - * System blacklist on older libsmbios - */ -static guint16 system_blacklist [] = { 0x071E, /* latitude 5414 */ - 0x07A8, /* latitude 5580 */ - 0x077A, /* xps 9365 */ }; - -/** * Systems containing host MST device */ static guint16 systems_host_mst [] = { 0x062d, /* Latitude E7250 */ @@ -146,14 +135,6 @@ 0x071e, /* Latitude Rugged 5414 */ 0x071c, /* Latitude Rugged 7414 */}; -static void -_fwup_resource_iter_free (fwup_resource_iter *iter) -{ - fwup_resource_iter_destroy (&iter); -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC (fwup_resource_iter, _fwup_resource_iter_free); - static guint16 fu_dell_get_system_id (FuPlugin *plugin) { @@ -188,11 +169,11 @@ static gboolean fu_dell_supported (FuPlugin *plugin) { - FuPluginData *data = fu_plugin_get_data (plugin); GBytes *de_table = NULL; + GBytes *da_table = NULL; GBytes *enclosure = NULL; - guint16 system_id = 0; const guint8 *value; + const struct da_structure *da_values; gsize len; /* make sure that Dell SMBIOS methods are available */ @@ -204,17 +185,16 @@ return FALSE; if (*value != 0xDE) return FALSE; - - /* skip blacklisted hw on libsmbios 2.3 or less */ - if (data->libsmbios_major <= 2 && - data->libsmbios_minor <= 3) { - system_id = fu_dell_get_system_id (plugin); - if (system_id == 0) - return FALSE; - for (guint i = 0; i < G_N_ELEMENTS (system_blacklist); i++) { - if (system_blacklist[i] == system_id) - return FALSE; - } + da_table = fu_plugin_get_smbios_data (plugin, 0xDA); + if (da_table == NULL) + return FALSE; + da_values = (struct da_structure *) g_bytes_get_data (da_table, &len); + if (len == 0) + return FALSE; + if (!(da_values->supported_cmds & (1 << DACI_FLASH_INTERFACE_CLASS))) { + g_debug ("unable to access flash interface. supported commands: 0x%x", + da_values->supported_cmds); + return FALSE; } /* only run on intended Dell hw types */ @@ -235,7 +215,7 @@ static gboolean fu_plugin_dell_match_dock_component (const gchar *query_str, - efi_guid_t *guid_out, + const gchar **guid_out, const gchar **name_out) { const DOCK_DESCRIPTION list[] = { @@ -247,12 +227,14 @@ {TBT_CBL_GUID, TBT_CBL_STR, TBT_CBL_DESC}, {UNIV_CBL_GUID, UNIV_CBL_STR, UNIV_CBL_DESC}, {LEGACY_CBL_GUID, LEGACY_CBL_STR, LEGACY_CBL_DESC}, + {NULL, FUTURE_EC_STR, NULL}, + {NULL, FUTURE_EC_STR2, NULL}, }; for (guint i = 0; i < G_N_ELEMENTS (list); i++) { if (g_strcmp0 (query_str, list[i].query) == 0) { - memcpy (guid_out, &list[i].guid, sizeof (efi_guid_t)); + *guid_out = list[i].guid; *name_out = list[i].desc; return TRUE; } @@ -277,39 +259,24 @@ data->can_switch_modes = TRUE; } -static AsVersionParseFlag +static FwupdVersionFormat fu_plugin_dell_get_version_format (FuPlugin *plugin) { const gchar *content; const gchar *quirk; + g_autofree gchar *group = NULL; content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); if (content == NULL) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FWUPD_VERSION_FORMAT_TRIPLET; /* any quirks match */ - quirk = fu_plugin_lookup_quirk_by_id (plugin, - FU_QUIRKS_UEFI_VERSION_FORMAT, - content); - if (g_strcmp0 (quirk, "none") == 0) - return AS_VERSION_PARSE_FLAG_NONE; - - /* fall back */ - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; -} - -static gchar * -fu_plugin_get_dock_key (FuPlugin *plugin, - GUsbDevice *device, const gchar *guid) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar* platform_id; - - if (data->smi_obj->fake_smbios) - platform_id = "fake"; - else - platform_id = g_usb_device_get_platform_id (device); - return g_strdup_printf ("%s_%s", platform_id, guid); + group = g_strdup_printf ("SmbiosManufacturer=%s", content); + quirk = fu_plugin_lookup_quirk_by_id (plugin, group, + FU_QUIRKS_UEFI_VERSION_FORMAT); + if (quirk == NULL) + return FWUPD_VERSION_FORMAT_TRIPLET; + return fwupd_version_format_from_string (quirk); } static gboolean @@ -321,14 +288,12 @@ } static gboolean -fu_plugin_dock_node (FuPlugin *plugin, GUsbDevice *device, - guint8 type, const efi_guid_t *guid_raw, - const gchar *component_desc, const gchar *version) +fu_plugin_dock_node (FuPlugin *plugin, const gchar *platform, + guint8 type, const gchar *component_guid, + const gchar *component_desc, const gchar *version, + FwupdVersionFormat version_format) { const gchar *dock_type; - g_autofree gchar *dock_id = NULL; - g_autofree gchar *guid_str = NULL; - g_autofree gchar *dock_key = NULL; g_autofree gchar *dock_name = NULL; g_autoptr(FuDevice) dev = NULL; @@ -338,89 +303,90 @@ return FALSE; } - guid_str = g_strdup ("00000000-0000-0000-0000-000000000000"); - if (efi_guid_to_str (guid_raw, &guid_str) < 0) { - g_debug ("Failed to convert GUID."); - return FALSE; - } - - dock_key = fu_plugin_get_dock_key (plugin, device, - guid_str); - if (fu_plugin_cache_lookup (plugin, dock_key) != NULL) { - g_debug ("%s is already registered.", dock_key); - return FALSE; - } - dev = fu_device_new (); - dock_id = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, guid_str); - dock_name = g_strdup_printf ("Dell %s %s", dock_type, - component_desc); - fu_device_set_id (dev, dock_id); + fu_device_set_physical_id (dev, platform); + fu_device_set_logical_id (dev, component_guid); + if (component_desc != NULL) { + dock_name = g_strdup_printf ("Dell %s %s", dock_type, + component_desc); + fu_device_add_parent_guid (dev, DOCK_FLASH_GUID); + } else { + dock_name = g_strdup_printf ("Dell %s", dock_type); + } fu_device_set_vendor (dev, "Dell Inc."); fu_device_set_name (dev, dock_name); + fu_device_set_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND, "device-firmware"); if (type == DOCK_TYPE_TB16) { fu_device_set_summary (dev, "A Thunderbolt™ 3 docking station"); } else if (type == DOCK_TYPE_WD15) { fu_device_set_summary (dev, "A USB type-C docking station"); } fu_device_add_icon (dev, "computer"); - fu_device_add_guid (dev, guid_str); + fu_device_add_guid (dev, component_guid); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); if (version != NULL) { - fu_device_set_version (dev, version); + fu_device_set_version (dev, version, version_format); if (fu_plugin_dell_capsule_supported (plugin)) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + } else { + fu_device_set_update_error (dev, + "UEFI capsule updates turned off in BIOS setup"); } } - fu_plugin_device_add (plugin, dev); - fu_plugin_cache_add (plugin, dock_key, dev); + fu_plugin_device_register (plugin, dev); return TRUE; } - -void -fu_plugin_dell_device_added_cb (GUsbContext *ctx, - GUsbDevice *device, - FuPlugin *plugin) +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, + FuUsbDevice *device, + GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - AsVersionParseFlag parse_flags; + FwupdVersionFormat version_format; guint16 pid; guint16 vid; const gchar *query_str; + const gchar *component_guid = NULL; const gchar *component_name = NULL; + const gchar *platform; DOCK_UNION buf; DOCK_INFO *dock_info; - efi_guid_t guid_raw; - efi_guid_t tmpguid; gboolean old_ec = FALSE; + g_autofree gchar *flash_ver_str = NULL; /* don't look up immediately if a dock is connected as that would mean a SMI on every USB device that showed up on the system */ if (!data->smi_obj->fake_smbios) { - vid = g_usb_device_get_vid (device); - pid = g_usb_device_get_pid (device); + vid = fu_usb_device_get_vid (device); + pid = fu_usb_device_get_pid (device); + platform = fu_device_get_physical_id (FU_DEVICE (device)); } else { vid = data->fake_vid; pid = data->fake_pid; + platform = "fake"; } /* we're going to match on the Realtek NIC in the dock */ - if (vid != DOCK_NIC_VID || pid != DOCK_NIC_PID) - return; + if (vid != DOCK_NIC_VID || pid != DOCK_NIC_PID) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "wrong VID/PID %04x:%04x", vid, pid); + return FALSE; + } buf.buf = NULL; if (!fu_dell_query_dock (data->smi_obj, &buf)) { - g_debug ("No dock detected."); - return; + g_debug ("no dock detected"); + return TRUE; } if (buf.record->dock_info_header.dir_version != 1) { - g_debug ("Dock info header version unknown: %d", - buf.record->dock_info_header.dir_version); - return; + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "dock info header version unknown %d", + buf.record->dock_info_header.dir_version); + return FALSE; } dock_info = &buf.record->dock_info; @@ -432,7 +398,7 @@ g_debug ("Dock cable type: %" G_GUINT32_FORMAT, dock_info->cable_type); g_debug ("Dock location: %d", dock_info->location); g_debug ("Dock component count: %d", dock_info->component_count); - parse_flags = fu_plugin_dell_get_version_format (plugin); + version_format = fu_plugin_dell_get_version_format (plugin); for (guint i = 0; i < dock_info->component_count; i++) { g_autofree gchar *fw_str = NULL; @@ -446,15 +412,20 @@ query_str = g_strrstr (dock_info->components[i].description, "Query "); if (query_str == NULL) { - g_debug ("Invalid dock component request"); - return; + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "invalid dock component request"); + return FALSE; } if (!fu_plugin_dell_match_dock_component (query_str + 6, - &guid_raw, + &component_guid, &component_name)) { - g_debug ("Unable to match dock component %s", - query_str); - return; + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "invalid dock component request %s", query_str); + return FALSE; + } + if (component_guid == NULL || component_name == NULL) { + g_debug ("%s is supported by another plugin", query_str); + return TRUE; } /* dock EC hasn't been updated for first time */ @@ -470,87 +441,42 @@ continue; } - fw_str = as_utils_version_from_uint32 (dock_info->components[i].fw_version, - parse_flags); + fw_str = fu_common_version_from_uint32 (dock_info->components[i].fw_version, + version_format); if (!fu_plugin_dock_node (plugin, - device, - buf.record->dock_info_header.dock_type, - &guid_raw, - component_name, - fw_str)) { - g_debug ("Failed to create %s", component_name); - return; + platform, + buf.record->dock_info_header.dock_type, + component_guid, + component_name, + fw_str, + version_format)) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "failed to create %s", component_name); + return FALSE; } } /* if an old EC or invalid EC version found, create updatable parent */ - if (old_ec) { - g_autofree gchar *fw_str = NULL; - tmpguid = DOCK_FLASH_GUID; - fw_str = as_utils_version_from_uint32 (dock_info->flash_pkg_version, - parse_flags); - if (!fu_plugin_dock_node (plugin, - device, - buf.record->dock_info_header.dock_type, - &tmpguid, - "", - fw_str)) { - g_debug ("Failed to create top dock node"); - return; - } - } - -#if defined (HAVE_SYNAPTICS) - fu_plugin_request_recoldplug (plugin); -#endif -} - -void -fu_plugin_dell_device_removed_cb (GUsbContext *ctx, - GUsbDevice *device, - FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const efi_guid_t guids[] = { WD15_EC_GUID, TB16_EC_GUID, TB16_PC2_GUID, - TB16_PC1_GUID, WD15_PC1_GUID, - LEGACY_CBL_GUID, UNIV_CBL_GUID, - TBT_CBL_GUID, DOCK_FLASH_GUID}; - const efi_guid_t *guid_raw; - guint16 pid; - guint16 vid; - FuDevice *dev = NULL; + if (old_ec) + flash_ver_str = fu_common_version_from_uint32 (dock_info->flash_pkg_version, + version_format); + if (!fu_plugin_dock_node (plugin, + platform, + buf.record->dock_info_header.dock_type, + DOCK_FLASH_GUID, + NULL, + flash_ver_str, + version_format)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "failed to create top dock node"); - if (!data->smi_obj->fake_smbios) { - vid = g_usb_device_get_vid (device); - pid = g_usb_device_get_pid (device); - } else { - vid = data->fake_vid; - pid = data->fake_pid; + return FALSE; } - /* we're going to match on the Realtek NIC in the dock */ - if (vid != DOCK_NIC_VID || pid != DOCK_NIC_PID) - return; - - /* remove any components already in database? */ - for (guint i = 0; i < G_N_ELEMENTS (guids); i++) { - g_autofree gchar *dock_key = NULL; - g_autofree gchar *guid_str = NULL; - guid_raw = &guids[i]; - guid_str = g_strdup ("00000000-0000-0000-0000-000000000000"); - efi_guid_to_str (guid_raw, &guid_str); - dock_key = fu_plugin_get_dock_key (plugin, device, - guid_str); - dev = fu_plugin_cache_lookup (plugin, dock_key); - if (dev != NULL) { - fu_plugin_device_remove (plugin, - dev); - fu_plugin_cache_remove (plugin, dock_key); - } - } #if defined (HAVE_SYNAPTICS) fu_plugin_request_recoldplug (plugin); #endif + return TRUE; } gboolean @@ -576,7 +502,7 @@ if (completion_code[3] == DELL_SUCCESS) { fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); } else { - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + FwupdUpdateState update_state = FWUPD_UPDATE_STATE_FAILED; switch (completion_code[3]) { case DELL_CONSISTENCY_FAIL: tmp = "The image failed one or more consistency checks."; @@ -592,12 +518,15 @@ break; case DELL_BATTERY_MISSING: tmp = "A battery must be installed for the operation to complete."; + update_state = FWUPD_UPDATE_STATE_FAILED_TRANSIENT; break; case DELL_BATTERY_DEAD: tmp = "A fully-charged battery must be present for the operation to complete."; + update_state = FWUPD_UPDATE_STATE_FAILED_TRANSIENT; break; case DELL_AC_MISSING: tmp = "An external power adapter must be connected for the operation to complete."; + update_state = FWUPD_UPDATE_STATE_FAILED_TRANSIENT; break; case DELL_CANT_SET_12V: tmp = "The 12V required to program the flash-memory could not be set."; @@ -623,6 +552,7 @@ default: break; } + fu_device_set_update_state (device, update_state); if (tmp != NULL) fu_device_set_update_error (device, tmp); } @@ -650,7 +580,7 @@ struct tpm_status *out = NULL; g_autoptr (FuDevice) dev_alt = NULL; g_autoptr (FuDevice) dev = NULL; - const gchar *product_name = NULL; + const gchar *product_name = "Unknown"; fu_dell_clear_smi (data->smi_obj); out = (struct tpm_status *) data->smi_obj->output; @@ -704,17 +634,17 @@ } tpm_guid_raw = g_strdup_printf ("%04x-%s", system_id, tpm_mode); - tpm_guid = as_utils_guid_from_string (tpm_guid_raw); + tpm_guid = fwupd_guid_hash_string (tpm_guid_raw); tpm_id = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid); tpm_guid_raw_alt = g_strdup_printf ("%04x-%s", system_id, tpm_mode_alt); - tpm_guid_alt = as_utils_guid_from_string (tpm_guid_raw_alt); + tpm_guid_alt = fwupd_guid_hash_string (tpm_guid_raw_alt); tpm_id_alt = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid_alt); g_debug ("Creating primary TPM GUID %s and secondary TPM GUID %s", tpm_guid_raw, tpm_guid_raw_alt); - version_str = as_utils_version_from_uint32 (out->fw_version, - AS_VERSION_PARSE_FLAG_NONE); + version_str = fu_common_version_from_uint32 (out->fw_version, + FWUPD_VERSION_FORMAT_QUAD); /* make it clear that the TPM is a discrete device of the product */ if (!data->smi_obj->fake_smbios) { @@ -730,21 +660,25 @@ fu_device_set_vendor (dev, "Dell Inc."); fu_device_set_name (dev, pretty_tpm_name); fu_device_set_summary (dev, "Platform TPM device"); - fu_device_set_version (dev, version_str); + fu_device_set_version (dev, version_str, FWUPD_VERSION_FORMAT_QUAD); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_icon (dev, "computer"); + fu_device_set_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND, "dell-tpm-firmware"); if ((out->status & TPM_OWN_MASK) == 0 && out->flashes_left > 0) { if (fu_plugin_dell_capsule_supported (plugin)) { fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + } else { + fu_device_set_update_error (dev, + "UEFI capsule updates turned off in BIOS setup"); } fu_device_set_flashes_left (dev, out->flashes_left); } else { g_debug ("%s updating disabled due to TPM ownership", pretty_tpm_name); } - fu_plugin_device_add (plugin, dev); + fu_plugin_device_register (plugin, dev); /* build alternate device node */ if (can_switch_modes) { @@ -758,7 +692,9 @@ fu_device_add_flag (dev_alt, FWUPD_DEVICE_FLAG_REQUIRE_AC); fu_device_add_flag (dev_alt, FWUPD_DEVICE_FLAG_LOCKED); fu_device_add_icon (dev_alt, "computer"); - fu_device_set_alternate (dev_alt, dev); + fu_device_set_alternate_id (dev_alt, fu_device_get_id (dev)); + fu_device_set_metadata (dev_alt, FU_DEVICE_METADATA_UEFI_DEVICE_KIND, "dell-tpm-firmware"); + fu_device_add_parent_guid (dev_alt, tpm_guid); /* If TPM is not owned and at least 1 flash left allow mode switching * @@ -771,7 +707,7 @@ g_debug ("%s mode switch disabled due to TPM ownership", pretty_tpm_name); } - fu_plugin_device_add (plugin, dev_alt); + fu_plugin_device_register (plugin, dev_alt); } else g_debug ("System %04x does not offer TPM modeswitching", @@ -780,165 +716,6 @@ return TRUE; } -gboolean -fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error) -{ - FuDevice *device_alt = NULL; - FwupdDeviceFlags device_flags_alt = 0; - guint flashes_left = 0; - guint flashes_left_alt = 0; - - /* for unlocking TPM1.2 <-> TPM2.0 switching */ - g_debug ("Unlocking upgrades for: %s (%s)", fu_device_get_name (device), - fu_device_get_id (device)); - device_alt = fu_device_get_alternate (device); - - if (!device_alt) - return FALSE; - g_debug ("Preventing upgrades for: %s (%s)", fu_device_get_name (device_alt), - fu_device_get_id (device_alt)); - - flashes_left = fu_device_get_flashes_left (device); - flashes_left_alt = fu_device_get_flashes_left (device_alt); - if (flashes_left == 0) { - /* flashes left == 0 on both means no flashes left */ - if (flashes_left_alt == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "ERROR: %s has no flashes left.", - fu_device_get_name (device)); - /* flashes left == 0 on just unlocking device is ownership */ - } else { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "ERROR: %s is currently OWNED. " - "Ownership must be removed to switch modes.", - fu_device_get_name (device_alt)); - } - return FALSE; - } - - - /* clone the info from real device but prevent it from being flashed */ - device_flags_alt = fu_device_get_flags (device_alt); - fu_device_set_flags (device, device_flags_alt); - fu_device_set_flags (device_alt, device_flags_alt & ~FWUPD_DEVICE_FLAG_UPDATABLE); - - /* make sure that this unlocked device can be updated */ - fu_device_set_version (device, "0.0.0.0"); - - return TRUE; -} - -gboolean -fu_plugin_update (FuPlugin *plugin, - FuDevice *device, - GBytes *blob_fw, - FwupdInstallFlags flags, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr (fwup_resource_iter) iter = NULL; - fwup_resource *re = NULL; - const gchar *name = NULL; - gint rc; - guint flashes_left; - const gchar *guidstr = NULL; - efi_guid_t guid; - - /* test the flash counter - * - devices with 0 left at setup aren't allowed offline updates - * - devices greater than 0 should show a warning when near 0 - */ - flashes_left = fu_device_get_flashes_left (device); - if (flashes_left > 0) { - name = fu_device_get_name (device); - g_debug ("%s has %u flashes left", name, flashes_left); - if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && - flashes_left <= 2) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "WARNING: %s only has %u flashes left. " - "See https://github.com/hughsie/fwupd/wiki/Dell-TPM:-flashes-left for more information.", - name, flashes_left); - return FALSE; - } - } - - if (data->smi_obj->fake_smbios) - return TRUE; - - /* perform the update */ - g_debug ("Performing capsule update"); - - /* Stuff the payload into a different GUID - * - with fwup 0.5 this uses the ESRT GUID - * - with fwup 0.6 this uses the payload's GUID - * it's preferable to use payload GUID to avoid - * a corner case scenario of UEFI BIOS and non-ESRT - * update happening at same time - */ - fwup_resource_iter_create (&iter); - fwup_resource_iter_next (iter, &re); - guidstr = fu_device_get_guid_default (device); - rc = efi_str_to_guid (guidstr, &guid); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to convert guid to string"); - return FALSE; - } - rc = fwup_set_guid (iter, &re, &guid); - if (rc < 0 || re == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Failed to update GUID %s", - strerror (rc)); - return FALSE; - } - - /* NOTE: if there are problems with this working, adjust the - * GUID in the capsule header to match something in ESRT. - * This won't actually cause any bad behavior because the real - * payload GUID is extracted later on. - */ - fu_device_set_status (device, FWUPD_STATUS_SCHEDULING); - rc = fwup_set_up_update_with_buf (re, 0, - g_bytes_get_data (blob_fw, NULL), - g_bytes_get_size (blob_fw)); - if (rc < 0) { - g_autoptr(GString) err_string = g_string_new ("Dell firmware update failed:\n"); - - rc = 1; - for (int i = 0; rc > 0; i++) { - char *filename = NULL; - char *function = NULL; - char *message = NULL; - int line = 0; - int err = 0; - - rc = efi_error_get (i, &filename, &function, &line, &message, &err); - if (rc <= 0) - break; - g_string_append_printf (err_string, - "{error #%d} %s:%d %s(): %s: %s \n", - i, filename, line, function, message, strerror(err)); - } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "%s", - err_string->str); - return FALSE; - } - return TRUE; -} - void fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) { @@ -959,7 +736,7 @@ device_id = g_strdup_printf ("TBT-%04x%04x", 0x00d4u, (unsigned) system_id); fu_device_set_vendor_id (device, vendor_id); - fu_device_add_guid (device, device_id); + fu_device_add_instance_id (device, device_id); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); } } @@ -1012,6 +789,7 @@ gboolean fu_plugin_update_prepare (FuPlugin *plugin, + FwupdInstallFlags flags, FuDevice *device, GError **error) { @@ -1021,6 +799,7 @@ gboolean fu_plugin_update_cleanup (FuPlugin *plugin, + FwupdInstallFlags flags, FuDevice *device, GError **error) { @@ -1045,13 +824,12 @@ FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_autofree gchar *tmp = NULL; - data->libsmbios_major = smbios_get_library_version_major(); - data->libsmbios_minor = smbios_get_library_version_minor(); - g_debug ("Using libsmbios %u.%u", data->libsmbios_major, - data->libsmbios_minor); - tmp = g_strdup_printf ("%u.%u", data->libsmbios_major, - data->libsmbios_minor); - fu_plugin_add_report_metadata (plugin, "LibsmbiosVersion", tmp); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + tmp = g_strdup_printf ("%d.%d", + smbios_get_library_version_major(), + smbios_get_library_version_minor()); + fu_plugin_add_runtime_version (plugin, "com.dell.libsmbios", tmp); + g_debug ("Using libsmbios %s", tmp); data->smi_obj = g_malloc0 (sizeof (FuDellSmiObj)); if (g_getenv ("FWUPD_DELL_VERBOSE") != NULL) @@ -1061,6 +839,10 @@ data->smi_obj->fake_smbios = FALSE; if (g_getenv ("FWUPD_DELL_FAKE_SMBIOS") != NULL) data->smi_obj->fake_smbios = TRUE; + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + + /* make sure that UEFI plugin is ready to receive devices */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "uefi"); } void @@ -1076,8 +858,8 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - GUsbContext *usb_ctx = fu_plugin_get_usb_context (plugin); - gint uefi_supported; + g_autofree gchar *sysfsfwdir = NULL; + g_autofree gchar *esrtdir = NULL; if (data->smi_obj->fake_smbios) { g_debug ("Called with fake SMBIOS implementation. " @@ -1103,26 +885,16 @@ } /* If ESRT is not turned on, fwupd will have already created an - * unlock device (if compiled with support). + * unlock device. * * Once unlocked, that will enable flashing capsules here too. - * - * that means we should only look for supported = 1 */ - uefi_supported = fwup_supported (); - data->capsule_supported = (uefi_supported == 1); - if (!data->capsule_supported) { - g_debug ("UEFI capsule firmware updating not supported (%x)", - (guint) uefi_supported); - } - - if (usb_ctx != NULL) { - g_signal_connect (usb_ctx, "device-added", - G_CALLBACK (fu_plugin_dell_device_added_cb), - plugin); - g_signal_connect (usb_ctx, "device-removed", - G_CALLBACK (fu_plugin_dell_device_removed_cb), - plugin); + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrtdir = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) { + data->capsule_supported = TRUE; + } else { + g_debug ("UEFI capsule firmware updating not supported"); } return TRUE; diff -Nru fwupd-1.0.6/plugins/dell/fu-plugin-dell.h fwupd-1.2.10/plugins/dell/fu-plugin-dell.h --- fwupd-1.0.6/plugins/dell/fu-plugin-dell.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/fu-plugin-dell.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,28 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2016 Mario Limonciello * - * Copyright (C) 2016 Mario Limonciello - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_DELL_H -#define __FU_PLUGIN_DELL_H +#pragma once -#include #include "fu-plugin.h" #include "fu-dell-smi.h" @@ -32,8 +15,6 @@ guint16 fake_pid; gboolean can_switch_modes; gboolean capsule_supported; - guint libsmbios_major; - guint libsmbios_minor; }; void @@ -44,16 +25,6 @@ gboolean fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error); -void -fu_plugin_dell_device_added_cb (GUsbContext *ctx, - GUsbDevice *device, - FuPlugin *plugin); - -void -fu_plugin_dell_device_removed_cb (GUsbContext *ctx, - GUsbDevice *device, - FuPlugin *plugin); - /* These are nodes that will indicate information about * the TPM status */ @@ -68,5 +39,3 @@ #define TPM_TYPE_MASK 0x0F00 #define TPM_1_2_MODE 0x0001 #define TPM_2_0_MODE 0x0002 - -#endif /* __FU_PLUGIN_DELL_H */ diff -Nru fwupd-1.0.6/plugins/dell/fu-self-test.c fwupd-1.2.10/plugins/dell/fu-self-test.c --- fwupd-1.0.6/plugins/dell/fu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,76 +1,116 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include #include #include +#include "fu-device-private.h" #include "fu-plugin-private.h" #include "fu-plugin-dell.h" +#include "fu-plugin-vfuncs.h" + +static FuDevice * +_find_device_by_id (GPtrArray *devices, const gchar *device_id) +{ + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + if (g_strcmp0 (fu_device_get_id (device), device_id) == 0) + return device; + } + return NULL; +} + +static FuDevice * +_find_device_by_name (GPtrArray *devices, const gchar *device_id) +{ + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + if (g_strcmp0 (fu_device_get_name (device), device_id) == 0) + return device; + } + return NULL; +} static void _plugin_device_added_cb (FuPlugin *plugin, FuDevice *device, gpointer user_data) { - FuDevice **dev = (FuDevice **) user_data; - g_set_object (dev, device); + GPtrArray *devices = (GPtrArray *) user_data; + if (fu_device_get_alternate_id (device) != NULL) { + FuDevice *device_alt = _find_device_by_id (devices, fu_device_get_alternate_id (device)); + if (device_alt != NULL) + fu_device_set_alternate (device, device_alt); + } + g_ptr_array_add (devices, g_object_ref (device)); +} + +static void +fu_engine_plugin_device_register_cb (FuPlugin *plugin_dell, + FuDevice *device, + gpointer user_data) +{ + FuPlugin *plugin_uefi = FU_PLUGIN (user_data); + g_autofree gchar *dbg = fu_device_to_string (device); + g_debug ("registering device: %s", dbg); + fu_plugin_runner_device_register (plugin_uefi, device); } static void fu_plugin_dell_tpm_func (void) { + FuDevice *device_v12; + FuDevice *device_v20; + const guint8 fw[30] = { 'F', 'W', 0x00 }; gboolean ret; struct tpm_status tpm_out; - FuDevice *device_alt = NULL; + g_autoptr(FuPlugin) plugin_dell = NULL; + g_autoptr(FuPlugin) plugin_uefi = NULL; + g_autoptr(GBytes) blob_fw = g_bytes_new_static (fw, sizeof(fw)); g_autoptr(GError) error = NULL; - g_autoptr(FuDevice) device = NULL; - g_autoptr(FuPlugin) plugin = NULL; + g_autoptr(GPtrArray) devices = NULL; memset (&tpm_out, 0x0, sizeof(tpm_out)); - g_setenv ("FWUPD_DELL_FAKE_SMBIOS", "1", FALSE); - plugin = fu_plugin_new (); - ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_dell.so", &error); + plugin_uefi = fu_plugin_new (); + ret = fu_plugin_open (plugin_uefi, PLUGINBUILDDIR "/../uefi/libfu_plugin_uefi.so", &error); g_assert_no_error (error); g_assert (ret); - ret = fu_plugin_runner_startup (plugin, &error); + ret = fu_plugin_runner_startup (plugin_uefi, &error); g_assert_no_error (error); g_assert (ret); - ret = fu_plugin_runner_coldplug(plugin, &error); - g_signal_connect (plugin, "device-added", + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_signal_connect (plugin_uefi, "device-added", G_CALLBACK (_plugin_device_added_cb), - &device); + devices); + + plugin_dell = fu_plugin_new (); + ret = fu_plugin_open (plugin_dell, PLUGINBUILDDIR "/libfu_plugin_dell.so", &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_plugin_runner_startup (plugin_dell, &error); + g_assert_no_error (error); + g_assert (ret); + g_signal_connect (plugin_dell, "device-register", + G_CALLBACK (fu_engine_plugin_device_register_cb), + plugin_uefi); + ret = fu_plugin_runner_coldplug (plugin_dell, &error); g_assert_no_error (error); g_assert (ret); /* inject fake data (no TPM) */ tpm_out.ret = -2; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, FALSE); - ret = fu_plugin_dell_detect_tpm (plugin, &error); + ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); g_assert_no_error (error); - g_assert (!ret); + g_assert_false (ret); + g_assert_cmpint (devices->len, ==, 0); /* inject fake data: * - that is out of flashes @@ -82,64 +122,62 @@ tpm_out.fw_version = 0; tpm_out.status = TPM_EN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 0; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin, &error); - device_alt = fu_device_get_alternate (device); - g_assert_no_error (error); - g_assert (ret); - g_assert (device != NULL); - g_assert (device_alt != NULL); + ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); + g_assert_true (ret); + g_assert_cmpint (devices->len, ==, 2); /* make sure 2.0 is locked */ - g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)); + device_v20 = _find_device_by_name (devices, "Unknown TPM 2.0"); + g_assert_nonnull (device_v20); + g_assert_true (fu_device_has_flag (device_v20, FWUPD_DEVICE_FLAG_LOCKED)); /* make sure not allowed to flash 1.2 */ - g_assert_false (fu_device_has_flag (device_alt, FWUPD_DEVICE_FLAG_UPDATABLE)); + device_v12 = _find_device_by_name (devices, "Unknown TPM 1.2"); + g_assert_nonnull (device_v12); + g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin, device, &error); + ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); - g_assert (!ret); + g_assert_false (ret); g_clear_error (&error); /* cleanup */ - fu_plugin_device_remove (plugin, device_alt); - fu_plugin_device_remove (plugin, device); - g_clear_object (&device); + g_ptr_array_set_size (devices, 0); /* inject fake data: - * - that hasflashes + * - that has flashes * - owned * - TPM 1.2 * dev will be the locked 2.0, alt will be the orig 1.2 */ tpm_out.status = TPM_EN_MASK | TPM_OWN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 125; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin, &error); - device_alt = fu_device_get_alternate (device); + ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); g_assert_no_error (error); g_assert (ret); - g_assert (device != NULL); - g_assert (device_alt != NULL); /* make sure not allowed to flash 1.2 */ - g_assert_false (fu_device_has_flag (device_alt, FWUPD_DEVICE_FLAG_UPDATABLE)); + device_v12 = _find_device_by_name (devices, "Unknown TPM 1.2"); + g_assert_nonnull (device_v12); + g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin, device, &error); + device_v20 = _find_device_by_name (devices, "Unknown TPM 2.0"); + g_assert_nonnull (device_v20); + ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); - g_assert (!ret); + g_assert_false (ret); g_clear_error (&error); /* cleanup */ - fu_plugin_device_remove (plugin, device_alt); - fu_plugin_device_remove (plugin, device); - g_clear_object (&device); + g_ptr_array_set_size (devices, 0); /* inject fake data: * - that has flashes @@ -149,33 +187,32 @@ */ tpm_out.status = TPM_EN_MASK | (TPM_1_2_MODE << 8); tpm_out.flashes_left = 125; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin, &error); - device_alt = fu_device_get_alternate (device); + ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); g_assert_no_error (error); g_assert (ret); - g_assert (device != NULL); - g_assert (device_alt != NULL); /* make sure allowed to flash 1.2 but not 2.0 */ - g_assert_true (fu_device_has_flag (device_alt, FWUPD_DEVICE_FLAG_UPDATABLE)); - g_assert_false (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE)); + device_v12 = _find_device_by_name (devices, "Unknown TPM 1.2"); + g_assert_nonnull (device_v12); + g_assert_true (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); + device_v20 = _find_device_by_name (devices, "Unknown TPM 2.0"); + g_assert_nonnull (device_v20); + g_assert_false (fu_device_has_flag (device_v20, FWUPD_DEVICE_FLAG_UPDATABLE)); /* try to unlock 2.0 */ - ret = fu_plugin_runner_unlock (plugin, device, &error); + ret = fu_plugin_runner_unlock (plugin_uefi, device_v20, &error); g_assert_no_error (error); g_assert (ret); /* make sure no longer allowed to flash 1.2 but can flash 2.0 */ - g_assert_false (fu_device_has_flag (device_alt, FWUPD_DEVICE_FLAG_UPDATABLE)); - g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE)); + g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); + g_assert_true (fu_device_has_flag (device_v20, FWUPD_DEVICE_FLAG_UPDATABLE)); /* cleanup */ - fu_plugin_device_remove (plugin, device_alt); - fu_plugin_device_remove (plugin, device); - g_clear_object (&device); + g_ptr_array_set_size (devices, 0); /* inject fake data: * - that has 1 flash left @@ -185,37 +222,36 @@ */ tpm_out.status = TPM_EN_MASK | (TPM_2_0_MODE << 8); tpm_out.flashes_left = 1; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &tpm_out, 0, 0, NULL, TRUE); - ret = fu_plugin_dell_detect_tpm (plugin, &error); - device_alt = fu_device_get_alternate (device); + ret = fu_plugin_dell_detect_tpm (plugin_dell, &error); g_assert_no_error (error); g_assert (ret); - g_assert (device != NULL); - g_assert (device_alt != NULL); /* make sure allowed to flash 2.0 but not 1.2 */ - g_assert_true (fu_device_has_flag (device_alt, FWUPD_DEVICE_FLAG_UPDATABLE)); - g_assert_false (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE)); + device_v20 = _find_device_by_name (devices, "Unknown TPM 2.0"); + g_assert_nonnull (device_v20); + g_assert_true (fu_device_has_flag (device_v20, FWUPD_DEVICE_FLAG_UPDATABLE)); + device_v12 = _find_device_by_name (devices, "Unknown TPM 1.2"); + g_assert_nonnull (device_v12); + g_assert_false (fu_device_has_flag (device_v12, FWUPD_DEVICE_FLAG_UPDATABLE)); /* With one flash left we need an override */ - ret = fu_plugin_runner_update (plugin, device_alt, NULL, NULL, - FWUPD_INSTALL_FLAG_NONE, &error); - g_assert (!ret); + ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, + FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert_false (ret); g_clear_error (&error); /* test override */ - ret = fu_plugin_runner_update (plugin, device_alt, NULL, NULL, - FWUPD_INSTALL_FLAG_FORCE, &error); - g_assert (ret); + g_test_expect_message ("FuPluginUefi", G_LOG_LEVEL_WARNING, + "missing or invalid embedded capsule header"); + ret = fu_plugin_runner_update (plugin_uefi, device_v20, blob_fw, + FWUPD_INSTALL_FLAG_FORCE, &error); + g_test_assert_expected_messages (); g_assert_no_error (error); - - /* cleanup */ - fu_plugin_device_remove (plugin, device_alt); - fu_plugin_device_remove (plugin, device); - g_clear_object (&device); + g_assert (ret); } static void @@ -226,40 +262,53 @@ DOCK_UNION buf; DOCK_INFO *dock_info; g_autoptr(GError) error = NULL; - g_autoptr(FuDevice) device = NULL; - g_autoptr(FuPlugin) plugin = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(FuPlugin) plugin_uefi = fu_plugin_new (); + g_autoptr(FuPlugin) plugin_dell = fu_plugin_new (); - g_setenv ("FWUPD_DELL_FAKE_SMBIOS", "1", FALSE); - plugin = fu_plugin_new (); - ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_dell.so", &error); + ret = fu_plugin_open (plugin_uefi, PLUGINBUILDDIR "/../uefi/libfu_plugin_uefi.so", &error); g_assert_no_error (error); g_assert (ret); - ret = fu_plugin_runner_startup (plugin, &error); + ret = fu_plugin_runner_startup (plugin_uefi, &error); g_assert_no_error (error); g_assert (ret); - g_signal_connect (plugin, "device-added", + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_signal_connect (plugin_uefi, "device-added", G_CALLBACK (_plugin_device_added_cb), - &device); - ret = fu_plugin_runner_coldplug (plugin, &error); + devices); + ret = fu_plugin_open (plugin_dell, PLUGINBUILDDIR "/libfu_plugin_dell.so", &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_plugin_runner_startup (plugin_dell, &error); + g_assert_no_error (error); + g_assert (ret); + g_signal_connect (plugin_dell, "device-register", + G_CALLBACK (fu_engine_plugin_device_register_cb), + plugin_uefi); + ret = fu_plugin_runner_coldplug (plugin_dell, &error); g_assert_no_error (error); g_assert (ret); /* make sure bad device doesn't trigger this */ - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, 0x1234, 0x4321, NULL, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, plugin); - g_assert (device == NULL); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + g_assert_false (ret); + g_clear_error (&error); + g_assert_cmpint (devices->len, ==, 0); /* inject a USB dongle matching correct VID/PID */ out[0] = 0; out[1] = 0; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, NULL, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, plugin); - g_assert (device == NULL); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + g_assert_true (ret); + g_clear_error (&error); + g_assert_cmpint (devices->len, ==, 0); /* inject valid TB16 dock w/ invalid flash pkg version */ buf.record = g_malloc0 (sizeof(DOCK_INFO_RECORD)); @@ -286,17 +335,15 @@ "Dock1,Cable,Cyp,TBT_Cable,0 :Query 2 2 2 3 0", 44); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, - plugin); - g_assert (device != NULL); - g_clear_object (&device); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, NULL); + g_assert (ret); + g_assert_cmpint (devices->len, ==, 4); + g_ptr_array_set_size (devices, 0); g_free (buf.record); - fu_plugin_dell_device_removed_cb (NULL, NULL, - plugin); /* inject valid TB16 dock w/ older system EC */ buf.record = g_malloc0 (sizeof(DOCK_INFO_RECORD)); @@ -323,18 +370,15 @@ "Dock1,Cable,Cyp,TBT_Cable,0 :Query 2 2 2 3 0", 44); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, - plugin); - g_assert (device != NULL); - g_clear_object (&device); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, NULL); + g_assert (ret); + g_assert_cmpint (devices->len, ==, 3); + g_ptr_array_set_size (devices, 0); g_free (buf.record); - fu_plugin_dell_device_removed_cb (NULL, NULL, - plugin); - /* inject valid WD15 dock w/ invalid flash pkg version */ buf.record = g_malloc0 (sizeof(DOCK_INFO_RECORD)); @@ -358,18 +402,16 @@ "Dock1,Cable,Cyp,IE_Cable,0 :Query 2 2 2 1 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, - plugin); - g_assert (device != NULL); - g_clear_object (&device); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + g_assert (ret); + g_assert_no_error (error); + g_assert_cmpint (devices->len, ==, 3); + g_ptr_array_set_size (devices, 0); g_free (buf.record); - fu_plugin_dell_device_removed_cb (NULL, NULL, - plugin); - /* inject valid WD15 dock w/ older system EC */ buf.record = g_malloc0 (sizeof(DOCK_INFO_RECORD)); @@ -393,17 +435,16 @@ "Dock1,Cable,Cyp,IE_Cable,0 :Query 2 2 2 1 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, - plugin); - g_assert (device != NULL); - g_clear_object (&device); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + g_assert (ret); + g_assert_no_error (error); + g_assert_cmpint (devices->len, ==, 2); + g_ptr_array_set_size (devices, 0); g_free (buf.record); - fu_plugin_dell_device_removed_cb (NULL, NULL, - plugin); /* inject an invalid future dock */ buf.record = g_malloc0 (sizeof(DOCK_INFO_RECORD)); @@ -421,21 +462,30 @@ "Dock1,EC,MIPS32,FUT_Dock,0 :Query 2 0 2 2 0", 43); out[0] = 0; out[1] = 1; - fu_plugin_dell_inject_fake_data (plugin, + fu_plugin_dell_inject_fake_data (plugin_dell, (guint32 *) &out, DOCK_NIC_VID, DOCK_NIC_PID, buf.buf, FALSE); - fu_plugin_dell_device_added_cb (NULL, NULL, - plugin); - g_assert (device == NULL); + ret = fu_plugin_usb_device_added (plugin_dell, NULL, &error); + g_assert_false (ret); + g_assert_cmpint (devices->len, ==, 0); g_free (buf.record); } int main (int argc, char **argv) { + g_autofree gchar *sysfsdir = NULL; g_test_init (&argc, &argv, NULL); + /* change path */ + g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); + + /* change behaviour */ + sysfsdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + g_setenv ("FWUPD_UEFI_ESP_PATH", sysfsdir, TRUE); + g_setenv ("FWUPD_DELL_FAKE_SMBIOS", "1", FALSE); + /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); diff -Nru fwupd-1.0.6/plugins/dell/meson.build fwupd-1.2.10/plugins/dell/meson.build --- fwupd-1.0.6/plugins/dell/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_dell', + fu_hash, sources : [ 'fu-plugin-dell.c', 'fu-dell-smi.c', @@ -16,23 +17,27 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : [ - cargs, - '-DLOCALSTATEDIR="' + localstatedir + '"', - ], + cargs, + ], dependencies : [ plugin_deps, efivar, libsmbios_c, - fwup, ], ) if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' cargs += '-DFU_OFFLINE_DESTDIR="/tmp/fwupd-self-test"' cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' e = executable( 'dell-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-dell-smi.c', @@ -46,19 +51,15 @@ dependencies : [ plugin_deps, efivar, - fwup, sqlite, - gudev, libsmbios_c, valgrind, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : [ cargs, - '-DLOCALSTATEDIR="/tmp/fwupd-self-test/var"', ], ) test('dell-self-test', e) diff -Nru fwupd-1.0.6/plugins/dell/README.md fwupd-1.2.10/plugins/dell/README.md --- fwupd-1.0.6/plugins/dell/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -6,24 +6,32 @@ This allows installing Dell capsules that are not part of the ESRT table. +GUID Generation +--------------- + +These devices uses custom GUIDs for Dell-specific hardware. + + * Thunderbolt devices: `TBT-0x00d4u$(system-id)` + * TPM devices `$(system-id)-$(mode)`, where `mode` is either `2.0` or `1.2` + +In both cases the `system-id` is derived from the SMBIOS Product SKU property. + Build Requirements ------------------ -For Dell support you will need libsmbios_c version 2.3.0 or later and -efivar. -* source: http://linux.dell.com/cgi-bin/cgit.cgi/libsmbios.git/ -* rpms: https://apps.fedoraproject.org/packages/libsmbios -* debs (Debian): http://tracker.debian.org/pkg/libsmbios -* debs (Ubuntu): http://launchpad.net/ubuntu/+source/libsmbios +For Dell support you will need libsmbios_c version 2.4.0 or later. + +* source: https://github.com/dell/libsmbios +* binaries: https://github.com/dell/libsmbios/releases If you don't want or need this functionality you can use the -`--disable-dell` option. +`-Dplugin_dell=false` option. # Devices powered by the Dell Plugin The Dell plugin creates device nodes for PC's that have switchable TPMs as well as the Type-C docks (WD15/TB16). -These device nodes can be flashed using UEFI capsule (and fwupdate) but don't +These device nodes can be flashed using UEFI capsule but don't use the ESRT table to communicate device status or version information. This is intentional behavior because more complicated decisions need to be made Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/image and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/image differ diff -Nru fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/status fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/status --- fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/type fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/type --- fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/version fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/version --- fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/xoffset fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/xoffset --- fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/xoffset 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/xoffset 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +123 diff -Nru fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/yoffset fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/yoffset --- fwupd-1.0.6/plugins/dell/tests/acpi/bgrt/yoffset 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/acpi/bgrt/yoffset 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +456 Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/dell/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/dell/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 differ diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c fwupd-1.2.10/plugins/dell/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c --- fwupd-1.0.6/plugins/dell/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 \ No newline at end of file diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/capsule_flags fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/capsule_flags --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/capsule_flags 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0xfe diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/fw_class fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/fw_class --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/fw_class 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +ddc0ee61-e7f0-4e7d-acc5-c070a398838e diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/fw_type fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/fw_type --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/fw_type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/fw_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/fw_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +65586 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_status fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_status --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/last_attempt_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +18472960 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/lowest_supported_fw_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/lowest_supported_fw_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +65582 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/capsule_flags fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/capsule_flags --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/capsule_flags 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/fw_class fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/fw_class --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/fw_class 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +671d19d0-d43c-4852-98d9-1ce16f9967e4 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/fw_type fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/fw_type --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/fw_type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/fw_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/fw_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_status fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_status --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/last_attempt_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/lowest_supported_fw_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/lowest_supported_fw_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/capsule_flags 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/fw_class fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/fw_class --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/fw_class 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +00000000-0000-0000-0000-000000000000 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/fw_type fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/fw_type --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/fw_type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/fw_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/fw_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/last_attempt_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version --- fwupd-1.0.6/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi/fw_platform_size fwupd-1.2.10/plugins/dell/tests/efi/fw_platform_size --- fwupd-1.0.6/plugins/dell/tests/efi/fw_platform_size 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi/fw_platform_size 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +64 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/height fwupd-1.2.10/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/height --- fwupd-1.0.6/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/height 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/height 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +789 diff -Nru fwupd-1.0.6/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/width fwupd-1.2.10/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/width --- fwupd-1.0.6/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/width 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/efi-framebuffer/efi-framebuffer.0/width 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +456 diff -Nru fwupd-1.0.6/plugins/dell/tests/.gitignore fwupd-1.2.10/plugins/dell/tests/.gitignore --- fwupd-1.0.6/plugins/dell/tests/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/.gitignore 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +EFI +efi/efivars/fwupd-c34cb672-a81e-5d32-9d89-cbcabe8ec37b-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/dell/tests/test.bmp and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/dell/tests/test.bmp differ diff -Nru fwupd-1.0.6/plugins/dell/tests/tpm0/active fwupd-1.2.10/plugins/dell/tests/tpm0/active --- fwupd-1.0.6/plugins/dell/tests/tpm0/active 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/tpm0/active 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/tpm0/caps fwupd-1.2.10/plugins/dell/tests/tpm0/caps --- fwupd-1.0.6/plugins/dell/tests/tpm0/caps 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/tpm0/caps 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +Manufacturer: 0x49465800 +TCG version: 1.2 +Firmware version: 6.40 diff -Nru fwupd-1.0.6/plugins/dell/tests/tpm0/enabled fwupd-1.2.10/plugins/dell/tests/tpm0/enabled --- fwupd-1.0.6/plugins/dell/tests/tpm0/enabled 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/tpm0/enabled 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/tpm0/owned fwupd-1.2.10/plugins/dell/tests/tpm0/owned --- fwupd-1.0.6/plugins/dell/tests/tpm0/owned 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/tpm0/owned 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/dell/tests/tpm0/pcrs fwupd-1.2.10/plugins/dell/tests/tpm0/pcrs --- fwupd-1.0.6/plugins/dell/tests/tpm0/pcrs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell/tests/tpm0/pcrs 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,24 @@ +PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 +PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 +PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E +PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC +PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A +PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA +PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 +PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 +PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD +PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff -Nru fwupd-1.0.6/plugins/dell-dock/dell-dock.quirk fwupd-1.2.10/plugins/dell-dock/dell-dock.quirk --- fwupd-1.0.6/plugins/dell-dock/dell-dock.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/dell-dock.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,115 @@ +# +# Copyright (C) 2018 Dell Inc. +# All rights reserved. +# +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. +# +# This file is provided under a dual MIT/LGPLv2 license. When using or +# redistributing this file, you may do so under either license. +# Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. +# +# SPDX-License-Identifier: LGPL-2.1+ OR MIT +# + +[DellDockUnlockTargets] +synapticsmst = 9 + +# Used to make plugin probe the devices +[DeviceInstanceId=USB\VID_413C&PID_B06F] +Name = Unprobed Dell accessory endpoint +Plugin = dell_dock +[DeviceInstanceId=USB\VID_413C&PID_B06E] +Name = Unprobed Dell accessory endpoint +Plugin = dell_dock + +# USB hub1 +[DeviceInstanceId=USB\VID_413C&PID_B06F&hub] +Name = RTS5413 in Dell dock +Summary = USB 3.1 Generation 1 Hub +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +Plugin = dell_dock +Vendor = Dell Inc +Icon = dock-usb +FirmwareSize = 0x10000 +Flags = require-ac,updatable +DellDockUnlockTarget = 8 +DellDockBlobMajorOffset = 0x7F6E +DellDockBlobMinorOffset = 0x7F6F +InstallDuration = 14 + +# USB hub2 +[DeviceInstanceId=USB\VID_413C&PID_B06E&hub] +Name = RTS5487 in Dell dock +Summary = USB 3.1 Generation 2 Hub +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +Vendor = Dell Inc +Plugin = dell_dock +Icon = dock-usb +FirmwareSize = 0x10000 +Flags = require-ac,updatable,has-bridge +DellDockUnlockTarget = 7 +DellDockBlobMajorOffset = 0x7F52 +DellDockBlobMinorOffset = 0x7F53 +InstallDuration = 3 + +# Embedded Controller +# Name is intentionally not set (it's queried by dock) +[Guid=USB\VID_413C&PID_B06E&hub&embedded] +Name = Dell dock +Summary = High performance dock +Plugin = dell_dock +Vendor = Dell Inc +Icon = dock-usb +FirmwareSizeMin = 0x1FFC0 +FirmwareSizeMax = 0x20000 +Flags = require-ac +Children = FuDellDockStatus|USB\VID_413C&PID_B06E&hub&status,FuDellDockMst|MST-panamera-vmm5331-259 +DellDockUnlockTarget = 1 +DellDockBoardMin = 6 +DellDockVersionLowest = 01.00.00.00 +DellDockBlobVersionOffset = 0x1AFC0 +InstallDuration = 60 + +# Representation of overall dock update +[DeviceInstanceId=USB\VID_413C&PID_B06E&hub&status] +Name = Package level of Dell dock +Summary = A representation of dock update status +Plugin = dell_dock +Vendor = Dell Inc +FirmwareSize = 24 +InstallDuration = 5 +DellDockBlobVersionOffset = 0x14 + +# MST Hub +[Guid=MST-panamera-vmm5331-259] +Name = VMM5331 in Dell dock +Summary = Multi Stream Transport controller +Vendor = Dell Inc +Plugin = synapticsmst +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +Flags = skip-restart,require-ac +FirmwareSize=524288 +DellDockUnlockTarget = 9 +InstallDuration = 95 +DellDockInstallDurationI2C=360 +DellDockBlobMajorOffset = 0x18400 +DellDockBlobMinorOffset = 0x18401 +DellDockBlobBuildOffset = 0x18402 + +# Thunderbolt controller +[Guid=TBT-00d4b070] +Name = Thunderbolt controller in Dell dock +Summary = Thunderbolt controller +Vendor = Dell Inc +ParentGuid = USB\VID_413C&PID_B06E&hub&embedded +FirmwareSizeMin=0x40000 +FirmwareSizeMax=0x80000 +Flags = require-ac +InstallDuration = 22 +DellDockInstallDurationI2C = 181 +DellDockUnlockTarget = 10 +DellDockHubVersionLowest = 1.31 +DellDockBlobMajorOffset = 0x400a +DellDockBlobMinorOffset = 0x4009 diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-common.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-common.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include "fu-dell-dock-common.h" +#include "fu-device-locker.h" +#include "fu-dell-dock-i2c-ec.h" + +gboolean +fu_dell_dock_set_power (FuDevice *device, guint8 target, + gboolean enabled, GError **error) +{ + FuDevice *parent; + g_autoptr(FuDeviceLocker) locker = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + parent = FU_IS_DELL_DOCK_EC (device) ? device : fu_device_get_parent (device); + + if (parent == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Couldn't find parent for %s", + fu_device_get_name (device)); + return FALSE; + } + + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + + return fu_dell_dock_ec_modify_lock (parent, target, enabled, error); +} + +void +fu_dell_dock_will_replug (FuDevice *device) +{ + guint64 timeout = fu_device_get_install_duration (device); + + g_return_if_fail (FU_IS_DEVICE (device)); + + g_debug ("Activated %" G_GUINT64_FORMAT "s replug delay for %s", + timeout, fu_device_get_name (device)); + fu_device_set_remove_delay (device, timeout * 1000); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); +} + +void +fu_dell_dock_clone_updatable (FuDevice *device) +{ + FuDevice *parent; + parent = fu_device_get_parent (device); + if (parent == NULL) + return; + if (fu_device_has_flag (parent, FWUPD_DEVICE_FLAG_UPDATABLE)) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + const gchar *message = fu_device_get_update_error (parent); + if (message != NULL) + fu_device_set_update_error (device, message); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-common.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-common.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include "fu-device.h" +#include "fu-dell-dock-i2c-ec.h" +#include "fu-dell-dock-i2c-mst.h" +#include "fu-dell-dock-i2c-tbt.h" +#include "fu-dell-dock-hub.h" +#include "fu-dell-dock-hid.h" +#include "fu-dell-dock-status.h" + +#define DELL_DOCK_EC_INSTANCE_ID "USB\\VID_413C&PID_B06E&hub&embedded" +#define DELL_DOCK_TBT_INSTANCE_ID "TBT-00d4b070" + +gboolean fu_dell_dock_set_power (FuDevice *device, + guint8 target, + gboolean enabled, + GError **error); +void fu_dell_dock_will_replug (FuDevice *device); + +void fu_dell_dock_clone_updatable (FuDevice *device); diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hid.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hid.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hid.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hid.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include +#include + +#include "fu-usb-device.h" +#include "fwupd-error.h" + +#include "fu-dell-dock-hid.h" + +#define HIDI2C_MAX_REGISTER 4 +#define HID_MAX_RETRIES 5 +#define TBT_MAX_RETRIES 2 +#define HIDI2C_TRANSACTION_TIMEOUT 2000 + +#define HUB_CMD_READ_DATA 0xC0 +#define HUB_CMD_WRITE_DATA 0x40 +#define HUB_EXT_READ_STATUS 0x09 +#define HUB_EXT_MCUMODIFYCLOCK 0x06 +#define HUB_EXT_I2C_WRITE 0xC6 +#define HUB_EXT_WRITEFLASH 0xC8 +#define HUB_EXT_I2C_READ 0xD6 +#define HUB_EXT_VERIFYUPDATE 0xD9 +#define HUB_EXT_ERASEBANK 0xE8 +#define HUB_EXT_WRITE_TBT_FLASH 0xFF + +#define TBT_COMMAND_WAKEUP 0x00000000 +#define TBT_COMMAND_AUTHENTICATE 0xFFFFFFFF +#define TBT_COMMAND_AUTHENTICATE_STATUS 0xFFFFFFFE + +typedef struct __attribute__ ((packed)) { + guint8 cmd; + guint8 ext; + union { + guint32 dwregaddr; + struct { + guint8 cmd_data0; + guint8 cmd_data1; + guint8 cmd_data2; + guint8 cmd_data3; + }; + }; + guint16 bufferlen; + FuHIDI2CParameters parameters; + guint8 extended_cmdarea[53]; + guint8 data[192]; +} FuHIDCmdBuffer; + +typedef struct __attribute__ ((packed)) { + guint8 cmd; + guint8 ext; + guint8 i2cslaveaddr; + guint8 i2cspeed; + union { + guint32 startaddress; + guint32 tbt_command; + }; + guint8 bufferlen; + guint8 extended_cmdarea[55]; + guint8 data[192]; +} FuTbtCmdBuffer; + +static gboolean +fu_dell_dock_hid_set_report (FuDevice *self, + guint8 *outbuffer, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gboolean ret; + gsize actual_len = 0; + for (gint i = 1; i <= HID_MAX_RETRIES; i++) { + g_autoptr(GError) error_local = NULL; + ret = g_usb_device_control_transfer ( + usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, HID_REPORT_SET, 0x0200, + 0x0000, outbuffer, 192, &actual_len, + HIDI2C_TRANSACTION_TIMEOUT, NULL, &error_local); + if (ret) + break; + if (i == HID_MAX_RETRIES || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } else { + g_debug ("attempt %d/%d: set control transfer failed: %s", + i, HID_MAX_RETRIES, + error_local->message); + sleep (1); + } + } + if (actual_len != 192) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_hid_get_report (FuDevice *self, + guint8 *inbuffer, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gboolean ret; + gsize actual_len = 0; + for (gint i = 1; i <= HID_MAX_RETRIES; i++) { + g_autoptr(GError) error_local = NULL; + ret = g_usb_device_control_transfer ( + usb_device, G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, HID_REPORT_GET, 0x0100, + 0x0000, inbuffer, 192, &actual_len, + HIDI2C_TRANSACTION_TIMEOUT, NULL, &error_local); + if (ret) + break; + if (i == HID_MAX_RETRIES || + g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } else { + g_debug ("attempt %d/%d: get control transfer failed: %s", + i, HID_MAX_RETRIES, + error_local->message); + } + } + if (actual_len != 192) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_get_hub_version (FuDevice *self, + GError **error) +{ + g_autofree gchar *version = NULL; + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, + .ext = HUB_EXT_READ_STATUS, + .cmd_data0 = 0, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (12), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to query hub version: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to query hub version: "); + return FALSE; + } + + version = g_strdup_printf ("%02x.%02x", + cmd_buffer.data[10], + cmd_buffer.data[11]); + fu_device_set_version (self, version, FWUPD_VERSION_FORMAT_PAIR); + return TRUE; +} + +gboolean +fu_dell_dock_hid_raise_mcu_clock (FuDevice *self, + gboolean enable, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_MCUMODIFYCLOCK, + .cmd_data0 = (guint8) enable, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = 0, + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, + "failed to set mcu clock to %d: ", + enable); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_get_ec_status (FuDevice *self, + guint8 *status1, + guint8 *status2, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_READ_STATUS, + .cmd_data0 = 0, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (27), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to get EC status: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get EC status: "); + return FALSE; + } + + *status1 = cmd_buffer.data[25]; + *status2 = cmd_buffer.data[26]; + + return TRUE; +} + +gboolean +fu_dell_dock_hid_erase_bank (FuDevice *self, guint8 idx, GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_ERASEBANK, + .cmd_data0 = 0, + .cmd_data1 = idx, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = 0, + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to erase bank: "); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_write_flash (FuDevice *self, + guint32 dwAddr, + const guint8 *input, + gsize write_size, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_WRITEFLASH, + .dwregaddr = GUINT32_TO_LE (dwAddr), + .bufferlen = GUINT16_TO_LE (write_size), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error ( + error, "failed to write %" G_GSIZE_FORMAT " flash to %x: ", + write_size, dwAddr); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_verify_update (FuDevice *self, + gboolean *result, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_VERIFYUPDATE, + .cmd_data0 = 1, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (1), + .parameters = {.i2cslaveaddr = 0, .regaddrlen = 0, .i2cspeed = 0}, + .extended_cmdarea[0 ... 52] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, + error)) { + g_prefix_error (error, "failed to verify update: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to verify update: "); + return FALSE; + } + *result = cmd_buffer.data[0]; + + return TRUE; +} + +gboolean +fu_dell_dock_hid_i2c_write (FuDevice *self, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_I2C_WRITE, + .dwregaddr = 0, + .bufferlen = GUINT16_TO_LE (write_size), + .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .regaddrlen = 0, + .i2cspeed = parameters->i2cspeed | 0x80}, + .extended_cmdarea[0 ... 52] = 0, + }; + + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + + return fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error); +} + +gboolean +fu_dell_dock_hid_i2c_read (FuDevice *self, + guint32 cmd, + gsize read_size, + GBytes **bytes, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuHIDCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_WRITE_DATA, + .ext = HUB_EXT_I2C_READ, + .dwregaddr = GUINT32_TO_LE (cmd), + .bufferlen = GUINT16_TO_LE (read_size), + .parameters = {.i2cslaveaddr = parameters->i2cslaveaddr, + .regaddrlen = parameters->regaddrlen, + .i2cspeed = parameters->i2cspeed | 0x80}, + .extended_cmdarea[0 ... 52] = 0, + .data[0 ... 191] = 0, + }; + + g_return_val_if_fail (read_size <= HIDI2C_MAX_READ, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (parameters->regaddrlen < HIDI2C_MAX_REGISTER, FALSE); + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) + return FALSE; + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) + return FALSE; + + *bytes = g_bytes_new (cmd_buffer.data, read_size); + + return TRUE; +} + +gboolean +fu_dell_dock_hid_tbt_wake (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .tbt_command = TBT_COMMAND_WAKEUP, + .bufferlen = 0, + .extended_cmdarea[0 ... 53] = 0, + .data[0 ... 191] = 0, + }; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to set wake thunderbolt: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get wake thunderbolt status: "); + return FALSE; + } + g_debug ("thunderbolt wake result: 0x%x", cmd_buffer.data[1]); + + return TRUE; +} + +static const gchar * +fu_dell_dock_hid_tbt_map_error (guint32 code) +{ + if (code == 1) + return g_strerror (EINVAL); + else if (code == 2) + return g_strerror (EPERM); + + return g_strerror (EIO); +} + +gboolean +fu_dell_dock_hid_tbt_write (FuDevice *self, + guint32 start_addr, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .startaddress = GUINT32_TO_LE (start_addr), + .bufferlen = write_size, + .extended_cmdarea[0 ... 53] = 0, + }; + guint8 result; + + g_return_val_if_fail (input != NULL, FALSE); + g_return_val_if_fail (write_size <= HIDI2C_MAX_WRITE, FALSE); + + memcpy (cmd_buffer.data, input, write_size); + + for (gint i = 1; i <= TBT_MAX_RETRIES; i++) { + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to run TBT update: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get TBT flash status: "); + return FALSE; + } + result = cmd_buffer.data[1] & 0xf; + if (result == 0) + break; + g_debug ("attempt %d/%d: Thunderbolt write failed: %x", + i, TBT_MAX_RETRIES, result); + } + if (result != 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Writing address 0x%04x failed: %s", + start_addr, fu_dell_dock_hid_tbt_map_error (result)); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_dell_dock_hid_tbt_authenticate (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error) +{ + FuTbtCmdBuffer cmd_buffer = { + .cmd = HUB_CMD_READ_DATA, /* It's a special write command that reads status result */ + .ext = HUB_EXT_WRITE_TBT_FLASH, + .i2cslaveaddr = parameters->i2cslaveaddr, + .i2cspeed = parameters->i2cspeed, /* unlike other commands doesn't need | 0x80 */ + .tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE), + .bufferlen = 0, + .extended_cmdarea[0 ... 53] = 0, + }; + guint8 result; + + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to send authentication: "); + return FALSE; + } + + cmd_buffer.tbt_command = GUINT32_TO_LE (TBT_COMMAND_AUTHENTICATE_STATUS); + /* needs at least 2 seconds */ + g_usleep (2000000); + for (gint i = 1; i <= TBT_MAX_RETRIES; i++) { + if (!fu_dell_dock_hid_set_report (self, (guint8 *) &cmd_buffer, error)) { + g_prefix_error (error, "failed to set check authentication: "); + return FALSE; + } + if (!fu_dell_dock_hid_get_report (self, cmd_buffer.data, error)) { + g_prefix_error (error, "failed to get check authentication: "); + return FALSE; + } + result = cmd_buffer.data[1] & 0xf; + if (result == 0) + break; + g_debug ("attempt %d/%d: Thunderbolt authenticate failed: %x", + i, TBT_MAX_RETRIES, result); + g_usleep (500000); + } + if (result != 0) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Thunderbolt authentication failed: %s", + fu_dell_dock_hid_tbt_map_error (result)); + return FALSE; + } + + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hid.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hid.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hid.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hid.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include + +#include "fu-device.h" + +typedef struct __attribute__ ((packed)) { + guint8 i2cslaveaddr; + guint8 regaddrlen; + guint8 i2cspeed; +} FuHIDI2CParameters; + +typedef enum { + I2C_SPEED_250K, + I2C_SPEED_400K, + I2C_SPEED_800K, + /* */ + I2C_SPEED_LAST, +} BridgedI2CSpeed; + +#define HIDI2C_MAX_READ 192 +#define HIDI2C_MAX_WRITE 128 + +gboolean fu_dell_dock_hid_i2c_write (FuDevice *self, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error); +gboolean fu_dell_dock_hid_i2c_read (FuDevice *self, + guint32 cmd, + gsize read_size, + GBytes **bytes, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_get_hub_version (FuDevice *self, + GError **error); + +gboolean fu_dell_dock_hid_raise_mcu_clock (FuDevice *self, + gboolean enable, + GError **error); + +gboolean fu_dell_dock_hid_get_ec_status (FuDevice *self, + guint8 *status1, + guint8 *status2, + GError **error); + +gboolean fu_dell_dock_hid_erase_bank (FuDevice *self, + guint8 idx, + GError **error); + +gboolean fu_dell_dock_hid_write_flash (FuDevice *self, + guint32 addr, + const guint8 *input, + gsize write_size, + GError **error); + +gboolean fu_dell_dock_hid_verify_update (FuDevice *self, + gboolean *result, + GError **error); + +gboolean fu_dell_dock_hid_tbt_wake (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_tbt_write (FuDevice *self, + guint32 start_addr, + const guint8 *input, + gsize write_size, + const FuHIDI2CParameters *parameters, + GError **error); + +gboolean fu_dell_dock_hid_tbt_authenticate (FuDevice *self, + const FuHIDI2CParameters *parameters, + GError **error); diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hub.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hub.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hub.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hub.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include "fu-usb-device.h" +#include "fwupd-error.h" + +#include "fu-dell-dock-common.h" + +struct _FuDellDockHub { + FuUsbDevice parent_instance; + guint8 unlock_target; + guint64 blob_major_offset; + guint64 blob_minor_offset; +}; + +G_DEFINE_TYPE (FuDellDockHub, fu_dell_dock_hub, FU_TYPE_USB_DEVICE) + +static gboolean +fu_dell_dock_hub_probe (FuDevice *device, GError **error) +{ + g_autofree gchar *devid = NULL; + + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X&hub", + (guint) fu_usb_device_get_vid (FU_USB_DEVICE (device)), + (guint) fu_usb_device_get_pid (FU_USB_DEVICE (device))); + + fu_device_set_logical_id (device, "hub"); + fu_device_add_instance_id (device, devid); + + return TRUE; +} + +static gboolean +fu_dell_dock_hub_write_fw (FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDellDockHub *self = FU_DELL_DOCK_HUB (device); + gsize fw_size = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &fw_size); + gsize write_size = + (fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size; + gsize nwritten = 0; + guint32 address = 0; + gboolean result = FALSE; + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strdup_printf ("%02x.%02x", + data[self->blob_major_offset], + data[self->blob_minor_offset]); + g_debug ("writing hub firmware version %s", dynamic_version); + + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + + if (!fu_dell_dock_hid_raise_mcu_clock (device, TRUE, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dell_dock_hid_erase_bank (device, 1, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + do { + /* last packet */ + if (fw_size - nwritten < write_size) + write_size = fw_size - nwritten; + + if (!fu_dell_dock_hid_write_flash (device, address, data, + write_size, error)) + return FALSE; + nwritten += write_size; + data += write_size; + address += write_size; + fu_device_set_progress_full (device, nwritten, fw_size); + } while (nwritten < fw_size); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!fu_dell_dock_hid_verify_update (device, &result, error)) + return FALSE; + if (!result) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to verify the update"); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version, FWUPD_VERSION_FORMAT_PAIR); + return TRUE; +} + +static gboolean +fu_dell_dock_hub_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockHub *self = FU_DELL_DOCK_HUB (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_dell_dock_hub_open (FuUsbDevice *fu_usb_device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (fu_usb_device); + + /* open device and clear status */ + if (!g_usb_device_claim_interface ( + usb_device, 0, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) { + g_prefix_error (error, "failed to claim HID interface: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_hub_close (FuUsbDevice *fu_usb_device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (fu_usb_device); + + if (!g_usb_device_release_interface ( + usb_device, 0, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + return TRUE; +} + +static void +fu_dell_dock_hub_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_dell_dock_hub_parent_class)->finalize (object); +} + +static void +fu_dell_dock_hub_init (FuDellDockHub *self) +{ +} + +static void +fu_dell_dock_hub_class_init (FuDellDockHubClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_hub_finalize; + klass_usb_device->open = fu_dell_dock_hub_open; + klass_usb_device->close = fu_dell_dock_hub_close; + klass_device->setup = fu_dell_dock_hid_get_hub_version; + klass_device->probe = fu_dell_dock_hub_probe; + klass_device->write_firmware = fu_dell_dock_hub_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_hub_set_quirk_kv; +} + +FuDellDockHub * +fu_dell_dock_hub_new (FuUsbDevice *device) +{ + FuDellDockHub *self = g_object_new (FU_TYPE_DELL_DOCK_HUB, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hub.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hub.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-hub.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-hub.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include "fu-usb-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_HUB (fu_dell_dock_hub_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockHub, fu_dell_dock_hub, FU, DELL_DOCK_HUB, FuUsbDevice) + +FuDellDockHub *fu_dell_dock_hub_new (FuUsbDevice *device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-ec.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-ec.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-ec.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-ec.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,1027 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fu-common-version.h" +#include "fu-usb-device.h" +#include "fwupd-error.h" + +#include "fu-dell-dock-common.h" + +#define I2C_EC_ADDRESS 0xec + +#define EC_CMD_SET_DOCK_PKG 0x01 +#define EC_CMD_GET_DOCK_INFO 0x02 +#define EC_CMD_GET_DOCK_DATA 0x03 +#define EC_CMD_GET_DOCK_TYPE 0x05 +#define EC_CMD_MODIFY_LOCK 0x0a +#define EC_CMD_RESET 0x0b +#define EC_CMD_REBOOT 0x0c +#define EC_CMD_PASSIVE 0x0d +#define EC_GET_FW_UPDATE_STATUS 0x0f + +#define EXPECTED_DOCK_INFO_SIZE 0xb7 +#define EXPECTED_DOCK_TYPE 0x04 + +#define TBT_MODE_MASK 0x01 + +#define BIT_SET(x,y) (x |= (1<data->board_id); + summary = fu_device_get_metadata (device, board_type_str); + if (summary != NULL) + fu_device_set_summary (device, summary); +} + +FuDevice * +fu_dell_dock_ec_get_symbiote (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + return self->symbiote; +} + +gboolean +fu_dell_dock_ec_needs_tbt (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + gboolean port0_tbt_mode = self->data->port0_dock_status & TBT_MODE_MASK; + + /* check for TBT module type */ + if (self->data->module_type != MODULE_TYPE_TBT) + return FALSE; + g_debug ("found thunderbolt dock, port mode: %d", port0_tbt_mode); + + return !port0_tbt_mode; +} + +gboolean +fu_dell_dock_ec_tbt_passive (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + if (self->passive_flow > 0) { + self->passive_flow |= PASSIVE_TBT_MASK; + return TRUE; + } + return FALSE; +} + +static const gchar* +fu_dell_dock_devicetype_to_str (guint device_type, guint sub_type) +{ + switch (device_type) { + case FU_DELL_DOCK_DEVICETYPE_MAIN_EC: + return "EC"; + case FU_DELL_DOCK_DEVICETYPE_MST: + return "MST"; + case FU_DELL_DOCK_DEVICETYPE_TBT: + return "Thunderbolt"; + case FU_DELL_DOCK_DEVICETYPE_HUB: + if (sub_type == SUBTYPE_GEN2) + return "USB 3.1 Gen2"; + else if (sub_type == SUBTYPE_GEN1) + return "USB 3.1 Gen1"; + return NULL; + case FU_DELL_DOCK_DEVICETYPE_PD: + return "PD"; + default: + return NULL; + } +} + +static gboolean +fu_dell_dock_ec_read (FuDevice *device, guint32 cmd, gsize length, + GBytes **bytes, GError **error) +{ + /* The first byte of result data will be the size of the return, + hide this from callers */ + guint8 result_length = length + 1; + g_autoptr(GBytes) bytes_local = NULL; + const guint8 *result; + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (self->symbiote != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + + if (!fu_dell_dock_hid_i2c_read (self->symbiote, cmd, result_length, + &bytes_local, &ec_base_settings, error)) { + g_prefix_error (error, "read over HID-I2C failed: "); + return FALSE; + } + result = g_bytes_get_data (bytes_local, NULL); + /* first byte of result should be size of our data */ + if (result[0] != length) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid result data: %d expected %" G_GSIZE_FORMAT, + result[0], length); + return FALSE; + } + *bytes = g_bytes_new (result + 1, length); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_write (FuDevice *device, gsize length, guint8 *data, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (self->symbiote != NULL, FALSE); + g_return_val_if_fail (length > 1, FALSE); + + if (!fu_dell_dock_hid_i2c_write (self->symbiote, data, length, + &ec_base_settings, error)) { + g_prefix_error (error, "write over HID-I2C failed: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_is_valid_dock (FuDevice *device, GError **error) +{ + g_autoptr(GBytes) data = NULL; + const guint8 *result = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_CMD_GET_DOCK_TYPE, 1, &data, error)) { + g_prefix_error (error, "Failed to query dock type: "); + return FALSE; + } + result = g_bytes_get_data (data, NULL); + + if (result == NULL || *result != EXPECTED_DOCK_TYPE) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "No valid dock was found"); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_dell_dock_ec_get_dock_info (FuDevice *device, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + const FuDellDockDockInfoHeader *header = NULL; + const FuDellDockEcQueryEntry *device_entry = NULL; + const FuDellDockEcAddrMap *map = NULL; + const gchar *hub_version; + guint32 oldest_base_pd = 0; + g_autoptr(GBytes) data = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_CMD_GET_DOCK_INFO, + EXPECTED_DOCK_INFO_SIZE, + &data, error)) { + g_prefix_error (error, "Failed to query dock info: "); + return FALSE; + } + if (!g_bytes_get_data (data, NULL)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to read dock info"); + return FALSE; + } + + header = (FuDellDockDockInfoHeader *) g_bytes_get_data (data, NULL); + if (!header) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to parse dock info"); + return FALSE; + } + + /* guard against EC not yet ready and fail init */ + if (header->total_devices == 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, + "No bridge devices detected, dock may be booting up"); + return FALSE; + } + g_debug ("%u devices [%u->%u]", + header->total_devices, + header->first_index, + header->last_index); + device_entry = + (FuDellDockEcQueryEntry *) ((guint8 *) header + sizeof(FuDellDockDockInfoHeader)); + for (guint i = 0; i < header->total_devices; i++) { + const gchar *type_str; + map = &(device_entry[i].ec_addr_map); + type_str = fu_dell_dock_devicetype_to_str (map->device_type, map->sub_type); + if (type_str == NULL) + continue; + g_debug ("#%u: %s in %s (A: %u I: %u)", i, type_str, + (map->location == LOCATION_BASE) ? "Base" : "Module", + map->arg, map->instance); + g_debug ("\tVersion32: %08x\tVersion8: %x %x %x %x", + device_entry[i].version.version_32, + device_entry[i].version.version_8[0], + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + /* BCD but guint32 */ + if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MAIN_EC) { + self->raw_versions->ec_version = device_entry[i].version.version_32; + self->ec_version = g_strdup_printf ( + "%02x.%02x.%02x.%02x", device_entry[i].version.version_8[0], + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + g_debug ("\tParsed version %s", self->ec_version); + fu_device_set_version (FU_DEVICE (self), self->ec_version, FWUPD_VERSION_FORMAT_QUAD); + + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MST) { + self->raw_versions->mst_version = device_entry[i].version.version_32; + /* guard against invalid MST version read from EC */ + if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 1)) { + g_warning ("[EC Bug] EC read invalid MST version %08x", + device_entry[i].version.version_32); + continue; + } + self->mst_version = g_strdup_printf ("%02x.%02x.%02x", + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + g_debug ("\tParsed version %s", self->mst_version); + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_TBT && + self->data->module_type == MODULE_TYPE_TBT) { + /* guard against invalid Thunderbolt version read from EC */ + if (!fu_dell_dock_test_valid_byte (device_entry[i].version.version_8, 2)) { + g_warning ("[EC bug] EC read invalid Thunderbolt version %08x", + device_entry[i].version.version_32); + continue; + } + self->raw_versions->tbt_version = device_entry[i].version.version_32; + self->tbt_version = g_strdup_printf ("%02x.%02x", + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + g_debug ("\tParsed version %s", self->tbt_version); + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_HUB) { + g_debug ("\thub subtype: %u", map->sub_type); + if (map->sub_type == SUBTYPE_GEN2) + self->raw_versions->hub2_version = device_entry[i].version.version_32; + else if (map->sub_type == SUBTYPE_GEN1) + self->raw_versions->hub1_version = device_entry[i].version.version_32; + } else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_PD && + map->location == LOCATION_BASE && + map->sub_type == 0) { + if (oldest_base_pd == 0 || + device_entry[i].version.version_32 < oldest_base_pd) + oldest_base_pd = GUINT32_TO_BE (device_entry[i].version.version_32); + g_debug ("\tParsed version: %02x.%02x.%02x.%02x", + device_entry[i].version.version_8[0], + device_entry[i].version.version_8[1], + device_entry[i].version.version_8[2], + device_entry[i].version.version_8[3]); + } + } + + /* Thunderbolt SKU takes a little longer */ + if (self->data->module_type == MODULE_TYPE_TBT) { + guint64 tmp = fu_device_get_install_duration (device); + fu_device_set_install_duration (device, tmp + 20); + } + + /* minimum EC version this code will support */ + if (fu_common_vercmp (self->ec_version, self->ec_minimum_version) < 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "dock containing EC version %s is not supported", + self->ec_version); + return FALSE; + } + + fu_device_set_version_lowest (device, self->ec_minimum_version); + + + /* Determine if the passive flow should be used when flashing */ + hub_version = fu_device_get_version (self->symbiote); + if (fu_common_vercmp (hub_version, "1.42") >= 0) { + g_debug ("using passive flow"); + self->passive_flow = PASSIVE_REBOOT_MASK; + fu_device_set_custom_flags (device, "skip-restart"); + } else { + g_debug ("not using passive flow (EC: %s Hub2: %s)", + self->ec_version, hub_version); + } + return TRUE; +} + +static gboolean +fu_dell_dock_ec_get_dock_data (FuDevice *device, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + g_autoptr(GBytes) data = NULL; + g_autoptr(GString) name = NULL; + gchar service_tag[8] = {0x00}; + const guint8 *result; + gsize length = sizeof(FuDellDockDockDataStructure); + g_autofree gchar *bundled_serial = NULL; + FuDellDockECFWUpdateStatus status; + + g_return_val_if_fail (device != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_CMD_GET_DOCK_DATA, length, + &data, error)) { + g_prefix_error (error, "Failed to query dock info: "); + return FALSE; + } + result = g_bytes_get_data (data, NULL); + if (result == NULL) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to read dock data"); + return FALSE; + } + if (g_bytes_get_size (data) != length) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Unexpected dock data size %" G_GSIZE_FORMAT, + g_bytes_get_size (data)); + return FALSE; + } + memcpy (self->data, result, length); + + /* guard against EC not yet ready and fail init */ + name = g_string_new (self->data->marketing_name); + if (name->len > 0) + fu_device_set_name (device, name->str); + else + g_warning ("[EC bug] Invalid dock name detected"); + + if (self->data->module_type >= 0xfe) + g_warning ("[EC bug] Invalid module type 0x%02x", + self->data->module_type); + + /* set serial number */ + memcpy (service_tag, self->data->service_tag, 7); + bundled_serial = g_strdup_printf ("%s/%08" G_GUINT64_FORMAT, + service_tag, + self->data->module_serial); + fu_device_set_serial (device, bundled_serial); + + /* copy this for being able to send in next commit transaction */ + self->raw_versions->pkg_version = self->data->dock_firmware_pkg_ver; + + /* read if passive update pending */ + if (!fu_dell_dock_get_ec_status (device, &status, error)) + return FALSE; + + /* make sure this hardware spin matches our expecations */ + if (self->data->board_id >= self->board_min) { + if (status != FW_UPDATE_IN_PROGRESS) { + fu_dell_dock_ec_set_board (device); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + fu_device_set_update_error (device, "An update is pending " + "next time the dock is " + "unplugged"); + } + } else { + g_warning ("This utility does not support this board, disabling updates for %s", + fu_device_get_name (device)); + } + + return TRUE; +} + +static void +fu_dell_dock_ec_to_string (FuDevice *device, GString *str) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + gchar service_tag[8] = {0x00}; + + g_string_append (str, " FuDellDellDockEc:\n"); + g_string_append_printf (str, "\tboard ID: %u\n", + self->data->board_id); + g_string_append_printf (str, "\tpower supply: %uW\n", + self->data->power_supply_wattage); + g_string_append_printf (str, "\tstatus (port0): %x\n", + self->data->port0_dock_status); + g_string_append_printf (str, "\tstatus (port1): %x\n", + self->data->port1_dock_status); + memcpy (service_tag, self->data->service_tag, 7); + g_string_append_printf (str, "\tservice tag: %s\n", + service_tag); + g_string_append_printf (str, "\tconfiguration: %u\n", + self->data->dock_configuration); + g_string_append_printf (str, "\tpackage firmware version: %x\n", + self->data->dock_firmware_pkg_ver); + g_string_append_printf (str, "\tmodule serial #: %08" G_GUINT64_FORMAT "\n", + self->data->module_serial); + g_string_append_printf (str, "\toriginal module serial #: %08" G_GUINT64_FORMAT "\n", + self->data->original_module_serial); + g_string_append_printf (str, "\ttype: %u\n", + self->data->dock_type); + g_string_append_printf (str, "\tmodule type: %x\n", + self->data->module_type); + g_string_append_printf (str, "\tminimum ec: %s\n", + self->ec_minimum_version); + g_string_append_printf (str, "\tpassive flow: %d\n", + self->passive_flow); +} + +gboolean +fu_dell_dock_ec_modify_lock (FuDevice *device, + guint8 target, + gboolean unlocked, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + guint32 cmd; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (target != 0, FALSE); + + cmd = EC_CMD_MODIFY_LOCK | /* cmd */ + 2 << 8 | /* length of data arguments */ + target << 16 | /* device to operate on */ + unlocked << 24; /* unlock/lock */ + + + if (!fu_dell_dock_ec_write (device, 4, (guint8 *) &cmd, error)) { + g_prefix_error (error, "Failed to unlock device %d: ", target); + return FALSE; + } + g_debug ("Modified lock for %d to %d through %s (%s)", + target, unlocked, + fu_device_get_name (device), + fu_device_get_id (device)); + + if (unlocked) + BIT_SET (self->dock_unlock_status, target); + else + BIT_CLEAR (self->dock_unlock_status, target); + g_debug ("current overall unlock status: 0x%08x", self->dock_unlock_status); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_reset (FuDevice *device, GError **error) +{ + guint16 cmd = EC_CMD_RESET; + + g_return_val_if_fail (device != NULL, FALSE); + + return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); +} + +static gboolean +fu_dell_dock_ec_activate (FuDevice *device, GError **error) +{ + FuDellDockECFWUpdateStatus status; + + /* read if passive update pending */ + if (!fu_dell_dock_get_ec_status (device, &status, error)) + return FALSE; + + if (status != FW_UPDATE_IN_PROGRESS) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "No firmware update pending for %s", + fu_device_get_name (device)); + return FALSE; + } + + return fu_dell_dock_ec_reset (device, error); +} + +gboolean +fu_dell_dock_ec_reboot_dock (FuDevice *device, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + g_return_val_if_fail (device != NULL, FALSE); + + if (self->passive_flow > 0) { + guint32 cmd = EC_CMD_PASSIVE | /* cmd */ + 1 << 8 | /* length of data arguments */ + self->passive_flow << 16; + g_debug ("activating passive flow (%x) for %s", + self->passive_flow, + fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 3, (guint8 *) &cmd, error); + } else { + guint16 cmd = EC_CMD_REBOOT; + g_debug ("rebooting %s", fu_device_get_name (device)); + return fu_dell_dock_ec_write (device, 2, (guint8 *) &cmd, error); + } + + return TRUE; +} + +static gboolean +fu_dell_dock_get_ec_status (FuDevice *device, + FuDellDockECFWUpdateStatus *status_out, + GError **error) +{ + g_autoptr(GBytes) data = NULL; + const guint8 *result = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (status_out != NULL, FALSE); + + if (!fu_dell_dock_ec_read (device, EC_GET_FW_UPDATE_STATUS, 1, + &data, error)) { + g_prefix_error (error, "Failed to read FW update status: "); + return FALSE; + } + result = g_bytes_get_data (data, NULL); + + if (!result) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, + "Failed to read FW update status"); + return FALSE; + } + *status_out = *result; + return TRUE; +} + +const gchar* +fu_dell_dock_ec_get_tbt_version (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + return self->tbt_version; +} + +const gchar* +fu_dell_dock_ec_get_mst_version (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + return self->mst_version; +} + +guint32 +fu_dell_dock_ec_get_status_version (FuDevice *device) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + return self->raw_versions->pkg_version; +} + +gboolean +fu_dell_dock_ec_commit_package (FuDevice *device, GBytes *blob_fw, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + gsize length = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &length); + g_autofree guint8 *payload = g_malloc0 (length + 2); + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + if (length != sizeof(FuDellDockDockPackageFWVersion)) { + g_set_error (error, G_IO_ERR, G_IO_ERROR_INVALID_DATA, + "Invalid package size %" G_GSIZE_FORMAT, + length); + return FALSE; + } + memcpy (self->raw_versions, data, length); + + g_debug ("Committing (%zu) bytes ", sizeof(FuDellDockDockPackageFWVersion)); + g_debug ("\tec_version: %x", self->raw_versions->ec_version); + g_debug ("\tmst_version: %x", self->raw_versions->mst_version); + g_debug ("\thub1_version: %x", self->raw_versions->hub1_version); + g_debug ("\thub2_version: %x", self->raw_versions->hub2_version); + g_debug ("\ttbt_version: %x", self->raw_versions->tbt_version); + g_debug ("\tpkg_version: %x", self->raw_versions->pkg_version); + + payload [0] = EC_CMD_SET_DOCK_PKG; + payload [1] = length; + memcpy (payload + 2, data, length); + + if (!fu_dell_dock_ec_write (device, length + 2, payload, error)) { + g_prefix_error (error, "Failed to query dock info: "); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_write_fw (FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + FuDellDockECFWUpdateStatus status = FW_UPDATE_IN_PROGRESS; + guint8 progress1 = 0, progress0 = 0; + gsize fw_size = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &fw_size); + gsize write_size = + (fw_size / HIDI2C_MAX_WRITE) >= 1 ? HIDI2C_MAX_WRITE : fw_size; + gsize nwritten = 0; + guint32 address = 0 | 0xff << 24; + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strndup ((gchar *) data + self->blob_version_offset, 11); + g_debug ("writing EC firmware version %s", dynamic_version); + + if (!fu_dell_dock_ec_modify_lock (device, self->unlock_target, TRUE, error)) + return FALSE; + + if (!fu_dell_dock_hid_raise_mcu_clock (self->symbiote, TRUE, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dell_dock_hid_erase_bank (self->symbiote, 0xff, error)) + return FALSE; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + do { + /* last packet */ + if (fw_size - nwritten < write_size) + write_size = fw_size - nwritten; + + if (!fu_dell_dock_hid_write_flash (self->symbiote, address, data, + write_size, error)) { + g_prefix_error (error, "write over HID failed: "); + return FALSE; + } + fu_device_set_progress_full (device, nwritten, fw_size); + nwritten += write_size; + data += write_size; + address += write_size; + } while (nwritten < fw_size); + + if (!fu_dell_dock_hid_raise_mcu_clock (self->symbiote, FALSE, error)) + return FALSE; + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version, FWUPD_VERSION_FORMAT_QUAD); + + /* activate passive behavior */ + if (self->passive_flow) + self->passive_flow |= PASSIVE_RESET_MASK; + + if (fu_device_has_custom_flag (device, "skip-restart")) { + g_debug ("Skipping EC reset per quirk request"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + return TRUE; + } + + if (!fu_dell_dock_ec_reset (device, error)) + return FALSE; + + /* notify daemon that this device will need to replug */ + fu_dell_dock_will_replug (device); + + /* poll for completion status */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + while (status != FW_UPDATE_COMPLETE) { + g_autoptr(GError) error_local = NULL; + + if (!fu_dell_dock_hid_get_ec_status (self->symbiote, &progress1, + &progress0, error)) { + g_prefix_error (error, "Failed to read scratch: "); + return FALSE; + } + g_debug ("Read %u and %u from scratch", progress1, progress0); + if (progress0 > 100) + progress0 = 100; + fu_device_set_progress_full (device, progress0, 100); + + /* This is expected to fail until update is done */ + if (!fu_dell_dock_get_ec_status (device, &status, + &error_local)) { + g_debug ("Flash EC Received result: %s (status %u)", + error_local->message, status); + return TRUE; + } + if (status == FW_UPDATE_AUTHENTICATION_FAILED) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid EC firmware image"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockBoardMin") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->board_min = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockBoardMin"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockVersionLowest") == 0) { + self->ec_minimum_version = g_strdup (value); + return TRUE; + } + if (g_str_has_prefix (key, "DellDockBoard")) { + fu_device_set_metadata (device, key, value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobVersionOffset") == 0) { + self->blob_version_offset = fu_common_strtoull (value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_dell_dock_ec_probe (FuDevice *device, GError **error) +{ + /* this will trigger setting up all the quirks */ + fu_device_add_instance_id (device, DELL_DOCK_EC_INSTANCE_ID); + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_query (FuDevice *device, GError **error) +{ + if (!fu_dell_dock_ec_get_dock_data (device, error)) + return FALSE; + + return fu_dell_dock_ec_get_dock_info (device, error); +} + +static gboolean +fu_dell_dock_ec_setup (FuDevice *device, GError **error) +{ + g_autoptr(GError) error_local = NULL; + GPtrArray *children; + + /* if query looks bad, wait a few seconds and retry */ + if (!fu_dell_dock_ec_query (device, &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID)) { + g_warning ("%s", error_local->message); + g_usleep (2 * G_USEC_PER_SEC); + if (!fu_dell_dock_ec_query (device, error)) + return FALSE; + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + } + + /* call setup on all the children we produced */ + children = fu_device_get_children (device); + for (guint i=0 ; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + g_autoptr(FuDeviceLocker) locker = NULL; + g_debug ("setup %s", + fu_device_get_name (child)); + locker = fu_device_locker_new (child, error); + if (locker == NULL) + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_dell_dock_ec_open (FuDevice *device, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + return fu_dell_dock_is_valid_dock (device, error); +} + +static gboolean +fu_dell_dock_ec_close (FuDevice *device, GError **error) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (device); + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_ec_finalize (GObject *object) +{ + FuDellDockEc *self = FU_DELL_DOCK_EC (object); + g_object_unref (self->symbiote); + g_free (self->ec_version); + g_free (self->mst_version); + g_free (self->tbt_version); + g_free (self->data); + g_free (self->raw_versions); + g_free (self->ec_minimum_version); + G_OBJECT_CLASS (fu_dell_dock_ec_parent_class)->finalize (object); +} + +static void +fu_dell_dock_ec_init (FuDellDockEc *self) +{ + self->data = g_new0 (FuDellDockDockDataStructure, 1); + self->raw_versions = g_new0 (FuDellDockDockPackageFWVersion, 1); +} + +static void +fu_dell_dock_ec_class_init (FuDellDockEcClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_ec_finalize; + klass_device->activate = fu_dell_dock_ec_activate; + klass_device->to_string = fu_dell_dock_ec_to_string; + klass_device->probe = fu_dell_dock_ec_probe; + klass_device->setup = fu_dell_dock_ec_setup; + klass_device->open = fu_dell_dock_ec_open; + klass_device->close = fu_dell_dock_ec_close; + klass_device->write_firmware = fu_dell_dock_ec_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_ec_set_quirk_kv; +} + +FuDellDockEc * +fu_dell_dock_ec_new (FuDevice *symbiote) +{ + FuDellDockEc *self = NULL; + + self = g_object_new (FU_TYPE_DELL_DOCK_EC, NULL); + self->symbiote = g_object_ref (symbiote); + fu_device_set_physical_id (FU_DEVICE (self), + fu_device_get_physical_id (self->symbiote)); + fu_device_set_logical_id (FU_DEVICE (self), "ec"); + + return self; +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-ec.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-ec.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-ec.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-ec.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_EC (fu_dell_dock_ec_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockEc, fu_dell_dock_ec, FU, DELL_DOCK_EC, FuDevice) + +FuDellDockEc *fu_dell_dock_ec_new (FuDevice *symbiote); + +G_END_DECLS + +gboolean fu_dell_dock_ec_needs_tbt (FuDevice *device); +gboolean fu_dell_dock_ec_tbt_passive (FuDevice *device); +gboolean fu_dell_dock_ec_modify_lock (FuDevice *self, + guint8 target, + gboolean unlocked, + GError **error); + +gboolean fu_dell_dock_ec_reboot_dock (FuDevice *device, + GError **error); + +const gchar *fu_dell_dock_ec_get_mst_version (FuDevice *device); +const gchar *fu_dell_dock_ec_get_tbt_version (FuDevice *device); +guint32 fu_dell_dock_ec_get_status_version (FuDevice *device); +gboolean fu_dell_dock_ec_commit_package (FuDevice *device, + GBytes *blob_fw, + GError **error); +FuDevice *fu_dell_dock_ec_get_symbiote (FuDevice *device); diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-mst.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-mst.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-mst.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-mst.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,990 @@ +/* + * Copyright (C) 2018 Synaptics + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-dell-dock-common.h" + +#define I2C_MST_ADDRESS 0x72 + +/* MST registers */ +#define MST_RC_TRIGGER_ADDR 0x2000fc +#define MST_CORE_MCU_BOOTLOADER_STS 0x20010c +#define MST_RC_COMMAND_ADDR 0x200110 +#define MST_RC_OFFSET_ADDR 0x200114 +#define MST_RC_LENGTH_ADDR 0x200118 +#define MST_RC_DATA_ADDR 0x200120 +#define MST_CORE_MCU_FW_VERSION 0x200160 +#define MST_REG_QUAD_DISABLE 0x200fc0 +#define MST_REG_HDCP22_DISABLE 0x200f90 + +/* MST remote control commands */ +#define MST_CMD_ENABLE_REMOTE_CONTROL 0x1 +#define MST_CMD_DISABLE_REMOTE_CONTROL 0x2 +#define MST_CMD_CHECKSUM 0x11 +#define MST_CMD_ERASE_FLASH 0x14 +#define MST_CMD_WRITE_FLASH 0x20 +#define MST_CMD_READ_FLASH 0x30 +#define MST_CMD_WRITE_MEMORY 0x21 +#define MST_CMD_READ_MEMORY 0x31 + +/* Arguments related to flashing */ +#define FLASH_SECTOR_ERASE_4K 0x1000 +#define FLASH_SECTOR_ERASE_32K 0x2000 +#define FLASH_SECTOR_ERASE_64K 0x3000 +#define EEPROM_TAG_OFFSET 0x1fff0 +#define EEPROM_BANK_OFFSET 0x20000 +#define EEPROM_ESM_OFFSET 0x40000 + +/* Flash offsets */ +#define MST_BOARDID_OFFSET 0x10e + +/* Remote control offsets */ +#define MST_CHIPID_OFFSET 0x1500 + +/* magic triggers */ +#define MST_TRIGGER_WRITE 0xf2 +#define MST_TRIGGER_REBOOT 0xf5 + +/* IDs used in DELL_DOCK */ +#define EXPECTED_CHIPID 0x5331 + +/* firmware file offsets */ +#define MST_BLOB_VERSION_OFFSET 0x06F0 + +typedef enum { + Bank0, + Bank1, + ESM, +} MSTBank; + +typedef struct { + guint start; + guint length; +} MSTBankAttributes; + +const MSTBankAttributes bank0_attributes = { + .start = 0, + .length = EEPROM_BANK_OFFSET, +}; + +const MSTBankAttributes bank1_attributes = { + .start = EEPROM_BANK_OFFSET, + .length = EEPROM_BANK_OFFSET, +}; + +const MSTBankAttributes esm_attributes = { + .start = EEPROM_ESM_OFFSET, + .length = 0x3ffff +}; + +FuHIDI2CParameters mst_base_settings = { + .i2cslaveaddr = I2C_MST_ADDRESS, + .regaddrlen = 0, + .i2cspeed = I2C_SPEED_400K, +}; + +struct _FuDellDockMst { + FuDevice parent_instance; + FuDevice *symbiote; + guint8 unlock_target; + guint64 blob_major_offset; + guint64 blob_minor_offset; + guint64 blob_build_offset; +}; + +G_DEFINE_TYPE (FuDellDockMst, fu_dell_dock_mst, FU_TYPE_DEVICE) + +/** + * fu_dell_dock_mst_get_bank_attribs: + * @bank: An MSTBank + * @out (out): The MSTBankAttributes attribute that matches + * @error: the #GError, or %NULL + * + * Returns a structure that corresponds to the attributes for a bank + * + * Returns: %TRUE for success + **/ +static gboolean +fu_dell_dock_mst_get_bank_attribs (MSTBank bank, + const MSTBankAttributes **out, + GError **error) +{ + switch (bank) { + case Bank0: + *out = &bank0_attributes; + break; + case Bank1: + *out = &bank1_attributes; + break; + case ESM: + *out = &esm_attributes; + break; + default: + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid bank specified %u", bank); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_dell_dock_mst_rc_command (FuDevice *symbiote, + guint8 cmd, + guint32 length, + guint32 offset, + const guint8 *data, + GError **error); + +static gboolean +fu_dell_dock_mst_read_register (FuDevice *symbiote, + guint32 address, + gsize length, + GBytes **bytes, + GError **error) +{ + g_return_val_if_fail (symbiote != NULL, FALSE); + g_return_val_if_fail (bytes != NULL, FALSE); + g_return_val_if_fail (length <= 32, FALSE); + + /* write the offset we're querying */ + if (!fu_dell_dock_hid_i2c_write (symbiote, (guint8 *) &address, 4, + &mst_base_settings, error)) + return FALSE; + + /* read data for the result */ + if (!fu_dell_dock_hid_i2c_read (symbiote, 0, length, bytes, + &mst_base_settings, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_write_register (FuDevice *symbiote, + guint32 address, + guint8 *data, + gsize length, + GError **error) +{ + g_autofree guint8 *buffer = g_malloc0 (length + 4); + memcpy (buffer, &address, 4); + memcpy (buffer + 4, data, length); + + g_return_val_if_fail (symbiote != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + /* write the offset we're querying */ + return fu_dell_dock_hid_i2c_write (symbiote, buffer, length + 4, + &mst_base_settings, error); +} + +static gboolean +fu_dell_dock_mst_query_active_bank (FuDevice *symbiote, + MSTBank *active, + GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint32 *data = NULL; + gsize length = 4; + + if (!fu_dell_dock_mst_read_register (symbiote, MST_CORE_MCU_BOOTLOADER_STS, + length, &bytes, error)) { + g_prefix_error (error, "Failed to query active bank: "); + return FALSE; + } + + data = g_bytes_get_data (bytes, &length); + if ((data[0] & (1 << 7)) || (data[0] & (1 << 30))) + *active = Bank1; + else + *active = Bank0; + g_debug ("MST: active bank is: %u", *active); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_disable_remote_control (FuDevice *symbiote, GError **error) +{ + g_debug ("MST: Disabling remote control"); + return fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_DISABLE_REMOTE_CONTROL, + 0, 0, + NULL, + error); +} + +static gboolean +fu_dell_dock_mst_enable_remote_control (FuDevice *symbiote, GError **error) +{ + g_autoptr(GError) error_local = NULL; + const gchar *data = "PRIUS"; + + g_debug ("MST: Enabling remote control"); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_ENABLE_REMOTE_CONTROL, + 5, 0, + (guint8 *) data, + &error_local)) { + g_debug ("Failed to enable remote control: %s", + error_local->message); + /* try to disable / re-enable */ + if (!fu_dell_dock_mst_disable_remote_control (symbiote, error)) + return FALSE; + return fu_dell_dock_mst_enable_remote_control (symbiote, error); + } + return TRUE; +} + +static gboolean +fu_dell_dock_trigger_rc_command (FuDevice *symbiote, GError **error) +{ + const guint8 *result = NULL; + guint32 tmp; + + /* Trigger the write */ + tmp = MST_TRIGGER_WRITE; + if (!fu_dell_dock_mst_write_register (symbiote, + MST_RC_TRIGGER_ADDR, + (guint8 *) &tmp, sizeof(guint32), + error)) { + g_prefix_error (error, "Failed to write MST_RC_TRIGGER_ADDR: "); + return FALSE; + } + /* poll for completion */ + tmp = 0xffff; + for (guint i = 0; i < 1000; i++) { + g_autoptr(GBytes) bytes = NULL; + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_COMMAND_ADDR, + sizeof(guint32), &bytes, + error)) { + g_prefix_error (error, + "Failed to poll MST_RC_COMMAND_ADDR"); + return FALSE; + } + result = g_bytes_get_data (bytes, NULL); + /* complete */ + if ((result[2] & 0x80) == 0) { + tmp = result[3]; + break; + } + g_usleep (2000); + } + switch (tmp) { + /* need to enable remote control */ + case 4: + return fu_dell_dock_mst_enable_remote_control (symbiote, error); + /* error scenarios */ + case 3: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown error"); + return FALSE; + case 2: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unsupported command"); + return FALSE; + case 1: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid argument"); + return FALSE; + /* success scenario */ + case 0: + return TRUE; + + default: + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Command timed out or unknown failure: %x", + tmp); + return FALSE; + } +} + +static gboolean +fu_dell_dock_mst_rc_command (FuDevice *symbiote, + guint8 cmd, + guint32 length, + guint32 offset, + const guint8 *data, + GError **error) +{ + /* 4 for cmd, 4 for offset, 4 for length, 4 for garbage */ + gint buffer_len = (data == NULL) ? 12 : length + 16; + g_autofree guint8 *buffer = g_malloc0 (buffer_len); + guint32 tmp; + + g_return_val_if_fail (symbiote != NULL, FALSE); + + /* command */ + tmp = (cmd | 0x80) << 16; + memcpy (buffer, &tmp, 4); + /* offset */ + memcpy (buffer + 4, &offset, 4); + /* length */ + memcpy (buffer + 8, &length, 4); + /* data */ + if (data != NULL) + memcpy (buffer + 16, data, length); + + /* write the combined register stream */ + if (!fu_dell_dock_mst_write_register (symbiote, MST_RC_COMMAND_ADDR, + buffer, buffer_len, error)) + return FALSE; + + return fu_dell_dock_trigger_rc_command (symbiote, error); +} + +static gboolean +fu_dell_dock_mst_read_chipid (FuDevice *symbiote, + guint16 *chip_id, + GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint8 *data; + gsize length = 4; + + g_return_val_if_fail (chip_id != NULL, FALSE); + + /* run an RC command to get data from memory */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_MEMORY, + length, MST_CHIPID_OFFSET, + NULL, + error)) + return FALSE; + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + length, + &bytes, + error)) + return FALSE; + data = g_bytes_get_data (bytes, &length); + *chip_id = (data[1] << 8) | data[2]; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_check_offset (guint8 byte, guint8 offset) +{ + if ((byte & offset) != 0) + return TRUE; + return FALSE; +} + +static gboolean +fu_d19_mst_check_fw (FuDevice *symbiote, GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + const guint8 *data; + gsize length = 4; + + if (!fu_dell_dock_mst_read_register (symbiote, + MST_CORE_MCU_BOOTLOADER_STS, + length, &bytes, + error)) + return FALSE; + data = g_bytes_get_data (bytes, &length); + + g_debug ("MST: firmware check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x01)); + g_debug ("MST: HDCP key check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x02)); + g_debug ("MST: Config0 check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x04)); + g_debug ("MST: Config1 check: %d", + fu_dell_dock_mst_check_offset (data[0], 0x08)); + + if (fu_dell_dock_mst_check_offset (data[0], 0xF0)) + g_debug ("MST: running in bootloader"); + else + g_debug ("MST: running in firmware"); + g_debug ("MST: Error code: %x", data[1]); + g_debug ("MST: GPIO boot strap record: %d", data[2]); + g_debug ("MST: Bootloader version number %x", data[3]); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_checksum_bank (FuDevice *symbiote, + GBytes *blob_fw, + MSTBank bank, + gboolean *checksum, + GError **error) +{ + g_autoptr(GBytes) csum_bytes = NULL; + const MSTBankAttributes *attribs = NULL; + gsize length = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &length); + guint32 payload_sum = 0; + guint32 bank_sum = 0; + + g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (checksum != NULL, FALSE); + + if (!fu_dell_dock_mst_get_bank_attribs (bank, &attribs, error)) + return FALSE; + + /* bank is specified outside of payload */ + if (attribs->start + attribs->length > length) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Payload %u is bigger than bank %u", + attribs->start + attribs->length, bank); + return FALSE; + } + + /* checksum the file */ + for (guint i = attribs->start; i < attribs->length + attribs->start; + i++) { + payload_sum += data[i]; + } + g_debug ("MST: Payload checksum: 0x%x", payload_sum); + + /* checksum the bank */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_CHECKSUM, + attribs->length, attribs->start, + NULL, + error)) { + g_prefix_error (error, "Failed to checksum bank %u: ", bank); + return FALSE; + } + /* read result from data register */ + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + 4, &csum_bytes, error)) + return FALSE; + data = g_bytes_get_data (csum_bytes, NULL); + bank_sum = GUINT32_FROM_LE (data[0] | data[1] << 8 | data[2] << 16 | + data[3] << 24); + g_debug ("MST: Bank %u checksum: 0x%x", bank, bank_sum); + + *checksum = (bank_sum == payload_sum); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_erase_bank (FuDevice *symbiote, MSTBank bank, GError **error) +{ + const MSTBankAttributes *attribs = NULL; + guint32 sector; + + if (!fu_dell_dock_mst_get_bank_attribs (bank, &attribs, error)) + return FALSE; + + for (guint32 i = attribs->start; i < attribs->start + attribs->length; + i += 0x10000) { + sector = FLASH_SECTOR_ERASE_64K | (i / 0x10000); + g_debug ("MST: Erasing sector 0x%x", sector); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_ERASE_FLASH, + 4, 0, + (guint8 *) §or, + error)) { + g_prefix_error ( + error, "Failed to erase sector 0x%x: ", sector); + return FALSE; + } + } + g_debug ("MST: Waiting for flash clear to settle"); + g_usleep (5000000); + + return TRUE; +} + +static gboolean +fu_dell_dock_write_flash_bank (FuDevice *device, + GBytes *blob_fw, + MSTBank bank, + GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + const MSTBankAttributes *attribs = NULL; + gsize write_size = 32; + guint end; + const guint8 *data = g_bytes_get_data (blob_fw, NULL); + + g_return_val_if_fail (blob_fw != NULL, FALSE); + + if (!fu_dell_dock_mst_get_bank_attribs (bank, &attribs, error)) + return FALSE; + end = attribs->start + attribs->length; + + g_debug ("MST: Writing payload to bank %u", bank); + for (guint i = attribs->start; i < end; i += write_size) { + if (!fu_dell_dock_mst_rc_command (self->symbiote, + MST_CMD_WRITE_FLASH, + write_size, i, + data + i, + error)) { + g_prefix_error ( + error, + "Failed to write bank %u payload offset 0x%x: ", + bank, i); + return FALSE; + } + fu_device_set_progress_full (device, + i - attribs->start, + end - attribs->start); + } + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_stop_esm (FuDevice *symbiote, GError **error) +{ + g_autoptr(GBytes) quad_bytes = NULL; + g_autoptr(GBytes) hdcp_bytes = NULL; + guint32 payload = 0x21; + gsize length = sizeof(guint32); + const guint8 *data; + guint8 data_out[sizeof(guint32)]; + + /* disable ESM first */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_MEMORY, + length, MST_RC_TRIGGER_ADDR, + (guint8 *) &payload, + error)) + return FALSE; + + /* waiting for ESM exit */ + g_usleep(200); + + /* disable QUAD mode */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_MEMORY, + length, MST_REG_QUAD_DISABLE, + NULL, + error)) + return FALSE; + + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + length, &quad_bytes, + error)) + return FALSE; + + data = g_bytes_get_data (quad_bytes, &length); + memcpy (data_out, data, length); + data_out[0] = 0x00; + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_MEMORY, + length, MST_REG_QUAD_DISABLE, + data_out, error)) + return FALSE; + + /* disable HDCP2.2 */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_MEMORY, + length, MST_REG_HDCP22_DISABLE, + NULL, + error)) + return FALSE; + + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + length, + &hdcp_bytes, + error)) + return FALSE; + + data = g_bytes_get_data (hdcp_bytes, &length); + memcpy (data_out, data, length); + data_out[0] = data[0] & (1 << 2); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_MEMORY, + length, MST_REG_HDCP22_DISABLE, + data_out, + error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_invalidate_bank (FuDevice *symbiote, MSTBank bank_in_use, + GError **error) +{ + const MSTBankAttributes *attribs; + g_autoptr(GBytes) bytes = NULL; + const guint8 *crc_tag; + const guint8 *new_tag; + guint32 crc_offset; + guint retries = 2; + + if (!fu_dell_dock_mst_get_bank_attribs (bank_in_use, &attribs, error)) { + g_prefix_error (error, "unable to invalidate bank: "); + return FALSE; + } + /* we need to write 4 byte increments over I2C so this differs from DP aux */ + crc_offset = attribs->start + EEPROM_TAG_OFFSET + 12; + + /* Read CRC byte to flip */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_FLASH, + 4, crc_offset, + NULL, + error)) { + + g_prefix_error (error, "failed to read tag from flash: "); + return FALSE; + } + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + 1, + &bytes, + error)) { + return FALSE; + } + crc_tag = g_bytes_get_data (bytes, NULL); + g_debug ("CRC byte is currently 0x%x", crc_tag[3]); + + for (guint32 retries_cnt = 0; ; retries_cnt++) { + g_autoptr(GBytes) bytes_new = NULL; + /* CRC8 is not 0xff, erase last 4k of bank# */ + if (crc_tag[3] != 0xff) { + guint32 sector = FLASH_SECTOR_ERASE_4K + + (attribs->start + attribs->length - 0x1000) / 0x1000; + g_debug ("Erasing 4k from sector 0x%x invalidate bank %u", + sector, bank_in_use); + /* offset for last 4k of bank# */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_ERASE_FLASH, + 4, 0, + (guint8 *) §or, + error)) { + + g_prefix_error (error, + "failed to erase sector 0x%x: ", + sector); + return FALSE; + } + /* CRC8 is 0xff, set it to 0x00 */ + } else { + guint32 write = 0x00; + g_debug ("Writing 0x00 byte to 0x%x to invalidate bank %u", + crc_offset, bank_in_use); + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_WRITE_FLASH, + 4, crc_offset, + (guint8*) &write, + error)) { + + g_prefix_error (error, "failed to clear CRC byte: "); + return FALSE; + } + } + /* re-read for comparison */ + if (!fu_dell_dock_mst_rc_command (symbiote, + MST_CMD_READ_FLASH, + 4, crc_offset, + NULL, + error)) { + + g_prefix_error (error, "failed to read tag from flash: "); + return FALSE; + } + if (!fu_dell_dock_mst_read_register (symbiote, + MST_RC_DATA_ADDR, + 4, &bytes_new, + error)) { + return FALSE; + } + new_tag = g_bytes_get_data (bytes_new, NULL); + g_debug ("CRC byte is currently 0x%x", new_tag[3]); + + /* tag successfully cleared */ + if ((new_tag[3] == 0xff && crc_tag[3] != 0xff) || + (new_tag[3] == 0x00 && crc_tag[3] == 0xff)) { + break; + } + if (retries_cnt > retries) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "set tag invalid fail (new 0x%x; old 0x%x)", + new_tag[3], crc_tag[3]); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_write_fw (FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + MSTBank bank_in_use = 0; + guint retries = 2; + gboolean checksum = FALSE; + guint8 order[2] = {ESM, Bank0}; + guint16 chip_id; + const guint8* data = g_bytes_get_data (blob_fw, NULL); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + g_return_val_if_fail (self->symbiote != NULL, FALSE); + + dynamic_version = g_strdup_printf ("%02x.%02x.%02x", + data[self->blob_major_offset], + data[self->blob_minor_offset], + data[self->blob_build_offset]); + g_debug ("writing MST firmware version %s", dynamic_version); + + /* determine the flash order */ + if (!fu_dell_dock_mst_query_active_bank (self->symbiote, &bank_in_use, error)) + return FALSE; + + if (bank_in_use == Bank0) + order[1] = Bank1; + + /* enable remote control */ + if (!fu_dell_dock_mst_enable_remote_control (self->symbiote, error)) + return FALSE; + + /* Read Synaptics MST chip ID */ + if (!fu_dell_dock_mst_read_chipid (self->symbiote, &chip_id, + error)) + return FALSE; + if (chip_id != EXPECTED_CHIPID) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown MST chip found %x", chip_id); + return FALSE; + } + + /* ESM needs special handling during flash process*/ + if (!fu_dell_dock_mst_stop_esm (self->symbiote, error)) + return FALSE; + + /* Write each bank in order */ + for (guint phase = 0; phase < 2; phase++) { + g_debug ("MST: Checking bank %u", order[phase]); + if (!fu_dell_dock_mst_checksum_bank (self->symbiote, + blob_fw, + order[phase], + &checksum, error)) + return FALSE; + if (checksum) { + g_debug ("MST: bank %u is already up to date", order[phase]); + continue; + } + g_debug ("MST: bank %u needs to be updated", order[phase]); + for (guint i = 0; i < retries; i++) { + fu_device_set_progress_full (device, 0, 100); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_dell_dock_mst_erase_bank (self->symbiote, + order[phase], + error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_dell_dock_write_flash_bank (device, blob_fw, + order[phase], error)) + return FALSE; + if (!fu_dell_dock_mst_checksum_bank (self->symbiote, + blob_fw, + order[phase], + &checksum, + error)) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + if (!checksum) { + g_debug ( + "MST: Failed to verify checksum on bank %u", + order[phase]); + continue; + } + g_debug ("MST: Bank %u successfully flashed", order[phase]); + break; + } + /* failed after all our retries */ + if (!checksum) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to write to bank %u", order[phase]); + return FALSE; + } + } + /* invalidate the previous bank */ + if (!fu_dell_dock_mst_invalidate_bank (self->symbiote, bank_in_use, error)) { + g_prefix_error (error, "failed to invalidate bank %u: ", bank_in_use); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version, FWUPD_VERSION_FORMAT_TRIPLET); + + /* disable remote control now */ + return fu_dell_dock_mst_disable_remote_control (self->symbiote, error); +} + +static gboolean +fu_dell_dock_mst_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } + if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "DellDockBlobBuildOffset") == 0) { + self->blob_build_offset = fu_common_strtoull (value); + return TRUE; + } + else if (g_strcmp0 (key, "DellDockInstallDurationI2C") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_install_duration (device, tmp); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static gboolean +fu_dell_dock_mst_setup (FuDevice *device, GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + FuDevice *parent; + const gchar *version; + + /* sanity check that we can talk to MST */ + if (!fu_d19_mst_check_fw (self->symbiote, error)) + return FALSE; + + /* set version from EC if we know it */ + parent = fu_device_get_parent (device); + version = fu_dell_dock_ec_get_mst_version (parent); + if (version != NULL) + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_TRIPLET); + + fu_dell_dock_clone_updatable (device); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_probe (FuDevice *device, GError **error) +{ + fu_device_set_logical_id (FU_DEVICE (device), "mst"); + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_open (FuDevice *device, GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + FuDevice *parent = fu_device_get_parent (device); + + g_return_val_if_fail (self->unlock_target != 0, FALSE); + g_return_val_if_fail (parent != NULL, FALSE); + + if (self->symbiote == NULL) + self->symbiote = g_object_ref (fu_dell_dock_ec_get_symbiote (parent)); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + /* open up access to controller bus */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_mst_close (FuDevice *device, GError **error) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (device); + + /* close access to controller bus */ + if (!fu_dell_dock_set_power (device, self->unlock_target, FALSE, error)) + return FALSE; + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_mst_finalize (GObject *object) +{ + FuDellDockMst *self = FU_DELL_DOCK_MST (object); + g_object_unref (self->symbiote); + G_OBJECT_CLASS (fu_dell_dock_mst_parent_class)->finalize (object); +} + +static void +fu_dell_dock_mst_init (FuDellDockMst *self) +{ +} + +static void +fu_dell_dock_mst_class_init (FuDellDockMstClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_mst_finalize; + klass_device->probe = fu_dell_dock_mst_probe; + klass_device->open = fu_dell_dock_mst_open; + klass_device->close = fu_dell_dock_mst_close; + klass_device->setup = fu_dell_dock_mst_setup; + klass_device->probe = fu_dell_dock_mst_probe; + klass_device->write_firmware = fu_dell_dock_mst_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_mst_set_quirk_kv; +} + +FuDellDockMst * +fu_dell_dock_mst_new (void) +{ + FuDellDockMst *device = NULL; + device = g_object_new (FU_TYPE_DELL_DOCK_MST, NULL); + return device; +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-mst.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-mst.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-mst.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-mst.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_MST (fu_dell_dock_mst_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockMst, fu_dell_dock_mst, FU, DELL_DOCK_MST, FuDevice) + +FuDellDockMst *fu_dell_dock_mst_new (void); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-tbt.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-tbt.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-tbt.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-tbt.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * Copyright (C) 2019 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fwupd-error.h" +#include "fu-device.h" +#include "fu-common.h" +#include "fu-common-version.h" + +#include "fu-dell-dock-common.h" + +#define I2C_TBT_ADDRESS 0xa2 + +const FuHIDI2CParameters tbt_base_settings = { + .i2cslaveaddr = I2C_TBT_ADDRESS, + .regaddrlen = 1, + .i2cspeed = I2C_SPEED_400K, +}; + +/* TR Device ID */ +#define PID_OFFSET 0x05 +#define INTEL_PID 0x15ef + +/* earlier versions have bugs */ +#define MIN_NVM "36.01" + +struct _FuDellDockTbt { + FuDevice parent_instance; + FuDevice *symbiote; + guint8 unlock_target; + guint64 blob_major_offset; + guint64 blob_minor_offset; + gchar *hub_minimum_version; +}; + +G_DEFINE_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU_TYPE_DEVICE) + +static gboolean +fu_dell_dock_tbt_write_fw (FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + guint32 start_offset = 0; + gsize image_size; + const guint8 *buffer = g_bytes_get_data (blob_fw, &image_size); + guint16 target_system = 0; + g_autoptr(GTimer) timer = g_timer_new (); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + dynamic_version = g_strdup_printf ("%02x.%02x", + buffer[self->blob_major_offset], + buffer[self->blob_minor_offset]); + g_debug ("writing Thunderbolt firmware version %s", dynamic_version); + g_debug ("Total Image size: %" G_GSIZE_FORMAT, image_size); + + memcpy (&start_offset, buffer, sizeof (guint32)); + g_debug ("Header size 0x%x", start_offset); + if (start_offset > image_size) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Image header is too big (0x%x)", + start_offset); + return FALSE; + } + + memcpy (&target_system, buffer + start_offset + PID_OFFSET, sizeof (guint16)); + if (target_system != INTEL_PID) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Image is not intended for this system (0x%x)", + target_system); + return FALSE; + } + + buffer += start_offset; + image_size -= start_offset; + + g_debug ("waking Thunderbolt controller"); + if (!fu_dell_dock_hid_tbt_wake (self->symbiote, &tbt_base_settings, error)) + return FALSE; + g_usleep (2000000); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < image_size; i+= HIDI2C_MAX_WRITE, buffer += HIDI2C_MAX_WRITE) { + guint8 write_size = (image_size - i) > HIDI2C_MAX_WRITE ? + HIDI2C_MAX_WRITE : (image_size - i); + + if (!fu_dell_dock_hid_tbt_write (self->symbiote, + i, + buffer, + write_size, + &tbt_base_settings, + error)) + return FALSE; + + fu_device_set_progress_full (device, i, image_size); + } + g_debug ("writing took %f seconds", + g_timer_elapsed (timer, NULL)); + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_BUSY); + + if (fu_dell_dock_ec_tbt_passive (fu_device_get_parent (device))) { + g_debug ("using passive flow for Thunderbolt"); + } else if (!fu_dell_dock_hid_tbt_authenticate (self->symbiote, + &tbt_base_settings, + error)) { + g_prefix_error (error, "failed to authenticate: "); + return FALSE; + } + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version, FWUPD_VERSION_FORMAT_PAIR); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + + if (g_strcmp0 (key, "DellDockUnlockTarget") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < G_MAXUINT8) { + self->unlock_target = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DellDockUnlockTarget"); + return FALSE; + } else if (g_strcmp0 (key, "DellDockInstallDurationI2C") == 0) { + guint64 tmp = fu_common_strtoull (value); + fu_device_set_install_duration (device, tmp); + return TRUE; + } else if (g_strcmp0 (key, "DellDockHubVersionLowest") == 0) { + self->hub_minimum_version = g_strdup (value); + return TRUE; + } else if (g_strcmp0 (key, "DellDockBlobMajorOffset") == 0) { + self->blob_major_offset = fu_common_strtoull (value); + return TRUE; + } else if (g_strcmp0 (key, "DellDockBlobMinorOffset") == 0) { + self->blob_minor_offset = fu_common_strtoull (value); + return TRUE; + } + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + + +static gboolean +fu_dell_dock_tbt_setup (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + FuDevice *parent; + const gchar *version; + const gchar *hub_version; + + /* set version from EC if we know it */ + parent = fu_device_get_parent (device); + version = fu_dell_dock_ec_get_tbt_version (parent); + if (version != NULL) + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_PAIR); + + /* minimum version of NVM that supports this feature */ + if (version == NULL || fu_common_vercmp (version, MIN_NVM) < 0) { + fu_device_set_update_error (device, + "Updates over I2C are disabled due to insuffient NVM version"); + return TRUE; + } + /* minimum Hub2 version that supports this feature */ + hub_version = fu_device_get_version (self->symbiote); + if (fu_common_vercmp (hub_version, self->hub_minimum_version) < 0) { + fu_device_set_update_error (device, + "Updates over I2C are disabled due to insufficient USB 3.1 G2 hub version"); + return TRUE; + } + + fu_dell_dock_clone_updatable (device); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_probe (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + fu_device_set_physical_id (device, fu_device_get_physical_id (parent)); + fu_device_set_logical_id (FU_DEVICE (device), "tbt"); + fu_device_add_instance_id (device, DELL_DOCK_TBT_INSTANCE_ID); + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_open (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + FuDevice *parent; + + g_return_val_if_fail (self->unlock_target != 0, FALSE); + + parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no parent"); + return FALSE; + } + + if (self->symbiote == NULL) + self->symbiote = g_object_ref (fu_dell_dock_ec_get_symbiote (parent)); + + if (!fu_device_open (self->symbiote, error)) + return FALSE; + + /* adjust to access controller */ + if (!fu_dell_dock_set_power (device, self->unlock_target, TRUE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_dell_dock_tbt_close (FuDevice *device, GError **error) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (device); + + /* adjust to access controller */ + if (!fu_dell_dock_set_power (device, self->unlock_target, FALSE, error)) + return FALSE; + + return fu_device_close (self->symbiote, error); +} + +static void +fu_dell_dock_tbt_finalize (GObject *object) +{ + FuDellDockTbt *self = FU_DELL_DOCK_TBT (object); + g_object_unref (self->symbiote); + g_free (self->hub_minimum_version); + + G_OBJECT_CLASS (fu_dell_dock_tbt_parent_class)->finalize (object); +} + +static void +fu_dell_dock_tbt_init (FuDellDockTbt *device) +{} + +static void +fu_dell_dock_tbt_class_init (FuDellDockTbtClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_tbt_finalize; + klass_device->probe = fu_dell_dock_tbt_probe; + klass_device->setup = fu_dell_dock_tbt_setup; + klass_device->open = fu_dell_dock_tbt_open; + klass_device->close = fu_dell_dock_tbt_close; + klass_device->write_firmware = fu_dell_dock_tbt_write_fw; + klass_device->set_quirk_kv = fu_dell_dock_tbt_set_quirk_kv; +} + +FuDellDockTbt * +fu_dell_dock_tbt_new (void) +{ + FuDellDockTbt *device = NULL; + device = g_object_new (FU_TYPE_DELL_DOCK_TBT, NULL); + return device; +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-tbt.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-tbt.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-i2c-tbt.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-i2c-tbt.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 Intel Corporation. + * Copyright (C) 2019 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_TBT (fu_dell_dock_tbt_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockTbt, fu_dell_dock_tbt, FU, DELL_DOCK_TBT, FuDevice) + +FuDellDockTbt *fu_dell_dock_tbt_new (void); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-status.c fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-status.c --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-status.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-status.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include + +#include "fu-dell-dock-common.h" + +struct _FuDellDockStatus { + FuDevice parent_instance; + guint64 blob_version_offset; +}; + +G_DEFINE_TYPE (FuDellDockStatus, fu_dell_dock_status, FU_TYPE_DEVICE) + +static gchar * +fu_dell_dock_status_ver_string (guint32 status_version) +{ + /* guint32 BCD */ + return g_strdup_printf ("%02x.%02x.%02x.%02x", + status_version & 0xff, + (status_version >> 8) & 0xff, + (status_version >> 16) & 0xff, + (status_version >> 24) & 0xff); +} + +static gboolean +fu_dell_dock_status_setup (FuDevice *device, GError **error) +{ + FuDevice *parent; + guint32 status_version; + g_autofree gchar *dynamic_version = NULL; + + parent = fu_device_get_parent (device); + status_version = fu_dell_dock_ec_get_status_version (parent); + + dynamic_version = fu_dell_dock_status_ver_string (status_version); + fu_device_set_version (device, dynamic_version, FWUPD_VERSION_FORMAT_QUAD); + fu_device_set_logical_id (FU_DEVICE (device), "status"); + + fu_dell_dock_clone_updatable (device); + + return TRUE; +} + +static gboolean +fu_dell_dock_status_write (FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDellDockStatus *self = FU_DELL_DOCK_STATUS (device); + FuDevice *parent; + gsize length = 0; + guint32 status_version = 0; + const guint8 *data = g_bytes_get_data (blob_fw, &length); + g_autofree gchar *dynamic_version = NULL; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (blob_fw != NULL, FALSE); + + memcpy (&status_version, data + self->blob_version_offset, sizeof (guint32)); + dynamic_version = fu_dell_dock_status_ver_string (status_version); + g_debug ("writing status firmware version %s", dynamic_version); + + parent = fu_device_get_parent (device); + if (!fu_dell_dock_ec_commit_package (parent, blob_fw, error)) + return FALSE; + + /* dock will reboot to re-read; this is to appease the daemon */ + fu_device_set_version (device, dynamic_version, FWUPD_VERSION_FORMAT_QUAD); + return TRUE; +} + +static gboolean +fu_dell_dock_status_open (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + + g_return_val_if_fail (parent != NULL, FALSE); + + return fu_device_open (parent, error); +} + +static gboolean +fu_dell_dock_status_close (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + + return fu_device_close (parent, error); +} + +static gboolean +fu_dell_dock_status_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDellDockStatus *self = FU_DELL_DOCK_STATUS (device); + if (g_strcmp0 (key, "DellDockBlobVersionOffset") == 0) { + self->blob_version_offset = fu_common_strtoull (value); + return TRUE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_dell_dock_status_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_dell_dock_status_parent_class)->finalize (object); +} + +static void +fu_dell_dock_status_init (FuDellDockStatus *self) +{ +} + +static void +fu_dell_dock_status_class_init (FuDellDockStatusClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_dell_dock_status_finalize; + klass_device->write_firmware = fu_dell_dock_status_write; + klass_device->setup = fu_dell_dock_status_setup; + klass_device->open = fu_dell_dock_status_open; + klass_device->close = fu_dell_dock_status_close; + klass_device->set_quirk_kv = fu_dell_dock_status_set_quirk_kv; +} + +FuDellDockStatus * +fu_dell_dock_status_new (void) +{ + FuDellDockStatus *self = NULL; + self = g_object_new (FU_TYPE_DELL_DOCK_STATUS, NULL); + return self; +} diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-status.h fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-status.h --- fwupd-1.0.6/plugins/dell-dock/fu-dell-dock-status.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-dell-dock-status.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#pragma once + +#include "config.h" + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_DELL_DOCK_STATUS (fu_dell_dock_status_get_type ()) +G_DECLARE_FINAL_TYPE (FuDellDockStatus, fu_dell_dock_status, FU, DELL_DOCK_STATUS, FuDevice) + +FuDellDockStatus *fu_dell_dock_status_new (void); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/dell-dock/fu-plugin-dell-dock.c fwupd-1.2.10/plugins/dell-dock/fu-plugin-dell-dock.c --- fwupd-1.0.6/plugins/dell-dock/fu-plugin-dell-dock.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/fu-plugin-dell-dock.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2018 Dell Inc. + * All rights reserved. + * + * This software and associated documentation (if any) is furnished + * under a license and may only be used or copied in accordance + * with the terms of the license. + * + * This file is provided under a dual MIT/LGPLv2 license. When using or + * redistributing this file, you may do so under either license. + * Dell Chooses the MIT license part of Dual MIT/LGPLv2 license agreement. + * + * SPDX-License-Identifier: LGPL-2.1+ OR MIT + */ + +#include "config.h" + +#include "fu-device.h" +#include "fwupd-error.h" +#include "fu-plugin-vfuncs.h" + +#include "fu-dell-dock-common.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + + /* allow these to be built by quirks */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + g_type_ensure (FU_TYPE_DELL_DOCK_STATUS); + g_type_ensure (FU_TYPE_DELL_DOCK_MST); + + /* currently slower performance, but more reliable in corner cases */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "synapticsmst"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.dell.dock"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); +} + +static gboolean +fu_plugin_dell_dock_create_node (FuPlugin *plugin, + FuDevice *device, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + fu_device_set_quirks (device, fu_plugin_get_quirks (plugin)); + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + fu_plugin_device_add (plugin, device); + + return TRUE; +} + +static gboolean +fu_plugin_dell_dock_probe (FuPlugin *plugin, + FuDevice *symbiote, + GError **error) +{ + g_autoptr(FuDellDockEc) ec_device = NULL; + + /* create all static endpoints */ + ec_device = fu_dell_dock_ec_new (symbiote); + if (!fu_plugin_dell_dock_create_node (plugin, + FU_DEVICE (ec_device), + error)) + return FALSE; + + /* create TBT endpoint if Thunderbolt SKU and Thunderbolt link inactive */ + if (fu_dell_dock_ec_needs_tbt (FU_DEVICE (ec_device))) { + g_autoptr(FuDellDockTbt) tbt_device = fu_dell_dock_tbt_new (); + fu_device_add_child (FU_DEVICE (ec_device), FU_DEVICE (tbt_device)); + if (!fu_plugin_dell_dock_create_node (plugin, + FU_DEVICE (tbt_device), + error)) + return FALSE; + } + + return TRUE; +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, + FuUsbDevice *device, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuDellDockHub) hub = fu_dell_dock_hub_new (device); + FuDevice *fu_device = FU_DEVICE (hub); + const gchar *key = NULL; + + locker = fu_device_locker_new (fu_device, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, fu_device); + + if (fu_device_has_custom_flag (fu_device, "has-bridge")) { + g_autoptr(GError) error_local = NULL; + + /* only add the device with parent to cache */ + key = fu_device_get_id (fu_device); + if (fu_plugin_cache_lookup (plugin, key) != NULL) { + g_debug ("Ignoring already added device %s", key); + return TRUE; + } + fu_plugin_cache_add (plugin, key, fu_device); + + /* probe for extended devices */ + if (!fu_plugin_dell_dock_probe (plugin, + fu_device, + &error_local)) { + g_warning ("Failed to probe bridged devices for %s: %s", + key, + error_local->message); + } + } + + /* clear updatable flag if parent doesn't have it */ + fu_dell_dock_clone_updatable (fu_device); + + return TRUE; +} + +gboolean +fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) +{ + const gchar *device_key = fu_device_get_id (device); + FuDevice *dev; + FuDevice *parent; + + /* only the device with bridge will be in cache */ + dev = fu_plugin_cache_lookup (plugin, device_key); + if (dev == NULL) + return TRUE; + fu_plugin_cache_remove (plugin, device_key); + + /* find the parent and ask daemon to remove whole chain */ + parent = fu_device_get_parent (dev); + if (parent != NULL && FU_IS_DELL_DOCK_EC (parent)) { + g_debug ("Removing %s (%s)", + fu_device_get_name (parent), + fu_device_get_id (parent)); + fu_plugin_device_remove (plugin, parent); + } + + return TRUE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *dev, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + + fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_device_write_firmware (dev, blob_fw, flags, error)) { + g_prefix_error (error, + "failed to update %s: ", + fu_device_get_name (dev)); + return FALSE; + } + fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); + + return TRUE; +} + +/* prefer to use EC if in the transaction and parent if it is not */ +static FuDevice * +fu_plugin_dell_dock_get_ec (GPtrArray *devices) +{ + FuDevice *ec_parent = NULL; + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + FuDevice *parent; + if (FU_IS_DELL_DOCK_EC (dev)) + return dev; + parent = fu_device_get_parent (dev); + if (parent != NULL && FU_IS_DELL_DOCK_EC (parent)) + ec_parent = parent; + } + + return ec_parent; +} + +gboolean +fu_plugin_composite_prepare (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); + gboolean remaining_replug = FALSE; + + if (parent == NULL) + return TRUE; + + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + /* if thunderbolt is part of transaction our family is leaving us */ + if (g_strcmp0 (fu_device_get_plugin (dev), "thunderbolt") == 0) { + if (fu_device_get_parent (dev) != parent) + continue; + fu_dell_dock_will_replug (parent); + /* set all other devices to replug */ + remaining_replug = TRUE; + continue; + } + /* different device */ + if (fu_device_get_parent (dev) != parent) + continue; + if (remaining_replug) + fu_dell_dock_will_replug (dev); + } + + return TRUE; +} + +gboolean +fu_plugin_composite_cleanup (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + FuDevice *parent = fu_plugin_dell_dock_get_ec (devices); + g_autoptr(FuDeviceLocker) locker = NULL; + + if (parent == NULL) + return TRUE; + + locker = fu_device_locker_new (parent, error); + if (locker == NULL) + return FALSE; + + return fu_dell_dock_ec_reboot_dock (parent, error); +} + +gboolean +fu_plugin_activate (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (!FU_IS_DELL_DOCK_EC (device)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Invalid device to activate"); + return FALSE; + } + + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + return fu_device_activate (device, error); +} diff -Nru fwupd-1.0.6/plugins/dell-dock/meson.build fwupd-1.2.10/plugins/dell-dock/meson.build --- fwupd-1.0.6/plugins/dell-dock/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,34 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginDellDock"'] + +install_data(['dell-dock.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_dell_dock', + fu_hash, + sources : [ + 'fu-plugin-dell-dock.c', + 'fu-dell-dock-common.c', + 'fu-dell-dock-hid.c', + 'fu-dell-dock-status.c', + 'fu-dell-dock-i2c-ec.c', + 'fu-dell-dock-hub.c', + 'fu-dell-dock-i2c-tbt.c', + 'fu-dell-dock-i2c-mst.c' + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + gudev, + ], +) diff -Nru fwupd-1.0.6/plugins/dell-dock/README.md fwupd-1.2.10/plugins/dell-dock/README.md --- fwupd-1.0.6/plugins/dell-dock/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-dock/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,71 @@ +Dell USB-C Dock +========= + +### Dell System +Unlike previous Dell USB-C devices, a Dell system is not needed for updating. + +### Components +The device contains components the following directly updatable components: +* USB hubs +* MST controller +* Thunderbolt controller +* Embedded controller + +This plugin is used to perform the update on the USB hubs as well as the Dell +Embedded controller. The USB hubs are updated directly over a USB HID endpoint +while the embedded controller is updated using an I2C over HID interface. + +The fwupd thunderbolt plugin is used for updating the Titan Ridge controller. + +The MST controller is updated through either the DP Aux interface +(SynapticsMST plugin) or I2C over HID interface provided by this plugin. + +## Device topology +When this plugin is used, devices present in other plugins may be shown in +the topology of this dock. This is intentional as this plugin works together +with those plugins to manage the flashing of all components. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract several firmware +blobs with an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.dell.dock + * com.synaptics.mst + +GUID Generation +--------------- + +These devices use several different generation schemes, e.g. + + * USB Hub1: `USB\VID_413C&PID_B06F&hub` + * USB Hub2: `USB\VID_413C&PID_B06E&hub` + * Embedded Controller: `USB\VID_413C&PID_B06E&hub&embedded` + * Update Level: `USB\VID_413C&PID_B06E&hub&status` + * MST Hub: `MST-panamera-vmm5331-259` + * Thunderbolt Controller: `TBT-00d4b070` + +Custom flag use: +---------------- +This plugin uses the following plugin-specific custom flags: + +* `skip-restart`: Don't run the reset or reboot procedure of the component + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------------|-------------------------------------------------------------------------|-----------------------| +| `DellDockUnlockTarget` | The EC argument needed for unlocking certain device usage. | 1.1.3 | +| `DellDockBlobMajorOffset` | The offset of the major version number in a payload | 1.1.3 | +| `DellDockBlobMinorOffset` | The offset of the minor version number in a payload | 1.1.3 | +| `DellDockBlobBuildOffset` | The offset of the build version number in a payload | 1.1.3 | +| `DellDockBlobVersionOffset` | The offset of the ASCII representation of a version string in a payload | 1.1.3 | +| `DellDockBoardMin` | The minimum board revision required to safely operate the plugin | 1.1.3 | +| `DellDockVersionLowest` | The minimum component version required to safely operate the plugin | 1.1.3 | +| `DellDockBoard*` | The board description of a board revision | 1.1.3 | +| `DellDockInstallDurationI2C` | The duration of time required to install a payload via I2C. | 1.1.3 | diff -Nru fwupd-1.0.6/plugins/dell-esrt/dell-esrt.conf fwupd-1.2.10/plugins/dell-esrt/dell-esrt.conf --- fwupd-1.0.6/plugins/dell-esrt/dell-esrt.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-esrt/dell-esrt.conf 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,8 @@ +[fwupd Remote] + +# this remote provides metadata shipped with the fwupd package +Enabled=true +Title=Enable UEFI capsule updates on Dell systems +Keyring=none +MetadataURI=file://@datadir@/fwupd/remotes.d/dell-esrt/metadata.xml +ApprovalRequired=false diff -Nru fwupd-1.0.6/plugins/dell-esrt/fu-plugin-dell-esrt.c fwupd-1.2.10/plugins/dell-esrt/fu-plugin-dell-esrt.c --- fwupd-1.0.6/plugins/dell-esrt/fu-plugin-dell-esrt.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-esrt/fu-plugin-dell-esrt.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2017-2018 Dell, Inc. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include "fu-plugin-vfuncs.h" + +/* Whitelisted smbios class/select commands */ +#define CLASS_ADMIN_PROP 10 +#define SELECT_ADMIN_PROP 3 + +/* whitelisted tokens */ +#define CAPSULE_EN_TOKEN 0x0461 +#define CAPSULE_DIS_TOKEN 0x0462 + +/* these aren't defined upstream but used in fwupdate */ +#define DELL_ADMIN_MASK 0xF +#define DELL_ADMIN_INSTALLED 0 + +static gboolean +fu_plugin_dell_esrt_query_token (guint16 token, gboolean *value, GError **error) +{ + if (!token_is_bool (token)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "token %" G_GUINT16_FORMAT " is not boolean", + token); + return FALSE; + } + if (value != NULL) + *value = token_is_active (token) > 0; + + return TRUE; +} + +static gboolean +fu_plugin_dell_esrt_activate_token (guint16 token, GError **error) +{ + token_activate (token); + if (token_is_active (token) < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "token %" G_GUINT16_FORMAT "cannot be activated " + "as the password is set", token); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_plugin_dell_esrt_admin_password_present (gboolean *password_present, GError **error) +{ + guint32 args[4] = { 0, }, out[4] = { 0, }; + + if (dell_simple_ci_smi (CLASS_ADMIN_PROP, + SELECT_ADMIN_PROP, args, out)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot call SMI for CLASS_ADMIN_PROP"); + return FALSE; + } + + if (out[0] != 0 || (out[1] & DELL_ADMIN_MASK) == DELL_ADMIN_INSTALLED) { + *password_present = TRUE; + } else { + *password_present = FALSE; + } + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + gboolean capsule_disable = FALSE; + g_autofree gchar *sysfsfwdir = NULL; + g_autofree gchar *esrtdir = NULL; + + /* already exists */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrtdir = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + if (g_file_test (esrtdir, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "UEFI firmware already supported"); + return FALSE; + } + + /* is the capsule functionality disabled */ + if (!fu_plugin_dell_esrt_query_token (CAPSULE_DIS_TOKEN, &capsule_disable, error)) + return FALSE; + if (!capsule_disable) { + gboolean capsule_enable = FALSE; + if (!fu_plugin_dell_esrt_query_token (CAPSULE_EN_TOKEN, &capsule_enable, error)) + return FALSE; + if (capsule_enable) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "UEFI firmware will be unlocked on next boot"); + return FALSE; + } + } + + return TRUE; +} + +gboolean +fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error) +{ + gboolean password_present = FALSE; + /* check the admin password isn't set */ + if (!fu_plugin_dell_esrt_admin_password_present (&password_present, error)) + return FALSE; + if (password_present) { + const gchar *err_string = "Cannot be unlocked automatically as admin password set"; + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + err_string); + fu_device_set_update_error (device, err_string); + return FALSE; + } + + /* disabled in BIOS, but supported to be enabled via tool */ + if (!fu_plugin_dell_esrt_query_token (CAPSULE_EN_TOKEN, NULL, error)) + return FALSE; + if (!fu_plugin_dell_esrt_activate_token (CAPSULE_EN_TOKEN, error)) + return FALSE; + fu_device_set_update_error (device, NULL); + + return TRUE; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + g_autoptr(FuDevice) dev = fu_device_new (); + + /* create a dummy device so we can unlock the feature */ + fu_device_set_id (dev, "UEFI-dummy-dev0"); + fu_device_set_name (dev, "Dell UEFI updates"); + fu_device_set_summary (dev, "Enable UEFI Update Functionality"); + fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); + fu_device_set_version (dev, "0", FWUPD_VERSION_FORMAT_NUMBER); + fu_device_add_icon (dev, "computer"); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_LOCKED); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_set_update_error (dev, "Firmware updates disabled; run 'fwupdmgr unlock' to enable"); + fu_plugin_device_add (plugin, dev); + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/dell-esrt/meson.build fwupd-1.2.10/plugins/dell-esrt/meson.build --- fwupd-1.0.6/plugins/dell-esrt/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-esrt/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,40 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginDellEsrt"'] + +install_data(['metadata.xml'], + install_dir : join_paths(datadir, 'fwupd', 'remotes.d', 'dell-esrt') +) + +shared_module('fu_plugin_dell_esrt', + fu_hash, + sources : [ + 'fu-plugin-dell-esrt.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + ], + link_with : [ + libfwupdprivate, + ], + dependencies : [ + plugin_deps, + libsmbios_c, + ], +) + +# replace @datadir@ +con2 = configuration_data() +con2.set('datadir', datadir) +configure_file( + input : 'dell-esrt.conf', + output : 'dell-esrt.conf', + configuration : con2, + install: true, + install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'), +) diff -Nru fwupd-1.0.6/plugins/dell-esrt/metadata.xml fwupd-1.2.10/plugins/dell-esrt/metadata.xml --- fwupd-1.0.6/plugins/dell-esrt/metadata.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-esrt/metadata.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,27 @@ + + + + + + org.fwupd.8330a096d9f1af8567c7374cb8403e1ce9cf3163.device + + 2d47f29b-83a2-4f31-a2e8-63474f4d4c2e + + UEFI Updates + Enable UEFI Update Functionality + + + +

+ Applying this update will enable the UEFI firmware reporting interface on your hardware. +

+

+ You will have to restart your computer after this update is installed + to be notified of any pending firmware updates. +

+
+
+
+
+ +
diff -Nru fwupd-1.0.6/plugins/dell-esrt/README.md fwupd-1.2.10/plugins/dell-esrt/README.md --- fwupd-1.0.6/plugins/dell-esrt/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dell-esrt/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,42 @@ +Dell ESRT Support +================= + +Introduction +------------ + +This allows enabling the BIOS setup option for UEFI capsule updates without +manually going into BIOS setup. + +GUID Generation +--------------- + +These device uses a hardcoded GUID of `2d47f29b-83a2-4f31-a2e8-63474f4d4c2e`. + +Build Requirements +------------------ + +For Dell support you will need libsmbios_c version 2.4.0 or later. + +* source: https://github.com/dell/libsmbios +* binaries: https://github.com/dell/libsmbios/releases + +If you don't want or need this functionality you can use the +`-Dplugin_dell=false` option. + +# Devices powered by the Dell Plugin +The Dell ESRT plugin allows the user to enable the UpdateCapsule functionality +at runtime. A reboot will be required and the BIOS administrator password +must not be set. + +Machines that offer this functionality will display an extra device in +```# fwupdmgr get-devices``` output. + +Example: +``` +UEFI dummy device + Guid: 2d47f29b-83a2-4f31-a2e8-63474f4d4c2e + Plugin: dell-esrt + Flags: internal|updatable|locked + Version: 0 + Created: 2018-06-25 +``` diff -Nru fwupd-1.0.6/plugins/dfu/contrib/parse-avrdude-conf.py fwupd-1.2.10/plugins/dfu/contrib/parse-avrdude-conf.py --- fwupd-1.0.6/plugins/dfu/contrib/parse-avrdude-conf.py 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/contrib/parse-avrdude-conf.py 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,10 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 """ This parses avrdude.conf and generates quirks for fwupd """ # pylint: disable=wrong-import-position,pointless-string-statement """ - Licensed under the GNU General Public License Version 2 - - 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 2 of the License, 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, see . - +SPDX-License-Identifier: LGPL-2.1+ """ import sys diff -Nru fwupd-1.0.6/plugins/dfu/dfu-chunked.c fwupd-1.2.10/plugins/dfu/dfu-chunked.c --- fwupd-1.0.6/plugins/dfu/dfu-chunked.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-chunked.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 20157 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include - -#include "dfu-chunked.h" - -/** - * dfu_chunked_packet_new: - * @idx: the packet number - * @page: the hardware memory page - * @address: the address *within* the page - * @data: the data - * @data_sz: size of @data_sz - * - * Creates a new packet of chunked data. - * - * Return value: (transfer full): a #DfuChunkedPacket - **/ -DfuChunkedPacket * -dfu_chunked_packet_new (guint32 idx, - guint32 page, - guint32 address, - const guint8 *data, - guint32 data_sz) -{ - DfuChunkedPacket *item = g_new0 (DfuChunkedPacket, 1); - item->idx = idx; - item->page = page; - item->address = address; - item->data = data; - item->data_sz = data_sz; - return item; -} - -/** - * dfu_chunked_packet_to_string: - * @item: a #DfuChunkedPacket - * - * Converts the chunked packet to a string representation. - * - * Return value: (transfer full): A string - **/ -gchar * -dfu_chunked_packet_to_string (DfuChunkedPacket *item) -{ - g_autoptr(GString) str = g_string_new (NULL); - if (item->data != NULL) { - for (guint32 i = 0; i < item->data_sz; i++) { - gchar tmp = (gchar) item->data[i]; - if (tmp == 0x00) - break; - g_string_append_c (str, g_ascii_isalnum (tmp) ? tmp : '?'); - } - } - return g_strdup_printf ("#%02" G_GUINT32_FORMAT ": page:%02x " - "addr:%04x len:%02" G_GUINT32_FORMAT " %s", - item->idx, - (guint) item->page, - (guint) item->address, - item->data_sz, - str->str); -} - -/** - * dfu_chunked_to_string: - * @segments: (element-type DfuChunkedPacket): array of packets - * - * Converts all the chunked packets in an array to a string representation. - * - * Return value: (transfer full): A string - **/ -gchar * -dfu_chunked_to_string (GPtrArray *segments) -{ - GString *str = g_string_new (NULL); - for (guint i = 0; i < segments->len; i++) { - DfuChunkedPacket *item = g_ptr_array_index (segments, i); - g_autofree gchar *tmp = dfu_chunked_packet_to_string (item); - g_string_append_printf (str, "%s\n", tmp); - } - return g_string_free (str, FALSE); -} - -/** - * dfu_chunked_new: - * @data: a linear blob of memory, or %NULL - * @data_sz: size of @data_sz - * @addr_start: the hardware address offset, or 0 - * @page_sz: the hardware page size, or 0 - * @packet_sz: the transfer size, or 0 - * - * Chunks a linear blob of memory into packets, ensuring each packet does not - * cross a package boundary and is less that a specific transfer size. - * - * Return value: (element-type DfuChunkedPacket): array of packets - **/ -GPtrArray * -dfu_chunked_new (const guint8 *data, - guint32 data_sz, - guint32 addr_start, - guint32 page_sz, - guint32 packet_sz) -{ - GPtrArray *segments = NULL; - guint32 page_old = G_MAXUINT32; - guint32 idx; - guint32 last_flush = 0; - - g_return_val_if_fail (data_sz > 0, NULL); - - segments = g_ptr_array_new_with_free_func (g_free); - for (idx = 1; idx < data_sz; idx++) { - guint32 page = 0; - if (page_sz > 0) - page = (addr_start + idx) / page_sz; - if (page_old == G_MAXUINT32) { - page_old = page; - } else if (page != page_old) { - const guint8 *data_offset = data != NULL ? data + last_flush : 0x0; - guint32 address_offset = addr_start + last_flush; - if (page_sz > 0) - address_offset %= page_sz; - g_ptr_array_add (segments, - dfu_chunked_packet_new (segments->len, - page_old, - address_offset, - data_offset, - idx - last_flush)); - last_flush = idx; - page_old = page; - continue; - } - if (packet_sz > 0 && idx - last_flush >= packet_sz) { - const guint8 *data_offset = data != NULL ? data + last_flush : 0x0; - guint32 address_offset = addr_start + last_flush; - if (page_sz > 0) - address_offset %= page_sz; - g_ptr_array_add (segments, - dfu_chunked_packet_new (segments->len, - page, - address_offset, - data_offset, - idx - last_flush)); - last_flush = idx; - continue; - } - } - if (last_flush != idx) { - const guint8 *data_offset = data != NULL ? data + last_flush : 0x0; - guint32 address_offset = addr_start + last_flush; - guint32 page = 0; - if (page_sz > 0) { - address_offset %= page_sz; - page = (addr_start + (idx - 1)) / page_sz; - } - g_ptr_array_add (segments, - dfu_chunked_packet_new (segments->len, - page, - address_offset, - data_offset, - data_sz - last_flush)); - } - return segments; -} diff -Nru fwupd-1.0.6/plugins/dfu/dfu-chunked.h fwupd-1.2.10/plugins/dfu/dfu-chunked.h --- fwupd-1.0.6/plugins/dfu/dfu-chunked.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-chunked.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __DFU_CHUNKED_H -#define __DFU_CHUNKED_H - -#include -#include - -G_BEGIN_DECLS - -typedef struct { - guint32 idx; - guint32 page; - guint32 address; - const guint8 *data; - guint32 data_sz; -} DfuChunkedPacket; - -DfuChunkedPacket *dfu_chunked_packet_new (guint32 idx, - guint32 page, - guint32 address, - const guint8 *data, - guint32 data_sz); -gchar *dfu_chunked_packet_to_string (DfuChunkedPacket *item); - -gchar *dfu_chunked_to_string (GPtrArray *chunked); -GPtrArray *dfu_chunked_new (const guint8 *data, - guint32 data_sz, - guint32 addr_start, - guint32 page_sz, - guint32 packet_sz); - -G_END_DECLS - -#endif /* __DFU_CHUNKED_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-cipher-xtea.c fwupd-1.2.10/plugins/dfu/dfu-cipher-xtea.c --- fwupd-1.0.6/plugins/dfu/dfu-cipher-xtea.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-cipher-xtea.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/plugins/dfu/dfu-cipher-xtea.h fwupd-1.2.10/plugins/dfu/dfu-cipher-xtea.h --- fwupd-1.0.6/plugins/dfu/dfu-cipher-xtea.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-cipher-xtea.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_XTEA_H -#define __DFU_FORMAT_XTEA_H +#pragma once #include #include @@ -37,5 +21,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_XTEA_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-common.c fwupd-1.2.10/plugins/dfu/dfu-common.c --- fwupd-1.0.6/plugins/dfu/dfu-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** @@ -193,23 +178,53 @@ } /** - * dfu_utils_bytes_is_empty: + * dfu_utils_bytes_pad: * @bytes: a #GBytes + * @sz: the desired size in bytes * - * Checks if a byte array are just empty (0xff) bytes. + * Pads a GBytes to a given @sz with `0xff`. * - * Return value: %TRUE if @bytes is empty + * Return value: (transfer full): a #GBytes **/ -gboolean -dfu_utils_bytes_is_empty (GBytes *bytes) +GBytes * +dfu_utils_bytes_pad (GBytes *bytes, gsize sz) { - gsize sz = 0; - const guint8 *buf = g_bytes_get_data (bytes, &sz); - for (gsize i = 0; i < sz; i++) { - if (buf[i] != 0xff) - return FALSE; + gsize bytes_sz; + + g_return_val_if_fail (g_bytes_get_size (bytes) <= sz, NULL); + + /* pad */ + bytes_sz = g_bytes_get_size (bytes); + if (bytes_sz < sz) { + const guint8 *data = g_bytes_get_data (bytes, NULL); + guint8 *data_new = g_malloc (sz); + memcpy (data_new, data, bytes_sz); + memset (data_new + bytes_sz, 0xff, sz - bytes_sz); + return g_bytes_new_take (data_new, sz); } - return TRUE; + + /* exactly right */ + return g_bytes_ref (bytes); +} + +/** + * dfu_utils_buffer_parse_uint4: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 1 byte long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint8 +dfu_utils_buffer_parse_uint4 (const gchar *data) +{ + gchar buffer[2]; + memcpy (buffer, data, 1); + buffer[1] = '\0'; + return (guint8) g_ascii_strtoull (buffer, NULL, 16); } /** @@ -253,6 +268,26 @@ } /** + * dfu_utils_buffer_parse_uint24: + * @data: a string + * + * Parses a base 16 number from a string. + * + * The string MUST be at least 6 bytes long as this function cannot check the + * length of @data. Checking the size must be done in the caller. + * + * Return value: A parsed value, or 0 for error + **/ +guint32 +dfu_utils_buffer_parse_uint24 (const gchar *data) +{ + gchar buffer[7]; + memcpy (buffer, data, 6); + buffer[6] = '\0'; + return (guint32) g_ascii_strtoull (buffer, NULL, 16); +} + +/** * dfu_utils_buffer_parse_uint32: * @data: a string * @@ -271,3 +306,27 @@ buffer[8] = '\0'; return (guint32) g_ascii_strtoull (buffer, NULL, 16); } + +/** + * dfu_utils_strnsplit: + * @str: a string to split + * @sz: size of @str + * @delimiter: a string which specifies the places at which to split the string + * @max_tokens: the maximum number of pieces to split @str into + * + * Splits a string into a maximum of @max_tokens pieces, using the given + * delimiter. If @max_tokens is reached, the remainder of string is appended + * to the last token. + * + * Return value: a newly-allocated NULL-terminated array of strings + **/ +gchar ** +dfu_utils_strnsplit (const gchar *str, gsize sz, + const gchar *delimiter, gint max_tokens) +{ + if (str[sz - 1] != '\0') { + g_autofree gchar *str2 = g_strndup (str, sz); + return g_strsplit (str2, delimiter, max_tokens); + } + return g_strsplit (str, delimiter, max_tokens); +} diff -Nru fwupd-1.0.6/plugins/dfu/dfu-common.h fwupd-1.2.10/plugins/dfu/dfu-common.h --- fwupd-1.0.6/plugins/dfu/dfu-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_COMMON_H -#define __DFU_COMMON_H +#pragma once #include #include @@ -131,7 +115,7 @@ * @DFU_CIPHER_KIND_XTEA: XTEA cipher detected * @DFU_CIPHER_KIND_RSA: RSA cipher detected * - * The type of cipher used for transfering the firmware. + * The type of cipher used for transferring the firmware. **/ typedef enum { DFU_CIPHER_KIND_NONE, @@ -172,11 +156,16 @@ /* helpers */ GBytes *dfu_utils_bytes_join_array (GPtrArray *chunks); -gboolean dfu_utils_bytes_is_empty (GBytes *bytes); +GBytes *dfu_utils_bytes_pad (GBytes *bytes, + gsize sz); +guint8 dfu_utils_buffer_parse_uint4 (const gchar *data); guint8 dfu_utils_buffer_parse_uint8 (const gchar *data); guint16 dfu_utils_buffer_parse_uint16 (const gchar *data); +guint32 dfu_utils_buffer_parse_uint24 (const gchar *data); guint32 dfu_utils_buffer_parse_uint32 (const gchar *data); +gchar **dfu_utils_strnsplit (const gchar *str, + gsize sz, + const gchar *delimiter, + gint max_tokens); G_END_DECLS - -#endif /* __DFU_COMMON_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-device.c fwupd-1.2.10/plugins/dfu/dfu-device.c --- fwupd-1.0.6/plugins/dfu/dfu-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** @@ -35,6 +20,61 @@ * See also: #DfuTarget, #DfuFirmware */ +/** + * FU_QUIRKS_DFU_FLAGS: + * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` + * @value: a string, separated using `|`, e.g. `ignore-polltimeout|no-pid-change` + * + * Assigns optional quirks to use for a DFU device which does not follow the + * DFU 1.0 or 1.1 specification. The list of supported quirks is thus: + * + * * `none`: No device quirks + * * `action-required`: User has to do something manually, e.g. press a button + * * `attach-extra-reset`: Device needs resetting twice for attach + * * `attach-upload-download`: An upload or download is required for attach + * * `force-dfu-mode`: Force DFU mode + * * `ignore-polltimeout`: Ignore the device download timeout + * * `ignore-runtime`: Device has broken DFU runtime support + * * `ignore-upload`: Uploading from the device is broken + * * `no-dfu-runtime`: No DFU runtime interface is provided + * * `no-get-status-upload`: Do not do GetStatus when uploading + * * `no-pid-change`: Accept the same VID:PID when changing modes + * * `use-any-interface`: Use any interface for DFU + * * `use-atmel-avr`: Device uses the ATMEL bootloader + * * `use-protocol-zero`: Fix up the protocol number + * * `legacy-protocol`: Use a legacy protocol version + * + * Default value: `none` + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_FLAGS "DfuFlags" + +/** + * FU_QUIRKS_DFU_FORCE_VERSION: + * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` + * @value: the uint16_t DFU version, encoded in base 16, e.g. `0110` + * + * Forces a specific DFU version for the hardware device. This is required + * if the device does not set, or sets incorrectly, items in the DFU functional + * descriptor. + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_FORCE_VERSION "DfuForceVersion" + +/** + * FU_QUIRKS_DFU_JABRA_DETACH: + * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` + * @value: the two uint8_t unlock values, encoded in base 16, e.g. `0201` + * + * Assigns the two magic bytes sent to the Jabra hardware when the device is + * in runtime mode to make it switch into DFU mode. + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_JABRA_DETACH "DfuJabraDetach" + #include "config.h" #include @@ -61,7 +101,9 @@ gboolean done_upload_or_download; gboolean claimed_interface; gchar *chip_id; + gchar *jabra_detach; guint16 version; + guint16 force_version; guint16 runtime_pid; guint16 runtime_vid; guint16 runtime_release; @@ -82,65 +124,6 @@ G_DEFINE_TYPE_WITH_PRIVATE (DfuDevice, dfu_device, FU_TYPE_USB_DEVICE) #define GET_PRIVATE(o) (dfu_device_get_instance_private (o)) -static gboolean dfu_device_open (FuUsbDevice *device, GError **error); -static gboolean dfu_device_close (FuUsbDevice *device, GError **error); -static gboolean dfu_device_probe (FuUsbDevice *device, GError **error); - -static void -dfu_device_class_init (DfuDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); - klass_usb_device->open = dfu_device_open; - klass_usb_device->close = dfu_device_close; - klass_usb_device->probe = dfu_device_probe; - - /** - * DfuDevice::status-changed: - * @device: the #DfuDevice instance that emitted the signal - * @status: the new #DfuStatus - * - * The ::status-changed signal is emitted when the status changes. - **/ - signals [SIGNAL_STATUS_CHANGED] = - g_signal_new ("status-changed", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (DfuDeviceClass, status_changed), - NULL, NULL, g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - /** - * DfuDevice::state-changed: - * @device: the #DfuDevice instance that emitted the signal - * @state: the new #DfuState - * - * The ::state-changed signal is emitted when the state changes. - **/ - signals [SIGNAL_STATE_CHANGED] = - g_signal_new ("state-changed", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (DfuDeviceClass, state_changed), - NULL, NULL, g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - object_class->finalize = dfu_device_finalize; -} - -static void -dfu_device_init (DfuDevice *device) -{ - DfuDevicePrivate *priv = GET_PRIVATE (device); - priv->iface_number = 0xff; - priv->runtime_pid = 0xffff; - priv->runtime_vid = 0xffff; - priv->runtime_release = 0xffff; - priv->state = DFU_STATE_APP_IDLE; - priv->status = DFU_STATUS_OK; - priv->targets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - priv->timeout_ms = 1500; - priv->transfer_size = 64; -} - /** * dfu_device_get_transfer_size: * @device: a #GUsbDevice @@ -204,20 +187,6 @@ priv->transfer_size = transfer_size; } -static void -dfu_device_finalize (GObject *object) -{ - DfuDevice *device = DFU_DEVICE (object); - DfuDevicePrivate *priv = GET_PRIVATE (device); - - if (priv->usb_context != NULL) - g_object_unref (priv->usb_context); - g_free (priv->chip_id); - g_ptr_array_unref (priv->targets); - - G_OBJECT_CLASS (dfu_device_parent_class)->finalize (object); -} - typedef struct __attribute__((packed)) { guint8 bLength; guint8 bDescriptorType; @@ -231,7 +200,7 @@ dfu_device_parse_iface_data (DfuDevice *device, GBytes *iface_data, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); - DfuFuncDescriptor desc; + DfuFuncDescriptor desc = { 0x0 }; const guint8 *buf; gsize sz; @@ -239,6 +208,10 @@ buf = g_bytes_get_data (iface_data, &sz); if (sz == sizeof(DfuFuncDescriptor)) { memcpy (&desc, buf, sz); + } else if (sz > sizeof(DfuFuncDescriptor)) { + g_debug ("DFU interface with %" G_GSIZE_FORMAT " bytes vendor data", + sz - sizeof(DfuFuncDescriptor)); + memcpy (&desc, buf, sizeof(DfuFuncDescriptor)); } else if (sz == sizeof(DfuFuncDescriptor) - 2) { g_warning ("truncated DFU interface data, no bcdDFUVersion"); memcpy (&desc, buf, sz); @@ -258,16 +231,6 @@ return FALSE; } - /* check sanity */ - if (desc.bLength != sz) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "DFU interface data has incorrect length: 0x%02x", - desc.bLength); - return FALSE; - } - /* get transfer size and version */ priv->transfer_size = GUINT16_FROM_LE (desc.wTransferSize); priv->version = GUINT16_FROM_LE (desc.bcdDFUVersion); @@ -314,7 +277,6 @@ { DfuDevicePrivate *priv = GET_PRIVATE (device); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - FuQuirks *system_quirks = fu_device_get_quirks (FU_DEVICE (device)); g_autoptr(GPtrArray) ifaces = NULL; /* add all DFU-capable targets */ @@ -325,7 +287,6 @@ for (guint i = 0; i < ifaces->len; i++) { GBytes *iface_data = NULL; DfuTarget *target; - const gchar *quirk_str; g_autoptr(GError) error_local = NULL; GUsbInterface *iface = g_ptr_array_index (ifaces, i); @@ -341,7 +302,9 @@ iface_data = g_usb_interface_get_extra (iface); if (g_bytes_get_size (iface_data) > 0) { if (!dfu_device_parse_iface_data (device, iface_data, &error_local)) { - g_warning ("failed to parse interface data: %s", + g_warning ("failed to parse interface data for %04x:%04x: %s", + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device), error_local->message); continue; } @@ -351,11 +314,8 @@ } /* fix up the version */ - quirk_str = fu_quirks_lookup_by_usb_device (system_quirks, - FU_QUIRKS_DFU_FORCE_VERSION, - usb_device); - if (quirk_str != NULL && strlen (quirk_str) == 4) - priv->version = dfu_utils_buffer_parse_uint16 (quirk_str); + if (priv->force_version > 0) + priv->version = priv->force_version; if (priv->version == DFU_VERSION_DFU_1_0 || priv->version == DFU_VERSION_DFU_1_1) { g_debug ("DFU v1.1"); @@ -415,17 +375,16 @@ } /* the device has no DFU runtime, so cheat */ - if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { - if (priv->targets->len == 0) { - g_debug ("no DFU runtime, so faking device"); - priv->state = DFU_STATE_APP_IDLE; - priv->iface_number = 0xff; - priv->runtime_vid = g_usb_device_get_vid (usb_device); - priv->runtime_pid = g_usb_device_get_pid (usb_device); - priv->runtime_release = g_usb_device_get_release (usb_device); - priv->attributes = DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD | - DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD; - } + if (priv->targets->len == 0 && + priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { + g_debug ("no DFU runtime, so faking device"); + priv->state = DFU_STATE_APP_IDLE; + priv->iface_number = 0xff; + priv->runtime_vid = g_usb_device_get_vid (usb_device); + priv->runtime_pid = g_usb_device_get_pid (usb_device); + priv->runtime_release = g_usb_device_get_release (usb_device); + priv->attributes = DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD | + DFU_DEVICE_ATTRIBUTE_CAN_UPLOAD; return TRUE; } @@ -612,7 +571,8 @@ dfu_device_set_quirks_from_string (DfuDevice *device, const gchar *str) { DfuDevicePrivate *priv = GET_PRIVATE (device); - g_auto(GStrv) split = g_strsplit (str, "|", -1); + g_auto(GStrv) split = g_strsplit (str, ",", -1); + priv->quirks = DFU_DEVICE_QUIRK_NONE; for (guint i = 0; split[i] != NULL; i++) { if (g_strcmp0 (split[i], "ignore-polltimeout") == 0) { priv->quirks |= DFU_DEVICE_QUIRK_IGNORE_POLLTIMEOUT; @@ -665,23 +625,6 @@ } } -static void -dfu_device_apply_quirks (DfuDevice *device) -{ - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - FuQuirks *system_quirks = fu_device_get_quirks (FU_DEVICE (device)); - if (system_quirks != NULL && usb_device != NULL) { - const gchar *quirk_str; - quirk_str = fu_quirks_lookup_by_usb_device (system_quirks, - FU_QUIRKS_DFU, - usb_device); - if (quirk_str != NULL) - dfu_device_set_quirks_from_string (device, quirk_str); - } else { - g_warning ("no system quirk information"); - } -} - void dfu_device_set_usb_context (DfuDevice *device, GUsbContext *quirks) { @@ -1051,7 +994,8 @@ } /* the device has no DFU runtime, so cheat */ - if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) + if (priv->state == DFU_STATE_APP_IDLE && + priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) return TRUE; /* ensure interface is claimed */ @@ -1086,7 +1030,8 @@ } /* some devices use the wrong state value */ - if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_FORCE_DFU_MODE)) { + if (dfu_device_has_quirk (device, DFU_DEVICE_QUIRK_FORCE_DFU_MODE) && + dfu_device_get_state (device) != DFU_STATE_DFU_IDLE) { g_debug ("quirking device into DFU mode"); dfu_device_set_state (device, DFU_STATE_DFU_IDLE); } else { @@ -1139,10 +1084,8 @@ dfu_device_detach (DfuDevice *device, GError **error) { DfuDevicePrivate *priv = GET_PRIVATE (device); - FuQuirks *system_quirks = fu_device_get_quirks (FU_DEVICE (device)); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); const guint16 timeout_reset_ms = 1000; - const gchar *quirk_str; g_autoptr(GError) error_local = NULL; g_return_val_if_fail (DFU_IS_DEVICE (device), FALSE); @@ -1169,10 +1112,7 @@ } /* handle Jabra devices that need a magic HID packet */ - quirk_str = fu_quirks_lookup_by_usb_device (system_quirks, - FU_QUIRKS_DFU_JABRA_DETACH, - usb_device); - if (quirk_str != NULL) { + if (priv->jabra_detach != NULL) { guint8 adr = 0x00; guint8 rep = 0x00; guint8 iface_hid; @@ -1180,16 +1120,8 @@ g_autoptr(GError) error_jabra = NULL; /* parse string and create magic packet */ - if (strlen (quirk_str) != 4) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "unsupported jabra quirk format: '%s'", - quirk_str); - return FALSE; - } - rep = dfu_utils_buffer_parse_uint8 (quirk_str + 0); - adr = dfu_utils_buffer_parse_uint8 (quirk_str + 2); + rep = dfu_utils_buffer_parse_uint8 (priv->jabra_detach + 0); + adr = dfu_utils_buffer_parse_uint8 (priv->jabra_detach + 2); buf[0] = rep; buf[1] = adr; buf[2] = 0x00; @@ -1252,7 +1184,8 @@ } /* the device has no DFU runtime, so cheat */ - if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) + if (priv->state == DFU_STATE_APP_IDLE && + priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) return TRUE; /* ensure interface is claimed */ @@ -1301,6 +1234,7 @@ } /* success */ + priv->force_version = 0x0; fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); return TRUE; } @@ -1335,7 +1269,8 @@ } /* the device has no DFU runtime, so cheat */ - if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { + if (priv->state == DFU_STATE_APP_IDLE && + priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -1401,7 +1336,8 @@ } /* the device has no DFU runtime, so cheat */ - if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { + if (priv->state == DFU_STATE_APP_IDLE && + priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -1470,7 +1406,8 @@ g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* the device has no DFU runtime, so cheat */ - if (priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { + if (priv->state == DFU_STATE_APP_IDLE && + priv->quirks & DFU_DEVICE_QUIRK_NO_DFU_RUNTIME) { priv->state = DFU_STATE_APP_IDLE; priv->status = DFU_STATUS_OK; } @@ -1517,13 +1454,8 @@ dfu_device_probe (FuUsbDevice *device, GError **error) { DfuDevice *self = DFU_DEVICE (device); - DfuDevicePrivate *priv = GET_PRIVATE (self); GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - /* set the quirks for this new device */ - priv->quirks = DFU_DEVICE_QUIRK_NONE; - dfu_device_apply_quirks (self); - /* add all the targets */ if (!dfu_device_add_targets (self, error)) { g_prefix_error (error, "%04x:%04x is not supported: ", @@ -1568,7 +1500,7 @@ g_autoptr(GUsbDevice) usb_device2 = NULL; /* close */ - fu_usb_device_close (FU_USB_DEVICE (device), NULL); + fu_device_close (FU_DEVICE (device), NULL); /* watch the device disappear and re-appear */ usb_device2 = g_usb_context_wait_for_replug (priv->usb_context, @@ -1581,7 +1513,7 @@ /* re-open with new device set */ fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); fu_usb_device_set_dev (FU_USB_DEVICE (device), usb_device2); - if (!fu_usb_device_open (FU_USB_DEVICE (device), error)) + if (!fu_device_open (FU_DEVICE (device), error)) return FALSE; if (!dfu_device_refresh_and_clear (device, error)) return FALSE; @@ -1696,6 +1628,7 @@ } /* success */ + priv->force_version = 0x0; fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); return TRUE; } @@ -2093,6 +2026,50 @@ return g_string_free (str, FALSE); } +static gboolean +dfu_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + DfuDevice *self = DFU_DEVICE (device); + DfuDevicePrivate *priv = GET_PRIVATE (self); + + if (g_strcmp0 (key, FU_QUIRKS_DFU_FLAGS) == 0) { + dfu_device_set_quirks_from_string (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_DFU_JABRA_DETACH) == 0) { + if (value != NULL && strlen (value) == 4) { + priv->jabra_detach = g_strdup (value); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unsupported jabra quirk format"); + return FALSE; + } + if (g_strcmp0 (key, FU_QUIRKS_DFU_FORCE_VERSION) == 0) { + if (value != NULL && strlen (value) == 4) { + priv->force_version = dfu_utils_buffer_parse_uint16 (value); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid DFU version"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + /** * dfu_device_get_attributes_as_string: (skip) * @device: a #DfuDevice @@ -2124,3 +2101,75 @@ g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); } + +static void +dfu_device_finalize (GObject *object) +{ + DfuDevice *device = DFU_DEVICE (object); + DfuDevicePrivate *priv = GET_PRIVATE (device); + + if (priv->usb_context != NULL) + g_object_unref (priv->usb_context); + g_free (priv->chip_id); + g_free (priv->jabra_detach); + g_ptr_array_unref (priv->targets); + + G_OBJECT_CLASS (dfu_device_parent_class)->finalize (object); +} + +static void +dfu_device_class_init (DfuDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->set_quirk_kv = dfu_device_set_quirk_kv; + klass_usb_device->open = dfu_device_open; + klass_usb_device->close = dfu_device_close; + klass_usb_device->probe = dfu_device_probe; + + /** + * DfuDevice::status-changed: + * @device: the #DfuDevice instance that emitted the signal + * @status: the new #DfuStatus + * + * The ::status-changed signal is emitted when the status changes. + **/ + signals [SIGNAL_STATUS_CHANGED] = + g_signal_new ("status-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DfuDeviceClass, status_changed), + NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + + /** + * DfuDevice::state-changed: + * @device: the #DfuDevice instance that emitted the signal + * @state: the new #DfuState + * + * The ::state-changed signal is emitted when the state changes. + **/ + signals [SIGNAL_STATE_CHANGED] = + g_signal_new ("state-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (DfuDeviceClass, state_changed), + NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + + object_class->finalize = dfu_device_finalize; +} + +static void +dfu_device_init (DfuDevice *device) +{ + DfuDevicePrivate *priv = GET_PRIVATE (device); + priv->iface_number = 0xff; + priv->runtime_pid = 0xffff; + priv->runtime_vid = 0xffff; + priv->runtime_release = 0xffff; + priv->state = DFU_STATE_APP_IDLE; + priv->status = DFU_STATUS_OK; + priv->targets = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->timeout_ms = 1500; + priv->transfer_size = 64; +} diff -Nru fwupd-1.0.6/plugins/dfu/dfu-device.h fwupd-1.2.10/plugins/dfu/dfu-device.h --- fwupd-1.0.6/plugins/dfu/dfu-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_DEVICE_H -#define __DFU_DEVICE_H +#pragma once #include #include @@ -177,5 +161,3 @@ GUsbContext *dfu_device_get_usb_context (DfuDevice *device); G_END_DECLS - -#endif /* __DFU_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-device-private.h fwupd-1.2.10/plugins/dfu/dfu-device-private.h --- fwupd-1.0.6/plugins/dfu/dfu-device-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-device-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_DEVICE_PRIVATE_H -#define __DFU_DEVICE_PRIVATE_H +#pragma once #include #include @@ -41,5 +25,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_DEVICE_PRIVATE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-element.c fwupd-1.2.10/plugins/dfu/dfu-element.c --- fwupd-1.0.6/plugins/dfu/dfu-element.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-element.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** @@ -39,6 +24,8 @@ #include "dfu-common.h" #include "dfu-element.h" +#include "fwupd-error.h" + static void dfu_element_finalize (GObject *object); typedef struct { @@ -241,7 +228,7 @@ g_assert (buf != NULL); memcpy (buf, data, length); - /* set the pading value */ + /* set the padding value */ if (priv->padding_value != 0x00) { memset (buf + length, priv->padding_value, @@ -252,3 +239,60 @@ g_bytes_unref (priv->contents); priv->contents = g_bytes_new_take (buf, target_size); } + +/** + * dfu_element_get_contents_chunk: + * @element: a #DfuElement + * @address: an address greater than dfu_element_get_address() + * @chunk_sz_max: the size of the new chunk + * @error: a #GError, or %NULL + * + * Gets a block of data from the @element. If the contents of the element is + * smaller than the requested chunk size then the #GBytes will be smaller + * than @chunk_sz_max. Use dfu_utils_bytes_pad() if padding is required. + * + * If the @address is larger than the size of the @element then an error is returned. + * + * Return value: (transfer full): a #GBytes, or %NULL + **/ +GBytes * +dfu_element_get_contents_chunk (DfuElement *element, + guint32 address, + guint32 chunk_sz_max, + GError **error) +{ + GBytes *blob; + gsize chunk_left; + guint32 offset; + + /* check address requested is larger than base address */ + if (address < dfu_element_get_address (element)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "requested address 0x%x less than base address 0x%x", + (guint) address, (guint) dfu_element_get_address (element)); + return NULL; + } + + /* offset into data */ + offset = address - dfu_element_get_address (element); + blob = dfu_element_get_contents (element); + if (offset > g_bytes_get_size (blob)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "offset 0x%x larger than data size 0x%x", + (guint) offset, + (guint) g_bytes_get_size (blob)); + return NULL; + } + + /* if we have less data than requested */ + chunk_left = g_bytes_get_size (blob) - offset; + if (chunk_sz_max > chunk_left) + return g_bytes_new_from_bytes (blob, offset, chunk_left); + + /* check chunk */ + return g_bytes_new_from_bytes (blob, offset, chunk_sz_max); +} diff -Nru fwupd-1.0.6/plugins/dfu/dfu-element.h fwupd-1.2.10/plugins/dfu/dfu-element.h --- fwupd-1.0.6/plugins/dfu/dfu-element.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-element.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_ELEMENT_H -#define __DFU_ELEMENT_H +#pragma once #include #include @@ -39,6 +23,10 @@ GBytes *dfu_element_get_contents (DfuElement *element); guint32 dfu_element_get_address (DfuElement *element); +GBytes *dfu_element_get_contents_chunk (DfuElement *element, + guint32 address, + guint32 chunk_sz_max, + GError **error); void dfu_element_set_contents (DfuElement *element, GBytes *contents); @@ -52,5 +40,3 @@ gchar *dfu_element_to_string (DfuElement *element); G_END_DECLS - -#endif /* __DFU_ELEMENT_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-firmware.c fwupd-1.2.10/plugins/dfu/dfu-firmware.c --- fwupd-1.0.6/plugins/dfu/dfu-firmware.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-firmware.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2015-2018 Richard Hughes * - * Copyright (C) 2015 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** @@ -36,13 +21,15 @@ #include #include -#include + +#include "fu-common-version.h" #include "dfu-common.h" #include "dfu-firmware.h" #include "dfu-format-dfu.h" #include "dfu-format-ihex.h" #include "dfu-format-raw.h" +#include "dfu-format-srec.h" #include "dfu-image.h" #include "fwupd-error.h" @@ -385,6 +372,8 @@ if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) priv->format = dfu_firmware_detect_ihex (bytes); if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) + priv->format = dfu_firmware_detect_srec (bytes); + if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) priv->format = dfu_firmware_detect_dfu (bytes); if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) priv->format = dfu_firmware_detect_raw (bytes); @@ -395,6 +384,10 @@ if (!dfu_firmware_from_ihex (firmware, bytes, flags, error)) return FALSE; break; + case DFU_FIRMWARE_FORMAT_SREC: + if (!dfu_firmware_from_srec (firmware, bytes, flags, error)) + return FALSE; + break; case DFU_FIRMWARE_FORMAT_DFU: case DFU_FIRMWARE_FORMAT_DFUSE: if (!dfu_firmware_from_dfu (firmware, bytes, flags, error)) @@ -579,6 +572,10 @@ if (priv->format == DFU_FIRMWARE_FORMAT_INTEL_HEX) return dfu_firmware_to_ihex (firmware, error); + /* Motorola S-record */ + if (priv->format == DFU_FIRMWARE_FORMAT_SREC) + return dfu_firmware_to_srec (firmware, error); + /* invalid */ g_set_error (error, FWUPD_ERROR, @@ -627,18 +624,6 @@ error); } -static gchar * -_bcd_version_from_uint16 (guint16 val) -{ -#if AS_CHECK_VERSION(0,7,3) - return as_utils_version_from_uint16 (val, AS_VERSION_PARSE_FLAG_USE_BCD); -#else - guint maj = ((val >> 12) & 0x0f) * 10 + ((val >> 8) & 0x0f); - guint min = ((val >> 4) & 0x0f) * 10 + (val & 0x0f); - return g_strdup_printf ("%u.%u", maj, min); -#endif -} - /** * dfu_firmware_to_string: * @firmware: a #DfuFirmware @@ -658,7 +643,8 @@ g_return_val_if_fail (DFU_IS_FIRMWARE (firmware), NULL); - release_str = _bcd_version_from_uint16 (priv->release); + release_str = fu_common_version_from_uint16 (priv->release, + FWUPD_VERSION_FORMAT_BCD); str = g_string_new (""); g_string_append_printf (str, "vid: 0x%04x\n", priv->vid); g_string_append_printf (str, "pid: 0x%04x\n", priv->pid); @@ -711,6 +697,8 @@ return "dfuse"; if (format == DFU_FIRMWARE_FORMAT_INTEL_HEX) return "ihex"; + if (format == DFU_FIRMWARE_FORMAT_SREC) + return "srec"; return NULL; } @@ -733,6 +721,8 @@ return DFU_FIRMWARE_FORMAT_DFUSE; if (g_strcmp0 (format, "ihex") == 0) return DFU_FIRMWARE_FORMAT_INTEL_HEX; + if (g_strcmp0 (format, "srec") == 0) + return DFU_FIRMWARE_FORMAT_SREC; return DFU_FIRMWARE_FORMAT_UNKNOWN; } diff -Nru fwupd-1.0.6/plugins/dfu/dfu-firmware.h fwupd-1.2.10/plugins/dfu/dfu-firmware.h --- fwupd-1.0.6/plugins/dfu/dfu-firmware.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-firmware.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2015-2018 Richard Hughes * - * Copyright (C) 2015 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FIRMWARE_H -#define __DFU_FIRMWARE_H +#pragma once #include #include @@ -63,6 +47,7 @@ * @DFU_FIRMWARE_FORMAT_DFU: DFU footer * @DFU_FIRMWARE_FORMAT_DFUSE: DfuSe header * @DFU_FIRMWARE_FORMAT_INTEL_HEX: Intel HEX + * @DFU_FIRMWARE_FORMAT_SREC: Motorola S-record * * The known versions of the DFU standard in BCD format. **/ @@ -72,6 +57,7 @@ DFU_FIRMWARE_FORMAT_DFU, DFU_FIRMWARE_FORMAT_DFUSE, DFU_FIRMWARE_FORMAT_INTEL_HEX, + DFU_FIRMWARE_FORMAT_SREC, /*< private >*/ DFU_FIRMWARE_FORMAT_LAST } DfuFirmwareFormat; @@ -133,5 +119,3 @@ const gchar *key); G_END_DECLS - -#endif /* __DFU_FIRMWARE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-dfu.c fwupd-1.2.10/plugins/dfu/dfu-format-dfu.c --- fwupd-1.0.6/plugins/dfu/dfu-format-dfu.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-dfu.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-dfu.h fwupd-1.2.10/plugins/dfu/dfu-format-dfu.h --- fwupd-1.0.6/plugins/dfu/dfu-format-dfu.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-dfu.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_DFU_H -#define __DFU_FORMAT_DFU_H +#pragma once #include #include @@ -38,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_DFU_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-dfuse.c fwupd-1.2.10/plugins/dfu/dfu-format-dfuse.c --- fwupd-1.0.6/plugins/dfu/dfu-format-dfuse.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-dfuse.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-dfuse.h fwupd-1.2.10/plugins/dfu/dfu-format-dfuse.h --- fwupd-1.0.6/plugins/dfu/dfu-format-dfuse.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-dfuse.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_DFUSE_H -#define __DFU_FORMAT_DFUSE_H +#pragma once #include #include @@ -38,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_DFUSE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-ihex.c fwupd-1.2.10/plugins/dfu/dfu-format-ihex.c --- fwupd-1.0.6/plugins/dfu/dfu-format-ihex.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-ihex.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -48,19 +33,47 @@ data = (guint8 *) g_bytes_get_data (bytes, &len); if (len < 12) return DFU_FIRMWARE_FORMAT_UNKNOWN; - if (data[0] != ':') - return DFU_FIRMWARE_FORMAT_UNKNOWN; - return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* match the first char */ + if (data[0] == ':') + return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* look for the EOF line */ + if (g_strstr_len ((const gchar *) data, (gssize) len, ":000000") != NULL) + return DFU_FIRMWARE_FORMAT_INTEL_HEX; + + /* failed */ + return DFU_FIRMWARE_FORMAT_UNKNOWN; } #define DFU_INHX32_RECORD_TYPE_DATA 0x00 #define DFU_INHX32_RECORD_TYPE_EOF 0x01 #define DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT 0x02 #define DFU_INHX32_RECORD_TYPE_START_SEGMENT 0x03 -#define DFU_INHX32_RECORD_TYPE_EXTENDED 0x04 -#define DFU_INHX32_RECORD_TYPE_ADDR32 0x05 +#define DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR 0x04 +#define DFU_INHX32_RECORD_TYPE_START_LINEAR 0x05 #define DFU_INHX32_RECORD_TYPE_SIGNATURE 0xfd +static const gchar * +dfu_firmware_ihex_record_type_to_string (guint8 record_type) +{ + if (record_type == DFU_INHX32_RECORD_TYPE_DATA) + return "DATA"; + if (record_type == DFU_INHX32_RECORD_TYPE_EOF) + return "EOF"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT) + return "EXTENDED_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_SEGMENT) + return "START_SEGMENT"; + if (record_type == DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR) + return "EXTENDED_LINEAR"; + if (record_type == DFU_INHX32_RECORD_TYPE_START_LINEAR) + return "ADDR32"; + if (record_type == DFU_INHX32_RECORD_TYPE_SIGNATURE) + return "SIGNATURE"; + return NULL; +} + /** * dfu_firmware_from_ihex: (skip) * @firmware: a #DfuFirmware @@ -78,25 +91,19 @@ DfuFirmwareParseFlags flags, GError **error) { - const gchar *in_buffer; + const gchar *data; gboolean got_eof = FALSE; - gsize len_in; - guint16 addr_high = 0; - guint16 addr_low = 0; - guint32 addr32 = 0; - guint32 addr32_last = 0; - guint32 element_address = 0; - guint8 checksum; - guint8 data_tmp; - guint8 len_tmp; - guint8 type; - guint end; - guint offset = 0; + gsize sz = 0; + guint32 abs_addr = 0x0; + guint32 addr_last = 0x0; + guint32 base_addr = G_MAXUINT32; + guint32 seg_addr = 0x0; + g_auto(GStrv) lines = NULL; g_autoptr(DfuElement) element = NULL; g_autoptr(DfuImage) image = NULL; g_autoptr(GBytes) contents = NULL; - g_autoptr(GString) string = NULL; - g_autoptr(GString) signature = g_string_new (NULL); + g_autoptr(GString) buf = g_string_new (NULL); + g_autoptr(GString) buf_signature = g_string_new (NULL); g_return_val_if_fail (bytes != NULL, FALSE); @@ -106,107 +113,130 @@ element = dfu_element_new (); /* parse records */ - in_buffer = g_bytes_get_data (bytes, &len_in); - string = g_string_new (""); - while (offset < len_in) { + data = g_bytes_get_data (bytes, &sz); + lines = dfu_utils_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; + guint32 addr; + guint8 byte_cnt; + guint8 record_type; + guint line_end; + + /* ignore comments */ + if (g_str_has_prefix (line, ";")) + continue; + + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r\x1a", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; /* check starting token */ - if (in_buffer[offset] != ':') { + if (line[0] != ':') { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid starting token, got %c at %x", - in_buffer[offset], offset); + "invalid starting token on line %u: %s", + ln + 1, line); return FALSE; } /* check there's enough data for the smallest possible record */ - if (offset + 12 > (guint) len_in) { + if (linesz < 11) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "record incomplete at %u, length %u", - offset, (guint) len_in); + "line %u is incomplete, length %u", + ln + 1, (guint) linesz); return FALSE; } /* length, 16-bit address, type */ - len_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 1); - addr_low = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 3); - type = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 7); + byte_cnt = dfu_utils_buffer_parse_uint8 (line + 1); + addr = dfu_utils_buffer_parse_uint16 (line + 3); + record_type = dfu_utils_buffer_parse_uint8 (line + 7); + g_debug ("%s:", dfu_firmware_ihex_record_type_to_string (record_type)); + g_debug (" addr_start:\t0x%04x", addr); + g_debug (" length:\t0x%02x", byte_cnt); + addr += seg_addr; + addr += abs_addr; + g_debug (" addr:\t0x%08x", addr); /* position of checksum */ - end = offset + 9 + len_tmp * 2; - if (end > (guint) len_in) { + line_end = 9 + byte_cnt * 2; + if (line_end > (guint) linesz) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "checksum > file length: %u", - end); + "line %u malformed, length: %u", + ln + 1, line_end); return FALSE; } /* verify checksum */ if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { - checksum = 0; - for (guint i = offset + 1; i < end + 2; i += 2) { - data_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + i); + guint8 checksum = 0; + for (guint i = 1; i < line_end + 2; i += 2) { + guint8 data_tmp = dfu_utils_buffer_parse_uint8 (line + i); checksum += data_tmp; } if (checksum != 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "invalid record checksum at 0x%04x " - "to 0x%04x, got 0x%02x", - offset, end, checksum); + "line %u has invalid checksum (0x%02x)", + ln + 1, checksum); return FALSE; } } /* process different record types */ - switch (type) { + switch (record_type) { case DFU_INHX32_RECORD_TYPE_DATA: - /* if not contiguous with previous record */ - if ((addr_high + addr_low) != addr32) { - if (addr32 == 0x0) { - g_debug ("base address %08x", addr_low); - dfu_element_set_address (element, addr_low); - } - addr32 = ((guint32) addr_high << 16) + addr_low; - if (element_address == 0x0) - element_address = addr32; - } + /* base address for element */ + if (base_addr == G_MAXUINT32) + base_addr = addr; /* does not make sense */ - if (addr32 < addr32_last) { + if (addr < addr_last) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid address 0x%x, last was 0x%x", - (guint) addr32, - (guint) addr32_last); + (guint) addr, + (guint) addr_last); return FALSE; } /* parse bytes from line */ - g_debug ("writing data 0x%08x", (guint32) addr32); - for (guint i = offset + 9; i < end; i += 2) { + g_debug ("writing data 0x%08x", (guint32) addr); + for (guint i = 9; i < line_end; i += 2) { /* any holes in the hex record */ - guint32 len_hole = addr32 - addr32_last; - if (addr32_last > 0x0 && len_hole > 1) { + guint32 len_hole = addr - addr_last; + guint8 data_tmp; + if (addr_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill", + (guint) len_hole); + return FALSE; + } + if (addr_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr_last + 1, addr_last + len_hole - 1); for (guint j = 1; j < len_hole; j++) { - g_debug ("filling address 0x%08x", - addr32_last + j); /* although 0xff might be clearer, * we can't write 0xffff to pic14 */ - g_string_append_c (string, 0x00); + g_string_append_c (buf, 0x00); } } /* write into buf */ - data_tmp = dfu_utils_buffer_parse_uint8 (in_buffer + i); - g_string_append_c (string, (gchar) data_tmp); - addr32_last = addr32++; + data_tmp = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (buf, (gchar) data_tmp); + addr_last = addr++; } break; case DFU_INHX32_RECORD_TYPE_EOF: @@ -220,25 +250,28 @@ } got_eof = TRUE; break; - case DFU_INHX32_RECORD_TYPE_EXTENDED: - addr_high = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 9); - addr32 = ((guint32) addr_high << 16) + addr_low; + case DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR: + abs_addr = dfu_utils_buffer_parse_uint16 (line + 9) << 16; + g_debug (" abs_addr:\t0x%02x", abs_addr); break; - case DFU_INHX32_RECORD_TYPE_ADDR32: - addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 9); + case DFU_INHX32_RECORD_TYPE_START_LINEAR: + abs_addr = dfu_utils_buffer_parse_uint32 (line + 9); + g_debug (" abs_addr:\t0x%08x", abs_addr); break; case DFU_INHX32_RECORD_TYPE_EXTENDED_SEGMENT: /* segment base address, so ~1Mb addressable */ - addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 9) * 16; + seg_addr = dfu_utils_buffer_parse_uint16 (line + 9) * 16; + g_debug (" seg_addr:\t0x%08x", seg_addr); break; case DFU_INHX32_RECORD_TYPE_START_SEGMENT: /* initial content of the CS:IP registers */ - addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 9); + seg_addr = dfu_utils_buffer_parse_uint32 (line + 9); + g_debug (" seg_addr:\t0x%02x", seg_addr); break; case DFU_INHX32_RECORD_TYPE_SIGNATURE: - for (guint i = offset + 9; i < end; i += 2) { - guint8 tmp_c = dfu_utils_buffer_parse_uint8 (in_buffer + i); - g_string_append_c (signature, tmp_c); + for (guint i = 9; i < line_end; i += 2) { + guint8 tmp_c = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (buf_signature, tmp_c); } break; default: @@ -249,17 +282,9 @@ FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "invalid ihex record type %i", - type); + record_type); return FALSE; } - - /* ignore any line return */ - offset = end + 2; - for (; offset < len_in; offset++) { - if (in_buffer[offset] != '\n' && - in_buffer[offset] != '\r') - break; - } } /* no EOF */ @@ -272,19 +297,20 @@ } /* add single image */ - contents = g_bytes_new (string->str, string->len); + contents = g_bytes_new (buf->str, buf->len); dfu_element_set_contents (element, contents); - dfu_element_set_address (element, element_address); + if (base_addr != G_MAXUINT32) + dfu_element_set_address (element, base_addr); dfu_image_add_element (image, element); dfu_firmware_add_image (firmware, image); dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_INTEL_HEX); /* add optional signature */ - if (signature->len > 0) { + if (buf_signature->len > 0) { g_autoptr(DfuElement) element_sig = dfu_element_new (); g_autoptr(DfuImage) image_sig = dfu_image_new (); - g_autoptr(GBytes) data = g_bytes_new_static (signature->str, signature->len); - dfu_element_set_contents (element_sig, data); + g_autoptr(GBytes) data_sig = g_bytes_new_static (buf_signature->str, buf_signature->len); + dfu_element_set_contents (element_sig, data_sig); dfu_image_add_element (image_sig, element_sig); dfu_image_set_name (image_sig, "signature"); dfu_firmware_add_image (firmware, image_sig); @@ -336,7 +362,7 @@ guint8 buf[2]; fu_common_write_uint16 (buf, address_offset, G_BIG_ENDIAN); dfu_firmware_ihex_emit_chunk (str, 0x0, - DFU_INHX32_RECORD_TYPE_EXTENDED, + DFU_INHX32_RECORD_TYPE_EXTENDED_LINEAR, buf, 2); address_offset_last = address_offset; } diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-ihex.h fwupd-1.2.10/plugins/dfu/dfu-format-ihex.h --- fwupd-1.0.6/plugins/dfu/dfu-format-ihex.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-ihex.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_IHEX_H -#define __DFU_FORMAT_IHEX_H +#pragma once #include #include @@ -38,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_IHEX_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-metadata.c fwupd-1.2.10/plugins/dfu/dfu-format-metadata.c --- fwupd-1.0.6/plugins/dfu/dfu-format-metadata.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-metadata.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -176,7 +161,7 @@ g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "metdata key too long: %s", + "metadata key too long: %s", key); return NULL; } diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-metadata.h fwupd-1.2.10/plugins/dfu/dfu-format-metadata.h --- fwupd-1.0.6/plugins/dfu/dfu-format-metadata.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-metadata.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_METADATA_H -#define __DFU_FORMAT_METADATA_H +#pragma once #include #include @@ -37,5 +21,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_METADATA_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-raw.c fwupd-1.2.10/plugins/dfu/dfu-format-raw.c --- fwupd-1.0.6/plugins/dfu/dfu-format-raw.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-raw.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-raw.h fwupd-1.2.10/plugins/dfu/dfu-format-raw.h --- fwupd-1.0.6/plugins/dfu/dfu-format-raw.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-raw.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_FORMAT_RAW_H -#define __DFU_FORMAT_RAW_H +#pragma once #include #include @@ -38,5 +22,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_FORMAT_RAW_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-srec.c fwupd-1.2.10/plugins/dfu/dfu-format-srec.c --- fwupd-1.0.6/plugins/dfu/dfu-format-srec.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-srec.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2015-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "dfu-element.h" +#include "dfu-firmware.h" +#include "dfu-format-srec.h" +#include "dfu-image.h" + +#include "fwupd-error.h" + +/** + * dfu_firmware_detect_srec: (skip) + * @bytes: data to parse + * + * Attempts to sniff the data and work out the firmware format + * + * Returns: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_RAW + **/ +DfuFirmwareFormat +dfu_firmware_detect_srec (GBytes *bytes) +{ + guint8 *data; + gsize len; + data = (guint8 *) g_bytes_get_data (bytes, &len); + if (len < 12) + return DFU_FIRMWARE_FORMAT_UNKNOWN; + if (memcmp (data, "S0", 2) != 0) + return DFU_FIRMWARE_FORMAT_UNKNOWN; + return DFU_FIRMWARE_FORMAT_SREC; +} + +/** + * dfu_firmware_from_srec: (skip) + * @firmware: a #DfuFirmware + * @bytes: data to parse + * @flags: some #DfuFirmwareParseFlags + * @error: a #GError, or %NULL + * + * Unpacks into a firmware object from raw data. + * + * Returns: %TRUE for success + **/ +gboolean +dfu_image_from_srec (DfuImage *image, + GBytes *bytes, + guint32 start_addr, + DfuFirmwareParseFlags flags, + GError **error) +{ + const gchar *data; + gboolean got_eof = FALSE; + gboolean got_hdr = FALSE; + gsize sz = 0; + guint16 data_cnt = 0; + guint32 addr32_last = 0; + guint32 element_address = 0; + g_auto(GStrv) lines = NULL; + g_autoptr(DfuElement) element = dfu_element_new (); + g_autoptr(GBytes) contents = NULL; + g_autoptr(GString) outbuf = g_string_new (NULL); + + g_return_val_if_fail (bytes != NULL, FALSE); + + /* parse records */ + data = g_bytes_get_data (bytes, &sz); + lines = dfu_utils_strnsplit (data, sz, "\n", -1); + for (guint ln = 0; lines[ln] != NULL; ln++) { + const gchar *line = lines[ln]; + gsize linesz; + guint32 rec_addr32; + guint8 addrsz = 0; /* bytes */ + guint8 rec_count; /* words */ + guint8 rec_kind; + + /* ignore blank lines */ + g_strdelimit (lines[ln], "\r", '\0'); + linesz = strlen (line); + if (linesz == 0) + continue; + + /* check starting token */ + if (line[0] != 'S') { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid starting token, got '%c' at line %u", + line[0], ln); + return FALSE; + } + + /* check there's enough data for the smallest possible record */ + if (linesz < 10) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "record incomplete at line %u, length %u", + ln, (guint) linesz); + return FALSE; + } + + /* kind, count, address, (data), checksum, linefeed */ + rec_kind = line[1] - '0'; + rec_count = dfu_utils_buffer_parse_uint8 (line + 2); + if (rec_count * 2 != linesz - 4) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "count incomplete at line %u, " + "length %u, expected %u", + ln, (guint) linesz - 4, (guint) rec_count * 2); + return FALSE; + } + + /* checksum check */ + if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { + guint8 rec_csum = 0; + guint8 rec_csum_expected; + for (guint8 i = 0; i < rec_count; i++) + rec_csum += dfu_utils_buffer_parse_uint8 (line + (i * 2) + 2); + rec_csum ^= 0xff; + rec_csum_expected = dfu_utils_buffer_parse_uint8 (line + (rec_count * 2) + 2); + if (rec_csum != rec_csum_expected) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "checksum incorrect line %u, " + "expected %02x, got %02x", + ln, rec_csum_expected, rec_csum); + return FALSE; + } + } + + /* set each command settings */ + switch (rec_kind) { + case 0: + addrsz = 2; + if (got_hdr) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "duplicate header record"); + return FALSE; + } + got_hdr = TRUE; + break; + case 1: + addrsz = 2; + break; + case 2: + addrsz = 3; + break; + case 3: + addrsz = 4; + break; + case 5: + addrsz = 2; + got_eof = TRUE; + break; + case 6: + addrsz = 3; + break; + case 7: + addrsz = 4; + got_eof = TRUE; + break; + case 8: + addrsz = 3; + got_eof = TRUE; + break; + case 9: + addrsz = 2; + got_eof = TRUE; + break; + default: + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid srec record type S%c", + line[1]); + return FALSE; + } + + /* parse address */ + switch (addrsz) { + case 2: + rec_addr32 = dfu_utils_buffer_parse_uint16 (line + 4); + break; + case 3: + rec_addr32 = dfu_utils_buffer_parse_uint24 (line + 4); + break; + case 4: + rec_addr32 = dfu_utils_buffer_parse_uint32 (line + 4); + break; + default: + g_assert_not_reached (); + } + + /* header */ + if (rec_kind == 0) { + g_autoptr(GString) modname = g_string_new (NULL); + if (rec_addr32 != 0x0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid header record address, got %04x", + rec_addr32); + return FALSE; + } + + /* could be anything, lets assume text */ + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); + if (!g_ascii_isgraph (tmp)) + break; + g_string_append_c (modname, tmp); + } + if (modname->len != 0) + dfu_image_set_name (image, modname->str); + continue; + } + + /* verify we got all records */ + if (rec_kind == 5) { + if (rec_addr32 != data_cnt) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "count record was not valid, got 0x%02x expected 0x%02x", + (guint) rec_addr32, (guint) data_cnt); + return FALSE; + } + } + + /* data */ + if (rec_kind == 1 || rec_kind == 2 || rec_kind == 3) { + /* invalid */ + if (!got_hdr) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "missing header record"); + return FALSE; + } + /* does not make sense */ + if (rec_addr32 < addr32_last) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid address 0x%x, last was 0x%x", + (guint) rec_addr32, + (guint) addr32_last); + return FALSE; + } + if (rec_addr32 < start_addr) { + g_debug ("ignoring data at 0x%x as before start address 0x%x", + (guint) rec_addr32, (guint) start_addr); + } else { + guint bytecnt = 0; + guint32 len_hole = rec_addr32 - addr32_last; + + /* fill any holes, but only up to 1Mb to avoid a DoS */ + if (addr32_last > 0 && len_hole > 0x100000) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "hole of 0x%x bytes too large to fill", + (guint) len_hole); + return FALSE; + } + if (addr32_last > 0x0 && len_hole > 1) { + g_debug ("filling address 0x%08x to 0x%08x", + addr32_last + 1, addr32_last + len_hole - 1); + for (guint j = 0; j < len_hole; j++) + g_string_append_c (outbuf, 0xff); + } + + /* add data */ + for (guint8 i = 4 + (addrsz * 2); i <= rec_count * 2; i += 2) { + guint8 tmp = dfu_utils_buffer_parse_uint8 (line + i); + g_string_append_c (outbuf, tmp); + bytecnt++; + } + if (element_address == 0x0) + element_address = rec_addr32; + addr32_last = rec_addr32 + bytecnt; + } + data_cnt++; + } + } + + /* no EOF */ + if (!got_eof) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no EOF, perhaps truncated file"); + return FALSE; + } + + /* add single image */ + contents = g_bytes_new (outbuf->str, outbuf->len); + dfu_element_set_contents (element, contents); + dfu_element_set_address (element, element_address); + dfu_image_add_element (image, element); + return TRUE; +} + +/** + * dfu_firmware_from_srec: (skip) + * @firmware: a #DfuFirmware + * @bytes: data to parse + * @flags: some #DfuFirmwareParseFlags + * @error: a #GError, or %NULL + * + * Unpacks into a firmware object from raw data. + * + * Returns: %TRUE for success + **/ +gboolean +dfu_firmware_from_srec (DfuFirmware *firmware, + GBytes *bytes, + DfuFirmwareParseFlags flags, + GError **error) +{ + g_autoptr(DfuImage) image = NULL; + + g_return_val_if_fail (bytes != NULL, FALSE); + + /* add single image */ + image = dfu_image_new (); + if (!dfu_image_from_srec (image, bytes, 0x0, flags, error)) + return FALSE; + dfu_firmware_add_image (firmware, image); + dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC); + return TRUE; +} + +/** + * dfu_firmware_to_srec: (skip) + * @firmware: a #DfuFirmware + * @error: a #GError, or %NULL + * + * Exports a Motorola S-record file + * + * Returns: (transfer full): the packed data + **/ +GBytes * +dfu_firmware_to_srec (DfuFirmware *firmware, GError **error) +{ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Motorola S-record export functionality missing"); + return NULL; +} diff -Nru fwupd-1.0.6/plugins/dfu/dfu-format-srec.h fwupd-1.2.10/plugins/dfu/dfu-format-srec.h --- fwupd-1.0.6/plugins/dfu/dfu-format-srec.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-format-srec.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "dfu-firmware.h" + +G_BEGIN_DECLS + +DfuFirmwareFormat dfu_firmware_detect_srec (GBytes *bytes); +GBytes *dfu_firmware_to_srec (DfuFirmware *firmware, + GError **error); +gboolean dfu_firmware_from_srec (DfuFirmware *firmware, + GBytes *bytes, + DfuFirmwareParseFlags flags, + GError **error); +gboolean dfu_image_from_srec (DfuImage *image, + GBytes *bytes, + guint32 start_addr, + DfuFirmwareParseFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/dfu/dfu-image.c fwupd-1.2.10/plugins/dfu/dfu-image.c --- fwupd-1.0.6/plugins/dfu/dfu-image.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-image.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** diff -Nru fwupd-1.0.6/plugins/dfu/dfu-image.h fwupd-1.2.10/plugins/dfu/dfu-image.h --- fwupd-1.0.6/plugins/dfu/dfu-image.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-image.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_IMAGE_H -#define __DFU_IMAGE_H +#pragma once #include #include @@ -58,5 +42,3 @@ gchar *dfu_image_to_string (DfuImage *image); G_END_DECLS - -#endif /* __DFU_IMAGE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-patch.c fwupd-1.2.10/plugins/dfu/dfu-patch.c --- fwupd-1.0.6/plugins/dfu/dfu-patch.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-patch.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** @@ -521,7 +506,7 @@ } data_new = g_malloc0 (sz_max); - memcpy (data_new, data_old, sz_max); + memcpy (data_new, data_old, MIN (sz, sz_max)); for (guint i = 0; i < priv->chunks->len; i++) { DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i); const guint8 *chunk_data; diff -Nru fwupd-1.0.6/plugins/dfu/dfu-patch.h fwupd-1.2.10/plugins/dfu/dfu-patch.h --- fwupd-1.0.6/plugins/dfu/dfu-patch.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-patch.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_PATCH_H -#define __DFU_PATCH_H +#pragma once #include #include @@ -69,5 +53,3 @@ GBytes *dfu_patch_get_checksum_new (DfuPatch *self); G_END_DECLS - -#endif /* __DFU_PATCH_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu.quirk fwupd-1.2.10/plugins/dfu/dfu.quirk --- fwupd-1.0.6/plugins/dfu/dfu.quirk 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -1,235 +1,342 @@ -[fwupd-dfu] +# All DFU devices +[DeviceInstanceId=USB\CLASS_FE&SUBCLASS_01] +Plugin = dfu # on PC platforms the DW1820A firmware is loaded at runtime and can't # be stored on the device itself as the flash chip is unpopulated -USB\VID_0A5C&PID_6412=ignore-runtime +[DeviceInstanceId=USB\VID_0A5C&PID_6412] +Plugin = dfu +DfuFlags = ignore-runtime # Openmoko Freerunner / GTA02 -USB\VID_1D50&PID_5119=ignore-polltimeout|no-pid-change|no-dfu-runtime|action-required|no-get-status-upload +[DeviceInstanceId=USB\VID_1D50&PID_5119] +Plugin = dfu +DfuFlags = ignore-polltimeout,no-pid-change,no-dfu-runtime,action-required,no-get-status-upload # OpenPCD Reader -USB\VID_16C0&PID_076B=ignore-polltimeout +[DeviceInstanceId=USB\VID_16C0&PID_076B] +Plugin = dfu +DfuFlags = ignore-polltimeout # SIMtrace -USB\VID_16C0&PID_0762=ignore-polltimeout +[DeviceInstanceId=USB\VID_16C0&PID_0762] +Plugin = dfu +DfuFlags = ignore-polltimeout # OpenPICC -USB\VID_16C0&PID_076C=ignore-polltimeout +[DeviceInstanceId=USB\VID_16C0&PID_076C] +Plugin = dfu +DfuFlags = ignore-polltimeout # Siemens AG, PXM 40 & PXM 50 -USB\VID_0908&PID_02C4&REV_0000=ignore-polltimeout -USB\VID_0908&PID_02C5&REV_0000=ignore-polltimeout +[DeviceInstanceId=USB\VID_0908&PID_02C4] +Plugin = dfu +[DeviceInstanceId=USB\VID_0908&PID_02C5] +Plugin = dfu +[DeviceInstanceId=USB\VID_0908&PID_02C4&REV_0000] +DfuFlags = ignore-polltimeout +[DeviceInstanceId=USB\VID_0908&PID_02C5&REV_0000] +DfuFlags = ignore-polltimeout # Midiman M-Audio Transit -USB\VID_0763&PID_2806=ignore-polltimeout +[DeviceInstanceId=USB\VID_0763&PID_2806] +Plugin = dfu +DfuFlags = ignore-polltimeout # LPC DFU bootloader -USB\VID_1FC9&PID_000C=force-dfu-mode +[DeviceInstanceId=USB\VID_1FC9&PID_000C] +Plugin = dfu +DfuFlags = force-dfu-mode # m-stack DFU -USB\VID_273F&PID_1003=attach-upload-download -USB\VID_273F&PID_100A=attach-upload-download +[DeviceInstanceId=USB\VID_273F&PID_1003] +DfuFlags = attach-upload-download +[DeviceInstanceId=USB\VID_273F&PID_100A] +DfuFlags = attach-upload-download # HydraBus -USB\VID_1D50&PID_60A7=no-dfu-runtime|action-required - -# Jabra 410, 510, 710 and 810 -USB\VID_0B0E&PID_0412=no-dfu-runtime -USB\VID_0B0E&PID_0420=no-dfu-runtime -USB\VID_0B0E&PID_2475=no-dfu-runtime -USB\VID_0B0E&PID_2456=no-dfu-runtime - -# Jabra 410, 510, 710 and 810 (DFU mode) -USB\VID_0B0E&PID_0411=no-pid-change|force-dfu-mode|ignore-upload|attach-extra-reset -USB\VID_0B0E&PID_0421=no-pid-change|force-dfu-mode|ignore-upload|attach-extra-reset -USB\VID_0B0E&PID_0982=no-pid-change|force-dfu-mode|ignore-upload|attach-extra-reset -USB\VID_0B0E&PID_0971=no-pid-change|force-dfu-mode|ignore-upload|attach-extra-reset +[DeviceInstanceId=USB\VID_1D50&PID_60A7] +Plugin = dfu +DfuFlags = no-dfu-runtime,action-required + +# Jabra 410 +[DeviceInstanceId=USB\VID_0B0E&PID_0412] +Plugin = dfu +DfuFlags = no-dfu-runtime +DfuJabraDetach = 0201 +CounterpartGuid = USB\VID_0B0E&PID_0411 + +# Jabra 510 +[DeviceInstanceId=USB\VID_0B0E&PID_0420] +Plugin = dfu +DfuFlags = no-dfu-runtime +DfuJabraDetach = 0201 +CounterpartGuid = USB\VID_0B0E&PID_0421 + +# Jabra 710 +[DeviceInstanceId=USB\VID_0B0E&PID_2475] +Plugin = dfu +DfuFlags = no-dfu-runtime +DfuJabraDetach = 0508 +CounterpartGuid = USB\VID_0B0E&PID_0982 + +# Jabra 810 +[DeviceInstanceId=USB\VID_0B0E&PID_2456] +Plugin = dfu +DfuFlags = no-dfu-runtime +DfuJabraDetach = 0508 +CounterpartGuid = USB\VID_0B0E&PID_0971 + +[DeviceInstanceId=USB\VID_0B0E&PID_0411] +Plugin = dfu +DfuFlags = no-pid-change,force-dfu-mode,ignore-upload,attach-extra-reset + +[DeviceInstanceId=USB\VID_0B0E&PID_0421] +Plugin = dfu +DfuFlags = no-pid-change,force-dfu-mode,ignore-upload,attach-extra-reset + +[DeviceInstanceId=USB\VID_0B0E&PID_0982] +Plugin = dfu +DfuFlags = no-pid-change,force-dfu-mode,ignore-upload,attach-extra-reset + +[DeviceInstanceId=USB\VID_0B0E&PID_0971] +Plugin = dfu +DfuFlags = no-pid-change,force-dfu-mode,ignore-upload,attach-extra-reset # Atmel AT90USB Bootloader -USB\VID_03EB&PID_2FF7=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FF9=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FFA=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FFB=use-any-interface|legacy-protocol|force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FF7] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FF9] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FFA] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FFB] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode # Atmel ATMEGA Bootloader -USB\VID_03EB&PID_2FEE=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FEF=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FF0=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FF2=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FF3=use-any-interface|legacy-protocol|force-dfu-mode -USB\VID_03EB&PID_2FF4=use-any-interface|legacy-protocol|force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FEE] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FEF] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FF0] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FF2] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FF3] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode +[DeviceInstanceId=USB\VID_03EB&PID_2FF4] +Plugin = dfu +DfuFlags = use-any-interface,legacy-protocol,force-dfu-mode # Atmel XMEGA Bootloader -USB\VID_03EB&PID_2FE2=use-any-interface|force-dfu-mode - -[fwupd-dfu-force-version] +[DeviceInstanceId=USB\VID_03EB&PID_2FE2] +Plugin = dfu +DfuFlags = use-any-interface,force-dfu-mode # Leaflabs Maple3 -USB\VID_1EAF&PID_0003&REV_0200=0110 +[DeviceInstanceId=USB\VID_1EAF&PID_0003&REV_0200] +Plugin = dfu +DfuForceVersion = 0110 # Atmel FLIP Bootloader -USB\VID_03EB=ff01 - -[fwupd-dfu-jabra-detach] - -# Jabra 410 and 510 -USB\VID_0B0E&PID_0412=0201 -USB\VID_0B0E&PID_0420=0201 - -# Jabra 710 and 810 -USB\VID_0B0E&PID_2475=0508 -USB\VID_0B0E&PID_2456=0508 - -[FuUsbDevice:guid] - -# Jabra 410, 510, 710 and 810 -USB\VID_0B0E&PID_0412=USB\VID_0B0E&PID_0411 -USB\VID_0B0E&PID_0420=USB\VID_0B0E&PID_0421 -USB\VID_0B0E&PID_2475=USB\VID_0B0E&PID_0982 -USB\VID_0B0E&PID_2456=USB\VID_0B0E&PID_0971 - -[fwupd-dfu-avr-chip-id] +[DeviceInstanceId=USB\VID_03EB] +Plugin = dfu +DfuForceVersion = ff01 # AT32UC3B1256 [BLDR][USER] USER@0x2000, BLDR+USER=0x40000 -0x58200203=@Flash/0x2000/1*248Kg +[AvrChipId=0x58200203] +DfuAltName = @Flash/0x2000/1*248Kg # AT32UC3A3256 [BLDR][USER] USER@0x2000, BLDR+USER=0x40000 -0x58200204=@Flash/0x2000/1*248Kg +[AvrChipId=0x58200204] +DfuAltName = @Flash/0x2000/1*248Kg # AT90USB1287 [USER][BLDR] BLDR@0x1e000, BLDR+USER=0x20000 -0x581e9782=@Flash/0x0/1*120Kg +[AvrChipId=0x581e9782] +DfuAltName = @Flash/0x0/1*120Kg # AT90USB647 [USER][BLDR] BLDR@0x0e000, BLDR+USER=0x10000 -0x581e9682=@Flash/0x0/1*56Kg - # AT90USB646 [USER][BLDR] BLDR@0x0e000, BLDR+USER=0x10000 -0x581e9682=@Flash/0x0/1*56Kg +[AvrChipId=0x581e9682] +DfuAltName = @Flash/0x0/1*56Kg # ATmega32U4 [USER][BLDR] BLDR@0x07000, BLDR+USER=0x08000 -0x581e9587=@Flash/0x0/1*28Kg +[AvrChipId=0x581e9587] +DfuAltName = @Flash/0x0/1*28Kg # ATmega16U4 [USER][BLDR] BLDR@0x03000, BLDR+USER=0x04000 -0x581e9488=@Flash/0x0/1*12Kg +[AvrChipId=0x581e9488] +DfuAltName = @Flash/0x0/1*12Kg # ATmega32U2 [USER][BLDR] BLDR@0x07000, BLDR+USER=0x08000 -0x581e958a=@Flash/0x0/1*28Kg +[AvrChipId=0x581e958a] +DfuAltName = @Flash/0x0/1*28Kg # ATmega16U2 [USER][BLDR] BLDR@0x03000, BLDR+USER=0x04000 -0x581e9489=@Flash/0x0/1*12Kg +[AvrChipId=0x581e9489] +DfuAltName = @Flash/0x0/1*12Kg # AT90USB162 [USER][BLDR] BLDR@0x03000, BLDR+USER=0x04000 -0x581e9482=@Flash/0x0/1*12Kg +[AvrChipId=0x581e9482] +DfuAltName = @Flash/0x0/1*12Kg # ATmega8U2 [USER][BLDR] BLDR@0x01000, BLDR+USER=0x02000 -0x581e9389=@Flash/0x0/1*4Kg +[AvrChipId=0x581e9389] +DfuAltName = @Flash/0x0/1*4Kg # AT90USB82 [USER][BLDR] BLDR@0x01000, BLDR+USER=0x02000 -0x581e9382=@Flash/0x0/1*4Kg +[AvrChipId=0x581e9382] +DfuAltName = @Flash/0x0/1*4Kg # ATxmega16A4 [USER] USER=0x4000 -0x1e9441=@Flash/0x0/1*16Kg +[AvrChipId=0x1e9441] +DfuAltName = @Flash/0x0/1*16Kg # ATxmega16C4 [USER] USER=0x4000 -0x1e9544=@Flash/0x0/1*16Kg +[AvrChipId=0x1e9544] +DfuAltName = @Flash/0x0/1*16Kg # ATxmega16D4 [USER] USER=0x4000 -0x1e9442=@Flash/0x0/1*16Kg +[AvrChipId=0x1e9442] +DfuAltName = @Flash/0x0/1*16Kg # ATxmega32A4 [USER] USER=0x8000 -0x1e9541=@Flash/0x0/1*32Kg +[AvrChipId=0x1e9541] +DfuAltName = @Flash/0x0/1*32Kg # ATxmega32C4 [USER] USER=0x8000 -0x1e9443=@Flash/0x0/1*32Kg +[AvrChipId=0x1e9443] +DfuAltName = @Flash/0x0/1*32Kg # ATxmega32D4 [USER] USER=0x8000 -0x1e9542=@Flash/0x0/1*32Kg +[AvrChipId=0x1e9542] +DfuAltName = @Flash/0x0/1*32Kg # ATxmega64A4 [USER] USER=0x10000 -0x1e9646=@Flash/0x0/1*64Kg +[AvrChipId=0x1e9646] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64C3 [USER] USER=0x10000 -0x1e9649=@Flash/0x0/1*64Kg +[AvrChipId=0x1e9649] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64D3 [USER] USER=0x10000 -0x1e964a=@Flash/0x0/1*64Kg +[AvrChipId=0x1e964a] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64D4 [USER] USER=0x10000 -0x1e9647=@Flash/0x0/1*64Kg +[AvrChipId=0x1e9647] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64A1 [USER] USER=0x10000 -0x1e964e=@Flash/0x0/1*64Kg +[AvrChipId=0x1e964e] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64A3 [USER] USER=0x10000 -0x1e9642=@Flash/0x0/1*64Kg +[AvrChipId=0x1e9642] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64B1 [USER] USER=0x10000 -0x1e9652=@Flash/0x0/1*64Kg +[AvrChipId=0x1e9652] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega64B3 [USER] USER=0x10000 -0x1e9651=@Flash/0x0/1*64Kg +[AvrChipId=0x1e9651] +DfuAltName = @Flash/0x0/1*64Kg # ATxmega128C3 [USER] USER=0x20000 -0x1e9752=@Flash/0x0/1*128Kg +[AvrChipId=0x1e9752] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128D3 [USER] USER=0x20000 -0x1e9748=@Flash/0x0/1*128Kg +[AvrChipId=0x1e9748] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128D4 [USER] USER=0x20000 -0x1e9747=@Flash/0x0/1*128Kg + [AvrChipId=0x1e9747] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A1 [USER] USER=0x20000 -0x1e974c=@Flash/0x0/1*128Kg +[AvrChipId=0x1e974c] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A1D [USER] USER=0x20000 -0x1e9741=@Flash/0x0/1*128Kg +[AvrChipId=0x1e9741] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A3 [USER] USER=0x20000 -0x1e9742=@Flash/0x0/1*128Kg +[AvrChipId=0x1e9742] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128A4 [USER] USER=0x20000 -0x1e9746=@Flash/0x0/1*128Kg +[AvrChipId=0x1e9746] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128B1 [USER] USER=0x20000 -0x1e974d=@Flash/0x0/1*128Kg +[AvrChipId=0x1e974d] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega128B3 [USER] USER=0x20000 -0x1e974b=@Flash/0x0/1*128Kg +[AvrChipId=0x1e974b] +DfuAltName = @Flash/0x0/1*128Kg # ATxmega192C3 [USER] USER=0x30000 -0x1e9751=@Flash/0x0/1*192Kg +[AvrChipId=0x1e9751] +DfuAltName = @Flash/0x0/1*192Kg # ATxmega192D3 [USER] USER=0x30000 -0x1e9749=@Flash/0x0/1*192Kg +[AvrChipId=0x1e9749] +DfuAltName = @Flash/0x0/1*192Kg # ATxmega192A1 [USER] USER=0x30000 -0x1e974e=@Flash/0x0/1*192Kg +[AvrChipId=0x1e974e] +DfuAltName = @Flash/0x0/1*192Kg # ATxmega192A3 [USER] USER=0x30000 -0x1e9744=@Flash/0x0/1*192Kg +[AvrChipId=0x1e9744] +DfuAltName = @Flash/0x0/1*192Kg # ATxmega256 [USER] USER=0x40000 -0x1e9846=@Flash/0x0/1*256Kg +[AvrChipId=0x1e9846] +DfuAltName = @Flash/0x0/1*256Kg # ATxmega256D3 [USER] USER=0x40000 -0x1e9844=@Flash/0x0/1*256Kg +[AvrChipId=0x1e9844] +DfuAltName = @Flash/0x0/1*256Kg # ATxmega256A3 [USER] USER=0x40000 -0x1e9842=@Flash/0x0/1*256Kg +[AvrChipId=0x1e9842] +DfuAltName = @Flash/0x0/1*256Kg # ATxmega256A3B [USER] USER=0x40000 -0x1e9843=@Flash/0x0/1*256Kg +[AvrChipId=0x1e9843] +DfuAltName = @Flash/0x0/1*256Kg # ATxmega384C3 [USER] USER=0x60000 -0x1e9845=@Flash/0x0/1*384Kg +[AvrChipId=0x1e9845] +DfuAltName = @Flash/0x0/1*384Kg # ATxmega384D3 [USER] USER=0x60000 -0x1e9847=@Flash/0x0/1*384Kg +[AvrChipId=0x1e9847] +DfuAltName = @Flash/0x0/1*384Kg # ATxmega8E5 [USER] USER=0x2000 -0x1e9341=@Flash/0x0/1*8Kg +[AvrChipId=0x1e9341] +DfuAltName = @Flash/0x0/1*8Kg # ATxmega16E5 [USER] USER=0x4000 -0x1e9445=@Flash/0x0/1*16Kg +[AvrChipId=0x1e9445] +DfuAltName = @Flash/0x0/1*16Kg # ATxmega32E5 [USER] USER=0x8000 -0x1e954c=@Flash/0x0/1*32Kg +[AvrChipId=0x1e954c] +DfuAltName = @Flash/0x0/1*32Kg diff -Nru fwupd-1.0.6/plugins/dfu/dfu-sector.c fwupd-1.2.10/plugins/dfu/dfu-sector.c --- fwupd-1.0.6/plugins/dfu/dfu-sector.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-sector.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** diff -Nru fwupd-1.0.6/plugins/dfu/dfu-sector.h fwupd-1.2.10/plugins/dfu/dfu-sector.h --- fwupd-1.0.6/plugins/dfu/dfu-sector.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-sector.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_SECTOR_H -#define __DFU_SECTOR_H +#pragma once #include #include @@ -64,5 +48,3 @@ gchar *dfu_sector_to_string (DfuSector *sector); G_END_DECLS - -#endif /* __DFU_SECTOR_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-sector-private.h fwupd-1.2.10/plugins/dfu/dfu-sector-private.h --- fwupd-1.0.6/plugins/dfu/dfu-sector-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-sector-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_SECTOR_PRIVATE_H -#define __DFU_SECTOR_PRIVATE_H +#pragma once #include "dfu-sector.h" @@ -34,5 +18,3 @@ DfuSectorCap cap); G_END_DECLS - -#endif /* __DFU_SECTOR_PRIVATE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-self-test.c fwupd-1.2.10/plugins/dfu/dfu-self-test.c --- fwupd-1.0.6/plugins/dfu/dfu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -25,7 +10,6 @@ #include #include -#include "dfu-chunked.h" #include "dfu-cipher-xtea.h" #include "dfu-common.h" #include "dfu-device-private.h" @@ -51,34 +35,6 @@ return g_strdup (full_tmp); } -static gchar * -_g_bytes_compare_verbose (GBytes *bytes1, GBytes *bytes2) -{ - const guint8 *data1; - const guint8 *data2; - gsize length1; - gsize length2; - - data1 = g_bytes_get_data (bytes1, &length1); - data2 = g_bytes_get_data (bytes2, &length2); - - /* not the same length */ - if (length1 != length2) { - return g_strdup_printf ("got %" G_GSIZE_FORMAT " bytes, " - "expected %" G_GSIZE_FORMAT, - length1, length2); - } - - /* return 00 01 02 03 */ - for (guint i = 0; i < length1; i++) { - if (data1[i] != data2[i]) { - return g_strdup_printf ("got 0x%02x, expected 0x%02x @ 0x%04x", - data1[i], data2[i], i); - } - } - return NULL; -} - static void dfu_cipher_xtea_func (void) { @@ -196,7 +152,9 @@ roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); - g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, fw), ==, NULL); + ret = fu_common_bytes_compare (roundtrip, fw, &error); + g_assert_no_error (error); + g_assert_true (ret); } static void @@ -264,14 +222,16 @@ g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x8eB4); g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE); - /* can we roundtrip without loosing data */ + /* can we roundtrip without losing data */ roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); g_assert_no_error (error); g_assert (roundtrip_orig != NULL); roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); - g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); + ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); + g_assert_no_error (error); + g_assert_true (ret); } static void @@ -303,7 +263,7 @@ g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x168d5); g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE); - /* can we roundtrip without loosing data */ + /* can we roundtrip without losing data */ roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); g_assert_no_error (error); g_assert (roundtrip_orig != NULL); @@ -315,7 +275,9 @@ // g_bytes_get_data (roundtrip, NULL), // g_bytes_get_size (roundtrip), NULL); - g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); + ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); + g_assert_no_error (error); + g_assert_true (ret); /* use usual image name copying */ g_unsetenv ("DFU_SELF_TEST_IMAGE_MEMCPY_NAME"); @@ -346,15 +308,16 @@ g_assert_cmpstr (dfu_firmware_get_metadata (firmware, "key"), ==, "value"); g_assert_cmpstr (dfu_firmware_get_metadata (firmware, "???"), ==, NULL); - /* can we roundtrip without loosing data */ + /* can we roundtrip without losing data */ roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); g_assert_no_error (error); g_assert (roundtrip_orig != NULL); roundtrip = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (roundtrip != NULL); - - g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); + ret = fu_common_bytes_compare (roundtrip, roundtrip_orig, &error); + g_assert_no_error (error); + g_assert_true (ret); } static void @@ -408,6 +371,47 @@ } static void +dfu_firmware_srec_func (void) +{ + gboolean ret; + g_autofree gchar *filename_hex = NULL; + g_autofree gchar *filename_ref = NULL; + g_autoptr(DfuFirmware) firmware = NULL; + g_autoptr(GBytes) data_bin = NULL; + g_autoptr(GBytes) data_ref = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file_bin = NULL; + g_autoptr(GFile) file_hex = NULL; + + filename_hex = dfu_test_get_filename ("firmware.srec"); + g_assert (filename_hex != NULL); + file_hex = g_file_new_for_path (filename_hex); + firmware = dfu_firmware_new (); + ret = dfu_firmware_parse_file (firmware, file_hex, + DFU_FIRMWARE_PARSE_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 136); + + dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); + data_bin = dfu_firmware_write_data (firmware, &error); + g_assert_no_error (error); + g_assert (data_bin != NULL); + + /* did we match the reference file? */ + filename_ref = dfu_test_get_filename ("firmware.bin"); + g_assert (filename_ref != NULL); + file_bin = g_file_new_for_path (filename_ref); + data_ref = dfu_self_test_get_bytes_for_file (file_bin, &error); + g_assert_no_error (error); + g_assert (data_ref != NULL); + ret = fu_common_bytes_compare (data_bin, data_ref, &error); + g_assert_no_error (error); + g_assert_true (ret); +} + +static void dfu_firmware_intel_hex_func (void) { const guint8 *data; @@ -448,7 +452,9 @@ data_ref = dfu_self_test_get_bytes_for_file (file_bin, &error); g_assert_no_error (error); g_assert (data_ref != NULL); - g_assert_cmpstr (_g_bytes_compare_verbose (data_bin, data_ref), ==, NULL); + ret = fu_common_bytes_compare (data_bin, data_ref, &error); + g_assert_no_error (error); + g_assert_true (ret); /* export a ihex file (which will be slightly different due to * non-continous regions being expanded */ @@ -475,7 +481,9 @@ data_bin2 = dfu_firmware_write_data (firmware, &error); g_assert_no_error (error); g_assert (data_bin2 != NULL); - g_assert_cmpstr (_g_bytes_compare_verbose (data_bin, data_bin2), ==, NULL); + ret = fu_common_bytes_compare (data_bin, data_bin2, &error); + g_assert_no_error (error); + g_assert_true (ret); } static void @@ -774,50 +782,6 @@ g_debug ("serialized blob %s", serialized_str); } -static void -dfu_chunked_func (void) -{ - g_autofree gchar *chunked1_str = NULL; - g_autofree gchar *chunked2_str = NULL; - g_autofree gchar *chunked3_str = NULL; - g_autofree gchar *chunked4_str = NULL; - g_autoptr(GPtrArray) chunked1 = NULL; - g_autoptr(GPtrArray) chunked2 = NULL; - g_autoptr(GPtrArray) chunked3 = NULL; - g_autoptr(GPtrArray) chunked4 = NULL; - - chunked3 = dfu_chunked_new ((const guint8 *) "123456", 6, 0x0, 3, 3); - chunked3_str = dfu_chunked_to_string (chunked3); - g_print ("\n%s", chunked3_str); - g_assert_cmpstr (chunked3_str, ==, "#00: page:00 addr:0000 len:03 123\n" - "#01: page:01 addr:0000 len:03 456\n"); - - chunked4 = dfu_chunked_new ((const guint8 *) "123456", 6, 0x4, 4, 4); - chunked4_str = dfu_chunked_to_string (chunked4); - g_print ("\n%s", chunked4_str); - g_assert_cmpstr (chunked4_str, ==, "#00: page:01 addr:0000 len:04 1234\n" - "#01: page:02 addr:0000 len:02 56\n"); - - chunked1 = dfu_chunked_new ((const guint8 *) "0123456789abcdef", 16, 0x0, 10, 4); - chunked1_str = dfu_chunked_to_string (chunked1); - g_print ("\n%s", chunked1_str); - g_assert_cmpstr (chunked1_str, ==, "#00: page:00 addr:0000 len:04 0123\n" - "#01: page:00 addr:0004 len:04 4567\n" - "#02: page:00 addr:0008 len:02 89\n" - "#03: page:01 addr:0000 len:04 abcd\n" - "#04: page:01 addr:0004 len:02 ef\n"); - - chunked2 = dfu_chunked_new ((const guint8 *) "XXXXXXYYYYYYZZZZZZ", 18, 0x0, 6, 4); - chunked2_str = dfu_chunked_to_string (chunked2); - g_print ("\n%s", chunked2_str); - g_assert_cmpstr (chunked2_str, ==, "#00: page:00 addr:0000 len:04 XXXX\n" - "#01: page:00 addr:0004 len:02 XX\n" - "#02: page:01 addr:0000 len:04 YYYY\n" - "#03: page:01 addr:0004 len:02 YY\n" - "#04: page:02 addr:0000 len:04 ZZZZ\n" - "#05: page:02 addr:0004 len:02 ZZ\n"); -} - int main (int argc, char **argv) { @@ -830,7 +794,7 @@ g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); /* tests go here */ - g_test_add_func ("/dfu/chunked", dfu_chunked_func); + g_test_add_func ("/dfu/firmware{srec}", dfu_firmware_srec_func); g_test_add_func ("/dfu/patch", dfu_patch_func); g_test_add_func ("/dfu/patch{merges}", dfu_patch_merges_func); g_test_add_func ("/dfu/patch{apply}", dfu_patch_apply_func); diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target-avr.c fwupd-1.2.10/plugins/dfu/dfu-target-avr.c --- fwupd-1.0.6/plugins/dfu/dfu-target-avr.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target-avr.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -24,7 +9,8 @@ #include #include -#include "dfu-chunked.h" +#include "fu-chunk.h" + #include "dfu-common.h" #include "dfu-sector.h" #include "dfu-target-avr.h" @@ -33,6 +19,22 @@ #include "fwupd-error.h" +/** + * FU_QUIRKS_DFU_AVR_ALT_NAME: + * @key: the AVR chip ID, e.g. `0x58200204` + * @value: the UM0424 sector description, e.g. `@Flash/0x2000/1*248Kg` + * + * Assigns a sector description for the chip ID. This is required so fwupd can + * program the user firmware avoiding the bootloader and for checking the total + * element size. + * + * The chip ID can be found from a datasheet or using `dfu-tool list` when the + * hardware is connected and in bootloader mode. + * + * Since: 1.0.1 + */ +#define FU_QUIRKS_DFU_AVR_ALT_NAME "DfuAltName" + typedef struct { guint32 device_id; } DfuTargetAvrPrivate; @@ -414,6 +416,7 @@ gsize sz; guint32 device_id_be; g_autofree gchar *chip_id = NULL; + g_autofree gchar *chip_id_prefixed = NULL; g_autoptr(GBytes) chunk_sig = NULL; /* already done */ @@ -428,8 +431,10 @@ return FALSE; } else { chunk_sig = dfu_target_avr32_get_chip_signature (target, error); - if (chunk_sig == NULL) + if (chunk_sig == NULL) { + g_prefix_error (error, "failed to get chip signature: "); return FALSE; + } } /* get data back */ @@ -463,9 +468,10 @@ /* set the alt-name using the device ID */ dfu_device_set_chip_id (dfu_target_get_device (target), chip_id); device = dfu_target_get_device (target); + chip_id_prefixed = g_strdup_printf ("AvrChipId=%s", chip_id); quirk_str = fu_quirks_lookup_by_id (fu_device_get_quirks (FU_DEVICE (device)), - FU_QUIRKS_DFU_AVR_CHIP_ID, - chip_id); + chip_id_prefixed, + FU_QUIRKS_DFU_AVR_ALT_NAME); if (quirk_str == NULL) { dfu_device_remove_attribute (dfu_target_get_device (target), DFU_DEVICE_ATTRIBUTE_CAN_DOWNLOAD); @@ -496,7 +502,7 @@ guint16 page_last = G_MAXUINT16; guint32 address; guint32 address_offset = 0x0; - g_autoptr(GPtrArray) packets = NULL; + g_autoptr(GPtrArray) chunks = NULL; const guint8 footer[] = { 0x00, 0x00, 0x00, 0x00, /* CRC */ 16, /* len */ 'D', 'F', 'U', /* signature */ @@ -549,56 +555,56 @@ /* chunk up the memory space into pages */ data = g_bytes_get_data (blob, NULL); - packets = dfu_chunked_new (data + address_offset, - g_bytes_get_size (blob) - address_offset, - dfu_sector_get_address (sector), - ATMEL_64KB_PAGE, - ATMEL_MAX_TRANSFER_SIZE); + chunks = fu_chunk_array_new (data + address_offset, + g_bytes_get_size (blob) - address_offset, + dfu_sector_get_address (sector), + ATMEL_64KB_PAGE, + ATMEL_MAX_TRANSFER_SIZE); /* update UI */ dfu_target_set_action (target, FWUPD_STATUS_DEVICE_WRITE); /* process each chunk */ - for (guint i = 0; i < packets->len; i++) { - const DfuChunkedPacket *packet = g_ptr_array_index (packets, i); + for (guint i = 0; i < chunks->len; i++) { + const FuChunk *chk = g_ptr_array_index (chunks, i); g_autofree guint8 *buf = NULL; g_autoptr(GBytes) chunk_tmp = NULL; /* select page if required */ - if (packet->page != page_last) { + if (chk->page != page_last) { if (dfu_device_has_quirk (dfu_target_get_device (target), DFU_DEVICE_QUIRK_LEGACY_PROTOCOL)) { if (!dfu_target_avr_select_memory_page (target, - packet->page, + chk->page, error)) return FALSE; } else { if (!dfu_target_avr32_select_memory_page (target, - packet->page, + chk->page, error)) return FALSE; } - page_last = packet->page; + page_last = chk->page; } - /* create packet with header and footer */ - buf = g_malloc0 (packet->data_sz + header_sz + sizeof(footer)); + /* create chk with header and footer */ + buf = g_malloc0 (chk->data_sz + header_sz + sizeof(footer)); buf[0] = DFU_AVR32_GROUP_DOWNLOAD; buf[1] = DFU_AVR32_CMD_PROGRAM_START; - fu_common_write_uint16 (&buf[2], packet->address, G_BIG_ENDIAN); - fu_common_write_uint16 (&buf[4], packet->address + packet->data_sz - 1, G_BIG_ENDIAN); - memcpy (&buf[header_sz], packet->data, packet->data_sz); - memcpy (&buf[header_sz + packet->data_sz], footer, sizeof(footer)); + fu_common_write_uint16 (&buf[2], chk->address, G_BIG_ENDIAN); + fu_common_write_uint16 (&buf[4], chk->address + chk->data_sz - 1, G_BIG_ENDIAN); + memcpy (&buf[header_sz], chk->data, chk->data_sz); + memcpy (&buf[header_sz + chk->data_sz], footer, sizeof(footer)); /* download data */ - chunk_tmp = g_bytes_new_static (buf, packet->data_sz + header_sz + sizeof(footer)); + chunk_tmp = g_bytes_new_static (buf, chk->data_sz + header_sz + sizeof(footer)); g_debug ("sending %" G_GSIZE_FORMAT " bytes to the hardware", g_bytes_get_size (chunk_tmp)); if (!dfu_target_download_chunk (target, i, chunk_tmp, error)) return FALSE; /* update UI */ - dfu_target_set_percentage (target, i + 1, packets->len); + dfu_target_set_percentage (target, i + 1, chunks->len); } /* done */ @@ -619,7 +625,7 @@ g_autoptr(DfuElement) element = NULL; g_autoptr(GBytes) contents = NULL; g_autoptr(GBytes) contents_truncated = NULL; - g_autoptr(GPtrArray) packets = NULL; + g_autoptr(GPtrArray) blobs = NULL; g_autoptr(GPtrArray) chunks = NULL; DfuSector *sector; @@ -650,63 +656,63 @@ address &= ~0x80000000; /* chunk up the memory space into pages */ - packets = dfu_chunked_new (NULL, maximum_size, address, - ATMEL_64KB_PAGE, ATMEL_MAX_TRANSFER_SIZE); + chunks = fu_chunk_array_new (NULL, maximum_size, address, + ATMEL_64KB_PAGE, ATMEL_MAX_TRANSFER_SIZE); /* update UI */ dfu_target_set_action (target, FWUPD_STATUS_DEVICE_READ); /* process each chunk */ - chunks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); - for (guint i = 0; i < packets->len; i++) { - GBytes *chunk_tmp = NULL; - const DfuChunkedPacket *packet = g_ptr_array_index (packets, i); + blobs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref); + for (guint i = 0; i < chunks->len; i++) { + GBytes *blob_tmp = NULL; + const FuChunk *chk = g_ptr_array_index (chunks, i); /* select page if required */ - if (packet->page != page_last) { + if (chk->page != page_last) { if (dfu_device_has_quirk (dfu_target_get_device (target), DFU_DEVICE_QUIRK_LEGACY_PROTOCOL)) { if (!dfu_target_avr_select_memory_page (target, - packet->page, + chk->page, error)) return NULL; } else { if (!dfu_target_avr32_select_memory_page (target, - packet->page, + chk->page, error)) return NULL; } - page_last = packet->page; + page_last = chk->page; } /* prepare to read */ if (!dfu_target_avr_read_memory (target, - packet->address, - packet->address + packet->data_sz - 1, + chk->address, + chk->address + chk->data_sz - 1, error)) return NULL; /* upload data */ - g_debug ("requesting %i bytes from the hardware", - ATMEL_MAX_TRANSFER_SIZE); - chunk_tmp = dfu_target_upload_chunk (target, i, - ATMEL_MAX_TRANSFER_SIZE, - error); - if (chunk_tmp == NULL) + g_debug ("requesting %i bytes from the hardware for chunk 0x%x", + ATMEL_MAX_TRANSFER_SIZE, i); + blob_tmp = dfu_target_upload_chunk (target, i, + ATMEL_MAX_TRANSFER_SIZE, + error); + if (blob_tmp == NULL) return NULL; - g_ptr_array_add (chunks, chunk_tmp); + g_ptr_array_add (blobs, blob_tmp); /* this page has valid data */ - if (!dfu_utils_bytes_is_empty (chunk_tmp)) { + if (!fu_common_bytes_is_empty (blob_tmp)) { g_debug ("chunk %u has data (page %" G_GUINT32_FORMAT ")", - i, packet->page); + i, chk->page); chunk_valid = i; } else { g_debug ("chunk %u is empty", i); } /* update UI */ - dfu_target_set_percentage (target, i + 1, packets->len); + dfu_target_set_percentage (target, i + 1, chunks->len); } /* done */ @@ -715,16 +721,16 @@ /* truncate the image if any sectors are empty, i.e. all 0xff */ if (chunk_valid == G_MAXUINT) { - g_debug ("all %u chunks are empty", chunks->len); + g_debug ("all %u chunks are empty", blobs->len); g_ptr_array_set_size (chunks, 0); - } else if (chunks->len != chunk_valid + 1) { + } else if (blobs->len != chunk_valid + 1) { g_debug ("truncating chunks from %u to %u", - chunks->len, chunk_valid + 1); - g_ptr_array_set_size (chunks, chunk_valid + 1); + blobs->len, chunk_valid + 1); + g_ptr_array_set_size (blobs, chunk_valid + 1); } /* create element of required size */ - contents = dfu_utils_bytes_join_array (chunks); + contents = dfu_utils_bytes_join_array (blobs); if (expected_size > 0 && g_bytes_get_size (contents) > expected_size) { contents_truncated = g_bytes_new_from_bytes (contents, 0x0, expected_size); } else { diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target-avr.h fwupd-1.2.10/plugins/dfu/dfu-target-avr.h --- fwupd-1.0.6/plugins/dfu/dfu-target-avr.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target-avr.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_AVR_H -#define __DFU_TARGET_AVR_H +#pragma once #include #include @@ -40,5 +24,3 @@ DfuTarget *dfu_target_avr_new (void); G_END_DECLS - -#endif /* __DFU_TARGET_AVR_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target.c fwupd-1.2.10/plugins/dfu/dfu-target.c --- fwupd-1.0.6/plugins/dfu/dfu-target.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ /** @@ -1057,7 +1042,7 @@ if (zone_cur == zone_last) continue; - /* get the size of the entire continous zone */ + /* get the size of the entire continuous zone */ zone_size = dfu_target_get_size_of_zone (target, zone_cur); zone_last = zone_cur; diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target.h fwupd-1.2.10/plugins/dfu/dfu-target.h --- fwupd-1.0.6/plugins/dfu/dfu-target.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_H -#define __DFU_TARGET_H +#pragma once #include #include @@ -46,7 +30,7 @@ * @DFU_TARGET_TRANSFER_FLAG_ANY_CIPHER: Allow any cipher kinds to be downloaded * @DFU_TARGET_TRANSFER_FLAG_ADDR_HEURISTIC: Automatically detect the address to use * - * The optional flags used for transfering firmware. + * The optional flags used for transferring firmware. **/ typedef enum { DFU_TARGET_TRANSFER_FLAG_NONE = 0, @@ -106,5 +90,3 @@ DfuCipherKind dfu_target_get_cipher_kind (DfuTarget *target); G_END_DECLS - -#endif /* __DFU_TARGET_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target-private.h fwupd-1.2.10/plugins/dfu/dfu-target-private.h --- fwupd-1.0.6/plugins/dfu/dfu-target-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_PRIVATE_H -#define __DFU_TARGET_PRIVATE_H +#pragma once #include @@ -71,5 +55,3 @@ GError **error); G_END_DECLS - -#endif /* __DFU_TARGET_PRIVATE_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target-stm.c fwupd-1.2.10/plugins/dfu/dfu-target-stm.c --- fwupd-1.0.6/plugins/dfu/dfu-target-stm.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target-stm.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -25,7 +10,6 @@ #include #include -#include "dfu-chunked.h" #include "dfu-common.h" #include "dfu-sector.h" #include "dfu-target-stm.h" @@ -133,7 +117,7 @@ g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "memory sector at 0x%04x is not readble", + "memory sector at 0x%04x is not readable", (guint) offset); return NULL; } diff -Nru fwupd-1.0.6/plugins/dfu/dfu-target-stm.h fwupd-1.2.10/plugins/dfu/dfu-target-stm.h --- fwupd-1.0.6/plugins/dfu/dfu-target-stm.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-target-stm.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __DFU_TARGET_STM_H -#define __DFU_TARGET_STM_H +#pragma once #include #include @@ -40,5 +24,3 @@ DfuTarget *dfu_target_stm_new (void); G_END_DECLS - -#endif /* __DFU_TARGET_STM_H */ diff -Nru fwupd-1.0.6/plugins/dfu/dfu-tool.c fwupd-1.2.10/plugins/dfu/dfu-tool.c --- fwupd-1.0.6/plugins/dfu/dfu-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/dfu-tool.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -26,7 +11,6 @@ #include #include #include -#include #include "dfu-cipher-xtea.h" #include "dfu-device-private.h" @@ -65,13 +49,17 @@ if (priv == NULL) return; g_free (priv->device_vid_pid); + g_object_unref (priv->progressbar); g_object_unref (priv->cancellable); g_object_unref (priv->quirks); if (priv->cmd_array != NULL) g_ptr_array_unref (priv->cmd_array); g_free (priv); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(DfuToolPrivate, dfu_tool_private_free) +#pragma clang diagnostic pop typedef gboolean (*FuUtilPrivateCb) (DfuToolPrivate *util, gchar **values, @@ -264,7 +252,7 @@ g_autoptr(DfuDevice) device = dfu_device_new (usb_device); fu_device_set_quirks (FU_DEVICE (device), priv->quirks); dfu_device_set_usb_context (device, usb_context); - if (fu_usb_device_probe (FU_USB_DEVICE (device), NULL)) + if (fu_device_probe (FU_DEVICE (device), NULL)) return g_steal_pointer (&device); } @@ -492,7 +480,7 @@ g_return_val_if_fail (search_sz == replace_sz, FALSE); /* find and replace each one */ - for (gsize i = 0; i < data_sz - search_sz; i++) { + for (gsize i = 0; i < data_sz - search_sz + 1; i++) { if (memcmp (data_buf + i, search_buf, search_sz) == 0) { g_print ("Replacing %" G_GSIZE_FORMAT " bytes @0x%04x\n", replace_sz, (guint) i); @@ -687,7 +675,7 @@ if (cnt == 0) { g_set_error_literal (error, FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, + FWUPD_ERROR_NOT_FOUND, "search string was not found"); return FALSE; } @@ -1438,7 +1426,7 @@ error->message); } if (!dfu_device_refresh (device, &error)) - return FALSE; + return NULL; } return g_strdup_printf ("%04x:%04x [%s:%s]", dfu_device_get_vid (device), @@ -1726,6 +1714,7 @@ /* open files */ for (guint i = 0; values[i] != NULL; i++) { + g_autofree gchar *tmp = NULL; g_autoptr(DfuFirmware) firmware = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GError) error_local = NULL; @@ -1739,7 +1728,8 @@ error_local->message); continue; } - g_print ("%s\n", dfu_firmware_to_string (firmware)); + tmp = dfu_firmware_to_string (firmware); + g_print ("%s\n", tmp); } return TRUE; } @@ -2013,18 +2003,6 @@ } } -static gchar * -_bcd_version_from_uint16 (guint16 val) -{ -#if AS_CHECK_VERSION(0,7,3) - return as_utils_version_from_uint16 (val, AS_VERSION_PARSE_FLAG_USE_BCD); -#else - guint maj = ((val >> 12) & 0x0f) * 10 + ((val >> 8) & 0x0f); - guint min = ((val >> 4) & 0x0f) * 10 + (val & 0x0f); - return g_strdup_printf ("%u.%u", maj, min); -#endif -} - static gboolean dfu_tool_list (DfuToolPrivate *priv, gchar **values, GError **error) { @@ -2056,9 +2034,10 @@ device = dfu_device_new (usb_device); fu_device_set_quirks (FU_DEVICE (device), priv->quirks); dfu_device_set_usb_context (device, usb_context); - if (!fu_usb_device_probe (FU_USB_DEVICE (device), NULL)) + if (!fu_device_probe (FU_DEVICE (device), NULL)) continue; - version = _bcd_version_from_uint16 (g_usb_device_get_release (usb_device)); + version = fu_common_version_from_uint16 (g_usb_device_get_release (usb_device), + FWUPD_VERSION_FORMAT_BCD); g_print ("%s %04x:%04x [v%s]:\n", /* TRANSLATORS: detected a DFU device */ _("Found"), @@ -2177,7 +2156,7 @@ if (priv->transfer_size > 0) dfu_device_set_transfer_size (device, priv->transfer_size); - /* detatch */ + /* detach */ locker = fu_device_locker_new (device, error); if (locker == NULL) return FALSE; @@ -2207,15 +2186,15 @@ g_autoptr(GOptionContext) context = NULL; const GOptionEntry options[] = { { "version", '\0', 0, G_OPTION_ARG_NONE, &version, - "Print the version number", NULL }, + _("Print the version number"), NULL }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - "Print verbose debug statements", NULL }, + _("Print verbose debug statements"), NULL }, { "device", 'd', 0, G_OPTION_ARG_STRING, &priv->device_vid_pid, - "Specify Vendor/Product ID(s) of DFU device", "VID:PID" }, + _("Specify Vendor/Product ID(s) of DFU device"), "VID:PID" }, { "transfer-size", 't', 0, G_OPTION_ARG_STRING, &priv->transfer_size, - "Specify the number of bytes per USB transfer", "BYTES" }, + _("Specify the number of bytes per USB transfer"), "BYTES" }, { "force", '\0', 0, G_OPTION_ARG_NONE, &priv->force, - "Force the action ignoring all warnings", NULL }, + _("Force the action ignoring all warnings"), NULL }, { NULL} }; @@ -2448,6 +2427,5 @@ } /* success/ */ - g_object_unref (priv->progressbar); return EXIT_SUCCESS; } diff -Nru fwupd-1.0.6/plugins/dfu/fu-plugin-dfu.c fwupd-1.2.10/plugins/dfu/fu-plugin-dfu.c --- fwupd-1.0.6/plugins/dfu/fu-plugin-dfu.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/fu-plugin-dfu.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,33 +1,24 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include - -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "dfu-device.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.usb.dfu"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.st.dfuse"); +} + static void fu_plugin_dfu_state_changed_cb (DfuDevice *device, DfuState state, @@ -46,13 +37,13 @@ } gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *dev, GError **error) { g_autoptr(DfuDevice) device = NULL; g_autoptr(FuDeviceLocker) locker = NULL; /* open the device */ - device = dfu_device_new (usb_device); + device = dfu_device_new (fu_usb_device_get_dev (dev)); fu_device_set_quirks (FU_DEVICE (device), fu_plugin_get_quirks (plugin)); dfu_device_set_usb_context (device, fu_plugin_get_usb_context (plugin)); locker = fu_device_locker_new (device, error); @@ -99,10 +90,9 @@ /* detach and USB reset */ if (!dfu_device_detach (device, error)) return FALSE; - if (!dfu_device_wait_for_replug (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; - /* success */ + /* wait for replug */ + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } @@ -127,10 +117,9 @@ /* attach it */ if (!dfu_device_attach (device, error)) return FALSE; - if (!dfu_device_wait_for_replug (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, error)) - return FALSE; - /* success */ + /* wait for replug */ + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } diff -Nru fwupd-1.0.6/plugins/dfu/fuzzing/example-addr32.srec fwupd-1.2.10/plugins/dfu/fuzzing/example-addr32.srec --- fwupd-1.0.6/plugins/dfu/fuzzing/example-addr32.srec 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/fuzzing/example-addr32.srec 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +S00400006299 +S108000031202D6E0A01 +S5030001FB diff -Nru fwupd-1.0.6/plugins/dfu/fuzzing/example.srec fwupd-1.2.10/plugins/dfu/fuzzing/example.srec --- fwupd-1.0.6/plugins/dfu/fuzzing/example.srec 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/fuzzing/example.srec 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +S0040000619A +S30A0000000031202D6E0AFF +S5030001FB diff -Nru fwupd-1.0.6/plugins/dfu/fuzzing.md fwupd-1.2.10/plugins/dfu/fuzzing.md --- fwupd-1.0.6/plugins/dfu/fuzzing.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/fuzzing.md 2019-07-15 18:25:54.000000000 +0000 @@ -17,3 +17,7 @@ echo -n helloworldhelloworldhelloworldhelloworld > grow-two-chunks.old echo -n XelloXorldhelloworldhelloworldhelloworlXXX > grow-two-chunks.new ./plugins/dfu/dfu-tool patch-create grow-two-chunks.old grow-two-chunks.new fuzzing-patch-dump/grow-two-chunks.bdiff + + echo "1" -n > test.bin + srec_cat test.bin -binary -o fuzzing/test2.srec -address-length=4 -header=a + srec_cat test.bin -binary -o fuzzing/test1.srec -header=b diff -Nru fwupd-1.0.6/plugins/dfu/meson.build fwupd-1.2.10/plugins/dfu/meson.build --- fwupd-1.0.6/plugins/dfu/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -6,8 +6,8 @@ dfu = static_library( 'dfu', + fu_hash, sources : [ - 'dfu-chunked.c', 'dfu-cipher-xtea.c', 'dfu-common.c', 'dfu-device.c', @@ -16,6 +16,7 @@ 'dfu-format-dfu.c', 'dfu-format-dfuse.c', 'dfu-format-ihex.c', + 'dfu-format-srec.c', 'dfu-format-metadata.c', 'dfu-format-raw.c', 'dfu-image.c', @@ -26,10 +27,13 @@ 'dfu-target-avr.c', ], dependencies : [ - appstream_glib, giounix, libm, gusb, + gudev, + ], + link_with : [ + libfwupdprivate, ], c_args : cargs, include_directories : [ @@ -40,6 +44,7 @@ ) shared_module('fu_plugin_dfu', + fu_hash, sources : [ 'fu-plugin-dfu.c', ], @@ -55,12 +60,14 @@ plugin_deps, ], link_with : [ + libfwupdprivate, dfu, ], ) dfu_tool = executable( 'dfu-tool', + fu_hash, sources : [ 'dfu-tool.c', ], @@ -71,14 +78,14 @@ include_directories('../../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, libm, gusb, + gudev, ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs, @@ -111,6 +118,7 @@ cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'dfu-self-test', + fu_hash, sources : [ 'dfu-self-test.c' ], @@ -121,14 +129,14 @@ include_directories('../../src'), ], dependencies : [ - appstream_glib, + libxmlb, gio, gusb, + gudev, libm, ], link_with : [ dfu, - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.0.6/plugins/dfu/README.md fwupd-1.2.10/plugins/dfu/README.md --- fwupd-1.0.6/plugins/dfu/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -6,3 +6,33 @@ Device Firmware Update is a standard that allows USB devices to be easily and safely updated by any operating system. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +DFU or DfuSe file format. + +This plugin supports the following protocol IDs: + + * org.usb.dfu + * com.st.dfuse + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_273F&PID_1003&REV_0001` + * `USB\VID_273F&PID_1003` + * `USB\VID_273F` + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +|`DfuFlags` | Optional quirks for a DFU device which doesn't follow the DFU 1.0 or 1.1 specification | 1.0.1| +|`DfuForceVersion` | Forces a specific DFU version for the hardware device. This is required if the device does not set, or sets incorrectly, items in the DFU functional descriptor. |1.0.1| +|`DfuJabraDetach` | Assigns the two magic bytes sent to the Jabra hardware when the device is in runtime mode to make it switch into DFU mode.|1.0.1| diff -Nru fwupd-1.0.6/plugins/dfu/tests/firmware.srec fwupd-1.2.10/plugins/dfu/tests/firmware.srec --- fwupd-1.0.6/plugins/dfu/tests/firmware.srec 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/dfu/tests/firmware.srec 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,7 @@ +S0220000687474703A2F2F737265636F72642E736F75726365666F7267652E6E65742F1D +S12300003DEF20F000000000FACF01F0FBCF02F0E9CF03F0EACF04F0E1CF05F0E2CF06F086 +S1230020D9CF07F0DACF08F0F3CF09F0F4CF0AF0F6CF0BF0F7CF0CF0F8CF0DF0F5CF0EF0FC +S12300400EC0F5FF0DC0F8FF0CC0F7FF0BC0F6FF0AC0F4FF09C0F3FF08C0DAFF07C0D9FFDC +S123006006C0E2FF05C0E1FF04C0EAFF03C0E9FF02C0FBFF01C0FAFF11003FEF20F0000112 +S10B008042EF20F03DEF20F0F7 +S5030005F7 diff -Nru fwupd-1.0.6/plugins/ebitdo/data/m30.txt fwupd-1.2.10/plugins/ebitdo/data/m30.txt --- fwupd-1.0.6/plugins/ebitdo/data/m30.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/data/m30.txt 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,168 @@ +Bus 002 Device 008: ID 2dc8:5006 8BitDo M30 gamepad +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x2dc8 8BitDo + idProduct 0x5006 M30 gamepad + bcdDevice 0.01 + iManufacturer 1 8Bitdo + iProduct 2 8BitDo M30 gamepad + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0029 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 480mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 123 + Report Descriptor: (length is 123) + Item(Global): Usage Page, data= [ 0x01 ] 1 + Generic Desktop Controls + Item(Local ): Usage, data= [ 0x05 ] 5 + Gamepad + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0x01 ] 1 + Item(Global): Physical Minimum, data= [ 0x00 ] 0 + Item(Global): Physical Maximum, data= [ 0x01 ] 1 + Item(Global): Report Size, data= [ 0x01 ] 1 + Item(Global): Report Count, data= [ 0x0f ] 15 + Item(Global): Usage Page, data= [ 0x09 ] 9 + Buttons + Item(Local ): Usage Minimum, data= [ 0x01 ] 1 + Button 1 (Primary) + Item(Local ): Usage Maximum, data= [ 0x0f ] 15 + (null) + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x01 ] 1 + Item(Main ): Input, data= [ 0x01 ] 1 + Constant Array Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Usage Page, data= [ 0x01 ] 1 + Generic Desktop Controls + Item(Global): Logical Maximum, data= [ 0x07 ] 7 + Item(Global): Physical Maximum, data= [ 0x3b 0x01 ] 315 + Item(Global): Report Size, data= [ 0x04 ] 4 + Item(Global): Report Count, data= [ 0x01 ] 1 + Item(Global): Unit, data= [ 0x14 ] 20 + System: English Rotation, Unit: Degrees + Item(Local ): Usage, data= [ 0x39 ] 57 + Hat Switch + Item(Main ): Input, data= [ 0x42 ] 66 + Data Variable Absolute No_Wrap Linear + Preferred_State Null_State Non_Volatile Bitfield + Item(Global): Unit, data= [ 0x00 ] 0 + System: None, Unit: (None) + Item(Global): Report Count, data= [ 0x01 ] 1 + Item(Main ): Input, data= [ 0x01 ] 1 + Constant Array Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Physical Maximum, data= [ 0xff 0x00 ] 255 + Item(Local ): Usage, data= [ 0x30 ] 48 + Direction-X + Item(Local ): Usage, data= [ 0x31 ] 49 + Direction-Y + Item(Local ): Usage, data= [ 0x32 ] 50 + Direction-Z + Item(Local ): Usage, data= [ 0x35 ] 53 + Rotate-Z + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x04 ] 4 + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Usage Page, data= [ 0x02 ] 2 + Simulation Controls + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Local ): Usage, data= [ 0xc4 ] 196 + Accelerator + Item(Local ): Usage, data= [ 0xc5 ] 197 + Brake + Item(Global): Report Count, data= [ 0x02 ] 2 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Usage Page, data= [ 0x08 ] 8 + LEDs + Item(Local ): Usage, data= [ 0x43 ] 67 + Slow Blink On Time + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Physical Minimum, data= [ 0x00 ] 0 + Item(Global): Physical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x02 ] 2 + Item(Main ): Output, data= [ 0x82 ] 130 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Volatile Bitfield + Item(Local ): Usage, data= [ 0x44 ] 68 + Slow Blink Off Time + Item(Main ): Output, data= [ 0x82 ] 130 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Volatile Bitfield + Item(Local ): Usage, data= [ 0x45 ] 69 + Fast Blink On Time + Item(Main ): Output, data= [ 0x82 ] 130 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Volatile Bitfield + Item(Local ): Usage, data= [ 0x46 ] 70 + Fast Blink Off Time + Item(Main ): Output, data= [ 0x82 ] 130 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 5 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 16 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.0.6/plugins/ebitdo/ebitdo.quirk fwupd-1.2.10/plugins/ebitdo/ebitdo.quirk --- fwupd-1.0.6/plugins/ebitdo/ebitdo.quirk 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/ebitdo.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -1,43 +1,92 @@ -[FuEbitdoDevice] - # bootloader -USB\VID_0483&PID_5750=bootloader -USB\VID_2DC8&PID_5750=bootloader +[DeviceInstanceId=USB\VID_0483&PID_5750] +Plugin = ebitdo +Flags = is-bootloader +[DeviceInstanceId=USB\VID_2DC8&PID_5750] +Plugin = ebitdo +Flags = is-bootloader +InstallDuration = 120 +[DeviceInstanceId=USB\VID_0483&PID_5760] +Plugin = ebitdo +Flags = is-bootloader +InstallDuration = 120 # FC30 -USB\VID_1235&PID_AB11=none -USB\VID_2DC8&PID_AB11=none +[DeviceInstanceId=USB\VID_1235&PID_AB11] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_AB11] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # NES30 -USB\VID_1235&PID_AB12=none -USB\VID_2DC8&PID_AB12=none +[DeviceInstanceId=USB\VID_1235&PID_AB12] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_AB12] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # SFC30 -USB\VID_1235&PID_AB21=none -USB\VID_2DC8&PID_AB21=none +[DeviceInstanceId=USB\VID_1235&PID_AB21] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_AB21] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # SNES30 -USB\VID_1235&PID_AB20=none -USB\VID_2DC8&PID_AB20=none +[DeviceInstanceId=USB\VID_1235&PID_AB20] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_AB20] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # FC30PRO -USB\VID_1002&PID_9000=none -USB\VID_2DC8&PID_9000=none +[DeviceInstanceId=USB\VID_1002&PID_9000] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_9000] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # NES30PRO -USB\VID_2002&PID_9000=none -USB\VID_2DC8&PID_9001=none +[DeviceInstanceId=USB\VID_2002&PID_9000] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_9001] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # FC30_ARCADE -USB\VID_8000&PID_1002=none -USB\VID_2DC8&PID_1002=none +[DeviceInstanceId=USB\VID_8000&PID_1002] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_1002] +Plugin = ebitdo +Flags = none +InstallDuration = 120 # SF30 PRO/SN30 PRO -## Nintendo Switch mode (Start + Y) -USB\VID_057E&PID_2009=none ## Dinput mode (Start + B) -USB\VID_2DC8&PID_6000=none -USB\VID_2DC8&PID_6001=none -## Xinput mode (Start + X) -USB\VID_045E&PID_028E=none +[DeviceInstanceId=USB\VID_2DC8&PID_6000] +Plugin = ebitdo +Flags = none +[DeviceInstanceId=USB\VID_2DC8&PID_6001] +Plugin = ebitdo +Flags = none +InstallDuration = 120 + +# M30 +[DeviceInstanceId=USB\VID_2DC8&PID_5006] +Plugin = ebitdo +Flags = none +InstallDuration = 120 diff -Nru fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-common.c fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-common.c --- fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -80,20 +65,6 @@ } void -fu_ebitdo_dump_raw (const gchar *title, const guint8 *data, gsize len) -{ - g_print ("%s:", title); - for (gsize i = strlen (title); i < 16; i++) - g_print (" "); - for (gsize i = 0; i < len; i++) { - g_print ("%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_print ("\n"); - } - g_print ("\n"); -} - -void fu_ebitdo_dump_pkt (FuEbitdoPkt *hdr) { g_print ("PktLength: 0x%02x\n", hdr->pkt_len); diff -Nru fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-common.h fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-common.h --- fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_EBITDO_COMMON_H -#define __FU_EBITDO_COMMON_H +#pragma once #include @@ -85,8 +69,3 @@ const gchar *fu_ebitdo_pkt_type_to_string (FuEbitdoPktType type); void fu_ebitdo_dump_firmware_header (FuEbitdoFirmwareHeader *hdr); void fu_ebitdo_dump_pkt (FuEbitdoPkt *hdr); -void fu_ebitdo_dump_raw (const gchar *title, - const guint8 *data, - gsize len); - -#endif /* __FU_EBITDO_COMMON_H */ diff -Nru fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-device.c fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-device.c --- fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,51 +1,25 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include #include "fu-ebitdo-common.h" #include "fu-ebitdo-device.h" -typedef struct -{ - gboolean is_bootloader; +struct _FuEbitdoDevice { + FuUsbDevice parent_instance; guint32 serial[9]; -} FuEbitdoDevicePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (FuEbitdoDevice, fu_ebitdo_device, FU_TYPE_USB_DEVICE) +}; -#define GET_PRIVATE(o) (fu_ebitdo_device_get_instance_private (o)) - -gboolean -fu_ebitdo_device_is_bootloader (FuEbitdoDevice *self) -{ - FuEbitdoDevicePrivate *priv = GET_PRIVATE (self); - return priv->is_bootloader; -} +G_DEFINE_TYPE (FuEbitdoDevice, fu_ebitdo_device, FU_TYPE_USB_DEVICE) static gboolean -fu_ebitdo_device_send (FuEbitdoDevice *device, +fu_ebitdo_device_send (FuEbitdoDevice *self, FuEbitdoPktType type, FuEbitdoPktCmd subtype, FuEbitdoPktCmd cmd, @@ -53,8 +27,7 @@ gsize in_len, GError **error) { - FuEbitdoDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); guint8 packet[FU_EBITDO_USB_EP_SIZE] = {0}; gsize actual_length; guint8 ep_out = FU_EBITDO_USB_RUNTIME_EP_OUT; @@ -62,7 +35,7 @@ FuEbitdoPkt *hdr = (FuEbitdoPkt *) packet; /* different */ - if (priv->is_bootloader) + if (fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) ep_out = FU_EBITDO_USB_BOOTLOADER_EP_OUT; /* check size */ @@ -93,7 +66,7 @@ /* debug */ if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { - fu_ebitdo_dump_raw ("->DEVICE", packet, (gsize) hdr->pkt_len + 1); + fu_common_dump_raw (G_LOG_DOMAIN, "->DEVICE", packet, (gsize) hdr->pkt_len + 1); fu_ebitdo_dump_pkt (hdr); } @@ -118,13 +91,12 @@ } static gboolean -fu_ebitdo_device_receive (FuEbitdoDevice *device, +fu_ebitdo_device_receive (FuEbitdoDevice *self, guint8 *out, gsize out_len, GError **error) { - FuEbitdoDevicePrivate *priv = GET_PRIVATE (device); - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); guint8 packet[FU_EBITDO_USB_EP_SIZE] = {0}; gsize actual_length; guint8 ep_in = FU_EBITDO_USB_RUNTIME_EP_IN; @@ -132,7 +104,7 @@ FuEbitdoPkt *hdr = (FuEbitdoPkt *) packet; /* different */ - if (priv->is_bootloader) + if (fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) ep_in = FU_EBITDO_USB_BOOTLOADER_EP_IN; /* get data from device */ @@ -155,7 +127,7 @@ /* debug */ if (g_getenv ("FWUPD_EBITDO_VERBOSE") != NULL) { - fu_ebitdo_dump_raw ("<-DEVICE", packet, actual_length); + fu_common_dump_raw (G_LOG_DOMAIN, "<-DEVICE", packet, actual_length); fu_ebitdo_dump_pkt (hdr); } @@ -240,40 +212,33 @@ } static void -fu_ebitdo_device_set_version (FuEbitdoDevice *device, guint32 version) +fu_ebitdo_device_set_version (FuEbitdoDevice *self, guint32 version) { g_autofree gchar *tmp = NULL; - tmp = g_strdup_printf ("%.2f", version / 100.f); - fu_device_set_version (FU_DEVICE (device), tmp); + tmp = g_strdup_printf ("%u.%02u", version / 100, version % 100); + fu_device_set_version (FU_DEVICE (self), tmp, FWUPD_VERSION_FORMAT_PAIR); } static gboolean -fu_ebitdo_device_validate (FuEbitdoDevice *device, GError **error) +fu_ebitdo_device_validate (FuEbitdoDevice *self, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); - guint8 idx; - g_autofree gchar *ven = NULL; + const gchar *ven; const gchar *whitelist[] = { "8Bitdo", "SFC30", NULL }; /* this is a new, always valid, VID */ - if (g_usb_device_get_vid (usb_device) == 0x2dc8) - return TRUE; - - /* SF30/SN30 Pro when started with "START + Y" - * Emulates a "Nintendo Switch Pro Controller" - * "Real" Nintendo Switch controllers don't work over USB */ - if (g_usb_device_get_vid (usb_device) == 0x057e && - g_usb_device_get_pid (usb_device) == 0x2009) + if (fu_usb_device_get_vid (FU_USB_DEVICE (self)) == 0x2dc8) return TRUE; /* verify the vendor prefix against a whitelist */ - idx = g_usb_device_get_manufacturer_index (usb_device); - ven = g_usb_device_get_string_descriptor (usb_device, idx, error); + ven = fu_device_get_vendor (FU_DEVICE (self)); if (ven == NULL) { - g_prefix_error (error, "could not check vendor descriptor: "); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "could not check vendor descriptor: "); return FALSE; } for (guint i = 0; whitelist[i] != NULL; i++) { @@ -291,12 +256,8 @@ static gboolean fu_ebitdo_device_open (FuUsbDevice *device, GError **error) { - FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); - FuEbitdoDevicePrivate *priv = GET_PRIVATE (self); GUsbDevice *usb_device = fu_usb_device_get_dev (device); - gdouble tmp; - guint32 version_tmp = 0; - guint32 serial_tmp[9] = {0}; + FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); /* open, then ensure this is actually 8Bitdo hardware */ if (!fu_ebitdo_device_validate (self, error)) @@ -307,8 +268,20 @@ return FALSE; } + /* success */ + return TRUE; +} + +static gboolean +fu_ebitdo_device_setup (FuDevice *device, GError **error) +{ + FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); + gdouble tmp; + guint32 version_tmp = 0; + guint32 serial_tmp[9] = {0}; + /* in firmware mode */ - if (!priv->is_bootloader) { + if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { if (!fu_ebitdo_device_send (self, FU_EBITDO_PKT_TYPE_USER_CMD, FU_EBITDO_PKT_CMD_GET_VERSION, @@ -361,23 +334,25 @@ return FALSE; } for (guint i = 0; i < 9; i++) - priv->serial[i] = GUINT32_FROM_LE (serial_tmp[i]); + self->serial[i] = GUINT32_FROM_LE (serial_tmp[i]); /* success */ return TRUE; } const guint32 * -fu_ebitdo_device_get_serial (FuEbitdoDevice *device) +fu_ebitdo_device_get_serial (FuEbitdoDevice *self) { - FuEbitdoDevicePrivate *priv = GET_PRIVATE (device); - return priv->serial; + return self->serial; } -gboolean -fu_ebitdo_device_write_firmware (FuEbitdoDevice *device, GBytes *fw, GError **error) +static gboolean +fu_ebitdo_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) { - FuEbitdoDevicePrivate *priv = GET_PRIVATE (device); + FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); FuEbitdoFirmwareHeader *hdr; const guint8 *payload_data; const guint chunk_sz = 32; @@ -391,6 +366,48 @@ 0xb91901c9, 0x3917edfe, 0xbcd6344f, 0xcf9e23b5 }; + /* not in bootloader mode, so print what to do */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + g_autoptr(GString) msg = g_string_new ("Not in bootloader mode: "); + g_string_append (msg, "Disconnect the controller, "); + g_print ("1. \n"); + switch (g_usb_device_get_pid (usb_device)) { + case 0xab11: /* FC30 */ + case 0xab12: /* NES30 */ + case 0xab21: /* SFC30 */ + case 0xab20: /* SNES30 */ + g_string_append (msg, "hold down L+R+START for 3 seconds until " + "both LED lights flashing, "); + break; + case 0x9000: /* FC30PRO */ + case 0x9001: /* NES30PRO */ + g_string_append (msg, "hold down RETURN+POWER for 3 seconds until " + "both LED lights flashing, "); + break; + case 0x1002: /* FC30-ARCADE */ + g_string_append (msg, "hold down L1+R1+HOME for 3 seconds until " + "both blue LED and green LED blink, "); + break; + case 0x6000: /* SF30 pro: Dinput mode */ + case 0x6001: /* SN30 pro: Dinput mode */ + case 0x028e: /* SF30/SN30 pro: Xinput mode */ + case 0x5006: /* M30 */ + g_string_append (msg, "press and hold L1+R1+START for 3 seconds " + "until the LED on top blinks red, "); + break; + default: + g_string_append (msg, "do what it says in the manual, "); + break; + } + g_string_append (msg, "then re-connect controller"); + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + msg->str); + return FALSE; + } + /* corrupt */ if (g_bytes_get_size (fw) < sizeof (FuEbitdoFirmwareHeader)) { g_set_error_literal (error, @@ -429,8 +446,8 @@ } /* set up the firmware header */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_DEVICE_WRITE); - if (!fu_ebitdo_device_send (device, + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + if (!fu_ebitdo_device_send (self, FU_EBITDO_PKT_TYPE_USER_CMD, FU_EBITDO_PKT_CMD_UPDATE_FIRMWARE_DATA, FU_EBITDO_PKT_CMD_FW_UPDATE_HEADER, @@ -443,7 +460,7 @@ error_local->message); return FALSE; } - if (!fu_ebitdo_device_receive (device, NULL, 0, &error_local)) { + if (!fu_ebitdo_device_receive (self, NULL, 0, &error_local)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, @@ -460,8 +477,8 @@ g_debug ("writing %u bytes to 0x%04x of 0x%04x", chunk_sz, offset, payload_len); } - fu_device_set_progress_full (FU_DEVICE (device), offset, payload_len); - if (!fu_ebitdo_device_send (device, + fu_device_set_progress_full (device, offset, payload_len); + if (!fu_ebitdo_device_send (self, FU_EBITDO_PKT_TYPE_USER_CMD, FU_EBITDO_PKT_CMD_UPDATE_FIRMWARE_DATA, FU_EBITDO_PKT_CMD_FW_UPDATE_DATA, @@ -474,7 +491,7 @@ offset, error_local->message); return FALSE; } - if (!fu_ebitdo_device_receive (device, NULL, 0, &error_local)) { + if (!fu_ebitdo_device_receive (self, NULL, 0, &error_local)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, @@ -485,15 +502,15 @@ } /* mark as complete */ - fu_device_set_progress_full (FU_DEVICE (device), payload_len, payload_len); + fu_device_set_progress_full (device, payload_len, payload_len); /* set the "encode id" which is likely a checksum, bluetooth pairing * or maybe just security-through-obscurity -- also note: * SET_ENCODE_ID enforces no read for success?! */ - serial_new[0] = priv->serial[0] ^ app_key_index[priv->serial[0] & 0x0f]; - serial_new[1] = priv->serial[1] ^ app_key_index[priv->serial[1] & 0x0f]; - serial_new[2] = priv->serial[2] ^ app_key_index[priv->serial[2] & 0x0f]; - if (!fu_ebitdo_device_send (device, + serial_new[0] = self->serial[0] ^ app_key_index[self->serial[0] & 0x0f]; + serial_new[1] = self->serial[1] ^ app_key_index[self->serial[1] & 0x0f]; + serial_new[2] = self->serial[2] ^ app_key_index[self->serial[2] & 0x0f]; + if (!fu_ebitdo_device_send (self, FU_EBITDO_PKT_TYPE_USER_CMD, FU_EBITDO_PKT_CMD_UPDATE_FIRMWARE_DATA, FU_EBITDO_PKT_CMD_FW_SET_ENCODE_ID, @@ -509,7 +526,7 @@ } /* mark flash as successful */ - if (!fu_ebitdo_device_send (device, + if (!fu_ebitdo_device_send (self, FU_EBITDO_PKT_TYPE_USER_CMD, FU_EBITDO_PKT_CMD_UPDATE_FIRMWARE_DATA, FU_EBITDO_PKT_CMD_FW_UPDATE_OK, @@ -522,7 +539,7 @@ error_local->message); return FALSE; } - if (!fu_ebitdo_device_receive (device, NULL, 0, &error_local)) { + if (!fu_ebitdo_device_receive (self, NULL, 0, &error_local)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, @@ -532,7 +549,6 @@ } /* success! */ - fu_device_set_status (FU_DEVICE (device), FWUPD_STATUS_IDLE); return TRUE; } @@ -540,19 +556,6 @@ fu_ebitdo_device_probe (FuUsbDevice *device, GError **error) { FuEbitdoDevice *self = FU_EBITDO_DEVICE (device); - FuEbitdoDevicePrivate *priv = GET_PRIVATE (self); - const gchar *quirk_str; - - /* devices have to be whitelisted */ - quirk_str = fu_device_get_plugin_hints (FU_DEVICE (device)); - if (quirk_str == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported with this device"); - return FALSE; - } - priv->is_bootloader = g_strcmp0 (quirk_str, "bootloader") == 0; /* allowed, but requires manual bootloader step */ fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); @@ -567,14 +570,11 @@ fu_device_add_icon (FU_DEVICE (device), "input-gaming"); /* only the bootloader can do the update */ - if (!priv->is_bootloader) { - fu_device_add_guid (FU_DEVICE (device), "USB\\VID_0483&PID_5750"); - fu_device_add_guid (FU_DEVICE (device), "USB\\VID_2DC8&PID_5750"); + if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_add_counterpart_guid (FU_DEVICE (device), "USB\\VID_0483&PID_5750"); + fu_device_add_counterpart_guid (FU_DEVICE (device), "USB\\VID_2DC8&PID_5750"); fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); - } else { - fu_device_remove_flag (FU_DEVICE (device), - FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); } /* success */ @@ -582,14 +582,17 @@ } static void -fu_ebitdo_device_init (FuEbitdoDevice *device) +fu_ebitdo_device_init (FuEbitdoDevice *self) { } static void fu_ebitdo_device_class_init (FuEbitdoDeviceClass *klass) { + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_ebitdo_device_write_firmware; + klass_device->setup = fu_ebitdo_device_setup; klass_usb_device->open = fu_ebitdo_device_open; klass_usb_device->probe = fu_ebitdo_device_probe; } @@ -604,11 +607,10 @@ * Since: 0.1.0 **/ FuEbitdoDevice * -fu_ebitdo_device_new (GUsbDevice *usb_device) +fu_ebitdo_device_new (FuUsbDevice *device) { - FuEbitdoDevice *device; - device = g_object_new (FU_TYPE_EBITDO_DEVICE, - "usb-device", usb_device, - NULL); - return FU_EBITDO_DEVICE (device); + FuEbitdoDevice *self; + self = g_object_new (FU_TYPE_EBITDO_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return FU_EBITDO_DEVICE (self); } diff -Nru fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-device.h fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-device.h --- fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,53 +1,21 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_EBITDO_DEVICE_H -#define __FU_EBITDO_DEVICE_H - -#include -#include +#pragma once #include "fu-plugin.h" G_BEGIN_DECLS #define FU_TYPE_EBITDO_DEVICE (fu_ebitdo_device_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuEbitdoDevice, fu_ebitdo_device, FU, EBITDO_DEVICE, FuUsbDevice) - -struct _FuEbitdoDeviceClass -{ - FuUsbDeviceClass parent_class; -}; +G_DECLARE_FINAL_TYPE (FuEbitdoDevice, fu_ebitdo_device, FU, EBITDO_DEVICE, FuUsbDevice) -FuEbitdoDevice *fu_ebitdo_device_new (GUsbDevice *usb_device); +FuEbitdoDevice *fu_ebitdo_device_new (FuUsbDevice *device); /* getters */ -gboolean fu_ebitdo_device_is_bootloader (FuEbitdoDevice *device); const guint32 *fu_ebitdo_device_get_serial (FuEbitdoDevice *device); -/* object methods */ -gboolean fu_ebitdo_device_write_firmware (FuEbitdoDevice *device, - GBytes *fw, - GError **error); - G_END_DECLS - -#endif /* __FU_EBITDO_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-tool.c fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-tool.c --- fwupd-1.0.6/plugins/ebitdo/fu-ebitdo-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/fu-ebitdo-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#include "config.h" - -#include - -#include "fu-ebitdo-common.h" -#include "fu-ebitdo-device.h" - - -static void -fu_ebitdo_tool_progress_cb (FuDevice *device, GParamSpec *pspec, gpointer user_data) -{ - g_print ("Written %u%%\n", fu_device_get_progress (device)); -} - -int -main (int argc, char **argv) -{ - gsize len; - g_autofree guint8 *data = NULL; - g_autoptr(FuEbitdoDevice) dev = NULL; - g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuQuirks) quirks = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GPtrArray) devices = NULL; - g_autoptr(GUsbContext) usb_ctx = NULL; - - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - - /* require filename */ - if (argc != 2) { - g_print ("USAGE: %s \n", argv[0]); - return 1; - } - - /* use quirks */ - quirks = fu_quirks_new (); - if (!fu_quirks_load (quirks, &error)) { - g_print ("Failed to load quirks: %s\n", error->message); - return 1; - } - - /* get the device */ - usb_ctx = g_usb_context_new (&error); - if (usb_ctx == NULL) { - g_print ("Failed to open USB devices: %s\n", error->message); - return 1; - } - g_usb_context_enumerate (usb_ctx); - devices = g_usb_context_get_devices (usb_ctx); - for (guint i = 0; i < devices->len; i++) { - GUsbDevice *usb_device = g_ptr_array_index (devices, i); - g_autoptr(FuEbitdoDevice) dev_tmp = fu_ebitdo_device_new (usb_device); - fu_device_set_quirks (FU_DEVICE (dev_tmp), quirks); - if (fu_usb_device_probe (FU_USB_DEVICE (dev_tmp), NULL)) { - dev = g_steal_pointer (&dev_tmp); - break; - } - } - - /* nothing supported */ - if (dev == NULL) { - g_print ("No supported device plugged in!\n"); - return 1; - } - - /* open device */ - locker = fu_device_locker_new (dev, &error); - if (locker == NULL) { - g_print ("Failed to open USB device: %s\n", error->message); - return 1; - } - g_print ("Device Firmware Ver: %s\n", - fu_device_get_version (FU_DEVICE (dev))); - g_print ("Device Verification ID:\n"); - for (guint i = 0; i < 9; i++) - g_print ("\t%u = 0x%08x\n", i, fu_ebitdo_device_get_serial(dev)[i]); - - /* not in bootloader mode, so print what to do */ - if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { - GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (dev)); - g_print ("1. Disconnect the controller\n"); - switch (g_usb_device_get_pid (usb_device)) { - case 0xab11: /* FC30 */ - case 0xab12: /* NES30 */ - case 0xab21: /* SFC30 */ - case 0xab20: /* SNES30 */ - g_print ("2. Hold down L+R+START for 3 seconds until " - "both LED lights flashing.\n"); - break; - case 0x9000: /* FC30PRO */ - case 0x9001: /* NES30PRO */ - g_print ("2. Hold down RETURN+POWER for 3 seconds until " - "both LED lights flashing.\n"); - break; - case 0x1002: /* FC30-ARCADE */ - g_print ("2. Hold down L1+R1+HOME for 3 seconds until " - "both blue LED and green LED blink.\n"); - break; - case 0x2009: /* SF30/SN30 pro: switch mode */ - case 0x6000: /* SF30 pro: Dinput mode */ - case 0x6001: /* SN30 pro: Dinput mode */ - case 0x028e: /* SF30/SN30 pro: Xinput mode */ - g_print ("2. Press and hold L1+R1+START for 3 seconds " - "until the LED on top blinks red.\n"); - break; - default: - g_print ("2. Do what it says in the manual.\n"); - break; - } - g_print ("3. Connect controller\n"); - return 1; - } - - /* load firmware file */ - if (!g_file_get_contents (argv[1], (gchar **) &data, &len, &error)) { - g_print ("Failed to load file: %s\n", error->message); - return 1; - } - - /* update with data blob */ - fw = g_bytes_new (data, len); - g_signal_connect (dev, "notify::progress", - G_CALLBACK (fu_ebitdo_tool_progress_cb), NULL); - if (!fu_ebitdo_device_write_firmware (dev, fw, &error)) { - g_print ("Failed to write firmware: %s\n", error->message); - return 1; - } - - /* success */ - g_print ("Now turn off the controller with the power button.\n"); - - return 0; -} diff -Nru fwupd-1.0.6/plugins/ebitdo/fu-plugin-ebitdo.c fwupd-1.2.10/plugins/ebitdo/fu-plugin-ebitdo.c --- fwupd-1.0.6/plugins/ebitdo/fu-plugin-ebitdo.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/fu-plugin-ebitdo.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,46 +1,37 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include "fu-ebitdo-device.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.8bitdo"); +} + gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuEbitdoDevice) device = NULL; + g_autoptr(FuEbitdoDevice) dev = NULL; /* open the device */ - device = fu_ebitdo_device_new (usb_device); - fu_device_set_quirks (FU_DEVICE (device), fu_plugin_get_quirks (plugin)); - locker = fu_device_locker_new (device, error); + dev = fu_ebitdo_device_new (device); + locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; /* success */ - fu_plugin_device_add (plugin, FU_DEVICE (device)); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } @@ -54,10 +45,9 @@ GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (dev)); FuEbitdoDevice *ebitdo_dev = FU_EBITDO_DEVICE (dev); g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(GUsbDevice) usb_device2 = NULL; /* get version */ - if (!fu_ebitdo_device_is_bootloader (ebitdo_dev)) { + if (!fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -69,7 +59,7 @@ locker = fu_device_locker_new (ebitdo_dev, error); if (locker == NULL) return FALSE; - if (!fu_ebitdo_device_write_firmware (ebitdo_dev, blob_fw, error)) + if (!fu_device_write_firmware (FU_DEVICE (ebitdo_dev), blob_fw, flags, error)) return FALSE; /* when doing a soft-reboot the device does not re-enumerate properly @@ -79,16 +69,9 @@ g_prefix_error (error, "failed to force-reset device: "); return FALSE; } - g_clear_object (&locker); - usb_device2 = g_usb_context_wait_for_replug (fu_plugin_get_usb_context (plugin), - usb_device, 10000, error); - if (usb_device2 == NULL) { - g_prefix_error (error, "device did not come back: "); - return FALSE; - } - fu_usb_device_set_dev (FU_USB_DEVICE (ebitdo_dev), usb_device2); - /* success */ + /* wait for replug */ + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); return TRUE; } diff -Nru fwupd-1.0.6/plugins/ebitdo/meson.build fwupd-1.2.10/plugins/ebitdo/meson.build --- fwupd-1.0.6/plugins/ebitdo/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -5,6 +5,7 @@ ) shared_module('fu_plugin_ebitdo', + fu_hash, sources : [ 'fu-plugin-ebitdo.c', 'fu-ebitdo-common.c', @@ -17,30 +18,11 @@ ], install : true, install_dir: plugin_dir, - c_args : cargs, - dependencies : [ - plugin_deps, - ], -) - -executable( - 'fu-ebitdo-tool', - sources : [ - 'fu-ebitdo-tool.c', - 'fu-ebitdo-common.c', - 'fu-ebitdo-device.c', - ], - include_directories : [ - include_directories('../..'), - include_directories('../../libfwupd'), - include_directories('../../src'), - ], - dependencies : [ - plugin_deps, - ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs, + dependencies : [ + plugin_deps, + ], ) diff -Nru fwupd-1.0.6/plugins/ebitdo/README.md fwupd-1.2.10/plugins/ebitdo/README.md --- fwupd-1.0.6/plugins/ebitdo/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/ebitdo/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -11,3 +11,23 @@ The 8Bitdo devices share legacy USB VID/PIDs with other projects and so we have to be a bit careful to not claim other devices as our own. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. The binary file has a vendor-specific header +that is used when flashing the image. + +This plugin supports the following protocol ID: + + * com.8bitdo + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_2DC8&PID_AB11&REV_0001` + * `USB\VID_2DC8&PID_AB11` + * `USB\VID_2DC8` diff -Nru fwupd-1.0.6/plugins/fastboot/data/android/flashfile.xml fwupd-1.2.10/plugins/fastboot/data/android/flashfile.xml --- fwupd-1.0.6/plugins/fastboot/data/android/flashfile.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/data/android/flashfile.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru fwupd-1.0.6/plugins/fastboot/data/lsusb.txt fwupd-1.2.10/plugins/fastboot/data/lsusb.txt --- fwupd-1.0.6/plugins/fastboot/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/data/lsusb.txt 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,58 @@ +Bus 001 Device 025: ID 18d1:4ee0 Google Inc. Nexus 4 (bootloader) +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x18d1 Google Inc. + idProduct 0x4ee0 Nexus 4 (bootloader) + bcdDevice 1.00 + iManufacturer 1 Google + iProduct 2 Android + iSerial 3 034412a082919b5c + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 66 + bInterfaceProtocol 3 + iInterface 4 fastboot + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.0.6/plugins/fastboot/data/qfil/partition_nand.xml fwupd-1.2.10/plugins/fastboot/data/qfil/partition_nand.xml --- fwupd-1.0.6/plugins/fastboot/data/qfil/partition_nand.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/data/qfil/partition_nand.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,21 @@ + + + + 0xAA7D1B9A + 0x1F7D48BC + + 0x4 + + + 0:SBL + 0x8 + 0x2 + 0 + 0xFF + 0x01 + 0x00 + 0xFE + sbl1.mbn + + + diff -Nru fwupd-1.0.6/plugins/fastboot/fastboot.quirk fwupd-1.2.10/plugins/fastboot/fastboot.quirk --- fwupd-1.0.6/plugins/fastboot/fastboot.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/fastboot.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +# All fastboot devices +[DeviceInstanceId=USB\CLASS_FF&SUBCLASS_42&PROT_03] +Plugin = fastboot diff -Nru fwupd-1.0.6/plugins/fastboot/fu-fastboot-device.c fwupd-1.2.10/plugins/fastboot/fu-fastboot-device.c --- fwupd-1.0.6/plugins/fastboot/fu-fastboot-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/fu-fastboot-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,714 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-archive.h" +#include "fu-chunk.h" +#include "fu-fastboot-device.h" + +#define FASTBOOT_REMOVE_DELAY_RE_ENUMERATE 60000 /* ms */ +#define FASTBOOT_TRANSACTION_TIMEOUT 1000 /* ms */ +#define FASTBOOT_TRANSACTION_RETRY_MAX 600 +#define FASTBOOT_EP_IN 0x81 +#define FASTBOOT_EP_OUT 0x01 +#define FASTBOOT_CMD_BUFSZ 64 /* bytes */ + +struct _FuFastbootDevice { + FuUsbDevice parent_instance; + gboolean secure; + guint blocksz; + guint8 intf_nr; +}; + +G_DEFINE_TYPE (FuFastbootDevice, fu_fastboot_device, FU_TYPE_USB_DEVICE) + +static void +fu_fastboot_device_to_string (FuDevice *device, GString *str) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + g_string_append (str, " FuFastbootDevice:\n"); + g_string_append_printf (str, " intf:\t0x%02x\n", (guint) self->intf_nr); + g_string_append_printf (str, " secure:\t%i\n", self->secure); + g_string_append_printf (str, " blocksz:\t%u\n", self->blocksz); +} + +static gboolean +fu_fastboot_device_probe (FuDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autoptr(GUsbInterface) intf = NULL; + + /* find the correct fastboot interface */ + intf = g_usb_device_get_interface (usb_device, 0xff, 0x42, 0x03, error); + if (intf == NULL) + return FALSE; + self->intf_nr = g_usb_interface_get_number (intf); + return TRUE; +} + +static gboolean +fu_fastboot_device_open (FuUsbDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + if (!g_usb_device_claim_interface (usb_device, self->intf_nr, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_fastboot_buffer_dump (const gchar *title, const guint8 *buf, gsize sz) +{ + if (g_getenv ("FWUPD_FASTBOOT_VERBOSE") == NULL) + return; + g_print ("%s (%" G_GSIZE_FORMAT "):\n", title, sz); + for (gsize i = 0; i < sz; i++) { + g_print ("%02x[%c] ", buf[i], g_ascii_isprint (buf[i]) ? buf[i] : '?'); + if (i > 0 && (i + 1) % 256 == 0) + g_print ("\n"); + } + g_print ("\n"); +} + +static gboolean +fu_fastboot_device_write (FuDevice *device, const guint8 *buf, gsize buflen, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gboolean ret; + gsize actual_len = 0; + g_autofree guint8 *buf2 = g_memdup (buf, (guint) buflen); + + fu_fastboot_buffer_dump ("writing", buf, buflen); + ret = g_usb_device_bulk_transfer (usb_device, + FASTBOOT_EP_OUT, + buf2, + buflen, + &actual_len, + FASTBOOT_TRANSACTION_TIMEOUT, + NULL, error); + if (!ret) { + g_prefix_error (error, "failed to do bulk transfer: "); + return FALSE; + } + if (actual_len != buflen) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_fastboot_device_writestr (FuDevice *device, const gchar *str, GError **error) +{ + gsize buflen = strlen (str); + if (buflen > FASTBOOT_CMD_BUFSZ - 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "fastboot limits writes to %i bytes", + FASTBOOT_CMD_BUFSZ - 4); + return FALSE; + } + return fu_fastboot_device_write (device, (const guint8 *) str, buflen, error); +} + +typedef enum { + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, +} FuFastbootDeviceReadFlags; + +static gboolean +fu_fastboot_device_read (FuDevice *device, + gchar **str, + FuFastbootDeviceReadFlags flags, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + guint retries = 1; + + /* these commands may return INFO or take some time to complete */ + if (flags & FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL) + retries = FASTBOOT_TRANSACTION_RETRY_MAX; + + for (guint i = 0; i < retries; i++) { + gboolean ret; + gsize actual_len = 0; + guint8 buf[FASTBOOT_CMD_BUFSZ] = { 0x00 }; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error_local = NULL; + + ret = g_usb_device_bulk_transfer (usb_device, + FASTBOOT_EP_IN, + buf, + sizeof(buf), + &actual_len, + FASTBOOT_TRANSACTION_TIMEOUT, + NULL, &error_local); + if (!ret) { + if (g_error_matches (error_local, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_TIMED_OUT)) { + g_debug ("ignoring %s", error_local->message); + continue; + } + g_propagate_prefixed_error (error, + g_steal_pointer (&error_local), + "failed to do bulk transfer: "); + return FALSE; + } + fu_fastboot_buffer_dump ("read", buf, actual_len); + if (actual_len < 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + /* info */ + tmp = g_strndup ((const gchar *) buf + 4, self->blocksz - 4); + if (memcmp (buf, "INFO", 4) == 0) { + if (g_strcmp0 (tmp, "erasing flash") == 0) + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + else if (g_strcmp0 (tmp, "writing flash") == 0) + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + else + g_debug ("INFO returned unknown: %s", tmp); + continue; + } + + /* success */ + if (memcmp (buf, "OKAY", 4) == 0 || memcmp (buf, "DATA", 4) == 0) { + if (str != NULL) + *str = g_steal_pointer (&tmp); + return TRUE; + } + + /* failure */ + if (memcmp (buf, "FAIL", 4) == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read response: %s", tmp); + return FALSE; + } + + /* unknown failure */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read response"); + return FALSE; + } + + /* we timed out a *lot* */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no response to read"); + return FALSE; +} + +static gboolean +fu_fastboot_device_getvar (FuDevice *device, const gchar *key, gchar **str, GError **error) +{ + g_autofree gchar *tmp = g_strdup_printf ("getvar:%s", key); + if (!fu_fastboot_device_writestr (device, tmp, error)) + return FALSE; + if (!fu_fastboot_device_read (device, str, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_cmd (FuDevice *device, const gchar *cmd, + FuFastbootDeviceReadFlags flags, GError **error) +{ + if (!fu_fastboot_device_writestr (device, cmd, error)) + return FALSE; + if (!fu_fastboot_device_read (device, NULL, flags, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_flash (FuDevice *device, const gchar *partition, GError **error) +{ + g_autofree gchar *tmp = g_strdup_printf ("flash:%s", partition); + return fu_fastboot_device_cmd (device, tmp, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, + error); +} + +static gboolean +fu_fastboot_device_download (FuDevice *device, GBytes *fw, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + gsize sz = g_bytes_get_size (fw); + g_autofree gchar *tmp = g_strdup_printf ("download:%08x", (guint) sz); + g_autoptr(GPtrArray) chunks = NULL; + + /* tell the client the size of data to expect */ + if (!fu_fastboot_device_cmd (device, tmp, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, + error)) + return FALSE; + + /* send the data in chunks */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + self->blocksz); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_fastboot_device_write (device, chk->data, chk->data_sz, error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len * 2); + } + if (!fu_fastboot_device_read (device, NULL, + FU_FASTBOOT_DEVICE_READ_FLAG_STATUS_POLL, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_fastboot_device_setup (FuDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + g_autofree gchar *product = NULL; + g_autofree gchar *serialno = NULL; + g_autofree gchar *version = NULL; + g_autofree gchar *secure = NULL; + g_autofree gchar *version_bootloader = NULL; + + /* product */ + if (!fu_fastboot_device_getvar (device, "product", &product, error)) + return FALSE; + if (product != NULL && product[0] != '\0') { + g_autofree gchar *tmp = g_strdup_printf ("Fastboot %s", product); + fu_device_set_name (device, tmp); + } + + /* fastboot API version */ + if (!fu_fastboot_device_getvar (device, "version", &version, error)) + return FALSE; + if (version != NULL && version[0] != '\0') + g_debug ("fastboot version=%s", version); + + /* bootloader version */ + if (!fu_fastboot_device_getvar (device, "version-bootloader", &version_bootloader, error)) + return FALSE; + if (version_bootloader != NULL && version_bootloader[0] != '\0') + fu_device_set_version_bootloader (device, version_bootloader); + + /* serialno */ + if (!fu_fastboot_device_getvar (device, "serialno", &serialno, error)) + return FALSE; + if (serialno != NULL && serialno[0] != '\0') + fu_device_set_serial (device, serialno); + + /* secure */ + if (!fu_fastboot_device_getvar (device, "secure", &secure, error)) + return FALSE; + if (secure != NULL && secure[0] != '\0') + self->secure = TRUE; + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_qfil_part (FuDevice *device, + FuArchive *archive, + XbNode *part, + GError **error) +{ + GBytes *data; + const gchar *fn; + const gchar *partition; + + /* not all partitions have images */ + fn = xb_node_query_text (part, "img_name", NULL); + if (fn == NULL) + return TRUE; + + /* find filename */ + data = fu_archive_lookup_by_fn (archive, fn, error); + if (data == NULL) + return FALSE; + + /* get the partition name */ + partition = xb_node_query_text (part, "name", error); + if (partition == NULL) + return FALSE; + if (g_str_has_prefix (partition, "0:")) + partition += 2; + + /* flash the partition */ + if (!fu_fastboot_device_download (device, data, error)) + return FALSE; + return fu_fastboot_device_flash (device, partition, error); +} + +static gboolean +fu_fastboot_device_write_motorola_part (FuDevice *device, + FuArchive *archive, + XbNode *part, + GError **error) +{ + const gchar *op = xb_node_get_attr (part, "operation"); + + /* oem */ + if (g_strcmp0 (op, "oem") == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "OEM commands are not supported"); + return FALSE; + } + + /* getvar */ + if (g_strcmp0 (op, "getvar") == 0) { + const gchar *var = xb_node_get_attr (part, "var"); + g_autofree gchar *tmp = NULL; + + /* check required args */ + if (var == NULL) { + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required var for part: %s", tmp); + return FALSE; + } + + /* just has to be non-empty */ + if (!fu_fastboot_device_getvar (device, var, &tmp, error)) + return FALSE; + if (tmp == NULL || tmp[0] == '\0') { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to getvar %s", var); + return FALSE; + } + return TRUE; + } + + /* erase */ + if (g_strcmp0 (op, "erase") == 0) { + const gchar *partition = xb_node_get_attr (part, "partition"); + g_autofree gchar *cmd = g_strdup_printf ("erase:%s", partition); + + /* check required args */ + if (partition == NULL) { + g_autofree gchar *tmp = NULL; + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required partition for part: %s", tmp); + return FALSE; + } + + /* erase the partition */ + return fu_fastboot_device_cmd (device, cmd, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); + } + + /* flash */ + if (g_strcmp0 (op, "flash") == 0) { + GBytes *data; + const gchar *filename = xb_node_get_attr (part, "filename"); + const gchar *partition = xb_node_get_attr (part, "partition"); + struct { + GChecksumType kind; + const gchar *str; + } csum_kinds[] = { + { G_CHECKSUM_MD5, "MD5" }, + { G_CHECKSUM_SHA1, "SHA1" }, + { 0, NULL } + }; + + /* check required args */ + if (partition == NULL || filename == NULL) { + g_autofree gchar *tmp = NULL; + tmp = xb_node_export (part, XB_NODE_EXPORT_FLAG_NONE, NULL); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "required partition and filename: %s", tmp); + return FALSE; + } + + /* find filename */ + data = fu_archive_lookup_by_fn (archive, filename, error); + if (data == NULL) + return FALSE; + + /* checksum is optional */ + for (guint i = 0; csum_kinds[i].str != NULL; i++) { + const gchar *csum; + g_autofree gchar *csum_actual = NULL; + + /* not provided */ + csum = xb_node_get_attr (part, csum_kinds[i].str); + if (csum == NULL) + continue; + + /* check is valid */ + csum_actual = g_compute_checksum_for_bytes (csum_kinds[i].kind, data); + if (g_strcmp0 (csum, csum_actual) != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%s invalid, expected %s, got %s", + filename, csum, csum_actual); + return FALSE; + } + } + + /* flash the partition */ + if (!fu_fastboot_device_download (device, data, error)) + return FALSE; + return fu_fastboot_device_flash (device, partition, error); + } + + /* dumb operation that doesn't expect a response */ + if (g_strcmp0 (op, "boot") == 0 || + g_strcmp0 (op, "continue") == 0 || + g_strcmp0 (op, "reboot") == 0 || + g_strcmp0 (op, "reboot-bootloader") == 0 || + g_strcmp0 (op, "powerdown") == 0) { + return fu_fastboot_device_cmd (device, op, + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); + } + + /* unknown */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown operation %s", op); + return FALSE; +} + +static gboolean +fu_fastboot_device_write_motorola (FuDevice *device, + FuArchive* archive, + GError **error) +{ + GBytes *data; + g_autoptr(GPtrArray) parts = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load the manifest of operations */ + data = fu_archive_lookup_by_fn (archive, "flashfile.xml", error); + if (data == NULL) + return FALSE; + if (!xb_builder_source_load_bytes (source, data, + XB_BUILDER_SOURCE_FLAG_NONE, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + + /* get all the operation parts */ + parts = xb_silo_query (silo, "parts/part", 0, error); + if (parts == NULL) + return FALSE; + for (guint i = 0; i < parts->len; i++) { + XbNode *part = g_ptr_array_index (parts, i); + if (!fu_fastboot_device_write_motorola_part (device, + archive, + part, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_qfil (FuDevice *device, FuArchive* archive, GError **error) +{ + GBytes *data; + g_autoptr(GPtrArray) parts = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load the manifest of operations */ + data = fu_archive_lookup_by_fn (archive, "partition_nand.xml", error); + if (data == NULL) + return FALSE; + if (!xb_builder_source_load_bytes (source, data, + XB_BUILDER_SOURCE_FLAG_NONE, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + + /* get all the operation parts */ + parts = xb_silo_query (silo, "nandboot/partitions/partition", 0, error); + if (parts == NULL) + return FALSE; + for (guint i = 0; i < parts->len; i++) { + XbNode *part = g_ptr_array_index (parts, i); + if (!fu_fastboot_device_write_qfil_part (device, + archive, + part, + error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuArchive) archive = NULL; + + /* decompress entire archive ahead of time */ + archive = fu_archive_new (fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error); + if (archive == NULL) + return FALSE; + + /* load the manifest of operations */ + if (fu_archive_lookup_by_fn (archive, "partition_nand.xml", NULL) != NULL) + return fu_fastboot_device_write_qfil (device, archive, error); + if (fu_archive_lookup_by_fn (archive, "flashfile.xml", NULL) != NULL) { + return fu_fastboot_device_write_motorola (device, + archive, + error); + } + + /* not supported */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "manifest not supported"); + return FALSE; +} + +static gboolean +fu_fastboot_device_close (FuUsbDevice *device, GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* we're done here */ + if (!g_usb_device_release_interface (usb_device, self->intf_nr, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_fastboot_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuFastbootDevice *self = FU_FASTBOOT_DEVICE (device); + + /* load slave address from quirks */ + if (g_strcmp0 (key, "FastbootBlockSize") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp >= 0x40 && tmp < 0x100000) { + self->blocksz = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid block size"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; + +} + +static gboolean +fu_fastboot_device_attach (FuDevice *device, GError **error) +{ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + return fu_fastboot_device_cmd (device, "reboot", + FU_FASTBOOT_DEVICE_READ_FLAG_NONE, + error); +} + +static void +fu_fastboot_device_init (FuFastbootDevice *self) +{ + /* this is a safe default, even using USBv1 */ + self->blocksz = 512; + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_remove_delay (FU_DEVICE (self), FASTBOOT_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_fastboot_device_class_init (FuFastbootDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->probe = fu_fastboot_device_probe; + klass_device->setup = fu_fastboot_device_setup; + klass_device->write_firmware = fu_fastboot_device_write_firmware; + klass_device->attach = fu_fastboot_device_attach; + klass_device->to_string = fu_fastboot_device_to_string; + klass_device->set_quirk_kv = fu_fastboot_device_set_quirk_kv; + klass_usb_device->open = fu_fastboot_device_open; + klass_usb_device->close = fu_fastboot_device_close; +} + +FuFastbootDevice * +fu_fastboot_device_new (FuUsbDevice *device) +{ + FuFastbootDevice *self = g_object_new (FU_TYPE_FASTBOOT_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/fastboot/fu-fastboot-device.h fwupd-1.2.10/plugins/fastboot/fu-fastboot-device.h --- fwupd-1.0.6/plugins/fastboot/fu-fastboot-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/fu-fastboot-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_FASTBOOT_DEVICE (fu_fastboot_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuFastbootDevice, fu_fastboot_device, FU, FASTBOOT_DEVICE, FuUsbDevice) + +FuFastbootDevice *fu_fastboot_device_new (FuUsbDevice *device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/fastboot/fu-plugin-fastboot.c fwupd-1.2.10/plugins/fastboot/fu-plugin-fastboot.c --- fwupd-1.0.6/plugins/fastboot/fu-plugin-fastboot.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/fu-plugin-fastboot.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-fastboot-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.google.fastboot"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* reset */ + if (!fu_device_attach (device, error)) + return FALSE; + + /* wait for replug */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuFastbootDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + dev = fu_fastboot_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/fastboot/meson.build fwupd-1.2.10/plugins/fastboot/meson.build --- fwupd-1.0.6/plugins/fastboot/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,27 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginFastboot"'] + +install_data(['fastboot.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_fastboot', + fu_hash, + sources : [ + 'fu-plugin-fastboot.c', + 'fu-fastboot-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff -Nru fwupd-1.0.6/plugins/fastboot/README.md fwupd-1.2.10/plugins/fastboot/README.md --- fwupd-1.0.6/plugins/fastboot/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/fastboot/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,40 @@ +Fastboot Support +================ + +Introduction +------------ + +This plugin is used to update hardware that uses the fastboot protocol. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +ZIP file format. Inside the zip file must be all the firmware images for each +partition and a manifest file. The partition images can be in any format, but +the manifest must be either an Android `flashfile.xml` format file, or a QFIL +`partition_nand.xml` format file. + +For both types, all partitions with a defined image found in the zip file will +be updated. + +This plugin supports the following protocol ID: + + * com.google.fastboot + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_18D1&PID_4EE0&REV_0001` + * `USB\VID_18D1&PID_4EE0` + * `USB\VID_18D1` + +Quirk use +--------- +This plugin uses the following plugin-specific quirk: + +| Quirk | Description | Minimum fwupd version | +|------------------------|----------------------------------|-----------------------| +| `FastbootBlockSize` | Block size to use for transfers | 1.2.2 | diff -Nru fwupd-1.0.6/plugins/flashrom/example/build.sh fwupd-1.2.10/plugins/flashrom/example/build.sh --- fwupd-1.0.6/plugins/flashrom/example/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/example/build.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,4 @@ +#/bin/sh +appstream-util validate-relax com.Flashrom.Laptop.metainfo.xml +tar -cf firmware.tar startup.sh random-tool +gcab --create --nopath Flashrom-Laptop-1.2.3.cab firmware.tar com.Flashrom.Laptop.metainfo.xml diff -Nru fwupd-1.0.6/plugins/flashrom/example/com.Flashrom.Laptop.metainfo.xml fwupd-1.2.10/plugins/flashrom/example/com.Flashrom.Laptop.metainfo.xml --- fwupd-1.0.6/plugins/flashrom/example/com.Flashrom.Laptop.metainfo.xml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/example/com.Flashrom.Laptop.metainfo.xml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,42 @@ + + + + com.Flashrom.Laptop.firmware + Flashrom Laptop Firmware + System firmware for a Flashrom laptop + +

+ The laptop can be updated using flashrom. +

+
+ + + a0ce5085-2dea-5086-ae72-45810a186ad0 + + http://www.bbc.co.uk/ + CC0-1.0 + Proprietary + Flashrom + + + + +

+ This release updates a frobnicator to frob faster. +

+
+
+
+ + + + startup.sh + firmware.bin + + + + + org.freedesktop.fwupd + + +
diff -Nru fwupd-1.0.6/plugins/flashrom/example/random-tool fwupd-1.2.10/plugins/flashrom/example/random-tool --- fwupd-1.0.6/plugins/flashrom/example/random-tool 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/example/random-tool 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +#/bin/sh +echo "hello from the sandbox" diff -Nru fwupd-1.0.6/plugins/flashrom/example/startup.sh fwupd-1.2.10/plugins/flashrom/example/startup.sh --- fwupd-1.0.6/plugins/flashrom/example/startup.sh 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/example/startup.sh 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,10 @@ +#/bin/sh + +# do something with the old firmware +sha1sum /boot/flashrom-librem15v3.bin + +# run a random tool +./random-tool + +# this is the deliverable +cp /boot/flashrom-librem15v3.bin firmware.bin diff -Nru fwupd-1.0.6/plugins/flashrom/flashrom.quirk fwupd-1.2.10/plugins/flashrom/flashrom.quirk --- fwupd-1.0.6/plugins/flashrom/flashrom.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/flashrom.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,8 @@ +# Purism +[HwId=a0ce5085-2dea-5086-ae72-45810a186ad0] +DeviceId=librem15v3 + +# Libretrend +[HwId=52b68c34-6b31-5ecc-8a5c-de37e666ccd5] +DeviceId=LT1000 +VersionFormat=quad diff -Nru fwupd-1.0.6/plugins/flashrom/fu-plugin-flashrom.c fwupd-1.2.10/plugins/flashrom/fu-plugin-flashrom.c --- fwupd-1.0.6/plugins/flashrom/fu-plugin-flashrom.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/fu-plugin-flashrom.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,263 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2017 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * 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 2 of the License, 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. + */ + +#include "config.h" + +#include + +#include "fu-plugin-vfuncs.h" +#include "libflashrom.h" + +#define SELFCHECK_TRUE 1 + +struct FuPluginData { + gsize flash_size; + struct flashrom_flashctx *flashctx; + struct flashrom_layout *layout; + struct flashrom_programmer *flashprog; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.flashrom"); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + flashrom_layout_release (data->layout); + flashrom_programmer_shutdown (data->flashprog); + flashrom_flash_release (data->flashctx); +} + +static int +fu_plugin_flashrom_debug_cb (enum flashrom_log_level lvl, const char *fmt, va_list args) +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" + g_autofree gchar *tmp = g_strdup_vprintf (fmt, args); +#pragma clang diagnostic pop + switch (lvl) { + case FLASHROM_MSG_ERROR: + case FLASHROM_MSG_WARN: + g_warning ("%s", tmp); + break; + case FLASHROM_MSG_INFO: + g_debug ("%s", tmp); + break; + case FLASHROM_MSG_DEBUG: + case FLASHROM_MSG_DEBUG2: + if (g_getenv ("FWUPD_FLASHROM_VERBOSE") != NULL) + g_debug ("%s", tmp); + break; + case FLASHROM_MSG_SPEW: + break; + default: + break; + } + return 0; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + GPtrArray *hwids = fu_plugin_get_hwids (plugin); + g_autoptr(GPtrArray) devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + for (guint i = 0; i < hwids->len; i++) { + const gchar *guid = g_ptr_array_index (hwids, i); + const gchar *quirk_str; + g_autofree gchar *quirk_key_prefixed = NULL; + quirk_key_prefixed = g_strdup_printf ("HwId=%s", guid); + quirk_str = fu_plugin_lookup_quirk_by_id (plugin, + quirk_key_prefixed, + "DeviceId"); + if (quirk_str != NULL) { + g_autofree gchar *device_id = g_strdup_printf ("flashrom-%s", quirk_str); + g_autoptr(FuDevice) dev = fu_device_new (); + fu_device_set_id (dev, device_id); + fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_name (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_PRODUCT_NAME)); + fu_device_set_vendor (dev, fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER)); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_ENSURE_SEMVER); + fu_device_set_version (dev, + fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION), + FWUPD_VERSION_FORMAT_UNKNOWN); + fu_device_add_guid (dev, guid); + g_ptr_array_add (devices, g_steal_pointer (&dev)); + break; + } + } + + /* nothing to do, so don't bother initializing flashrom */ + if (devices->len == 0) + return TRUE; + + /* actually probe hardware to check for support */ + if (flashrom_init (SELFCHECK_TRUE)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flashrom initialization error"); + return FALSE; + } + flashrom_set_log_callback (fu_plugin_flashrom_debug_cb); + if (flashrom_programmer_init (&data->flashprog, "internal", NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "programmer initialization failed"); + return FALSE; + } + if (flashrom_flash_probe (&data->flashctx, data->flashprog, NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flash probe failed"); + return FALSE; + } + data->flash_size = flashrom_flash_getsize (data->flashctx); + if (data->flash_size == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "flash size zero"); + return FALSE; + } + + /* add devices */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + fu_plugin_device_add (plugin, dev); + fu_plugin_cache_add (plugin, fu_device_get_id (dev), dev); + } + return TRUE; +} + +gboolean +fu_plugin_update_prepare (FuPlugin *plugin, + FwupdInstallFlags flags, + FuDevice *device, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *firmware_orig = NULL; + g_autofree gchar *basename = NULL; + + /* not us */ + if (fu_plugin_cache_lookup (plugin, fu_device_get_id (device)) == NULL) + return TRUE; + + /* if the original firmware doesn't exist, grab it now */ + basename = g_strdup_printf ("flashrom-%s.bin", fu_device_get_id (device)); + firmware_orig = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", + "builder", basename, NULL); + if (!fu_common_mkdir_parent (firmware_orig, error)) + return FALSE; + if (!g_file_test (firmware_orig, G_FILE_TEST_EXISTS)) { + g_autofree guint8 *newcontents = g_malloc0 (data->flash_size); + g_autoptr(GBytes) buf = NULL; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + if (flashrom_image_read (data->flashctx, newcontents, data->flash_size)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to back up original firmware"); + return FALSE; + } + buf = g_bytes_new_static (newcontents, data->flash_size); + if (!fu_common_set_contents_bytes (firmware_orig, buf, error)) + return FALSE; + } + + return TRUE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize sz = 0; + gint rc; + const guint8 *buf = g_bytes_get_data (blob_fw, &sz); + + if (flashrom_layout_read_from_ifd (&data->layout, data->flashctx, NULL, 0)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read layout from Intel ICH descriptor"); + return FALSE; + } + + /* include bios region for safety reasons */ + if (flashrom_layout_include_region (data->layout, "bios")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid region name"); + return FALSE; + } + + /* write region */ + flashrom_layout_set (data->flashctx, data->layout); + if (sz != data->flash_size) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "invalid image size 0x%x, expected 0x%x", + (guint) sz, (guint) data->flash_size); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + rc = flashrom_image_write (data->flashctx, (void *) buf, sz, NULL /* refbuffer */); + if (rc != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "image write failed, err=%i", rc); + return FALSE; + } + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (flashrom_image_verify (data->flashctx, (void *) buf, sz)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "image verify failed"); + return FALSE; + } + + /* success */ + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/flashrom/meson.build fwupd-1.2.10/plugins/flashrom/meson.build --- fwupd-1.0.6/plugins/flashrom/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,30 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginFlashrom"'] + +install_data(['flashrom.quirk'], + install_dir: join_paths(get_option('datadir'), 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_flashrom', + fu_hash, + sources : [ + 'fu-plugin-flashrom.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + dependencies : [ + plugin_deps, + libflashrom, + ], +) diff -Nru fwupd-1.0.6/plugins/flashrom/README.md fwupd-1.2.10/plugins/flashrom/README.md --- fwupd-1.0.6/plugins/flashrom/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/flashrom/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,25 @@ +Flashrom +======== + +Introduction +------------ + +This plugin uses `flashrom` to update the system firmware. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format, which is typically the raw input for an +EEPROM programmer. + +This plugin supports the following protocol ID: + + * org.flashrom + +GUID Generation +--------------- + +These device uses hardware ID values which are derived from SMBIOS. They should +match the values provided by `fwupdtool hwids` or the `ComputerHardwareIds.exe` +Windows utility. diff -Nru fwupd-1.0.6/plugins/meson.build fwupd-1.2.10/plugins/meson.build --- fwupd-1.0.6/plugins/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,15 +1,33 @@ +subdir('ata') subdir('dfu') +subdir('colorhug') subdir('ebitdo') +subdir('fastboot') subdir('steelseries') +subdir('dell-dock') subdir('nitrokey') +subdir('rts54hid') +subdir('rts54hub') +subdir('synaptics-prometheus') subdir('test') subdir('udev') subdir('unifying') subdir('upower') +subdir('wacom-raw') +subdir('wacom-usb') +subdir('superio') # depends on dfu subdir('csr') +if get_option('plugin_nvme') +subdir('nvme') +endif + +if get_option('plugin_modem_manager') +subdir('modem-manager') +endif + if get_option('plugin_altos') subdir('altos') endif @@ -18,17 +36,18 @@ subdir('amt') endif -if get_option('plugin_thunderbolt') and udev.found() +if get_option('plugin_thunderbolt') subdir('thunderbolt') subdir('thunderbolt-power') endif -if get_option('plugin_colorhug') -subdir('colorhug') +if get_option('plugin_redfish') +subdir('redfish') endif if get_option('plugin_dell') subdir('dell') +subdir('dell-esrt') endif if get_option('plugin_synaptics') @@ -38,3 +57,7 @@ if get_option('plugin_uefi') subdir('uefi') endif + +if get_option('plugin_flashrom') +subdir('flashrom') +endif diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-mm-device.c fwupd-1.2.10/plugins/modem-manager/fu-mm-device.c --- fwupd-1.0.6/plugins/modem-manager/fu-mm-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-mm-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-io-channel.h" +#include "fu-archive.h" +#include "fu-mm-device.h" +#include "fu-device-private.h" +#include "fu-mm-utils.h" +#include "fu-qmi-pdc-updater.h" + +/* Amount of time for the modem to be re-probed and exposed in MM after being + * uninhibited. The timeout is long enough to cover the worst case, where the + * modem boots without SIM card inserted (and therefore the initialization + * may be very slow) and also where carrier config switching is explicitly + * required (e.g. if switching from the default (DF) to generic (GC).*/ +#define FU_MM_DEVICE_REMOVE_DELAY_REPROBE 120000 /* ms */ + +struct _FuMmDevice { + FuDevice parent_instance; + MMManager *manager; + + /* ModemManager-based devices will have MMObject and inhibition_uid set, + * udev-based ones won't (as device is already inhibited) */ + MMObject *omodem; + gchar *inhibition_uid; + + /* Properties read from the ModemManager-exposed modem, and to be + * propagated to plain udev-exposed modem objects. We assume that + * the firmware upgrade operation doesn't change the USB layout, and + * therefore the USB interface of the modem device that was an + * AT-capable TTY is assumed to be the same one after the upgrade. + */ + MMModemFirmwareUpdateMethod update_methods; + gchar *detach_fastboot_at; + gint port_at_ifnum; + + /* fastboot detach handling */ + gchar *port_at; + FuIOChannel *io_channel; + + /* qmi-pdc update logic */ + gchar *port_qmi; + FuQmiPdcUpdater *qmi_pdc_updater; + GArray *qmi_pdc_active_id; + guint attach_idle; +}; + +enum { + SIGNAL_ATTACH_FINISHED, + SIGNAL_LAST +}; + +static guint signals [SIGNAL_LAST] = { 0 }; + +G_DEFINE_TYPE (FuMmDevice, fu_mm_device, FU_TYPE_DEVICE) + +static void +fu_mm_device_to_string (FuDevice *device, GString *str) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + g_string_append (str, " FuMmDevice:\n"); + if (self->port_at != NULL) { + g_string_append_printf (str, " at-port:\t\t\t%s\n", + self->port_at); + } + if (self->port_qmi != NULL) { + g_string_append_printf (str, " qmi-port:\t\t\t%s\n", + self->port_qmi); + } +} + +const gchar * +fu_mm_device_get_inhibition_uid (FuMmDevice *device) +{ + g_return_val_if_fail (FU_IS_MM_DEVICE (device), NULL); + return device->inhibition_uid; +} + +MMModemFirmwareUpdateMethod +fu_mm_device_get_update_methods (FuMmDevice *device) +{ + g_return_val_if_fail (FU_IS_MM_DEVICE (device), MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE); + return device->update_methods; +} + +const gchar * +fu_mm_device_get_detach_fastboot_at (FuMmDevice *device) +{ + g_return_val_if_fail (FU_IS_MM_DEVICE (device), NULL); + return device->detach_fastboot_at; +} + +gint +fu_mm_device_get_port_at_ifnum (FuMmDevice *device) +{ + g_return_val_if_fail (FU_IS_MM_DEVICE (device), -1); + return device->port_at_ifnum; +} + +static gboolean +fu_mm_device_probe_default (FuDevice *device, GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + MMModemFirmware *modem_fw; + MMModem *modem = mm_object_peek_modem (self->omodem); + MMModemPortInfo *ports = NULL; + const gchar **device_ids; + const gchar *version; + guint n_ports = 0; + g_autoptr(MMFirmwareUpdateSettings) update_settings = NULL; + g_autofree gchar *device_sysfs_path = NULL; + + /* inhibition uid is the modem interface 'Device' property, which may + * be the device sysfs path or a different user-provided id */ + self->inhibition_uid = mm_modem_dup_device (modem); + + /* find out what update methods we should use */ + modem_fw = mm_object_peek_modem_firmware (self->omodem); + update_settings = mm_modem_firmware_get_update_settings (modem_fw); + self->update_methods = mm_firmware_update_settings_get_method (update_settings); + if (self->update_methods == MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "modem cannot be put in programming mode"); + return FALSE; + } + + /* various fastboot commands */ + if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) { + const gchar *tmp; + tmp = mm_firmware_update_settings_get_fastboot_at (update_settings); + if (tmp == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "modem does not set fastboot command"); + return FALSE; + } + self->detach_fastboot_at = g_strdup (tmp); + } + + /* get GUIDs */ + device_ids = mm_firmware_update_settings_get_device_ids (update_settings); + if (device_ids == NULL || device_ids[0] == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "modem did not specify any device IDs"); + return FALSE; + } + + /* get version string, which is fw_ver+config_ver */ + version = mm_firmware_update_settings_get_version (update_settings); + if (version == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "modem did not specify a firmware version"); + return FALSE; + } + + /* look for the AT and QMI/MBIM ports */ + if (!mm_modem_get_ports (modem, &ports, &n_ports)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to get port information"); + return FALSE; + } + if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) { + for (guint i = 0; i < n_ports; i++) { + if (ports[i].type == MM_MODEM_PORT_TYPE_AT) { + self->port_at = g_strdup_printf ("/dev/%s", ports[i].name); + break; + } + } + } + if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) { + for (guint i = 0; i < n_ports; i++) { + if ((ports[i].type == MM_MODEM_PORT_TYPE_QMI) || + (ports[i].type == MM_MODEM_PORT_TYPE_MBIM)) { + self->port_qmi = g_strdup_printf ("/dev/%s", ports[i].name); + break; + } + } + } + mm_modem_port_info_array_free (ports, n_ports); + + /* an at port is required for fastboot */ + if ((self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) && + (self->port_at == NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to find AT port"); + return FALSE; + } + + /* a qmi port is required for qmi-pdc */ + if ((self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) && + (self->port_qmi == NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to find QMI port"); + return FALSE; + } + + /* if we have the at port reported, get sysfs path and interface number */ + if (self->port_at != NULL) { + fu_mm_utils_get_port_info (self->port_at, &device_sysfs_path, &self->port_at_ifnum, NULL); + } else if (self->port_qmi != NULL) { + fu_mm_utils_get_port_info (self->port_qmi, &device_sysfs_path, NULL, NULL); + } else { + g_warn_if_reached (); + } + + /* if no device sysfs file, error out */ + if (device_sysfs_path == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to find device sysfs path"); + return FALSE; + } + + /* add properties to fwupd device */ + fu_device_set_physical_id (device, device_sysfs_path); + if (mm_modem_get_manufacturer (modem) != NULL) + fu_device_set_vendor (device, mm_modem_get_manufacturer (modem)); + if (mm_modem_get_model (modem) != NULL) + fu_device_set_name (device, mm_modem_get_model (modem)); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_UNKNOWN); + for (guint i = 0; device_ids[i] != NULL; i++) + fu_device_add_instance_id (device, device_ids[i]); + + /* convert the instance IDs to GUIDs */ + fu_device_convert_instance_ids (device); + + return TRUE; +} + +static gboolean +fu_mm_device_probe_udev (FuDevice *device, GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + + /* an at port is required for fastboot */ + if ((self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) && + (self->port_at == NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to find AT port"); + return FALSE; + } + + /* a qmi port is required for qmi-pdc */ + if ((self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) && + (self->port_qmi == NULL)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to find QMI port"); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_mm_device_probe (FuDevice *device, GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + + if (self->omodem) { + return fu_mm_device_probe_default (device, error); + } else { + return fu_mm_device_probe_udev (device, error); + } +} + +static gboolean +fu_mm_device_at_cmd (FuMmDevice *self, const gchar *cmd, GError **error) +{ + const gchar *buf; + gsize bufsz = 0; + g_autoptr(GBytes) at_req = NULL; + g_autoptr(GBytes) at_res = NULL; + g_autofree gchar *cmd_cr = g_strdup_printf ("%s\r\n", cmd); + + /* command */ + at_req = g_bytes_new (cmd_cr, strlen (cmd_cr)); + if (g_getenv ("FWUPD_MODEM_MANAGER_VERBOSE") != NULL) + fu_common_dump_bytes (G_LOG_DOMAIN, "writing", at_req); + if (!fu_io_channel_write_bytes (self->io_channel, at_req, 1500, + FU_IO_CHANNEL_FLAG_FLUSH_INPUT, error)) { + g_prefix_error (error, "failed to write %s: ", cmd); + return FALSE; + } + + /* response */ + at_res = fu_io_channel_read_bytes (self->io_channel, -1, 1500, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT, error); + if (at_res == NULL) { + g_prefix_error (error, "failed to read response for %s: ", cmd); + return FALSE; + } + if (g_getenv ("FWUPD_MODEM_MANAGER_VERBOSE") != NULL) + fu_common_dump_bytes (G_LOG_DOMAIN, "read", at_res); + buf = g_bytes_get_data (at_res, &bufsz); + if (bufsz < 6) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to read valid response for %s", cmd); + return FALSE; + } + if (memcmp (buf, "\r\nOK\r\n", 6) != 0) { + g_autofree gchar *tmp = g_strndup (buf + 2, bufsz - 4); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to read valid response for %s: %s", + cmd, tmp); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_mm_device_io_open (FuMmDevice *self, GError **error) +{ + /* open device */ + self->io_channel = fu_io_channel_new_file (self->port_at, error); + if (self->io_channel == NULL) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_mm_device_io_close (FuMmDevice *self, GError **error) +{ + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); + return TRUE; +} + +static gboolean +fu_mm_device_detach_fastboot (FuDevice *device, GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* boot to fastboot mode */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_mm_device_io_open, + (FuDeviceLockerFunc) fu_mm_device_io_close, + error); + if (locker == NULL) + return FALSE; + if (!fu_mm_device_at_cmd (self, "AT", error)) + return FALSE; + if (!fu_mm_device_at_cmd (self, self->detach_fastboot_at, error)) { + g_prefix_error (error, "rebooting into fastboot not supported: "); + return FALSE; + } + + /* success */ + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_mm_device_detach (FuDevice *device, GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* This plugin supports currently two methods to download firmware: + * fastboot and qmi-pdc. A modem may require one of those, or both, + * depending on the update type or the modem type. + * + * The first time this detach() method is executed is always for a + * FuMmDevice that was created from a MM-exposed modem, which is the + * moment when we're going to decide the amount of retries we need to + * flash all firmware. + * + * If the FuMmModem is created from a MM-exposed modem and... + * a) we only support fastboot, we just trigger the fastboot detach. + * b) we only support qmi-pdc, we just exit without any detach. + * c) we support both fastboot and qmi-pdc, we will set the + * ANOTHER_WRITE_REQUIRED flag in the device and we'll trigger + * the fastboot detach. + * + * If the FuMmModem is created from udev events... + * d) it means we're in the extra required write that was flagged + * in an earlier detach(), and we need to perform the qmi-pdc + * update procedure at this time, so we just exit without any + * detach. + */ + + /* FuMmDevice created from MM... */ + if (self->omodem != NULL) { + /* both fastboot and qmi-pdc supported? another write required */ + if ((self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) && + (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC)) { + g_debug ("both fastboot and qmi-pdc supported, so the upgrade requires another write"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + } + /* fastboot */ + if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT) + return fu_mm_device_detach_fastboot (device, error); + /* otherwise, assume we don't need any detach */ + return TRUE; + } + + /* FuMmDevice created from udev... + * assume we don't need any detach */ + return TRUE; +} + +typedef struct { + gchar *filename; + GBytes *bytes; + GArray *digest; + gboolean active; +} FuMmFileInfo; + +static void +fu_mm_file_info_free (FuMmFileInfo *file_info) +{ + g_clear_pointer (&file_info->digest, g_array_unref); + g_free (file_info->filename); + g_bytes_unref (file_info->bytes); + g_free (file_info); +} + +typedef struct { + FuMmDevice *device; + GError *error; + GPtrArray *file_infos; + gsize total_written; + gsize total_bytes; +} FuMmArchiveIterateCtx; + +static gboolean +fu_mm_should_be_active (const gchar *version, + const gchar *filename) +{ + g_auto(GStrv) split = NULL; + g_autofree gchar *carrier_id = NULL; + + /* The filename of the mcfg file is composed of a "mcfg." prefix, then the + * carrier code, followed by the carrier version, and finally a ".mbn" + * prefix. Here we try to guess, based on the carrier code, whether the + * specific mcfg file should be activated after the firmware upgrade + * operation. + * + * This logic requires that the previous device version includes the carrier + * code also embedded in the version string. E.g. "xxxx.VF.xxxx". If we find + * this match, we assume this is the active config to use. + */ + + split = g_strsplit (filename, ".", -1); + if (g_strv_length (split) < 4) + return FALSE; + if (g_strcmp0 (split[0], "mcfg") != 0) + return FALSE; + + carrier_id = g_strdup_printf (".%s.", split[1]); + return (g_strstr_len (version, -1, carrier_id) != NULL); +} + +static void +fu_mm_qmi_pdc_archive_iterate_mcfg (FuArchive *archive, + const gchar *filename, + GBytes *bytes, + gpointer user_data) +{ + FuMmArchiveIterateCtx *ctx = user_data; + FuMmFileInfo *file_info; + + /* filenames should be named as 'mcfg.*.mbn', e.g.: mcfg.A2.018.mbn */ + if (!g_str_has_prefix (filename, "mcfg.") || !g_str_has_suffix (filename, ".mbn")) + return; + + file_info = g_new0 (FuMmFileInfo, 1); + file_info->filename = g_strdup (filename); + file_info->bytes = g_bytes_ref (bytes); + file_info->active = fu_mm_should_be_active (fu_device_get_version (FU_DEVICE (ctx->device)), filename); + g_ptr_array_add (ctx->file_infos, file_info); + ctx->total_bytes += g_bytes_get_size (file_info->bytes); +} + +static gboolean +fu_mm_device_qmi_open (FuMmDevice *self, GError **error) +{ + self->qmi_pdc_updater = fu_qmi_pdc_updater_new (self->port_qmi); + return fu_qmi_pdc_updater_open (self->qmi_pdc_updater, error); +} + +static gboolean +fu_mm_device_qmi_close (FuMmDevice *self, GError **error) +{ + g_autoptr(FuQmiPdcUpdater) updater = NULL; + + updater = g_steal_pointer (&self->qmi_pdc_updater); + return fu_qmi_pdc_updater_close (updater, error); +} + +static gboolean +fu_mm_device_qmi_close_no_error (FuMmDevice *self, GError **error) +{ + g_autoptr(FuQmiPdcUpdater) updater = NULL; + + updater = g_steal_pointer (&self->qmi_pdc_updater); + fu_qmi_pdc_updater_close (updater, NULL); + return TRUE; +} + +static gboolean +fu_mm_device_write_firmware_qmi_pdc (FuDevice *device, GBytes *fw, GArray **active_id, GError **error) +{ + g_autoptr(FuArchive) archive = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(GPtrArray) file_infos = g_ptr_array_new_with_free_func ((GDestroyNotify)fu_mm_file_info_free); + gint active_i = -1; + FuMmArchiveIterateCtx archive_context = { + .device = FU_MM_DEVICE (device), + .error = NULL, + .file_infos = file_infos, + .total_written = 0, + .total_bytes = 0, + }; + + /* decompress entire archive ahead of time */ + archive = fu_archive_new (fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error); + if (archive == NULL) + return FALSE; + + /* boot to fastboot mode */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) fu_mm_device_qmi_open, + (FuDeviceLockerFunc) fu_mm_device_qmi_close, + error); + if (locker == NULL) + return FALSE; + + /* process the list of MCFG files to write */ + fu_archive_iterate (archive, fu_mm_qmi_pdc_archive_iterate_mcfg, &archive_context); + + for (guint i = 0; i < file_infos->len; i++) { + FuMmFileInfo *file_info = g_ptr_array_index (file_infos, i); + file_info->digest = fu_qmi_pdc_updater_write (archive_context.device->qmi_pdc_updater, + file_info->filename, + file_info->bytes, + &archive_context.error); + if (file_info->digest == NULL) { + g_prefix_error (&archive_context.error, + "Failed to write file '%s':", file_info->filename); + break; + } + /* if we wrongly detect more than one, just assume the latest one; this + * is not critical, it may just take a bit more time to perform the + * automatic carrier config switching in ModemManager */ + if (file_info->active) + active_i = i; + } + + /* set expected active configuration */ + if (active_i >= 0 && active_id != NULL) { + FuMmFileInfo *file_info = g_ptr_array_index (file_infos, active_i); + *active_id = g_array_ref (file_info->digest); + } + + if (archive_context.error != NULL) { + g_propagate_error (error, archive_context.error); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_mm_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GPtrArray) array = NULL; + + /* lock device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* qmi pdc write operation */ + if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) + return fu_mm_device_write_firmware_qmi_pdc (device, fw, &self->qmi_pdc_active_id, error); + + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "unsupported update method"); + return FALSE; +} + +static gboolean +fu_mm_device_attach_qmi_pdc (FuMmDevice *self, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* ignore action if there is no active id specified */ + if (self->qmi_pdc_active_id == NULL) + return TRUE; + + /* errors closing may be expected if the device really reboots itself */ + locker = fu_device_locker_new_full (self, + (FuDeviceLockerFunc) fu_mm_device_qmi_open, + (FuDeviceLockerFunc) fu_mm_device_qmi_close_no_error, + error); + if (locker == NULL) + return FALSE; + + if (!fu_qmi_pdc_updater_activate (self->qmi_pdc_updater, self->qmi_pdc_active_id, error)) + return FALSE; + + return TRUE; +} + +static gboolean +fu_mm_device_attach_noop_idle (gpointer user_data) +{ + FuMmDevice *self = FU_MM_DEVICE (user_data); + self->attach_idle = 0; + g_signal_emit (self, signals [SIGNAL_ATTACH_FINISHED], 0); + return G_SOURCE_REMOVE; +} + +static gboolean +fu_mm_device_attach_qmi_pdc_idle (gpointer user_data) +{ + FuMmDevice *self = FU_MM_DEVICE (user_data); + g_autoptr(GError) error = NULL; + + if (!fu_mm_device_attach_qmi_pdc (self, &error)) + g_warning ("qmi-pdc attach operation failed: %s", error->message); + else + g_debug ("qmi-pdc attach operation successful"); + + self->attach_idle = 0; + g_signal_emit (self, signals [SIGNAL_ATTACH_FINISHED], 0); + return G_SOURCE_REMOVE; +} + +static gboolean +fu_mm_device_attach (FuDevice *device, GError **error) +{ + FuMmDevice *self = FU_MM_DEVICE (device); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* lock device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* we want this attach operation to be triggered asynchronously, because the engine + * must learn that it has to wait for replug before we actually trigger the reset. */ + if (self->update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC) + self->attach_idle = g_idle_add ((GSourceFunc) fu_mm_device_attach_qmi_pdc_idle, self); + else + self->attach_idle = g_idle_add ((GSourceFunc) fu_mm_device_attach_noop_idle, self); + + /* wait for re-probing after uninhibiting */ + fu_device_set_remove_delay (device, FU_MM_DEVICE_REMOVE_DELAY_REPROBE); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static void +fu_mm_device_init (FuMmDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION); + fu_device_set_summary (FU_DEVICE (self), "Mobile broadband device"); + fu_device_add_icon (FU_DEVICE (self), "network-modem"); +} + +static void +fu_mm_device_finalize (GObject *object) +{ + FuMmDevice *self = FU_MM_DEVICE (object); + if (self->attach_idle) + g_source_remove (self->attach_idle); + if (self->qmi_pdc_active_id) + g_array_unref (self->qmi_pdc_active_id); + g_object_unref (self->manager); + if (self->omodem != NULL) + g_object_unref (self->omodem); + g_free (self->detach_fastboot_at); + g_free (self->port_at); + g_free (self->port_qmi); + g_free (self->inhibition_uid); + G_OBJECT_CLASS (fu_mm_device_parent_class)->finalize (object); +} + +static void +fu_mm_device_class_init (FuMmDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_mm_device_finalize; + klass_device->to_string = fu_mm_device_to_string; + klass_device->probe = fu_mm_device_probe; + klass_device->detach = fu_mm_device_detach; + klass_device->write_firmware = fu_mm_device_write_firmware; + klass_device->attach = fu_mm_device_attach; + + signals [SIGNAL_ATTACH_FINISHED] = + g_signal_new ("attach-finished", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +FuMmDevice * +fu_mm_device_new (MMManager *manager, MMObject *omodem) +{ + FuMmDevice *self = g_object_new (FU_TYPE_MM_DEVICE, NULL); + self->manager = g_object_ref (manager); + self->omodem = g_object_ref (omodem); + self->port_at_ifnum = -1; + return self; +} + +FuPluginMmInhibitedDeviceInfo * +fu_plugin_mm_inhibited_device_info_new (FuMmDevice *device) +{ + FuPluginMmInhibitedDeviceInfo *info; + + info = g_new0 (FuPluginMmInhibitedDeviceInfo, 1); + info->physical_id = g_strdup (fu_device_get_physical_id (FU_DEVICE (device))); + info->vendor = g_strdup (fu_device_get_vendor (FU_DEVICE (device))); + info->name = g_strdup (fu_device_get_name (FU_DEVICE (device))); + info->version = g_strdup (fu_device_get_version (FU_DEVICE (device))); + info->guids = fu_device_get_guids (FU_DEVICE (device)); + info->update_methods = fu_mm_device_get_update_methods (device); + info->detach_fastboot_at = g_strdup (fu_mm_device_get_detach_fastboot_at (device)); + info->port_at_ifnum = fu_mm_device_get_port_at_ifnum (device); + info->inhibited_uid = g_strdup (fu_mm_device_get_inhibition_uid (device)); + + return info; +} + +void +fu_plugin_mm_inhibited_device_info_free (FuPluginMmInhibitedDeviceInfo *info) +{ + g_free (info->inhibited_uid); + g_free (info->physical_id); + g_free (info->vendor); + g_free (info->name); + g_free (info->version); + if (info->guids) + g_ptr_array_unref (info->guids); + g_free (info->detach_fastboot_at); + g_free (info); +} + +FuMmDevice * +fu_mm_device_udev_new (MMManager *manager, + FuPluginMmInhibitedDeviceInfo *info) +{ + FuMmDevice *self = g_object_new (FU_TYPE_MM_DEVICE, NULL); + g_debug ("creating udev-based mm device at %s", info->physical_id); + self->manager = g_object_ref (manager); + fu_device_set_physical_id (FU_DEVICE (self), info->physical_id); + fu_device_set_vendor (FU_DEVICE (self), info->vendor); + fu_device_set_name (FU_DEVICE (self), info->name); + fu_device_set_version (FU_DEVICE (self), info->version, FWUPD_VERSION_FORMAT_UNKNOWN); + self->update_methods = info->update_methods; + self->detach_fastboot_at = g_strdup (info->detach_fastboot_at); + self->port_at_ifnum = info->port_at_ifnum; + + for (guint i = 0; i < info->guids->len; i++) + fu_device_add_guid (FU_DEVICE (self), g_ptr_array_index (info->guids, i)); + + return self; +} + +void +fu_mm_device_udev_add_port (FuMmDevice *self, + const gchar *subsystem, + const gchar *path, + gint ifnum) +{ + g_return_if_fail (FU_IS_MM_DEVICE (self)); + + /* cdc-wdm ports always added unless one already set */ + if (g_str_equal (subsystem, "usbmisc") && + (self->port_qmi == NULL)) { + g_debug ("added QMI port %s (%s)", path, subsystem); + self->port_qmi = g_strdup (path); + return; + } + + if (g_str_equal (subsystem, "tty") && + (self->port_at == NULL) && + (ifnum >= 0) && (ifnum == self->port_at_ifnum)) { + g_debug ("added AT port %s (%s)", path, subsystem); + self->port_at = g_strdup (path); + return; + } + + /* otherwise, ignore all other ports */ + g_debug ("ignoring port %s (%s)", path, subsystem); +} diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-mm-device.h fwupd-1.2.10/plugins/modem-manager/fu-mm-device.h --- fwupd-1.0.6/plugins/modem-manager/fu-mm-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-mm-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * Copyright (C) 2019 Aleksander Morgado + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_MM_DEVICE_H +#define __FU_MM_DEVICE_H + +#include + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_MM_DEVICE (fu_mm_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuMmDevice, fu_mm_device, FU, MM_DEVICE, FuDevice) + +FuMmDevice *fu_mm_device_new (MMManager *manager, + MMObject *omodem); +const gchar *fu_mm_device_get_inhibition_uid (FuMmDevice *device); +const gchar *fu_mm_device_get_detach_fastboot_at (FuMmDevice *device); +gint fu_mm_device_get_port_at_ifnum (FuMmDevice *device); +MMModemFirmwareUpdateMethod fu_mm_device_get_update_methods (FuMmDevice *device); + +/* support for udev-based devices */ + +typedef struct FuPluginMmInhibitedDeviceInfo FuPluginMmInhibitedDeviceInfo; +struct FuPluginMmInhibitedDeviceInfo { + gchar *inhibited_uid; + gchar *physical_id; + gchar *vendor; + gchar *name; + gchar *version; + GPtrArray *guids; + MMModemFirmwareUpdateMethod update_methods; + gchar *detach_fastboot_at; + gint port_at_ifnum; +}; +FuPluginMmInhibitedDeviceInfo *fu_plugin_mm_inhibited_device_info_new (FuMmDevice *device); +void fu_plugin_mm_inhibited_device_info_free (FuPluginMmInhibitedDeviceInfo *info); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FuPluginMmInhibitedDeviceInfo, fu_plugin_mm_inhibited_device_info_free); + +FuMmDevice *fu_mm_device_udev_new (MMManager *manager, + FuPluginMmInhibitedDeviceInfo *info); +void fu_mm_device_udev_add_port (FuMmDevice *device, + const gchar *subsystem, + const gchar *path, + gint ifnum); + +G_END_DECLS + +#endif /* __FU_MM_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-mm-utils.c fwupd-1.2.10/plugins/modem-manager/fu-mm-utils.c --- fwupd-1.0.6/plugins/modem-manager/fu-mm-utils.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-mm-utils.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Aleksander Morgado + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include "fu-mm-utils.h" + +gboolean +fu_mm_utils_get_udev_port_info (GUdevDevice *device, + gchar **out_device_sysfs_path, + gint *out_port_ifnum, + GError **error) +{ + gint port_ifnum = -1; + const gchar *aux; + g_autoptr(GUdevDevice) parent = NULL; + g_autofree gchar *device_sysfs_path = NULL; + + /* ID_USB_INTERFACE_NUM is set on the port device itself */ + aux = g_udev_device_get_property (device, "ID_USB_INTERFACE_NUM"); + if (aux != NULL) + port_ifnum = (guint16) g_ascii_strtoull (aux, NULL, 16); + + /* we need to traverse all parents of the give udev device until we find + * the first 'usb_device' reported, which is the GUdevDevice associated with + * the full USB device (i.e. all ports of the same device). + */ + parent = g_udev_device_get_parent (device); + while (parent != NULL) { + g_autoptr(GUdevDevice) next = NULL; + + if (g_strcmp0 (g_udev_device_get_devtype (parent), "usb_device") == 0) { + device_sysfs_path = g_strdup (g_udev_device_get_sysfs_path (parent)); + break; + } + + /* check next parent */ + next = g_udev_device_get_parent (parent); + g_set_object (&parent, next); + } + + if (parent == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to lookup device info: parent usb_device not found"); + return FALSE; + } + + if (out_port_ifnum != NULL) + *out_port_ifnum = port_ifnum; + if (out_device_sysfs_path != NULL) + *out_device_sysfs_path = g_steal_pointer (&device_sysfs_path); + return TRUE; +} + +gboolean +fu_mm_utils_get_port_info (const gchar *path, + gchar **out_device_sysfs_path, + gint *out_port_ifnum, + GError **error) +{ + g_autoptr(GUdevClient) client = NULL; + g_autoptr(GUdevDevice) dev = NULL; + + client = g_udev_client_new (NULL); + dev = g_udev_client_query_by_device_file (client, path); + if (dev == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to lookup device by path"); + return FALSE; + } + + return fu_mm_utils_get_udev_port_info (dev, out_device_sysfs_path, out_port_ifnum, error); +} diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-mm-utils.h fwupd-1.2.10/plugins/modem-manager/fu-mm-utils.h --- fwupd-1.0.6/plugins/modem-manager/fu-mm-utils.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-mm-utils.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Aleksander Morgado + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_MM_UTILS_H +#define __FU_MM_UTILS_H + +#include "config.h" +#include + +G_BEGIN_DECLS + +#ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop +#endif + +gboolean fu_mm_utils_get_udev_port_info (GUdevDevice *dev, + gchar **device_sysfs_path, + gint *port_ifnum, + GError **error); +gboolean fu_mm_utils_get_port_info (const gchar *path, + gchar **device_sysfs_path, + gint *port_ifnum, + GError **error); + +G_END_DECLS + +#endif /* __FU_MM_UTILS_H */ diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-plugin-modem-manager.c fwupd-1.2.10/plugins/modem-manager/fu-plugin-modem-manager.c --- fwupd-1.0.6/plugins/modem-manager/fu-plugin-modem-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-plugin-modem-manager.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-plugin-vfuncs.h" + +#include "fu-mm-device.h" +#include "fu-mm-utils.h" + +/* amount of time to wait for ports of the same device being exposed by kernel */ +#define FU_MM_UDEV_DEVICE_PORTS_TIMEOUT 3 /* s */ + +typedef struct FuPluginMmInhibitedDeviceInfo FuPluginMmInhibitedDeviceInfo; + +struct FuPluginData { + MMManager *manager; + gboolean manager_ready; + GUdevClient *udev_client; + guint udev_timeout_id; + + /* when a device is inhibited from MM, we store all relevant details + * ourselves to recreate a functional device object even without MM + */ + FuPluginMmInhibitedDeviceInfo *inhibited; +}; + +static void +fu_plugin_mm_udev_device_removed (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + FuMmDevice *dev; + + if (priv->inhibited == NULL) + return; + + dev = fu_plugin_cache_lookup (plugin, priv->inhibited->physical_id); + if (dev == NULL) + return; + + /* once the first port is gone, consider device is gone */ + fu_plugin_cache_remove (plugin, priv->inhibited->physical_id); + fu_plugin_device_remove (plugin, FU_DEVICE (dev)); + + /* no need to wait for more ports, cancel that right away */ + if (priv->udev_timeout_id != 0) { + g_source_remove (priv->udev_timeout_id); + priv->udev_timeout_id = 0; + } +} + +static void +fu_plugin_mm_uninhibit_device (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FuPluginMmInhibitedDeviceInfo) info = NULL; + + /* get the device removed from the plugin cache before uninhibiting */ + fu_plugin_mm_udev_device_removed (plugin); + + info = g_steal_pointer (&priv->inhibited); + if ((priv->manager != NULL) && (info != NULL)) { + g_debug ("uninhibit modemmanager device with uid %s", info->inhibited_uid); + mm_manager_uninhibit_device_sync (priv->manager, info->inhibited_uid, NULL, NULL); + } +} + +static gboolean +fu_plugin_mm_udev_device_ports_timeout (gpointer user_data) +{ + FuPlugin *plugin = user_data; + FuPluginData *priv = fu_plugin_get_data (plugin); + FuMmDevice *dev; + g_autoptr(GError) error = NULL; + + g_return_val_if_fail (priv->inhibited != NULL, G_SOURCE_REMOVE); + priv->udev_timeout_id = 0; + + dev = fu_plugin_cache_lookup (plugin, priv->inhibited->physical_id); + if (dev != NULL) { + if (!fu_device_probe (FU_DEVICE (dev), &error)) { + g_warning ("failed to probe MM device: %s", error->message); + } else { + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + } + + return G_SOURCE_REMOVE; +} + +static void +fu_plugin_mm_udev_device_ports_timeout_reset (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + g_return_if_fail (priv->inhibited != NULL); + if (priv->udev_timeout_id != 0) + g_source_remove (priv->udev_timeout_id); + priv->udev_timeout_id = g_timeout_add_seconds (FU_MM_UDEV_DEVICE_PORTS_TIMEOUT, + fu_plugin_mm_udev_device_ports_timeout, + plugin); +} + +static void +fu_plugin_mm_udev_device_port_added (FuPlugin *plugin, + const gchar *subsystem, + const gchar *path, + gint ifnum) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + FuMmDevice *existing; + g_autoptr(FuMmDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + g_return_if_fail (priv->inhibited != NULL); + existing = fu_plugin_cache_lookup (plugin, priv->inhibited->physical_id); + if (existing != NULL) { + /* add port to existing device */ + fu_mm_device_udev_add_port (existing, subsystem, path, ifnum); + fu_plugin_mm_udev_device_ports_timeout_reset (plugin); + return; + } + /* create device and add to cache */ + dev = fu_mm_device_udev_new (priv->manager, priv->inhibited); + fu_mm_device_udev_add_port (dev, subsystem, path, ifnum); + fu_plugin_cache_add (plugin, priv->inhibited->physical_id, dev); + + /* wait a bit before probing, in case more ports get added */ + fu_plugin_mm_udev_device_ports_timeout_reset (plugin); +} + +static gboolean +fu_plugin_mm_udev_uevent_cb (GUdevClient *udev, + const gchar *action, + GUdevDevice *device, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *subsystem = g_udev_device_get_subsystem (device); + const gchar *name = g_udev_device_get_name (device); + g_autofree gchar *path = NULL; + g_autofree gchar *device_sysfs_path = NULL; + gint ifnum = -1; + + if (action == NULL || subsystem == NULL || priv->inhibited == NULL || name == NULL) + return TRUE; + + /* ignore if loading port info fails */ + if (!fu_mm_utils_get_udev_port_info (device, &device_sysfs_path, &ifnum, NULL)) + return TRUE; + + /* ignore all events for ports not owned by our device */ + if (g_strcmp0 (device_sysfs_path, priv->inhibited->physical_id) != 0) + return TRUE; + + /* ignore non-cdc-wdm usbmisc ports */ + if (g_str_equal (subsystem, "usbmisc") && !g_str_has_prefix (name, "cdc-wdm")) + return TRUE; + + path = g_strdup_printf ("/dev/%s", name); + + if ((g_str_equal (action, "add")) || (g_str_equal (action, "change"))) { + g_debug ("added port to inhibited modem: %s (ifnum %d)", path, ifnum); + fu_plugin_mm_udev_device_port_added (plugin, subsystem, path, ifnum); + } else if (g_str_equal (action, "remove")) { + g_debug ("removed port from inhibited modem: %s", path); + fu_plugin_mm_udev_device_removed (plugin); + } + + return TRUE; +} + +static gboolean +fu_plugin_mm_inhibit_device (FuPlugin *plugin, FuDevice *device, GError **error) +{ + static const gchar *subsystems[] = { "tty", "usbmisc", NULL }; + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FuPluginMmInhibitedDeviceInfo) info = NULL; + + fu_plugin_mm_uninhibit_device (plugin); + + info = fu_plugin_mm_inhibited_device_info_new (FU_MM_DEVICE (device)); + + g_debug ("inhibit modemmanager device with uid %s", info->inhibited_uid); + if (!mm_manager_inhibit_device_sync (priv->manager, info->inhibited_uid, NULL, error)) + return FALSE; + + /* setup inhibited device info */ + priv->inhibited = g_steal_pointer (&info); + + /* as soon as inhibition is place, we need to do modem device monitoring based + * on the udev client, as MM no longer reports devices */ + priv->udev_client = g_udev_client_new (subsystems); + g_signal_connect (priv->udev_client, "uevent", + G_CALLBACK (fu_plugin_mm_udev_uevent_cb), plugin); + + return TRUE; +} + +static void +fu_plugin_mm_device_add (FuPlugin *plugin, MMObject *modem) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *object_path = mm_object_get_path (modem); + g_autoptr(FuMmDevice) dev = NULL; + g_autoptr(GError) error = NULL; + if (fu_plugin_cache_lookup (plugin, object_path) != NULL) { + g_warning ("MM device already added, ignoring"); + return; + } + dev = fu_mm_device_new (priv->manager, modem); + if (!fu_device_probe (FU_DEVICE (dev), &error)) { + g_warning ("failed to probe MM device: %s", error->message); + return; + } + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + fu_plugin_cache_add (plugin, object_path, dev); +} + +static void +fu_plugin_mm_device_added_cb (MMManager *manager, MMObject *modem, FuPlugin *plugin) +{ + fu_plugin_mm_device_add (plugin, modem); +} + +static void +fu_plugin_mm_device_removed_cb (MMManager *manager, MMObject *modem, FuPlugin *plugin) +{ + const gchar *object_path = mm_object_get_path (modem); + FuMmDevice *dev = fu_plugin_cache_lookup (plugin, object_path); + if (dev == NULL) + return; + g_debug ("removed modem: %s", mm_object_get_path (modem)); + fu_plugin_cache_remove (plugin, object_path); + fu_plugin_device_remove (plugin, FU_DEVICE (dev)); +} + +static void +fu_plugin_mm_teardown_manager (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + if (priv->manager_ready) { + g_debug ("ModemManager no longer available"); + g_signal_handlers_disconnect_by_func (priv->manager, + G_CALLBACK (fu_plugin_mm_device_added_cb), + plugin); + g_signal_handlers_disconnect_by_func (priv->manager, + G_CALLBACK (fu_plugin_mm_device_removed_cb), + plugin); + priv->manager_ready = FALSE; + } +} + +static void +fu_plugin_mm_setup_manager (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *version = mm_manager_get_version (priv->manager); + GList *list; + + if (fu_common_vercmp (version, MM_REQUIRED_VERSION) < 0) { + g_warning ("ModemManager %s is available, but need at least %s", + version, MM_REQUIRED_VERSION); + return; + } + + g_debug ("ModemManager %s is available", version); + + g_signal_connect (priv->manager, "object-added", + G_CALLBACK (fu_plugin_mm_device_added_cb), plugin); + g_signal_connect (priv->manager, "object-removed", + G_CALLBACK (fu_plugin_mm_device_removed_cb), plugin); + + list = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->manager)); + for (GList *l = list; l != NULL; l = g_list_next (l)) { + MMObject *modem = MM_OBJECT (l->data); + fu_plugin_mm_device_add (plugin, modem); + g_object_unref (modem); + } + g_list_free (list); + + priv->manager_ready = TRUE; +} + +static void +fu_plugin_mm_name_owner_updated (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + const gchar *name_owner; + name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->manager)); + if (name_owner != NULL) + fu_plugin_mm_setup_manager (plugin); + else + fu_plugin_mm_teardown_manager (plugin); +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_signal_connect_swapped (priv->manager, "notify::name-owner", + G_CALLBACK (fu_plugin_mm_name_owner_updated), + plugin); + fu_plugin_mm_name_owner_updated (plugin); + return TRUE; +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(GDBusConnection) connection = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + priv->manager = mm_manager_new_sync (connection, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, + NULL, error); + if (priv->manager == NULL) + return FALSE; + + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + + fu_plugin_mm_uninhibit_device (plugin); + + if (priv->udev_timeout_id) + g_source_remove (priv->udev_timeout_id); + if (priv->udev_client) + g_object_unref (priv->udev_client); + if (priv->manager != NULL) + g_object_unref (priv->manager); +} + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + FuPluginData *priv = fu_plugin_get_data (plugin); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* inhibit device and track it inside the plugin, not bound to the + * lifetime of the FuMmDevice, because that object will only exist for + * as long as the ModemManager device exists, and inhibiting will + * implicitly remove the device from ModemManager. */ + if (priv->inhibited == NULL) { + if (!fu_plugin_mm_inhibit_device (plugin, device, error)) + return FALSE; + } + + /* reset */ + if (!fu_device_detach (device, error)) { + fu_plugin_mm_uninhibit_device (plugin); + return FALSE; + } + + /* note: wait for replug set by device if it really needs it */ + return TRUE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +static void +fu_plugin_mm_device_attach_finished (gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_mm_uninhibit_device (plugin); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open device */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + + /* schedule device attach asynchronously, which is extremely important + * so that engine can setup the device "waiting" logic before the actual + * attach procedure happens (which will reset the module if it worked + * properly) */ + if (!fu_device_attach (device, error)) + return FALSE; + + /* this signal will always be emitted asynchronously */ + g_signal_connect_swapped (device, "attach-finished", + G_CALLBACK (fu_plugin_mm_device_attach_finished), plugin); + + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-qmi-pdc-updater.c fwupd-1.2.10/plugins/modem-manager/fu-qmi-pdc-updater.c --- fwupd-1.0.6/plugins/modem-manager/fu-qmi-pdc-updater.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-qmi-pdc-updater.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,687 @@ +/* + * Copyright (C) 2019 Aleksander Morgado + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-qmi-pdc-updater.h" + +#define FU_QMI_PDC_MAX_OPEN_ATTEMPTS 8 + +struct _FuQmiPdcUpdater { + GObject parent_instance; + gchar *qmi_port; + QmiDevice *qmi_device; + QmiClientPdc *qmi_client; +}; + +G_DEFINE_TYPE (FuQmiPdcUpdater, fu_qmi_pdc_updater, G_TYPE_OBJECT) + +typedef struct { + GMainLoop *mainloop; + QmiDevice *qmi_device; + QmiClientPdc *qmi_client; + GError *error; + guint open_attempts; +} OpenContext; + +static void fu_qmi_pdc_updater_qmi_device_open_attempt (OpenContext *ctx); + +static void +fu_qmi_pdc_updater_qmi_device_open_abort_ready (GObject *qmi_device, GAsyncResult *res, gpointer user_data) +{ + OpenContext *ctx = (OpenContext *) user_data; + + g_warn_if_fail (ctx->error != NULL); + + /* ignore errors when aborting open */ + qmi_device_close_finish (QMI_DEVICE (qmi_device), res, NULL); + + ctx->open_attempts--; + if (ctx->open_attempts == 0) { + g_clear_object (&ctx->qmi_client); + g_clear_object (&ctx->qmi_device); + g_main_loop_quit (ctx->mainloop); + return; + } + + /* retry */ + g_clear_error (&ctx->error); + fu_qmi_pdc_updater_qmi_device_open_attempt (ctx); +} + +static void +fu_qmi_pdc_updater_open_abort (OpenContext *ctx) +{ + qmi_device_close_async (ctx->qmi_device, + 15, NULL, fu_qmi_pdc_updater_qmi_device_open_abort_ready, ctx); +} + +static void +fu_qmi_pdc_updater_qmi_device_allocate_client_ready (GObject *qmi_device, GAsyncResult *res, gpointer user_data) +{ + OpenContext *ctx = (OpenContext *) user_data; + + ctx->qmi_client = QMI_CLIENT_PDC (qmi_device_allocate_client_finish (QMI_DEVICE (qmi_device), res, &ctx->error)); + if (ctx->qmi_client == NULL) { + fu_qmi_pdc_updater_open_abort (ctx); + return; + } + + g_main_loop_quit (ctx->mainloop); +} + +static void +fu_qmi_pdc_updater_qmi_device_open_ready (GObject *qmi_device, GAsyncResult *res, gpointer user_data) +{ + OpenContext *ctx = (OpenContext *) user_data; + + if (!qmi_device_open_finish (QMI_DEVICE (qmi_device), res, &ctx->error)) { + fu_qmi_pdc_updater_open_abort (ctx); + return; + } + + qmi_device_allocate_client (ctx->qmi_device, QMI_SERVICE_PDC, QMI_CID_NONE, 5, NULL, + fu_qmi_pdc_updater_qmi_device_allocate_client_ready, ctx); +} + +static void +fu_qmi_pdc_updater_qmi_device_open_attempt (OpenContext *ctx) +{ + QmiDeviceOpenFlags open_flags = QMI_DEVICE_OPEN_FLAGS_NONE; + + /* automatically detect QMI and MBIM ports */ + open_flags |= QMI_DEVICE_OPEN_FLAGS_AUTO; + /* qmi pdc requires indications, so enable them by default */ + open_flags |= QMI_DEVICE_OPEN_FLAGS_EXPECT_INDICATIONS; + /* all communication through the proxy */ + open_flags |= QMI_DEVICE_OPEN_FLAGS_PROXY; + + g_debug ("trying to open QMI device..."); + qmi_device_open (ctx->qmi_device, open_flags, 5, NULL, + fu_qmi_pdc_updater_qmi_device_open_ready, ctx); +} + +static void +fu_qmi_pdc_updater_qmi_device_new_ready (GObject *source, GAsyncResult *res, gpointer user_data) +{ + OpenContext *ctx = (OpenContext *) user_data; + + ctx->qmi_device = qmi_device_new_finish (res, &ctx->error); + if (ctx->qmi_device == NULL) { + g_main_loop_quit (ctx->mainloop); + return; + } + + fu_qmi_pdc_updater_qmi_device_open_attempt (ctx); +} + +gboolean +fu_qmi_pdc_updater_open (FuQmiPdcUpdater *self, GError **error) +{ + g_autoptr(GMainLoop) mainloop = g_main_loop_new (NULL, FALSE); + g_autoptr(GFile) qmi_device_file = g_file_new_for_path (self->qmi_port); + OpenContext ctx = { + .mainloop = mainloop, + .qmi_device = NULL, + .qmi_client = NULL, + .error = NULL, + .open_attempts = FU_QMI_PDC_MAX_OPEN_ATTEMPTS, + }; + + qmi_device_new (qmi_device_file, NULL, fu_qmi_pdc_updater_qmi_device_new_ready, &ctx); + g_main_loop_run (mainloop); + + /* either we have all device, client and config list set, or otherwise error is set */ + + if ((ctx.qmi_device != NULL) && (ctx.qmi_client != NULL)) { + g_warn_if_fail (!ctx.error); + self->qmi_device = ctx.qmi_device; + self->qmi_client = ctx.qmi_client; + /* success */ + return TRUE; + } + + g_warn_if_fail (ctx.error != NULL); + g_warn_if_fail (ctx.qmi_device == NULL); + g_warn_if_fail (ctx.qmi_client == NULL); + g_propagate_error (error, ctx.error); + return FALSE; +} + +typedef struct { + GMainLoop *mainloop; + QmiDevice *qmi_device; + QmiClientPdc *qmi_client; + GError *error; +} CloseContext; + +static void +fu_qmi_pdc_updater_qmi_device_close_ready (GObject *qmi_device, GAsyncResult *res, gpointer user_data) +{ + CloseContext *ctx = (CloseContext *) user_data; + + /* ignore errors when closing if we had one already set when releasing client */ + qmi_device_close_finish (QMI_DEVICE (qmi_device), res, (ctx->error == NULL) ? &ctx->error : NULL); + g_clear_object (&ctx->qmi_device); + g_main_loop_quit (ctx->mainloop); +} + +static void +fu_qmi_pdc_updater_qmi_device_release_client_ready (GObject *qmi_device, GAsyncResult *res, gpointer user_data) +{ + CloseContext *ctx = (CloseContext *) user_data; + + qmi_device_release_client_finish (QMI_DEVICE (qmi_device), res, &ctx->error); + g_clear_object (&ctx->qmi_client); + + qmi_device_close_async (ctx->qmi_device, + 15, NULL, fu_qmi_pdc_updater_qmi_device_close_ready, ctx); +} + +gboolean +fu_qmi_pdc_updater_close (FuQmiPdcUpdater *self, GError **error) +{ + g_autoptr(GMainLoop) mainloop = g_main_loop_new (NULL, FALSE); + CloseContext ctx = { + .mainloop = mainloop, + .qmi_device = g_steal_pointer (&self->qmi_device), + .qmi_client = g_steal_pointer (&self->qmi_client), + }; + + qmi_device_release_client (ctx.qmi_device, QMI_CLIENT (ctx.qmi_client), + QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID, + 5, NULL, fu_qmi_pdc_updater_qmi_device_release_client_ready, &ctx); + g_main_loop_run (mainloop); + + /* we should always have both device and client cleared, and optionally error set */ + + g_warn_if_fail (ctx.qmi_device == NULL); + g_warn_if_fail (ctx.qmi_client == NULL); + + if (ctx.error != NULL) { + g_propagate_error (error, ctx.error); + return FALSE; + } + + return TRUE; +} + +#define QMI_LOAD_CHUNK_SIZE 0x400 + +typedef struct { + GMainLoop *mainloop; + QmiClientPdc *qmi_client; + GError *error; + gulong indication_id; + guint timeout_id; + GBytes *blob; + GArray *digest; + gsize offset; + guint token; +} WriteContext; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcLoadConfigInput, qmi_message_pdc_load_config_input_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcLoadConfigOutput, qmi_message_pdc_load_config_output_unref) +#pragma clang diagnostic pop + +static void fu_qmi_pdc_updater_load_config (WriteContext *ctx); + +static gboolean +fu_qmi_pdc_updater_load_config_timeout (gpointer user_data) +{ + WriteContext *ctx = user_data; + + ctx->timeout_id = 0; + g_signal_handler_disconnect (ctx->qmi_client, ctx->indication_id); + ctx->indication_id = 0; + + g_set_error_literal (&ctx->error, G_IO_ERROR, G_IO_ERROR_FAILED, + "couldn't load mcfg: timed out"); + g_main_loop_quit (ctx->mainloop); + + return G_SOURCE_REMOVE; +} + +static void +fu_qmi_pdc_updater_load_config_indication (QmiClientPdc *client, + QmiIndicationPdcLoadConfigOutput *output, + WriteContext *ctx) +{ + gboolean frame_reset; + guint32 remaining_size; + guint16 error_code = 0; + + g_source_remove (ctx->timeout_id); + ctx->timeout_id = 0; + g_signal_handler_disconnect (ctx->qmi_client, ctx->indication_id); + ctx->indication_id = 0; + + if (!qmi_indication_pdc_load_config_output_get_indication_result (output, &error_code, &ctx->error)) { + g_main_loop_quit (ctx->mainloop); + return; + } + + if (error_code != 0) { + /* when a given mcfg file already exists in the device, an "invalid id" error is returned; + * the error naming here is a bit off, as the same protocol error number is used both for + * 'invalid id' and 'invalid qos id' + */ + if (error_code == QMI_PROTOCOL_ERROR_INVALID_QOS_ID) { + g_debug ("file already available in device"); + g_main_loop_quit (ctx->mainloop); + return; + } + + g_set_error (&ctx->error, G_IO_ERROR, G_IO_ERROR_FAILED, + "couldn't load mcfg: %s", qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + g_main_loop_quit (ctx->mainloop); + return; + } + + if (qmi_indication_pdc_load_config_output_get_frame_reset (output, &frame_reset, NULL) && frame_reset) { + g_set_error (&ctx->error, G_IO_ERROR, G_IO_ERROR_FAILED, + "couldn't load mcfg: sent data discarded"); + g_main_loop_quit (ctx->mainloop); + return; + } + + if (!qmi_indication_pdc_load_config_output_get_remaining_size (output, &remaining_size, &ctx->error)) { + g_prefix_error (&ctx->error, "couldn't load remaining size: "); + g_main_loop_quit (ctx->mainloop); + return; + } + + if (remaining_size == 0) { + g_debug ("finished loading mcfg"); + g_main_loop_quit (ctx->mainloop); + return; + } + + g_debug ("loading next chunk (%u bytes remaining)", remaining_size); + fu_qmi_pdc_updater_load_config (ctx); +} + +static void +fu_qmi_pdc_updater_load_config_ready (GObject *qmi_client, GAsyncResult *res, gpointer user_data) +{ + WriteContext *ctx = (WriteContext *) user_data; + g_autoptr(QmiMessagePdcLoadConfigOutput) output = NULL; + + output = qmi_client_pdc_load_config_finish (QMI_CLIENT_PDC (qmi_client), res, &ctx->error); + if (output == NULL) { + g_main_loop_quit (ctx->mainloop); + return; + } + + if (!qmi_message_pdc_load_config_output_get_result (output, &ctx->error)) { + g_main_loop_quit (ctx->mainloop); + return; + } + + /* after receiving the response to our request, we now expect an indication + * with the actual result of the operation */ + g_warn_if_fail (ctx->indication_id == 0); + ctx->indication_id = g_signal_connect (ctx->qmi_client, "load-config", + G_CALLBACK (fu_qmi_pdc_updater_load_config_indication), ctx); + + /* don't wait forever */ + g_warn_if_fail (ctx->timeout_id == 0); + ctx->timeout_id = g_timeout_add_seconds (5, fu_qmi_pdc_updater_load_config_timeout, ctx); +} + +static void +fu_qmi_pdc_updater_load_config (WriteContext *ctx) +{ + g_autoptr(QmiMessagePdcLoadConfigInput) input = NULL; + g_autoptr(GArray) chunk = NULL; + gsize full_size; + gsize chunk_size; + + input = qmi_message_pdc_load_config_input_new (); + qmi_message_pdc_load_config_input_set_token (input, ctx->token++, NULL); + + full_size = g_bytes_get_size (ctx->blob); + if ((ctx->offset + QMI_LOAD_CHUNK_SIZE) > full_size) + chunk_size = full_size - ctx->offset; + else + chunk_size = QMI_LOAD_CHUNK_SIZE; + + chunk = g_array_sized_new (FALSE, FALSE, sizeof (guint8), chunk_size); + g_array_set_size (chunk, chunk_size); + memcpy (chunk->data, (const guint8 *)g_bytes_get_data (ctx->blob, NULL) + ctx->offset, chunk_size); + + qmi_message_pdc_load_config_input_set_config_chunk (input, + QMI_PDC_CONFIGURATION_TYPE_SOFTWARE, + ctx->digest, + full_size, + chunk, + NULL); + ctx->offset += chunk_size; + + qmi_client_pdc_load_config (ctx->qmi_client, input, 10, NULL, + fu_qmi_pdc_updater_load_config_ready, ctx); +} + +static GArray * +fu_qmi_pdc_updater_get_checksum (GBytes *blob) +{ + gsize file_size; + gsize hash_size; + GArray *digest; + g_autoptr(GChecksum) checksum = NULL; + + /* get checksum, to be used as unique id */ + file_size = g_bytes_get_size (blob); + hash_size = g_checksum_type_get_length (G_CHECKSUM_SHA1); + checksum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (checksum, g_bytes_get_data (blob, NULL), file_size); + /* libqmi expects a GArray of bytes, not a GByteArray */ + digest = g_array_sized_new (FALSE, FALSE, sizeof (guint8), hash_size); + g_array_set_size (digest, hash_size); + g_checksum_get_digest (checksum, (guint8 *)digest->data, &hash_size); + + return digest; +} + +GArray * +fu_qmi_pdc_updater_write (FuQmiPdcUpdater *self, const gchar *filename, GBytes *blob, GError **error) +{ + g_autoptr(GMainLoop) mainloop = g_main_loop_new (NULL, FALSE); + g_autoptr(GArray) digest = fu_qmi_pdc_updater_get_checksum (blob); + WriteContext ctx = { + .mainloop = mainloop, + .qmi_client = self->qmi_client, + .error = NULL, + .indication_id = 0, + .timeout_id = 0, + .blob = blob, + .digest = digest, + .offset = 0, + .token = 0, + }; + + fu_qmi_pdc_updater_load_config (&ctx); + g_main_loop_run (mainloop); + + if (ctx.error != NULL) { + g_propagate_error (error, ctx.error); + return NULL; + } + + return g_steal_pointer (&digest); +} + +typedef struct { + GMainLoop *mainloop; + QmiClientPdc *qmi_client; + GError *error; + gulong indication_id; + guint timeout_id; + GArray *digest; + guint token; +} ActivateContext; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcActivateConfigInput, qmi_message_pdc_activate_config_input_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcActivateConfigOutput, qmi_message_pdc_activate_config_output_unref) +#pragma clang diagnostic pop + +static gboolean +fu_qmi_pdc_updater_activate_config_timeout (gpointer user_data) +{ + ActivateContext *ctx = user_data; + + ctx->timeout_id = 0; + g_signal_handler_disconnect (ctx->qmi_client, ctx->indication_id); + ctx->indication_id = 0; + + /* not an error, the device may go away without sending the indication */ + g_main_loop_quit (ctx->mainloop); + + return G_SOURCE_REMOVE; +} + +static void +fu_qmi_pdc_updater_activate_config_indication (QmiClientPdc *client, + QmiIndicationPdcActivateConfigOutput *output, + ActivateContext *ctx) +{ + guint16 error_code = 0; + + g_source_remove (ctx->timeout_id); + ctx->timeout_id = 0; + g_signal_handler_disconnect (ctx->qmi_client, ctx->indication_id); + ctx->indication_id = 0; + + if (!qmi_indication_pdc_activate_config_output_get_indication_result (output, &error_code, &ctx->error)) { + g_main_loop_quit (ctx->mainloop); + return; + } + + if (error_code != 0) { + g_set_error (&ctx->error, G_IO_ERROR, G_IO_ERROR_FAILED, + "couldn't activate config: %s", qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + g_main_loop_quit (ctx->mainloop); + return; + } + + /* assume ok */ + g_debug ("successful activate configuration indication: assuming device reset is ongoing"); + g_main_loop_quit (ctx->mainloop); +} + +static void +fu_qmi_pdc_updater_activate_config_ready (GObject *qmi_client, GAsyncResult *res, gpointer user_data) +{ + ActivateContext *ctx = (ActivateContext *) user_data; + g_autoptr(QmiMessagePdcActivateConfigOutput) output = NULL; + + output = qmi_client_pdc_activate_config_finish (QMI_CLIENT_PDC (qmi_client), res, &ctx->error); + if (output == NULL) { + /* If we didn't receive a response, this is a good indication that the device + * reseted itself, we can consider this a successful operation. + * Note: not using g_error_matches() to avoid matching the domain, because the + * error may be either QMI_CORE_ERROR_TIMEOUT or MBIM_CORE_ERROR_TIMEOUT (same + * numeric value), and we don't want to build-depend on libmbim just for this. + */ + if (ctx->error->code == QMI_CORE_ERROR_TIMEOUT) { + g_debug ("request to activate configuration timed out: assuming device reset is ongoing"); + g_clear_error (&ctx->error); + } + g_main_loop_quit (ctx->mainloop); + return; + } + + if (!qmi_message_pdc_activate_config_output_get_result (output, &ctx->error)) { + g_main_loop_quit (ctx->mainloop); + return; + } + + /* When we activate the config, if the operation is successful, we'll just + * see the modem going away completely. So, do not consider an error the timeout + * waiting for the Activate Config indication, as that is actually a good + * thing. + */ + g_warn_if_fail (ctx->indication_id == 0); + ctx->indication_id = g_signal_connect (ctx->qmi_client, "activate-config", + G_CALLBACK (fu_qmi_pdc_updater_activate_config_indication), ctx); + + /* don't wait forever */ + g_warn_if_fail (ctx->timeout_id == 0); + ctx->timeout_id = g_timeout_add_seconds (5, fu_qmi_pdc_updater_activate_config_timeout, ctx); +} + +static void +fu_qmi_pdc_updater_activate_config (ActivateContext *ctx) +{ + g_autoptr(QmiMessagePdcActivateConfigInput) input = NULL; + + input = qmi_message_pdc_activate_config_input_new (); + qmi_message_pdc_activate_config_input_set_config_type (input, QMI_PDC_CONFIGURATION_TYPE_SOFTWARE, NULL); + qmi_message_pdc_activate_config_input_set_token (input, ctx->token++, NULL); + + g_debug ("activating selected configuration..."); + qmi_client_pdc_activate_config (ctx->qmi_client, input, 5, NULL, + fu_qmi_pdc_updater_activate_config_ready, ctx); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcSetSelectedConfigInput, qmi_message_pdc_set_selected_config_input_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QmiMessagePdcSetSelectedConfigOutput, qmi_message_pdc_set_selected_config_output_unref) +#pragma clang diagnostic pop + +static gboolean +fu_qmi_pdc_updater_set_selected_config_timeout (gpointer user_data) +{ + ActivateContext *ctx = user_data; + + ctx->timeout_id = 0; + g_signal_handler_disconnect (ctx->qmi_client, ctx->indication_id); + ctx->indication_id = 0; + + g_set_error_literal (&ctx->error, G_IO_ERROR, G_IO_ERROR_FAILED, + "couldn't set selected config: timed out"); + g_main_loop_quit (ctx->mainloop); + + return G_SOURCE_REMOVE; +} + +static void +fu_qmi_pdc_updater_set_selected_config_indication (QmiClientPdc *client, + QmiIndicationPdcSetSelectedConfigOutput *output, + ActivateContext *ctx) +{ + guint16 error_code = 0; + + g_source_remove (ctx->timeout_id); + ctx->timeout_id = 0; + g_signal_handler_disconnect (ctx->qmi_client, ctx->indication_id); + ctx->indication_id = 0; + + if (!qmi_indication_pdc_set_selected_config_output_get_indication_result (output, &error_code, &ctx->error)) { + g_main_loop_quit (ctx->mainloop); + return; + } + + if (error_code != 0) { + g_set_error (&ctx->error, G_IO_ERROR, G_IO_ERROR_FAILED, + "couldn't set selected config: %s", qmi_protocol_error_get_string ((QmiProtocolError) error_code)); + g_main_loop_quit (ctx->mainloop); + return; + } + + g_debug ("current configuration successfully selected..."); + + /* now activate config */ + fu_qmi_pdc_updater_activate_config (ctx); +} + +static void +fu_qmi_pdc_updater_set_selected_config_ready (GObject *qmi_client, GAsyncResult *res, gpointer user_data) +{ + ActivateContext *ctx = (ActivateContext *) user_data; + g_autoptr(QmiMessagePdcSetSelectedConfigOutput) output = NULL; + + output = qmi_client_pdc_set_selected_config_finish (QMI_CLIENT_PDC (qmi_client), res, &ctx->error); + if (output == NULL) { + g_main_loop_quit (ctx->mainloop); + return; + } + + if (!qmi_message_pdc_set_selected_config_output_get_result (output, &ctx->error)) { + g_main_loop_quit (ctx->mainloop); + return; + } + + /* after receiving the response to our request, we now expect an indication + * with the actual result of the operation */ + g_warn_if_fail (ctx->indication_id == 0); + ctx->indication_id = g_signal_connect (ctx->qmi_client, "set-selected-config", + G_CALLBACK (fu_qmi_pdc_updater_set_selected_config_indication), ctx); + + /* don't wait forever */ + g_warn_if_fail (ctx->timeout_id == 0); + ctx->timeout_id = g_timeout_add_seconds (5, fu_qmi_pdc_updater_set_selected_config_timeout, ctx); +} + +static void +fu_qmi_pdc_updater_set_selected_config (ActivateContext *ctx) +{ + g_autoptr(QmiMessagePdcSetSelectedConfigInput) input = NULL; + QmiConfigTypeAndId type_and_id; + + type_and_id.config_type = QMI_PDC_CONFIGURATION_TYPE_SOFTWARE; + type_and_id.id = ctx->digest; + + input = qmi_message_pdc_set_selected_config_input_new (); + qmi_message_pdc_set_selected_config_input_set_type_with_id (input, &type_and_id, NULL); + qmi_message_pdc_set_selected_config_input_set_token (input, ctx->token++, NULL); + + g_debug ("selecting current configuration..."); + qmi_client_pdc_set_selected_config (ctx->qmi_client, input, 10, NULL, + fu_qmi_pdc_updater_set_selected_config_ready, ctx); +} + +gboolean +fu_qmi_pdc_updater_activate (FuQmiPdcUpdater *self, GArray *digest, GError **error) +{ + g_autoptr(GMainLoop) mainloop = g_main_loop_new (NULL, FALSE); + ActivateContext ctx = { + .mainloop = mainloop, + .qmi_client = self->qmi_client, + .error = NULL, + .indication_id = 0, + .timeout_id = 0, + .digest = digest, + .token = 0, + }; + + fu_qmi_pdc_updater_set_selected_config (&ctx); + g_main_loop_run (mainloop); + + if (ctx.error != NULL) { + g_propagate_error (error, ctx.error); + return FALSE; + } + + return TRUE; +} + +static void +fu_qmi_pdc_updater_init (FuQmiPdcUpdater *self) +{ +} + +static void +fu_qmi_pdc_updater_finalize (GObject *object) +{ + FuQmiPdcUpdater *self = FU_QMI_PDC_UPDATER (object); + g_warn_if_fail (self->qmi_client == NULL); + g_warn_if_fail (self->qmi_device == NULL); + g_free (self->qmi_port); + G_OBJECT_CLASS (fu_qmi_pdc_updater_parent_class)->finalize (object); +} + +static void +fu_qmi_pdc_updater_class_init (FuQmiPdcUpdaterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_qmi_pdc_updater_finalize; +} + +FuQmiPdcUpdater * +fu_qmi_pdc_updater_new (const gchar *path) +{ + FuQmiPdcUpdater *self = g_object_new (FU_TYPE_QMI_PDC_UPDATER, NULL); + self->qmi_port = g_strdup (path); + return self; +} diff -Nru fwupd-1.0.6/plugins/modem-manager/fu-qmi-pdc-updater.h fwupd-1.2.10/plugins/modem-manager/fu-qmi-pdc-updater.h --- fwupd-1.0.6/plugins/modem-manager/fu-qmi-pdc-updater.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/fu-qmi-pdc-updater.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Aleksander Morgado + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_QMI_PDC_UPDATER_H +#define __FU_QMI_PDC_UPDATER_H + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_QMI_PDC_UPDATER (fu_qmi_pdc_updater_get_type ()) +G_DECLARE_FINAL_TYPE (FuQmiPdcUpdater, fu_qmi_pdc_updater, FU, QMI_PDC_UPDATER, GObject) + +FuQmiPdcUpdater *fu_qmi_pdc_updater_new (const gchar *qmi_port); +gboolean fu_qmi_pdc_updater_open (FuQmiPdcUpdater *self, + GError **error); +GArray *fu_qmi_pdc_updater_write (FuQmiPdcUpdater *self, + const gchar *filename, + GBytes *blob, + GError **error); +gboolean fu_qmi_pdc_updater_activate (FuQmiPdcUpdater *self, + GArray *digest, + GError **error); +gboolean fu_qmi_pdc_updater_close (FuQmiPdcUpdater *self, + GError **error); + +G_END_DECLS + +#endif /* __FU_QMI_PDC_UPDATER_H */ diff -Nru fwupd-1.0.6/plugins/modem-manager/meson.build fwupd-1.2.10/plugins/modem-manager/meson.build --- fwupd-1.0.6/plugins/modem-manager/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginMm"'] + +shared_module('fu_plugin_modem_manager', + fu_hash, + sources : [ + 'fu-plugin-modem-manager.c', + 'fu-mm-device.c', + 'fu-qmi-pdc-updater.c', + 'fu-mm-utils.c' + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + ], + link_with : [ + libfwupdprivate, + ], + dependencies : [ + plugin_deps, + libmm_glib, + libqmi_glib, + ], +) diff -Nru fwupd-1.0.6/plugins/modem-manager/README.md fwupd-1.2.10/plugins/modem-manager/README.md --- fwupd-1.0.6/plugins/modem-manager/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/modem-manager/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,42 @@ +ModemManager +============ + +Introduction +------------ + +This plugin adds support for devices managed by ModemManager. + +GUID Generation +--------------- + +These device use the ModemManager "Firmware Device IDs" as the GUID, e.g. + + * `USB\VID_413C&PID_81D7&REV_0318&CARRIER_VODAFONE` + * `USB\VID_413C&PID_81D7&REV_0318` + * `USB\VID_413C&PID_81D7` + * `USB\VID_413C` + +Update method: fastboot +----------------------- + +If the device supports the 'fastboot' update method, it must also report which +AT command should be used to trigger the modem reboot into fastboot mode. + +Once the device is in fastboot mode, the firmware upgrade process will happen +as defined e.g. in the 'flashfile.xml' file. Every file included in the CAB that +is not listed in the associated 'flashfile.xml' will be totally ignored during +the fastboot upgrade procedure. + +Update method: qmi-pdc +---------------------- + +If the device supports the 'qmi-pdc' update method, the contents of the CAB +file should include files named as 'mcfg.*.mbn' which will be treated as MCFG +configuration files to download into the device using the Persistent Device +Configuration QMI service. + +If a device supports both 'fastboot' and 'qmi-pdc' methods, the fastboot +operation will always be run before the QMI operation, so that e.g. the full +partition where the MCFG files are stored can be wiped out before installing +the new ones. + diff -Nru fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-common.c fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-common.c --- fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-common.h fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-common.h --- fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_NITROKEY_COMMON_H -#define __FU_NITROKEY_COMMON_H +#pragma once #include @@ -29,6 +13,54 @@ guint32 fu_nitrokey_perform_crc32 (const guint8 *data, gsize size); -G_END_DECLS +#define NITROKEY_TRANSACTION_TIMEOUT 100 /* ms */ +#define NITROKEY_NR_RETRIES 5 -#endif /* __FU_NITROKEY_COMMON_H */ +#define NITROKEY_REQUEST_DATA_LENGTH 59 +#define NITROKEY_REPLY_DATA_LENGTH 53 + +#define NITROKEY_CMD_GET_DEVICE_STATUS (0x20 + 14) + +typedef struct __attribute__((packed)) { + guint8 command; + guint8 payload[NITROKEY_REQUEST_DATA_LENGTH]; + guint32 crc; +} NitrokeyHidRequest; + +typedef struct __attribute__((packed)) { + guint8 device_status; + guint8 command_id; + guint32 last_command_crc; + guint8 last_command_status; + guint8 payload[NITROKEY_REPLY_DATA_LENGTH]; + guint32 crc; +} NitrokeyHidResponse; + +/* based from libnitrokey/stick20_commands.h from libnitrokey v3.4.1 */ +typedef struct __attribute__((packed)) { + guint8 _padding[18]; /* stick20_commands.h:132 // 26 - 8 = 18 */ + guint8 SendCounter; + guint8 SendDataType; + guint8 FollowBytesFlag; + guint8 SendSize; + guint16 MagicNumber_StickConfig; + guint8 ReadWriteFlagUncryptedVolume; + guint8 ReadWriteFlagCryptedVolume; + guint8 VersionMajor; + guint8 VersionMinor; + guint8 VersionReservedByte; + guint8 VersionBuildIteration; + guint8 ReadWriteFlagHiddenVolume; + guint8 FirmwareLocked; + guint8 NewSDCardFound; + guint8 SDFillWithRandomChars; + guint32 ActiveSD_CardID; + guint8 VolumeActiceFlag; + guint8 NewSmartCardFound; + guint8 UserPwRetryCount; + guint8 AdminPwRetryCount; + guint32 ActiveSmartCardID; + guint8 StickKeysNotInitiated; +} NitrokeyGetDeviceStatusPayload; + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-device.c fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-device.c --- fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,84 +1,18 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include #include "fu-nitrokey-common.h" #include "fu-nitrokey-device.h" G_DEFINE_TYPE (FuNitrokeyDevice, fu_nitrokey_device, FU_TYPE_USB_DEVICE) -#define NITROKEY_TRANSACTION_TIMEOUT 100 /* ms */ -#define NITROKEY_NR_RETRIES 5 - -#define NITROKEY_REQUEST_DATA_LENGTH 59 -#define NITROKEY_REPLY_DATA_LENGTH 53 - -#define NITROKEY_CMD_GET_DEVICE_STATUS (0x20 + 14) - -typedef struct __attribute__((packed)) { - guint8 command; - guint8 payload[NITROKEY_REQUEST_DATA_LENGTH]; - guint32 crc; -} NitrokeyHidRequest; - -typedef struct __attribute__((packed)) { - guint8 _padding; /* always zero */ - guint8 device_status; - guint32 last_command_crc; - guint8 last_command_status; - guint8 payload[NITROKEY_REPLY_DATA_LENGTH]; - guint32 crc; -} NitrokeyHidResponse; - -/* based from libnitrokey/stick20_commands.h */ -typedef struct __attribute__((packed)) { - guint8 _padding[24]; - guint8 SendCounter; - guint8 SendDataType; - guint8 FollowBytesFlag; - guint8 SendSize; - guint16 MagicNumber_StickConfig; - guint8 ReadWriteFlagUncryptedVolume; - guint8 ReadWriteFlagCryptedVolume; - guint8 VersionReserved1; - guint8 VersionMinor; - guint8 VersionReserved2; - guint8 VersionMajor; - guint8 ReadWriteFlagHiddenVolume; - guint8 FirmwareLocked; - guint8 NewSDCardFound; - guint8 SDFillWithRandomChars; - guint32 ActiveSD_CardID; - guint8 VolumeActiceFlag; - guint8 NewSmartCardFound; - guint8 UserPwRetryCount; - guint8 AdminPwRetryCount; - guint32 ActiveSmartCardID; - guint8 StickKeysNotInitiated; -} NitrokeyGetDeviceStatusPayload; - static void _dump_to_console (const gchar *title, const guint8 *buf, gsize buf_sz) { @@ -222,55 +156,30 @@ } static gboolean -fu_nitrokey_device_probe (FuUsbDevice *device, GError **error) +fu_nitrokey_device_open (FuUsbDevice *device, GError **error) { GUsbDevice *usb_device = fu_usb_device_get_dev (device); - /* not the right kind of device */ - if (g_usb_device_get_vid (usb_device) != 0x20a0 || - g_usb_device_get_pid (usb_device) != 0x4109) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported with this device"); + /* claim interface */ + if (!g_usb_device_claim_interface (usb_device, 0x02, /* idx */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to do claim nitrokey: "); return FALSE; } - /* harcoded */ - fu_device_set_name (FU_DEVICE (device), "Nitrokey Storage"); - fu_device_set_vendor (FU_DEVICE (device), "Nitrokey"); - fu_device_set_summary (FU_DEVICE (device), "A secure memory stick"); - fu_device_add_icon (FU_DEVICE (device), "media-removable"); - - /* also add the USB VID:PID hash of the bootloader */ - fu_device_add_guid (FU_DEVICE (device), "USB\\VID_03EB&PID_2FF1"); - fu_device_set_remove_delay (FU_DEVICE (device), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - - /* allowed, but requires manual bootloader step */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION); - /* success */ return TRUE; } static gboolean -fu_nitrokey_device_open (FuUsbDevice *device, GError **error) +fu_nitrokey_device_setup (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); NitrokeyGetDeviceStatusPayload payload; guint8 buf_reply[NITROKEY_REPLY_DATA_LENGTH]; g_autofree gchar *version = NULL; - /* claim interface */ - if (!g_usb_device_claim_interface (usb_device, 0x02, /* idx */ - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "failed to do claim nitrokey: "); - return FALSE; - } - /* get firmware version */ if (!nitrokey_execute_cmd_full (usb_device, NITROKEY_CMD_GET_DEVICE_STATUS, @@ -281,9 +190,9 @@ return FALSE; } _dump_to_console ("payload", buf_reply, sizeof(buf_reply)); - memcpy (&payload, buf_reply, sizeof(buf_reply)); - version = g_strdup_printf ("%u.%u", payload.VersionMinor, payload.VersionMajor); - fu_device_set_version (FU_DEVICE (device), version); + memcpy (&payload, buf_reply, sizeof(payload)); + version = g_strdup_printf ("%u.%u", payload.VersionMajor, payload.VersionMinor); + fu_device_set_version (FU_DEVICE (device), version, FWUPD_VERSION_FORMAT_PAIR); /* success */ return TRUE; @@ -307,23 +216,24 @@ static void fu_nitrokey_device_init (FuNitrokeyDevice *device) { + fu_device_set_remove_delay (FU_DEVICE (device), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); } static void fu_nitrokey_device_class_init (FuNitrokeyDeviceClass *klass) { + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->setup = fu_nitrokey_device_setup; klass_usb_device->open = fu_nitrokey_device_open; klass_usb_device->close = fu_nitrokey_device_close; - klass_usb_device->probe = fu_nitrokey_device_probe; } FuNitrokeyDevice * -fu_nitrokey_device_new (GUsbDevice *usb_device) +fu_nitrokey_device_new (FuUsbDevice *device) { - FuNitrokeyDevice *device; - device = g_object_new (FU_TYPE_NITROKEY_DEVICE, - "usb-device", usb_device, - NULL); - return FU_NITROKEY_DEVICE (device); + FuNitrokeyDevice *self = g_object_new (FU_TYPE_NITROKEY_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return FU_NITROKEY_DEVICE (self); } diff -Nru fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-device.h fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-device.h --- fwupd-1.0.6/plugins/nitrokey/fu-nitrokey-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/fu-nitrokey-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_NITROKEY_DEVICE_H -#define __FU_NITROKEY_DEVICE_H - -#include -#include +#pragma once #include "fu-plugin.h" @@ -37,8 +18,6 @@ FuUsbDeviceClass parent_class; }; -FuNitrokeyDevice *fu_nitrokey_device_new (GUsbDevice *usb_device); +FuNitrokeyDevice *fu_nitrokey_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_NITROKEY_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/nitrokey/fu-plugin-nitrokey.c fwupd-1.2.10/plugins/nitrokey/fu-plugin-nitrokey.c --- fwupd-1.0.6/plugins/nitrokey/fu-plugin-nitrokey.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/fu-plugin-nitrokey.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,45 +1,36 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "fu-nitrokey-device.h" #include "fu-nitrokey-common.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); +} + gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; - g_autoptr(FuNitrokeyDevice) device = NULL; + g_autoptr(FuNitrokeyDevice) dev = NULL; /* open the device */ - device = fu_nitrokey_device_new (usb_device); - locker = fu_device_locker_new (device, error); + dev = fu_nitrokey_device_new (device); + locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; /* success */ - fu_plugin_device_add (plugin, FU_DEVICE (device)); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } diff -Nru fwupd-1.0.6/plugins/nitrokey/fu-self-test.c fwupd-1.2.10/plugins/nitrokey/fu-self-test.c --- fwupd-1.0.6/plugins/nitrokey/fu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -26,6 +11,59 @@ #include "fu-nitrokey-common.h" static void +fu_nitrokey_version_test (void) +{ + /* use the Nitrokey Storage v0.53 status response for test, CRC 0xa2762d14 */ + NitrokeyGetDeviceStatusPayload payload; + NitrokeyHidResponse res; + guint32 crc_tmp; + /* 65 bytes of response from HIDAPI; first byte is always 0 */ + const guint8 buf[] = { + /*0x00,*/ + 0x00, 0x2e, 0xef, 0xc4, 0x9b, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2e, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1c, 0x18, 0x33, + 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x45, 0x24, 0xf1, 0x4c, 0x01, 0x00, + 0x03, 0x03, 0xc7, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2d, 0x76, + 0xa2 }; + + /* testing the whole path, as in fu_nitrokey_device_setup()*/ + memcpy (&res, buf, sizeof (buf)); + memcpy (&payload, &res.payload, sizeof (payload)); + + /* verify the version number */ + g_assert_cmpint (payload.VersionMajor, == , 0); + g_assert_cmpint (payload.VersionMinor, == , 53); + g_assert_cmpint (buf[34], == , payload.VersionMinor); + g_assert_cmpint (payload.VersionBuildIteration, == , 0); + + /* verify the response checksum */ + crc_tmp = fu_nitrokey_perform_crc32 (buf, sizeof (res) - 4); + g_assert_cmpint (GUINT32_FROM_LE (res.crc), == , crc_tmp); + +} + +static void +fu_nitrokey_version_test_static (void) +{ + /* use static response from numbered bytes, to make sure fields occupy + * expected bytes */ + NitrokeyGetDeviceStatusPayload payload; + NitrokeyHidResponse res; + + const guint8 buf[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + }; + memcpy (&res, buf, sizeof (buf)); + memcpy (&payload, &res.payload, sizeof (payload)); + g_assert_cmpint (payload.VersionMajor, == , 33); /* 0x1a */ + g_assert_cmpint (payload.VersionMinor, == , 34); /* 0x1b */ + g_assert_cmpint (buf[34], == , 34); +} + +static void fu_nitrokey_func (void) { const guint8 buf[] = { 0x00, 0x01, 0x02, 0x03, @@ -46,5 +84,7 @@ /* tests go here */ g_test_add_func ("/fwupd/nitrokey", fu_nitrokey_func); + g_test_add_func ("/fwupd/nitrokey-version-static", fu_nitrokey_version_test_static); + g_test_add_func ("/fwupd/nitrokey-version", fu_nitrokey_version_test); return g_test_run (); } diff -Nru fwupd-1.0.6/plugins/nitrokey/meson.build fwupd-1.2.10/plugins/nitrokey/meson.build --- fwupd-1.0.6/plugins/nitrokey/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,11 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginNitrokey"'] +install_data(['nitrokey.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_nitrokey', + fu_hash, sources : [ 'fu-nitrokey-device.c', 'fu-nitrokey-common.c', @@ -13,6 +18,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, @@ -22,6 +30,7 @@ if get_option('tests') e = executable( 'nitrokey-self-test', + fu_hash, sources : [ 'fu-nitrokey-common.c', 'fu-self-test.c', diff -Nru fwupd-1.0.6/plugins/nitrokey/nitrokey.quirk fwupd-1.2.10/plugins/nitrokey/nitrokey.quirk --- fwupd-1.0.6/plugins/nitrokey/nitrokey.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/nitrokey.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,7 @@ +# Nitrokey Storage +[DeviceInstanceId=USB\VID_20A0&PID_4109] +Plugin = nitrokey +Flags = needs-bootloader,use-runtime-version +CounterpartGuid = USB\VID_03EB&PID_2FF1 +Summary = A secure memory stick +Icon = media-removable diff -Nru fwupd-1.0.6/plugins/nitrokey/README.md fwupd-1.2.10/plugins/nitrokey/README.md --- fwupd-1.0.6/plugins/nitrokey/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/nitrokey/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -10,3 +10,12 @@ The device is switched to a DFU bootloader only when the secret firmware pin is entered into the nitrokey-app tool. This cannot be automated. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_20A0&PID_4109&REV_0001` + * `USB\VID_20A0&PID_4109` + * `USB\VID_20A0` diff -Nru fwupd-1.0.6/plugins/nvme/fu-nvme-common.c fwupd-1.2.10/plugins/nvme/fu-nvme-common.c --- fwupd-1.0.6/plugins/nvme/fu-nvme-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/fu-nvme-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-nvme-common.h" + +const gchar * +fu_nvme_status_to_string (guint32 status) +{ + switch (status) { + case NVME_SC_SUCCESS: + return "Command completed successfully"; + case NVME_SC_INVALID_OPCODE: + return "Associated command opcode field is not valid"; + case NVME_SC_INVALID_FIELD: + return "Unsupported value in a defined field"; + case NVME_SC_CMDID_CONFLICT: + return "Command identifier is already in use"; + case NVME_SC_DATA_XFER_ERROR: + return "Error while trying to transfer the data or metadata"; + case NVME_SC_POWER_LOSS: + return "Command aborted due to power loss notification"; + case NVME_SC_INTERNAL: + return "Internal error"; + case NVME_SC_ABORT_REQ: + return "Command Abort request"; + case NVME_SC_ABORT_QUEUE: + return "Delete I/O Submission Queue request"; + case NVME_SC_FUSED_FAIL: + return "Other command in a fused operation failing"; + case NVME_SC_FUSED_MISSING: + return "Missing Fused Command"; + case NVME_SC_INVALID_NS: + return "Namespace or the format of that namespace is invalid"; + case NVME_SC_CMD_SEQ_ERROR: + return "Protocol violation in a multicommand sequence"; + case NVME_SC_SANITIZE_FAILED: + return "No recovery actions has been successfully completed"; + case NVME_SC_SANITIZE_IN_PROGRESS: + return "A sanitize operation is in progress"; + case NVME_SC_LBA_RANGE: + return "LBA exceeds the size of the namespace"; + case NVME_SC_NS_WRITE_PROTECTED: + return "Namespace is write protected by the host"; + case NVME_SC_CAP_EXCEEDED: + return "Capacity of the namespace to be exceeded"; + case NVME_SC_NS_NOT_READY: + return "Namespace is not ready to be accessed"; + case NVME_SC_RESERVATION_CONFLICT: + return "Conflict with a reservation on the accessed namespace"; + case NVME_SC_CQ_INVALID: + return "Completion Queue does not exist"; + case NVME_SC_QID_INVALID: + return "Invalid queue identifier specified"; + case NVME_SC_QUEUE_SIZE: + return "Invalid queue size"; + case NVME_SC_ABORT_LIMIT: + return "Outstanding Abort commands has exceeded the limit"; + case NVME_SC_ABORT_MISSING: + return "Abort command is missing"; + case NVME_SC_ASYNC_LIMIT: + return "Outstanding Async commands has been exceeded"; + case NVME_SC_FIRMWARE_SLOT: + return "Slot is invalid or read only"; + case NVME_SC_FIRMWARE_IMAGE: + return "Image specified for activation is invalid"; + case NVME_SC_INVALID_VECTOR: + return "Creation failed due to an invalid interrupt vector"; + case NVME_SC_INVALID_LOG_PAGE: + return "Log page indicated is invalid"; + case NVME_SC_INVALID_FORMAT: + return "LBA Format specified is not supported"; + case NVME_SC_FW_NEEDS_CONV_RESET: + return "commit was successful, but activation requires reset"; + case NVME_SC_INVALID_QUEUE: + return "Failed to delete the I/O Completion Queue specified"; + case NVME_SC_FEATURE_NOT_SAVEABLE: + return "Feature Identifier does not support a saveable value"; + case NVME_SC_FEATURE_NOT_CHANGEABLE: + return "Feature Identifier is not able to be changed"; + case NVME_SC_FEATURE_NOT_PER_NS: + return "Feature Identifier specified is not namespace specific"; + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + return "Commit was successful, activation requires NVM Subsystem"; + case NVME_SC_FW_NEEDS_RESET: + return "Commit was successful, activation requires a reset"; + case NVME_SC_FW_NEEDS_MAX_TIME: + return "Would exceed the Maximum Time for Firmware Activation"; + case NVME_SC_FW_ACIVATE_PROHIBITED: + return "Image specified is being prohibited from activation"; + case NVME_SC_OVERLAPPING_RANGE: + return "Image has overlapping ranges"; + case NVME_SC_NS_INSUFFICENT_CAP: + return "Requires more free space than is currently available"; + case NVME_SC_NS_ID_UNAVAILABLE: + return "Number of namespaces supported has been exceeded"; + case NVME_SC_NS_ALREADY_ATTACHED: + return "Controller is already attached to the namespace"; + case NVME_SC_NS_IS_PRIVATE: + return "Namespace is private"; + case NVME_SC_NS_NOT_ATTACHED: + return "Controller is not attached to the namespace"; + case NVME_SC_THIN_PROV_NOT_SUPP: + return "Thin provisioning is not supported by the controller"; + case NVME_SC_CTRL_LIST_INVALID: + return "Controller list provided is invalid"; + case NVME_SC_BP_WRITE_PROHIBITED: + return "Trying to modify a Boot Partition while it is locked"; + case NVME_SC_BAD_ATTRIBUTES: + return "Bad attributes"; + case NVME_SC_WRITE_FAULT: + return "Write data could not be committed to the media"; + case NVME_SC_READ_ERROR: + return "Read data could not be recovered from the media"; + case NVME_SC_GUARD_CHECK: + return "End-to-end guard check failure"; + case NVME_SC_APPTAG_CHECK: + return "End-to-end application tag check failure"; + case NVME_SC_REFTAG_CHECK: + return "End-to-end reference tag check failure"; + case NVME_SC_COMPARE_FAILED: + return "Miscompare during a Compare command"; + case NVME_SC_ACCESS_DENIED: + return "Access denied"; + case NVME_SC_UNWRITTEN_BLOCK: + return "Read from an LBA range containing a unwritten block"; + case NVME_SC_ANA_PERSISTENT_LOSS: + return "Namespace is in the ANA Persistent Loss state"; + case NVME_SC_ANA_INACCESSIBLE: + return "Namespace being in the ANA Inaccessible state"; + case NVME_SC_ANA_TRANSITION: + return "Namespace transitioning between Async Access states"; + default: + return "Unknown"; + } +} diff -Nru fwupd-1.0.6/plugins/nvme/fu-nvme-common.h fwupd-1.2.10/plugins/nvme/fu-nvme-common.h --- fwupd-1.0.6/plugins/nvme/fu-nvme-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/fu-nvme-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +enum { + /* + * Generic Command Status: + */ + NVME_SC_SUCCESS = 0x0, + NVME_SC_INVALID_OPCODE = 0x1, + NVME_SC_INVALID_FIELD = 0x2, + NVME_SC_CMDID_CONFLICT = 0x3, + NVME_SC_DATA_XFER_ERROR = 0x4, + NVME_SC_POWER_LOSS = 0x5, + NVME_SC_INTERNAL = 0x6, + NVME_SC_ABORT_REQ = 0x7, + NVME_SC_ABORT_QUEUE = 0x8, + NVME_SC_FUSED_FAIL = 0x9, + NVME_SC_FUSED_MISSING = 0xa, + NVME_SC_INVALID_NS = 0xb, + NVME_SC_CMD_SEQ_ERROR = 0xc, + NVME_SC_SGL_INVALID_LAST = 0xd, + NVME_SC_SGL_INVALID_COUNT = 0xe, + NVME_SC_SGL_INVALID_DATA = 0xf, + NVME_SC_SGL_INVALID_METADATA = 0x10, + NVME_SC_SGL_INVALID_TYPE = 0x11, + + NVME_SC_SGL_INVALID_OFFSET = 0x16, + NVME_SC_SGL_INVALID_SUBTYPE = 0x17, + + NVME_SC_SANITIZE_FAILED = 0x1C, + NVME_SC_SANITIZE_IN_PROGRESS = 0x1D, + + NVME_SC_NS_WRITE_PROTECTED = 0x20, + + NVME_SC_LBA_RANGE = 0x80, + NVME_SC_CAP_EXCEEDED = 0x81, + NVME_SC_NS_NOT_READY = 0x82, + NVME_SC_RESERVATION_CONFLICT = 0x83, + + /* + * Command Specific Status: + */ + NVME_SC_CQ_INVALID = 0x100, + NVME_SC_QID_INVALID = 0x101, + NVME_SC_QUEUE_SIZE = 0x102, + NVME_SC_ABORT_LIMIT = 0x103, + NVME_SC_ABORT_MISSING = 0x104, + NVME_SC_ASYNC_LIMIT = 0x105, + NVME_SC_FIRMWARE_SLOT = 0x106, + NVME_SC_FIRMWARE_IMAGE = 0x107, + NVME_SC_INVALID_VECTOR = 0x108, + NVME_SC_INVALID_LOG_PAGE = 0x109, + NVME_SC_INVALID_FORMAT = 0x10a, + NVME_SC_FW_NEEDS_CONV_RESET = 0x10b, + NVME_SC_INVALID_QUEUE = 0x10c, + NVME_SC_FEATURE_NOT_SAVEABLE = 0x10d, + NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e, + NVME_SC_FEATURE_NOT_PER_NS = 0x10f, + NVME_SC_FW_NEEDS_SUBSYS_RESET = 0x110, + NVME_SC_FW_NEEDS_RESET = 0x111, + NVME_SC_FW_NEEDS_MAX_TIME = 0x112, + NVME_SC_FW_ACIVATE_PROHIBITED = 0x113, + NVME_SC_OVERLAPPING_RANGE = 0x114, + NVME_SC_NS_INSUFFICENT_CAP = 0x115, + NVME_SC_NS_ID_UNAVAILABLE = 0x116, + NVME_SC_NS_ALREADY_ATTACHED = 0x118, + NVME_SC_NS_IS_PRIVATE = 0x119, + NVME_SC_NS_NOT_ATTACHED = 0x11a, + NVME_SC_THIN_PROV_NOT_SUPP = 0x11b, + NVME_SC_CTRL_LIST_INVALID = 0x11c, + NVME_SC_BP_WRITE_PROHIBITED = 0x11e, + + /* + * I/O Command Set Specific - NVM commands: + */ + NVME_SC_BAD_ATTRIBUTES = 0x180, + NVME_SC_INVALID_PI = 0x181, + NVME_SC_READ_ONLY = 0x182, + NVME_SC_ONCS_NOT_SUPPORTED = 0x183, + + /* + * I/O Command Set Specific - Fabrics commands: + */ + NVME_SC_CONNECT_FORMAT = 0x180, + NVME_SC_CONNECT_CTRL_BUSY = 0x181, + NVME_SC_CONNECT_INVALID_PARAM = 0x182, + NVME_SC_CONNECT_RESTART_DISC = 0x183, + NVME_SC_CONNECT_INVALID_HOST = 0x184, + + NVME_SC_DISCOVERY_RESTART = 0x190, + NVME_SC_AUTH_REQUIRED = 0x191, + + /* + * Media and Data Integrity Errors: + */ + NVME_SC_WRITE_FAULT = 0x280, + NVME_SC_READ_ERROR = 0x281, + NVME_SC_GUARD_CHECK = 0x282, + NVME_SC_APPTAG_CHECK = 0x283, + NVME_SC_REFTAG_CHECK = 0x284, + NVME_SC_COMPARE_FAILED = 0x285, + NVME_SC_ACCESS_DENIED = 0x286, + NVME_SC_UNWRITTEN_BLOCK = 0x287, + + /* + * Path-related Errors: + */ + NVME_SC_ANA_PERSISTENT_LOSS = 0x301, + NVME_SC_ANA_INACCESSIBLE = 0x302, + NVME_SC_ANA_TRANSITION = 0x303, + + NVME_SC_DNR = 0x4000, +}; + +const gchar *fu_nvme_status_to_string (guint32 status); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/nvme/fu-nvme-device.c fwupd-1.2.10/plugins/nvme/fu-nvme-device.c --- fwupd-1.0.6/plugins/nvme/fu-nvme-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/fu-nvme-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "fu-chunk.h" +#include "fu-nvme-common.h" +#include "fu-nvme-device.h" + +#define FU_NVME_ID_CTRL_SIZE 0x1000 + +struct _FuNvmeDevice { + FuUdevDevice parent_instance; + guint pci_depth; + gint fd; + guint64 write_block_size; +}; + +G_DEFINE_TYPE (FuNvmeDevice, fu_nvme_device, FU_TYPE_UDEV_DEVICE) + +#ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop +#endif + +static void +fu_nvme_device_to_string (FuDevice *device, GString *str) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + g_string_append (str, " FuNvmeDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", self->fd); + g_string_append_printf (str, " pci-depth:\t\t%u\n", self->pci_depth); +} + +/* @addr_start and @addr_end are *inclusive* to match the NMVe specification */ +static gchar * +fu_nvme_device_get_string_safe (const guint8 *buf, guint16 addr_start, guint16 addr_end) +{ + GString *str; + + g_return_val_if_fail (buf != NULL, NULL); + g_return_val_if_fail (addr_start < addr_end, NULL); + + str = g_string_new_len (NULL, addr_end + addr_start + 1); + for (guint16 i = addr_start; i <= addr_end; i++) { + gchar tmp = (gchar) buf[i]; + /* skip leading spaces */ + if (g_ascii_isspace (tmp) && str->len == 0) + continue; + if (g_ascii_isprint (tmp)) + g_string_append_c (str, tmp); + } + + /* nothing found */ + if (str->len == 0) { + g_string_free (str, TRUE); + return NULL; + } + return g_strchomp (g_string_free (str, FALSE)); +} + +static gchar * +fu_nvme_device_get_guid_safe (const guint8 *buf, guint16 addr_start) +{ + if (!fu_common_guid_is_plausible (buf + addr_start)) + return NULL; + return fwupd_guid_to_string ((const fwupd_guid_t *) (buf + addr_start), + FWUPD_GUID_FLAG_MIXED_ENDIAN); +} + +static gboolean +fu_nvme_device_submit_admin_passthru (FuNvmeDevice *self, struct nvme_admin_cmd *cmd, GError **error) +{ + gint rc; + guint32 err; + + /* submit admin command */ + rc = ioctl (self->fd, NVME_IOCTL_ADMIN_CMD, cmd); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to issue admin command 0x%02x: %s", + cmd->opcode, + strerror (errno)); + return FALSE; + } + + /* check the error code */ + err = rc & 0x3ff; + switch (err) { + case NVME_SC_SUCCESS: + /* devices are always added with _NEEDS_REBOOT, so ignore */ + case NVME_SC_FW_NEEDS_CONV_RESET: + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + case NVME_SC_FW_NEEDS_RESET: + return TRUE; + default: + break; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not supported: %s", + fu_nvme_status_to_string (err)); + return FALSE; + +} + +static gboolean +fu_nvme_device_identify_ctrl (FuNvmeDevice *self, guint8 *data, GError **error) +{ + struct nvme_admin_cmd cmd = { + .opcode = 0x06, + .nsid = 0x00, + .addr = 0x0, /* memory address of data */ + .data_len = FU_NVME_ID_CTRL_SIZE, + .cdw10 = 0x01, + .cdw11 = 0x00, + }; + memcpy (&cmd.addr, &data, sizeof (gpointer)); + return fu_nvme_device_submit_admin_passthru (self, &cmd, error); +} + +static gboolean +fu_nvme_device_fw_commit (FuNvmeDevice *self, + guint8 slot, + guint8 action, + guint8 bpid, + GError **error) +{ + struct nvme_admin_cmd cmd = { + .opcode = 0x10, + .cdw10 = (bpid << 31) | (action << 3) | slot, + }; + return fu_nvme_device_submit_admin_passthru (self, &cmd, error); +} + +static gboolean +fu_nvme_device_fw_download (FuNvmeDevice *self, + guint32 addr, + const guint8 *data, + guint32 data_sz, + GError **error) +{ + struct nvme_admin_cmd cmd = { + .opcode = 0x11, + .addr = 0x0, /* memory address of data */ + .data_len = data_sz, + .cdw10 = (data_sz >> 2) - 1, /* convert to DWORDs */ + .cdw11 = addr >> 2, /* convert to DWORDs */ + }; + memcpy (&cmd.addr, &data, sizeof (gpointer)); + return fu_nvme_device_submit_admin_passthru (self, &cmd, error); +} + +static void +fu_nvme_device_parse_cns_maybe_dell (FuNvmeDevice *self, const guint8 *buf) +{ + g_autofree gchar *component_id = NULL; + g_autofree gchar *devid = NULL; + g_autofree gchar *guid_efi = NULL; + g_autofree gchar *guid = NULL; + + /* add extra component ID if set */ + component_id = fu_nvme_device_get_string_safe (buf, 0xc36, 0xc3d); + if (component_id == NULL || + !g_str_is_ascii (component_id) || + strlen (component_id) < 6) { + g_debug ("invalid component ID, skipping"); + return; + } + + /* do not add the FuUdevDevice instance IDs as generic firmware + * should not be used on these OEM-specific devices */ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS); + + /* add instance ID *and* GUID as using no-auto-instance-ids */ + devid = g_strdup_printf ("STORAGE-DELL-%s", component_id); + fu_device_add_instance_id (FU_DEVICE (self), devid); + guid = fwupd_guid_hash_string (devid); + fu_device_add_guid (FU_DEVICE (self), guid); + + /* also add the EFI GUID */ + guid_efi = fu_nvme_device_get_guid_safe (buf, 0x0c26); + if (guid_efi != NULL) + fu_device_add_guid (FU_DEVICE (self), guid_efi); +} + +static gboolean +fu_nvme_device_set_version (FuNvmeDevice *self, const gchar *version, GError **error) +{ + FwupdVersionFormat fmt = fu_device_get_version_format (FU_DEVICE (self)); + + /* unset */ + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN || fmt == FWUPD_VERSION_FORMAT_PLAIN) { + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_PLAIN); + return TRUE; + } + + /* AA.BB.CC.DD */ + if (fmt == FWUPD_VERSION_FORMAT_QUAD) { + guint64 tmp = g_ascii_strtoull (version, NULL, 16); + g_autofree gchar *version_new = NULL; + if (tmp == 0 || tmp > G_MAXUINT32) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%s is not valid 32 bit number", + version); + return FALSE; + } + version_new = fu_common_version_from_uint32 (tmp, FWUPD_VERSION_FORMAT_QUAD); + fu_device_set_version (FU_DEVICE (self), version_new, fmt); + return TRUE; + } + + /* invalid, or not supported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "version format %s not handled", + fwupd_version_format_to_string (fmt)); + return FALSE; +} + +static gboolean +fu_nvme_device_parse_cns (FuNvmeDevice *self, const guint8 *buf, gsize sz, GError **error) +{ + guint8 fawr; + guint8 fwug; + guint8 nfws; + guint8 s1ro; + g_autofree gchar *gu = NULL; + g_autofree gchar *mn = NULL; + g_autofree gchar *sn = NULL; + g_autofree gchar *sr = NULL; + + /* wrong size */ + if (sz != FU_NVME_ID_CTRL_SIZE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to parse blob, expected 0x%04x bytes", + (guint) FU_NVME_ID_CTRL_SIZE); + return FALSE; + } + + /* get sanitiezed string from CNS -- see the following doc for offsets: + * NVM-Express-1_3c-2018.05.24-Ratified.pdf */ + sn = fu_nvme_device_get_string_safe (buf, 4, 23); + if (sn != NULL) + fu_device_set_serial (FU_DEVICE (self), sn); + mn = fu_nvme_device_get_string_safe (buf, 24, 63); + if (mn != NULL) + fu_device_set_name (FU_DEVICE (self), mn); + sr = fu_nvme_device_get_string_safe (buf, 64, 71); + if (sr != NULL) { + if (!fu_nvme_device_set_version (self, sr, error)) + return FALSE; + } + + /* firmware update granularity (FWUG) */ + fwug = buf[319]; + if (fwug != 0x00 && fwug != 0xff) + self->write_block_size = ((guint64) fwug) * 0x1000; + + /* firmware slot information */ + fawr = (buf[260] & 0x10) >> 4; + nfws = (buf[260] & 0x0e) >> 1; + s1ro = buf[260] & 0x01; + g_debug ("fawr: %u, nr fw slots: %u, slot1 r/o: %u", fawr, nfws, s1ro); + + /* FRU globally unique identifier (FGUID) */ + gu = fu_nvme_device_get_guid_safe (buf, 127); + if (gu != NULL) + fu_device_add_guid (FU_DEVICE (self), gu); + + /* Dell helpfully provide an EFI GUID we can use in the vendor offset, + * but don't have a header or any magic we can use -- so check if the + * component ID looks plausible and the GUID is "sane" */ + fu_nvme_device_parse_cns_maybe_dell (self, buf); + + /* fall back to the device description */ + if (fu_device_get_guids (FU_DEVICE (self))->len == 0) { + g_debug ("no vendor GUID, falling back to mn"); + fu_device_add_instance_id (FU_DEVICE (self), mn); + } + return TRUE; +} + +static void +fu_nvme_device_dump (const gchar *title, const guint8 *buf, gsize sz) +{ + if (g_getenv ("FWPUD_NVME_VERBOSE") == NULL) + return; + g_print ("%s (%" G_GSIZE_FORMAT "):", title, sz); + for (gsize i = 0; i < sz; i++) { + if (i % 64 == 0) + g_print ("\naddr 0x%04x: ", (guint) i); + g_print ("%02x", buf[i]); + } + g_print ("\n"); +} + +static gboolean +fu_nvme_device_open (FuDevice *device, GError **error) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + self->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDONLY); + if (self->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s: %s", + g_udev_device_get_device_file (udev_device), + strerror (errno)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_nvme_device_probe (FuUdevDevice *device, GError **error) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "pci", error)) + return FALSE; + + /* look at the PCI depth to work out if in an external enclosure */ + self->pci_depth = fu_udev_device_get_slot_depth (device, "pci"); + if (self->pci_depth <= 2) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + + /* all devices need at least a warm reset, but some quirked drives + * need a full "cold" shutdown and startup */ + if (!fu_device_has_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + + return TRUE; +} + +static gboolean +fu_nvme_device_setup (FuDevice *device, GError **error) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + guint8 buf[FU_NVME_ID_CTRL_SIZE] = { 0x0 }; + + /* get and parse CNS */ + if (!fu_nvme_device_identify_ctrl (self, buf, error)) { + g_prefix_error (error, "failed to identify %s: ", + fu_device_get_physical_id (FU_DEVICE (self))); + return FALSE; + } + fu_nvme_device_dump ("CNS", buf, sizeof (buf)); + if (!fu_nvme_device_parse_cns (self, buf, sizeof(buf), error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_nvme_device_close (FuDevice *device, GError **error) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = 0; + return TRUE; +} + +static gboolean +fu_nvme_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + g_autoptr(GBytes) fw2 = NULL; + g_autoptr(GPtrArray) chunks = NULL; + guint64 block_size = self->write_block_size > 0 ? + self->write_block_size : 0x1000; + + /* some vendors provide firmware files whose sizes are not multiples + * of blksz *and* the device won't accept blocks of different sizes */ + if (fu_device_has_custom_flag (device, "force-align")) { + fw2 = fu_common_bytes_align (fw, block_size, 0xff); + } else { + fw2 = g_bytes_ref (fw); + } + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw2, + 0x00, /* start_addr */ + 0x00, /* page_sz */ + block_size); /* block size */ + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_nvme_device_fw_download (self, + chk->address, + chk->data, + chk->data_sz, + error)) { + g_prefix_error (error, "failed to write chunk %u: ", i); + return FALSE; + } + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len + 1); + } + + /* commit */ + if (!fu_nvme_device_fw_commit (self, + 0x00, /* let controller choose */ + 0x01, /* download replaces, activated on reboot */ + 0x00, /* boot partition identifier */ + error)) { + g_prefix_error (error, "failed to commit to auto slot: "); + return FALSE; + } + + /* success! */ + fu_device_set_progress (device, 100); + return TRUE; +} + +static gboolean +fu_nvme_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuNvmeDevice *self = FU_NVME_DEVICE (device); + if (g_strcmp0 (key, "NvmeBlockSize") == 0) { + self->write_block_size = fu_common_strtoull (value); + return TRUE; + } + + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_nvme_device_init (FuNvmeDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_summary (FU_DEVICE (self), "NVM Express Solid State Drive"); + fu_device_add_icon (FU_DEVICE (self), "drive-harddisk"); +} + +static void +fu_nvme_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_nvme_device_parent_class)->finalize (object); +} + +static void +fu_nvme_device_class_init (FuNvmeDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_udev_device = FU_UDEV_DEVICE_CLASS (klass); + object_class->finalize = fu_nvme_device_finalize; + klass_device->to_string = fu_nvme_device_to_string; + klass_device->set_quirk_kv = fu_nvme_device_set_quirk_kv; + klass_device->open = fu_nvme_device_open; + klass_device->setup = fu_nvme_device_setup; + klass_device->close = fu_nvme_device_close; + klass_device->write_firmware = fu_nvme_device_write_firmware; + klass_udev_device->probe = fu_nvme_device_probe; +} + +FuNvmeDevice * +fu_nvme_device_new (FuUdevDevice *device) +{ + FuNvmeDevice *self = g_object_new (FU_TYPE_NVME_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} + +FuNvmeDevice * +fu_nvme_device_new_from_blob (const guint8 *buf, gsize sz, GError **error) +{ + g_autoptr(FuNvmeDevice) self = g_object_new (FU_TYPE_NVME_DEVICE, NULL); + if (!fu_nvme_device_parse_cns (self, buf, sz, error)) + return NULL; + return g_steal_pointer (&self); +} diff -Nru fwupd-1.0.6/plugins/nvme/fu-nvme-device.h fwupd-1.2.10/plugins/nvme/fu-nvme-device.h --- fwupd-1.0.6/plugins/nvme/fu-nvme-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/fu-nvme-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_NVME_DEVICE (fu_nvme_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuNvmeDevice, fu_nvme_device, FU, NVME_DEVICE, FuUdevDevice) + +FuNvmeDevice *fu_nvme_device_new (FuUdevDevice *device); +FuNvmeDevice *fu_nvme_device_new_from_blob (const guint8 *buf, + gsize sz, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/nvme/fu-plugin-nvme.c fwupd-1.2.10/plugins/nvme/fu-plugin-nvme.c --- fwupd-1.0.6/plugins/nvme/fu-plugin-nvme.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/fu-plugin-nvme.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-nvme-device.h" + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + g_autoptr(FuNvmeDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "nvme") != 0) + return TRUE; + + dev = fu_nvme_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "nvme"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.nvmexpress"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} diff -Nru fwupd-1.0.6/plugins/nvme/fu-self-test.c fwupd-1.2.10/plugins/nvme/fu-self-test.c --- fwupd-1.0.6/plugins/nvme/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-device-private.h" +#include "fu-nvme-device.h" +#include "fu-test.h" + +static void +fu_nvme_cns_func (void) +{ + gboolean ret; + gsize sz; + g_autofree gchar *data = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuNvmeDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + path = fu_test_get_filename (TESTDATADIR, "TOSHIBA_THNSN5512GPU7.bin"); + g_assert_nonnull (path); + ret = g_file_get_contents (path, &data, &sz, &error); + g_assert_no_error (error); + g_assert (ret); + dev = fu_nvme_device_new_from_blob ((guint8 *)data, sz, &error); + g_assert_no_error (error); + g_assert_nonnull (dev); + fu_device_convert_instance_ids (FU_DEVICE (dev)); + g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), ==, "THNSN5512GPU7 TOSHIBA"); + g_assert_cmpstr (fu_device_get_version (FU_DEVICE (dev)), ==, "410557LA"); + g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), ==, "37RSDEADBEEF"); + g_assert_cmpstr (fu_device_get_guid_default (FU_DEVICE (dev)), ==, "e1409b09-50cf-5aef-8ad8-760b9022f88d"); +} + +static void +fu_nvme_cns_all_func (void) +{ + const gchar *fn; + g_autofree gchar *path = NULL; + g_autoptr(GDir) dir = NULL; + + /* may or may not exist */ + path = fu_test_get_filename (TESTDATADIR, "blobs"); + if (path == NULL) + return; + dir = g_dir_open (path, 0, NULL); + while ((fn = g_dir_read_name (dir)) != NULL) { + gsize sz; + g_autofree gchar *data = NULL; + g_autofree gchar *filename = NULL; + g_autoptr(FuNvmeDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + filename = g_build_filename (path, fn, NULL); + g_print ("parsing %s... ", filename); + if (!g_file_get_contents (filename, &data, &sz, &error)) { + g_print ("failed to load %s: %s\n", filename, error->message); + continue; + } + dev = fu_nvme_device_new_from_blob ((guint8 *) data, sz, &error); + if (dev == NULL) { + g_print ("failed to load %s: %s\n", filename, error->message); + continue; + } + g_assert_cmpstr (fu_device_get_name (FU_DEVICE (dev)), !=, NULL); + g_assert_cmpstr (fu_device_get_version (FU_DEVICE (dev)), !=, NULL); + g_assert_cmpstr (fu_device_get_serial (FU_DEVICE (dev)), !=, NULL); + g_print ("done\n"); + } +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/fwupd/cns", fu_nvme_cns_func); + g_test_add_func ("/fwupd/cns{all}", fu_nvme_cns_all_func); + return g_test_run (); +} diff -Nru fwupd-1.0.6/plugins/nvme/meson.build fwupd-1.2.10/plugins/nvme/meson.build --- fwupd-1.0.6/plugins/nvme/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,61 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginNvme"'] + +install_data([ + 'nvme.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_nvme', + fu_hash, + sources : [ + 'fu-plugin-nvme.c', + 'fu-nvme-common.c', + 'fu-nvme-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + libfwupdprivate, + ], + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'nvme-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-nvme-common.c', + 'fu-nvme-device.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../..'), + include_directories('../../libfwupd'), + include_directories('../../src'), + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('nvme-self-test', e) +endif diff -Nru fwupd-1.0.6/plugins/nvme/nvme.quirk fwupd-1.2.10/plugins/nvme/nvme.quirk --- fwupd-1.0.6/plugins/nvme/nvme.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/nvme.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +# Phison +[DeviceInstanceId=NVME\VEN_1987] +Flags = force-align,needs-shutdown diff -Nru fwupd-1.0.6/plugins/nvme/README.md fwupd-1.2.10/plugins/nvme/README.md --- fwupd-1.0.6/plugins/nvme/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,51 @@ +NVMe +==== + +Introduction +------------ + +This plugin adds support for NVMe storage hardware. Devices are enumerated from +the Identify Controller data structure and can be updated with appropriate +firmware file. Firmware is sent in 4kB chunks and activated on next reboot. + +The device GUID is read from the vendor specific area and if not found then +generated from the trimmed model string. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.nvmexpress + +GUID Generation +--------------- + +These device use the NVMe DeviceInstanceId values, e.g. + + * `NVME\VEN_1179&DEV_010F&REV_01` + * `NVME\VEN_1179&DEV_010F` + * `NVME\VEN_1179` + +The FRU globally unique identifier (FGUID) is also added from the CNS if set. +Please refer to this document for more details on how to add support for FGUID: +https://nvmexpress.org/wp-content/uploads/NVM_Express_Revision_1.3.pdf + +Additionally, for NVMe drives with Dell vendor firmware two extra GUIDs are +added: + + * `STORAGE-DELL-${component-id}` + +and any optional GUID saved in the vendor extension block. + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +| `NvmeBlockSize` | The block size used for NVMe writes | 1.1.3 | +| `Flags` | `force-align` if image should be padded | 1.2.4 | diff -Nru fwupd-1.0.6/plugins/nvme/tests/.gitignore fwupd-1.2.10/plugins/nvme/tests/.gitignore --- fwupd-1.0.6/plugins/nvme/tests/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/nvme/tests/.gitignore 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +blobs Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/nvme/tests/TOSHIBA_THNSN5512GPU7.bin differ diff -Nru fwupd-1.0.6/plugins/README.md fwupd-1.2.10/plugins/README.md --- fwupd-1.0.6/plugins/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -5,12 +5,15 @@ and writing different firmware) as well as ways quirk their behavior. You can find more information about the architecture in the developers section -of the [fwupd website](http://www.fwupd.org). +of the [fwupd website](https://fwupd.org). If you have a firmware specification and would like to see support in this project, please file an issue and share the spec. Patches are also welcome. +We will not accept plugins that upgrade hardware using a proprietary Linux +executable, library, or DBus interface. + Plugin interaction ------------------ Some plugins may be able to influence the behavior of other plugins. diff -Nru fwupd-1.0.6/plugins/redfish/fu-plugin-redfish.c fwupd-1.2.10/plugins/redfish/fu-plugin-redfish.c --- fwupd-1.0.6/plugins/redfish/fu-plugin-redfish.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/fu-plugin-redfish.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-redfish-client.h" +#include "fu-redfish-common.h" + +struct FuPluginData { + FuRedfishClient *client; +}; + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + + return fu_redfish_client_update (data->client, device, blob_fw, error); +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + GPtrArray *devices; + + /* get the list of devices */ + if (!fu_redfish_client_coldplug (data->client, error)) + return FALSE; + devices = fu_redfish_client_get_devices (data->client); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + fu_plugin_device_add (plugin, device); + } + return TRUE; +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + GBytes *smbios_data = fu_plugin_get_smbios_data (plugin, REDFISH_SMBIOS_TABLE_TYPE); + g_autofree gchar *redfish_uri = NULL; + g_autofree gchar *ca_check = NULL; + + /* read the conf file */ + redfish_uri = fu_plugin_get_config_value (plugin, "Uri"); + if (redfish_uri != NULL) { + g_autofree gchar *username = NULL; + g_autofree gchar *password = NULL; + const gchar *ip_str = NULL; + g_auto(GStrv) split = NULL; + guint64 port; + + if (g_str_has_prefix (redfish_uri, "https://")) { + fu_redfish_client_set_https (data->client, TRUE); + ip_str = redfish_uri + strlen ("https://"); + } else if (g_str_has_prefix (redfish_uri, "http://")) { + fu_redfish_client_set_https (data->client, FALSE); + ip_str = redfish_uri + strlen ("http://"); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "in valid scheme"); + return FALSE; + } + + split = g_strsplit (ip_str, ":", 2); + fu_redfish_client_set_hostname (data->client, split[0]); + port = g_ascii_strtoull (split[1], NULL, 10); + if (port == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no port specified"); + return FALSE; + } + fu_redfish_client_set_port (data->client, port); + + username = fu_plugin_get_config_value (plugin, "Username"); + password = fu_plugin_get_config_value (plugin, "Password"); + if (username != NULL && password != NULL) { + fu_redfish_client_set_username (data->client, username); + fu_redfish_client_set_password (data->client, password); + } + } else { + if (smbios_data == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no SMBIOS table"); + return FALSE; + } + } + + ca_check = fu_plugin_get_config_value (plugin, "CACheck"); + if (ca_check != NULL && g_ascii_strcasecmp (ca_check, "false") == 0) + fu_redfish_client_set_cacheck (data->client, FALSE); + else + fu_redfish_client_set_cacheck (data->client, TRUE); + + return fu_redfish_client_setup (data->client, smbios_data, error); +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + data->client = fu_redfish_client_new (); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.dmtf.redfish"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_object_unref (data->client); +} diff -Nru fwupd-1.0.6/plugins/redfish/fu-redfish-client.c fwupd-1.2.10/plugins/redfish/fu-redfish-client.c --- fwupd-1.0.6/plugins/redfish/fu-redfish-client.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/fu-redfish-client.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,850 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fwupd-error.h" +#include "fwupd-enums.h" + +#include "fu-device.h" + +#include "fu-redfish-client.h" +#include "fu-redfish-common.h" + +struct _FuRedfishClient +{ + GObject parent_instance; + SoupSession *session; + gchar *hostname; + guint port; + gchar *username; + gchar *password; + gchar *update_uri_path; + gchar *push_uri_path; + gboolean auth_created; + gboolean use_https; + gboolean cacheck; + GPtrArray *devices; +}; + +G_DEFINE_TYPE (FuRedfishClient, fu_redfish_client, G_TYPE_OBJECT) + +static void +fu_redfish_client_set_auth (FuRedfishClient *self, SoupURI *uri, + SoupMessage *msg) +{ + if ((self->username != NULL && self->password != NULL) && + self->auth_created == FALSE) { + /* + * Some redfish implementations miss WWW-Authenticate + * header for a 401 response, and SoupAuthManager couldn't + * generate SoupAuth accordingly. Since DSP0266 makes + * Basic Authorization a requirement for redfish, it shall be + * safe to use Basic Auth for all redfish implementations. + */ + SoupAuthManager *manager = SOUP_AUTH_MANAGER (soup_session_get_feature (self->session, SOUP_TYPE_AUTH_MANAGER)); + g_autoptr(SoupAuth) auth = soup_auth_new (SOUP_TYPE_AUTH_BASIC, + msg, "Basic"); + soup_auth_authenticate (auth, self->username, self->password); + soup_auth_manager_use_auth (manager, uri, auth); + self->auth_created = TRUE; + } +} + +static GBytes * +fu_redfish_client_fetch_data (FuRedfishClient *self, const gchar *uri_path, GError **error) +{ + guint status_code; + g_autoptr(SoupMessage) msg = NULL; + g_autoptr(SoupURI) uri = NULL; + + /* create URI */ + uri = soup_uri_new (NULL); + soup_uri_set_scheme (uri, self->use_https ? "https" : "http"); + soup_uri_set_path (uri, uri_path); + soup_uri_set_host (uri, self->hostname); + soup_uri_set_port (uri, self->port); + msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); + if (msg == NULL) { + g_autofree gchar *tmp = soup_uri_to_string (uri, FALSE); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI %s", tmp); + return NULL; + } + fu_redfish_client_set_auth (self, uri, msg); + status_code = soup_session_send_message (self->session, msg); + if (status_code != SOUP_STATUS_OK) { + g_autofree gchar *tmp = soup_uri_to_string (uri, FALSE); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to download %s: %s", + tmp, soup_status_get_phrase (status_code)); + return NULL; + } + return g_bytes_new (msg->response_body->data, msg->response_body->length); +} + +static gboolean +fu_redfish_client_coldplug_member (FuRedfishClient *self, + JsonObject *member, + GError **error) +{ + g_autoptr(FuDevice) dev = NULL; + const gchar *guid = NULL; + g_autofree gchar *id = NULL; + + if (json_object_has_member (member, "SoftwareId")) { + guid = json_object_get_string_member (member, "SoftwareId"); + } else if (json_object_has_member (member, "Oem")) { + JsonObject *oem = json_object_get_object_member (member, "Oem"); + if (oem != NULL && json_object_has_member (oem, "Hpe")) { + JsonObject *hpe = json_object_get_object_member (oem, "Hpe"); + if (hpe != NULL && json_object_has_member (hpe, "DeviceClass")) + guid = json_object_get_string_member (hpe, "DeviceClass"); + } + } + + /* skip the devices without guid */ + if (guid == NULL) + return TRUE; + + dev = fu_device_new (); + + id = g_strdup_printf ("Redfish-Inventory-%s", + json_object_get_string_member (member, "Id")); + fu_device_set_id (dev, id); + + fu_device_add_guid (dev, guid); + if (json_object_has_member (member, "Name")) + fu_device_set_name (dev, json_object_get_string_member (member, "Name")); + fu_device_set_summary (dev, "Redfish device"); + if (json_object_has_member (member, "Version")) { + fu_device_set_version (dev, json_object_get_string_member (member, "Version"), + FWUPD_VERSION_FORMAT_UNKNOWN); + } + if (json_object_has_member (member, "LowestSupportedVersion")) + fu_device_set_version_lowest (dev, json_object_get_string_member (member, "LowestSupportedVersion")); + if (json_object_has_member (member, "Description")) + fu_device_set_description (dev, json_object_get_string_member (member, "Description")); + if (json_object_has_member (member, "Updateable")) { + if (json_object_get_boolean_member (member, "Updateable")) + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + /* assume the device is updatable */ + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } + + /* success */ + g_ptr_array_add (self->devices, g_steal_pointer (&dev)); + return TRUE; +} + +static gboolean +fu_redfish_client_coldplug_collection (FuRedfishClient *self, + JsonObject *collection, + GError **error) +{ + JsonArray *members; + JsonNode *node_root; + JsonObject *member; + + members = json_object_get_array_member (collection, "Members"); + for (guint i = 0; i < json_array_get_length (members); i++) { + g_autoptr(JsonParser) parser = json_parser_new (); + g_autoptr(GBytes) blob = NULL; + JsonObject *member_id; + const gchar *member_uri; + + member_id = json_array_get_object_element (members, i); + member_uri = json_object_get_string_member (member_id, "@odata.id"); + if (member_uri == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no @odata.id string"); + return FALSE; + } + + /* try to connect */ + blob = fu_redfish_client_fetch_data (self, member_uri, error); + if (blob == NULL) + return FALSE; + + /* get the member object */ + if (!json_parser_load_from_data (parser, + g_bytes_get_data (blob, NULL), + (gssize) g_bytes_get_size (blob), + error)) { + g_prefix_error (error, "failed to parse node: "); + return FALSE; + } + node_root = json_parser_get_root (parser); + if (node_root == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no root node"); + return FALSE; + } + member = json_node_get_object (node_root); + if (member == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no member object"); + return FALSE; + } + + /* Create the device for the member */ + if (!fu_redfish_client_coldplug_member (self, member, error)) + return FALSE; + } + return TRUE; +} + +static gboolean +fu_redfish_client_coldplug_inventory (FuRedfishClient *self, + JsonObject *inventory, + GError **error) +{ + g_autoptr(JsonParser) parser = json_parser_new (); + g_autoptr(GBytes) blob = NULL; + JsonNode *node_root; + JsonObject *collection; + const gchar *collection_uri; + + if (inventory == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no inventory object"); + return FALSE; + } + + collection_uri = json_object_get_string_member (inventory, "@odata.id"); + if (collection_uri == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no @odata.id string"); + return FALSE; + } + + /* try to connect */ + blob = fu_redfish_client_fetch_data (self, collection_uri, error); + if (blob == NULL) + return FALSE; + + /* get the inventory object */ + if (!json_parser_load_from_data (parser, + g_bytes_get_data (blob, NULL), + (gssize) g_bytes_get_size (blob), + error)) { + g_prefix_error (error, "failed to parse node: "); + return FALSE; + } + node_root = json_parser_get_root (parser); + if (node_root == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no root node"); + return FALSE; + } + collection = json_node_get_object (node_root); + if (collection == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no collection object"); + return FALSE; + } + + return fu_redfish_client_coldplug_collection (self, collection, error); +} + +gboolean +fu_redfish_client_coldplug (FuRedfishClient *self, GError **error) +{ + JsonNode *node_root; + JsonObject *obj_root = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(JsonParser) parser = json_parser_new (); + + /* nothing set */ + if (self->update_uri_path == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no update_uri_path"); + return FALSE; + } + + /* try to connect */ + blob = fu_redfish_client_fetch_data (self, self->update_uri_path, error); + if (blob == NULL) + return FALSE; + + /* get the update service */ + if (!json_parser_load_from_data (parser, + g_bytes_get_data (blob, NULL), + (gssize) g_bytes_get_size (blob), + error)) { + g_prefix_error (error, "failed to parse node: "); + return FALSE; + } + node_root = json_parser_get_root (parser); + if (node_root == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no root node"); + return FALSE; + } + obj_root = json_node_get_object (node_root); + if (obj_root == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no root object"); + return FALSE; + } + if (!json_object_get_boolean_member (obj_root, "ServiceEnabled")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "service is not enabled"); + return FALSE; + } + if (!json_object_has_member (obj_root, "HttpPushUri")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "HttpPushUri is not available"); + return FALSE; + } + self->push_uri_path = g_strdup (json_object_get_string_member (obj_root, "HttpPushUri")); + if (self->push_uri_path == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "HttpPushUri is invalid"); + return FALSE; + } + if (json_object_has_member (obj_root, "FirmwareInventory")) { + JsonObject *tmp = json_object_get_object_member (obj_root, "FirmwareInventory"); + return fu_redfish_client_coldplug_inventory (self, tmp, error); + } + if (json_object_has_member (obj_root, "SoftwareInventory")) { + JsonObject *tmp = json_object_get_object_member (obj_root, "SoftwareInventory"); + return fu_redfish_client_coldplug_inventory (self, tmp, error); + } + return TRUE; +} + +static gboolean +fu_redfish_client_set_uefi_credentials (FuRedfishClient *self, GError **error) +{ + guint32 indications_le; + g_autofree gchar *userpass_safe = NULL; + g_auto(GStrv) split = NULL; + g_autoptr(GBytes) indications = NULL; + g_autoptr(GBytes) userpass = NULL; + + /* get the uint32 specifying if there are EFI variables set */ + indications = fu_redfish_common_get_evivar_raw (REDFISH_EFI_INFORMATION_GUID, + REDFISH_EFI_INFORMATION_INDICATIONS, + error); + if (indications == NULL) + return FALSE; + if (g_bytes_get_size (indications) != 4) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid value for %s, got %" G_GSIZE_FORMAT " bytes", + REDFISH_EFI_INFORMATION_INDICATIONS, + g_bytes_get_size (indications)); + return FALSE; + } + memcpy (&indications_le, g_bytes_get_data (indications, NULL), 4); + if ((indications_le & REDFISH_EFI_INDICATIONS_OS_CREDENTIALS) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no indications for OS credentials"); + return FALSE; + } + + /* read the correct EFI var for runtime */ + userpass = fu_redfish_common_get_evivar_raw (REDFISH_EFI_INFORMATION_GUID, + REDFISH_EFI_INFORMATION_OS_CREDENTIALS, + error); + if (userpass == NULL) + return FALSE; + + /* it might not be NUL terminated */ + userpass_safe = g_strndup (g_bytes_get_data (userpass, NULL), + g_bytes_get_size (userpass)); + split = g_strsplit (userpass_safe, ":", -1); + if (g_strv_length (split) != 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "invalid format for username:password, got '%s'", + userpass_safe); + return FALSE; + } + fu_redfish_client_set_username (self, split[0]); + fu_redfish_client_set_password (self, split[1]); + return TRUE; +} + +static void +fu_redfish_client_parse_interface_data (const guint8 *buf, guint8 sz) +{ + switch (buf[0]) { + case REDFISH_INTERFACE_TYPE_USB_NEWORK: + g_debug ("USB Network Interface"); + /* + * uint16 idVendor(2-bytes) + * uint16 idProduct(2-bytes) + * uint8 SerialNumberLen: + * uint8 DescriptorType: + * uint8* SerialNumber: + */ + break; + case REDFISH_INTERFACE_TYPE_PCI_NEWORK: + g_debug ("PCI Network Interface"); + /* + * uint16 VendorID + * uint16 DeviceID + * uint16 Subsystem_Vendor_ID + * uint16 Subsystem_ID + */ + break; + default: + break; + } +} + +typedef struct __attribute__((packed)) { + guint8 service_uuid[16]; + guint8 host_ip_assignment_type; + guint8 host_ip_address_format; + guint8 host_ip_address[16]; + guint8 host_ip_mask[16]; + guint8 service_ip_assignment_type; + guint8 service_ip_address_format; + guint8 service_ip_address[16]; + guint8 service_ip_mask[16]; + guint16 service_ip_port; + guint32 service_ip_vlan_id; + guint8 service_hostname_len; + /* service_hostname; */ +} RedfishProtocolDataOverIp; + +static gboolean +fu_redfish_client_parse_protocol_data (FuRedfishClient *self, + const guint8 *buf, + guint8 sz, + GError **error) +{ + RedfishProtocolDataOverIp *pr; + if (sz < sizeof(RedfishProtocolDataOverIp)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "protocol data too small"); + return FALSE; + } + pr = (RedfishProtocolDataOverIp *) buf; + + /* parse the hostname and port */ + if (pr->service_ip_assignment_type == REDFISH_IP_ASSIGNMENT_TYPE_STATIC || + pr->service_ip_assignment_type == REDFISH_IP_ASSIGNMENT_TYPE_AUTO_CONFIG) { + if (pr->service_ip_address_format == REDFISH_IP_ADDRESS_FORMAT_V4) { + g_autofree gchar *tmp = NULL; + tmp = fu_redfish_common_buffer_to_ipv4 (pr->service_ip_address); + fu_redfish_client_set_hostname (self, tmp); + } else if (pr->service_ip_address_format == REDFISH_IP_ADDRESS_FORMAT_V6) { + g_autofree gchar *tmp = NULL; + tmp = fu_redfish_common_buffer_to_ipv6 (pr->service_ip_address); + fu_redfish_client_set_hostname (self, tmp); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "address format is invalid"); + return FALSE; + } + fu_redfish_client_set_port (self, pr->service_ip_port); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "DHCP address formats not supported (%0x2)", + pr->service_ip_assignment_type); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_redfish_client_set_smbios_interfaces (FuRedfishClient *self, + GBytes *smbios_table, + GError **error) +{ + const guint8 *buf; + gsize sz = 0; + + /* check size */ + buf = g_bytes_get_data (smbios_table, &sz); + if (sz < 0x09) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "SMBIOS entry too small: %" G_GSIZE_FORMAT, + sz); + return FALSE; + } + + /* check interface type */ + if (buf[0x04] != REDFISH_CONTROLLER_INTERFACE_TYPE_NETWORK_HOST) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "only Network Host Interface supported"); + return FALSE; + } + + /* check length */ + if (buf[0x05] > sz - 0x08) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "interface specific data too large %u > %" G_GSIZE_FORMAT, + buf[0x05], sz - 0x08); + return FALSE; + } + + /* parse data, for not just for debugging */ + if (buf[0x05] > 0) + fu_redfish_client_parse_interface_data (&buf[0x06], buf[0x05]); + + /* parse protocol records */ + for (guint8 i = 0x07 + buf[0x05]; i < sz - 1; i++) { + guint8 protocol_id = buf[i]; + guint8 protocol_sz = buf[i+1]; + if (protocol_sz > sz - buf[0x05] + 0x07) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "protocol length too large"); + return FALSE; + } + if (protocol_id == REDFISH_PROTOCOL_REDFISH_OVER_IP) { + if (!fu_redfish_client_parse_protocol_data (self, + &buf[i+2], + protocol_sz, + error)) + return FALSE; + } else { + g_debug ("ignoring unsupported protocol ID %02x", + protocol_id); + } + i += protocol_sz - 1; + } + + return TRUE; +} + +gboolean +fu_redfish_client_update (FuRedfishClient *self, FuDevice *device, GBytes *blob_fw, + GError **error) +{ + FwupdRelease *release; + g_autofree gchar *filename = NULL; + + guint status_code; + g_autoptr(SoupMessage) msg = NULL; + g_autoptr(SoupURI) uri = NULL; + g_autoptr(SoupMultipart) multipart = NULL; + g_autoptr(SoupBuffer) buffer = NULL; + g_autofree gchar *uri_str = NULL; + + /* Get the update version */ + release = fwupd_device_get_release_default (FWUPD_DEVICE (device)); + if (release != NULL) { + filename = g_strdup_printf ("%s-%s.bin", + fu_device_get_name (device), + fwupd_release_get_version (release)); + } else { + filename = g_strdup_printf ("%s.bin", + fu_device_get_name (device)); + } + + /* create URI */ + uri = soup_uri_new (NULL); + soup_uri_set_scheme (uri, self->use_https ? "https" : "http"); + soup_uri_set_path (uri, self->push_uri_path); + soup_uri_set_host (uri, self->hostname); + soup_uri_set_port (uri, self->port); + uri_str = soup_uri_to_string (uri, FALSE); + + /* Create the multipart request */ + multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); + buffer = soup_buffer_new (SOUP_MEMORY_COPY, + g_bytes_get_data (blob_fw, NULL), + g_bytes_get_size (blob_fw)); + soup_multipart_append_form_file (multipart, filename, filename, + "application/octet-stream", + buffer); + msg = soup_form_request_new_from_multipart (uri_str, multipart); + if (msg == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to create message for URI %s", uri_str); + return FALSE; + } + fu_redfish_client_set_auth (self, uri, msg); + status_code = soup_session_send_message (self->session, msg); + if (status_code != SOUP_STATUS_OK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to upload %s to %s: %s", + filename, uri_str, + soup_status_get_phrase (status_code)); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_redfish_client_setup (FuRedfishClient *self, GBytes *smbios_table, GError **error) +{ + JsonNode *node_root; + JsonObject *obj_root = NULL; + JsonObject *obj_update_service = NULL; + const gchar *data_id; + const gchar *version = NULL; + g_autofree gchar *user_agent = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(JsonParser) parser = json_parser_new (); + + /* sanity check */ + if (self->port == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no port specified"); + return FALSE; + } + if (self->port > 0xffff) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid port specified: 0x%x", + self->port); + return FALSE; + } + + /* create the soup session */ + user_agent = g_strdup_printf ("%s/%s", PACKAGE_NAME, PACKAGE_VERSION); + self->session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, + SOUP_SESSION_TIMEOUT, 60, + NULL); + if (self->session == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to setup networking"); + return FALSE; + } + + if (self->cacheck == FALSE) { + g_object_set (G_OBJECT (self->session), + SOUP_SESSION_SSL_STRICT, FALSE, + NULL); + } + + /* this is optional */ + if (smbios_table != NULL) { + g_autoptr(GError) error_smbios = NULL; + g_autoptr(GError) error_uefi = NULL; + if (!fu_redfish_client_set_smbios_interfaces (self, + smbios_table, + &error_smbios)) { + g_debug ("failed to get connection URI automatically: %s", + error_smbios->message); + } + if (!fu_redfish_client_set_uefi_credentials (self, &error_uefi)) { + g_debug ("failed to get username and password automatically: %s", + error_uefi->message); + } + } + if (self->hostname != NULL) + g_debug ("Hostname: %s", self->hostname); + if (self->port != 0) + g_debug ("Port: %u", self->port); + if (self->username != NULL) + g_debug ("Username: %s", self->username); + if (self->password != NULL) + g_debug ("Password: %s", self->password); + + /* try to connect */ + blob = fu_redfish_client_fetch_data (self, "/redfish/v1/", error); + if (blob == NULL) + return FALSE; + + /* get the update service */ + if (!json_parser_load_from_data (parser, + g_bytes_get_data (blob, NULL), + (gssize) g_bytes_get_size (blob), + error)) { + g_prefix_error (error, "failed to parse node: "); + return FALSE; + } + node_root = json_parser_get_root (parser); + if (node_root == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no root node"); + return FALSE; + } + obj_root = json_node_get_object (node_root); + if (obj_root == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no root object"); + return FALSE; + } + if (json_object_has_member (obj_root, "ServiceVersion")) { + version = json_object_get_string_member (obj_root, + "ServiceVersion"); + } else if (json_object_has_member (obj_root, "RedfishVersion")) { + version = json_object_get_string_member (obj_root, + "RedfishVersion"); + } + g_debug ("Version: %s", version); + g_debug ("UUID: %s", + json_object_get_string_member (obj_root, "UUID")); + + if (json_object_has_member (obj_root, "UpdateService")) + obj_update_service = json_object_get_object_member (obj_root, "UpdateService"); + if (obj_update_service == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no UpdateService object"); + return FALSE; + } + data_id = json_object_get_string_member (obj_update_service, "@odata.id"); + if (data_id == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no @odata.id string"); + return FALSE; + } + self->update_uri_path = g_strdup (data_id); + return TRUE; +} + +GPtrArray * +fu_redfish_client_get_devices (FuRedfishClient *self) +{ + return self->devices; +} + +void +fu_redfish_client_set_hostname (FuRedfishClient *self, const gchar *hostname) +{ + g_free (self->hostname); + self->hostname = g_strdup (hostname); +} + +void +fu_redfish_client_set_port (FuRedfishClient *self, guint port) +{ + self->port = port; +} + +void +fu_redfish_client_set_https (FuRedfishClient *self, gboolean use_https) +{ + self->use_https = use_https; +} + +void +fu_redfish_client_set_cacheck (FuRedfishClient *self, gboolean cacheck) +{ + self->cacheck = cacheck; +} + +void +fu_redfish_client_set_username (FuRedfishClient *self, const gchar *username) +{ + g_free (self->username); + self->username = g_strdup (username); +} + +void +fu_redfish_client_set_password (FuRedfishClient *self, const gchar *password) +{ + g_free (self->password); + self->password = g_strdup (password); +} + +static void +fu_redfish_client_finalize (GObject *object) +{ + FuRedfishClient *self = FU_REDFISH_CLIENT (object); + if (self->session != NULL) + g_object_unref (self->session); + g_free (self->update_uri_path); + g_free (self->push_uri_path); + g_free (self->hostname); + g_free (self->username); + g_free (self->password); + g_ptr_array_unref (self->devices); + G_OBJECT_CLASS (fu_redfish_client_parent_class)->finalize (object); +} + +static void +fu_redfish_client_class_init (FuRedfishClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_redfish_client_finalize; +} + +static void +fu_redfish_client_init (FuRedfishClient *self) +{ + self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +FuRedfishClient * +fu_redfish_client_new (void) +{ + FuRedfishClient *self; + self = g_object_new (REDFISH_TYPE_CLIENT, NULL); + return FU_REDFISH_CLIENT (self); +} + +/* vim: set noexpandtab: */ diff -Nru fwupd-1.0.6/plugins/redfish/fu-redfish-client.h fwupd-1.2.10/plugins/redfish/fu-redfish-client.h --- fwupd-1.0.6/plugins/redfish/fu-redfish-client.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/fu-redfish-client.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,41 @@ + /* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define REDFISH_TYPE_CLIENT (fu_redfish_client_get_type ()) + +G_DECLARE_FINAL_TYPE (FuRedfishClient, fu_redfish_client, FU, REDFISH_CLIENT, GObject) + +FuRedfishClient *fu_redfish_client_new (void); +void fu_redfish_client_set_hostname (FuRedfishClient *self, + const gchar *hostname); +void fu_redfish_client_set_username (FuRedfishClient *self, + const gchar *username); +void fu_redfish_client_set_password (FuRedfishClient *self, + const gchar *password); +void fu_redfish_client_set_port (FuRedfishClient *self, + guint port); +void fu_redfish_client_set_https (FuRedfishClient *self, + gboolean use_https); +void fu_redfish_client_set_cacheck (FuRedfishClient *self, + gboolean cacheck); +gboolean fu_redfish_client_update (FuRedfishClient *self, + FuDevice *device, + GBytes *blob_fw, + GError **error); +gboolean fu_redfish_client_setup (FuRedfishClient *self, + GBytes *smbios_table, + GError **error); +gboolean fu_redfish_client_coldplug (FuRedfishClient *self, + GError **error); +GPtrArray *fu_redfish_client_get_devices (FuRedfishClient *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/redfish/fu-redfish-common.c fwupd-1.2.10/plugins/redfish/fu-redfish-common.c --- fwupd-1.0.6/plugins/redfish/fu-redfish-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/fu-redfish-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fwupd-error.h" + +#include "fu-redfish-common.h" + +GBytes * +fu_redfish_common_get_evivar_raw (efi_guid_t guid, const gchar *name, GError **error) +{ + gsize sz = 0; + guint32 attribs = 0; + guint8 *data = NULL; + + if (efi_get_variable (guid, name, &data, &sz, &attribs) < 0) { + g_autofree gchar *guid_str = NULL; + efi_guid_to_str (&guid, &guid_str); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to get efivar for %s %s", + guid_str, name); + return NULL; + } + return g_bytes_new_take (data, sz); +} + +gchar * +fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; i < 4; i++) { + g_string_append_printf (str, "%u", buffer[i]); + if (i != 3) + g_string_append (str, "."); + } + return g_string_free (str, FALSE); +} + +gchar * +fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; i < 16; i += 4) { + g_string_append_printf (str, "%02x%02x%02x%02x", + buffer[i+0], buffer[i+1], + buffer[i+2], buffer[i+3]); + if (i != 12) + g_string_append (str, ":"); + } + return g_string_free (str, FALSE); +} + +/* vim: set noexpandtab: */ diff -Nru fwupd-1.0.6/plugins/redfish/fu-redfish-common.h fwupd-1.2.10/plugins/redfish/fu-redfish-common.h --- fwupd-1.0.6/plugins/redfish/fu-redfish-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/fu-redfish-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,50 @@ + /* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +/* SMBIOS */ +#define REDFISH_SMBIOS_TABLE_TYPE 0x42 + +#define REDFISH_PROTOCOL_REDFISH_OVER_IP 0x04 + +#define REDFISH_CONTROLLER_INTERFACE_TYPE_NETWORK_HOST 0x40 + +#define REDFISH_INTERFACE_TYPE_USB_NEWORK 0x02 +#define REDFISH_INTERFACE_TYPE_PCI_NEWORK 0x03 + +#define REDFISH_IP_ASSIGNMENT_TYPE_STATIC 0x00 +#define REDFISH_IP_ASSIGNMENT_TYPE_DHCP 0x02 +#define REDFISH_IP_ASSIGNMENT_TYPE_AUTO_CONFIG 0x03 +#define REDFISH_IP_ASSIGNMENT_TYPE_HOST_SELECT 0x04 + +#define REDFISH_IP_ADDRESS_FORMAT_UNKNOWN 0x00 +#define REDFISH_IP_ADDRESS_FORMAT_V4 0x01 +#define REDFISH_IP_ADDRESS_FORMAT_V6 0x02 + +/* EFI */ +#define REDFISH_EFI_INFORMATION_GUID EFI_GUID(0x16faa37e,0x4b6a,0x4891,0x9028,0x24,0x2d,0xe6,0x5a,0x3b,0x70) + +#define REDFISH_EFI_INFORMATION_INDICATIONS "RedfishIndications" +#define REDFISH_EFI_INFORMATION_FW_CREDENTIALS "RedfishFWCredentials" +#define REDFISH_EFI_INFORMATION_OS_CREDENTIALS "RedfishOSCredentials" + +#define REDFISH_EFI_INDICATIONS_FW_CREDENTIALS 0x00000001 +#define REDFISH_EFI_INDICATIONS_OS_CREDENTIALS 0x00000002 + +/* shared */ +GBytes *fu_redfish_common_get_evivar_raw (efi_guid_t guid, + const gchar *name, + GError **error); +gchar *fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer); +gchar *fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/redfish/fu-self-test.c fwupd-1.2.10/plugins/redfish/fu-self-test.c --- fwupd-1.0.6/plugins/redfish/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-plugin-private.h" +#include "fu-test.h" + +#include "fu-redfish-common.h" + +static void +fu_test_redfish_common_func (void) +{ + const guint8 buf[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + g_autofree gchar *ipv4 = NULL; + g_autofree gchar *ipv6 = NULL; + + ipv4 = fu_redfish_common_buffer_to_ipv4 (buf); + g_assert_cmpstr (ipv4, ==, "0.1.2.3"); + ipv6 = fu_redfish_common_buffer_to_ipv6 (buf); + g_assert_cmpstr (ipv6, ==, "00010203:04050607:08090a0b:0c0d0e0f"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_test_add_func ("/redfish/common", fu_test_redfish_common_func); + return g_test_run (); +} diff -Nru fwupd-1.0.6/plugins/redfish/meson.build fwupd-1.2.10/plugins/redfish/meson.build --- fwupd-1.0.6/plugins/redfish/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,57 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginRedfish"'] + +shared_module('fu_plugin_redfish', + fu_hash, + sources : [ + 'fu-plugin-redfish.c', + 'fu-redfish-client.c', + 'fu-redfish-common.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + efivar, + libjsonglib, + ], +) + +install_data(['redfish.conf'], + install_dir: join_paths(sysconfdir, 'fwupd') +) + +if get_option('tests') + e = executable( + 'redfish-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-redfish-client.c', + 'fu-redfish-common.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + dependencies : [ + plugin_deps, + efivar, + libjsonglib, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('redfish-self-test', e) +endif diff -Nru fwupd-1.0.6/plugins/redfish/README.md fwupd-1.2.10/plugins/redfish/README.md --- fwupd-1.0.6/plugins/redfish/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,70 @@ +Redfish Support +=============== + +Introduction +------------ + +Redfish is an open industry standard specification and schema that helps enable +simple and secure management of modern scalable platform hardware. + +By specifying a RESTful interface and utilizing JSON and OData, Redfish helps +customers integrate solutions within their existing tool chains. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * org.dmtf.redfish + +GUID Generation +--------------- + +These devices use the provided GUID provided in the `SoftwareId` parameter +without modification. Devices without GUIDs are not supported. + +Setting Service IP Manually +--------------------------- + +The service IP may not be automatically discoverable due to the absence of +Type 0x42 entry in SMBIOS. In this case, you have to specify the service IP +to RedfishUri in /etc/fwupd/redfish.conf + +Take HPE Gen10 for example, the service IP can be found with the following +command: + + # ilorest --nologo list --selector=EthernetInterface. -j + +This command lists all network interfaces, and the Redfish service IP belongs +to one of "Manager Network" Interfaces. For example: + + { + "@odata.context": "/redfish/v1/$metadata#EthernetInterface.EthernetInterface", + "@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces/1/", + "@odata.type": "#EthernetInterface.v1_0_3.EthernetInterface", + "Description": "Configuration of this Manager Network Interface", + "HostName": "myredfish", + "IPv4Addresses": [ + { + "SubnetMask": "255.255.255.0", + "AddressOrigin": "DHCP", + "Gateway": "192.168.0.1", + "Address": "192.168.0.133" + } + ], + ... + +In this example, the service IP is "192.168.0.133". + +Since the conventional HTTP port is 80 and HTTPS port is 443, we can set +RedfishUri to either "http://192.168.0.133:80" or "https://192.168.0.133:443" +and verify the uri with + + $ curl http://192.168.0.133:80/redfish/v1/ + +or + + $ curl -k https://192.168.0.133:443/redfish/v1/ diff -Nru fwupd-1.0.6/plugins/redfish/redfish.conf fwupd-1.2.10/plugins/redfish/redfish.conf --- fwupd-1.0.6/plugins/redfish/redfish.conf 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/redfish/redfish.conf 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,14 @@ +[redfish] + +# The URI to the Redfish service in the format ://: +# ex: https://192.168.0.133:443 +#Uri= + +# The username and password to the Redfish service +#Username= +#Password= + +# Whether to verify the server certificate or not +# Expected value: TRUE or FALSE +# Default: TRUE +#CACheck= diff -Nru fwupd-1.0.6/plugins/rts54hid/fu-plugin-rts54hid.c fwupd-1.2.10/plugins/rts54hid/fu-plugin-rts54hid.c --- fwupd-1.0.6/plugins/rts54hid/fu-plugin-rts54hid.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/fu-plugin-rts54hid.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-rts54hid-device.h" +#include "fu-rts54hid-module.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); + + /* register the custom types */ + g_type_ensure (FU_TYPE_RTS54HID_MODULE); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuRts54HidDevice) dev = NULL; + + /* open the device */ + dev = fu_rts54hid_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + + /* success */ + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-common.h fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-common.h --- fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Copyright (C) 2018 Dell Inc. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define FU_RTS54HID_TRANSFER_BLOCK_SIZE 0x80 +#define FU_RTS54HID_REPORT_LENGTH 0xc0 + +/* [vendor-cmd:64] [data-payload:128] */ +#define FU_RTS54HID_CMD_BUFFER_OFFSET_DATA 0x40 + +typedef struct __attribute__ ((packed)) { + guint8 slave_addr; + guint8 data_sz; + guint8 speed; +} FuRts54HidI2cParameters; + +typedef struct __attribute__ ((packed)) { + guint8 cmd; + guint8 ext; + union { + guint32 dwregaddr; + struct { + guint8 cmd_data0; + guint8 cmd_data1; + guint8 cmd_data2; + guint8 cmd_data3; + }; + }; + guint16 bufferlen; + union { + FuRts54HidI2cParameters parameters_i2c; + guint32 parameters; + }; +} FuRts54HidCmdBuffer; + +typedef enum { + FU_RTS54HID_I2C_SPEED_250K, + FU_RTS54HID_I2C_SPEED_400K, + FU_RTS54HID_I2C_SPEED_800K, + /* */ + FU_RTS54HID_I2C_SPEED_LAST, +} FuRts54HidI2cSpeed; + +typedef enum { + FU_RTS54HID_CMD_READ_DATA = 0xc0, + FU_RTS54HID_CMD_WRITE_DATA = 0x40, + /* */ + FU_RTS54HID_CMD_LAST, +} FuRts54HidCmd; + +typedef enum { + FU_RTS54HID_EXT_MCUMODIFYCLOCK = 0x06, + FU_RTS54HID_EXT_READ_STATUS = 0x09, + FU_RTS54HID_EXT_I2C_WRITE = 0xc6, + FU_RTS54HID_EXT_WRITEFLASH = 0xc8, + FU_RTS54HID_EXT_I2C_READ = 0xd6, + FU_RTS54HID_EXT_READFLASH = 0xd8, + FU_RTS54HID_EXT_VERIFYUPDATE = 0xd9, + FU_RTS54HID_EXT_ERASEBANK = 0xe8, + FU_RTS54HID_EXT_RESET2FLASH = 0xe9, + /* */ + FU_RTS54HID_EXT_LAST, +} FuRts54HidExt; diff -Nru fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-device.c fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-device.c --- fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-rts54hid-common.h" +#include "fu-rts54hid-device.h" + +struct _FuRts54HidDevice { + FuUsbDevice parent_instance; + gboolean fw_auth; + gboolean dual_bank; +}; + +G_DEFINE_TYPE (FuRts54HidDevice, fu_rts54hid_device, FU_TYPE_USB_DEVICE) + +#define FU_RTS54HID_DEVICE_TIMEOUT 1000 /* ms */ + +static void +fu_rts54hid_device_to_string (FuDevice *device, GString *str) +{ + FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device); + g_string_append (str, " FuRts54HidDevice:\n"); + g_string_append_printf (str, " fw-auth: %i\n", self->fw_auth); + g_string_append_printf (str, " dual-bank: %i\n", self->dual_bank); +} + +gboolean +fu_rts54hid_device_set_report (FuRts54HidDevice *self, + guint8 *buf, gsize buf_sz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_len = 0; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_SET, + 0x0200, 0x0000, + buf, buf_sz, + &actual_len, + FU_RTS54HID_DEVICE_TIMEOUT * 2, + NULL, error)) { + g_prefix_error (error, "failed to SetReport: "); + return FALSE; + } + if (actual_len != buf_sz) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} + +gboolean +fu_rts54hid_device_get_report (FuRts54HidDevice *self, + guint8 *buf, gsize buf_sz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_len = 0; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_GET, + 0x0100, 0x0000, + buf, buf_sz, + &actual_len, /* actual length */ + FU_RTS54HID_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to GetReport: "); + return FALSE; + } + if (actual_len != buf_sz) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hid_device_set_clock_mode (FuRts54HidDevice *self, gboolean enable, GError **error) +{ + FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_MCUMODIFYCLOCK, + .cmd_data0 = (guint8) enable, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = 0, + .parameters = 0, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to set clock-mode=%i: ", enable); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hid_device_reset_to_flash (FuRts54HidDevice *self, GError **error) +{ + FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_RESET2FLASH, + .dwregaddr = 0, + .bufferlen = 0, + .parameters = 0, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to soft reset: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hid_device_write_flash (FuRts54HidDevice *self, + guint32 addr, + const guint8 *data, + guint16 data_sz, + GError **error) +{ + FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_WRITEFLASH, + .dwregaddr = GUINT32_TO_LE (addr), + .bufferlen = GUINT16_TO_LE (data_sz), + .parameters = 0, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + + g_return_val_if_fail (data_sz <= 128, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data_sz != 0, FALSE); + + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + memcpy (buf + FU_RTS54HID_CMD_BUFFER_OFFSET_DATA, data, data_sz); + if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to write flash @%08x: ", (guint) addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hid_device_verify_update_fw (FuRts54HidDevice *self, GError **error) +{ + const FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_VERIFYUPDATE, + .cmd_data0 = 1, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (1), + .parameters = 0, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + + /* set then get */ + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) + return FALSE; + g_usleep (4 * G_USEC_PER_SEC); + if (!fu_rts54hid_device_get_report (self, buf, sizeof(buf), error)) + return FALSE; + + /* check device status */ + if (buf[0x40] != 0x01) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "firmware flash failed"); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hid_device_erase_spare_bank (FuRts54HidDevice *self, GError **error) +{ + FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_ERASEBANK, + .cmd_data0 = 0, + .cmd_data1 = 1, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = 0, + .parameters = 0, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to erase spare bank: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hid_device_ensure_status (FuRts54HidDevice *self, GError **error) +{ + const FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_READ_DATA, + .ext = FU_RTS54HID_EXT_READ_STATUS, + .cmd_data0 = 0, + .cmd_data1 = 0, + .cmd_data2 = 0, + .cmd_data3 = 0, + .bufferlen = GUINT16_TO_LE (32), + .parameters = 0, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + g_autofree gchar *version = NULL; + + /* set then get */ + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + if (!fu_rts54hid_device_set_report (self, buf, sizeof(buf), error)) + return FALSE; + if (!fu_rts54hid_device_get_report (self, buf, sizeof(buf), error)) + return FALSE; + + /* check the hardware capabilities */ + self->dual_bank = (buf[0x40 + 7] & 0xf0) == 0x80; + self->fw_auth = (buf[0x40 + 13] & 0x02) > 0; + + /* hub version is more accurate than bcdVersion */ + version = g_strdup_printf ("%x.%x", buf[0x40 + 10], buf[0x40 + 11]); + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_PAIR); + return TRUE; +} + +static gboolean +fu_rts54hid_device_open (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* disconnect, set config, reattach kernel driver */ + if (!g_usb_device_set_configuration (usb_device, 0x00, error)) + return FALSE; + if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hid_device_setup (FuDevice *device, GError **error) +{ + FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device); + + /* check this device is correct */ + if (!fu_rts54hid_device_ensure_status (self, error)) + return FALSE; + + /* both conditions must be set */ + if (!self->fw_auth) { + fu_device_set_update_error (device, + "device does not support authentication"); + } else if (!self->dual_bank) { + fu_device_set_update_error (device, + "device does not support dual-bank updating"); + } else { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hid_device_close (FuUsbDevice *device, GError **error) +{ + FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device); + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* set MCU to normal clock rate */ + if (!fu_rts54hid_device_set_clock_mode (self, FALSE, error)) + return FALSE; + + /* we're done here */ + if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to release interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hid_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuRts54HidDevice *self = FU_RTS54HID_DEVICE (device); + g_autoptr(GPtrArray) chunks = NULL; + + /* set MCU to high clock rate for better ISP performance */ + if (!fu_rts54hid_device_set_clock_mode (self, TRUE, error)) + return FALSE; + + /* erase spare flash bank only if it is not empty */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_rts54hid_device_erase_spare_bank (self, error)) + return FALSE; + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + FU_RTS54HID_TRANSFER_BLOCK_SIZE); + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + + /* write chunk */ + if (!fu_rts54hid_device_write_flash (self, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len * 2); + } + + /* get device to authenticate the firmware */ + if (!fu_rts54hid_device_verify_update_fw (self, error)) + return FALSE; + + /* send software reset to run available flash code */ + if (!fu_rts54hid_device_reset_to_flash (self, error)) + return FALSE; + + /* success! */ + return TRUE; +} + +static void +fu_rts54hid_device_init (FuRts54HidDevice *self) +{ +} + +static void +fu_rts54hid_device_class_init (FuRts54HidDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_rts54hid_device_write_firmware; + klass_device->to_string = fu_rts54hid_device_to_string; + klass_device->setup = fu_rts54hid_device_setup; + klass_usb_device->open = fu_rts54hid_device_open; + klass_usb_device->close = fu_rts54hid_device_close; +} + +FuRts54HidDevice * +fu_rts54hid_device_new (FuUsbDevice *device) +{ + FuRts54HidDevice *self = g_object_new (FU_TYPE_RTS54HID_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-device.h fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-device.h --- fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_RTS54HID_DEVICE (fu_rts54hid_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuRts54HidDevice, fu_rts54hid_device, FU, RTS54HID_DEVICE, FuUsbDevice) + +FuRts54HidDevice *fu_rts54hid_device_new (FuUsbDevice *device); +gboolean fu_rts54hid_device_set_report (FuRts54HidDevice *self, + guint8 *buf, + gsize buf_sz, + GError **error); +gboolean fu_rts54hid_device_get_report (FuRts54HidDevice *self, + guint8 *buf, + gsize buf_sz, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-module.c fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-module.c --- fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-module.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-module.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-rts54hid-common.h" +#include "fu-rts54hid-module.h" +#include "fu-rts54hid-device.h" + +struct _FuRts54HidModule { + FuDevice parent_instance; + guint8 slave_addr; + guint8 i2c_speed; + guint8 register_addr_len; +}; + +G_DEFINE_TYPE (FuRts54HidModule, fu_rts54hid_module, FU_TYPE_DEVICE) + +static void +fu_rts54hid_module_to_string (FuDevice *module, GString *str) +{ + FuRts54HidModule *self = FU_RTS54HID_MODULE (module); + g_string_append (str, " FuRts54HidModule:\n"); + g_string_append_printf (str, " slave-addr: 0x%02x\n", self->slave_addr); + g_string_append_printf (str, " i2c-speed: 0x%02x\n", self->i2c_speed); + g_string_append_printf (str, " register_addr_len: 0x%02x\n", self->register_addr_len); +} + +static FuRts54HidDevice * +fu_rts54hid_module_get_parent (FuRts54HidModule *self, GError **error) +{ + FuDevice *parent = fu_device_get_parent (FU_DEVICE (self)); + if (parent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no parent set"); + return NULL; + } + return FU_RTS54HID_DEVICE (parent); +} + +static gboolean +fu_rts54hid_module_i2c_write (FuRts54HidModule *self, + const guint8 *data, + guint8 data_sz, + GError **error) +{ + FuRts54HidDevice *parent; + const FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_I2C_WRITE, + .dwregaddr = 0, + .bufferlen = GUINT16_TO_LE (data_sz), + .parameters_i2c = {.slave_addr = self->slave_addr, + .data_sz = self->register_addr_len, + .speed = self->i2c_speed | 0x80}, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + + g_return_val_if_fail (data_sz <= 128, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data_sz != 0, FALSE); + + /* get parent to issue command */ + parent = fu_rts54hid_module_get_parent (self, error); + if (parent == NULL) + return FALSE; + + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + memcpy (buf + FU_RTS54HID_CMD_BUFFER_OFFSET_DATA, data, data_sz); + if (!fu_rts54hid_device_set_report (parent, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hid_module_i2c_read (FuRts54HidModule *self, + guint32 cmd, + guint8 *data, + guint8 data_sz, + GError **error) +{ + FuRts54HidDevice *parent; + const FuRts54HidCmdBuffer cmd_buffer = { + .cmd = FU_RTS54HID_CMD_WRITE_DATA, + .ext = FU_RTS54HID_EXT_I2C_READ, + .dwregaddr = GUINT32_TO_LE (cmd), + .bufferlen = GUINT16_TO_LE (data_sz), + .parameters_i2c = {.slave_addr = self->slave_addr, + .data_sz = self->register_addr_len, + .speed = self->i2c_speed | 0x80}, + }; + guint8 buf[FU_RTS54HID_REPORT_LENGTH] = { 0 }; + + g_return_val_if_fail (data_sz <= 192, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data_sz != 0, FALSE); + + /* get parent to issue command */ + parent = fu_rts54hid_module_get_parent (self, error); + if (parent == NULL) + return FALSE; + + /* read from module */ + memcpy (buf, &cmd_buffer, sizeof(cmd_buffer)); + if (!fu_rts54hid_device_set_report (parent, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to write i2c @%04x: ", self->slave_addr); + return FALSE; + } + if (!fu_rts54hid_device_get_report (parent, buf, sizeof(buf), error)) + return FALSE; + memcpy (data, buf + FU_RTS54HID_CMD_BUFFER_OFFSET_DATA, data_sz); + + return TRUE; +} + +static gboolean +fu_rts54hid_module_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuRts54HidModule *self = FU_RTS54HID_MODULE (device); + + /* load slave address from quirks */ + if (g_strcmp0 (key, "Rts54SlaveAddr") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp <= 0xff) { + self->slave_addr = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid slave address"); + return FALSE; + } + + /* load i2c speed from quirks */ + if (g_strcmp0 (key, "Rts54I2cSpeed") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp < FU_RTS54HID_I2C_SPEED_LAST) { + self->i2c_speed = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid I²C speed"); + return FALSE; + } + + /* load register address length from quirks */ + if (g_strcmp0 (key, "Rts54RegisterAddrLen") == 0) { + guint64 tmp = fu_common_strtoull (value); + if (tmp <= 0xff) { + self->register_addr_len = tmp; + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid register address length"); + return FALSE; + } + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; + +} + +static gboolean +fu_rts54hid_module_open (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no parent device"); + return FALSE; + } + return fu_device_open (parent, error); +} + +static gboolean +fu_rts54hid_module_close (FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + if (parent == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no parent device"); + return FALSE; + } + return fu_device_close (parent, error); +} + +static gboolean +fu_rts54hid_module_write_firmware (FuDevice *module, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuRts54HidModule *self = FU_RTS54HID_MODULE (module); + g_autoptr(GPtrArray) chunks = NULL; + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + FU_RTS54HID_TRANSFER_BLOCK_SIZE); + + if (0) { + if (!fu_rts54hid_module_i2c_read (self, 0x0000, NULL, 0, error)) + return FALSE; + if (!fu_rts54hid_module_i2c_write (self, NULL, 0, error)) + return FALSE; + } + + /* write each block */ + fu_device_set_status (module, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + + /* write chunk */ + if (!fu_rts54hid_module_i2c_write (self, + chk->data, + chk->data_sz, + error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (module, (gsize) i, (gsize) chunks->len * 2); + } + + /* success! */ + return TRUE; +} + +static void +fu_rts54hid_module_init (FuRts54HidModule *self) +{ +} + +static void +fu_rts54hid_module_class_init (FuRts54HidModuleClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_rts54hid_module_write_firmware; + klass_device->to_string = fu_rts54hid_module_to_string; + klass_device->set_quirk_kv = fu_rts54hid_module_set_quirk_kv; + klass_device->open = fu_rts54hid_module_open; + klass_device->close = fu_rts54hid_module_close; +} + +FuRts54HidModule * +fu_rts54hid_module_new (void) +{ + FuRts54HidModule *self = NULL; + self = g_object_new (FU_TYPE_RTS54HID_MODULE, NULL); + return self; +} diff -Nru fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-module.h fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-module.h --- fwupd-1.0.6/plugins/rts54hid/fu-rts54hid-module.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/fu-rts54hid-module.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_RTS54HID_MODULE (fu_rts54hid_module_get_type ()) +G_DECLARE_FINAL_TYPE (FuRts54HidModule, fu_rts54hid_module, FU, RTS54HID_MODULE, FuDevice) + +FuRts54HidModule *fu_rts54hid_module_new (void); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/rts54hid/meson.build fwupd-1.2.10/plugins/rts54hid/meson.build --- fwupd-1.0.6/plugins/rts54hid/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,30 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginRts54Hid"'] + +install_data([ + 'rts54hid.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_rts54hid', + fu_hash, + sources : [ + 'fu-rts54hid-device.c', + 'fu-rts54hid-module.c', + 'fu-plugin-rts54hid.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff -Nru fwupd-1.0.6/plugins/rts54hid/README.md fwupd-1.2.10/plugins/rts54hid/README.md --- fwupd-1.0.6/plugins/rts54hid/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,44 @@ +Realtek RTS54HID HID Support +========================= + +Introduction +------------ + +This plugin allows the user to update any supported hub and attached downstream +ICs using a custom HID-based flashing protocol. It does not support any RTS54xx +device using the HUB update protocol. + +Other devices connected to the RTS54HIDxx using I2C will be supported soon. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.realtek.rts54 + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0BDA&PID_1100&REV_0001` + * `USB\VID_0BDA&PID_1100` + * `USB\VID_0BDA` + +Child I²C devices are created using the device number as a suffix, for instance: + + * `USB\VID_0BDA&PID_1100&I2C_01` + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|------------------------|---------------------------------------------|-----------------------| +| `Rts54SlaveAddr` | The slave address of a child module. | 1.1.3 | +| `Rts54I2cSpeed` | The I2C speed to operate at (0, 1, 2). | 1.1.3 | +| `Rts54RegisterAddrLen` | The I2C register address length of commands | 1.1.3 | diff -Nru fwupd-1.0.6/plugins/rts54hid/rts54hid.quirk fwupd-1.2.10/plugins/rts54hid/rts54hid.quirk --- fwupd-1.0.6/plugins/rts54hid/rts54hid.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hid/rts54hid.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +# RTS5423 +[DeviceInstanceId=USB\VID_0BDA&PID_1100] +Plugin = rts54hid +FirmwareSizeMin = 0x10000 +FirmwareSizeMax = 0x40000 +Children = FuRts54HidModule|USB\VID_0BDA&PID_1100&I2C_01 + +# this is a fictitious example... +[DeviceInstanceId=USB\VID_0BDA&PID_1100&I2C_01] +Plugin = rts54hid +Name = HDMI Converter +Flags = updatable +FirmwareSize = 0x20000 +Rts54SlaveAddr = 0x00 +Rts54I2cSpeed = 0x00 +Rts54RegisterAddrLen = 0x04 diff -Nru fwupd-1.0.6/plugins/rts54hub/data/lsusb.txt fwupd-1.2.10/plugins/rts54hub/data/lsusb.txt --- fwupd-1.0.6/plugins/rts54hub/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/data/lsusb.txt 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,137 @@ +Bus 001 Device 038: ID 0bda:5423 Realtek Semiconductor Corp. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.10 + bDeviceClass 9 Hub + bDeviceSubClass 0 + bDeviceProtocol 2 TT per port + bMaxPacketSize0 64 + idVendor 0x0bda Realtek Semiconductor Corp. + idProduct 0x5423 + bcdDevice 1.19 + iManufacturer 1 Generic + iProduct 2 4-Port USB 2.0 Hub + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 41 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xe0 + Self Powered + Remote Wakeup + MaxPower 0mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 9 Hub + bInterfaceSubClass 0 + bInterfaceProtocol 1 Single TT + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0001 1x 1 bytes + bInterval 12 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 9 Hub + bInterfaceSubClass 0 + bInterfaceProtocol 2 TT per port + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0001 1x 1 bytes + bInterval 12 +Hub Descriptor: + bLength 9 + bDescriptorType 41 + nNbrPorts 5 + wHubCharacteristic 0x00a9 + Per-port power switching + Per-port overcurrent protection + TT think time 16 FS bits + Port indicators + bPwrOn2PwrGood 0 * 2 milli seconds + bHubContrCurrent 100 milli Ampere + DeviceRemovable 0x00 + PortPwrCtrlMask 0xff + Hub Port Status: + Port 1: 0000.0100 power + Port 2: 0000.0100 power + Port 3: 0000.0100 power + Port 4: 0000.0100 power + Port 5: 0000.0503 highspeed power enable connect +Binary Object Store Descriptor: + bLength 5 + bDescriptorType 15 + wTotalLength 73 + bNumDeviceCaps 5 + USB 2.0 Extension Device Capability: + bLength 7 + bDescriptorType 16 + bDevCapabilityType 2 + bmAttributes 0x0000f41e + BESL Link Power Management (LPM) Supported + BESL value 1024 us + Deep BESL value 61440 us + SuperSpeed USB Device Capability: + bLength 10 + bDescriptorType 16 + bDevCapabilityType 3 + bmAttributes 0x00 + wSpeedsSupported 0x000e + Device can operate at Full Speed (12Mbps) + Device can operate at High Speed (480Mbps) + Device can operate at SuperSpeed (5Gbps) + bFunctionalitySupport 1 + Lowest fully-functional device speed is Full Speed (12Mbps) + bU1DevExitLat 10 micro seconds + bU2DevExitLat 1023 micro seconds + SuperSpeedPlus USB Device Capability: + bLength 28 + bDescriptorType 16 + bDevCapabilityType 10 + bmAttributes 0x00000023 + Sublink Speed Attribute count 3 + Sublink Speed ID count 1 + wFunctionalitySupport 0x1100 + bmSublinkSpeedAttr[0] 0x00050030 + Speed Attribute ID: 0 5Gb/s Symmetric RX SuperSpeed + bmSublinkSpeedAttr[1] 0x000500b0 + Speed Attribute ID: 0 5Gb/s Symmetric TX SuperSpeed + bmSublinkSpeedAttr[2] 0x000a4031 + Speed Attribute ID: 1 10Gb/s Symmetric RX SuperSpeedPlus + bmSublinkSpeedAttr[3] 0x000a40b1 + Speed Attribute ID: 1 10Gb/s Symmetric TX SuperSpeedPlus + Container ID Device Capability: + bLength 20 + bDescriptorType 16 + bDevCapabilityType 4 + bReserved 0 + ContainerID {20b9cde5-7039-e011-a935-0002a5d5c51b} + ** UNRECOGNIZED: 03 10 0b +Device Status: 0x0001 + Self Powered diff -Nru fwupd-1.0.6/plugins/rts54hub/fu-plugin-rts54hub.c fwupd-1.2.10/plugins/rts54hub/fu-plugin-rts54hub.c --- fwupd-1.0.6/plugins/rts54hub/fu-plugin-rts54hub.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/fu-plugin-rts54hub.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-rts54hub-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.realtek.rts54"); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuRts54HubDevice) dev = NULL; + + /* open the device */ + dev = fu_rts54hub_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + + /* success */ + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/rts54hub/fu-rts54hub-device.c fwupd-1.2.10/plugins/rts54hub/fu-rts54hub-device.c --- fwupd-1.0.6/plugins/rts54hub/fu-rts54hub-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/fu-rts54hub-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-rts54hub-device.h" + +struct _FuRts54HubDevice { + FuUsbDevice parent_instance; + gboolean fw_auth; + gboolean dual_bank; + gboolean running_on_flash; + guint8 vendor_cmd; +}; + +G_DEFINE_TYPE (FuRts54HubDevice, fu_rts54hub_device, FU_TYPE_USB_DEVICE) + +#define FU_RTS54HUB_DEVICE_TIMEOUT 100 /* ms */ +#define FU_RTS54HUB_DEVICE_TIMEOUT_RW 1000 /* ms */ +#define FU_RTS54HUB_DEVICE_TIMEOUT_ERASE 5000 /* ms */ +#define FU_RTS54HUB_DEVICE_TIMEOUT_AUTH 10000 /* ms */ +#define FU_RTS54HUB_DEVICE_BLOCK_SIZE 4096 +#define FU_RTS54HUB_DEVICE_STATUS_LEN 25 + +typedef enum { + FU_RTS54HUB_VENDOR_CMD_NONE = 0x00, + FU_RTS54HUB_VENDOR_CMD_STATUS = 1 << 0, + FU_RTS54HUB_VENDOR_CMD_FLASH = 1 << 1, +} FuRts54HubVendorCmd; + +static void +fu_rts54hub_device_to_string (FuDevice *device, GString *str) +{ + FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device); + g_string_append (str, " FuRts54HubDevice:\n"); + g_string_append_printf (str, " fw-auth: %i\n", self->fw_auth); + g_string_append_printf (str, " dual-bank: %i\n", self->dual_bank); + g_string_append_printf (str, " running-on-flash: %i\n", self->running_on_flash); +} + +static gboolean +fu_rts54hub_device_highclockmode (FuRts54HubDevice *self, guint16 value, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x06, /* request */ + value, /* value */ + 0, /* idx */ + NULL, 0, /* data */ + NULL, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to set highclockmode: "); + return FALSE; + } + return TRUE; +} + + +static gboolean +fu_rts54hub_device_reset_flash (FuRts54HubDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xC0 + 0x29, /* request */ + 0x0, /* value */ + 0x0, /* idx */ + NULL, 0, /* data */ + NULL, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to reset flash: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hub_device_write_flash (FuRts54HubDevice *self, + guint32 addr, + const guint8 *data, + gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_len = 0; + g_autofree guint8 *datarw = g_memdup (data, datasz); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xC0 + 0x08, /* request */ + addr % (1 << 16), /* value */ + addr / (1 << 16), /* idx */ + datarw, datasz, /* data */ + &actual_len, + FU_RTS54HUB_DEVICE_TIMEOUT_RW, + NULL, error)) { + g_prefix_error (error, "failed to write flash: "); + return FALSE; + } + if (actual_len != datasz) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only wrote %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} + +#if 0 +static gboolean +fu_rts54hub_device_read_flash (FuRts54HubDevice *self, + guint32 addr, + guint8 *data, + gsize datasz, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_len = 0; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xC0 + 0x18, /* request */ + addr % (1 << 16), /* value */ + addr / (1 << 16), /* idx */ + data, datasz, /* data */ + &actual_len, + FU_RTS54HUB_DEVICE_TIMEOUT_RW, + NULL, error)) { + g_prefix_error (error, "failed to read flash: "); + return FALSE; + } + if (actual_len != datasz) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + return TRUE; +} +#endif + +static gboolean +fu_rts54hub_device_flash_authentication (FuRts54HubDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xC0 + 0x19, /* request */ + 0x01, /* value */ + 0x0, /* idx */ + NULL, 0, /* data */ + NULL, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT_AUTH, + NULL, error)) { + g_prefix_error (error, "failed to authenticate: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hub_device_erase_flash (FuRts54HubDevice *self, + guint8 erase_type, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0xC0 + 0x28, /* request */ + erase_type * 256, /* value */ + 0x0, /* idx */ + NULL, 0, /* data */ + NULL, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT_ERASE, + NULL, error)) { + g_prefix_error (error, "failed to erase flash: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_rts54hub_device_vendor_cmd (FuRts54HubDevice *self, guint8 value, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + + /* don't set something that's already set */ + if (self->vendor_cmd == value) { + g_debug ("skipping vendor command 0x%02x as already set", value); + return TRUE; + } + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x02, /* request */ + value, /* value */ + 0x0bda, /* idx */ + NULL, 0, /* data */ + NULL, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to issue vendor cmd 0x%02x: ", value); + return FALSE; + } + self->vendor_cmd = value; + return TRUE; +} + +static gboolean +fu_rts54hub_device_ensure_status (FuRts54HubDevice *self, GError **error) +{ + guint8 data[FU_RTS54HUB_DEVICE_STATUS_LEN] = { 0 }; + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_len = 0; + + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x09, /* request */ + 0x0, /* value */ + 0x0, /* idx */ + data, sizeof(data), + &actual_len, /* actual */ + FU_RTS54HUB_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "failed to get status: "); + return FALSE; + } + if (actual_len != FU_RTS54HUB_DEVICE_STATUS_LEN) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "only read %" G_GSIZE_FORMAT "bytes", actual_len); + return FALSE; + } + + /* check the hardware capabilities */ + self->dual_bank = (data[7] & 0x80) == 0x80; + self->fw_auth = (data[13] & 0x02) > 0; + self->running_on_flash = (data[15] & 0x02) > 0; + + return TRUE; +} + +static gboolean +fu_rts54hub_device_setup (FuDevice *device, GError **error) +{ + FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device); + + /* check this device is correct */ + if (!fu_rts54hub_device_vendor_cmd (self, FU_RTS54HUB_VENDOR_CMD_STATUS, error)) { + g_prefix_error (error, "failed to vendor enable: "); + return FALSE; + } + if (!fu_rts54hub_device_ensure_status (self, error)) + return FALSE; + + /* all three conditions must be set */ + if (!self->running_on_flash) { + fu_device_set_update_error (device, + "device is abnormally running from ROM"); + } else if (!self->fw_auth) { + fu_device_set_update_error (device, + "device does not support authentication"); + } else if (!self->dual_bank) { + fu_device_set_update_error (device, + "device does not support dual-bank updating"); + } else { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hub_device_close (FuUsbDevice *device, GError **error) +{ + FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device); + + /* disable vendor commands */ + if (self->vendor_cmd != FU_RTS54HUB_VENDOR_CMD_NONE) { + if (!fu_rts54hub_device_vendor_cmd (self, FU_RTS54HUB_VENDOR_CMD_NONE, error)) { + g_prefix_error (error, "failed to disable vendor command: "); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_rts54hub_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuRts54HubDevice *self = FU_RTS54HUB_DEVICE (device); + g_autoptr(GPtrArray) chunks = NULL; + + /* enable vendor commands */ + if (!fu_rts54hub_device_vendor_cmd (self, + FU_RTS54HUB_VENDOR_CMD_STATUS | + FU_RTS54HUB_VENDOR_CMD_FLASH, + error)) { + g_prefix_error (error, "failed to cmd enable: "); + return FALSE; + } + + /* erase spare flash bank only if it is not empty */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_rts54hub_device_erase_flash (self, 1, error)) + return FALSE; + + /* set MCU clock to high clock mode */ + if (!fu_rts54hub_device_highclockmode (self, 0x0001, error)) { + g_prefix_error (error, "failed to enable MCU clock: "); + return FALSE; + } + + /* set SPI controller clock to high clock mode */ + if (!fu_rts54hub_device_highclockmode (self, 0x0101, error)) { + g_prefix_error (error, "failed to enable SPI clock: "); + return FALSE; + } + + /* build packets */ + chunks = fu_chunk_array_new_from_bytes (fw, + 0x00, /* start addr */ + 0x00, /* page_sz */ + FU_RTS54HUB_DEVICE_BLOCK_SIZE); + + /* write each block */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + + /* write chunk */ + if (!fu_rts54hub_device_write_flash (self, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len - 1); + } + + /* get device to authenticate the firmware */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_VERIFY); + if (!fu_rts54hub_device_flash_authentication (self, error)) + return FALSE; + + /* send software reset to run available flash code */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!fu_rts54hub_device_reset_flash (self, error)) + return FALSE; + + /* don't reset the vendor command enable, the device will be rebooted */ + self->vendor_cmd = FU_RTS54HUB_VENDOR_CMD_NONE; + + /* success! */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static GBytes * +fu_rts54hub_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + gsize sz = 0; + const guint8 *data = g_bytes_get_data (fw, &sz); + if (sz < 0x7ef3) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware was too small"); + return NULL; + } + if ((data[0x7ef3] & 0xf0) != 0x80) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware needs to be dual bank"); + return NULL; + } + return g_bytes_ref (fw); +} + +static void +fu_rts54hub_device_init (FuRts54HubDevice *self) +{ + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_rts54hub_device_class_init (FuRts54HubDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_rts54hub_device_write_firmware; + klass_device->setup = fu_rts54hub_device_setup; + klass_device->to_string = fu_rts54hub_device_to_string; + klass_device->prepare_firmware = fu_rts54hub_device_prepare_firmware; + klass_usb_device->close = fu_rts54hub_device_close; +} + +FuRts54HubDevice * +fu_rts54hub_device_new (FuUsbDevice *device) +{ + FuRts54HubDevice *self = g_object_new (FU_TYPE_RTS54HUB_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/rts54hub/fu-rts54hub-device.h fwupd-1.2.10/plugins/rts54hub/fu-rts54hub-device.h --- fwupd-1.0.6/plugins/rts54hub/fu-rts54hub-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/fu-rts54hub-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_RTS54HUB_DEVICE (fu_rts54hub_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuRts54HubDevice, fu_rts54hub_device, FU, RTS54HUB_DEVICE, FuUsbDevice) + +FuRts54HubDevice *fu_rts54hub_device_new (FuUsbDevice *device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/rts54hub/meson.build fwupd-1.2.10/plugins/rts54hub/meson.build --- fwupd-1.0.6/plugins/rts54hub/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginRts54Hub"'] + +install_data([ + 'rts54hub.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_rts54hub', + fu_hash, + sources : [ + 'fu-rts54hub-device.c', + 'fu-plugin-rts54hub.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff -Nru fwupd-1.0.6/plugins/rts54hub/README.md fwupd-1.2.10/plugins/rts54hub/README.md --- fwupd-1.0.6/plugins/rts54hub/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,30 @@ +Realtek RTS54 HUB Support +========================= + +Introduction +------------ + +This plugin allows the user to update any supported hub and attached downstream +ICs using a custom HUB-based flashing protocol. It does not support any RTS54xx +device using the HID update protocol. + +Other devices connected to the RTS54xx using I2C will be supported soon. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.realtek.rts54 + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_0BDA&PID_5423&REV_0001` + * `USB\VID_0BDA&PID_5423` + * `USB\VID_0BDA` diff -Nru fwupd-1.0.6/plugins/rts54hub/rts54hub.quirk fwupd-1.2.10/plugins/rts54hub/rts54hub.quirk --- fwupd-1.0.6/plugins/rts54hub/rts54hub.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/rts54hub/rts54hub.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,5 @@ +# RTS5423 Development Board +[DeviceInstanceId=USB\VID_0BDA&PID_5423] +Plugin = rts54hub +FirmwareSizeMin = 0x20000 +FirmwareSizeMax = 0x40000 diff -Nru fwupd-1.0.6/plugins/steelseries/fu-plugin-steelseries.c fwupd-1.2.10/plugins/steelseries/fu-plugin-steelseries.c --- fwupd-1.0.6/plugins/steelseries/fu-plugin-steelseries.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/steelseries/fu-plugin-steelseries.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,40 +1,31 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "fu-steelseries-device.h" +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); +} + gboolean -fu_plugin_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { - g_autoptr(FuSteelseriesDevice) device = NULL; + g_autoptr(FuSteelseriesDevice) dev = NULL; g_autoptr(FuDeviceLocker) locker = NULL; - device = fu_steelseries_device_new (usb_device); - locker = fu_device_locker_new (device, error); + dev = fu_steelseries_device_new (device); + locker = fu_device_locker_new (dev, error); if (locker == NULL) return FALSE; - fu_plugin_device_add (plugin, FU_DEVICE (device)); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); return TRUE; } diff -Nru fwupd-1.0.6/plugins/steelseries/fu-steelseries-device.c fwupd-1.2.10/plugins/steelseries/fu-steelseries-device.c --- fwupd-1.0.6/plugins/steelseries/fu-steelseries-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/steelseries/fu-steelseries-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -30,47 +15,32 @@ G_DEFINE_TYPE (FuSteelseriesDevice, fu_steelseries_device, FU_TYPE_USB_DEVICE) static gboolean -fu_steelseries_device_probe (FuUsbDevice *device, GError **error) +fu_steelseries_device_open (FuUsbDevice *device, GError **error) { GUsbDevice *usb_device = fu_usb_device_get_dev (device); + const guint8 iface_idx = 0x00; - /* not the right kind of device */ - if (g_usb_device_get_vid (usb_device) != 0x1038 || - g_usb_device_get_pid (usb_device) != 0x1702) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "not supported with this device"); + /* get firmware version on SteelSeries Rival 100 */ + if (!g_usb_device_claim_interface (usb_device, iface_idx, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim interface: "); return FALSE; } - /* hardcoded */ - fu_device_set_name (FU_DEVICE (device), "SteelSeries Rival 100"); - fu_device_set_vendor (FU_DEVICE (device), "SteelSeries"); - fu_device_set_summary (FU_DEVICE (device), "An optical gaming mouse"); - fu_device_add_icon (FU_DEVICE (device), "input-mouse"); - /* success */ return TRUE; } static gboolean -fu_steelseries_device_open (FuUsbDevice *device, GError **error) +fu_steelseries_device_setup (FuDevice *device, GError **error) { - GUsbDevice *usb_device = fu_usb_device_get_dev (device); - const guint8 iface_idx = 0x00; + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); gboolean ret; gsize actual_len = 0; guint8 data[32]; g_autofree gchar *version = NULL; - /* get firmware version on SteelSeries Rival 100 */ - if (!g_usb_device_claim_interface (usb_device, iface_idx, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "failed to claim interface: "); - return FALSE; - } memset (data, 0x00, sizeof(data)); data[0] = 0x16; ret = g_usb_device_control_transfer (usb_device, @@ -117,7 +87,7 @@ return FALSE; } version = g_strdup_printf ("%i.%i.%i", data[0], data[1], data[2]); - fu_device_set_version (FU_DEVICE (device), version); + fu_device_set_version (FU_DEVICE (device), version, FWUPD_VERSION_FORMAT_TRIPLET); /* success */ return TRUE; @@ -149,18 +119,17 @@ static void fu_steelseries_device_class_init (FuSteelseriesDeviceClass *klass) { + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->setup = fu_steelseries_device_setup; klass_usb_device->open = fu_steelseries_device_open; klass_usb_device->close = fu_steelseries_device_close; - klass_usb_device->probe = fu_steelseries_device_probe; } FuSteelseriesDevice * -fu_steelseries_device_new (GUsbDevice *usb_device) +fu_steelseries_device_new (FuUsbDevice *device) { - FuSteelseriesDevice *device = NULL; - device = g_object_new (FU_TYPE_STEELSERIES_DEVICE, - "usb-device", usb_device, - NULL); - return device; + FuSteelseriesDevice *self = g_object_new (FU_TYPE_STEELSERIES_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; } diff -Nru fwupd-1.0.6/plugins/steelseries/fu-steelseries-device.h fwupd-1.2.10/plugins/steelseries/fu-steelseries-device.h --- fwupd-1.0.6/plugins/steelseries/fu-steelseries-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/steelseries/fu-steelseries-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_STEELSERIES_DEVICE_H -#define __FU_STEELSERIES_DEVICE_H - -#include -#include +#pragma once #include "fu-plugin.h" @@ -37,8 +18,6 @@ FuUsbDeviceClass parent_class; }; -FuSteelseriesDevice *fu_steelseries_device_new (GUsbDevice *usb_device); +FuSteelseriesDevice *fu_steelseries_device_new (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_STEELSERIES_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/steelseries/meson.build fwupd-1.2.10/plugins/steelseries/meson.build --- fwupd-1.0.6/plugins/steelseries/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/steelseries/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,11 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginSteelSeries"'] +install_data(['steelseries.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_steelseries', + fu_hash, sources : [ 'fu-plugin-steelseries.c', 'fu-steelseries-device.c', @@ -12,6 +17,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.0.6/plugins/steelseries/README.md fwupd-1.2.10/plugins/steelseries/README.md --- fwupd-1.0.6/plugins/steelseries/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/steelseries/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -7,3 +7,12 @@ This plugin is used to get the correct version number on SteelSeries gaming mice. These mice have updatable firmware but so far no updates are available from the vendor. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_1038&PID_1702&REV_0001` + * `USB\VID_1038&PID_1702` + * `USB\VID_1038` diff -Nru fwupd-1.0.6/plugins/steelseries/steelseries.quirk fwupd-1.2.10/plugins/steelseries/steelseries.quirk --- fwupd-1.0.6/plugins/steelseries/steelseries.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/steelseries/steelseries.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,5 @@ +# Rival 100 +[DeviceInstanceId=USB\VID_1038&PID_1702] +Plugin = steelseries +Summary = An optical gaming mouse +Icon = input-mouse diff -Nru fwupd-1.0.6/plugins/superio/fu-plugin-superio.c fwupd-1.2.10/plugins/superio/fu-plugin-superio.c --- fwupd-1.0.6/plugins/superio/fu-plugin-superio.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-plugin-superio.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-superio-it85-device.h" +#include "fu-superio-it89-device.h" + +#define FU_QUIRKS_SUPERIO_CHIPSETS "SuperioChipsets" + +static gboolean +fu_plugin_superio_coldplug_chipset (FuPlugin *plugin, const gchar *chipset, GError **error) +{ + g_autoptr(FuSuperioDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + g_autofree gchar *key = g_strdup_printf ("SuperIO=%s", chipset); + guint64 id; + guint64 port; + + /* get ID we need for the chipset */ + id = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Id"); + if (id == 0x0000 || id > 0xffff) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SuperIO chip %s has invalid Id", chipset); + return FALSE; + } + + /* set address */ + port = fu_plugin_lookup_quirk_by_id_as_uint64 (plugin, key, "Port"); + if (port == 0x0 || port > 0xffff) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SuperIO chip %s has invalid Port", chipset); + return FALSE; + } + + /* create IT89xx or IT89xx */ + if (id >> 8 == 0x85) { + dev = g_object_new (FU_TYPE_SUPERIO_IT85_DEVICE, + "chipset", chipset, + "id", id, + "port", port, + NULL); + } else if (id >> 8 == 0x89) { + dev = g_object_new (FU_TYPE_SUPERIO_IT89_DEVICE, + "chipset", chipset, + "id", id, + "port", port, + NULL); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SuperIO chip %s has unsupported Id", chipset); + return FALSE; + } + + /* unlock */ + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + + return TRUE; +} + +static gboolean +fu_plugin_superio_coldplug_chipsets (FuPlugin *plugin, const gchar *str, GError **error) +{ + g_auto(GStrv) chipsets = g_strsplit (str, ",", -1); + for (guint i = 0; chipsets[i] != NULL; i++) { + if (!fu_plugin_superio_coldplug_chipset (plugin, chipsets[i], error)) + return FALSE; + } + return TRUE; +} + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "tw.com.ite.superio"); +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + GPtrArray *hwids = fu_plugin_get_hwids (plugin); + for (guint i = 0; i < hwids->len; i++) { + const gchar *tmp; + const gchar *guid = g_ptr_array_index (hwids, i); + g_autofree gchar *key = g_strdup_printf ("HwId=%s", guid); + tmp = fu_plugin_lookup_quirk_by_id (plugin, key, FU_QUIRKS_SUPERIO_CHIPSETS); + if (tmp == NULL) + continue; + if (!fu_plugin_superio_coldplug_chipsets (plugin, tmp, error)) + return FALSE; + } + return TRUE; +} + +gboolean +fu_plugin_verify_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_verify_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_verify (FuPlugin *plugin, FuDevice *device, + FuPluginVerifyFlags flags, GError **error) +{ + g_autoptr(GBytes) fw = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + GChecksumType checksum_types[] = { + G_CHECKSUM_SHA1, + G_CHECKSUM_SHA256, + 0 }; + + /* get data */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + fw = fu_device_read_firmware (device, error); + if (fw == NULL) + return FALSE; + for (guint i = 0; checksum_types[i] != 0; i++) { + g_autofree gchar *hash = NULL; + hash = g_compute_checksum_for_bytes (checksum_types[i], fw); + fu_device_add_checksum (device, hash); + } + return TRUE; +} + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-common.c fwupd-1.2.10/plugins/superio/fu-superio-common.c --- fwupd-1.0.6/plugins/superio/fu-superio-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-superio-common.h" + +gboolean +fu_superio_outb (gint fd, guint16 port, guint8 data, GError **error) +{ + if (pwrite (fd, &data, 1, (goffset) port) != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write to port %04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +} + +gboolean +fu_superio_inb (gint fd, guint16 port, guint8 *data, GError **error) +{ + if (pread (fd, data, 1, (goffset) port) != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to read from port %04x: %s", + (guint) port, + strerror (errno)); + return FALSE; + } + return TRUE; +} + +const gchar * +fu_superio_ldn_to_text (guint8 ldn) +{ + if (ldn == SIO_LDN_FDC) + return "Floppy Disk Controller"; + if (ldn == SIO_LDN_GPIO) + return "General Purpose IO"; + if (ldn == SIO_LDN_PARALLEL_PORT) + return "Parallel Port"; + if (ldn == SIO_LDN_UART1) + return "Serial Port 1"; + if (ldn == SIO_LDN_UART2) + return "Serial Port 2"; + if (ldn == SIO_LDN_UART3) + return "Serial Port 3"; + if (ldn == SIO_LDN_UART4) + return "Serial Port 4"; + if (ldn == SIO_LDN_SWUC) + return "System Wake-Up Control"; + if (ldn == SIO_LDN_KBC_MOUSE) + return "KBC/Mouse"; + if (ldn == SIO_LDN_KBC_KEYBOARD) + return "KBC/Keyboard"; + if (ldn == SIO_LDN_CIR) + return "Consumer IR"; + if (ldn == SIO_LDN_SMFI) + return "Shared Memory/Flash"; + if (ldn == SIO_LDN_RTCT) + return "RTC-like Timer"; + if (ldn == SIO_LDN_SSSP1) + return "Serial Peripheral"; + if (ldn == SIO_LDN_PECI) + return "Platform Environmental Control"; + if (ldn == SIO_LDN_PM1) + return "Power Management 1"; + if (ldn == SIO_LDN_PM2) + return "Power Management 2"; + if (ldn == SIO_LDN_PM3) + return "Power Management 3"; + if (ldn == SIO_LDN_PM4) + return "Power Management 4"; + if (ldn == SIO_LDN_PM5) + return "Power Management 5"; + return NULL; +} diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-common.h fwupd-1.2.10/plugins/superio/fu-superio-common.h --- fwupd-1.0.6/plugins/superio/fu-superio-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +/* for all LDNs */ +#define SIO_LDNxx_IDX_LDNSEL 0x07 +#define SIO_LDNxx_IDX_CHIPID1 0x20 +#define SIO_LDNxx_IDX_CHIPID2 0x21 +#define SIO_LDNxx_IDX_CHIPVER 0x22 +#define SIO_LDNxx_IDX_SIOCTRL 0x23 +#define SIO_LDNxx_IDX_SIOIRQ 0x25 +#define SIO_LDNxx_IDX_SIOGP 0x26 +#define SIO_LDNxx_IDX_SIOPWR 0x2d +#define SIO_LDNxx_IDX_D2ADR 0x2e +#define SIO_LDNxx_IDX_D2DAT 0x2f + +#define SIO_LDNxx_IDX_IOBAD0 0x60 /* 16 bit */ +#define SIO_LDNxx_IDX_IOBAD1 0x62 /* 16 bit */ + +/* these registers are only accessible by EC */ +#define GCTRL_ECHIPID1 0x2000 +#define GCTRL_ECHIPID2 0x2001 +#define GCTRL_ECHIPVER 0x2002 + +/* to create sub-addresses */ +#define SIO_DEPTH2_I2EC_ADDRL 0x10 +#define SIO_DEPTH2_I2EC_ADDRH 0x11 +#define SIO_DEPTH2_I2EC_DATA 0x12 + +/* + * The PMC is a communication channel used between the host and the EC. + * Compatible mode uses four registers: + * + * Name | EC | HOST | ADDR + * _____________________|_______________|_______________|______ + * PMDIR | RO | WO | 0x62 + * PMDOR | WO | RO | 0x62 + * PMCMDR | RO | RO | 0x66 + * PMSTR | RO | RO | 0x66 + */ +#define SIO_EC_PMC_PM1STS 0x00 +#define SIO_EC_PMC_PM1DO 0x01 +#define SIO_EC_PMC_PM1DOSCI 0x02 +#define SIO_EC_PMC_PM1DOCMI 0x03 +#define SIO_EC_PMC_PM1DI 0x04 +#define SIO_EC_PMC_PM1DISCI 0x05 +#define SIO_EC_PMC_PM1CTL 0x06 +#define SIO_EC_PMC_PM1IC 0x07 +#define SIO_EC_PMC_PM1IE 0x08 + +/* SPI commands */ +#define SIO_SPI_CMD_READ 0x03 +#define SIO_SPI_CMD_HS_READ 0x0b +#define SIO_SPI_CMD_FAST_READ_DUAL_OP 0x3b +#define SIO_SPI_CMD_FAST_READ_DUAL_IO 0xbb +#define SIO_SPI_CMD_4K_SECTOR_ERASE 0xd7 /* or 0x20 or 0x52 */ +#define SIO_SPI_CMD_64K_BLOCK_ERASE 0xd8 +#define SIO_SPI_CMD_CHIP_ERASE 0xc7 /* or 0x60 */ +#define SIO_SPI_CMD_PAGE_PROGRAM 0x02 +#define SIO_SPI_CMD_WRITE_WORD 0xad +#define SIO_SPI_CMD_RDSR 0x05 /* read status register */ +#define SIO_SPI_CMD_WRSR 0x01 /* write status register */ +#define SIO_SPI_CMD_WREN 0x06 /* write enable */ +#define SIO_SPI_CMD_WRDI 0x04 /* write disable */ +#define SIO_SPI_CMD_RDID 0xab +#define SIO_SPI_CMD_JEDEC_ID 0x9f +#define SIO_SPI_CMD_DPD 0xb9 /* deep sleep */ +#define SIO_SPI_CMD_RDPD 0xab /* wake from deep sleep */ + +/* EC Status Register (see ec/google/chromeec/ec_commands.h) */ +#define SIO_STATUS_EC_OBF (1 << 0) /* o/p buffer full */ +#define SIO_STATUS_EC_IBF (1 << 1) /* i/p buffer full */ +#define SIO_STATUS_EC_IS_BUSY (1 << 2) +#define SIO_STATUS_EC_IS_CMD (1 << 3) +#define SIO_STATUS_EC_BURST_ENABLE (1 << 4) +#define SIO_STATUS_EC_SCI (1 << 5) /* 1 if more events in queue */ + +/* EC Command Register (see KB3700-ds-01.pdf) */ +#define SIO_CMD_EC_READ 0x80 +#define SIO_CMD_EC_WRITE 0x81 +#define SIO_CMD_EC_BURST_ENABLE 0x82 +#define SIO_CMD_EC_BURST_DISABLE 0x83 +#define SIO_CMD_EC_QUERY_EVENT 0x84 +#define SIO_CMD_EC_GET_NAME_STR 0x92 +#define SIO_CMD_EC_GET_VERSION_STR 0x93 +#define SIO_CMD_EC_DISABLE_HOST_WA 0xdc +#define SIO_CMD_EC_ENABLE_HOST_WA 0xfc + +typedef enum { + SIO_LDN_FDC = 0x00, /* IT87 */ + SIO_LDN_UART1 = 0x01, /* IT87+IT89 */ + SIO_LDN_UART2 = 0x02, /* IT87+IT89 */ + SIO_LDN_PARALLEL_PORT = 0x03, /* IT87 */ + SIO_LDN_SWUC = 0x04, /* IT87+IT89 */ + SIO_LDN_KBC_MOUSE = 0x05, /* IT87+IT89 */ + SIO_LDN_KBC_KEYBOARD = 0x06, /* IT87+IT89 */ + SIO_LDN_GPIO = 0x07, /* IT87 */ + SIO_LDN_UART3 = 0x08, /* IT87 */ + SIO_LDN_UART4 = 0x09, /* IT87 */ + SIO_LDN_CIR = 0x0a, /* IT89 */ + SIO_LDN_SMFI = 0x0f, /* IT89 */ + SIO_LDN_RTCT = 0x10, /* IT89 */ + SIO_LDN_PM1 = 0x11, /* IT89 */ + SIO_LDN_PM2 = 0x12, /* IT89 */ + SIO_LDN_SSSP1 = 0x13, /* IT89 */ + SIO_LDN_PECI = 0x14, /* IT89 */ + SIO_LDN_PM3 = 0x17, /* IT89 */ + SIO_LDN_PM4 = 0x18, /* IT89 */ + SIO_LDN_PM5 = 0x19, /* IT89 */ + SIO_LDN_LAST = 0x1a +} SioLdn; + +const gchar *fu_superio_ldn_to_text (guint8 ldn); +gboolean fu_superio_outb (gint fd, + guint16 port, + guint8 data, + GError **error); +gboolean fu_superio_inb (gint fd, + guint16 port, + guint8 *data, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-device.c fwupd-1.2.10/plugins/superio/fu-superio-device.c --- fwupd-1.0.6/plugins/superio/fu-superio-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include "fu-superio-common.h" +#include "fu-superio-device.h" + +#define FU_PLUGIN_SUPERIO_TIMEOUT 0.25 /* s */ + +typedef struct +{ + gint fd; + gchar *chipset; + guint16 port; + guint16 pm1_iobad0; + guint16 pm1_iobad1; + guint16 id; +} FuSuperioDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuSuperioDevice, fu_superio_device, FU_TYPE_DEVICE) + +#define GET_PRIVATE(o) (fu_superio_device_get_instance_private (o)) + +enum { + PROP_0, + PROP_CHIPSET, + PROP_PORT, + PROP_ID, + PROP_LAST +}; + +gboolean +fu_superio_device_regval (FuSuperioDevice *self, guint8 addr, + guint8 *data, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + if (!fu_superio_outb (priv->fd, priv->port, addr, error)) + return FALSE; + if (!fu_superio_inb (priv->fd, priv->port + 1, data, error)) + return FALSE; + return TRUE; +} + +gboolean +fu_superio_device_regval16 (FuSuperioDevice *self, guint8 addr, + guint16 *data, GError **error) +{ + guint8 msb; + guint8 lsb; + if (!fu_superio_device_regval (self, addr, &msb, error)) + return FALSE; + if (!fu_superio_device_regval (self, addr + 1, &lsb, error)) + return FALSE; + *data = ((guint16) msb << 8) | (guint16) lsb; + return TRUE; +} + +gboolean +fu_superio_device_regwrite (FuSuperioDevice *self, guint8 addr, + guint8 data, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + if (!fu_superio_outb (priv->fd, priv->port, addr, error)) + return FALSE; + if (!fu_superio_outb (priv->fd, priv->port + 1, data, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_superio_device_set_ldn (FuSuperioDevice *self, guint8 ldn, GError **error) +{ + return fu_superio_device_regwrite (self, SIO_LDNxx_IDX_LDNSEL, ldn, error); +} + +static gboolean +fu_superio_device_regdump (FuSuperioDevice *self, guint8 ldn, GError **error) +{ + const gchar *ldnstr = fu_superio_ldn_to_text (ldn); + guint8 buf[0xff] = { 0x00 }; + guint16 iobad0 = 0x0; + guint16 iobad1 = 0x0; + g_autoptr(GString) str = g_string_new (NULL); + + /* set LDN */ + if (!fu_superio_device_set_ldn (self, ldn, error)) + return FALSE; + for (guint i = 0x00; i < 0xff; i++) { + if (!fu_superio_device_regval (self, i, &buf[i], error)) + return FALSE; + } + + /* get the i/o base addresses */ + if (!fu_superio_device_regval16 (self, SIO_LDNxx_IDX_IOBAD0, &iobad0, error)) + return FALSE; + if (!fu_superio_device_regval16 (self, SIO_LDNxx_IDX_IOBAD1, &iobad1, error)) + return FALSE; + + g_string_append_printf (str, "LDN:0x%02x ", ldn); + if (iobad0 != 0x0) + g_string_append_printf (str, "IOBAD0:0x%04x ", iobad0); + if (iobad1 != 0x0) + g_string_append_printf (str, "IOBAD1:0x%04x ", iobad1); + if (ldnstr != NULL) + g_string_append_printf (str, "(%s)", ldnstr); + fu_common_dump_raw (G_LOG_DOMAIN, str->str, buf, sizeof(buf)); + return TRUE; +} + +static void +fu_superio_device_to_string (FuDevice *device, GString *str) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + g_string_append (str, " FuSuperioDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", priv->fd); + g_string_append_printf (str, " chipset:\t\t%s\n", priv->chipset); + g_string_append_printf (str, " id:\t\t\t0x%04x\n", (guint) priv->id); + g_string_append_printf (str, " port:\t\t0x%04x\n", (guint) priv->port); + g_string_append_printf (str, " pm1-iobad0:\t\t0x%04x\n", (guint) priv->pm1_iobad0); + g_string_append_printf (str, " pm1-iobad1:\t\t0x%04x\n", (guint) priv->pm1_iobad1); +} + +static guint16 +fu_superio_device_check_id (FuSuperioDevice *self, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + guint16 id_tmp; + + /* check ID, which can be done from any LDN */ + if (!fu_superio_device_regval16 (self, SIO_LDNxx_IDX_CHIPID1, &id_tmp, error)) + return FALSE; + if (priv->id != id_tmp) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "SuperIO chip not supported, got %04x, expected %04x", + (guint) id_tmp, (guint) priv->id); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_superio_device_wait_for (FuSuperioDevice *self, guint8 mask, gboolean set, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GTimer) timer = g_timer_new (); + do { + guint8 status = 0x00; + if (!fu_superio_inb (priv->fd, priv->pm1_iobad1, &status, error)) + return FALSE; + if (g_timer_elapsed (timer, NULL) > FU_PLUGIN_SUPERIO_TIMEOUT) + break; + if (set && (status & mask) != 0) + return TRUE; + if (!set && (status & mask) == 0) + return TRUE; + } while (TRUE); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out whilst waiting for 0x%02x:%i", mask, set); + return FALSE; +} + +gboolean +fu_superio_device_ec_read (FuSuperioDevice *self, guint8 *data, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + if (!fu_superio_device_wait_for (self, SIO_STATUS_EC_OBF, TRUE, error)) + return FALSE; + return fu_superio_inb (priv->fd, priv->pm1_iobad0, data, error); +} + +gboolean +fu_superio_device_ec_write0 (FuSuperioDevice *self, guint8 data, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + if (!fu_superio_device_wait_for (self, SIO_STATUS_EC_IBF, FALSE, error)) + return FALSE; + return fu_superio_outb (priv->fd, priv->pm1_iobad0, data, error); +} + +gboolean +fu_superio_device_ec_write1 (FuSuperioDevice *self, guint8 data, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + if (!fu_superio_device_wait_for (self, SIO_STATUS_EC_IBF, FALSE, error)) + return FALSE; + return fu_superio_outb (priv->fd, priv->pm1_iobad1, data, error); +} + +static gboolean +fu_superio_device_ec_flush (FuSuperioDevice *self, GError **error) +{ + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + guint8 status = 0x00; + g_autoptr(GTimer) timer = g_timer_new (); + do { + guint8 unused = 0; + if (!fu_superio_inb (priv->fd, priv->pm1_iobad1, &status, error)) + return FALSE; + if ((status & SIO_STATUS_EC_OBF) == 0) + break; + if (!fu_superio_inb (priv->fd, priv->pm1_iobad0, &unused, error)) + return FALSE; + if (g_timer_elapsed (timer, NULL) > FU_PLUGIN_SUPERIO_TIMEOUT) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out whilst waiting for flush"); + return FALSE; + } + } while (TRUE); + return TRUE; +} + +gboolean +fu_superio_device_ec_get_param (FuSuperioDevice *self, guint8 param, guint8 *data, GError **error) +{ + if (!fu_superio_device_ec_write1 (self, SIO_CMD_EC_READ, error)) + return FALSE; + if (!fu_superio_device_ec_write0 (self, param, error)) + return FALSE; + return fu_superio_device_ec_read (self, data, error); +} + +#if 0 +static gboolean +fu_superio_device_ec_set_param (FuSuperioDevice *self, guint8 param, guint8 data, GError **error) +{ + if (!fu_superio_device_ec_write1 (self, SIO_CMD_EC_WRITE, error)) + return FALSE; + if (!fu_superio_device_ec_write0 (self, param, error)) + return FALSE; + return fu_superio_device_ec_write0 (self, data, error); +} +#endif + +static gboolean +fu_superio_device_open (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + + /* open device */ + priv->fd = g_open (fu_device_get_physical_id (device), O_RDWR); + if (priv->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s: %s", + fu_device_get_physical_id (device), + strerror (errno)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_superio_device_probe (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *devid = NULL; + g_autofree gchar *name = NULL; + + /* use the chipset name as the logical ID and for the GUID */ + fu_device_set_logical_id (device, priv->chipset); + devid = g_strdup_printf ("SuperIO-%s", priv->chipset); + fu_device_add_instance_id (device, devid); + name = g_strdup_printf ("SuperIO %s", priv->chipset); + fu_device_set_name (FU_DEVICE (self), name); + return TRUE; +} + +static gboolean +fu_superio_device_setup (FuDevice *device, GError **error) +{ + FuSuperioDeviceClass *klass = FU_SUPERIO_DEVICE_GET_CLASS (device); + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + guint8 tmp = 0x0; + + /* check port is valid */ + if (!fu_superio_inb (priv->fd, priv->pm1_iobad0, &tmp, error)) + return FALSE; + if (tmp != 0xff) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "check port!"); + return FALSE; + } + + /* check ID is correct */ + if (!fu_superio_device_check_id (self, error)) { + g_prefix_error (error, "failed to probe id: "); + return FALSE; + } + + /* dump LDNs */ + if (g_getenv ("FWUPD_SUPERIO_VERBOSE") != NULL) { + for (guint j = 0; j < SIO_LDN_LAST; j++) { + if (!fu_superio_device_regdump (self, j, error)) + return FALSE; + } + } + + /* set Power Management I/F Channel 1 LDN */ + if (!fu_superio_device_set_ldn (self, SIO_LDN_PM1, error)) + return FALSE; + + /* get the PM1 IOBAD0 address */ + if (!fu_superio_device_regval16 (self, SIO_LDNxx_IDX_IOBAD0, + &priv->pm1_iobad0, error)) + return FALSE; + + /* get the PM1 IOBAD1 address */ + if (!fu_superio_device_regval16 (self, SIO_LDNxx_IDX_IOBAD1, + &priv->pm1_iobad1, error)) + return FALSE; + + /* drain */ + if (!fu_superio_device_ec_flush (self, error)) { + g_prefix_error (error, "failed to flush: "); + return FALSE; + } + + /* dump PMC register map */ + if (g_getenv ("FWUPD_SUPERIO_VERBOSE") != NULL) { + guint8 buf[0xff] = { 0x00 }; + for (guint i = 0x00; i < 0xff; i++) { + g_autoptr(GError) error_local = NULL; + if (!fu_superio_device_ec_get_param (self, i, &buf[i], &error_local)) { + g_debug ("param: 0x%02x = %s", i, error_local->message); + continue; + } + } + fu_common_dump_raw (G_LOG_DOMAIN, "EC Registers", buf, 0x100); + } + + /* subclassed setup */ + if (klass->setup != NULL) + return klass->setup (self, error); + + /* success */ + return TRUE; +} + +static GBytes * +fu_superio_device_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + gsize sz = 0; + const guint8 *buf = g_bytes_get_data (fw, &sz); + const guint8 sig1[] = { 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 }; + const guint8 sig2[] = { 0x85, 0x12, 0x5a, 0x5a, 0xaa }; + + /* find signature -- maybe ignore byte 0x14 too? */ + for (gsize off = 0; off < sz; off += 16) { + if (memcmp (&buf[off], sig1, sizeof(sig1)) == 0 && + memcmp (&buf[off + 8], sig2, sizeof(sig2)) == 0) { + g_debug ("found signature at 0x%04x", (guint) off); + return g_bytes_ref (fw); + } + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "did not detect signature in firmware image"); + return NULL; +} + +static gboolean +fu_superio_device_close (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + if (!g_close (priv->fd, error)) + return FALSE; + priv->fd = 0; + return TRUE; +} + +static void +fu_superio_device_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (object); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_CHIPSET: + g_value_set_string (value, priv->chipset); + break; + case PROP_PORT: + g_value_set_uint (value, priv->port); + break; + case PROP_ID: + g_value_set_uint (value, priv->id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_superio_device_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (object); + FuSuperioDevicePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_CHIPSET: + g_free (priv->chipset); + priv->chipset = g_value_dup_string (value); + break; + case PROP_PORT: + priv->port = g_value_get_uint (value); + break; + case PROP_ID: + priv->id = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_superio_device_init (FuSuperioDevice *self) +{ + fu_device_set_physical_id (FU_DEVICE (self), "/dev/port"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_set_summary (FU_DEVICE (self), "Embedded Controller"); + fu_device_add_icon (FU_DEVICE (self), "computer"); +} + +static void +fu_superio_device_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_superio_device_parent_class)->finalize (object); +} + +static void +fu_superio_device_class_init (FuSuperioDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + + /* properties */ + object_class->get_property = fu_superio_device_get_property; + object_class->set_property = fu_superio_device_set_property; + pspec = g_param_spec_string ("chipset", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_CHIPSET, pspec); + pspec = g_param_spec_uint ("port", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PORT, pspec); + pspec = g_param_spec_uint ("id", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_ID, pspec); + + object_class->finalize = fu_superio_device_finalize; + klass_device->to_string = fu_superio_device_to_string; + klass_device->open = fu_superio_device_open; + klass_device->probe = fu_superio_device_probe; + klass_device->setup = fu_superio_device_setup; + klass_device->close = fu_superio_device_close; + klass_device->prepare_firmware = fu_superio_device_prepare_firmware; +} diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-device.h fwupd-1.2.10/plugins/superio/fu-superio-device.h --- fwupd-1.0.6/plugins/superio/fu-superio-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SUPERIO_DEVICE (fu_superio_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuSuperioDevice, fu_superio_device, FU, SUPERIO_DEVICE, FuDevice) + +struct _FuSuperioDeviceClass +{ + FuDeviceClass parent_class; + gboolean (*setup) (FuSuperioDevice *self, + GError **error); +}; + +gboolean fu_superio_device_ec_read (FuSuperioDevice *self, + guint8 *data, + GError **error); +gboolean fu_superio_device_ec_write0 (FuSuperioDevice *self, + guint8 data, + GError **error); +gboolean fu_superio_device_ec_write1 (FuSuperioDevice *self, + guint8 data, + GError **error); +gboolean fu_superio_device_ec_get_param (FuSuperioDevice *self, + guint8 param, + guint8 *data, + GError **error); +gboolean fu_superio_device_regval (FuSuperioDevice *self, + guint8 addr, + guint8 *data, + GError **error); +gboolean fu_superio_device_regval16 (FuSuperioDevice *self, + guint8 addr, + guint16 *data, + GError **error); +gboolean fu_superio_device_regwrite (FuSuperioDevice *self, + guint8 addr, + guint8 data, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-it85-device.c fwupd-1.2.10/plugins/superio/fu-superio-it85-device.c --- fwupd-1.0.6/plugins/superio/fu-superio-it85-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-it85-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" +#include "fu-superio-common.h" +#include "fu-superio-it85-device.h" + +struct _FuSuperioIt85Device { + FuSuperioDevice parent_instance; +}; + +G_DEFINE_TYPE (FuSuperioIt85Device, fu_superio_it85_device, FU_TYPE_SUPERIO_DEVICE) + +static gchar * +fu_superio_it85_device_get_str (FuSuperioDevice *self, guint8 idx, GError **error) +{ + GString *str = g_string_new (NULL); + if (!fu_superio_device_ec_write1 (self, idx, error)) + return NULL; + for (guint i = 0; i < 0xff; i++) { + guint8 c = 0; + if (!fu_superio_device_ec_read (self, &c, error)) + return NULL; + if (c == '$') + break; + g_string_append_c (str, c); + } + return g_string_free (str, FALSE); +} + +static gboolean +fu_superio_it85_device_setup (FuSuperioDevice *self, GError **error) +{ + guint8 size_tmp = 0; + g_autofree gchar *name = NULL; + g_autofree gchar *version = NULL; + + /* get EC size */ + if (!fu_superio_device_ec_get_param (self, 0xe5, &size_tmp, error)) { + g_prefix_error (error, "failed to get EC size: "); + return FALSE; + } + fu_device_set_firmware_size (FU_DEVICE (self), ((guint32) size_tmp) << 10); + + /* get EC strings */ + name = fu_superio_it85_device_get_str (self, SIO_CMD_EC_GET_NAME_STR, error); + if (name == NULL) { + g_prefix_error (error, "failed to get EC name: "); + return FALSE; + } + fu_device_set_name (FU_DEVICE (self), name); + version = fu_superio_it85_device_get_str (self, SIO_CMD_EC_GET_VERSION_STR, error); + if (version == NULL) { + g_prefix_error (error, "failed to get EC version: "); + return FALSE; + } + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_UNKNOWN); + return TRUE; +} + +static void +fu_superio_it85_device_init (FuSuperioIt85Device *self) +{ +} + +static void +fu_superio_it85_device_class_init (FuSuperioIt85DeviceClass *klass) +{ + FuSuperioDeviceClass *klass_superio_device = FU_SUPERIO_DEVICE_CLASS (klass); + klass_superio_device->setup = fu_superio_it85_device_setup; +} diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-it85-device.h fwupd-1.2.10/plugins/superio/fu-superio-it85-device.h --- fwupd-1.0.6/plugins/superio/fu-superio-it85-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-it85-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-superio-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SUPERIO_IT85_DEVICE (fu_superio_it85_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuSuperioIt85Device, fu_superio_it85_device, FU, SUPERIO_IT85_DEVICE, FuSuperioDevice) + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-it89-device.c fwupd-1.2.10/plugins/superio/fu-superio-it89-device.c --- fwupd-1.0.6/plugins/superio/fu-superio-it89-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-it89-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-chunk.h" +#include "fu-superio-common.h" +#include "fu-superio-it89-device.h" + +struct _FuSuperioIt89Device { + FuSuperioDevice parent_instance; +}; + +G_DEFINE_TYPE (FuSuperioIt89Device, fu_superio_it89_device, FU_TYPE_SUPERIO_DEVICE) + +static gboolean +fu_superio_it89_device_read_ec_register (FuSuperioDevice *self, + guint16 addr, + guint8 *outval, + GError **error) +{ + if (!fu_superio_device_regwrite (self, + SIO_LDNxx_IDX_D2ADR, + SIO_DEPTH2_I2EC_ADDRH, + error)) + return FALSE; + if (!fu_superio_device_regwrite (self, + SIO_LDNxx_IDX_D2DAT, + addr >> 8, + error)) + return FALSE; + if (!fu_superio_device_regwrite (self, + SIO_LDNxx_IDX_D2ADR, + SIO_DEPTH2_I2EC_ADDRL, + error)) + return FALSE; + if (!fu_superio_device_regwrite (self, + SIO_LDNxx_IDX_D2DAT, + addr & 0xff, error)) + return FALSE; + if (!fu_superio_device_regwrite (self, + SIO_LDNxx_IDX_D2ADR, + SIO_DEPTH2_I2EC_DATA, + error)) + return FALSE; + return fu_superio_device_regval (self, + SIO_LDNxx_IDX_D2DAT, + outval, + error); +} + +static gboolean +fu_superio_it89_device_ec_size (FuSuperioDevice *self, GError **error) +{ + guint8 tmp = 0; + + /* not sure why we can't just use SIO_LDNxx_IDX_CHIPID1, + * but lets do the same as the vendor flash tool... */ + if (!fu_superio_it89_device_read_ec_register (self, GCTRL_ECHIPID1, &tmp, error)) + return FALSE; + if (tmp == 0x85) { + g_warning ("possibly IT85xx class device?!"); + fu_device_set_firmware_size (FU_DEVICE (self), 0x20000); + return TRUE; + } + g_debug ("ECHIPID1: 0x%02x", (guint) tmp); + + /* can't we just use SIO_LDNxx_IDX_CHIPVER... */ + if (!fu_superio_it89_device_read_ec_register (self, GCTRL_ECHIPVER, &tmp, error)) + return FALSE; + g_debug ("ECHIPVER: 0x%02x", (guint) tmp); + if (tmp >> 4 == 0x00) { + fu_device_set_firmware_size (FU_DEVICE (self), 0x20000); + return TRUE; + } + if (tmp >> 4 == 0x04) { + fu_device_set_firmware_size (FU_DEVICE (self), 0x30000); + return TRUE; + } + if (tmp >> 4 == 0x08) { + fu_device_set_firmware_size (FU_DEVICE (self), 0x40000); + return TRUE; + } + g_warning ("falling back to default size"); + fu_device_set_firmware_size (FU_DEVICE (self), 0x20000); + return TRUE; +} + +static gboolean +fu_superio_it89_device_setup (FuSuperioDevice *self, GError **error) +{ + guint8 version_tmp[2] = { 0x00 }; + g_autofree gchar *version = NULL; + + /* try to recover this */ + if (g_getenv ("FWUPD_SUPERIO_RECOVER") != NULL) { + fu_device_set_firmware_size (FU_DEVICE (self), 0x20000); + return TRUE; + } + + /* get version */ + if (!fu_superio_device_ec_get_param (self, 0x00, &version_tmp[0], error)) { + g_prefix_error (error, "failed to get version major: "); + return FALSE; + } + if (!fu_superio_device_ec_get_param (self, 0x01, &version_tmp[1], error)) { + g_prefix_error (error, "failed to get version minor: "); + return FALSE; + } + version = g_strdup_printf ("%02u.%02u", version_tmp[0], version_tmp[1]); + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_PAIR); + + /* get size from the EC */ + if (!fu_superio_it89_device_ec_size (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_superio_it89_device_ec_pm1do_sci (FuSuperioDevice *self, guint8 val, GError **error) +{ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DOSCI, error)) + return FALSE; + if (!fu_superio_device_ec_write1 (self, val, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_superio_it89_device_ec_pm1do_smi (FuSuperioDevice *self, guint8 val, GError **error) +{ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DOCMI, error)) + return FALSE; + if (!fu_superio_device_ec_write1 (self, val, error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_superio_device_ec_read_status (FuSuperioDevice *self, GError **error) +{ + guint8 tmp = 0x00; + + /* read status register */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_RDSR, error)) + return FALSE; + + /* wait for write */ + do { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, &tmp, error)) + return FALSE; + } while ((tmp & SIO_STATUS_EC_OBF) != 0); + + /* watch SCI events */ + return fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DISCI, error); +} + +static gboolean +fu_superio_device_ec_write_disable (FuSuperioDevice *self, GError **error) +{ + guint8 tmp = 0x00; + + /* read existing status */ + if (!fu_superio_device_ec_read_status (self, error)) + return FALSE; + + /* write disable */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_WRDI, error)) + return FALSE; + + /* read status register */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_RDSR, error)) + return FALSE; + + /* wait for read */ + do { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, &tmp, error)) + return FALSE; + } while ((tmp & SIO_STATUS_EC_IBF) != 0); + + /* watch SCI events */ + return fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DISCI, error); +} + +static gboolean +fu_superio_device_ec_write_enable (FuSuperioDevice *self, GError **error) +{ + guint8 tmp = 0x0; + + /* read existing status */ + if (!fu_superio_device_ec_read_status (self, error)) + return FALSE; + + /* write enable */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_WREN, error)) + return FALSE; + + /* read status register */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_RDSR, error)) + return FALSE; + + /* wait for !BUSY */ + do { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, &tmp, error)) + return FALSE; + } while ((tmp & 3) != SIO_STATUS_EC_IBF); + + /* watch SCI events */ + return fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DISCI, error); +} + +static GBytes * +fu_superio_it89_device_read_addr (FuSuperioDevice *self, + guint32 addr, + guint size, + GFileProgressCallback progress_cb, + GError **error) +{ + g_autofree guint8 *buf = NULL; + + /* check... */ + if (!fu_superio_device_ec_write_disable (self, error)) + return NULL; + if (!fu_superio_device_ec_read_status (self, error)) + return NULL; + + /* high speed read */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return NULL; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_HS_READ, error)) + return NULL; + + /* set address, MSB, MID, LSB */ + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 16, error)) + return NULL; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 8, error)) + return NULL; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr & 0xff, error)) + return NULL; + + /* padding for HS? */ + if (!fu_superio_it89_device_ec_pm1do_smi (self, 0x0, error)) + return NULL; + + /* read out data */ + buf = g_malloc0 (size); + for (guint i = 0; i < size; i++) { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return NULL; + if (!fu_superio_device_ec_read (self, &buf[i], error)) + return NULL; + + /* update progress */ + if (progress_cb != NULL) + progress_cb ((goffset) i, (goffset) size, self); + } + + /* check again... */ + if (!fu_superio_device_ec_read_status (self, error)) + return NULL; + + /* success */ + return g_bytes_new_take (g_steal_pointer (&buf), size); +} + +static void +fu_superio_it89_device_progress_cb (goffset current, goffset total, gpointer user_data) +{ + FuDevice *device = FU_DEVICE (user_data); + fu_device_set_progress_full (device, (gsize) current, (gsize) total); +} + +static gboolean +fu_superio_it89_device_write_addr (FuSuperioDevice *self, guint addr, GBytes *fw, GError **error) +{ + gsize size = 0; + const guint8 *buf = g_bytes_get_data (fw, &size); + + /* sanity check */ + if ((addr & 0xff) != 0x00) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "write addr unaligned, got 0x%04x", + (guint) addr); + } + if (size % 2 != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "write length not supported, got 0x%04x", + (guint) size); + } + + /* enable writes */ + if (!fu_superio_device_ec_write_enable (self, error)) + return FALSE; + + /* write DWORDs */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_WRITE_WORD, error)) + return FALSE; + + /* set address, MSB, MID, LSB */ + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 16, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 8, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr & 0xff, error)) + return FALSE; + + /* write data two bytes at a time */ + for (guint i = 0; i < size; i += 2) { + if (i > 0) { + if (!fu_superio_device_ec_read_status (self, error)) + return FALSE; + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, + SIO_SPI_CMD_WRITE_WORD, + error)) + return FALSE; + } + if (!fu_superio_it89_device_ec_pm1do_smi (self, buf[i+0], error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_smi (self, buf[i+1], error)) + return FALSE; + } + + /* reset back? */ + if (!fu_superio_device_ec_write_disable (self, error)) + return FALSE; + return fu_superio_device_ec_read_status (self, error); +} + +static gboolean +fu_superio_it89_device_erase_addr (FuSuperioDevice *self, guint addr, GError **error) +{ + /* enable writes */ + if (!fu_superio_device_ec_write_enable (self, error)) + return FALSE; + + /* sector erase */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_4K_SECTOR_ERASE, error)) + return FALSE; + + /* set address, MSB, MID, LSB */ + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 16, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr >> 8, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_smi (self, addr & 0xff, error)) + return FALSE; + + /* watch SCI events */ + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DISCI, error)) + return FALSE; + return fu_superio_device_ec_read_status (self, error); +} + +/* The 14th byte of the 16 byte signature is always read from the hardware as + * 0x00 rather than the specified 0xAA. Fix up the firmware to match the + * .ROM file which uses 0x7F as the number of bytes to mirror to e-flash... */ +static GBytes * +fu_plugin_superio_fix_signature (FuSuperioDevice *self, GBytes *fw, GError **error) +{ + gsize sz = 0; + const guint8 *buf = g_bytes_get_data (fw, &sz); + g_autofree guint8 *buf2 = NULL; + const guint signature_offset = 0x4d; /* IT85, IT89 is 0x8d */ + + /* not big enough */ + if (sz < signature_offset + 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "image too small to fix"); + return NULL; + } + + /* not zero */ + if (buf[signature_offset] != 0x0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "nonzero signature byte"); + return NULL; + } + + /* fix signature to match SMT version */ + buf2 = g_memdup (buf, sz); + buf2[signature_offset] = 0x7f; + return g_bytes_new_take (g_steal_pointer (&buf2), sz); +} + +static GBytes * +fu_superio_it89_device_read_firmware (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + guint64 fwsize = fu_device_get_firmware_size_min (device); + g_autoptr(GBytes) blob = NULL; + + fu_device_set_status (device, FWUPD_STATUS_DEVICE_READ); + blob = fu_superio_it89_device_read_addr (self, 0x0, fwsize, + fu_superio_it89_device_progress_cb, + error); + return fu_plugin_superio_fix_signature (self, blob, error); +} + +static gboolean +fu_superio_it89_device_attach (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + + /* re-enable HOSTWA -- use 0xfd for LCFC */ + if (!fu_superio_device_ec_write1 (self, SIO_CMD_EC_ENABLE_HOST_WA, error)) + return FALSE; + + /* success */ + fu_device_remove_flag (self, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_superio_it89_device_detach (FuDevice *device, GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + guint8 tmp = 0x00; + + /* turn off HOSTWA bit, keeping HSEMIE and HSEMW high */ + if (!fu_superio_device_ec_write1 (self, SIO_CMD_EC_DISABLE_HOST_WA, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, &tmp, error)) + return FALSE; + if (tmp != 0x33) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "failed to clear HOSTWA, got 0x%02x, expected 0x33", + tmp); + return FALSE; + } + + /* success */ + fu_device_add_flag (self, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_superio_it89_device_check_eflash (FuSuperioDevice *self, GError **error) +{ + g_autoptr(GBytes) fw = NULL; + const guint64 fwsize = fu_device_get_firmware_size_min (FU_DEVICE (self)); + const guint sigsz = 16; + + /* last 16 bytes of eeprom */ + fw = fu_superio_it89_device_read_addr (self, fwsize - sigsz, + sigsz, NULL, error); + if (fw == NULL) { + g_prefix_error (error, "failed to read signature bytes"); + return FALSE; + } + + /* cannot flash here without keyboard programmer */ + if (!fu_common_bytes_is_empty (fw)) { + gsize sz = 0; + const guint8 *buf = g_bytes_get_data (fw, &sz); + g_autoptr(GString) str = g_string_new (NULL); + for (guint i = 0; i < sz; i++) + g_string_append_printf (str, "0x%02x ", buf[i]); + if (str->len > 0) + g_string_truncate (str, str->len - 1); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "e-flash has been protected: %s", + str->str); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_superio_it89_device_write_chunk (FuSuperioDevice *self, FuChunk *chk, GError **error) +{ + g_autoptr(GBytes) fw1 = NULL; + g_autoptr(GBytes) fw2 = NULL; + g_autoptr(GBytes) fw3 = NULL; + + /* erase page */ + if (!fu_superio_it89_device_erase_addr (self, chk->address, error)) { + g_prefix_error (error, "failed to erase @0x%04x", (guint) chk->address); + return FALSE; + } + + /* check erased */ + fw1 = fu_superio_it89_device_read_addr (self, chk->address, + chk->data_sz, NULL, + error); + if (fw1 == NULL) { + g_prefix_error (error, "failed to read erased " + "bytes @0x%04x", (guint) chk->address); + return FALSE; + } + if (!fu_common_bytes_is_empty (fw1)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "sector was not erased"); + return FALSE; + } + + /* skip empty page */ + fw2 = g_bytes_new_static (chk->data, chk->data_sz); + if (fu_common_bytes_is_empty (fw2)) + return TRUE; + + /* write page */ + if (!fu_superio_it89_device_write_addr (self, chk->address, fw2, error)) { + g_prefix_error (error, "failed to write @0x%04x", (guint) chk->address); + return FALSE; + } + + /* verify page */ + fw3 = fu_superio_it89_device_read_addr (self, chk->address, + chk->data_sz, NULL, + error); + if (fw3 == NULL) { + g_prefix_error (error, "failed to read written " + "bytes @0x%04x", (guint) chk->address); + return FALSE; + } + if (!fu_common_bytes_compare (fw2, fw3, error)) { + g_prefix_error (error, "failed to verify @0x%04x", + (guint) chk->address); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_superio_it89_device_get_jedec_id (FuSuperioDevice *self, guint8 *id, GError **error) +{ + /* read status register */ + if (!fu_superio_device_ec_read_status (self, error)) + return FALSE; + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DO, error)) + return FALSE; + if (!fu_superio_it89_device_ec_pm1do_sci (self, SIO_SPI_CMD_JEDEC_ID, error)) + return FALSE; + + /* wait for reads */ + for (guint i = 0; i < 4; i++) { + if (!fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DI, error)) + return FALSE; + if (!fu_superio_device_ec_read (self, &id[i], error)) + return FALSE; + } + + /* watch SCI events */ + return fu_superio_device_ec_write1 (self, SIO_EC_PMC_PM1DISCI, error); +} + +static gboolean +fu_superio_it89_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuSuperioDevice *self = FU_SUPERIO_DEVICE (device); + guint8 id[4] = { 0x0 }; + g_autoptr(GBytes) fw_fixed = NULL; + g_autoptr(GPtrArray) chunks = NULL; + + /* check JEDEC ID */ + if (!fu_superio_it89_device_get_jedec_id (self, id, error)) { + g_prefix_error (error, "failed to get JEDEC ID: "); + return FALSE; + } + if (id[0] != 0xff || id[1] != 0xff || id[2] != 0xfe || id[3] != 0xff) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "JEDEC ID not valid, 0x%02x%02x%02x%02x", + id[0], id[1], id[2], id[3]); + return FALSE; + } + + /* check eflash is writable */ + if (!fu_superio_it89_device_check_eflash (self, error)) + return FALSE; + + /* disable the mirroring of e-flash */ + if (g_getenv ("FWUPD_SUPERIO_DISABLE_MIRROR") != NULL) { + fw_fixed = fu_plugin_superio_fix_signature (self, fw, error); + if (fw_fixed == NULL) + return FALSE; + } else { + fw_fixed = g_bytes_ref (fw); + } + + /* chunks of 1kB, skipping the final chunk */ + chunks = fu_chunk_array_new_from_bytes (fw_fixed, 0x00, 0x00, 0x400); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len - 1; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + + /* try this many times; the failure-to-flash case leaves you + * without a keyboard and future boot may completely fail */ + for (guint j = 0;; j++) { + g_autoptr(GError) error_chk = NULL; + if (fu_superio_it89_device_write_chunk (self, chk, &error_chk)) + break; + if (j > 5) { + g_propagate_error (error, g_steal_pointer (&error_chk)); + return FALSE; + } + g_warning ("failure %u: %s", j, error_chk->message); + } + + /* set progress */ + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + /* success */ + fu_device_set_progress (device, 100); + return TRUE; +} + +static void +fu_superio_it89_device_init (FuSuperioIt89Device *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_ONLY_OFFLINE); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_NEEDS_REBOOT); +} + +static void +fu_superio_it89_device_class_init (FuSuperioIt89DeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuSuperioDeviceClass *klass_superio_device = FU_SUPERIO_DEVICE_CLASS (klass); + klass_device->attach = fu_superio_it89_device_attach; + klass_device->detach = fu_superio_it89_device_detach; + klass_device->read_firmware = fu_superio_it89_device_read_firmware; + klass_device->write_firmware = fu_superio_it89_device_write_firmware; + klass_superio_device->setup = fu_superio_it89_device_setup; +} diff -Nru fwupd-1.0.6/plugins/superio/fu-superio-it89-device.h fwupd-1.2.10/plugins/superio/fu-superio-it89-device.h --- fwupd-1.0.6/plugins/superio/fu-superio-it89-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/fu-superio-it89-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-superio-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SUPERIO_IT89_DEVICE (fu_superio_it89_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuSuperioIt89Device, fu_superio_it89_device, FU, SUPERIO_IT89_DEVICE, FuSuperioDevice) + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/superio/meson.build fwupd-1.2.10/plugins/superio/meson.build --- fwupd-1.0.6/plugins/superio/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,30 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginSuperio"'] + +install_data(['superio.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_superio', + fu_hash, + sources : [ + 'fu-plugin-superio.c', + 'fu-superio-device.c', + 'fu-superio-it85-device.c', + 'fu-superio-it89-device.c', + 'fu-superio-common.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff -Nru fwupd-1.0.6/plugins/superio/README.md fwupd-1.2.10/plugins/superio/README.md --- fwupd-1.0.6/plugins/superio/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,24 @@ +SuperIO +======= + +This plugin enumerates the various ITE85* SuperIO embedded controller ICs found +in many laptops. Vendors wanting to expose the SuperIO functionality will need +to add a HwId quirk entry to `superio.quirk`. + +See https://en.wikipedia.org/wiki/Super_I/O for more details about SuperIO +and what the EC actually does. + +Other useful links: + +* https://raw.githubusercontent.com/system76/ecflash/master/ec.py +* https://github.com/system76/firmware-update/tree/master/src +* https://github.com/coreboot/coreboot/blob/master/util/superiotool/superiotool.h +* https://github.com/flashrom/flashrom/blob/master/it85spi.c +* http://wiki.laptop.org/go/Ec_specification + +GUID Generation +--------------- + +These devices use a custom GUID generated using the SuperIO chipset name: + + * `SuperIO-$(chipset)`, for example `SuperIO-IT8512` diff -Nru fwupd-1.0.6/plugins/superio/superio.quirk fwupd-1.2.10/plugins/superio/superio.quirk --- fwupd-1.0.6/plugins/superio/superio.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/superio/superio.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,49 @@ +# N13xWU +[HwId=992f1bc7-f8ee-567a-88dd-30e5158d72ed] +SuperioChipsets=IT8587 + +# W740SU +[HwId=f00d8c4e-dce2-51c3-89d6-6cbc5fc5cdbb] +SuperioChipsets=IT8587 + +# Star LabTop Mk3 +[HwId=3dc52d2c-9e9b-5ba5-b10d-9ba1eb11dacc] +SuperioChipsets=IT8987 +InstallDuration=20 + +# Star Lite Mk2 +[HwId=d1a64840-4307-58fb-a62c-de28a07c0151] +SuperioChipsets=IT8987 +InstallDuration=20 + +[SuperIO=IT8510] +Id=0x8510 +Port=0x2e + +[SuperIO=IT8511] +Id=0x8511 +Port=0x2e + +[SuperIO=IT8512] +Id=0x8512 +Port=0x2e + +[SuperIO=IT8513] +Id=0x8513 +Port=0x2e + +[SuperIO=IT8516] +Id=0x8516 +Port=0x2e + +[SuperIO=IT8518] +Id=0x8518 +Port=0x2e + +[SuperIO=IT8587] +Id=0x8587 +Port=0x2e + +[SuperIO=IT8987] +Id=0x8987 +Port=0x4e diff -Nru fwupd-1.0.6/plugins/synapticsmst/fu-plugin-synapticsmst.c fwupd-1.2.10/plugins/synapticsmst/fu-plugin-synapticsmst.c --- fwupd-1.0.6/plugins/synapticsmst/fu-plugin-synapticsmst.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/fu-plugin-synapticsmst.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,41 +1,43 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Mario Limonciello * Copyright (C) 2017 Peichen Huang * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include "synapticsmst-device.h" #include "synapticsmst-common.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" #define SYNAPTICS_FLASH_MODE_DELAY 3 +#define SYNAPTICS_UPDATE_ENUMERATE_TRIES 3 + +static gboolean +syanpticsmst_check_amdgpu_safe (GError **error) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_auto(GStrv) lines = NULL; -#define HWID_DELL_INC "85d38fda-fc0e-5c6f-808f-076984ae7978" + if (!g_file_get_contents ("/proc/modules", &buf, &bufsz, error)) + return FALSE; -struct FuPluginData { - gchar *dock_type; - gchar *system_type; -}; + lines = g_strsplit (buf, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix (lines[i], "amdgpu ")) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "amdgpu has known issues with synapticsmst"); + return FALSE; + } + } + + return TRUE; +} static gboolean synapticsmst_common_check_supported_system (FuPlugin *plugin, GError **error) @@ -46,16 +48,10 @@ return TRUE; } - /* tests for "Dell Inc." manufacturer string - * this isn't strictly a complete tests due to OEM rebranded - * systems being excluded, but should cover most cases */ - if (!fu_plugin_check_hwid (plugin, HWID_DELL_INC)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "MST firmware updating not supported by OEM"); + /* See https://github.com/hughsie/fwupd/issues/1121 for more details */ + if (!syanpticsmst_check_amdgpu_safe (error)) return FALSE; - } + if (!g_file_test (SYSFS_DRM_DP_AUX, G_FILE_TEST_IS_DIR)) { g_set_error (error, G_IO_ERROR, @@ -66,18 +62,99 @@ return TRUE; } +/* creates MST-$str-$BOARDID */ +static void +fu_plugin_synapticsmst_create_simple_guid (FuDevice *fu_device, + SynapticsMSTDevice *device, + const gchar *str) +{ + guint16 board_id = synapticsmst_device_get_board_id (device); + g_autofree gchar *devid = g_strdup_printf ("MST-%s-%u", str, board_id); + fu_device_add_instance_id (fu_device, devid); +} + +/* creates MST-$str-$chipid-$BOARDID */ +static void +fu_plugin_synapticsmst_create_complex_guid (FuDevice *fu_device, + SynapticsMSTDevice *device, + const gchar *device_kind) +{ + const gchar *chip_id_str = synapticsmst_device_get_chip_id_str (device); + g_autofree gchar *chip_id_down = g_ascii_strdown (chip_id_str, -1); + g_autofree gchar *tmp = g_strdup_printf ("%s-%s", device_kind, chip_id_down); + + fu_plugin_synapticsmst_create_simple_guid (fu_device, device, tmp); +} + +static gboolean +fu_plugin_synapticsmst_lookup_device (FuPlugin *plugin, + FuDevice *fu_device, + SynapticsMSTDevice *device, + GError **error) +{ + const gchar *board_str; + const gchar *guid_template; + guint16 board_id = synapticsmst_device_get_board_id (device); + const gchar *chip_id_str = synapticsmst_device_get_chip_id_str (device); + g_autofree gchar *group = NULL; + g_autofree gchar *name = NULL; + + /* GUIDs used only for test mode */ + if (g_getenv ("FWUPD_SYNAPTICSMST_FW_DIR") != NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_strdup_printf ("test-%s", chip_id_str); + fu_plugin_synapticsmst_create_simple_guid (fu_device, device, tmp); + return TRUE; + } + + /* set up the device name via quirks */ + group = g_strdup_printf ("SynapticsMSTBoardID=%u", board_id); + board_str = fu_plugin_lookup_quirk_by_id (plugin, group, + FU_QUIRKS_NAME); + if (board_str == NULL) + board_str = "Unknown Platform"; + name = g_strdup_printf ("Synaptics %s inside %s", synapticsmst_device_get_chip_id_str (device), + board_str); + fu_device_set_name (fu_device, name); + + /* build the GUIDs for the device */ + guid_template = fu_plugin_lookup_quirk_by_id (plugin, group, "DeviceKind"); + /* no quirks defined for this board */ + if (guid_template == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Unknown board_id %x", + board_id); + return FALSE; + + /* this is a host system, use system ID */ + } else if (g_strcmp0 (guid_template, "system") == 0) { + const gchar *system_type = fu_plugin_get_dmi_value (plugin, + FU_HWIDS_KEY_PRODUCT_SKU); + fu_plugin_synapticsmst_create_simple_guid (fu_device, device, + system_type); + /* docks or something else */ + } else { + g_auto(GStrv) templates = NULL; + templates = g_strsplit (guid_template, ",", -1); + for (guint i = 0; templates[i] != NULL; i++) { + fu_plugin_synapticsmst_create_complex_guid (fu_device, + device, + templates[i]); + } + } + + return TRUE; +} + static gboolean fu_plugin_synaptics_add_device (FuPlugin *plugin, SynapticsMSTDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(FuDevice) dev = NULL; const gchar *kind_str = NULL; - const gchar *board_str = NULL; - const gchar *guid_str = NULL; - g_autofree gchar *name = NULL; g_autofree gchar *dev_id_str = NULL; g_autofree gchar *layer_str = NULL; g_autofree gchar *rad_str = NULL; @@ -87,61 +164,46 @@ aux_node = synapticsmst_device_get_aux_node (device); if (!synapticsmst_device_enumerate_device (device, - data->dock_type, - data->system_type, error)) { - g_debug ("error enumerating device at %s", aux_node); + g_prefix_error (error, "Error enumerating device at %s: ", aux_node); return FALSE; } + /* create the device */ + dev = fu_device_new (); + /* Store $KIND-$AUXNODE-$LAYER-$RAD as device ID */ layer = synapticsmst_device_get_layer (device); rad = synapticsmst_device_get_rad (device); - board_str = synapticsmst_device_board_id_to_string (synapticsmst_device_get_board_id (device)); - name = g_strdup_printf ("Synaptics %s inside %s", synapticsmst_device_get_chip_id (device), - board_str); - guid_str = synapticsmst_device_get_guid (device); - if (guid_str == NULL) { - g_debug ("invalid GUID for board ID %x", - synapticsmst_device_get_board_id(device)); - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Invalid device"); - return FALSE; - } - /* Store $KIND-$AUXNODE-$LAYER-$RAD as device ID */ kind_str = synapticsmst_device_kind_to_string (synapticsmst_device_get_kind (device)); dev_id_str = g_strdup_printf ("MST-%s-%s-%u-%u", kind_str, aux_node, layer, rad); - layer_str = g_strdup_printf ("%u", layer); - rad_str = g_strdup_printf ("%u", rad); - - if (board_str == NULL) { - g_debug ("invalid board ID (%x)", synapticsmst_device_get_board_id (device)); - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Invalid device"); - return FALSE; - } - - /* create the device */ - dev = fu_device_new (); fu_device_set_id (dev, dev_id_str); + fu_device_set_physical_id (dev, aux_node); fu_device_set_metadata (dev, "SynapticsMSTKind", kind_str); fu_device_set_metadata (dev, "SynapticsMSTAuxNode", aux_node); + layer_str = g_strdup_printf ("%u", layer); fu_device_set_metadata (dev, "SynapticsMSTLayer", layer_str); + rad_str = g_strdup_printf ("%u", rad); fu_device_set_metadata (dev, "SynapticsMSTRad", rad_str); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_set_name (dev, name); fu_device_set_vendor (dev, "Synaptics"); fu_device_set_summary (dev, "Multi-Stream Transport Device"); fu_device_add_icon (dev, "computer"); - fu_device_set_version (dev, synapticsmst_device_get_version (device)); - fu_device_add_guid (dev, guid_str); + fu_device_set_version (dev, synapticsmst_device_get_version (device), + FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); + /* create GUIDs and name */ + if (!fu_plugin_synapticsmst_lookup_device (plugin, dev, device, error)) + return FALSE; + if (!fu_device_setup (dev, error)) + return FALSE; fu_plugin_device_add (plugin, dev); fu_plugin_cache_add (plugin, dev_id_str, dev); + + /* inhibit the idle sleep of the daemon */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, + "SynapticsMST can cause the screen to flash when probing"); return TRUE; } @@ -151,7 +213,6 @@ GError **error) { g_autoptr(SynapticsMSTDevice) cascade_device = NULL; - g_autofree gchar *dev_id_str = NULL; FuDevice *fu_dev = NULL; const gchar *aux_node; @@ -166,6 +227,7 @@ for (guint8 j = 0; j < 2; j++) { guint8 layer = synapticsmst_device_get_layer (device) + 1; guint16 rad = synapticsmst_device_get_rad (device) | (j << (2 * (layer - 1))); + g_autofree gchar *dev_id_str = NULL; dev_id_str = g_strdup_printf ("MST-REMOTE-%s-%u-%u", aux_node, layer, rad); fu_dev = fu_plugin_cache_lookup (plugin, dev_id_str); @@ -212,11 +274,11 @@ static void fu_plugin_synapticsmst_remove_cascaded (FuPlugin *plugin, const gchar *aux_node) { - g_autofree gchar *dev_id_str = NULL; FuDevice *fu_dev = NULL; - for (guint8 i=0; i < 8; i++) { - for (guint16 j=0; j < 256; j++) { + for (guint8 i = 0; i < 8; i++) { + for (guint16 j = 0; j < 256; j++) { + g_autofree gchar *dev_id_str = NULL; dev_id_str = g_strdup_printf ("MST-REMOTE-%s-%u-%u", aux_node, i, j); fu_dev = fu_plugin_cache_lookup (plugin, dev_id_str); @@ -237,7 +299,6 @@ g_autoptr(GDir) dir = NULL; const gchar *dp_aux_dir; const gchar *aux_node = NULL; - g_autofree gchar *dev_id_str = NULL; dp_aux_dir = g_getenv ("FWUPD_SYNAPTICSMST_FW_DIR"); if (dp_aux_dir == NULL) @@ -246,6 +307,7 @@ g_debug ("Using %s to look for MST devices", dp_aux_dir); dir = g_dir_open (dp_aux_dir, 0, NULL); do { + g_autofree gchar *dev_id_str = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(SynapticsMSTDevice) device = NULL; FuDevice *fu_dev = NULL; @@ -257,9 +319,9 @@ dev_id_str = g_strdup_printf ("MST-DIRECT-%s-0-0", aux_node); fu_dev = fu_plugin_cache_lookup (plugin, dev_id_str); - /* If we open succesfully a device exists here */ + /* If we open successfully a device exists here */ device = synapticsmst_device_new (SYNAPTICSMST_DEVICE_KIND_DIRECT, aux_node, 0, 0); - if (!synapticsmst_device_open (device, NULL)) { + if (!synapticsmst_device_open (device, &error_local)) { /* No device exists here, but was there - remove from DB */ if (fu_dev != NULL) { g_debug ("Removing devices on %s", aux_node); @@ -269,7 +331,8 @@ aux_node); } else { /* Nothing to see here - move on*/ - g_debug ("No device found on %s", aux_node); + g_debug ("No device found on %s: %s", aux_node, error_local->message); + g_clear_error (&error_local); } continue; } @@ -278,7 +341,7 @@ if (fu_dev == NULL) { g_debug ("Adding direct device %s", dev_id_str); if (!fu_plugin_synaptics_add_device (plugin, device, &error_local)) - g_warning ("failed to add device: %s", error_local->message); + g_debug ("failed to add device: %s", error_local->message); } else { g_debug ("Skipping previously added device %s", dev_id_str); } @@ -304,12 +367,13 @@ FwupdInstallFlags flags, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(SynapticsMSTDevice) device = NULL; SynapticsMSTDeviceKind kind; const gchar *aux_node; guint8 layer; guint8 rad; + gboolean reboot; + gboolean install_force; /* extract details to build a new device */ kind = synapticsmst_device_kind_from_string (fu_device_get_metadata (dev, "SynapticsMSTKind")); @@ -326,67 +390,96 @@ device = synapticsmst_device_new (kind, aux_node, layer, rad); - if (!synapticsmst_device_enumerate_device (device, data->dock_type, - data->system_type, error)) + if (!synapticsmst_device_enumerate_device (device, error)) return FALSE; - if (synapticsmst_device_board_id_to_string (synapticsmst_device_get_board_id (device)) != NULL) { - fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); - if (!synapticsmst_device_write_firmware (device, blob_fw, - fu_synapticsmst_write_progress_cb, - dev, - error)) { - g_prefix_error (error, "failed to flash firmware: "); - return FALSE; - } - } else { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Unknown device"); + reboot = !fu_device_has_custom_flag (dev, "skip-restart"); + install_force = (flags & FWUPD_INSTALL_FLAG_FORCE) != 0 || + fu_device_has_custom_flag (dev, "ignore-board-id"); + fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); + if (!synapticsmst_device_write_firmware (device, blob_fw, + fu_synapticsmst_write_progress_cb, + dev, + reboot, + install_force, + error)) { + g_prefix_error (error, "failed to flash firmware: "); return FALSE; } + if (!reboot) { + g_debug ("Skipping device restart per quirk request"); + return TRUE; + } + /* Re-run device enumeration to find the new device version */ fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); - if (!synapticsmst_device_enumerate_device (device, data->dock_type, - data->system_type, error)) { - return FALSE; + for (guint i = 1; i <= SYNAPTICS_UPDATE_ENUMERATE_TRIES; i++) { + g_autoptr(GError) error_local = NULL; + g_usleep (SYNAPTICS_FLASH_MODE_DELAY * 1000000); + if (!synapticsmst_device_enumerate_device (device, + &error_local)) { + g_warning ("Unable to find device after %u seconds: %s", + SYNAPTICS_FLASH_MODE_DELAY * i, + error_local->message); + if (i == SYNAPTICS_UPDATE_ENUMERATE_TRIES) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s", + error_local->message); + return FALSE; + } + } } - fu_device_set_version (dev, synapticsmst_device_get_version (device)); + fu_device_set_version (dev, synapticsmst_device_get_version (device), + FWUPD_VERSION_FORMAT_TRIPLET); return TRUE; } -void -fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +gboolean +fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *tmp; - - /* dell plugin */ - if (g_strcmp0 (fu_device_get_plugin (device), "dell") == 0) { - /* only look at external devices from dell plugin */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) - return; - - tmp = fu_device_get_metadata (device, - FU_DEVICE_METADATA_DELL_DOCK_TYPE); + const gchar *aux_node; + const gchar *kind_str; + const gchar *layer_str; + const gchar *rad_str; + g_autofree gchar *dev_id_str = NULL; - if (tmp) - data->dock_type = g_strdup (tmp); + aux_node = fu_device_get_metadata (device, "SynapticsMSTAuxNode"); + if (aux_node == NULL) + return TRUE; + kind_str = fu_device_get_metadata (device, "SynapticsMSTKind"); + if (kind_str == NULL) + return TRUE; + layer_str = fu_device_get_metadata (device, "SynapticsMSTLayer"); + if (layer_str == NULL) + return TRUE; + rad_str = fu_device_get_metadata (device, "SynapticsMSTRad"); + if (rad_str == NULL) + return TRUE; + dev_id_str = g_strdup_printf ("MST-%s-%s-%s-%s", + kind_str, aux_node, layer_str, rad_str); + if (fu_plugin_cache_lookup (plugin, dev_id_str) != NULL) { + g_debug ("Removing %s from cache", dev_id_str); + fu_plugin_cache_remove (plugin, dev_id_str); + } else { + g_debug ("%s constructed but not found in cache", dev_id_str); } + return TRUE; } static gboolean fu_plugin_synapticsmst_coldplug (FuPlugin *plugin, GError **error) { + g_autoptr(GError) error_local = NULL; /* verify that this is a supported system */ if (!synapticsmst_common_check_supported_system (plugin, error)) return FALSE; /* look for host devices or already plugged in dock devices */ - if (!fu_plugin_synapticsmst_enumerate (plugin, error)) - g_debug ("error enumerating"); + if (!fu_plugin_synapticsmst_enumerate (plugin, &error_local)) + g_debug ("error enumerating: %s", error_local->message); return TRUE; } @@ -402,24 +495,12 @@ return fu_plugin_synapticsmst_coldplug (plugin, error); } -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - - g_free(data->dock_type); - g_free(data->system_type); -} void fu_plugin_init (FuPlugin *plugin) { - FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - - data->system_type = - g_strdup (fu_plugin_get_dmi_value (plugin, - FU_HWIDS_KEY_PRODUCT_SKU)); - /* make sure dell is already coldplugged */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "dell"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.mst"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } diff -Nru fwupd-1.0.6/plugins/synapticsmst/fu-self-test.c fwupd-1.2.10/plugins/synapticsmst/fu-self-test.c --- fwupd-1.0.6/plugins/synapticsmst/fu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,28 +1,12 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Mario Limonciello * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include #include #include @@ -60,29 +44,32 @@ g_assert (ret); /* Test with no Synaptics MST devices */ - test_directory = "./tests/no_devices"; - if (g_file_test (test_directory, G_FILE_TEST_IS_DIR)) { - g_setenv ("FWUPD_SYNAPTICSMST_FW_DIR", test_directory, TRUE); - ret = fu_plugin_runner_coldplug (plugin, &error); - g_assert_no_error (error); - g_assert (ret); - } + test_directory = SOURCEDIR "/tests/no_devices"; + g_assert(g_file_test (test_directory, G_FILE_TEST_IS_DIR)); + + g_setenv ("FWUPD_SYNAPTICSMST_FW_DIR", test_directory, TRUE); + ret = fu_plugin_runner_coldplug (plugin, &error); + g_assert_no_error (error); + g_assert (ret); /* Emulate adding/removing a Dell TB16 dock */ - test_directory = "./tests/tb16_dock"; - if (g_file_test (test_directory, G_FILE_TEST_IS_DIR)) { - g_setenv ("FWUPD_SYNAPTICSMST_FW_DIR", test_directory, TRUE); - ret = fu_plugin_runner_coldplug (plugin, &error); - g_assert_no_error (error); - g_assert (ret); - - device_count = devices->len; - for (guint i = 0; i < device_count; i++) { - device = g_ptr_array_index (devices, i); - g_assert_cmpstr (fu_device_get_version (device), ==, "3.10.002"); - g_ptr_array_remove (devices, device); - fu_plugin_device_remove (plugin, device); - } + test_directory = SOURCEDIR "/tests/tb16_dock"; + + g_assert (g_file_test (test_directory, G_FILE_TEST_IS_DIR)); + + g_setenv ("FWUPD_SYNAPTICSMST_FW_DIR", test_directory, TRUE); + ret = fu_plugin_runner_coldplug (plugin, &error); + g_assert_no_error (error); + g_assert (ret); + + device_count = devices->len; + g_assert_cmpuint (device_count, ==, 2); + + for (guint i = 0; i < device_count; i++) { + device = g_ptr_array_index (devices, i); + g_assert_cmpstr (fu_device_get_version (device), ==, "3.10.002"); + g_ptr_array_remove (devices, device); + fu_plugin_device_remove (plugin, device); } g_ptr_array_unref (devices); } diff -Nru fwupd-1.0.6/plugins/synapticsmst/meson.build fwupd-1.2.10/plugins/synapticsmst/meson.build --- fwupd-1.0.6/plugins/synapticsmst/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,11 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginSynapticsMST"'] +install_data(['synapticsmst.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + shared_module('fu_plugin_synapticsmst', + fu_hash, sources : [ 'fu-plugin-synapticsmst.c', 'synapticsmst-common.c', @@ -14,48 +19,27 @@ install : true, install_dir: plugin_dir, c_args : [ - cargs, - '-DLOCALSTATEDIR="' + localstatedir + '"', - ], - dependencies : [ - plugin_deps, - efivar, - ], - # https://github.com/hughsie/fwupd/issues/207 - override_options : [ - 'werror=false', - ] -) - -executable( - 'synapticsmst-tool', - sources : [ - 'synapticsmst-tool.c', - 'synapticsmst-device.c', - 'synapticsmst-common.c', + cargs, ], - include_directories : [ - include_directories('../..'), - include_directories('../../src'), - include_directories('../../libfwupd'), + link_with : [ + libfwupdprivate, ], dependencies : [ plugin_deps, ], - c_args : cargs, - # https://github.com/hughsie/fwupd/issues/207 - override_options : [ - 'werror=false', - ] ) if get_option('tests') cargs += '-DFU_OFFLINE_DESTDIR="/tmp/fwupd-self-test"' cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' + cargs += '-DSOURCEDIR="' + meson.current_source_dir() + '"' e = executable( 'synapticsmst-self-test', + fu_hash, sources : [ 'fu-self-test.c', + 'synapticsmst-common.c', + 'synapticsmst-device.c', ], include_directories : [ include_directories('../..'), @@ -68,13 +52,12 @@ valgrind, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : [ cargs, - '-DLOCALSTATEDIR="/tmp/fwupd-self-test/var"', ], ) - test('synapticsmst-self-test', e) + test('synapticsmst-self-test', e, + env: ['FWUPD_LOCALSTATEDIR=/tmp/fwupd-self-test/var']) endif diff -Nru fwupd-1.0.6/plugins/synapticsmst/README.md fwupd-1.2.10/plugins/synapticsmst/README.md --- fwupd-1.0.6/plugins/synapticsmst/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -3,6 +3,26 @@ This plugin supports querying and flashing Synaptics MST hubs used in Dell systems and docks. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. + +This plugin supports the following protocol ID: + + * com.synaptics.mst + +GUID Generation +--------------- + +These devices use custom GUID values, e.g. + + * `MST-$(device_kind)-$(chip-ID)-$(board-ID)` + +Please refer to the plugin source for more details about how the GUID is +constructed for specific hardware. + ## Requirements ### (Kernel) DP Aux Interface Kernel 4.6 introduced an DRM DP Aux interface for manipulation of the registers @@ -41,18 +61,19 @@ ## Supported devices Not all Dell systems or accessories contain MST hubs. Here is a sample list of systems known to support them however: -1. Dell WD15 dock -2. Dell TB16 dock -3. Latitude E5570 -4. Latitude E5470 -5. Latitude E5270 -6. Latitude E7470 -7. Latitude E7270 -8. Latitude E7450 -9. Latitude E7250 -10. Latitude E5550 -11. Latitude E5450 -12. Latitude E5250 -13. Latitude Rugged 5414 -14. Latitude Rugged 7214 -15. Latitude Rugged 7414 + * Dell WD15 dock + * Dell TB16 dock + * Dell TB18DC + * Latitude E5570 + * Latitude E5470 + * Latitude E5270 + * Latitude E7470 + * Latitude E7270 + * Latitude E7450 + * Latitude E7250 + * Latitude E5550 + * Latitude E5450 + * Latitude E5250 + * Latitude Rugged 5414 + * Latitude Rugged 7214 + * Latitude Rugged 7414 diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst-common.c fwupd-1.2.10/plugins/synapticsmst/synapticsmst-common.c --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,38 +1,14 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Peichen Huang * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include #include "synapticsmst-common.h" -#include "synapticsmst-device.h" #define UNIT_SIZE 32 #define MAX_WAIT_TIME 3 /* unit : second */ @@ -44,30 +20,72 @@ guint8 rad; }; -guint8 +static gboolean synapticsmst_common_aux_node_read (SynapticsMSTConnection *connection, - gint offset, gint *buf, gint length) + guint32 offset, guint8 *buf, + gint length, GError **error) { - if (lseek (connection->fd, offset, SEEK_SET) != offset) - return DPCD_SEEK_FAIL; + if (lseek (connection->fd, offset, SEEK_SET) != offset) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to lseek"); + return FALSE; + } - if (read (connection->fd, buf, length) != length) - return DPCD_ACCESS_FAIL; + if (read (connection->fd, buf, length) != length) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to read"); + return FALSE; + } - return DPCD_SUCCESS; + return TRUE; } -static guint8 +static gboolean synapticsmst_common_aux_node_write (SynapticsMSTConnection *connection, - gint offset, const gint *buf, gint length) + guint32 offset, const guint8 *buf, + gint length, GError **error) { - if (lseek (connection->fd, offset, SEEK_SET) != offset) - return DPCD_SEEK_FAIL; + if (lseek (connection->fd, offset, SEEK_SET) != offset) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to lseek"); + return FALSE; + } - if (write (connection->fd, buf, length) != length) - return DPCD_ACCESS_FAIL; + if (write (connection->fd, buf, length) != length) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to write"); + return FALSE; + } + + return TRUE; +} - return DPCD_SUCCESS; +static gboolean +synapticsmst_common_bus_read (SynapticsMSTConnection *connection, + guint32 offset, + guint8 *buf, + guint32 length, GError **error) +{ + return synapticsmst_common_aux_node_read (connection, offset, buf, + length, error); +} + +static gboolean +synapticsmst_common_bus_write (SynapticsMSTConnection *connection, + guint32 offset, + const guint8 *buf, + guint32 length, GError **error) +{ + return synapticsmst_common_aux_node_write (connection, offset, buf, + length, error); } void @@ -87,61 +105,68 @@ return connection; } -guint8 -synapticsmst_common_read_dpcd (SynapticsMSTConnection *connection, - gint offset, gint *buf, gint length) +gboolean +synapticsmst_common_read (SynapticsMSTConnection *connection, + guint32 offset, guint8 *buf, + guint32 length, GError **error) { if (connection->layer && connection->remain_layer) { - guint8 rc, node; + guint8 node; + gboolean result; connection->remain_layer--; node = (connection->rad >> connection->remain_layer * 2) & 0x03; - rc = synapticsmst_common_rc_get_command (connection, - UPDC_READ_FROM_TX_DPCD + node, - length, offset, (guint8 *)buf); + result = synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_TX_DPCD + node, + length, offset, (guint8 *)buf, + error); connection->remain_layer++; - return rc; + return result; } - return synapticsmst_common_aux_node_read (connection, offset, buf, length); + + return synapticsmst_common_bus_read (connection, offset, buf, length, error); } -guint8 -synapticsmst_common_write_dpcd (SynapticsMSTConnection *connection, - gint offset, - const gint *buf, - gint length) +gboolean +synapticsmst_common_write (SynapticsMSTConnection *connection, + guint32 offset, + const guint8 *buf, + guint32 length, GError **error) { if (connection->layer && connection->remain_layer) { - guint8 rc, node; + guint8 node; + gboolean result; connection->remain_layer--; node = (connection->rad >> connection->remain_layer * 2) & 0x03; - rc = synapticsmst_common_rc_set_command (connection, - UPDC_WRITE_TO_TX_DPCD + node, - length, offset, (guint8 *)buf); + result = synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_TX_DPCD + node, + length, offset, (guint8 *)buf, + error); connection->remain_layer++; - return rc; + return result; } - return synapticsmst_common_aux_node_write (connection, offset, buf, length); + + return synapticsmst_common_bus_write (connection, offset, buf, length, error); } -guint8 +gboolean synapticsmst_common_rc_set_command (SynapticsMSTConnection *connection, - gint rc_cmd, - gint length, - gint offset, - const guint8 *buf) -{ - guint8 rc = 0; - gint cur_offset = offset; - gint cur_length; + guint32 rc_cmd, + guint32 length, + guint32 offset, + const guint8 *buf, + GError **error) +{ + guint32 cur_offset = offset; + guint32 cur_length; gint data_left = length; gint cmd; gint readData = 0; long deadline; struct timespec t_spec; - do{ + do { if (data_left > UNIT_SIZE) { cur_length = UNIT_SIZE; } else { @@ -150,52 +175,73 @@ if (cur_length) { /* write data */ - rc = synapticsmst_common_write_dpcd (connection, REG_RC_DATA, (gint *)buf, cur_length); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_DATA, + buf, cur_length, + error)) { + g_prefix_error (error, "failure writing data register: "); + return FALSE; + } /* write offset */ - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_OFFSET, - &cur_offset, 4); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_OFFSET, + (guint8 *)&cur_offset, 4, + error)) { + g_prefix_error (error, "failure writing offset register: "); + return FALSE; + } /* write length */ - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_LEN, - &cur_length, 4); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_LEN, + (guint8 *)&cur_length, 4, + error)) { + g_prefix_error (error, "failure writing length register: "); + return FALSE; + } } /* send command */ cmd = 0x80 | rc_cmd; - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_CMD, - &cmd, 1); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_CMD, + (guint8 *)&cmd, 1, + error)) { + g_prefix_error (error, "failed to write command: "); + return FALSE; + } /* wait command complete */ clock_gettime (CLOCK_REALTIME, &t_spec); deadline = t_spec.tv_sec + MAX_WAIT_TIME; do { - rc = synapticsmst_common_read_dpcd (connection, - REG_RC_CMD, - &readData, 2); + if (!synapticsmst_common_read (connection, + REG_RC_CMD, + (guint8 *)&readData, 2, + error)) { + g_prefix_error (error, "failed to read command: "); + return FALSE; + } clock_gettime (CLOCK_REALTIME, &t_spec); if (t_spec.tv_sec > deadline) { - rc = -1; + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "timeout exceeded"); + return FALSE; } - } while (rc == 0 && readData & 0x80); + } while (readData & 0x80); + + if (readData & 0xFF00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "remote command failed: %d", + (readData >> 8) & 0xFF); - if (rc) - break; - else if (readData & 0xFF00) { - rc = (readData >> 8) & 0xFF; - break; + return FALSE; } buf += cur_length; @@ -203,22 +249,22 @@ data_left -= cur_length; } while (data_left); - return rc; + return TRUE; } -guint8 +gboolean synapticsmst_common_rc_get_command (SynapticsMSTConnection *connection, - gint rc_cmd, - gint length, - gint offset, - guint8 *buf) -{ - guint8 rc = 0; - gint cur_offset = offset; - gint cur_length; + guint32 rc_cmd, + guint32 length, + guint32 offset, + guint8 *buf, + GError **error) +{ + guint32 cur_offset = offset; + guint32 cur_length; gint data_need = length; - gint cmd; - gint readData = 0; + guint32 cmd; + guint32 readData = 0; long deadline; struct timespec t_spec; @@ -231,56 +277,75 @@ if (cur_length) { /* write offset */ - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_OFFSET, - &cur_offset, 4); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_OFFSET, + (guint8 *)&cur_offset, 4, + error)) { + g_prefix_error (error, "failed to write offset: "); + return FALSE; + } /* write length */ - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_LEN, - &cur_length, 4); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_LEN, + (guint8 *)&cur_length, 4, + error)) { + g_prefix_error (error, "failed to write length: "); + return FALSE; + } } /* send command */ cmd = 0x80 | rc_cmd; - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_CMD, - &cmd, 1); - if (rc) - break; + if (!synapticsmst_common_write (connection, + REG_RC_CMD, + (guint8 *)&cmd, 1, + error)) { + g_prefix_error (error, "failed to write command: "); + return FALSE; + } /* wait command complete */ clock_gettime (CLOCK_REALTIME, &t_spec); deadline = t_spec.tv_sec + MAX_WAIT_TIME; do { - rc = synapticsmst_common_read_dpcd (connection, - REG_RC_CMD, - &readData, 2); + if (!synapticsmst_common_read (connection, + REG_RC_CMD, + (guint8 *)&readData, 2, + error)) { + g_prefix_error (error, "failed to read command: "); + return FALSE; + } clock_gettime (CLOCK_REALTIME, &t_spec); if (t_spec.tv_sec > deadline) { - rc = -1; + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "timeout exceeded"); + return FALSE; } - } while (rc == 0 && readData & 0x80); + } while (readData & 0x80); + + if (readData & 0xFF00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "remote command failed: %u", + (readData >> 8) & 0xFF); - if (rc) - break; - else if (readData & 0xFF00) { - rc = (readData >> 8) & 0xFF; - break; + return FALSE; } if (cur_length) { - rc = synapticsmst_common_read_dpcd (connection, - REG_RC_DATA, - (gint *)buf, - cur_length); - if (rc) - break; + if (!synapticsmst_common_read (connection, + REG_RC_DATA, + buf, + cur_length, + error)) { + g_prefix_error (error, "failed to read data: "); + return FALSE; + } } buf += cur_length; @@ -288,117 +353,159 @@ data_need -= cur_length; } - return rc; + return TRUE; } -guint8 +gboolean synapticsmst_common_rc_special_get_command (SynapticsMSTConnection *connection, - gint rc_cmd, - gint cmd_length, - gint cmd_offset, + guint32 rc_cmd, + guint32 cmd_length, + guint32 cmd_offset, guint8 *cmd_data, - gint length, - guint8 *buf) + guint32 length, + guint8 *buf, + GError **error) { - guint8 rc = 0; - gint readData = 0; - gint cmd; + guint32 readData = 0; + guint32 cmd; long deadline; struct timespec t_spec; if (cmd_length) { /* write cmd data */ if (cmd_data != NULL) { - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_DATA, - (gint *)cmd_data, - cmd_length); - if (rc) - return rc; + if (!synapticsmst_common_write (connection, + REG_RC_DATA, + cmd_data, + cmd_length, + error)) { + g_prefix_error (error, "Failed to write command data: "); + return FALSE; + } } /* write offset */ - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_OFFSET, - &cmd_offset, 4); - if (rc) - return rc; + if (!synapticsmst_common_write (connection, + REG_RC_OFFSET, + (guint8 *)&cmd_offset, 4, + error)) { + g_prefix_error (error, "failed to write offset: "); + return FALSE; + } /* write length */ - rc = synapticsmst_common_write_dpcd (connection, - REG_RC_LEN, - &cmd_length, 4); - if (rc) - return rc; + if (!synapticsmst_common_write (connection, + REG_RC_LEN, + (guint8 *)&cmd_length, 4, + error)) { + g_prefix_error (error, "failed to write length: "); + return FALSE; + } } /* send command */ cmd = 0x80 | rc_cmd; - rc = synapticsmst_common_write_dpcd (connection, REG_RC_CMD, &cmd, 1); - if (rc) - return rc; + if (!synapticsmst_common_write (connection, + REG_RC_CMD, + (guint8 *)&cmd, 1, + error)) { + g_prefix_error (error, "failed to write command: "); + return FALSE; + } /* wait command complete */ clock_gettime (CLOCK_REALTIME, &t_spec); deadline = t_spec.tv_sec + MAX_WAIT_TIME; do { - rc = synapticsmst_common_read_dpcd (connection, - REG_RC_CMD, - &readData, 2); + if (!synapticsmst_common_read (connection, + REG_RC_CMD, + (guint8 *)&readData, 2, + error)) { + g_prefix_error (error, "failed to read command: "); + return FALSE; + } clock_gettime (CLOCK_REALTIME, &t_spec); - if (t_spec.tv_sec > deadline) - return -1; + if (t_spec.tv_sec > deadline) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "timeout exceeded"); + return FALSE; + + } } while (readData & 0x80); - if (rc) - return rc; - else if (readData & 0xFF00) { - rc = (readData >> 8) & 0xFF; - return rc; + if (readData & 0xFF00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "remote command failed: %u", + (readData >> 8) & 0xFF); + + return FALSE; } if (length) { - rc = synapticsmst_common_read_dpcd (connection, - REG_RC_DATA, - (gint *)buf, length); - if (rc) - return rc; + if (!synapticsmst_common_read (connection, + REG_RC_DATA, + buf, length, + error)) { + g_prefix_error (error, "failed to read length: "); + } } - return rc; + return TRUE; } -guint8 -synapticsmst_common_enable_remote_control (SynapticsMSTConnection *connection) +gboolean +synapticsmst_common_enable_remote_control (SynapticsMSTConnection *connection, + GError **error) { const gchar *sc = "PRIUS"; - guint8 rc = 0; for (gint i = 0; i <= connection->layer; i++) { - g_autoptr(SynapticsMSTConnection) connection_tmp = NULL; - connection_tmp = synapticsmst_common_new (connection->fd, i, connection->rad); - rc = synapticsmst_common_rc_set_command (connection_tmp, + g_autoptr(SynapticsMSTConnection) connection_tmp = synapticsmst_common_new (connection->fd, i, connection->rad); + g_autoptr(GError) error_local = NULL; + if (!synapticsmst_common_rc_set_command (connection_tmp, UPDC_ENABLE_RC, - 5, 0, (guint8*)sc); - if (rc) - break; + 5, 0, (guint8*)sc, + &error_local)) { + g_debug ("Failed to enable remote control in layer %d: %s, retrying", + i, error_local->message); + + if (!synapticsmst_common_disable_remote_control (connection_tmp, error)) + return FALSE; + if (!synapticsmst_common_rc_set_command (connection_tmp, + UPDC_ENABLE_RC, + 5, 0, (guint8*)sc, + error)) { + g_prefix_error (error, + "failed to enable remote control in layer %d: ", + i); + return FALSE; + } + } } - return rc; + + return TRUE; } -guint8 -synapticsmst_common_disable_remote_control (SynapticsMSTConnection *connection) +gboolean +synapticsmst_common_disable_remote_control (SynapticsMSTConnection *connection, + GError **error) { - guint8 rc = 0; - for (gint i = connection->layer; i >= 0; i--) { - g_autoptr(SynapticsMSTConnection) connection_tmp = NULL; - connection_tmp = synapticsmst_common_new (connection->fd, i, connection->rad); - rc = synapticsmst_common_rc_set_command (connection_tmp, + g_autoptr(SynapticsMSTConnection) connection_tmp = synapticsmst_common_new (connection->fd, i, connection->rad); + if (!synapticsmst_common_rc_set_command (connection_tmp, UPDC_DISABLE_RC, - 0, 0, NULL); - if (rc) - break; + 0, 0, NULL, + error)) { + g_prefix_error (error, + "failed to disable remote control in layer %d: ", + i); + return FALSE; + } } - return rc; + + return TRUE; } diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst-common.h fwupd-1.2.10/plugins/synapticsmst/synapticsmst-common.h --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Peichen Huang * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __SYNAPTICSMST_COMMON_H -#define __SYNAPTICSMST_COMMON_H +#pragma once #include #include @@ -29,6 +13,9 @@ #define ADDR_CUSTOMER_ID 0X10E #define ADDR_BOARD_ID 0x10F +#define ADDR_MEMORY_CUSTOMER_ID 0x170E +#define ADDR_MEMORY_BOARD_ID 0x170F + #define REG_RC_CAP 0x4B0 #define REG_RC_STATE 0X4B1 #define REG_RC_CMD 0x4B2 @@ -42,12 +29,6 @@ #define REG_FIRMWARE_VERSION 0x50A typedef enum { - DPCD_SUCCESS = 0, - DPCD_SEEK_FAIL, - DPCD_ACCESS_FAIL, -} SynapticsMstDpcdRc; - -typedef enum { UPDC_COMMAND_SUCCESS = 0, UPDC_COMMAND_INVALID, UPDC_COMMAND_UNSUPPORT, @@ -56,18 +37,20 @@ } SynapticsMstUpdcRc; typedef enum { - UPDC_ENABLE_RC = 1, - UPDC_DISABLE_RC, - UPDC_GET_ID, - UPDC_GET_VERSION, - UPDC_ENABLE_FLASH_CHIP_ERASE = 8, - UPDC_CAL_EEPROM_CHECKSUM = 0X11, - UPDC_FLASH_ERASE = 0X14, - UPDC_CAL_EEPROM_CHECK_CRC8 = 0X16, - UPDC_CAL_EEPROM_CHECK_CRC16, + UPDC_ENABLE_RC = 0x01, + UPDC_DISABLE_RC = 0x02, + UPDC_GET_ID = 0x03, + UPDC_GET_VERSION = 0x04, + UPDC_ENABLE_FLASH_CHIP_ERASE = 0x08, + UPDC_CAL_EEPROM_CHECKSUM = 0x11, + UPDC_FLASH_ERASE = 0x14, + UPDC_CAL_EEPROM_CHECK_CRC8 = 0x16, + UPDC_CAL_EEPROM_CHECK_CRC16 = 0x17, UPDC_WRITE_TO_EEPROM = 0X20, + UPDC_WRITE_TO_MEMORY = 0x21, UPDC_WRITE_TO_TX_DPCD = 0x22, UPDC_READ_FROM_EEPROM = 0x30, + UPDC_READ_FROM_MEMORY = 0x31, UPDC_READ_FROM_TX_DPCD = 0x32, } SynapticsMstUpdcCmd; @@ -79,45 +62,48 @@ guint8 layer, guint rad); -guint8 synapticsmst_common_aux_node_read (SynapticsMSTConnection *connection, - gint offset, - gint *buf, - gint length); - -guint8 synapticsmst_common_read_dpcd (SynapticsMSTConnection *connection, - gint offset, - gint *buf, - gint length); - -guint8 synapticsmst_common_write_dpcd (SynapticsMSTConnection *connection, - gint offset, - const gint *buf, - gint length); - -guint8 synapticsmst_common_rc_set_command (SynapticsMSTConnection *connection, - gint rc_cmd, - gint length, - gint offset, - const guint8 *buf); - -guint8 synapticsmst_common_rc_get_command (SynapticsMSTConnection *connection, - gint rc_cmd, - gint length, - gint offset, - guint8 *buf); - -guint8 synapticsmst_common_rc_special_get_command (SynapticsMSTConnection *connection, - gint rc_cmd, - gint cmd_length, - gint cmd_offset, - guint8 *cmd_data, - gint length, - guint8 *buf); - -guint8 synapticsmst_common_enable_remote_control (SynapticsMSTConnection *connection); - -guint8 synapticsmst_common_disable_remote_control (SynapticsMSTConnection *connection); - +gboolean synapticsmst_common_read (SynapticsMSTConnection *connection, + guint32 offset, + guint8 *buf, + guint32 length, + GError **error); + +gboolean synapticsmst_common_write (SynapticsMSTConnection *connection, + guint32 offset, + const guint8 *buf, + guint32 length, + GError **error); + +gboolean synapticsmst_common_rc_set_command (SynapticsMSTConnection *connection, + guint32 rc_cmd, + guint32 length, + guint32 offset, + const guint8 *buf, + GError **error); + + +gboolean synapticsmst_common_rc_get_command (SynapticsMSTConnection *connection, + guint32 rc_cmd, + guint32 length, + guint32 offset, + guint8 *buf, + GError **error); + +gboolean synapticsmst_common_rc_special_get_command (SynapticsMSTConnection *connection, + guint32 rc_cmd, + guint32 cmd_length, + guint32 cmd_offset, + guint8 *cmd_data, + guint32 length, + guint8 *buf, + GError **error); + +gboolean synapticsmst_common_enable_remote_control (SynapticsMSTConnection *connection, + GError **error); + +gboolean synapticsmst_common_disable_remote_control (SynapticsMSTConnection *connection, + GError **error); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(SynapticsMSTConnection, synapticsmst_common_free) - -#endif /* __SYNAPTICSMST_COMMON_H */ +#pragma clang diagnostic pop diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst-device.c fwupd-1.2.10/plugins/synapticsmst/synapticsmst-device.c --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,50 +1,59 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Peichen Huang + * Copyright (C) 2018 Ryan Chang * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include -#include -#include -#include + +#include "fu-device-locker.h" #include "synapticsmst-device.h" #include "synapticsmst-common.h" -#define BLOCK_UNIT 64 +#include +#include +#include + +#define BIT( n ) ( 1 << (n) ) +#define FLASH_SECTOR_ERASE_4K 0x1000 +#define FLASH_SECTOR_ERASE_32K 0x2000 +#define FLASH_SECTOR_ERASE_64K 0x3000 +#define EEPROM_TAG_OFFSET 0x1FFF0 +#define EEPROM_BANK_OFFSET 0x20000 +#define EEPROM_ESM_OFFSET 0x40000 +#define ESM_CODE_SIZE 0x40000 +#define PAYLOAD_SIZE_512K 0x80000 +#define PAYLOAD_SIZE_64K 0x10000 +#define MAX_RETRY_COUNTS 10 +#define BLOCK_UNIT 64 +#define BANKTAG_0 0 +#define BANKTAG_1 1 +#define CRC_8 8 +#define CRC_16 16 +#define REG_ESM_DISABLE 0x2000fc +#define REG_QUAD_DISABLE 0x200fc0 +#define REG_HDCP22_DISABLE 0x200f90 + +#define FLASH_SETTLE_TIME 5000000 /* us */ typedef struct { SynapticsMSTDeviceKind kind; gchar *version; - SynapticsMSTDeviceBoardID board_id; - gchar *chip_id; - gchar *guid; + guint32 board_id; + guint16 chip_id; + gchar *chip_id_str; + GPtrArray *guids; gchar *aux_node; guint8 layer; guint16 rad; gint fd; - gboolean has_cascade; + gboolean has_cascade; gchar *fw_dir; - gboolean test_mode; + gboolean test_mode; } SynapticsMSTDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (SynapticsMSTDevice, synapticsmst_device, G_TYPE_OBJECT) @@ -71,31 +80,6 @@ return NULL; } -const gchar * -synapticsmst_device_board_id_to_string (SynapticsMSTDeviceBoardID board_id) -{ - if (board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_X6) - return "Dell X6 Platform"; - if (board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_X7) - return "Dell X7 Platform"; - if (board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_WD15_TB16_WIRE) - return "Dell WD15/TB16 wired Dock"; - if (board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_WLD15_WIRELESS) - return "Dell WLD15 Wireless Dock"; - if (board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_X7_RUGGED) - return "Dell Rugged Platform"; - if ((board_id & 0xFF00) == SYNAPTICSMST_DEVICE_BOARDID_EVB) - return "SYNA evb board"; - return "Unknown Platform"; -} - -const gchar * -synapticsmst_device_get_guid (SynapticsMSTDevice *device) -{ - SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); - return priv->guid; -} - static void synapticsmst_device_finalize (GObject *object) { @@ -108,8 +92,7 @@ g_free (priv->fw_dir); g_free (priv->aux_node); g_free (priv->version); - g_free (priv->chip_id); - g_free (priv->guid); + g_free (priv->chip_id_str); G_OBJECT_CLASS (synapticsmst_device_parent_class)->finalize (object); } @@ -118,11 +101,11 @@ { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); const gchar *tmp; - - priv->test_mode = FALSE; - priv->fw_dir = g_strdup ("/dev"); tmp = g_getenv ("FWUPD_SYNAPTICSMST_FW_DIR"); - if (tmp != NULL) { + if (tmp == NULL) { + priv->test_mode = FALSE; + priv->fw_dir = g_strdup ("/dev"); + } else { priv->test_mode = TRUE; priv->fw_dir = g_strdup (tmp); } @@ -142,7 +125,7 @@ return priv->kind; } -SynapticsMSTDeviceBoardID +guint16 synapticsmst_device_get_board_id (SynapticsMSTDevice *device) { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); @@ -174,24 +157,19 @@ if (priv->fd == -1) { g_set_error (error, G_IO_ERROR, - G_IO_ERROR_PERMISSION_DENIED, - "cannot open device %s", - filename); + g_io_error_from_errno (errno), + "cannot open device %s: %s", + filename, g_strerror (errno)); return FALSE; } return TRUE; } connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); - if (synapticsmst_common_enable_remote_control (connection)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to enable MST remote control"); + if (!synapticsmst_common_enable_remote_control (connection, error)) return FALSE; - } else { - return TRUE; - } + + return TRUE; } static gboolean @@ -228,28 +206,24 @@ } connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); - if (synapticsmst_common_disable_remote_control (connection)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to disable MST remote control"); + if (!synapticsmst_common_disable_remote_control (connection, error)) return FALSE; - } else { - return TRUE; - } + + return TRUE; } gboolean synapticsmst_device_scan_cascade_device (SynapticsMSTDevice *device, - GError ** error, + GError **error, guint8 tx_port) { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); guint8 layer = priv->layer + 1; guint16 rad = priv->rad | (tx_port << (2 * (priv->layer))); guint8 byte[4]; - guint8 rc; g_autoptr(SynapticsMSTConnection) connection = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; if (priv->test_mode) return TRUE; @@ -257,28 +231,28 @@ /* reset */ priv->has_cascade = FALSE; - if (!synapticsmst_device_enable_remote_control (device, error)) { - g_prefix_error (error, - "failed to scan cascade device on tx_port %d: ", - tx_port); + /* enable remote control and disable on exit */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) synapticsmst_device_enable_remote_control, + (FuDeviceLockerFunc) synapticsmst_device_disable_remote_control, + error); + if (locker == NULL) return FALSE; - } connection = synapticsmst_common_new (priv->fd, layer, rad); - rc = synapticsmst_common_read_dpcd (connection, REG_RC_CAP, (gint *)byte, 1); - if (rc == DPCD_SUCCESS ) { - if (byte[0] & 0x04) { - synapticsmst_common_read_dpcd (connection, REG_VENDOR_ID, (gint *)byte, 3); - if (byte[0] == 0x90 && byte[1] == 0xCC && byte[2] == 0x24) - priv->has_cascade = TRUE; - } + if (!synapticsmst_common_read (connection, REG_RC_CAP, byte, 1, &error_local)) { + g_debug ("No cascade device found: %s", error_local->message); + return TRUE; } - - if (!synapticsmst_device_disable_remote_control (device, error)) { - g_prefix_error (error, - "failed to scan cascade device on tx_port %d: ", - tx_port); - return FALSE; + if (byte[0] & 0x04) { + if (!synapticsmst_common_read (connection, REG_VENDOR_ID, byte, 3, error)) { + g_prefix_error (error, + "failed to read cascade device on tx_port %d: ", + tx_port); + return FALSE; + } + if (byte[0] == 0x90 && byte[1] == 0xCC && byte[2] == 0x24) + priv->has_cascade = TRUE; } return TRUE; @@ -291,7 +265,6 @@ GError **error) { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); - guint8 rc; if (priv->test_mode) { g_autofree gchar *filename = NULL; @@ -327,111 +300,99 @@ } close (fd); } else { - rc = synapticsmst_common_rc_get_command (connection, - UPDC_READ_FROM_EEPROM, - 2, ADDR_CUSTOMER_ID, byte); - if (rc) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to read from EEPROM of device"); + /* get board ID via MCU address 0x170E instead of flash access due to HDCP2.2 running */ + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_MEMORY, + 2, + (gint)ADDR_MEMORY_CUSTOMER_ID, byte, + error)) { + g_prefix_error (error, "Memory query failed: "); return FALSE; } } + + return TRUE; +} + +static gboolean +synapticsmst_device_get_active_bank_panamera (SynapticsMSTDevice *device, + guint8 *bank_out, + GError **error) +{ + g_autoptr(SynapticsMSTConnection) connection = NULL; + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + guint32 dwData[16]; + + /* get used bank */ + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_MEMORY, + ((sizeof(dwData)/sizeof(dwData[0]))*4), + (gint) 0x20010c, (guint8*) dwData, + error)) { + g_prefix_error (error, "get active bank failed: "); + return FALSE; + } + if ((dwData[0] & BIT(7)) || (dwData[0] & BIT(30))) + *bank_out = BANKTAG_1; + else + *bank_out = BANKTAG_0; + + g_debug ("bank in use:%x", *bank_out); + return TRUE; } gboolean synapticsmst_device_enumerate_device (SynapticsMSTDevice *device, - const gchar *dock_type, - const gchar *system_type, GError **error) { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); guint8 byte[16]; - g_autofree gchar *system = NULL; - guint8 rc; + guint8 bank; g_autoptr(SynapticsMSTConnection) connection = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; - //FIXME? if (!synapticsmst_device_open (device, error)) { g_prefix_error (error, "Failed to open device in DP Aux Node %s: ", synapticsmst_device_get_aux_node (device)); return FALSE; } - /* enable remote control */ - if (!synapticsmst_device_enable_remote_control (device, error)) + /* enable remote control and disable on exit */ + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) synapticsmst_device_enable_remote_control, + (FuDeviceLockerFunc) synapticsmst_device_disable_remote_control, + error); + if (locker == NULL) return FALSE; /* read firmware version */ connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); - rc = synapticsmst_common_read_dpcd (connection, - REG_FIRMWARE_VERSION, - (gint *)byte, 3); - if (rc) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to read dpcd from device"); + if (!synapticsmst_common_read (connection, REG_FIRMWARE_VERSION, + byte, 3, error)) return FALSE; - } + priv->version = g_strdup_printf ("%1d.%02d.%03d", byte[0], byte[1], byte[2]); /* read board ID */ if (!synapticsmst_device_read_board_id (device, connection, byte, error)) return FALSE; priv->board_id = (byte[0] << 8) | (byte[1]); + g_debug ("BoardID %x", priv->board_id); /* read board chip_id */ - rc = synapticsmst_common_read_dpcd (connection, - REG_CHIP_ID, - (gint *)byte, 2); - if (rc) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to read dpcd from device"); + if (!synapticsmst_common_read (connection, REG_CHIP_ID, + byte, 2, error)) { + g_prefix_error (error, "failed to read chip id: "); return FALSE; } - priv->chip_id = g_strdup_printf ("VMM%02x%02x", byte[0], byte[1]); - - switch (priv->board_id >> 8) { - /* only dell is supported for today */ - case CUSTOMERID_DELL: - /* If this is a dock, use dock ID*/ - if (priv->test_mode) - system = g_strdup_printf ("test-%s", priv->chip_id); - else if (priv->board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_WD15_TB16_WIRE) { - system = g_strdup_printf ("%s-%s", dock_type, priv->chip_id); - system = g_ascii_strdown (system, -1); - } - else if (priv->board_id == SYNAPTICSMST_DEVICE_BOARDID_DELL_WLD15_WIRELESS) - system = g_strdup ("wld15"); - - /* This is a host system, use system ID */ - else - system = g_strdup (system_type); - - /* set up GUID - * GUID is MST-$SYSTEMID-$BOARDID - * $BOARDID includes CUSTOMERID in first byte, BOARD in second byte */ - if (system != NULL) - priv->guid = g_strdup_printf ("MST-%s-%u", system, - priv->board_id); - break; - /* EVB development board */ - case 0: - priv->board_id = (byte[0] << 8 | byte[1]); - break; - /* unknown */ - default: - g_warning ("Unknown board_id %x", priv->board_id); - priv->board_id = 0xFF; - } + priv->chip_id = (byte[0] << 8) | (byte[1]); + priv->chip_id_str = g_strdup_printf ("VMM%02x%02x", byte[0], byte[1]); - /* disable remote control */ - if (!synapticsmst_device_disable_remote_control (device, error)) + /* if running on panamera, check the active bank (for debugging logs) */ + if (priv->chip_id > 0x5000 && + !synapticsmst_device_get_active_bank_panamera (device, &bank, error)) return FALSE; return TRUE; @@ -451,13 +412,21 @@ return priv->version; } -const gchar * +static guint16 synapticsmst_device_get_chip_id (SynapticsMSTDevice *device) { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); return priv->chip_id; } +const gchar * +synapticsmst_device_get_chip_id_str (SynapticsMSTDevice *device) +{ + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + return priv->chip_id_str; +} + + guint16 synapticsmst_device_get_rad (SynapticsMSTDevice *device) { @@ -481,252 +450,762 @@ static gboolean synapticsmst_device_get_flash_checksum (SynapticsMSTDevice *device, - gint length, gint offset, + guint32 length, guint32 offset, guint32 *checksum, GError **error) { SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(SynapticsMSTConnection) connection = NULL; connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); - if (synapticsmst_common_rc_special_get_command (connection, + if (!synapticsmst_common_rc_special_get_command (connection, UPDC_CAL_EEPROM_CHECKSUM, length, offset, NULL, 4, - (guint8 *)checksum)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to get flash checksum"); + (guint8 *)checksum, + error)) { + g_prefix_error (error, "failed to get flash checksum: "); return FALSE; + } + + return TRUE; +} + +static guint16 +synapticsmst_device_get_crc (guint16 crc, guint8 type, guint32 length, const guint8 *payload_data) +{ + static const guint16 CRC16_table[] = { + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 + }; + static const guint16 CRC8_table[] = { + 0x00, 0xd5, 0x7f, 0xaa, 0xfe, 0x2b, 0x81, 0x54, 0x29, 0xfc, 0x56, 0x83, 0xd7, 0x02, 0xa8, 0x7d, + 0x52, 0x87, 0x2d, 0xf8, 0xac, 0x79, 0xd3, 0x06, 0x7b, 0xae, 0x04, 0xd1, 0x85, 0x50, 0xfa, 0x2f, + 0xa4, 0x71, 0xdb, 0x0e, 0x5a, 0x8f, 0x25, 0xf0, 0x8d, 0x58, 0xf2, 0x27, 0x73, 0xa6, 0x0c, 0xd9, + 0xf6, 0x23, 0x89, 0x5c, 0x08, 0xdd, 0x77, 0xa2, 0xdf, 0x0a, 0xa0, 0x75, 0x21, 0xf4, 0x5e, 0x8b, + 0x9d, 0x48, 0xe2, 0x37, 0x63, 0xb6, 0x1c, 0xc9, 0xb4, 0x61, 0xcb, 0x1e, 0x4a, 0x9f, 0x35, 0xe0, + 0xcf, 0x1a, 0xb0, 0x65, 0x31, 0xe4, 0x4e, 0x9b, 0xe6, 0x33, 0x99, 0x4c, 0x18, 0xcd, 0x67, 0xb2, + 0x39, 0xec, 0x46, 0x93, 0xc7, 0x12, 0xb8, 0x6d, 0x10, 0xc5, 0x6f, 0xba, 0xee, 0x3b, 0x91, 0x44, + 0x6b, 0xbe, 0x14, 0xc1, 0x95, 0x40, 0xea, 0x3f, 0x42, 0x97, 0x3d, 0xe8, 0xbc, 0x69, 0xc3, 0x16, + 0xef, 0x3a, 0x90, 0x45, 0x11, 0xc4, 0x6e, 0xbb, 0xc6, 0x13, 0xb9, 0x6c, 0x38, 0xed, 0x47, 0x92, + 0xbd, 0x68, 0xc2, 0x17, 0x43, 0x96, 0x3c, 0xe9, 0x94, 0x41, 0xeb, 0x3e, 0x6a, 0xbf, 0x15, 0xc0, + 0x4b, 0x9e, 0x34, 0xe1, 0xb5, 0x60, 0xca, 0x1f, 0x62, 0xb7, 0x1d, 0xc8, 0x9c, 0x49, 0xe3, 0x36, + 0x19, 0xcc, 0x66, 0xb3, 0xe7, 0x32, 0x98, 0x4d, 0x30, 0xe5, 0x4f, 0x9a, 0xce, 0x1b, 0xb1, 0x64, + 0x72, 0xa7, 0x0d, 0xd8, 0x8c, 0x59, 0xf3, 0x26, 0x5b, 0x8e, 0x24, 0xf1, 0xa5, 0x70, 0xda, 0x0f, + 0x20, 0xf5, 0x5f, 0x8a, 0xde, 0x0b, 0xa1, 0x74, 0x09, 0xdc, 0x76, 0xa3, 0xf7, 0x22, 0x88, 0x5d, + 0xd6, 0x03, 0xa9, 0x7c, 0x28, 0xfd, 0x57, 0x82, 0xff, 0x2a, 0x80, 0x55, 0x01, 0xd4, 0x7e, 0xab, + 0x84, 0x51, 0xfb, 0x2e, 0x7a, 0xaf, 0x05, 0xd0, 0xad, 0x78, 0xd2, 0x07, 0x53, 0x86, 0x2c, 0xf9 + }; + guint8 val; + guint16 remainder = (guint16) crc; + const guint8 *message = payload_data; + + if (type == CRC_8) { + for (guint32 byte = 0; byte < length; ++byte) { + val = (guint8)(message[byte] ^ remainder); + remainder = CRC8_table[val]; + } } else { - return TRUE; + for (guint32 byte = 0; byte < length; ++byte) { + val = (guint8)(message[byte] ^ (remainder >> 8)); + remainder = CRC16_table[val] ^ (remainder << 8); + } } + + return remainder; } -gboolean -synapticsmst_device_write_firmware (SynapticsMSTDevice *device, - GBytes *fw, - GFileProgressCallback progress_cb, - gpointer progress_data, - GError **error) +static gboolean +synapticsmst_device_set_flash_sector_erase (SynapticsMSTDevice *device, + guint16 rc_cmd, + guint16 offset, + GError **error) { - const guint8 *payload_data; - guint32 payload_len; - guint32 code_size = 0; + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + guint16 us_data; + g_autoptr(SynapticsMSTConnection) connection = NULL; + + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + /* Need to add Wp control ? */ + us_data = rc_cmd + offset; + + if (!synapticsmst_common_rc_set_command (connection, + UPDC_FLASH_ERASE, + 2, 0, (guint8 *)&us_data, + error)) { + g_prefix_error (error, "can't sector erase flash at offset %x", + offset); + return FALSE; + } + + return TRUE; +} + +static gboolean +synapticsmst_device_update_esm (SynapticsMSTDevice *device, + const guint8 *payload_data, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error) +{ + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); guint32 checksum = 0; + guint32 esm_sz = ESM_CODE_SIZE; guint32 flash_checksum = 0; - guint32 offset = 0; + guint32 unit_sz = BLOCK_UNIT; guint32 write_loops = 0; - guint32 data_to_write = 0; - guint8 percentage = 0; - guint8 rc = 0; - guint16 tmp; - guint16 erase_code = 0xFFFF; - SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); g_autoptr(SynapticsMSTConnection) connection = NULL; - /* get firmware data and check size */ - payload_data = g_bytes_get_data (fw, NULL); - payload_len = g_bytes_get_size (fw); - if (payload_len > 0x10000 || payload_len == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid file size"); + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + + for (guint32 i = 0; i < esm_sz; i++) + checksum += *(payload_data + EEPROM_ESM_OFFSET +i); + if (!synapticsmst_device_get_flash_checksum (device, + esm_sz, + EEPROM_ESM_OFFSET, + &flash_checksum, error)) { return FALSE; } - /* check firmware content */ - for (guint8 i = 0; i < 128; i++) - checksum += *(payload_data + i); + /* ESM checksum same */ + if (checksum == flash_checksum) { + g_debug ("ESM checksum already matches"); + return TRUE; + } + g_debug ("ESM checksum %x doesn't match expected %x", flash_checksum, checksum); - if (checksum & 0xFF) { - g_set_error_literal (error, + /* update ESM firmware */ + write_loops = esm_sz / unit_sz; + for (guint retries_cnt = 0; ; retries_cnt++) { + guint32 write_idx = 0; + guint32 write_offset = EEPROM_ESM_OFFSET; + const guint8 *esm_code_ptr = &payload_data[EEPROM_ESM_OFFSET]; + + /* erase ESM firmware; erase failure is fatal */ + for (guint32 j = 0; j < 4; j++) { + if (!synapticsmst_device_set_flash_sector_erase (device, + FLASH_SECTOR_ERASE_64K, + j + 4, + error)) { + g_prefix_error (error, "failed to erase sector %u: ", j); + return FALSE; + } + } + + g_debug ("Waiting for flash clear to settle"); + g_usleep (FLASH_SETTLE_TIME); + + /* write firmware */ + for (guint32 i = 0; i < write_loops; i++) { + g_autoptr(GError) error_local = NULL; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, + unit_sz, + write_offset, + esm_code_ptr + write_idx, + &error_local)) { + g_warning ("failed to write ESM: %s", error_local->message); + break; + } + write_offset += unit_sz; + write_idx += unit_sz; + if (progress_cb != NULL) { + progress_cb ((goffset) i * 100, + (goffset) (write_loops -1) * 100, + progress_data); + } + + } + + /* check ESM checksum */ + checksum = 0; + flash_checksum = 0; + for (guint32 i = 0; i < esm_sz; i++) + checksum += *(payload_data + EEPROM_ESM_OFFSET +i); + if (!synapticsmst_device_get_flash_checksum (device, + esm_sz, + EEPROM_ESM_OFFSET, + &flash_checksum, + error)) + return FALSE; + + /* ESM update done */ + if (checksum == flash_checksum) + break; + g_debug ("attempt %u: ESM checksum %x didn't match %x", retries_cnt, flash_checksum, checksum); + + /* abort */ + if (retries_cnt > MAX_RETRY_COUNTS) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "EDID checksum error"); - return FALSE; + "checksum did not match after %u tries", retries_cnt); + return FALSE; + } } + g_debug ("ESM successfully written"); - checksum = 0; - offset = 128; - for (guint8 i = 0; i < 128; i++) - checksum += *(payload_data + offset + i); + return TRUE; +} - if (checksum & 0xFF) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "EDID checksum error"); - return FALSE; +static gboolean +synapticsmst_device_update_tesla_leaf_firmware (SynapticsMSTDevice *device, + guint32 payload_len, + const guint8 *payload_data, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error) +{ + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + g_autoptr(SynapticsMSTConnection) connection = NULL; + guint32 data_to_write = 0; + guint32 offset = 0; + guint32 write_loops = 0; + + write_loops = (payload_len / BLOCK_UNIT); + data_to_write = payload_len; + + if (payload_len % BLOCK_UNIT) + write_loops++; + + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + for (guint32 retries_cnt = 0; ; retries_cnt++) { + guint32 checksum = 0; + guint32 flash_checksum = 0; + + if (!synapticsmst_device_set_flash_sector_erase (device, 0xffff, 0, error)) + return FALSE; + g_debug ("Waiting for flash clear to settle"); + g_usleep (FLASH_SETTLE_TIME); + + for (guint32 i = 0; i < write_loops; i++) { + g_autoptr(GError) error_local = NULL; + guint8 length = BLOCK_UNIT; + + if (data_to_write < BLOCK_UNIT) + length = data_to_write; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, + length, offset, + payload_data + offset, + &error_local)) { + g_warning ("Failed to write flash offset 0x%04x: %s, retrying", + offset, error_local->message); + /* repeat once */ + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, + length, offset, + payload_data + offset, + error)) { + g_prefix_error (error, "can't write flash offset 0x%04x: ", + offset); + return FALSE; + } + } + offset += length; + data_to_write -= length; + if (progress_cb != NULL) { + progress_cb ((goffset) i * 100, + (goffset) (write_loops -1) * 100, + progress_data); + } + } + + /* check data just written */ + for (guint32 i = 0; i < payload_len; i++) + checksum += *(payload_data + i); + + if (!synapticsmst_device_get_flash_checksum (device, + payload_len, + 0, + &flash_checksum, + error)) + return FALSE; + if (checksum == flash_checksum) + break; + g_debug ("attempt %u: checksum %x didn't match %x", retries_cnt, flash_checksum, checksum); + + if (retries_cnt > MAX_RETRY_COUNTS) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum %x mismatched %x", + flash_checksum, + checksum); + return FALSE; + } } - checksum = 0; - offset = 0x100; - for (guint16 i = 0; i < 256; i++) - checksum += *(payload_data + offset + i); + return TRUE; +} - if (checksum & 0xFF) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "configuration checksum error"); +static gboolean +synapticsmst_device_update_panamera_firmware (SynapticsMSTDevice *device, + guint32 payload_len, + const guint8 *payload_data, + GFileProgressCallback progress_cb, + gpointer progress_data, + GError **error) +{ + + guint16 crc_tmp = 0; + guint32 fw_size; + guint32 unit_sz = BLOCK_UNIT; + guint32 write_loops = 0; + guint8 bank_in_use; + guint8 bank_to_update = BANKTAG_1; + guint8 readBuf[256]; + guint8 tagData[16]; + struct tm *pTM; + time_t timeptr; + g_autoptr(SynapticsMSTConnection) connection = NULL; + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + + /* get used bank */ + if (!synapticsmst_device_get_active_bank_panamera (device, &bank_in_use, error)) return FALSE; + if (bank_in_use == BANKTAG_1) + bank_to_update = BANKTAG_0; + g_debug ("bank to update:%x", bank_to_update); + + /* get firmware size */ + fw_size = 0x410 + (*(payload_data + 0x400) << 24) + + (*(payload_data + 0x401) << 16) + + (*(payload_data + 0x402) << 8) + + (*(payload_data + 0x403)); + + /* Current max firmware size is 104K */ + if (fw_size < payload_len) + fw_size = 104 * 1024; + g_debug ("Calculated fw size as %u", fw_size); + + /* Update firmware */ + write_loops = fw_size / unit_sz; + if (fw_size % unit_sz) + write_loops++; + + for (guint32 retries_cnt = 0; ; retries_cnt++) { + guint32 checksum = 0; + guint32 erase_offset; + guint32 flash_checksum = 0; + guint32 write_idx; + guint32 write_offset; + + /* erase storage */ + erase_offset = bank_to_update * 2; + if (!synapticsmst_device_set_flash_sector_erase (device, + FLASH_SECTOR_ERASE_64K, erase_offset++, error)) + return FALSE; + if (!synapticsmst_device_set_flash_sector_erase (device, + FLASH_SECTOR_ERASE_64K, erase_offset, error)) + return FALSE; + g_debug ("Waiting for flash clear to settle"); + g_usleep (FLASH_SETTLE_TIME); + + /* write */ + write_idx = 0; + write_offset = EEPROM_BANK_OFFSET * bank_to_update; + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + for (guint32 i = 0; i < write_loops ; i++ ) { + g_autoptr(GError) error_local = NULL; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, + unit_sz, + write_offset, + payload_data + write_idx, + &error_local)) { + g_warning ("Write failed: %s, retrying", error_local->message); + /* repeat once */ + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, + unit_sz, + write_offset, + payload_data + write_idx, + error)) { + g_prefix_error (error, "firmware write failed: "); + return FALSE; + } + } + + write_offset += unit_sz; + write_idx += unit_sz; + if (progress_cb != NULL) { + progress_cb ((goffset) i * 100, + (goffset) (write_loops -1) * 100, + progress_data); + } + } + + /* verify CRC */ + checksum = synapticsmst_device_get_crc ( 0, 16, fw_size, payload_data ); + for (guint32 i = 0; i < 4; i++) { + g_usleep (1000); /* wait crc calculation */ + if (!synapticsmst_common_rc_special_get_command (connection, + UPDC_CAL_EEPROM_CHECK_CRC16, + fw_size, (EEPROM_BANK_OFFSET * bank_to_update), + NULL, 4, (guint8 *)(&flash_checksum), + error)) { + g_prefix_error (error, "Failed to get flash checksum: "); + return FALSE; + } + } + if (checksum == flash_checksum) + break; + if (retries_cnt > MAX_RETRY_COUNTS) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware update fail"); + return FALSE; + } + g_usleep (2000); } - checksum = 0; - offset = 0x200; - for (guint16 i = 0; i < 256; i++) - checksum += *(payload_data + offset + i); - if (checksum & 0xFF) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "configuration checksum error"); + /* set tag valid */ + time (&timeptr); + pTM = localtime (&timeptr); + memset (tagData, 0, sizeof (tagData)); + memset (readBuf, 0, sizeof (readBuf)); + + tagData[1] = pTM->tm_mon + 1; + tagData[2] = pTM->tm_mday; + tagData[3] = pTM->tm_year + 1900 - 2000; + crc_tmp = synapticsmst_device_get_crc (0, 16, fw_size, payload_data); + tagData[0] = bank_to_update; + tagData[4] = (crc_tmp >> 8) & 0xff; + tagData[5] = crc_tmp & 0xff; + tagData[15] = (guint8) synapticsmst_device_get_crc (0, 8, 15, tagData); + g_debug ("tag date %x %x %x crc %x %x %x %x", tagData[1], tagData[2], tagData[3], tagData[0], tagData[4], tagData[5], tagData[15]); + + for (guint32 retries_cnt = 0; ; retries_cnt++) { + gboolean match = TRUE; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, + 16, + (EEPROM_BANK_OFFSET * bank_to_update + EEPROM_TAG_OFFSET), + tagData, + error)) { + g_prefix_error (error, "failed to write tag: "); + return FALSE; + } + g_usleep (200); + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_EEPROM, + 16, + (EEPROM_BANK_OFFSET * bank_to_update + EEPROM_TAG_OFFSET), + readBuf, + error)) { + g_prefix_error (error, "failed to read tag: "); + return FALSE; + } + for (guint32 i = 0; i < 16; i++){ + if (readBuf[i] != tagData[i]){ + match = FALSE; + break; + } + } + if (match) + break; + if (retries_cnt > MAX_RETRY_COUNTS) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "set tag valid fail"); + return FALSE; + } + } + + /* set tag invalid*/ + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_EEPROM, 1, + (EEPROM_BANK_OFFSET * bank_in_use + EEPROM_TAG_OFFSET + 15), + tagData, + error)) { + g_prefix_error (error, "failed to read tag from flash: "); return FALSE; } - checksum = 0; - offset = 0x400; - code_size = (*(payload_data + offset) << 8) + *(payload_data + offset + 1); - if (code_size >= 0xFFFF) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid firmware size"); + for (guint32 retries_cnt = 0; ; retries_cnt++) { + /* CRC8 is not 0xff, erase last 4k of bank# */ + if (tagData[0] != 0xff) { + guint32 erase_offset; + /* offset for last 4k of bank# */ + erase_offset = (EEPROM_BANK_OFFSET * bank_in_use + EEPROM_BANK_OFFSET - 0x1000) / 0x1000; + if (!synapticsmst_device_set_flash_sector_erase (device, + FLASH_SECTOR_ERASE_4K, + erase_offset, + error)) + return FALSE; + /* CRC8 is 0xff, set it to 0x00 */ + } else { + tagData[1] = 0x00; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_EEPROM, 1, + (EEPROM_BANK_OFFSET * bank_in_use + EEPROM_TAG_OFFSET + 15), + &tagData[1], + error)) { + g_prefix_error (error, "failed to clear CRC: "); + return FALSE; + } + } + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_EEPROM, 1, + (EEPROM_BANK_OFFSET * bank_in_use + EEPROM_TAG_OFFSET + 15), + readBuf, + error)) { + g_prefix_error (error, "failed to read CRC from flash: "); + return FALSE; + } + if ((readBuf[0] == 0xff && tagData[0] != 0xff) || + (readBuf[0] == 0x00 && tagData[0] == 0xff)) { + break; + } + if (retries_cnt > MAX_RETRY_COUNTS) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "set tag invalid fail"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +synapticsmst_device_check_firmware_content (SynapticsMSTDevice *device, + GBytes *fw, + SynapticsMSTChipKind chip_type, + GError **error) +{ + gsize payload_len, payload_len_max; + + switch (chip_type) { + case SYNAPTICSMST_CHIP_KIND_PANAMERA: + payload_len_max = PAYLOAD_SIZE_512K; + break; + case SYNAPTICSMST_CHIP_KIND_TESLA_LEAF: + payload_len_max = PAYLOAD_SIZE_64K; + break; + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unknown chip type %u", + chip_type); return FALSE; + } - for (guint32 i = 0; i < (code_size + 17); i++) - checksum += *(payload_data + offset + i); - if (checksum & 0xFF) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware checksum error"); + /* check size */ + payload_len = g_bytes_get_size (fw); + if (payload_len > payload_len_max || payload_len == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid payload size %" G_GSIZE_FORMAT "(max %" G_GSIZE_FORMAT")", + payload_len, + payload_len_max); return FALSE; } - /* TODO: May need a way to override this to cover field - * issues of invalid firmware flashed*/ - /* check firmware and board ID again */ - tmp = (*(payload_data + ADDR_CUSTOMER_ID) << 8) + *(payload_data + ADDR_BOARD_ID); - if (tmp != synapticsmst_device_get_board_id (device)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "board ID mismatch"); + + return TRUE; +} + +static gboolean +synapticsmst_device_panamera_prepare_write (SynapticsMSTDevice *device, GError **error) +{ + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + guint32 dwData[4] = {0}; + g_autoptr(SynapticsMSTConnection) connection = NULL; + + /* Need to detect flash mode and ESM first ? */ + /* disable flash Quad mode and ESM/HDCP2.2*/ + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + + /* disable ESM first */ + dwData[0] = 0x21; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_MEMORY, + 4, (gint)REG_ESM_DISABLE, (guint8*)dwData, + error)) { + g_prefix_error (error, "ESM disable failed: "); return FALSE; } - if (!synapticsmst_device_open (device, error)) { - g_prefix_error (error, - "can't open DP Aux node %s", - synapticsmst_device_get_aux_node (device)); + /* wait for ESM exit */ + g_usleep (200); + + /* disable QUAD mode */ + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_MEMORY, + ((sizeof(dwData)/sizeof(dwData[0]))*4), + (gint)REG_QUAD_DISABLE, (guint8*)dwData, + error)) { + g_prefix_error (error, "quad query failed: "); return FALSE; } - /* enable remote control */ - if (!synapticsmst_device_enable_remote_control (device, error)) + dwData[0] = 0x00; + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_MEMORY, + 4, (gint)REG_QUAD_DISABLE, (guint8*)dwData, + error)) { + g_prefix_error (error, "quad disable failed: "); return FALSE; + } - /* erase SPI flash */ - connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); - if (synapticsmst_common_rc_set_command (connection, - UPDC_FLASH_ERASE, - 2, 0, (guint8 *)&erase_code)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "can't erase flash"); + /* disable HDCP2.2 */ + if (!synapticsmst_common_rc_get_command (connection, + UPDC_READ_FROM_MEMORY, + 4, (gint)REG_HDCP22_DISABLE, (guint8*)dwData, + error)) { + g_prefix_error (error, "HDCP query failed: "); return FALSE; } - /* update firmware */ - write_loops = (payload_len / BLOCK_UNIT); - data_to_write = payload_len; - rc = 0; - offset = 0; + dwData[0] = dwData[0] & (~BIT(2)); + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_MEMORY, + 4, (gint)REG_HDCP22_DISABLE, (guint8*)dwData, + error)) { + g_prefix_error (error, "HDCP disable failed: "); + return FALSE; + } - if (payload_len % BLOCK_UNIT) - write_loops++; + return TRUE; +} - if (progress_cb == NULL) - g_debug ("updating... 0%%"); +static gboolean +synapticsmst_device_restart (SynapticsMSTDevice *device, + GError **error) +{ + g_autoptr(SynapticsMSTConnection) connection = NULL; + SynapticsMSTDevicePrivate *priv = GET_PRIVATE (device); + guint8 dwData[4] = {0xF5, 0, 0 ,0}; + g_autoptr(GError) error_local = NULL; - for (guint32 i = 0; i < write_loops; i++) { - guint8 length = BLOCK_UNIT; - if (data_to_write < BLOCK_UNIT) - length = data_to_write; + /* issue the reboot command, ignore return code (triggers before returning) */ + connection = synapticsmst_common_new (priv->fd, priv->layer, priv->rad); + if (!synapticsmst_common_rc_set_command (connection, + UPDC_WRITE_TO_MEMORY, + 4, (gint) 0x2000FC, (guint8*) &dwData, + &error_local)) + g_debug ("failed to restart: %s", error_local->message); - rc = synapticsmst_common_rc_set_command (connection, - UPDC_WRITE_TO_EEPROM, - length, offset, - payload_data + offset); - if (rc) { - /* repeat once */ - rc = synapticsmst_common_rc_set_command (connection, - UPDC_WRITE_TO_EEPROM, - length, offset, - payload_data + offset); - } + return TRUE; +} - if (rc) - break; +gboolean +synapticsmst_device_write_firmware (SynapticsMSTDevice *device, + GBytes *fw, + GFileProgressCallback progress_cb, + gpointer progress_data, + gboolean reboot, + gboolean install_force, + GError **error) +{ + const guint8 *payload_data; + gsize payload_len; + guint16 tmp; + SynapticsMSTChipKind chip_type = SYNAPTICSMST_CHIP_KIND_UNKNOWN; + g_autoptr(FuDeviceLocker) locker = NULL; - offset += length; - data_to_write -= length; - percentage = i * 100 / (write_loops - 1); - if (progress_cb != NULL) { - progress_cb ((goffset) i * 100, - (goffset) (write_loops -1) * 100, - progress_data); - } else { - g_debug ("updating... %d%%\n", percentage); - } - } + payload_data = g_bytes_get_data (fw, &payload_len); - if (rc) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "can't write flash at offset 0x%04x", - offset); - } else { - /* check data just written */ - checksum = 0; - for (guint32 i = 0; i < payload_len; i++) { - checksum += *(payload_data + i); - } + if (synapticsmst_device_get_chip_id (device) > 0x5000) + chip_type = SYNAPTICSMST_CHIP_KIND_PANAMERA; + else + chip_type = SYNAPTICSMST_CHIP_KIND_TESLA_LEAF; - flash_checksum = 0; - if (synapticsmst_device_get_flash_checksum (device, - payload_len, - 0, - &flash_checksum, - error)) { - if (checksum != flash_checksum) { - rc = -1; - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "checksum mismatch"); - } - } else { - rc = -1; - } + if (!synapticsmst_device_check_firmware_content (device, fw, chip_type, error)){ + g_prefix_error (error, "Invalid file content: "); + return FALSE; + } + /* check firmware and board ID again */ + tmp = (*(payload_data + ADDR_CUSTOMER_ID) << 8) + *(payload_data + ADDR_BOARD_ID); + if (tmp != synapticsmst_device_get_board_id (device) && !install_force) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "board ID mismatch"); + return FALSE; } - /* disable remote control and close aux node */ - if (!synapticsmst_device_disable_remote_control (device, error)) + /* open device */ + if (!synapticsmst_device_open (device, error)) { + g_prefix_error (error, + "can't open DP Aux node %s", + synapticsmst_device_get_aux_node (device)); return FALSE; + } - if (rc) { + /* enable remote control and disable on exit */ + if (reboot) { + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) synapticsmst_device_enable_remote_control, + (FuDeviceLockerFunc) synapticsmst_device_restart, + error); + } else { + locker = fu_device_locker_new_full (device, + (FuDeviceLockerFunc) synapticsmst_device_enable_remote_control, + (FuDeviceLockerFunc) synapticsmst_device_disable_remote_control, + error); + } + if (locker == NULL) return FALSE; + + /* update firmware */ + if (chip_type == SYNAPTICSMST_CHIP_KIND_PANAMERA) { + if (!synapticsmst_device_panamera_prepare_write (device, error)) { + g_prefix_error (error, "Failed to prepare for write: "); + return FALSE; + } + if (!synapticsmst_device_update_esm (device, + payload_data, + progress_cb, + progress_data, + error)) { + g_prefix_error (error, "ESM update failed: "); + return FALSE; + } + if (!synapticsmst_device_update_panamera_firmware (device, + payload_len, + payload_data, + progress_cb, + progress_data, + error)) { + g_prefix_error (error, "Firmware update failed: "); + return FALSE; + } } else { - return TRUE; + if (!synapticsmst_device_update_tesla_leaf_firmware (device, + payload_len, + payload_data, + progress_cb, + progress_data, + error)) { + g_prefix_error (error, "Firmware update failed: "); + return FALSE; + } } + + return TRUE; } SynapticsMSTDevice * @@ -775,21 +1254,25 @@ if (priv->fd == -1) { g_set_error (error, G_IO_ERROR, - G_IO_ERROR_PERMISSION_DENIED, - "cannot open device %s", - filename); + g_io_error_from_errno (errno), + "cannot open device %s: %s", + filename, g_strerror (errno)); return FALSE; } connection = synapticsmst_common_new (priv->fd, 0, 0); - if (synapticsmst_common_aux_node_read (connection, REG_RC_CAP, (gint *)byte, 1) == DPCD_SUCCESS) { - if (byte[0] & 0x04) { - synapticsmst_common_aux_node_read (connection, - REG_VENDOR_ID, - (gint *)byte, 3); - if (byte[0] == 0x90 && byte[1] == 0xCC && byte[2] == 0x24) - return TRUE; + if (!synapticsmst_common_read (connection, REG_RC_CAP, byte, 1, error)) { + g_prefix_error (error, "failed to read device: "); + return FALSE; + } + if (byte[0] & 0x04) { + if (!synapticsmst_common_read (connection, REG_VENDOR_ID, + byte, 3, error)) { + g_prefix_error (error, "failed to read vendor ID: "); + return FALSE; } + if (byte[0] == 0x90 && byte[1] == 0xCC && byte[2] == 0x24) + return TRUE; } /* not a correct device */ @@ -797,7 +1280,5 @@ G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "no device"); - close (priv->fd); - priv->fd = 0; return FALSE; } diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst-device.h fwupd-1.2.10/plugins/synapticsmst/synapticsmst-device.h --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,13 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Peichen Huang * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __SYNAPTICSMST_DEVICE_H -#define __SYNAPTICSMST_DEVICE_H +#pragma once -#include #include G_BEGIN_DECLS @@ -56,14 +39,12 @@ } SynapticsMSTDeviceKind; typedef enum { - SYNAPTICSMST_DEVICE_BOARDID_EVB = 0x00, - SYNAPTICSMST_DEVICE_BOARDID_DELL_X6 = 0x110, - SYNAPTICSMST_DEVICE_BOARDID_DELL_X7, - SYNAPTICSMST_DEVICE_BOARDID_DELL_WD15_TB16_WIRE, - SYNAPTICSMST_DEVICE_BOARDID_DELL_WLD15_WIRELESS, - SYNAPTICSMST_DEVICE_BOARDID_DELL_X7_RUGGED = 0X115, - SYNAPTICSMST_DEVICE_BOARDID_UNKNOWN = 0xFF, -} SynapticsMSTDeviceBoardID; + SYNAPTICSMST_CHIP_KIND_UNKNOWN, + SYNAPTICSMST_CHIP_KIND_TESLA_LEAF, + SYNAPTICSMST_CHIP_KIND_PANAMERA, + /**/ + SYNAPTICSMST_CHIP_KIND_LAST +} SynapticsMSTChipKind; #define CUSTOMERID_DELL 0x1 @@ -75,8 +56,7 @@ /* helpers */ SynapticsMSTDeviceKind synapticsmst_device_kind_from_string (const gchar *kind); const gchar *synapticsmst_device_kind_to_string (SynapticsMSTDeviceKind kind); -const gchar *synapticsmst_device_board_id_to_string (SynapticsMSTDeviceBoardID board_id); -const gchar *synapticsmst_device_get_guid (SynapticsMSTDevice *device); +GPtrArray *synapticsmst_device_get_guids (SynapticsMSTDevice *device); gboolean synapticsmst_device_scan_cascade_device (SynapticsMSTDevice *device, GError **error, guint8 tx_port); @@ -85,26 +65,23 @@ /* getters */ SynapticsMSTDeviceKind synapticsmst_device_get_kind (SynapticsMSTDevice *device); -SynapticsMSTDeviceBoardID synapticsmst_device_get_board_id (SynapticsMSTDevice *device); +guint16 synapticsmst_device_get_board_id (SynapticsMSTDevice *device); const gchar *synapticsmst_device_get_version (SynapticsMSTDevice *device); -const gchar *synapticsmst_device_get_chip_id (SynapticsMSTDevice *device); +const gchar *synapticsmst_device_get_chip_id_str (SynapticsMSTDevice *device); const gchar *synapticsmst_device_get_aux_node (SynapticsMSTDevice *device); guint16 synapticsmst_device_get_rad (SynapticsMSTDevice *device); guint8 synapticsmst_device_get_layer (SynapticsMSTDevice *device); -gboolean -synapticsmst_device_get_cascade (SynapticsMSTDevice *device); +gboolean synapticsmst_device_get_cascade (SynapticsMSTDevice *device); /* object methods */ gboolean synapticsmst_device_enumerate_device (SynapticsMSTDevice *devices, - const gchar *dock_type, - const gchar *sytem_type, GError **error); gboolean synapticsmst_device_write_firmware (SynapticsMSTDevice *device, GBytes *fw, GFileProgressCallback progress_cb, gpointer user_data, + gboolean reboot, + gboolean install_force, GError **error); G_END_DECLS - -#endif /* __SYNAPTICSMST_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst_evb.quirk fwupd-1.2.10/plugins/synapticsmst/synapticsmst_evb.quirk --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst_evb.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst_evb.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +# Synaptics MST early validation board support +# +# This is not installed by default, but can be used to exercise new boards +# that don't yet have customer ID or board ID bytes filled out. +# +# To use it, load the quirk file into the quirks directory for the fwupd installation +# Usually this is /usr/share/fwupd/quirks.d +# +# Note: The flag "ignore-board-id" will be used to ignore the board ID checking in +# during flashing. This shouldn't be used in practice for production boards. +# + +[SynapticsMSTBoardID=2] +Name = Synaptics EVB development board +DeviceKind = panamera_evb + +[Guid=MST-panamera_evb-vmm5331-2] +Flags = ignore-board-id diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst.quirk fwupd-1.2.10/plugins/synapticsmst/synapticsmst.quirk --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,40 @@ +# GUID generation for Synaptics MST plugin +# +# SynapticsMSTBoardID is the 16 bit board ID which contains: +# * Customer ID in first byte +# * Board ID in the second byte +# +# DeviceKind = system +# * Will map to a GUID containing HwID product SKU +# * These GUIDs will look like MST-${PRODUCTSKU}-${BOARDID} +# DeviceKind != system +# * Will map to a GUID containing each comma delimitted substring +# * These GUIDs will look like MST-${DEVICEKIND}-${CHIPID}-${BOARDID} +# +# By default the Synaptics MST device will restart after update +# To override this behavior add the custom flag "skip-restart" +# + +[SynapticsMSTBoardID=272] +Name = Dell X6 Platform +DeviceKind = system + +[SynapticsMSTBoardID=273] +Name = Dell X7 Platform +DeviceKind = system + +[SynapticsMSTBoardID=274] +Name = Dell WD15/TB16/TB18 wired Dock +DeviceKind = wd15,tb16,tb18 + +[SynapticsMSTBoardID=275] +Name = Dell WLD15 Wireless Dock +DeviceKind = wld15 + +[SynapticsMSTBoardID=277] +Name = Dell Rugged Platform +DeviceKind = system + +[SynapticsMSTBoardID=259] +Name = Dell dock +DeviceKind = panamera diff -Nru fwupd-1.0.6/plugins/synapticsmst/synapticsmst-tool.c fwupd-1.2.10/plugins/synapticsmst/synapticsmst-tool.c --- fwupd-1.0.6/plugins/synapticsmst/synapticsmst-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/synapticsmst/synapticsmst-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,443 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Mario Limonciello - * Copyright (C) 2017 Peichen Huang - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#include "config.h" -#include "synapticsmst-common.h" -#include "synapticsmst-device.h" - -#include -#include -#include -#include -#include -#include - -typedef struct { - GCancellable *cancellable; - GPtrArray *cmd_array; - gboolean force; - GPtrArray *device_array; -} SynapticsMSTToolPrivate; - -static void -synapticsmst_tool_private_free (SynapticsMSTToolPrivate *priv) -{ - if (priv == NULL) - return; - g_object_unref (priv->cancellable); - g_ptr_array_unref (priv->device_array); - if (priv->cmd_array != NULL) - g_ptr_array_unref (priv->cmd_array); - g_free (priv); -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(SynapticsMSTToolPrivate, synapticsmst_tool_private_free) - -typedef gboolean (*FuUtilPrivateCb) (SynapticsMSTToolPrivate *util, - gchar **values, - guint8 device_index, - GError **error); - -typedef struct { - gchar *name; - gchar *arguments; - gchar *description; - FuUtilPrivateCb callback; -} FuUtilItem; - -static void -synapticsmst_tool_item_free (FuUtilItem *item) -{ - g_free (item->name); - g_free (item->arguments); - g_free (item->description); - g_free (item); -} - -static gint -synapticsmst_tool_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) -{ - return g_strcmp0 ((*item1)->name, (*item2)->name); -} - -static void -synapticsmst_tool_add (GPtrArray *array, - const gchar *name, - const gchar *arguments, - const gchar *description, - FuUtilPrivateCb callback) -{ - g_auto(GStrv) names = NULL; - - g_return_if_fail (name != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (callback != NULL); - - /* add each one */ - names = g_strsplit (name, ",", -1); - for (guint i = 0; names[i] != NULL; i++) { - FuUtilItem *item = g_new0 (FuUtilItem, 1); - item->name = g_strdup (names[i]); - if (i == 0) { - item->description = g_strdup (description); - } else { - /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ - item->description = g_strdup_printf (_("Alias to %s"), - names[0]); - } - item->arguments = g_strdup (arguments); - item->callback = callback; - g_ptr_array_add (array, item); - } -} - -static gchar * -synapticsmst_tool_get_descriptions (GPtrArray *array) -{ - gsize len; - const gsize max_len = 31; - GString *str; - - /* print each command */ - str = g_string_new (""); - for (guint i = 0; i < array->len; i++) { - FuUtilItem *item = g_ptr_array_index (array, i); - g_string_append (str, " "); - g_string_append (str, item->name); - len = strlen (item->name) + 2; - if (item->arguments != NULL) { - g_string_append (str, " "); - g_string_append (str, item->arguments); - len += strlen (item->arguments) + 1; - } - if (len < max_len) { - for (gsize j = len; j < max_len + 1; j++) - g_string_append_c (str, ' '); - g_string_append (str, item->description); - g_string_append_c (str, '\n'); - } else { - g_string_append_c (str, '\n'); - for (gsize j = 0; j < max_len + 1; j++) - g_string_append_c (str, ' '); - g_string_append (str, item->description); - g_string_append_c (str, '\n'); - } - } - - /* remove trailing newline */ - if (str->len > 0) - g_string_set_size (str, str->len - 1); - - return g_string_free (str, FALSE); -} - -static gboolean -synapticsmst_tool_scan_aux_nodes (SynapticsMSTToolPrivate *priv, GError **error) -{ - SynapticsMSTDevice *cascade_device = NULL; - GDir *dir; - const gchar *aux_node; - guint8 layer = 0; - guint16 rad = 0; - - dir = g_dir_open (SYSFS_DRM_DP_AUX, 0, NULL); - do { - g_autoptr(GError) error_local = NULL; - g_autoptr(SynapticsMSTDevice) device = NULL; - - aux_node = g_dir_read_name (dir); - if (aux_node == NULL) - break; - - /* can we open the device? */ - device = synapticsmst_device_new (SYNAPTICSMST_DEVICE_KIND_DIRECT, aux_node, 0, 0); - if (!synapticsmst_device_open (device, &error_local)) { - if (g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_PERMISSION_DENIED)) { - g_set_error (error, - error_local->domain, - error_local->code, - "failed to open aux node: %s", - error_local->message); - return FALSE; - } - /* ignore */ - continue; - } - - /* add device to results */ - g_ptr_array_add (priv->device_array, g_object_ref (device)); - } while (TRUE); - - /* no devices */ - if (priv->device_array->len == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "No Synaptics MST Device Found"); - return FALSE; - } - - /* add all cascaded devices */ - for (guint8 i = 0; i < priv->device_array->len; i++) { - SynapticsMSTDevice *device = g_ptr_array_index (priv->device_array, i); - aux_node = synapticsmst_device_get_aux_node (device); - if (!synapticsmst_device_open (device, error)) { - g_prefix_error (error, - "failed to open aux node %s again", - aux_node); - return FALSE; - } - - for (guint8 j = 0; j < 2; j++) { - if (!synapticsmst_device_scan_cascade_device (device, error, j)) - return FALSE; - if (!synapticsmst_device_get_cascade (device)) - continue; - layer = synapticsmst_device_get_layer (device) + 1; - rad = synapticsmst_device_get_rad (device) | (j << (2 * (layer - 1))); - cascade_device = synapticsmst_device_new (SYNAPTICSMST_DEVICE_KIND_REMOTE, - aux_node, layer, rad); - g_ptr_array_add (priv->device_array, cascade_device); - } - } - - /* success */ - return TRUE; -} - -static gboolean -synapticsmst_tool_enumerate (SynapticsMSTToolPrivate *priv, - gchar **values, - guint8 device_index, - GError **error) -{ - SynapticsMSTDevice *device = NULL; - - /* check avaliable dp aux nodes and add devices */ - if (!synapticsmst_tool_scan_aux_nodes (priv, error)) - return FALSE; - - g_print ("\nMST Devices:\n"); - /* enumerate all devices one by one */ - for (guint8 i = 0; i < priv->device_array->len; i++) { - const gchar *board_id = NULL; - device = g_ptr_array_index (priv->device_array, i); - g_print ("[Device %1d]\n", i+1); - if (!synapticsmst_device_enumerate_device (device, NULL, NULL, - error)) - return FALSE; - - board_id = synapticsmst_device_board_id_to_string (synapticsmst_device_get_board_id (device)); - if (board_id != NULL) { - g_print ("Device: %s with Synaptics %s\n", - board_id, - synapticsmst_device_get_chip_id (device)); - g_print ("Connect Type: %s in DP Aux Node %s\n", - synapticsmst_device_kind_to_string (synapticsmst_device_get_kind (device)), - synapticsmst_device_get_aux_node (device)); - g_print ("Firmware version: %s\n", synapticsmst_device_get_version (device)); - } else { - g_print ("Unknown Device\n"); - } - g_print ("\n"); - } - return TRUE; -} - -static gboolean -synapticsmst_tool_flash (SynapticsMSTToolPrivate *priv, - gchar **values, - guint8 device_index, - GError **error) -{ - SynapticsMSTDevice *device = NULL; - gsize len; - g_autofree guint8 *data = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(GError) error_local = NULL; - - /* incorrect args */ - if (g_strv_length (values) != 1) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Incorrect arguments, expected FILENAME]"); - return FALSE; - } - - /* check avaliable dp aux nodes and add devices */ - if (!synapticsmst_tool_scan_aux_nodes (priv, error)) - return FALSE; - - device = g_ptr_array_index (priv->device_array, (device_index - 1)); - if (!synapticsmst_device_enumerate_device (device, NULL, NULL, error)) - return FALSE; - - if (synapticsmst_device_board_id_to_string (synapticsmst_device_get_board_id (device)) == NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "failed to flash firmware: unknown device"); - return FALSE; - } - if (!g_file_get_contents (values[0], - (gchar **) &data, &len, - &error_local)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Failed to flash firmware: " - "can't load file %s: %s", - values[0], - error_local->message); - return FALSE; - } - - fw = g_bytes_new (data, len); - if (!synapticsmst_device_write_firmware (device, fw, NULL, NULL, error)) { - g_prefix_error (error, "failed to flash firmware: "); - return FALSE; - } - g_print ("Update Sucessfully. Please reset device to apply new firmware\n"); - - return TRUE; -} - -static gboolean -synapticsmst_tool_run (SynapticsMSTToolPrivate *priv, - const gchar *command, - gchar **values, - guint8 device_index, - GError **error) -{ - /* find command */ - for (guint i = 0; i < priv->cmd_array->len; i++) { - FuUtilItem *item = g_ptr_array_index (priv->cmd_array, i); - if (g_strcmp0 (item->name, command) == 0) - return item->callback (priv, values, device_index, error); - } - - /* not found */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - /* TRANSLATORS: error message */ - _("Command not found")); - return FALSE; -} - -static gboolean -synapticsmst_tool_sigint_cb (gpointer user_data) -{ - SynapticsMSTToolPrivate *priv = (SynapticsMSTToolPrivate *) user_data; - g_debug ("Handling SIGINT"); - g_cancellable_cancel (priv->cancellable); - return FALSE; -} - -int -main (int argc, char **argv) -{ - gboolean ret; - gboolean verbose = FALSE; - guint8 device_index = 0; - g_autofree gchar *cmd_descriptions = NULL; - g_autoptr (SynapticsMSTToolPrivate) priv = g_new0 (SynapticsMSTToolPrivate, 1); - g_autoptr (GError) error = NULL; - g_autoptr (GOptionContext) context = NULL; - const GOptionEntry options[] = { - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - "Print verbose debug statements", NULL }, - { "force", '\0', 0, G_OPTION_ARG_NONE, &priv->force, - "Force the action ignoring all warnings", NULL }, - { NULL} - }; - - setlocale (LC_ALL, ""); - - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - /* list of devices */ - priv->device_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - - /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) synapticsmst_tool_item_free); - synapticsmst_tool_add (priv->cmd_array, - "enumerate", - NULL, - /* TRANSLATORS: command description */ - _("Enumerate all Synaptics MST devices"), - synapticsmst_tool_enumerate); - synapticsmst_tool_add (priv->cmd_array, - "flash", - NULL, - /* TRANSLATORS: command description */ - _("Flash firmware file to MST device"), - synapticsmst_tool_flash); - - /* do stuff on ctrl+c */ - priv->cancellable = g_cancellable_new (); - g_unix_signal_add_full (G_PRIORITY_DEFAULT, - SIGINT, - synapticsmst_tool_sigint_cb, - priv, - NULL); - - /* sort by command name */ - g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) synapticsmst_tool_sort_command_name_cb); - - /* get a list of the commands */ - context = g_option_context_new (NULL); - cmd_descriptions = synapticsmst_tool_get_descriptions (priv->cmd_array); - g_option_context_set_summary (context, cmd_descriptions); - - g_set_application_name (_("Synaptics Multistream Transport Utility")); - g_option_context_add_main_entries (context, options, NULL); - ret = g_option_context_parse (context, &argc, &argv, &error); - if (!ret) { - /* TRANSLATORS: the user didn't read the man page */ - g_print ("%s: %s\n", _("Failed to parse arguments"), error->message); - return EXIT_FAILURE; - } - - /* set verbose? */ - if (verbose) - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - - /* run the specified command */ - if (argc == 4) - device_index = strtol (argv[3], NULL, 10); - ret = synapticsmst_tool_run (priv, argv[1], (gchar**) &argv[2], device_index, &error); - if (!ret) { - g_print ("%s\n", error->message); - return EXIT_FAILURE; - } - - /* success/ */ - return EXIT_SUCCESS; -} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/data/lsusb.txt fwupd-1.2.10/plugins/synaptics-prometheus/data/lsusb.txt --- fwupd-1.0.6/plugins/synaptics-prometheus/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/data/lsusb.txt 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,69 @@ +Bus 001 Device 043: ID 06cb:00a9 Synaptics, Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 255 Vendor Specific Class + bDeviceSubClass 16 + bDeviceProtocol 255 + bMaxPacketSize0 8 + idVendor 0x06cb Synaptics, Inc. + idProduct 0x00a9 + bcdDevice 0.00 + iManufacturer 0 + iProduct 0 + iSerial 1 942cfe315551 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0027 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xa0 + (Bus Powered) + Remote Wakeup + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 4 +Device Status: 0x0000 + (Bus Powered) Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/synaptics-prometheus/data/test.pkg and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/synaptics-prometheus/data/test.pkg differ diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-dump.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-dump.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-dump.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-dump.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-synaprom-firmware.h" + +static gboolean +fu_dump_parse (const gchar *filename, GError **error) +{ + gchar *data = NULL; + gsize len = 0; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) array = NULL; + if (!g_file_get_contents (filename, &data, &len, error)) + return FALSE; + blob = g_bytes_new_take (data, len); + array = fu_synaprom_firmware_new (blob, error); + return array != NULL; +} + +static gboolean +fu_dump_generate (const gchar *filename, GError **error) +{ + const gchar *data; + gsize len = 0; + g_autoptr(GBytes) blob = NULL; + blob = fu_synaprom_firmware_generate (); + data = g_bytes_get_data (blob, &len); + return g_file_set_contents (filename, data, len, error); +} + +int +main (int argc, char **argv) +{ + g_autoptr(GError) error = NULL; + if (argc == 2) { + if (!fu_dump_parse (argv[1], &error)) { + g_printerr ("parse failed: %s\n", error->message); + return 1; + } + } else if (argc == 3 && g_strcmp0 (argv[2], "gen") == 0) { + if (!fu_dump_generate (argv[1], &error)) { + g_printerr ("generate failed: %s\n", error->message); + return 1; + } + } else { + g_printerr ("firmware filename required\n"); + return 2; + } + g_print ("OK!\n"); + return 0; +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-plugin-synaptics-prometheus.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-synaprom-device.h" + +#include "fu-plugin-vfuncs.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.synaptics.prometheus"); +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + g_autoptr(FuSynapromDevice) dev = NULL; + + /* open the device */ + dev = fu_synaprom_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + + /* success */ + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *dev, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* write the firmware */ + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + if (!fu_device_write_firmware (dev, blob_fw, flags, error)) + return FALSE; + + /* success */ + return TRUE; +} + +gboolean +fu_plugin_update_reload (FuPlugin *plugin, FuDevice *dev, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + + /* get the new version number */ + locker = fu_device_locker_new (dev, error); + if (locker == NULL) { + g_prefix_error (error, "failed to re-open device: "); + return FALSE; + } + + /* success */ + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-self-test.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-self-test.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-plugin-private.h" +#include "fu-test.h" + +#include "fu-synaprom-device.h" +#include "fu-synaprom-firmware.h" + +static void +fu_test_synaprom_firmware_func (void) +{ + const guint8 *buf; + gsize sz = 0; + g_autofree gchar *filename = NULL; + g_autoptr(FuSynapromDevice) device = fu_synaprom_device_new (NULL); + g_autoptr(GBytes) blob1 = NULL; + g_autoptr(GBytes) blob2 = NULL; + g_autoptr(GBytes) fw = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) firmware = NULL; + + filename = fu_test_get_filename (TESTDATADIR, "test.pkg"); + g_assert_nonnull (filename); + fw = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (fw); + buf = g_bytes_get_data (fw, &sz); + g_assert_cmpint (sz, ==, 294); + g_assert_cmpint (buf[0], ==, 0x01); + g_assert_cmpint (buf[1], ==, 0x00); + firmware = fu_synaprom_firmware_new (fw, &error); + g_assert_no_error (error); + g_assert_nonnull (firmware); + + /* does not exist */ + blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware, 0, NULL); + g_assert_null (blob1); + blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware, + FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER, + NULL); + g_assert_null (blob1); + + /* header needs to exist */ + blob1 = fu_synaprom_firmware_get_bytes_by_tag (firmware, + FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER, + &error); + g_assert_no_error (error); + g_assert_nonnull (blob1); + buf = g_bytes_get_data (blob1, &sz); + g_assert_cmpint (sz, ==, 24); + g_assert_cmpint (buf[0], ==, 0x41); + g_assert_cmpint (buf[1], ==, 0x00); + g_assert_cmpint (buf[2], ==, 0x00); + g_assert_cmpint (buf[3], ==, 0x00); + g_assert_cmpint (buf[4], ==, 0xff); + + /* payload needs to exist */ + fu_synaprom_device_set_version (device, 10, 1, 1234); + blob2 = fu_synaprom_device_prepare_fw (FU_DEVICE (device), fw, + FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_nonnull (blob2); + buf = g_bytes_get_data (blob2, &sz); + g_assert_cmpint (sz, ==, 2); + g_assert_cmpint (buf[0], ==, 'R'); + g_assert_cmpint (buf[1], ==, 'H'); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_test_add_func ("/synaprom/firmware", fu_test_synaprom_firmware_func); + return g_test_run (); +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-common.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-common.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-synaprom-common.h" + +enum { + FU_SYNAPROM_RESULT_OK = 0, + FU_SYNAPROM_RESULT_GEN_OPERATION_CANCELED = 103, + FU_SYNAPROM_RESULT_GEN_INVALID = 110, + FU_SYNAPROM_RESULT_GEN_BAD_PARAM = 111, + FU_SYNAPROM_RESULT_GEN_NULL_POINTER = 112, + FU_SYNAPROM_RESULT_GEN_UNEXPECTED_FORMAT = 114, + FU_SYNAPROM_RESULT_GEN_TIMEOUT = 117, + FU_SYNAPROM_RESULT_GEN_OBJECT_DOESNT_EXIST = 118, + FU_SYNAPROM_RESULT_GEN_ERROR = 119, + FU_SYNAPROM_RESULT_SENSOR_MALFUNCTIONED = 202, + FU_SYNAPROM_RESULT_SYS_OUT_OF_MEMORY = 602, +}; + +GByteArray * +fu_synaprom_request_new (guint8 cmd, const gpointer data, gsize len) +{ + GByteArray *blob = g_byte_array_new (); + g_byte_array_append (blob, &cmd, 1); + if (data != NULL) + g_byte_array_append (blob, data, len); + return blob; +} + +GByteArray * +fu_synaprom_reply_new (gsize cmdlen) +{ + GByteArray *blob = g_byte_array_new (); + g_byte_array_set_size (blob, cmdlen); + return blob; +} + +gboolean +fu_synaprom_error_from_status (guint16 status, GError **error) +{ + if (status == FU_SYNAPROM_RESULT_OK) + return TRUE; + switch (status) { + case FU_SYNAPROM_RESULT_GEN_OPERATION_CANCELED: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "cancelled"); + break; + case FU_SYNAPROM_RESULT_GEN_BAD_PARAM: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "bad parameter"); + break; + case FU_SYNAPROM_RESULT_GEN_NULL_POINTER: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "NULL pointer"); + break; + case FU_SYNAPROM_RESULT_GEN_UNEXPECTED_FORMAT: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "unexpected format"); + break; + case FU_SYNAPROM_RESULT_GEN_TIMEOUT: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timed out"); + break; + case FU_SYNAPROM_RESULT_GEN_OBJECT_DOESNT_EXIST: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "object does not exist"); + break; + case FU_SYNAPROM_RESULT_GEN_ERROR: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "generic error"); + break; + case FU_SYNAPROM_RESULT_SENSOR_MALFUNCTIONED: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_INITIALIZED, + "sensor malfunctioned"); + break; + case FU_SYNAPROM_RESULT_SYS_OUT_OF_MEMORY: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_AGAIN, + "out of heap memory"); + break; + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "error status: 0x%x", + status); + } + return FALSE; +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-common.h fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-common.h --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +GByteArray *fu_synaprom_request_new (guint8 cmd, + const gpointer data, + gsize len); +GByteArray *fu_synaprom_reply_new (gsize cmdlen); +gboolean fu_synaprom_error_from_status (guint16 status, + GError **error); diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-config.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-config.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-config.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-config.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-synaprom-common.h" +#include "fu-synaprom-config.h" +#include "fu-synaprom-firmware.h" + +struct _FuSynapromConfig { + FuDevice parent_instance; + FuSynapromDevice *device; + guint32 configid1; /* config ID1 */ + guint32 configid2; /* config ID2 */ +}; + +/* Iotas can exceed the size of available RAM in the part. + * In order to allow the host to read them the IOTA_FIND command supports + * transferring iotas with multiple commands */ +typedef struct __attribute__((packed)) { + guint16 itype; /* type of iotas to find */ + guint16 flags; /* flags, see below */ + guint8 maxniotas; /* maximum number of iotas to return, 0 = unlimited */ + guint8 firstidx; /* first index of iotas to return */ + guint8 dummy[2]; + guint32 offset; /* byte offset of data to return */ + guint32 nbytes; /* maximum number of bytes to return */ +} FuSynapromCmdIotaFind; + +/* this is followed by a chain of iotas, as follows */ +typedef struct __attribute__((packed)) { + guint16 status; + guint32 fullsize; + guint16 nbytes; + guint16 itype; +} FuSynapromReplyIotaFindHdr; + +/* this iota contains the configuration id and version */ +typedef struct __attribute__((packed)) { + guint32 config_id1; /* YYMMDD */ + guint32 config_id2; /* HHMMSS */ + guint16 version; + guint16 unused[3]; +} FuSynapromIotaConfigVersion; + +#define FU_SYNAPROM_CMD_IOTA_FIND_FLAGS_ALLIOTAS 0x0001 /* itype ignored*/ +#define FU_SYNAPROM_CMD_IOTA_FIND_FLAGS_READMAX 0x0002 /* nbytes ignored */ +#define FU_SYNAPROM_MAX_IOTA_READ_SIZE (64 * 1024) /* max size of iota data returned */ + +#define FU_SYNAPROM_IOTA_ITYPE_CONFIG_VERSION 0x0009 /* Configuration id and version */ + +G_DEFINE_TYPE (FuSynapromConfig, fu_synaprom_config, FU_TYPE_DEVICE) + +enum { + PROP_0, + PROP_DEVICE, + PROP_LAST +}; + +static gboolean +fu_synaprom_config_setup (FuDevice *device, GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + FuSynapromCmdIotaFind cmd = { 0x0 }; + FuSynapromIotaConfigVersion cfg; + FuSynapromReplyIotaFindHdr hdr; + g_autofree gchar *version = NULL; + g_autoptr(GByteArray) reply = NULL; + g_autoptr(GByteArray) request = NULL; + + /* get IOTA */ + cmd.itype = GUINT16_TO_LE((guint16)FU_SYNAPROM_IOTA_ITYPE_CONFIG_VERSION); + cmd.flags = GUINT16_TO_LE((guint16)FU_SYNAPROM_CMD_IOTA_FIND_FLAGS_READMAX); + request = fu_synaprom_request_new (FU_SYNAPROM_CMD_IOTA_FIND, &cmd, sizeof(cmd)); + reply = fu_synaprom_reply_new (sizeof(FuSynapromReplyIotaFindHdr) + FU_SYNAPROM_MAX_IOTA_READ_SIZE); + if (!fu_synaprom_device_cmd_send (self->device, request, reply, 5000, error)) + return FALSE; + if (reply->len < sizeof(hdr) + sizeof(cfg)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "CFG return data invalid size: 0x%04x", + reply->len); + return FALSE; + } + memcpy (&hdr, reply->data, sizeof(hdr)); + if (GUINT32_FROM_LE(hdr.itype) != FU_SYNAPROM_IOTA_ITYPE_CONFIG_VERSION) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "CFG iota had invalid itype: 0x%04x", + GUINT32_FROM_LE(hdr.itype)); + return FALSE; + } + memcpy (&cfg, reply->data + sizeof(hdr), sizeof(cfg)); + self->configid1 = GUINT32_FROM_LE(cfg.config_id1); + self->configid2 = GUINT32_FROM_LE(cfg.config_id2); + g_debug ("id1=%u, id2=%u, ver=%u", + self->configid1, self->configid2, + GUINT16_FROM_LE(cfg.version)); + + /* no downgrades are allowed */ + version = g_strdup_printf ("%04u", GUINT16_FROM_LE(cfg.version)); + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_PLAIN); + fu_device_set_version_lowest (FU_DEVICE (self), version); + return TRUE; +} + +static GBytes * +fu_synaprom_config_prepare_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + FuSynapromFirmwareCfgHeader hdr; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) firmware = NULL; + guint32 product; + guint32 id1; + + /* parse the firmware */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + firmware = fu_synaprom_firmware_new (fw, error); + if (firmware == NULL) + return NULL; + + /* check the update header product and version */ + blob = fu_synaprom_firmware_get_bytes_by_tag (firmware, + FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER, + error); + if (blob == NULL) + return NULL; + if (g_bytes_get_size (blob) != sizeof(hdr)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "CFG metadata is invalid"); + return NULL; + } + memcpy (&hdr, g_bytes_get_data (blob, NULL), sizeof(hdr)); + product = GUINT32_FROM_LE(hdr.product); + if (product != FU_SYNAPROM_PRODUCT_PROMETHEUS) { + if (flags & FWUPD_INSTALL_FLAG_FORCE) { + g_warning ("CFG metadata not compatible, " + "got 0x%02x expected 0x%02x", + product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "CFG metadata not compatible, " + "got 0x%02x expected 0x%02x", + product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); + return NULL; + } + } + id1 = GUINT32_FROM_LE(hdr.id1); + if (id1 != self->configid1) { + if (flags & FWUPD_INSTALL_FLAG_FORCE) { + g_warning ("CFG version not compatible, " + "got %u expected %u", + id1, self->configid1); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "CFG version not compatible, " + "got %u expected %u", + id1, self->configid1); + return NULL; + } + } + + /* get payload */ + return fu_synaprom_firmware_get_bytes_by_tag (firmware, + FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD, + error); +} + +static gboolean +fu_synaprom_config_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + /* I assume the CFG/MFW difference is detected in the device...*/ + return fu_synaprom_device_write_fw (self->device, fw, error); +} + +static void +fu_synaprom_config_init (FuSynapromConfig *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_logical_id (FU_DEVICE (self), "cfg"); + fu_device_set_name (FU_DEVICE (self), "Prometheus IOTA Config"); +} + +static void +fu_synaprom_config_finalize (GObject *obj) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (obj); + g_object_unref (self->device); +} + +static void +fu_synaprom_config_constructed (GObject *obj) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (obj); + g_autofree gchar *devid = NULL; + + /* append the firmware kind to the generated GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X-cfg", + fu_usb_device_get_vid (FU_USB_DEVICE (self->device)), + fu_usb_device_get_pid (FU_USB_DEVICE (self->device))); + fu_device_add_instance_id (FU_DEVICE (self), devid); + + G_OBJECT_CLASS (fu_synaprom_config_parent_class)->constructed (obj); +} + +static void +fu_synaprom_config_get_property (GObject *obj, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (obj); + switch (prop_id) { + case PROP_DEVICE: + g_value_set_object (value, self->device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +fu_synaprom_config_set_property (GObject *obj, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (obj); + switch (prop_id) { + case PROP_DEVICE: + g_set_object (&self->device, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static gboolean +fu_synaprom_config_open (FuDevice *device, GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + return fu_device_open (FU_DEVICE (self->device), error); +} + +static gboolean +fu_synaprom_config_close (FuDevice *device, GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + return fu_device_close (FU_DEVICE (self->device), error); +} + +static gboolean +fu_synaprom_config_attach (FuDevice *device, GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + return fu_device_attach (FU_DEVICE (self->device), error); +} + +static gboolean +fu_synaprom_config_detach (FuDevice *device, GError **error) +{ + FuSynapromConfig *self = FU_SYNAPROM_CONFIG (device); + return fu_device_detach (FU_DEVICE (self->device), error); +} + +static void +fu_synaprom_config_class_init (FuSynapromConfigClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->constructed = fu_synaprom_config_constructed; + object_class->finalize = fu_synaprom_config_finalize; + object_class->get_property = fu_synaprom_config_get_property; + object_class->set_property = fu_synaprom_config_set_property; + klass_device->write_firmware = fu_synaprom_config_write_firmware; + klass_device->prepare_firmware = fu_synaprom_config_prepare_firmware; + klass_device->open = fu_synaprom_config_open; + klass_device->close = fu_synaprom_config_close; + klass_device->setup = fu_synaprom_config_setup; + klass_device->attach = fu_synaprom_config_attach; + klass_device->detach = fu_synaprom_config_detach; + + pspec = g_param_spec_object ("device", NULL, NULL, + FU_TYPE_SYNAPROM_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_DEVICE, pspec); +} + +FuSynapromConfig * +fu_synaprom_config_new (FuSynapromDevice *device) +{ + FuSynapromConfig *self; + self = g_object_new (FU_TYPE_SYNAPROM_CONFIG, + "device", device, + NULL); + return FU_SYNAPROM_CONFIG (self); +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-config.h fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-config.h --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-config.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-config.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" +#include "fu-synaprom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SYNAPROM_CONFIG (fu_synaprom_config_get_type ()) +G_DECLARE_FINAL_TYPE (FuSynapromConfig, fu_synaprom_config, FU, SYNAPROM_CONFIG, FuDevice) + +FuSynapromConfig *fu_synaprom_config_new (FuSynapromDevice *device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-device.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-device.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-synaprom-common.h" +#include "fu-synaprom-config.h" +#include "fu-synaprom-device.h" +#include "fu-synaprom-firmware.h" + +struct _FuSynapromDevice { + FuUsbDevice parent_instance; + guint8 vmajor; + guint8 vminor; +}; + +/* vendor-specific USB control requets to write DFT word (Hayes) */ +#define FU_SYNAPROM_USB_CTRLREQUEST_VENDOR_WRITEDFT 21 + +/* endpoint addresses for command and fingerprint data */ +#define FU_SYNAPROM_USB_REQUEST_EP 0x01 +#define FU_SYNAPROM_USB_REPLY_EP 0x81 +#define FU_SYNAPROM_USB_FINGERPRINT_EP 0x82 +#define FU_SYNAPROM_USB_INTERRUPT_EP 0x83 + +/* le */ +typedef struct __attribute__((packed)) { + guint16 status; +} FuSynapromReplyGeneric; + +/* le */ +typedef struct __attribute__((packed)) { + guint16 status; + guint32 buildtime; /* Unix-style build time */ + guint32 buildnum; /* build number */ + guint8 vmajor; /* major version */ + guint8 vminor; /* minor version */ + guint8 target; /* target, e.g. VCSFW_TARGET_ROM */ + guint8 product; /* product, e.g. VCSFW_PRODUCT_FALCON */ + guint8 siliconrev; /* silicon revision */ + guint8 formalrel; /* boolean: non-zero -> formal release */ + guint8 platform; /* Platform (PCB) revision */ + guint8 patch; /* patch level */ + guint8 serial_number[6]; /* 48-bit Serial Number */ + guint8 security[2]; /* bytes 0 and 1 of OTP */ + guint32 patchsig; /* opaque patch signature */ + guint8 iface; /* interface type, see below */ + guint8 otpsig[3]; /* OTP Patch Signature */ + guint16 otpspare1; /* spare space */ + guint8 reserved; /* reserved byte */ + guint8 device_type; /* device type */ +} FuSynapromReplyGetVersion; + +/* the following bits describe security options in +** FuSynapromReplyGetVersion::security[1] bit-field */ +#define FU_SYNAPROM_SECURITY1_PROD_SENSOR (1 << 5) + +G_DEFINE_TYPE (FuSynapromDevice, fu_synaprom_device, FU_TYPE_USB_DEVICE) + +static gboolean +fu_synaprom_device_open (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + if (!g_usb_device_claim_interface (usb_device, 0x0, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + return FALSE; + } + return TRUE; +} + +gboolean +fu_synaprom_device_cmd_send (FuSynapromDevice *device, + GByteArray *request, + GByteArray *reply, + guint timeout_ms, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gboolean ret; + gsize actual_len = 0; + + if (g_getenv ("FWUPD_SYNAPROM_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "REQST", + request->data, request->len, 16, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + } + ret = g_usb_device_bulk_transfer (usb_device, + FU_SYNAPROM_USB_REQUEST_EP, + request->data, + request->len, + &actual_len, + timeout_ms, NULL, error); + if (!ret) { + g_prefix_error (error, "failed to request: "); + return FALSE; + } + if (actual_len < request->len) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only sent 0x%04x of 0x%04x", + (guint) actual_len, request->len); + return FALSE; + } + + ret = g_usb_device_bulk_transfer (usb_device, + FU_SYNAPROM_USB_REPLY_EP, + reply->data, + reply->len, + NULL, /* allowed to return short read */ + timeout_ms, NULL, error); + if (!ret) { + g_prefix_error (error, "failed to reply: "); + return FALSE; + } + if (g_getenv ("FWUPD_SYNAPROM_VERBOSE") != NULL) { + fu_common_dump_full (G_LOG_DOMAIN, "REPLY", + reply->data, actual_len, 16, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + } + + /* parse as FuSynapromReplyGeneric */ + if (reply->len >= sizeof(FuSynapromReplyGeneric)) { + FuSynapromReplyGeneric *hdr = (FuSynapromReplyGeneric *) reply->data; + return fu_synaprom_error_from_status (GUINT16_FROM_LE(hdr->status), error); + } + + /* success */ + return TRUE; +} + +void +fu_synaprom_device_set_version (FuSynapromDevice *self, + guint8 vmajor, guint8 vminor, guint32 buildnum) +{ + g_autofree gchar *str = NULL; + + /* set display version */ + str = g_strdup_printf ("%02u.%02u.%u", vmajor, vminor, buildnum); + fu_device_set_version (FU_DEVICE (self), str, FWUPD_VERSION_FORMAT_TRIPLET); + + /* we need this for checking the firmware compatibility later */ + self->vmajor = vmajor; + self->vminor = vminor; +} + +static void +fu_synaprom_device_set_serial_number (FuSynapromDevice *self, guint64 serial_number) +{ + g_autofree gchar *str = NULL; + str = g_strdup_printf ("%" G_GUINT64_FORMAT, serial_number); + fu_device_set_serial (FU_DEVICE (self), str); +} + +static gboolean +fu_synaprom_device_setup (FuDevice *device, GError **error) +{ + FuSynapromDevice *self = FU_SYNAPROM_DEVICE (device); + FuSynapromReplyGetVersion pkt; + guint32 product; + guint64 serial_number = 0; + g_autoptr(GByteArray) request = NULL; + g_autoptr(GByteArray) reply = NULL; + + /* get version */ + request = fu_synaprom_request_new (FU_SYNAPROM_CMD_GET_VERSION, NULL, 0); + reply = fu_synaprom_reply_new (sizeof(FuSynapromReplyGetVersion)); + if (!fu_synaprom_device_cmd_send (self, request, reply, 250, error)) { + g_prefix_error (error, "failed to get version: "); + return FALSE; + } + memcpy (&pkt, reply->data, sizeof(pkt)); + product = GUINT32_FROM_LE(pkt.product); + g_debug ("product ID is %u, version=%u.%u, buildnum=%u prod=%i", + product, pkt.vmajor, pkt.vminor, GUINT32_FROM_LE(pkt.buildnum), + pkt.security[1] & FU_SYNAPROM_SECURITY1_PROD_SENSOR); + fu_synaprom_device_set_version (self, pkt.vmajor, pkt.vminor, + GUINT32_FROM_LE(pkt.buildnum)); + + /* get serial number */ + memcpy (&serial_number, pkt.serial_number, sizeof(pkt.serial_number)); + fu_synaprom_device_set_serial_number (self, serial_number); + + /* check device type */ + if (product == FU_SYNAPROM_PRODUCT_PROMETHEUS) { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } else if (product == FU_SYNAPROM_PRODUCT_PROMETHEUSPBL || + product == FU_SYNAPROM_PRODUCT_PROMETHEUSMSBL) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "device %u is not supported by this plugin", + product); + return FALSE; + } + + /* add updatable config child, if this is a production sensor */ + if (pkt.security[1] & FU_SYNAPROM_SECURITY1_PROD_SENSOR) { + g_autoptr(FuSynapromConfig) cfg = fu_synaprom_config_new (self); + if (!fu_device_setup (FU_DEVICE (cfg), error)) { + g_prefix_error (error, "failed to get config version: "); + return FALSE; + } + fu_device_add_child (FU_DEVICE (device), FU_DEVICE (cfg)); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_synaprom_device_cmd_download_chunk (FuSynapromDevice *device, + const GByteArray *chunk, + GError **error) +{ + g_autoptr(GByteArray) request = NULL; + g_autoptr(GByteArray) reply = NULL; + request = fu_synaprom_request_new (FU_SYNAPROM_CMD_BOOTLDR_PATCH, + chunk->data, chunk->len); + reply = fu_synaprom_reply_new (sizeof(FuSynapromReplyGeneric)); + return fu_synaprom_device_cmd_send (device, request, reply, 20000, error); +} + +GBytes * +fu_synaprom_device_prepare_fw (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuSynapromDevice *self = FU_SYNAPROM_DEVICE (device); + FuSynapromFirmwareMfwHeader hdr; + guint32 product; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) firmware = NULL; + + /* parse the firmware */ + fu_device_set_status (device, FWUPD_STATUS_DECOMPRESSING); + firmware = fu_synaprom_firmware_new (fw, error); + if (firmware == NULL) + return NULL; + + /* check the update header product and version */ + blob = fu_synaprom_firmware_get_bytes_by_tag (firmware, + FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER, + error); + if (blob == NULL) + return NULL; + if (g_bytes_get_size (blob) != sizeof(hdr)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "MFW metadata is invalid"); + return NULL; + } + memcpy (&hdr, g_bytes_get_data (blob, NULL), sizeof(hdr)); + product = GUINT32_FROM_LE(hdr.product); + if (product != FU_SYNAPROM_PRODUCT_PROMETHEUS) { + if (flags & FWUPD_INSTALL_FLAG_FORCE) { + g_warning ("MFW metadata not compatible, " + "got 0x%02x expected 0x%02x", + product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "MFW metadata not compatible, " + "got 0x%02x expected 0x%02x", + product, (guint) FU_SYNAPROM_PRODUCT_PROMETHEUS); + return NULL; + } + } + if (hdr.vmajor != self->vmajor || hdr.vminor != self->vminor) { + if (flags & FWUPD_INSTALL_FLAG_FORCE) { + g_warning ("MFW version not compatible, " + "got %u.%u expected %u.%u", + hdr.vmajor, hdr.vminor, + self->vmajor, self->vminor); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "MFW version not compatible, " + "got %u.%u expected %u.%u", + hdr.vmajor, hdr.vminor, + self->vmajor, self->vminor); + return NULL; + } + } + + /* get payload */ + return fu_synaprom_firmware_get_bytes_by_tag (firmware, + FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD, + error); +} + +gboolean +fu_synaprom_device_write_fw (FuSynapromDevice *self, GBytes *fw, GError **error) +{ + const guint8 *buf; + gsize sz = 0; + + /* write chunks */ + fu_device_set_progress (FU_DEVICE (self), 10); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); + buf = g_bytes_get_data (fw, &sz); + while (sz != 0) { + guint32 chunksz; + g_autoptr(GByteArray) chunk = g_byte_array_new (); + + /* get chunk size */ + if (sz < sizeof(guint32)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "No enough data for patch len"); + return FALSE; + } + memcpy (&chunksz, buf, sizeof(guint32)); + buf += sizeof(guint32); + sz -= sizeof(guint32); + if (sz < chunksz) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "No enough data for patch chunk"); + return FALSE; + } + + /* download chunk */ + g_byte_array_append (chunk, buf, chunksz); + if (!fu_synaprom_device_cmd_download_chunk (self, chunk, error)) + return FALSE; + + /* next chunk */ + buf += chunksz; + sz -= chunksz; + } + + /* success! */ + fu_device_set_progress (FU_DEVICE (self), 100); + return TRUE; +} + +static gboolean +fu_synaprom_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuSynapromDevice *self = FU_SYNAPROM_DEVICE (device); + return fu_synaprom_device_write_fw (self, fw, error); +} + +static gboolean +fu_synaprom_device_attach (FuDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gboolean ret; + gsize actual_len = 0; + guint8 data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + ret = g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_SYNAPROM_USB_CTRLREQUEST_VENDOR_WRITEDFT, + 0x0000, 0x0000, + data, sizeof(data), &actual_len, + 2000, NULL, error); + if (!ret) + return FALSE; + if (actual_len != sizeof(data)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only sent 0x%04x of 0x%04x", + (guint) actual_len, (guint) sizeof(data)); + return FALSE; + } + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!g_usb_device_reset (usb_device, error)) { + g_prefix_error (error, "failed to force-reset device: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_synaprom_device_detach (FuDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); + gboolean ret; + gsize actual_len = 0; + guint8 data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }; + + ret = g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + FU_SYNAPROM_USB_CTRLREQUEST_VENDOR_WRITEDFT, + 0x0000, 0x0000, + data, sizeof(data), &actual_len, + 2000, NULL, error); + if (!ret) + return FALSE; + if (actual_len != sizeof(data)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "only sent 0x%04x of 0x%04x", + (guint) actual_len, (guint) sizeof(data)); + return FALSE; + } + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + if (!g_usb_device_reset (usb_device, error)) { + g_prefix_error (error, "failed to force-reset device: "); + return FALSE; + } + return TRUE; +} + +static void +fu_synaprom_device_init (FuSynapromDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_set_name (FU_DEVICE (self), "Prometheus"); + fu_device_set_summary (FU_DEVICE (self), "Fingerprint reader"); + fu_device_set_vendor (FU_DEVICE (self), "Synaptics"); + fu_device_add_icon (FU_DEVICE (self), "touchpad-disabled"); +} + +static void +fu_synaprom_device_class_init (FuSynapromDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_synaprom_device_write_firmware; + klass_device->prepare_firmware = fu_synaprom_device_prepare_fw; + klass_device->setup = fu_synaprom_device_setup; + klass_device->attach = fu_synaprom_device_attach; + klass_device->detach = fu_synaprom_device_detach; + klass_usb_device->open = fu_synaprom_device_open; +} + +FuSynapromDevice * +fu_synaprom_device_new (FuUsbDevice *device) +{ + FuSynapromDevice *self; + self = g_object_new (FU_TYPE_SYNAPROM_DEVICE, NULL); + if (device != NULL) + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return FU_SYNAPROM_DEVICE (self); +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-device.h fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-device.h --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_SYNAPROM_DEVICE (fu_synaprom_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuSynapromDevice, fu_synaprom_device, FU, SYNAPROM_DEVICE, FuUsbDevice) + +#define FU_SYNAPROM_PRODUCT_PROMETHEUS 65 /* Prometheus (b1422) */ +#define FU_SYNAPROM_PRODUCT_PROMETHEUSPBL 66 +#define FU_SYNAPROM_PRODUCT_PROMETHEUSMSBL 67 + +#define FU_SYNAPROM_CMD_GET_VERSION 0x01 +#define FU_SYNAPROM_CMD_BOOTLDR_PATCH 0x7d +#define FU_SYNAPROM_CMD_IOTA_FIND 0x8e + +FuSynapromDevice *fu_synaprom_device_new (FuUsbDevice *device); +gboolean fu_synaprom_device_cmd_send (FuSynapromDevice *device, + GByteArray *request, + GByteArray *reply, + guint timeout_ms, + GError **error); +gboolean fu_synaprom_device_write_fw (FuSynapromDevice *self, + GBytes *fw, + GError **error); + +/* for self tests */ +void fu_synaprom_device_set_version (FuSynapromDevice *self, + guint8 vmajor, + guint8 vminor, + guint32 buildnum); +GBytes *fu_synaprom_device_prepare_fw (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-firmware.c fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-firmware.c --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-firmware.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-synaprom-firmware.h" + +typedef struct __attribute__((packed)) { + guint16 tag; + guint32 bufsz; +} FuSynapromFirmwareHdr; + +typedef struct { + guint16 tag; + GBytes *bytes; +} FuSynapromFirmwareItem; + +/* use only first 12 bit of 16 bits as tag value */ +#define FU_SYNAPROM_FIRMWARE_TAG_MAX 0xfff0 +#define FU_SYNAPROM_FIRMWARE_SIGSIZE 0x0100 + +static void +fu_synaprom_firmware_item_free (FuSynapromFirmwareItem *item) +{ + g_bytes_unref (item->bytes); + g_free (item); +} + +static const gchar * +fu_synaprom_firmware_tag_to_string (guint16 tag) +{ + if (tag == FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER) + return "mfw-update-header"; + if (tag == FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD) + return "mfw-update-payload"; + if (tag == FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER) + return "cfg-update-header"; + if (tag == FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD) + return "cfg-update-payload"; + return NULL; +} + +GPtrArray * +fu_synaprom_firmware_new (GBytes *blob, GError **error) +{ + const guint8 *buf; + gsize bufsz = 0; + gsize offset = 0; + g_autoptr(GPtrArray) firmware = NULL; + + g_return_val_if_fail (blob != NULL, NULL); + + firmware = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_synaprom_firmware_item_free); + buf = g_bytes_get_data (blob, &bufsz); + + /* 256 byte signature as footer */ + if (bufsz < FU_SYNAPROM_FIRMWARE_SIGSIZE + sizeof(FuSynapromFirmwareHdr)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "blob is too small to be firmware"); + return NULL; + } + bufsz -= FU_SYNAPROM_FIRMWARE_SIGSIZE; + + /* parse each chunk */ + while (offset != bufsz) { + FuSynapromFirmwareHdr header; + guint32 hdrsz; + g_autofree FuSynapromFirmwareItem *item = NULL; + + /* verify item header */ + memcpy (&header, buf, sizeof(header)); + item = g_new0 (FuSynapromFirmwareItem, 1); + item->tag = GUINT16_FROM_LE(header.tag); + if (item->tag >= FU_SYNAPROM_FIRMWARE_TAG_MAX) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "tag 0x%04x is too large", + item->tag); + return NULL; + } + hdrsz = GUINT32_FROM_LE(header.bufsz); + offset += sizeof(header) + hdrsz; + if (offset > bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "data is corrupted 0x%04x > 0x%04x", + (guint) offset, (guint) bufsz); + return NULL; + } + + /* move pointer to data */ + buf += sizeof(header); + item->bytes = g_bytes_new (buf, hdrsz); + g_debug ("adding 0x%04x (%s) with size 0x%04x", + item->tag, + fu_synaprom_firmware_tag_to_string (item->tag), + hdrsz); + g_ptr_array_add (firmware, g_steal_pointer (&item)); + + /* next item */ + buf += hdrsz; + } + return g_steal_pointer (&firmware); +} + +GBytes * +fu_synaprom_firmware_get_bytes_by_tag (GPtrArray *firmware, guint16 tag, GError **error) +{ + for (guint i = 0; i < firmware->len; i++) { + FuSynapromFirmwareItem *item = g_ptr_array_index (firmware, i); + if (item->tag == tag) + return g_bytes_ref (item->bytes); + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "no item with tag 0x%04x", tag); + return NULL; +} + +GBytes * +fu_synaprom_firmware_generate (void) +{ + GByteArray *blob = g_byte_array_new (); + const guint8 data[] = { 'R', 'H' }; + FuSynapromFirmwareMfwHeader hdr = { + .product = GUINT32_TO_LE(0x41), + .id = GUINT32_TO_LE(0xff), + .buildtime = GUINT32_TO_LE(0xff), + .buildnum = GUINT32_TO_LE(0xff), + .vmajor = 10, + .vminor = 1, + }; + guint16 tag1 = GUINT16_TO_LE(FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER); + guint16 tag2 = GUINT16_TO_LE(FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD); + guint32 hdrsz = GUINT32_TO_LE(sizeof(hdr)); + guint32 datasz = GUINT32_TO_LE(sizeof(data)); + + /* add header */ + g_byte_array_append (blob, (const guint8 *) &tag1, sizeof(tag1)); + g_byte_array_append (blob, (const guint8 *) &hdrsz, sizeof(hdrsz)); + g_byte_array_append (blob, (const guint8 *) &hdr, sizeof(hdr)); + + /* add payload */ + g_byte_array_append (blob, (const guint8 *) &tag2, sizeof(tag2)); + g_byte_array_append (blob, (const guint8 *) &datasz, sizeof(datasz)); + g_byte_array_append (blob, data, sizeof(data)); + + /* add signature */ + for (guint i = 0; i < FU_SYNAPROM_FIRMWARE_SIGSIZE; i++) { + guint8 sig = 0xff; + g_byte_array_append (blob, &sig, 1); + } + return g_byte_array_free_to_bytes (blob); +} diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-firmware.h fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-firmware.h --- fwupd-1.0.6/plugins/synaptics-prometheus/fu-synaprom-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/fu-synaprom-firmware.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Synaptics Inc + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_SYNAPROM_FIRMWARE_TAG_MFW_HEADER 0x0001 +#define FU_SYNAPROM_FIRMWARE_TAG_MFW_PAYLOAD 0x0002 +#define FU_SYNAPROM_FIRMWARE_TAG_CFG_HEADER 0x0003 +#define FU_SYNAPROM_FIRMWARE_TAG_CFG_PAYLOAD 0x0004 + +/* le */ +typedef struct __attribute__((packed)) { + guint32 product; + guint32 id; /* MFW unique id used for compat verification */ + guint32 buildtime; /* unix-style build time */ + guint32 buildnum; /* build number */ + guint8 vmajor; /* major version */ + guint8 vminor; /* minor version */ + guint8 unused[6]; +} FuSynapromFirmwareMfwHeader; + +/* le */ +typedef struct __attribute__((packed)) { + guint32 product; + guint32 id1; /* verification ID */ + guint32 id2; /* verification ID */ + guint16 version; /* config version */ + guint8 unused[2]; +} FuSynapromFirmwareCfgHeader; + +GPtrArray *fu_synaprom_firmware_new (GBytes *blob, + GError **error); +GBytes *fu_synaprom_firmware_get_bytes_by_tag (GPtrArray *firmware, + guint16 tag, + GError **error); +GBytes *fu_synaprom_firmware_generate (void); diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/meson.build fwupd-1.2.10/plugins/synaptics-prometheus/meson.build --- fwupd-1.0.6/plugins/synaptics-prometheus/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,75 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginSynapticsPrometheus"'] + +install_data(['synaptics-prometheus.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_synaptics_prometheus', + fu_hash, + sources : [ + 'fu-plugin-synaptics-prometheus.c', + 'fu-synaprom-common.c', + 'fu-synaprom-config.c', + 'fu-synaprom-device.c', + 'fu-synaprom-firmware.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'data') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'synaptics-prometheus-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-synaprom-common.c', + 'fu-synaprom-config.c', + 'fu-synaprom-device.c', + 'fu-synaprom-firmware.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('synaptics-prometheus-self-test', e) + + # for fuzzing + executable( + 'synaptics-prometheus-dump', + sources : [ + 'fu-dump.c', + 'fu-synaprom-firmware.c', + ], + include_directories : [ + include_directories('../..'), + ], + dependencies : [ + gio, + ], + c_args : cargs + ) +endif diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/README.md fwupd-1.2.10/plugins/synaptics-prometheus/README.md --- fwupd-1.0.6/plugins/synaptics-prometheus/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,26 @@ +Synaptics Prometheus +==================== + +Introduction +------------ + +This plugin can flash the firmware on the Synaptics Prometheus fingerprint readers. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format. The binary file has a vendor-specific header +that is used when flashing the image. + +This plugin supports the following protocol ID: + + * com.synaptics.prometheus + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_06CB&PID_00A9&REV_0001` + * `USB\VID_06CB&PID_00A9` diff -Nru fwupd-1.0.6/plugins/synaptics-prometheus/synaptics-prometheus.quirk fwupd-1.2.10/plugins/synaptics-prometheus/synaptics-prometheus.quirk --- fwupd-1.0.6/plugins/synaptics-prometheus/synaptics-prometheus.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/synaptics-prometheus/synaptics-prometheus.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,7 @@ +[DeviceInstanceId=USB\VID_06CB&PID_00A9] +Plugin = synaptics_prometheus +InstallDuration = 2 + +[DeviceInstanceId=USB\VID_06CB&PID_00BD] +Plugin = synaptics_prometheus +InstallDuration = 2 diff -Nru fwupd-1.0.6/plugins/test/fu-plugin-test.c fwupd-1.2.10/plugins/test/fu-plugin-test.c --- fwupd-1.0.6/plugins/test/fu-plugin-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/test/fu-plugin-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" struct FuPluginData { @@ -31,6 +15,11 @@ void fu_plugin_init (FuPlugin *plugin) { + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "build-hash") == 0) + fu_plugin_set_build_hash (plugin, "invalid"); + else + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.acme.test"); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); g_debug ("init"); } @@ -56,7 +45,7 @@ fu_device_set_vendor (device, "ACME Corp."); fu_device_set_vendor_id (device, "USB:0x046D"); fu_device_set_version_bootloader (device, "0.1.2"); - fu_device_set_version (device, "1.2.2"); + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_version_lowest (device, "1.2.0"); if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "registration") == 0) { fu_plugin_device_register (plugin, device); @@ -69,6 +58,33 @@ } } fu_plugin_device_add (plugin, device); + + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "composite") == 0) { + g_autoptr(FuDevice) child1 = NULL; + g_autoptr(FuDevice) child2 = NULL; + + child1 = fu_device_new (); + fu_device_set_physical_id (child1, "fake"); + fu_device_set_logical_id (child1, "child1"); + fu_device_add_guid (child1, "7fddead7-12b5-4fb9-9fa0-6d30305df755"); + fu_device_set_name (child1, "Module1"); + fu_device_set_version (child1, "1", FWUPD_VERSION_FORMAT_PLAIN); + fu_device_add_parent_guid (child1, "b585990a-003e-5270-89d5-3705a17f9a43"); + fu_device_add_flag (child1, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_plugin_device_add (plugin, child1); + + child2 = fu_device_new (); + fu_device_set_physical_id (child2, "fake"); + fu_device_set_logical_id (child2, "child2"); + fu_device_add_guid (child2, "b8fe6b45-8702-4bcd-8120-ef236caac76f"); + fu_device_set_name (child2, "Module2"); + fu_device_set_version (child2, "10", FWUPD_VERSION_FORMAT_PLAIN); + fu_device_add_parent_guid (child2, "b585990a-003e-5270-89d5-3705a17f9a43"); + fu_device_add_flag (child2, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_plugin_device_add (plugin, child2); + + } + return TRUE; } @@ -108,7 +124,9 @@ FwupdInstallFlags flags, GError **error) { - if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "fail") == 0) { + const gchar *test = g_getenv ("FWUPD_PLUGIN_TEST"); + gboolean requires_activation = g_strcmp0 (test, "requires-activation") == 0; + if (g_strcmp0 (test, "fail") == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -131,12 +149,45 @@ fu_device_set_progress (device, i); } + /* composite test, upgrade composite devices */ + if (g_strcmp0 (test, "composite") == 0) { + if (g_strcmp0 (fu_device_get_logical_id (device), "child1") == 0) { + fu_device_set_version (device, "2", FWUPD_VERSION_FORMAT_PLAIN); + return TRUE; + } else if (g_strcmp0 (fu_device_get_logical_id (device), "child2") == 0) { + fu_device_set_version (device, "11", FWUPD_VERSION_FORMAT_PLAIN); + return TRUE; + } + } + /* upgrade, or downgrade */ - if (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) { - fu_device_set_version (device, "1.2.2"); + if (requires_activation) { + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); } else { - fu_device_set_version (device, "1.2.3"); + if (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) { + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); + } else { + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + } + } + + /* do this all over again */ + if (g_strcmp0 (test, "another-write-required") == 0) { + g_unsetenv ("FWUPD_PLUGIN_TEST"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); } + + /* for the self tests only */ + fu_device_set_metadata_integer (device, "nr-update", + fu_device_get_metadata_integer (device, "nr-update") + 1); + + return TRUE; +} + +gboolean +fu_plugin_activate (FuPlugin *plugin, FuDevice *device, GError **error) +{ + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); return TRUE; } @@ -147,3 +198,31 @@ fu_device_set_update_error (device, NULL); return TRUE; } + +gboolean +fu_plugin_composite_prepare (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "composite") == 0) { + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + fu_device_set_metadata (device, "frimbulator", "1"); + } + } + return TRUE; +} + +gboolean +fu_plugin_composite_cleanup (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + if (g_strcmp0 (g_getenv ("FWUPD_PLUGIN_TEST"), "composite") == 0) { + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + fu_device_set_metadata (device, "frombulator", "1"); + } + } + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/test/meson.build fwupd-1.2.10/plugins/test/meson.build --- fwupd-1.0.6/plugins/test/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/test/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -6,6 +6,7 @@ endif shared_module('fu_plugin_test', + fu_hash, sources : [ 'fu-plugin-test.c', ], @@ -16,6 +17,9 @@ ], install : install_dummy, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.0.6/plugins/test/README.md fwupd-1.2.10/plugins/test/README.md --- fwupd-1.0.6/plugins/test/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/test/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -5,3 +5,9 @@ ------------ This plugin is used when running the self tests in the fwupd project. + +GUID Generation +--------------- + +The devices created by this plugin use hardcoded GUIDs that do not correspond +to any kind of DeviceInstanceId values. diff -Nru fwupd-1.0.6/plugins/thunderbolt/fu-plugin-thunderbolt.c fwupd-1.2.10/plugins/thunderbolt/fu-plugin-thunderbolt.c --- fwupd-1.0.6/plugins/thunderbolt/fu-plugin-thunderbolt.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/fu-plugin-thunderbolt.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Christian J. Kellner * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -27,20 +12,22 @@ #include #include #include +#include -#include -#include -#include - -#include "fu-plugin-thunderbolt.h" #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" #include "fu-thunderbolt-image.h" #ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop #endif +#define TBT_NVM_RETRY_TIMEOUT 200 /* ms */ +#define FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT 60000 /* ms */ + typedef void (*UEventNotify) (FuPlugin *plugin, GUdevDevice *udevice, const gchar *action, @@ -48,16 +35,6 @@ struct FuPluginData { GUdevClient *udev; - - /* in the case we are updating */ - UEventNotify update_notify; - gpointer update_data; - - /* the timeout we wait for the device - * to be updated to re-appear, in ms. - * defaults to: - * FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT_MS */ - guint timeout; }; static gchar * @@ -77,13 +54,13 @@ return fu_plugin_thunderbolt_gen_id_from_syspath (syspath); } -static guint64 +static gboolean udev_device_get_sysattr_guint64 (GUdevDevice *device, const gchar *name, + guint64 *val_out, GError **error) { const gchar *sysfs; - guint64 val; sysfs = g_udev_device_get_sysfs_attr (device, name); if (sysfs == NULL) { @@ -91,19 +68,19 @@ FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed get id %s for %s", name, sysfs); - return 0x0; + return FALSE; } - val = g_ascii_strtoull (sysfs, NULL, 16); - if (val == 0x0) { + *val_out = g_ascii_strtoull (sysfs, NULL, 16); + if (*val_out == 0x0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to parse %s", sysfs); - return 0x0; + return FALSE; } - return val; + return TRUE; } static guint16 @@ -112,11 +89,10 @@ GError **error) { - guint64 id; + guint64 id = 0; - id = udev_device_get_sysattr_guint64 (device, name, error); - if (id == 0x0) - return id; + if (!udev_device_get_sysattr_guint64 (device, name, &id, error)) + return 0x0; if (id > G_MAXUINT16) { g_set_error (error, @@ -182,40 +158,80 @@ return NULL; } +static gchar * +fu_plugin_thunderbolt_parse_version (const gchar *version_raw) +{ + g_auto(GStrv) split = NULL; + if (version_raw == NULL) + return NULL; + split = g_strsplit (version_raw, ".", -1); + if (g_strv_length (split) != 2) + return NULL; + return g_strdup_printf ("%02x.%02x", + (guint) g_ascii_strtoull (split[0], NULL, 16), + (guint) g_ascii_strtoull (split[1], NULL, 16)); +} + +static gchar * +fu_plugin_thunderbolt_udev_get_version (GUdevDevice *udevice) +{ + const gchar *version = NULL; + + for (guint i = 0; i < 50; i++) { + version = g_udev_device_get_sysfs_attr (udevice, "nvm_version"); + if (version != NULL) + break; + g_debug ("Attempt %u: Failed to read NVM version", i); + if (errno != EAGAIN) + break; + g_usleep (TBT_NVM_RETRY_TIMEOUT * 1000); + } + + return fu_plugin_thunderbolt_parse_version (version); +} + static gboolean fu_plugin_thunderbolt_is_native (GUdevDevice *udevice, gboolean *is_native, GError **error) { + gsize nr_chunks; g_autoptr(GFile) nvmem = NULL; g_autoptr(GBytes) controller_fw = NULL; - gchar *content; - gsize length; + g_autoptr(GInputStream) istr = NULL; nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, TRUE, error); if (nvmem == NULL) return FALSE; - if (!g_file_load_contents (nvmem, NULL, &content, &length, NULL, error)) + /* read just enough bytes to read the status byte */ + nr_chunks = (FU_TBT_OFFSET_NATIVE + FU_TBT_CHUNK_SZ - 1) / FU_TBT_CHUNK_SZ; + istr = G_INPUT_STREAM (g_file_read (nvmem, NULL, error)); + if (istr == NULL) + return FALSE; + controller_fw = g_input_stream_read_bytes (istr, + nr_chunks * FU_TBT_CHUNK_SZ, + NULL, error); + if (controller_fw == NULL) return FALSE; - controller_fw = g_bytes_new_take (content, length); - - return fu_plugin_thunderbolt_controller_is_native (controller_fw, - is_native, - error); + return fu_thunderbolt_image_controller_is_native (controller_fw, + is_native, + error); } -static gchar * -fu_plugin_thunderbolt_parse_version (const gchar *version_raw) +static gboolean +fu_plugin_thunderbolt_can_update (GUdevDevice *udevice) { - g_auto(GStrv) split = NULL; - if (version_raw == NULL) - return NULL; - split = g_strsplit (version_raw, ".", -1); - if (g_strv_length (split) != 2) - return NULL; - return g_strdup_printf ("%02x.%02x", - (guint) g_ascii_strtoull (split[0], NULL, 16), - (guint) g_ascii_strtoull (split[1], NULL, 16)); + g_autoptr(GError) nvmem_error = NULL; + g_autoptr(GFile) non_active_nvmem = NULL; + + non_active_nvmem = fu_plugin_thunderbolt_find_nvmem (udevice, FALSE, + &nvmem_error); + if (non_active_nvmem == NULL) { + g_debug ("%s", nvmem_error->message); + return FALSE; + } + + return TRUE; } static void @@ -225,7 +241,6 @@ const gchar *name; const gchar *uuid; const gchar *vendor; - const gchar *version_raw; const gchar *devpath; const gchar *devtype; gboolean is_host; @@ -238,7 +253,9 @@ g_autofree gchar *vendor_id = NULL; g_autofree gchar *device_id = NULL; g_autoptr(FuDevice) dev = NULL; - g_autoptr(GError) error = NULL; + g_autoptr(GError) error_vid = NULL; + g_autoptr(GError) error_did = NULL; + g_autoptr(GError) error_setup = NULL; uuid = g_udev_device_get_sysfs_attr (device, "unique_id"); if (uuid == NULL) { @@ -264,28 +281,29 @@ return; } - vid = fu_plugin_thunderbolt_udev_get_id (device, "vendor", &error); + vid = fu_plugin_thunderbolt_udev_get_id (device, "vendor", &error_vid); if (vid == 0x0) - g_warning ("failed to get Vendor ID: %s", error->message); + g_warning ("failed to get Vendor ID: %s", error_vid->message); - did = fu_plugin_thunderbolt_udev_get_id (device, "device", &error); + did = fu_plugin_thunderbolt_udev_get_id (device, "device", &error_did); if (did == 0x0) - g_warning ("failed to get Device ID: %s", error->message); + g_warning ("failed to get Device ID: %s", error_did->message); dev = fu_device_new (); - /* test for safe mode */ is_host = fu_plugin_thunderbolt_is_host (device); - version_raw = g_udev_device_get_sysfs_attr (device, "nvm_version"); - version = fu_plugin_thunderbolt_parse_version (version_raw); + + version = fu_plugin_thunderbolt_udev_get_version (device); + /* test for safe mode */ if (is_host && version == NULL) { + g_autoptr(GError) error_local = NULL; g_autofree gchar *test_safe = NULL; g_autofree gchar *safe_path = NULL; /* glib can't return a properly mapped -ENODATA but the * kernel only returns -ENODATA or -EAGAIN */ safe_path = g_build_path ("/", devpath, "nvm_version", NULL); - if (!g_file_get_contents (safe_path, &test_safe, NULL, &error) && - !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + if (!g_file_get_contents (safe_path, &test_safe, NULL, &error_local) && + !g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_warning ("%s is in safe mode -- VID/DID will " "need to be set by another plugin", devpath); @@ -298,24 +316,34 @@ is_safemode ? "True" : "False"); } if (!is_safemode) { - if (is_host) { - if (!fu_plugin_thunderbolt_is_native (device, &is_native, &error)) { - g_warning ("failed to get native mode status: %s", error->message); - return; + if (fu_plugin_thunderbolt_can_update (device)) { + if (is_host) { + g_autoptr(GError) native_error = NULL; + if (!fu_plugin_thunderbolt_is_native (device, + &is_native, + &native_error)) { + g_warning ("failed to get native mode status: %s", + native_error->message); + return; + } + fu_plugin_add_report_metadata (plugin, + "ThunderboltNative", + is_native ? "True" : "False"); } - fu_plugin_add_report_metadata (plugin, - "ThunderboltNative", - is_native ? "True" : "False"); + vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); + device_id = g_strdup_printf ("TBT-%04x%04x%s", + (guint) vid, + (guint) did, + is_native ? "-native" : ""); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_set_update_error (dev, "Missing non-active nvmem"); } - vendor_id = g_strdup_printf ("TBT:0x%04X", (guint) vid); - device_id = g_strdup_printf ("TBT-%04x%04x%s", - (guint) vid, - (guint) did, - is_native ? "-native" : ""); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); + } else { + fu_device_set_update_error (dev, "Device is in safe mode"); } - fu_device_set_platform_id (dev, uuid); + fu_device_set_physical_id (dev, uuid); fu_device_set_metadata (dev, "sysfs-path", devpath); name = g_udev_device_get_sysfs_attr (device, "device_name"); @@ -335,20 +363,31 @@ fu_device_add_icon (dev, "audio-card"); } + fu_device_set_quirks (dev, fu_plugin_get_quirks (plugin)); vendor = g_udev_device_get_sysfs_attr (device, "vendor_name"); if (vendor != NULL) fu_device_set_vendor (dev, vendor); if (vendor_id != NULL) fu_device_set_vendor_id (dev, vendor_id); if (device_id != NULL) - fu_device_add_guid (dev, device_id); + fu_device_add_instance_id (dev, device_id); if (version != NULL) - fu_device_set_version (dev, version); + fu_device_set_version (dev, version, FWUPD_VERSION_FORMAT_PAIR); if (is_host) fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); + /* we never open the device, so convert the instance IDs */ + if (!fu_device_setup (dev, &error_setup)) { + g_warning ("failed to setup: %s", error_setup->message); + return; + } fu_plugin_cache_add (plugin, id, dev); fu_plugin_device_add (plugin, dev); + + /* inhibit the idle sleep of the daemon */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE, + "thunderbolt requires device wakeup"); } static void @@ -366,6 +405,7 @@ * power on supported devices even when in low power mode -- * this will happen in coldplug_prepare and prepare_for_update */ if (fu_plugin_thunderbolt_is_host (device) && + !fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG) && fu_device_get_metadata_boolean (dev, FU_DEVICE_METADATA_TBT_CAN_FORCE_POWER)) { g_debug ("ignoring remove event as force powered"); return; @@ -379,7 +419,7 @@ fu_plugin_thunderbolt_change (FuPlugin *plugin, GUdevDevice *device) { FuDevice *dev; - const gchar *version; + g_autofree gchar *version = NULL; g_autofree gchar *id = NULL; id = fu_plugin_thunderbolt_gen_id (device); @@ -390,8 +430,8 @@ return; } - version = g_udev_device_get_sysfs_attr (device, "nvm_version"); - fu_device_set_version (dev, version); + version = fu_plugin_thunderbolt_udev_get_version (device); + fu_device_set_version (dev, version, FWUPD_VERSION_FORMAT_PAIR); } static gboolean @@ -401,20 +441,12 @@ gpointer user_data) { FuPlugin *plugin = (FuPlugin *) user_data; - FuPluginData *data = fu_plugin_get_data (plugin); if (action == NULL) return TRUE; g_debug ("uevent for %s: %s", g_udev_device_get_sysfs_path (device), action); - if (data->update_notify != NULL) { - g_debug ("using update notify handler for uevent"); - - data->update_notify (plugin, device, action, data->update_data); - return TRUE; - } - if (g_str_equal (action, "add")) { fu_plugin_thunderbolt_add (plugin, device); } else if (g_str_equal (action, "remove")) { @@ -444,10 +476,7 @@ return VALIDATION_FAILED; controller_fw = g_bytes_new_take (content, length); - - return fu_plugin_thunderbolt_validate_image (controller_fw, - blob_fw, - error); + return fu_thunderbolt_image_validate (controller_fw, blob_fw, error); } static gboolean @@ -478,7 +507,7 @@ if (n < 1 && errno != EINTR) { g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), - "could write to 'nvm_authenticate': %s", + "could not write to 'nvm_authenticate': %s", g_strerror (errno)); (void) close (fd); return FALSE; @@ -489,7 +518,7 @@ if (r < 0 && errno != EINTR) { g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), - "could close 'nvm_authenticate': %s", + "could not close 'nvm_authenticate': %s", g_strerror (errno)); return FALSE; } @@ -555,192 +584,6 @@ return g_output_stream_close (os, NULL, error); } -typedef struct UpdateData { - - gboolean have_device; - GMainLoop *mainloop; - const gchar *target_uuid; - guint timeout_id; - - GHashTable *changes; -} UpdateData; - -static gboolean -on_wait_for_device_timeout (gpointer user_data) -{ - UpdateData *data = (UpdateData *) user_data; - g_main_loop_quit (data->mainloop); - data->timeout_id = 0; - return FALSE; -} - -static void -on_wait_for_device_added (FuPlugin *plugin, - GUdevDevice *device, - UpdateData *up_data) -{ - FuDevice *dev; - const gchar *uuid; - const gchar *path; - const gchar *version; - g_autofree gchar *id = NULL; - - uuid = g_udev_device_get_sysfs_attr (device, "unique_id"); - if (uuid == NULL) - return; - - dev = g_hash_table_lookup (up_data->changes, uuid); - if (dev == NULL) { - /* a previously unknown device, add it via - * the normal way */ - fu_plugin_thunderbolt_add (plugin, device); - return; - } - - /* ensure the device path is correct */ - path = g_udev_device_get_sysfs_path (device); - fu_device_set_metadata (dev, "sysfs-path", path); - - /* make sure the version is correct, might have changed - * after update. */ - version = g_udev_device_get_sysfs_attr (device, "nvm_version"); - fu_device_set_version (dev, version); - - id = fu_plugin_thunderbolt_gen_id (device); - fu_plugin_cache_add (plugin, id, dev); - - g_hash_table_remove (up_data->changes, uuid); - - /* check if this device is the target*/ - if (g_str_equal (uuid, up_data->target_uuid)) { - up_data->have_device = TRUE; - g_debug ("target (%s) re-appeared", uuid); - g_main_loop_quit (up_data->mainloop); - } -} - -static void -on_wait_for_device_removed (FuPlugin *plugin, - GUdevDevice *device, - UpdateData *up_data) -{ - g_autofree gchar *id = NULL; - FuDevice *dev; - const gchar *uuid; - - id = fu_plugin_thunderbolt_gen_id (device); - dev = fu_plugin_cache_lookup (plugin, id); - - if (dev == NULL) - return; - - fu_plugin_cache_remove (plugin, id); - uuid = fu_device_get_platform_id (dev); - g_hash_table_insert (up_data->changes, - (gpointer) uuid, - g_object_ref (dev)); - - /* check if this device is the target */ - if (g_str_equal (uuid, up_data->target_uuid)) { - up_data->have_device = FALSE; - g_debug ("target (%s) disappeared", uuid); - } -} - -static void -on_wait_for_device_notify (FuPlugin *plugin, - GUdevDevice *device, - const char *action, - gpointer user_data) -{ - UpdateData *up_data = (UpdateData *) user_data; - - /* nb: action cannot be NULL since we are only called from - * udev_event_cb, which ensures that */ - if (g_str_equal (action, "add")) { - on_wait_for_device_added (plugin, device, up_data); - } else if (g_str_equal (action, "remove")) { - on_wait_for_device_removed (plugin, device, up_data); - } else if (g_str_equal (action, "change")) { - fu_plugin_thunderbolt_change (plugin, device); - } -} - -static void -remove_leftover_devices (gpointer key, - gpointer value, - gpointer user_data) -{ - FuPlugin *plugin = FU_PLUGIN (user_data); - FuDevice *dev = FU_DEVICE (value); - const gchar *syspath = fu_device_get_metadata (dev, "sysfs-path"); - g_autofree gchar *id = NULL; - - id = fu_plugin_thunderbolt_gen_id_from_syspath (syspath); - - fu_plugin_cache_remove (plugin, id); - fu_plugin_device_remove (plugin, dev); -} - -static gboolean -fu_plugin_thunderbolt_wait_for_device (FuPlugin *plugin, - FuDevice *dev, - GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - UpdateData up_data = { TRUE, }; - g_autoptr(GMainLoop) mainloop = NULL; - g_autoptr(GHashTable) changes = NULL; - - up_data.mainloop = mainloop = g_main_loop_new (NULL, FALSE); - up_data.target_uuid = fu_device_get_platform_id (dev); - - /* this will limit the maximum amount of time we wait for - * the device (i.e. 'dev') to re-appear. */ - up_data.timeout_id = g_timeout_add (data->timeout, - on_wait_for_device_timeout, - &up_data); - - /* this will capture the device added, removed, changed - * signals while we are updating. */ - data->update_data = &up_data; - data->update_notify = on_wait_for_device_notify; - - changes = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); - up_data.changes = changes; - - /* now we wait ... */ - g_main_loop_run (mainloop); - - /* restore original udev change handler */ - data->update_data = NULL; - data->update_notify = NULL; - - if (up_data.timeout_id > 0) - g_source_remove (up_data.timeout_id); - - if (!up_data.have_device) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "timed out while waiting for device"); - return FALSE; - } - - g_hash_table_foreach (changes, remove_leftover_devices, plugin); - - return TRUE; -} - -/* internal interface */ - -void -fu_plugin_thunderbolt_set_timeout (FuPlugin *plugin, guint timeout_ms) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - data->timeout = timeout_ms; -} - /* virtual functions */ void @@ -749,11 +592,14 @@ FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); const gchar *subsystems[] = { "thunderbolt", NULL }; + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.intel.thunderbolt"); data->udev = g_udev_client_new (subsystems); g_signal_connect (data->udev, "uevent", G_CALLBACK (udev_uevent_cb), plugin); - data->timeout = FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT_MS; + /* dell-dock plugin uses a slower bus for flashing */ + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_BETTER_THAN, "dell_dock"); } void @@ -802,10 +648,10 @@ { FuPluginData *data = fu_plugin_get_data (plugin); const gchar *devpath; - guint64 status; g_autoptr(GUdevDevice) udevice = NULL; g_autoptr(GError) error_local = NULL; - gboolean force = (flags & FWUPD_INSTALL_FLAG_FORCE) != 0; + gboolean install_force = (flags & FWUPD_INSTALL_FLAG_FORCE) != 0; + gboolean device_ignore_validation = fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_IGNORE_VALIDATION); FuPluginValidation validation; devpath = fu_device_get_metadata (dev, "sysfs-path"); @@ -837,7 +683,7 @@ default: break; } - if (!force) { + if (!install_force && !device_ignore_validation) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -850,41 +696,65 @@ } fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); - if (!fu_plugin_thunderbolt_write_firmware (dev, udevice, blob_fw, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "could not write firmware to thunderbolt device at %s: %s", - devpath, error_local->message); + if (!fu_plugin_thunderbolt_write_firmware (dev, udevice, blob_fw, error)) { + g_prefix_error (error, + "could not write firmware to thunderbolt device at %s: ", + devpath); return FALSE; } - if (!fu_plugin_thunderbolt_trigger_update (udevice, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Could not start thunderbolt device upgrade: %s", - error_local->message); + if (!fu_plugin_thunderbolt_trigger_update (udevice, error)) { + g_prefix_error (error, "could not start thunderbolt device upgrade: "); return FALSE; } fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); + fu_device_set_remove_delay (dev, FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + + return TRUE; +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, + FuDevice *dev, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + const gchar *devpath; + const gchar *attribute; + guint64 status; + g_autoptr(GUdevDevice) udevice = NULL; - /* the device will disappear and we need to wait until it reappears, - * and then check if we find an error */ - if (!fu_plugin_thunderbolt_wait_for_device (plugin, dev, &error_local)) { + devpath = fu_device_get_metadata (dev, "sysfs-path"); + udevice = g_udev_client_query_by_sysfs_path (data->udev, devpath); + if (udevice == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, - "could not detect device after update: %s", - error_local->message); + "could not find thunderbolt device at %s", + devpath); return FALSE; } /* now check if the update actually worked */ - status = udev_device_get_sysattr_guint64 (udevice, - "nvm_authenticate", - &error_local); + attribute = g_udev_device_get_sysfs_attr (udevice, "nvm_authenticate"); + if (attribute == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to find nvm_authenticate attribute for %s", + fu_device_get_name (dev)); + return FALSE; + } + status = g_ascii_strtoull (attribute, NULL, 16); + if (status == G_MAXUINT64 && errno == ERANGE) { + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errno), + "failed to read 'nvm_authenticate: %s", + g_strerror (errno)); + return FALSE; + } /* anything else then 0x0 means we got an error */ if (status != 0x0) { diff -Nru fwupd-1.0.6/plugins/thunderbolt/fu-plugin-thunderbolt.h fwupd-1.2.10/plugins/thunderbolt/fu-plugin-thunderbolt.h --- fwupd-1.0.6/plugins/thunderbolt/fu-plugin-thunderbolt.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/fu-plugin-thunderbolt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Christian J. Kellner - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#ifndef __FU_PLUGIN_THUNDERBOLT_H__ -#define __FU_PLUGIN_THUNDERBOLT_H__ - -#include "fu-plugin.h" - -#define FU_PLUGIN_THUNDERBOLT_UPDATE_TIMEOUT_MS 60 * 1000 - -void fu_plugin_thunderbolt_set_timeout (FuPlugin *plugin, - guint timeout_ms); - -#endif /* __FU_PLUGIN_THUNDERBOLT_H__ */ diff -Nru fwupd-1.0.6/plugins/thunderbolt/fu-self-test.c fwupd-1.2.10/plugins/thunderbolt/fu-self-test.c --- fwupd-1.0.6/plugins/thunderbolt/fu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,11 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Christian J. Kellner * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#define _GNU_SOURCE 1 #include #include #include @@ -40,7 +24,6 @@ #include #include "fu-plugin-private.h" -#include "fu-plugin-thunderbolt.h" #include "fu-thunderbolt-image.h" #include "fu-test.h" @@ -91,6 +74,7 @@ const char *name; /* sysfs: device_name */ const char *id; /* sysfs: device */ const char *nvm_version; + const char *nvm_parsed_version; int delay_ms; @@ -188,8 +172,10 @@ g_slice_free (MockTree, tree); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC (MockTree, mock_tree_free); - +#pragma clang diagnostic pop static GPtrArray * mock_tree_init_children (MockTree *node, int *id) @@ -470,7 +456,7 @@ { SyncContext *ctx = (SyncContext *) user_data; MockTree *tree = ctx->tree; - const gchar *uuid = fu_device_get_platform_id (device); + const gchar *uuid = fu_device_get_physical_id (device); MockTree *target; target = (MockTree *) mock_tree_find_uuid (tree, uuid); @@ -491,7 +477,7 @@ { SyncContext *ctx = (SyncContext *) user_data; MockTree *tree = ctx->tree; - const gchar *uuid = fu_device_get_platform_id (device); + const gchar *uuid = fu_device_get_physical_id (device); MockTree *target; target = (MockTree *) mock_tree_find_uuid (tree, uuid); @@ -551,7 +537,7 @@ { AttachContext *ctx = (AttachContext *) user_data; MockTree *tree = ctx->tree; - const gchar *uuid = fu_device_get_platform_id (device); + const gchar *uuid = fu_device_get_physical_id (device); MockTree *target; target = (MockTree *) mock_tree_find_uuid (tree, uuid); @@ -561,7 +547,7 @@ return; } - target->fu_device = g_object_ref (device); + g_set_object (&target->fu_device, device); if (mock_tree_all (tree, mock_tree_node_have_fu_device, NULL)) { ctx->complete = TRUE; @@ -695,7 +681,10 @@ g_free (ctx); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC (UpdateContext, update_context_free); +#pragma clang diagnostic pop static gboolean reattach_tree (gpointer user_data) @@ -802,19 +791,22 @@ .name = "Laptop", .id = "0x23", - .nvm_version = "20.0", + .nvm_version = "20.2", + .nvm_parsed_version = "20.02", .children = (MockDevice[]) { { .name = "Thunderbolt Cable", .id = "0x24", .nvm_version = "20.0", + .nvm_parsed_version = "20.00", .children = (MockDevice[]) { { .name = "Thunderbolt Dock", .id = "0x25", .nvm_version = "10.0", + .nvm_parsed_version = "10.00", }, { NULL, } @@ -823,6 +815,7 @@ .name = "Thunderbolt Cable", .id = "0x24", .nvm_version = "23.0", + .nvm_parsed_version = "23.00", .children = (MockDevice[]) { { @@ -830,6 +823,7 @@ .id = "0x26", .nvm_version = "5.0", + .nvm_parsed_version = "05.00", }, { NULL, } }, @@ -878,12 +872,14 @@ { TestFlags flags = GPOINTER_TO_UINT(params); gboolean ret; + g_autofree gchar *sysfs = NULL; g_autoptr(GError) error = NULL; tt->bed = umockdev_testbed_new (); g_assert_nonnull (tt->bed); - g_debug ("mock sysfs at %s", umockdev_testbed_get_sys_dir (tt->bed)); + sysfs = umockdev_testbed_get_sys_dir (tt->bed); + g_debug ("mock sysfs at %s", sysfs); tt->plugin = fu_plugin_new (); g_assert_nonnull (tt->plugin); @@ -903,8 +899,7 @@ } if (!umockdev_in_mock_environment ()) { - g_warning ("Need to run within umockdev wrapper (umockdev-wrapper %s)!", - program_invocation_short_name); + g_warning ("Need to run with umockdev-wrapper"); return; } @@ -1050,40 +1045,40 @@ g_assert_nonnull (bad_data); /* now for some testing ... this should work */ - val = fu_plugin_thunderbolt_validate_image (ctl_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, fwi_data, &error); g_assert_no_error (error); g_assert_cmpint (val, ==, VALIDATION_PASSED); /* these all should fail */ /* valid controller, bad update data */ - val = fu_plugin_thunderbolt_validate_image (ctl_data, ctl_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, ctl_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [ctl, ctl]: %s", error->message); g_clear_error (&error); - val = fu_plugin_thunderbolt_validate_image (ctl_data, bad_data, &error); + val = fu_thunderbolt_image_validate (ctl_data, bad_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [ctl, bad]: %s", error->message); g_clear_error (&error); /* bad controller data, valid update data */ - val = fu_plugin_thunderbolt_validate_image (fwi_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (fwi_data, fwi_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [fwi, fwi]: %s", error->message); g_clear_error (&error); - val = fu_plugin_thunderbolt_validate_image (bad_data, fwi_data, &error); + val = fu_thunderbolt_image_validate (bad_data, fwi_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [bad, fwi]: %s", error->message); g_clear_error (&error); /* both bad */ - val = fu_plugin_thunderbolt_validate_image (bad_data, bad_data, &error); + val = fu_thunderbolt_image_validate (bad_data, bad_data, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_READ); g_assert_cmpint (val, ==, VALIDATION_FAILED); g_debug ("expected image validation error [bad, bad]: %s", error->message); @@ -1136,7 +1131,16 @@ /* simulate an update, where the device goes away and comes back * after the time in the last parameter (given in ms) */ up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 1000); - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* we wait until the plugin has picked up all the + * subtree changes */ + ret = mock_tree_settle (tree, plugin); + g_assert_true (ret); + + ret = fu_plugin_runner_update_attach (plugin, tree->fu_device, &error); g_assert_no_error (error); g_assert_true (ret); @@ -1144,8 +1148,7 @@ g_debug ("version after update: %s", version_after); g_assert_cmpstr (version_after, ==, "42.23"); - /* we wait until the plugin has picked up all the - * subtree changes */ + /* make sure all pending events have happened */ ret = mock_tree_settle (tree, plugin); g_assert_true (ret); @@ -1177,14 +1180,9 @@ up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 1000); up_ctx->result = UPDATE_FAIL_DEVICE_INTERNAL; - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL); - g_assert_false (ret); - - /* version should *not* have changed */ - version_after = fu_device_get_version (tree->fu_device); - g_debug ("version after update: %s", version_after); - g_assert_cmpstr (version_after, ==, tree->device->nvm_version); + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); + g_assert_no_error (error); + g_assert_true (ret); /* we wait until the plugin has picked up all the * subtree changes, and make sure we still receive @@ -1192,6 +1190,19 @@ ret = mock_tree_settle (tree, plugin); g_assert_true (ret); + ret = fu_plugin_runner_update_attach (plugin, tree->fu_device, &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL); + g_assert_false (ret); + + /* make sure all pending events have happened */ + ret = mock_tree_settle (tree, plugin); + g_assert_true (ret); + + /* version should *not* have changed (but we get parsed version) */ + version_after = fu_device_get_version (tree->fu_device); + g_debug ("version after update: %s", version_after); + g_assert_cmpstr (version_after, ==, tree->device->nvm_parsed_version); + ret = mock_tree_all (tree, mock_tree_node_have_fu_device, NULL); g_assert_true (ret); } @@ -1217,52 +1228,16 @@ up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 1000); up_ctx->result = UPDATE_FAIL_DEVICE_NOSHOW; - /* lets make the plugin only wait a second for the device */ - fu_plugin_thunderbolt_set_timeout (plugin, 1000); - - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); - g_assert_false (ret); -} - -static void -test_update_fail_tooslow (ThunderboltTest *tt, gconstpointer user_data) -{ - FuPlugin *plugin = tt->plugin; - MockTree *tree = tt->tree; - GBytes *fw_data = tt->fw_data; - gboolean ret; - g_autoptr(GError) error = NULL; - g_autoptr(UpdateContext) up_ctx = NULL; - - /* test sanity check */ - g_assert_nonnull (tree); - g_assert_nonnull (fw_data); - - /* simulate an update, as in test_update_working, that is also working, - * but that takes longer then our timeout, i.e. set_timeout < last - * param in prepare_for_update. We will report an error, but we want - * to make sure that the device tree afterwards is still correct - */ - up_ctx = mock_tree_prepare_for_update (tree, plugin, "42.23", fw_data, 2000); - up_ctx->result = UPDATE_SUCCESS; - - /* lets make the plugin only wait half a second (1/4 of update time) */ - fu_plugin_thunderbolt_set_timeout (plugin, 500); - - ret = fu_plugin_runner_update (plugin, tree->fu_device, NULL, fw_data, 0, &error); - g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); - g_assert_false (ret); - - /* we wait until we see all devices again */ - ret = mock_tree_settle (tree, plugin); + ret = fu_plugin_runner_update (plugin, tree->fu_device, fw_data, 0, &error); + g_assert_no_error (error); g_assert_true (ret); + mock_tree_sync (tree, plugin, 500); + ret = mock_tree_all (tree, mock_tree_node_have_fu_device, NULL); - g_assert_true (ret); + g_assert_false (ret); } - int main (int argc, char **argv) { @@ -1313,12 +1288,5 @@ test_update_fail_nowshow, test_tear_down); - g_test_add ("/thunderbolt/update{failing-tooslow}", - ThunderboltTest, - TEST_INIT_FULL, - test_set_up, - test_update_fail_tooslow, - test_tear_down); - return g_test_run (); } diff -Nru fwupd-1.0.6/plugins/thunderbolt/fu-thunderbolt-image.c fwupd-1.2.10/plugins/thunderbolt/fu-thunderbolt-image.c --- fwupd-1.0.6/plugins/thunderbolt/fu-thunderbolt-image.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/fu-thunderbolt-image.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Intel Corporation. * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -54,6 +39,10 @@ guint ports; } FuThunderboltHwInfo; +enum { + DROM_ENTRY_MC = 0x6, +}; + static const FuThunderboltHwInfo * get_hw_info (guint16 id) { @@ -87,6 +76,12 @@ return pointer != 0 && pointer != 0xFFFFFF; } +static inline gboolean +valid_pd_pointer (guint32 pointer) +{ + return pointer != 0 && pointer != 0xFFFFFFFF; +} + /* returns NULL on error */ static GByteArray * read_location (const FuThunderboltFwLocation *location, @@ -250,6 +245,58 @@ } /* + * reads generic entries from DROM based on type field and fills + * location to point to the entry data if found. Returns TRUE if there + * was no error even if the entry was not found (location->offset is != 0 + * when entry was found). + */ +static gboolean +read_drom_entry_location (const FuThunderboltFwObject *fw, + guint8 type, + FuThunderboltFwLocation *location, + GError **error) +{ + const FuThunderboltFwLocation drom_len_loc = { .offset = 0x0E, .len = 2, .section = DROM_SECTION, .description = "DROM length" }; + FuThunderboltFwLocation drom_entry_loc = { .len = 2, .section = DROM_SECTION, .description = "DROM generic entry" }; + guint16 drom_size; + + if (!read_uint16 (&drom_len_loc, fw, &drom_size, error)) + return FALSE; + + drom_size &= 0x0FFF; + /* drom_size is size of DROM block except for identification + * section and crc32 so add them here */ + drom_size += 9 + 4; + + /* DROM entries start right after the identification section */ + drom_entry_loc.offset = 9 + 4 + 9; + + do { + g_autoptr(GByteArray) entry = NULL; + guint8 entry_type; + guint8 entry_length; + + entry = read_location (&drom_entry_loc, fw, error); + if (entry == NULL) + return FALSE; + + entry_length = entry->data[0]; + entry_type = entry->data[1] & 0x3F; + + /* generic entry (port bit is not set) */ + if ((entry->data[1] & (1 << 7)) == 0 && entry_type == type) { + location->len = entry_length - 2; + location->offset = drom_entry_loc.offset + 2; + return TRUE; + } + + drom_entry_loc.offset += entry_length; + } while (drom_entry_loc.offset < drom_size); + + return TRUE; +} + +/* * Takes a FwObject and fills its section array up * Assumes sections[DIGITAL_SECTION].offset is already set */ @@ -264,9 +311,7 @@ if (!read_uint32 (&drom_offset, fw, &offset, error)) return FALSE; fw->sections[DROM_SECTION] = offset + fw->sections[DIGITAL_SECTION]; - } - if (!is_host) { if (!read_uint32 (&arc_params_offset, fw, &offset, error)) return FALSE; fw->sections[ARC_PARAMS_SECTION] = offset + fw->sections[DIGITAL_SECTION]; @@ -389,6 +434,7 @@ { .offset = 0x129, .len = 1, .description = "Snk1" }, { .offset = 0x136, .len = 1, .description = "Src0", .mask = 0xF0 }, { .offset = 0xB6, .len = 1, .description = "PA/PB (USB2)", .mask = 0xC0 }, + { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }, { 0 }, @@ -402,6 +448,7 @@ { .offset = 0x13, .len = 1, .description = "PB", .mask = 0x44, .section = DRAM_UCODE_SECTION }, { .offset = 0x121, .len = 1, .description = "Snk0" }, { .offset = 0xB6, .len = 1, .description = "PA/PB (USB2)", .mask = 0xC0 }, + { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }, { 0 } }; @@ -414,6 +461,8 @@ { .offset = 0x136, .len = 1, .description = "Src0", .mask = 0xF0 }, { .offset = 0xB6, .len = 1, .description = "PA/PB (USB2)", .mask = 0xC0 }, { .offset = 0x5E, .len = 1, .description = "Aux", .mask = 0x0F }, + { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, + { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }, { 0 }, { .offset = 0x13, .len = 1, .description = "PB", .mask = 0xCC, .section = DRAM_UCODE_SECTION }, @@ -442,21 +491,93 @@ } } +/* + * Finds optional multi controller (MC) entry from controller DROM. + * Returns TRUE if the controller did not have MC entry or the + * controller and image MC entries match. In any other case FALSE is + * returned and error is set accordingly. + */ +static gboolean +compare_device_mc (const FuThunderboltFwObject *controller, + const FuThunderboltFwObject *image, + GError **error) +{ + FuThunderboltFwLocation image_mc_loc = { .section = DROM_SECTION, .description = "Multi Controller" }; + FuThunderboltFwLocation controller_mc_loc = image_mc_loc; + g_autoptr(GByteArray) controller_mc = NULL; + g_autoptr(GByteArray) image_mc = NULL; + + if (!read_drom_entry_location (controller, DROM_ENTRY_MC, + &controller_mc_loc, error)) + return FALSE; + + /* it is fine if the controller does not have MC entry */ + if (controller_mc_loc.offset == 0) + return TRUE; + + if (!read_drom_entry_location (image, DROM_ENTRY_MC, &image_mc_loc, error)) + return FALSE; + + if (image_mc_loc.offset == 0) { + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "firmware does not have multi controller entry"); + return FALSE; + } + if (controller_mc_loc.len != image_mc_loc.len) { + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "firmware multi controller entry length mismatch"); + return FALSE; + } + + controller_mc = read_location (&controller_mc_loc, controller, error); + if (controller_mc == NULL) + return FALSE; + image_mc = read_location (&image_mc_loc, image, error); + if (image_mc == NULL) + return FALSE; + + if (memcmp (controller_mc->data, image_mc->data, controller_mc->len) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "firmware multi controller entry mismatch"); + return FALSE; + } + + return TRUE; +} + static const FuThunderboltFwLocation * -get_device_locations (guint16 id) +get_device_locations (guint16 id, const FuThunderboltFwObject *controller, + const FuThunderboltFwObject *image, GError **error) { - static const FuThunderboltFwLocation locations[] = { + static const FuThunderboltFwLocation AR[] = { + { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, { .offset = 0x124, .len = 1, .section = ARC_PARAMS_SECTION, .description = "X of N" }, { 0 } }; + static const FuThunderboltFwLocation TR[] = { + { .offset = 0x45, .len = 1, .description = "Flash Size", .mask = 0x07 }, + { 0 } + }; + switch (id) { case 0x1578: case 0x1576: case 0x15D3: case 0x15DA: case 0x15C0: - return locations; + return AR; + case 0x15E7: + case 0x15EA: + case 0x15EF: + /* if the controller has multi controller entry need to + * compare it against the image first. */ + if (!compare_device_mc (controller, image, error)) + return NULL; + return TR; default: return NULL; } @@ -489,10 +610,41 @@ return TRUE; } +static gboolean +compare_pd_existence (guint16 id, + const FuThunderboltFwObject *controller, + const FuThunderboltFwObject *image, + GError **error) +{ + const FuThunderboltFwLocation pd_pointer_loc = { .offset = 0x10C, .len = 4, .section = ARC_PARAMS_SECTION, .description = "PD pointer" }; + gboolean controller_has_pd; + gboolean image_has_pd; + guint32 pd_pointer; + + if (controller->sections[ARC_PARAMS_SECTION] == 0) + return TRUE; + + if (!read_uint32 (&pd_pointer_loc, controller, &pd_pointer, error)) + return FALSE; + controller_has_pd = valid_pd_pointer (pd_pointer); + + if (!read_uint32 (&pd_pointer_loc, image, &pd_pointer, error)) + return FALSE; + image_has_pd = valid_pd_pointer (pd_pointer); + + if (controller_has_pd != image_has_pd) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "PD section mismatch"); + return FALSE; + } + + return TRUE; +} + FuPluginValidation -fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, - GBytes *blob_fw, - GError **error) +fu_thunderbolt_image_validate (GBytes *controller_fw, + GBytes *blob_fw, + GError **error) { gboolean is_host; guint16 device_id; @@ -585,6 +737,9 @@ return VALIDATION_FAILED; } + if (!compare_pd_existence (hw_info->id, &controller, &image, error)) + return VALIDATION_FAILED; + /* * 0 is for the unknown device case, for being future-compatible with * new devices; so we can't know which locations to check besides the @@ -594,14 +749,21 @@ if (hw_info->id == 0) return UNKNOWN_DEVICE; - locations = is_host ? - get_host_locations (hw_info->id) : - get_device_locations (hw_info->id); - if (locations == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "FW locations to check not found for this controller"); - return VALIDATION_FAILED; + if (is_host) { + locations = get_host_locations (hw_info->id); + if (locations == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, + "FW locations to check not found for this controller"); + return VALIDATION_FAILED; + } + } else { + locations = get_device_locations (hw_info->id, &controller, + &image, error); + if (locations == NULL) { + /* error is set already by the above */ + return VALIDATION_FAILED; + } } if (!compare_locations (&locations, &controller, &image, error)) @@ -617,16 +779,18 @@ } gboolean -fu_plugin_thunderbolt_controller_is_native (GBytes *controller_fw, - gboolean *is_native, - GError **error) +fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, + gboolean *is_native, + GError **error) { guint32 controller_sections[SECTION_COUNT] = { [DIGITAL_SECTION] = 0 }; gsize fw_size; const guint8 *fw_data = g_bytes_get_data (controller_fw, &fw_size); const FuThunderboltFwObject controller = { fw_data, fw_size, controller_sections }; - - const FuThunderboltFwLocation location = { .offset = 0x7B, .len = 1, .description = "Native", .mask = 0x20 }; - + const FuThunderboltFwLocation location = { + .offset = FU_TBT_OFFSET_NATIVE, + .len = 1, + .description = "Native", + .mask = 0x20 }; return read_bool (&location, &controller, is_native, error); } diff -Nru fwupd-1.0.6/plugins/thunderbolt/fu-thunderbolt-image.h fwupd-1.2.10/plugins/thunderbolt/fu-thunderbolt-image.h --- fwupd-1.0.6/plugins/thunderbolt/fu-thunderbolt-image.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/fu-thunderbolt-image.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Intel Corporation. * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_THUNDERBOLT_IMAGE_H__ -#define __FU_THUNDERBOLT_IMAGE_H__ +#pragma once #include @@ -30,12 +14,14 @@ UNKNOWN_DEVICE, } FuPluginValidation; -FuPluginValidation fu_plugin_thunderbolt_validate_image (GBytes *controller_fw, +/* byte offsets in firmware image */ +#define FU_TBT_OFFSET_NATIVE 0x7B +#define FU_TBT_CHUNK_SZ 0x40 + +FuPluginValidation fu_thunderbolt_image_validate (GBytes *controller_fw, GBytes *blob_fw, GError **error); -gboolean fu_plugin_thunderbolt_controller_is_native (GBytes *controller_fw, +gboolean fu_thunderbolt_image_controller_is_native (GBytes *controller_fw, gboolean *is_native, GError **error); - -#endif /* __FU_THUNDERBOLT_IMAGE_H__ */ diff -Nru fwupd-1.0.6/plugins/thunderbolt/fu-thunderbolt-tool.c fwupd-1.2.10/plugins/thunderbolt/fu-thunderbolt-tool.c --- fwupd-1.0.6/plugins/thunderbolt/fu-thunderbolt-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/fu-thunderbolt-tool.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Intel Corporation. * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" @@ -97,7 +82,7 @@ controller = g_bytes_new_take (controller_data, controller_len); } - validation = fu_plugin_thunderbolt_validate_image (controller, image, &error); + validation = fu_thunderbolt_image_validate (controller, image, &error); g_assert_no_error (error); g_assert_cmpint (validation, ==, VALIDATION_PASSED); diff -Nru fwupd-1.0.6/plugins/thunderbolt/meson.build fwupd-1.2.10/plugins/thunderbolt/meson.build --- fwupd-1.0.6/plugins/thunderbolt/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] fu_plugin_thunderbolt = shared_module('fu_plugin_thunderbolt', + fu_hash, sources : [ 'fu-plugin-thunderbolt.c', 'fu-thunderbolt-image.c', @@ -12,10 +13,12 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - gudev, ], ) @@ -23,6 +26,7 @@ testdatadir_dst = join_paths(meson.build_root(), 'data', 'tests') cargs += '-DTESTDATADIR="' + testdatadir_src + ':' + testdatadir_dst + '"' executable('tbtfwucli', + fu_hash, sources : [ 'fu-thunderbolt-tool.c', ], @@ -34,12 +38,10 @@ c_args : cargs, link_with : [ fu_plugin_thunderbolt, - fwupd, libfwupdprivate, ], dependencies : [ plugin_deps, - gudev, ], ) @@ -49,6 +51,7 @@ cargs += '-DPLUGINBUILDDIR="' + meson.current_build_dir() + '"' e = executable( 'thunderbolt-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-plugin-thunderbolt.c', @@ -61,16 +64,18 @@ ], dependencies : [ plugin_deps, - gudev, umockdev, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs ) test_env = environment() - test_env.prepend('LD_PRELOAD', 'libumockdev-preload.so.0') + if get_option('b_sanitize') == 'address' + test_env.prepend('LD_PRELOAD', 'libasan.so.5', 'libumockdev-preload.so.0', separator : ' ') + else + test_env.prepend('LD_PRELOAD', 'libumockdev-preload.so.0') + endif test('thunderbolt-self-test', e, env: test_env, timeout : 120) endif diff -Nru fwupd-1.0.6/plugins/thunderbolt/README.md fwupd-1.2.10/plugins/thunderbolt/README.md --- fwupd-1.0.6/plugins/thunderbolt/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -9,6 +9,28 @@ Versions 1 and 2 use the same connector as Mini DisplayPort (MDP), whereas version 3 uses USB Type-C. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +an unspecified binary file format, with vendor specific header. + +This plugin supports the following protocol ID: + + * com.intel.thunderbolt + +GUID Generation +--------------- + +These devices use a custom GUID generation scheme. +When the device is in "safe mode" the GUID is hardcoded using: + + * `TBT-safemode` + +... and when in runtime mode the GUID is: + + * `TBT-$(vid)$(pid)-native` when native, and `TBT-$(vid)$(pid)` otherwise. + Runtime Power Management ------------------------ diff -Nru fwupd-1.0.6/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c fwupd-1.2.10/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c --- fwupd-1.0.6/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt-power/fu-plugin-thunderbolt-power.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,38 +1,28 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017 Dell, Inc. * - * Copyright (C) 2017 Dell Inc. - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include #include -#include -#include +#include #include -#include #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" +#define BOLT_DBUS_SERVICE "org.freedesktop.bolt" +#define BOLT_DBUS_PATH "/org/freedesktop/bolt" +#define BOLT_DBUS_INTERFACE "org.freedesktop.bolt1.Power" + #ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop #endif /* empirically measured amount of time for the TBT device to come and go */ @@ -42,11 +32,105 @@ GUdevClient *udev; gchar *force_path; gboolean needs_forcepower; + gboolean updating; guint timeout_id; + gint bolt_fd; }; +static gboolean +fu_plugin_thunderbolt_power_bolt_supported (FuPlugin *plugin) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GError) error_local = NULL; + gboolean supported = FALSE; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error_local); + if (connection == NULL) { + g_warning ("Failed to initialize d-bus connection: %s", + error_local->message); + return supported; + } + + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + BOLT_DBUS_SERVICE, + BOLT_DBUS_PATH, + BOLT_DBUS_INTERFACE, + NULL, + &error_local); + if (proxy == NULL) { + g_warning ("Failed to initialize d-bus proxy: %s", + error_local->message); + return supported; + } + val = g_dbus_proxy_get_cached_property (proxy, "Supported"); + if (val != NULL) + g_variant_get (val, "b", &supported); + + g_debug ("Bolt force power support: %d", supported); + + return supported; +} + +static gboolean +fu_plugin_thunderbolt_power_bolt_force_power (FuPlugin *plugin, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GUnixFDList) fds = NULL; + g_autoptr(GVariant) val = NULL; + GVariant *input; + + input = g_variant_new ("(ss)", + "fwupd", /* who */ + ""); /* flags */ + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + BOLT_DBUS_SERVICE, + BOLT_DBUS_PATH, + BOLT_DBUS_INTERFACE, + NULL, + error); + if (proxy == NULL) + return FALSE; + + val = g_dbus_proxy_call_with_unix_fd_list_sync (proxy, + "ForcePower", + input, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &fds, + NULL, + error); + + if (val == NULL) + return FALSE; + + if (g_unix_fd_list_get_length (fds) != 1) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + "invalid number of file descriptors returned: %d", + g_unix_fd_list_get_length (fds)); + return FALSE; + } + data->bolt_fd = g_unix_fd_list_get (fds, 0, NULL); + + return TRUE; +} + static void -fu_plugin_thunderbolt_power_get_path (FuPlugin *plugin) +fu_plugin_thunderbolt_power_get_kernel_path (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(GList) devices = NULL; @@ -77,7 +161,7 @@ "force_power", NULL); if (g_file_test (built_path, G_FILE_TEST_IS_REGULAR)) { data->force_path = g_steal_pointer (&built_path); - g_debug ("Detected force power support at %s", + g_debug ("Direct kernel force power support at %s", data->force_path); break; } @@ -86,21 +170,21 @@ } static gboolean -fu_plugin_thunderbolt_power_supported (FuPlugin *plugin) +fu_plugin_thunderbolt_power_kernel_supported (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); return data->force_path != NULL; } static gboolean -fu_plugin_thunderbolt_power_set (FuPlugin *plugin, gboolean enable, - GError **error) +fu_plugin_thunderbolt_power_kernel_force_power (FuPlugin *plugin, gboolean enable, + GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); gint fd; gint ret; - if (!fu_plugin_thunderbolt_power_supported (plugin)) { + if (!fu_plugin_thunderbolt_power_kernel_supported (plugin)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -108,7 +192,7 @@ enable); return FALSE; } - g_debug ("Setting force power to %d", enable); + g_debug ("Setting force power to %d using kernel", enable); fd = g_open (data->force_path, O_WRONLY); if (fd == -1) { g_set_error (error, @@ -126,10 +210,28 @@ g_close (fd, NULL); return FALSE; } + return g_close (fd, error); } static gboolean +fu_plugin_thunderbolt_power_set (FuPlugin *plugin, gboolean enable, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + + /* prefer bolt API if available */ + if (fu_plugin_thunderbolt_power_bolt_supported (plugin)) { + g_debug ("Setting force power to %d using bolt", enable); + if (enable) + return fu_plugin_thunderbolt_power_bolt_force_power (plugin, error); + return data->bolt_fd >= 0 ? g_close (data->bolt_fd, error) : TRUE; + } + + return fu_plugin_thunderbolt_power_kernel_force_power (plugin, enable, error); +} + +static gboolean fu_plugin_thunderbolt_power_reset_cb (gpointer user_data) { FuPlugin *plugin = FU_PLUGIN (user_data); @@ -141,6 +243,28 @@ return FALSE; } +static void +fu_plugin_thunderbolt_reset_timeout (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + + if (!data->needs_forcepower || data->updating) + return; + + g_debug ("Setting timeout to %d seconds", + TBT_NEW_DEVICE_TIMEOUT * 10); + + /* in case this was a re-coldplug */ + if (data->timeout_id != 0) + g_source_remove (data->timeout_id); + + /* reset force power to off after enough time to enumerate */ + data->timeout_id = + g_timeout_add (TBT_NEW_DEVICE_TIMEOUT * 10000, + fu_plugin_thunderbolt_power_reset_cb, + plugin); +} + static gboolean udev_uevent_cb (GUdevClient *udev, const gchar *action, @@ -152,12 +276,19 @@ if (action == NULL) return TRUE; - g_debug ("uevent for %s: %s", g_udev_device_get_sysfs_path (device), action); - + g_debug ("uevent for %s: (%s) %s", + g_udev_device_get_name (device), + g_udev_device_get_sysfs_path (device), + action); + + /* thunderbolt device was turned on */ + if (g_str_equal (g_udev_device_get_subsystem (device), "thunderbolt") && + g_str_equal (action, "add")) { + fu_plugin_thunderbolt_reset_timeout (plugin); /* intel-wmi-thunderbolt has been loaded/unloaded */ - if (g_str_equal (action, "change")) { - fu_plugin_thunderbolt_power_get_path (plugin); - if (fu_plugin_thunderbolt_power_supported (plugin)) { + } else if (g_str_equal (action, "change")) { + fu_plugin_thunderbolt_power_get_kernel_path (plugin); + if (fu_plugin_thunderbolt_power_kernel_supported (plugin)) { fu_plugin_set_enabled (plugin, TRUE); fu_plugin_request_recoldplug (plugin); } else { @@ -174,29 +305,37 @@ fu_plugin_init (FuPlugin *plugin) { FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - const gchar *subsystems[] = { "wmi", NULL }; + const gchar *subsystems[] = { "thunderbolt", "wmi", NULL }; data->udev = g_udev_client_new (subsystems); g_signal_connect (data->udev, "uevent", G_CALLBACK (udev_uevent_cb), plugin); /* initially set to true, will wait for a device_register to reset */ data->needs_forcepower = TRUE; + /* will reset when needed */ + data->bolt_fd = -1; /* determines whether to run device_registered */ - fu_plugin_thunderbolt_power_get_path (plugin); + fu_plugin_thunderbolt_power_get_kernel_path (plugin); /* make sure it's tried to coldplug */ fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "thunderbolt"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); - if (data->timeout_id != 0) + if (data->timeout_id != 0) { g_source_remove (data->timeout_id); + data->timeout_id = 0; + } g_object_unref (data->udev); g_free (data->force_path); + /* in case destroying before force power turned off */ + if (data->bolt_fd >= 0) + g_close (data->bolt_fd, NULL); } void @@ -206,7 +345,8 @@ /* thunderbolt plugin */ if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") == 0 && - fu_plugin_thunderbolt_power_supported (plugin)) { + (fu_plugin_thunderbolt_power_bolt_supported (plugin) || + fu_plugin_thunderbolt_power_kernel_supported (plugin))) { data->needs_forcepower = FALSE; if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) { fu_device_set_metadata_boolean (device, @@ -218,6 +358,7 @@ gboolean fu_plugin_update_prepare (FuPlugin *plugin, + FwupdInstallFlags flags, FuDevice *device, GError **error) { @@ -229,6 +370,12 @@ if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0) return TRUE; + /* reset any timers that might still be running from coldplug */ + if (data->timeout_id != 0) { + g_source_remove (data->timeout_id); + data->timeout_id = 0; + } + devpath = fu_device_get_metadata (device, "sysfs-path"); udevice = g_udev_client_query_by_sysfs_path (data->udev, devpath); @@ -236,6 +383,7 @@ data->needs_forcepower = FALSE; return TRUE; } + data->updating = TRUE; if (!fu_plugin_thunderbolt_power_set (plugin, TRUE, error)) return FALSE; @@ -261,6 +409,7 @@ gboolean fu_plugin_update_cleanup (FuPlugin *plugin, + FwupdInstallFlags flags, FuDevice *device, GError **error) { @@ -270,6 +419,7 @@ if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0) return TRUE; + data->updating = FALSE; if (data->needs_forcepower && !fu_plugin_thunderbolt_power_set (plugin, FALSE, error)) return FALSE; @@ -281,11 +431,12 @@ { FuPluginData *data = fu_plugin_get_data (plugin); - if (!fu_plugin_thunderbolt_power_supported (plugin)) { + if (!fu_plugin_thunderbolt_power_bolt_supported (plugin) && + !fu_plugin_thunderbolt_power_kernel_supported (plugin)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "missing kernel support for intel-wmi-thunderbolt"); + "No support for force power via kernel or bolt"); return FALSE; } @@ -293,15 +444,8 @@ if (data->needs_forcepower) { if (!fu_plugin_thunderbolt_power_set (plugin, TRUE, error)) return FALSE; - /* in case this was a re-coldplug */ - if (data->timeout_id != 0) - g_source_remove (data->timeout_id); - - /* reset force power to off after enough time to enumerate */ - data->timeout_id = - g_timeout_add (TBT_NEW_DEVICE_TIMEOUT * 10000, - fu_plugin_thunderbolt_power_reset_cb, - plugin); + + fu_plugin_thunderbolt_reset_timeout (plugin); } return TRUE; diff -Nru fwupd-1.0.6/plugins/thunderbolt-power/meson.build fwupd-1.2.10/plugins/thunderbolt-power/meson.build --- fwupd-1.0.6/plugins/thunderbolt-power/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/thunderbolt-power/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,7 @@ -cargs = ['-DG_LOG_DOMAIN="FuPluginThunderboltPower"'] +cargs = ['-DG_LOG_DOMAIN="FuPluginThunderbolt"'] fu_plugin_thunderbolt_power = shared_module('fu_plugin_thunderbolt_power', + fu_hash, sources : [ 'fu-plugin-thunderbolt-power.c', ], @@ -11,9 +12,11 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - gudev, ], ) diff -Nru fwupd-1.0.6/plugins/udev/fu-plugin-udev.c fwupd-1.2.10/plugins/udev/fu-plugin-udev.c --- fwupd-1.0.6/plugins/udev/fu-plugin-udev.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/fu-plugin-udev.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,36 +1,21 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include -#include - #include "fu-plugin.h" #include "fu-rom.h" #include "fu-plugin-vfuncs.h" -struct FuPluginData { - GUdevClient *gudev_client; -}; +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_udev_subsystem (plugin, "pci"); +} gboolean fu_plugin_verify (FuPlugin *plugin, @@ -61,10 +46,11 @@ if (g_strcmp0 (fu_device_get_version (device), fu_rom_get_version (rom)) != 0) { g_debug ("changing version of %s from %s to %s", - fu_device_get_platform_id (device), + fu_device_get_id (device), fu_device_get_version (device), fu_rom_get_version (rom)); - fu_device_set_version (device, fu_rom_get_version (rom)); + fu_device_set_version (device, fu_rom_get_version (rom), + FWUPD_VERSION_FORMAT_UNKNOWN); } /* Also add the GUID from the firmware as the firmware may be more @@ -81,194 +67,38 @@ return TRUE; } -static gchar * -fu_plugin_udev_generate_vendor_id (GUdevDevice *device) -{ - const gchar *pci_id; - const gchar *subsys; - guint64 vid; - g_autofree gchar *subsys_up = NULL; - g_autofree gchar *vid_str = NULL; - - /* get upper cased subsystem */ - subsys = g_udev_device_get_subsystem (device); - if (subsys == NULL) - return NULL; - subsys_up = g_ascii_strup (subsys, -1); - - /* get vendor ID */ - pci_id = g_udev_device_get_property (device, "PCI_ID"); - if (pci_id != NULL) { - g_auto(GStrv) split = g_strsplit (pci_id, ":", 2); - vid_str = g_strdup (split[0]); - } - if (vid_str == NULL) { - g_warning ("no vendor ID for %s", - g_udev_device_get_sysfs_path (device)); - return NULL; - } - vid = g_ascii_strtoull (vid_str, NULL, 16); - if (vid == 0x0) { - g_warning ("failed to parse %s", vid_str); - return NULL; - } - return g_strdup_printf ("%s:0x%04X", subsys_up, (guint) vid); -} - -static void -fu_plugin_udev_add (FuPlugin *plugin, GUdevDevice *device) +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) { - FuDevice *dev_tmp; - const gchar *display_name; - const gchar *guid; - const gchar *id = NULL; - const gchar *product; - const gchar *vendor; + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + const gchar *guid = NULL; g_autofree gchar *rom_fn = NULL; - g_autofree gchar *vendor_id = NULL; - g_autofree gchar *version = NULL; - g_auto(GStrv) split = NULL; - g_autoptr(AsProfile) profile = as_profile_new (); - g_autoptr(AsProfileTask) ptask = NULL; - g_autoptr(FuDevice) dev = NULL; /* interesting device? */ - guid = g_udev_device_get_property (device, "FWUPD_GUID"); + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "pci") != 0) + return TRUE; + guid = g_udev_device_get_property (udev_device, "FWUPD_GUID"); if (guid == NULL) - return; - - /* get data */ - ptask = as_profile_start (profile, "FuPluginUdev:client-add{%s}", guid); - g_assert (ptask != NULL); - g_debug ("adding udev device: %s", g_udev_device_get_sysfs_path (device)); - - /* is already in database */ - id = g_udev_device_get_sysfs_path (device); - dev_tmp = fu_plugin_cache_lookup (plugin, id); - if (dev_tmp != NULL) { - g_debug ("ignoring duplicate %s", id); - return; - } + return TRUE; - /* get the FW version from the BCD device revision */ - product = g_udev_device_get_property (device, "PRODUCT"); - if (product != NULL) { - split = g_strsplit (product, "/", -1); - if (g_strv_length (split) != 3) { - g_warning ("env{PRODUCT} is invalid: %s", product); - return; - } - version = g_strdup (split[2]); - } + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "pci", error)) + return FALSE; /* did we get enough data */ - dev = fu_device_new (); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - fu_device_set_platform_id (dev, id); - fu_device_add_guid (dev, guid); - fu_device_add_icon (dev, "audio-card"); - display_name = g_udev_device_get_property (device, "FWUPD_MODEL"); - if (display_name == NULL) - display_name = g_udev_device_get_property (device, "ID_MODEL_FROM_DATABASE"); - if (display_name != NULL) - fu_device_set_name (dev, display_name); - vendor = g_udev_device_get_property (device, "FWUPD_VENDOR"); - if (vendor == NULL) - vendor = g_udev_device_get_property (device, "ID_VENDOR_FROM_DATABASE"); - if (vendor != NULL) - fu_device_set_vendor (dev, vendor); - if (version != NULL) - fu_device_set_version (dev, version); - - /* set vendor ID */ - vendor_id = fu_plugin_udev_generate_vendor_id (device); - if (vendor_id != NULL) - fu_device_set_vendor_id (FU_DEVICE (dev), vendor_id); + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_icon (FU_DEVICE (device), "audio-card"); /* get the FW version from the rom when unlocked */ - rom_fn = g_build_filename (g_udev_device_get_sysfs_path (device), "rom", NULL); + rom_fn = g_build_filename (fu_udev_device_get_sysfs_path (device), "rom", NULL); if (g_file_test (rom_fn, G_FILE_TEST_EXISTS)) - fu_device_set_metadata (dev, "RomFilename", rom_fn); - - /* insert to hash */ - fu_plugin_cache_add (plugin, id, dev); - fu_plugin_device_add_delay (plugin, dev); -} - -static void -fu_plugin_udev_remove (FuPlugin *plugin, GUdevDevice *device) -{ - FuDevice *dev; - const gchar *id; - - /* interesting device? */ - if (g_udev_device_get_property (device, "FWUPD_GUID") == NULL) - return; - - /* already in database */ - id = g_udev_device_get_sysfs_path (device); - dev = fu_plugin_cache_lookup (plugin, id); - if (dev == NULL) - return; - fu_plugin_device_remove (plugin, dev); -} - -static void -fu_plugin_udev_uevent_cb (GUdevClient *gudev_client, - const gchar *action, - GUdevDevice *udev_device, - FuPlugin *plugin) -{ - if (g_strcmp0 (action, "remove") == 0) { - fu_plugin_udev_remove (plugin, udev_device); - return; - } - if (g_strcmp0 (action, "add") == 0) { - fu_plugin_udev_add (plugin, udev_device); - return; - } -} - -void -fu_plugin_init (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - const gchar *subsystems[] = { "pci", NULL }; - - data->gudev_client = g_udev_client_new (subsystems); - g_signal_connect (data->gudev_client, "uevent", - G_CALLBACK (fu_plugin_udev_uevent_cb), plugin); -} + fu_device_set_metadata (FU_DEVICE (device), "RomFilename", rom_fn); -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_object_unref (data->gudev_client); -} + /* we never open the device, so convert the instance IDs */ + if (!fu_device_setup (FU_DEVICE (device), error)) + return FALSE; -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - GList *devices; - GUdevDevice *udev_device; - const gchar *devclass[] = { "pci", NULL }; - g_autoptr(AsProfile) profile = as_profile_new (); - - /* get all devices of class */ - for (guint i = 0; devclass[i] != NULL; i++) { - g_autoptr(AsProfileTask) ptask = NULL; - ptask = as_profile_start (profile, "FuPluginUdev:coldplug{%s}", devclass[i]); - g_assert (ptask != NULL); - devices = g_udev_client_query_by_subsystem (data->gudev_client, - devclass[i]); - for (GList *l = devices; l != NULL; l = l->next) { - udev_device = l->data; - fu_plugin_udev_add (plugin, udev_device); - } - g_list_foreach (devices, (GFunc) g_object_unref, NULL); - g_list_free (devices); - } + /* insert to hash */ + fu_plugin_device_add (plugin, FU_DEVICE (device)); return TRUE; } diff -Nru fwupd-1.0.6/plugins/udev/fu-rom.c fwupd-1.2.10/plugins/udev/fu-rom.c --- fwupd-1.0.6/plugins/udev/fu-rom.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/fu-rom.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,12 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include -#include -#include #include #include @@ -55,7 +37,8 @@ guint16 dmtf_clp_ptr; } FuRomPciHeader; -typedef struct { +struct _FuRom { + GObject parent_instance; GPtrArray *checksums; GInputStream *stream; FuRomKind kind; @@ -64,10 +47,9 @@ guint16 vendor_id; guint16 device_id; GPtrArray *hdrs; /* of FuRomPciHeader */ -} FuRomPrivate; +}; -G_DEFINE_TYPE_WITH_PRIVATE (FuRom, fu_rom, G_TYPE_OBJECT) -#define GET_PRIVATE(o) (fu_rom_get_instance_private (o)) +G_DEFINE_TYPE (FuRom, fu_rom, G_TYPE_OBJECT) static void fu_rom_pci_header_free (FuRomPciHeader *hdr) @@ -305,14 +287,13 @@ } gboolean -fu_rom_extract_all (FuRom *rom, const gchar *path, GError **error) +fu_rom_extract_all (FuRom *self, const gchar *path, GError **error) { - FuRomPrivate *priv = GET_PRIVATE (rom); FuRomPciHeader *hdr; - for (guint i = 0; i < priv->hdrs->len; i++) { + for (guint i = 0; i < self->hdrs->len; i++) { g_autofree gchar *fn = NULL; - hdr = g_ptr_array_index (priv->hdrs, i); + hdr = g_ptr_array_index (self->hdrs, i); fn = g_strdup_printf ("%s/%02u.bin", path, i); g_debug ("dumping ROM #%u at 0x%04x [0x%02x] to %s", i, hdr->rom_offset, hdr->rom_len, fn); @@ -327,21 +308,20 @@ } static void -fu_rom_find_and_blank_serial_numbers (FuRom *rom) +fu_rom_find_and_blank_serial_numbers (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); FuRomPciHeader *hdr; guint8 *tmp; /* bail if not likely */ - if (priv->kind == FU_ROM_KIND_PCI || - priv->kind == FU_ROM_KIND_INTEL) { + if (self->kind == FU_ROM_KIND_PCI || + self->kind == FU_ROM_KIND_INTEL) { g_debug ("no serial numbers likely"); return; } - for (guint i = 0; i < priv->hdrs->len; i++) { - hdr = g_ptr_array_index (priv->hdrs, i); + for (guint i = 0; i < self->hdrs->len; i++) { + hdr = g_ptr_array_index (self->hdrs, i); g_debug ("looking for PPID at 0x%04x", hdr->rom_offset); tmp = fu_rom_pci_strstr (hdr, "PPID"); if (tmp != NULL) { @@ -558,22 +538,20 @@ } gboolean -fu_rom_load_data (FuRom *rom, +fu_rom_load_data (FuRom *self, guint8 *buffer, gsize buffer_sz, FuRomLoadFlags flags, GCancellable *cancellable, GError **error) { - FuRomPrivate *priv = GET_PRIVATE (rom); FuRomPciHeader *hdr = NULL; guint32 sz = buffer_sz; guint32 jump = 0; guint32 hdr_sz = 0; - g_autofree gchar *id = NULL; g_autoptr(GChecksum) checksum_sha1 = g_checksum_new (G_CHECKSUM_SHA1); g_autoptr(GChecksum) checksum_sha256 = g_checksum_new (G_CHECKSUM_SHA256); - g_return_val_if_fail (FU_IS_ROM (rom), FALSE); + g_return_val_if_fail (FU_IS_ROM (self), FALSE); /* detect optional IFR header and skip to option ROM */ if (memcmp (buffer, "NVGI", 4) == 0) { @@ -609,7 +587,7 @@ hdr->rom_len = sz - hdr->rom_offset; hdr->rom_data = g_memdup (&buffer[hdr->rom_offset], hdr->rom_len); hdr->image_len = hdr->rom_len; - g_ptr_array_add (priv->hdrs, hdr); + g_ptr_array_add (self->hdrs, hdr); } else { g_debug ("ignoring 0x%04x bytes of padding", (guint) (buffer_sz - (jump + hdr_sz))); @@ -622,7 +600,7 @@ /* we can't break on hdr->last_image as * NVIDIA uses packed but not merged extended headers */ - g_ptr_array_add (priv->hdrs, hdr); + g_ptr_array_add (self->hdrs, hdr); /* NVIDIA don't always set a ROM size for extensions */ jump_sz = hdr->rom_len; @@ -634,7 +612,7 @@ } /* we found nothing */ - if (priv->hdrs->len == 0) { + if (self->hdrs->len == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -644,16 +622,16 @@ } /* print all headers */ - for (guint i = 0; i < priv->hdrs->len; i++) { - hdr = g_ptr_array_index (priv->hdrs, i); + for (guint i = 0; i < self->hdrs->len; i++) { + hdr = g_ptr_array_index (self->hdrs, i); fu_rom_pci_print_header (hdr); } /* find first ROM header */ - hdr = g_ptr_array_index (priv->hdrs, 0); - priv->vendor_id = hdr->vendor_id; - priv->device_id = hdr->device_id; - priv->kind = FU_ROM_KIND_PCI; + hdr = g_ptr_array_index (self->hdrs, 0); + self->vendor_id = hdr->vendor_id; + self->device_id = hdr->device_id; + self->kind = FU_ROM_KIND_PCI; /* detect intel header */ if (memcmp (hdr->reserved, "00000000000", 11) == 0) @@ -667,15 +645,15 @@ } if (hdr->entry_point == 0x374beb) { - priv->kind = FU_ROM_KIND_NVIDIA; + self->kind = FU_ROM_KIND_NVIDIA; } else if (memcmp (buffer + hdr_sz, "$VBT", 4) == 0) { - priv->kind = FU_ROM_KIND_INTEL; + self->kind = FU_ROM_KIND_INTEL; } else if (memcmp(buffer + 0x30, " 761295520", 10) == 0) { - priv->kind = FU_ROM_KIND_ATI; + self->kind = FU_ROM_KIND_ATI; } /* nothing */ - if (priv->kind == FU_ROM_KIND_UNKNOWN) { + if (self->kind == FU_ROM_KIND_UNKNOWN) { g_autofree gchar *str = NULL; str = fu_rom_get_hex_dump (buffer + hdr_sz, 0x32); g_set_error (error, @@ -687,33 +665,31 @@ } /* find version string */ - priv->version = fu_rom_find_version (priv->kind, hdr); - if (priv->version != NULL) { - g_strstrip (priv->version); - g_strdelimit (priv->version, "\r\n ", '\0'); + self->version = fu_rom_find_version (self->kind, hdr); + if (self->version != NULL) { + g_strstrip (self->version); + g_strdelimit (self->version, "\r\n ", '\0'); } /* update checksum */ if (flags & FU_ROM_LOAD_FLAG_BLANK_PPID) - fu_rom_find_and_blank_serial_numbers (rom); - for (guint i = 0; i < priv->hdrs->len; i++) { - hdr = g_ptr_array_index (priv->hdrs, i); + fu_rom_find_and_blank_serial_numbers (self); + for (guint i = 0; i < self->hdrs->len; i++) { + hdr = g_ptr_array_index (self->hdrs, i); g_checksum_update (checksum_sha1, hdr->rom_data, hdr->rom_len); g_checksum_update (checksum_sha256, hdr->rom_data, hdr->rom_len); } /* done updating checksums */ - g_ptr_array_add (priv->checksums, g_strdup (g_checksum_get_string (checksum_sha1))); - g_ptr_array_add (priv->checksums, g_strdup (g_checksum_get_string (checksum_sha256))); + g_ptr_array_add (self->checksums, g_strdup (g_checksum_get_string (checksum_sha1))); + g_ptr_array_add (self->checksums, g_strdup (g_checksum_get_string (checksum_sha256))); /* update guid */ - id = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", - priv->vendor_id, priv->device_id); - priv->guid = as_utils_guid_from_string (id); - g_debug ("using %s for %s", priv->guid, id); + self->guid = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", + self->vendor_id, self->device_id); /* not known */ - if (priv->version == NULL) { + if (self->version == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, @@ -725,10 +701,9 @@ } gboolean -fu_rom_load_file (FuRom *rom, GFile *file, FuRomLoadFlags flags, +fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, GCancellable *cancellable, GError **error) { - FuRomPrivate *priv = GET_PRIVATE (rom); const gssize buffer_sz = 0x400000; gssize sz; guint number_reads = 0; @@ -736,16 +711,12 @@ g_autofree gchar *fn = NULL; g_autofree guint8 *buffer = NULL; g_autoptr(GFileOutputStream) output_stream = NULL; - g_autoptr(AsProfile) profile = as_profile_new (); - g_autoptr(AsProfileTask) ptask = NULL; - g_return_val_if_fail (FU_IS_ROM (rom), FALSE); + g_return_val_if_fail (FU_IS_ROM (self), FALSE); /* open file */ - ptask = as_profile_start_literal (profile, "FuRom:reading-data"); - g_assert (ptask != NULL); - priv->stream = G_INPUT_STREAM (g_file_read (file, cancellable, &error_local)); - if (priv->stream == NULL) { + self->stream = G_INPUT_STREAM (g_file_read (file, cancellable, &error_local)); + if (self->stream == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AUTH_FAILED, @@ -767,7 +738,7 @@ /* read out the header */ buffer = g_malloc ((gsize) buffer_sz); - sz = g_input_stream_read (priv->stream, buffer, buffer_sz, + sz = g_input_stream_read (self->stream, buffer, buffer_sz, cancellable, error); if (sz < 0) return FALSE; @@ -782,7 +753,7 @@ /* ensure we got enough data to fill the buffer */ while (sz < buffer_sz) { gssize sz_chunk; - sz_chunk = g_input_stream_read (priv->stream, + sz_chunk = g_input_stream_read (self->stream, buffer + sz, buffer_sz - sz, cancellable, @@ -806,54 +777,48 @@ } g_debug ("ROM buffer filled %" G_GSSIZE_FORMAT "kb/%" G_GSSIZE_FORMAT "kb", sz / 0x400, buffer_sz / 0x400); - return fu_rom_load_data (rom, buffer, sz, flags, cancellable, error); + return fu_rom_load_data (self, buffer, sz, flags, cancellable, error); } FuRomKind -fu_rom_get_kind (FuRom *rom) +fu_rom_get_kind (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - g_return_val_if_fail (FU_IS_ROM (rom), FU_ROM_KIND_UNKNOWN); - return priv->kind; + g_return_val_if_fail (FU_IS_ROM (self), FU_ROM_KIND_UNKNOWN); + return self->kind; } const gchar * -fu_rom_get_version (FuRom *rom) +fu_rom_get_version (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - g_return_val_if_fail (FU_IS_ROM (rom), NULL); - return priv->version; + g_return_val_if_fail (FU_IS_ROM (self), NULL); + return self->version; } const gchar * -fu_rom_get_guid (FuRom *rom) +fu_rom_get_guid (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - g_return_val_if_fail (FU_IS_ROM (rom), NULL); - return priv->guid; + g_return_val_if_fail (FU_IS_ROM (self), NULL); + return self->guid; } guint16 -fu_rom_get_vendor (FuRom *rom) +fu_rom_get_vendor (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - g_return_val_if_fail (FU_IS_ROM (rom), 0x0000); - return priv->vendor_id; + g_return_val_if_fail (FU_IS_ROM (self), 0x0000); + return self->vendor_id; } guint16 -fu_rom_get_model (FuRom *rom) +fu_rom_get_model (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - g_return_val_if_fail (FU_IS_ROM (rom), 0x0000); - return priv->device_id; + g_return_val_if_fail (FU_IS_ROM (self), 0x0000); + return self->device_id; } GPtrArray * -fu_rom_get_checksums (FuRom *rom) +fu_rom_get_checksums (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - return priv->checksums; + return self->checksums; } static void @@ -864,25 +829,23 @@ } static void -fu_rom_init (FuRom *rom) +fu_rom_init (FuRom *self) { - FuRomPrivate *priv = GET_PRIVATE (rom); - priv->checksums = g_ptr_array_new_with_free_func (g_free); - priv->hdrs = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_rom_pci_header_free); + self->checksums = g_ptr_array_new_with_free_func (g_free); + self->hdrs = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_rom_pci_header_free); } static void fu_rom_finalize (GObject *object) { - FuRom *rom = FU_ROM (object); - FuRomPrivate *priv = GET_PRIVATE (rom); + FuRom *self = FU_ROM (object); - g_free (priv->version); - g_free (priv->guid); - g_ptr_array_unref (priv->checksums); - g_ptr_array_unref (priv->hdrs); - if (priv->stream != NULL) - g_object_unref (priv->stream); + g_free (self->version); + g_free (self->guid); + g_ptr_array_unref (self->checksums); + g_ptr_array_unref (self->hdrs); + if (self->stream != NULL) + g_object_unref (self->stream); G_OBJECT_CLASS (fu_rom_parent_class)->finalize (object); } @@ -890,7 +853,7 @@ FuRom * fu_rom_new (void) { - FuRom *rom; - rom = g_object_new (FU_TYPE_ROM, NULL); - return FU_ROM (rom); + FuRom *self; + self = g_object_new (FU_TYPE_ROM, NULL); + return FU_ROM (self); } diff -Nru fwupd-1.0.6/plugins/udev/fu-rom.h fwupd-1.2.10/plugins/udev/fu-rom.h --- fwupd-1.0.6/plugins/udev/fu-rom.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/fu-rom.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,39 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ROM_H -#define __FU_ROM_H +#pragma once -#include #include G_BEGIN_DECLS #define FU_TYPE_ROM (fu_rom_get_type ()) -G_DECLARE_DERIVABLE_TYPE (FuRom, fu_rom, FU, ROM, GObject) - -struct _FuRomClass -{ - GObjectClass parent_class; -}; +G_DECLARE_FINAL_TYPE (FuRom, fu_rom, FU, ROM, GObject) typedef enum { FU_ROM_KIND_UNKNOWN, @@ -52,29 +30,26 @@ FuRom *fu_rom_new (void); -gboolean fu_rom_load_file (FuRom *rom, +gboolean fu_rom_load_file (FuRom *self, GFile *file, FuRomLoadFlags flags, GCancellable *cancellable, GError **error); -gboolean fu_rom_load_data (FuRom *rom, +gboolean fu_rom_load_data (FuRom *self, guint8 *buffer, gsize buffer_sz, FuRomLoadFlags flags, GCancellable *cancellable, GError **error); -gboolean fu_rom_extract_all (FuRom *rom, +gboolean fu_rom_extract_all (FuRom *self, const gchar *path, GError **error); -FuRomKind fu_rom_get_kind (FuRom *rom); -const gchar *fu_rom_get_version (FuRom *rom); -GPtrArray *fu_rom_get_checksums (FuRom *rom); -const gchar *fu_rom_get_guid (FuRom *rom); -guint16 fu_rom_get_vendor (FuRom *rom); -guint16 fu_rom_get_model (FuRom *rom); +FuRomKind fu_rom_get_kind (FuRom *self); +const gchar *fu_rom_get_version (FuRom *self); +GPtrArray *fu_rom_get_checksums (FuRom *self); +const gchar *fu_rom_get_guid (FuRom *self); +guint16 fu_rom_get_vendor (FuRom *self); +guint16 fu_rom_get_model (FuRom *self); const gchar *fu_rom_kind_to_string (FuRomKind kind); G_END_DECLS - -#endif /* __FU_ROM_H */ - diff -Nru fwupd-1.0.6/plugins/udev/fu-rom-tool.c fwupd-1.2.10/plugins/udev/fu-rom-tool.c --- fwupd-1.0.6/plugins/udev/fu-rom-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/fu-rom-tool.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/plugins/udev/fu-self-test.c fwupd-1.2.10/plugins/udev/fu-self-test.c --- fwupd-1.0.6/plugins/udev/fu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,28 +1,12 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include -#include #include #include #include diff -Nru fwupd-1.0.6/plugins/udev/meson.build fwupd-1.2.10/plugins/udev/meson.build --- fwupd-1.0.6/plugins/udev/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUdev"'] shared_module('fu_plugin_udev', + fu_hash, sources : [ 'fu-plugin-udev.c', 'fu-rom.c', @@ -12,15 +13,18 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - gudev, ], ) executable( 'fu-rom-tool', + fu_hash, sources : [ 'fu-rom-tool.c', 'fu-rom.c', @@ -32,10 +36,9 @@ ], dependencies : [ plugin_deps, - gudev, + libjsonglib, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs, @@ -48,6 +51,7 @@ cargs += '-DTESTDATADIR="' + testdatadir + '"' e = executable( 'udev-self-test', + fu_hash, sources : [ 'fu-self-test.c', 'fu-rom.c', @@ -59,10 +63,8 @@ ], dependencies : [ plugin_deps, - gudev, ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs diff -Nru fwupd-1.0.6/plugins/udev/README.md fwupd-1.2.10/plugins/udev/README.md --- fwupd-1.0.6/plugins/udev/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/udev/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -10,3 +10,12 @@ This plugin is also able to read and parse the firmware of some PCI devices which allows some host state verification to be done. + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `PCI\VEN_%04X&DEV_%04X` + +Additionally, GUIDs found in OptionROMs may also be added. diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-cleanups.h fwupd-1.2.10/plugins/uefi/efi/fwup-cleanups.h --- fwupd-1.0.6/plugins/uefi/efi/fwup-cleanups.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-cleanups.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define _DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline VOID name(VOID *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } +_DEFINE_CLEANUP_FUNCTION0(VOID *, _FreePool_p, FreePool) +#define _cleanup_free __attribute__ ((cleanup(_FreePool_p))) + +static inline VOID * +_steal_pointer(VOID *pp) +{ + VOID **ptr = (VOID **) pp; + VOID *ref = *ptr; + *ptr = NULL; + return ref; +} diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-common.c fwupd-1.2.10/plugins/uefi/efi/fwup-common.c --- fwupd-1.0.6/plugins/uefi/efi/fwup-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-debug.h" +#include "fwup-common.h" + +VOID +fwup_msleep(unsigned long msecs) +{ + BS->Stall(msecs); +} + +/* + * Allocate some raw pages that aren't part of the pool allocator. + */ +VOID * +fwup_malloc_raw(UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); /* page size is always 4096 */ + EFI_STATUS rc; + EFI_PHYSICAL_ADDRESS pageaddr = 0; + EFI_ALLOCATE_TYPE type = AllocateAnyPages; + + if (sizeof(VOID *) == 4) { + pageaddr = 0xffffffffULL - 8192; + type = AllocateMaxAddress; + } + + rc = uefi_call_wrapper(BS->AllocatePages, 4, type, + EfiLoaderData, pages, + &pageaddr); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not allocate %d", size); + return NULL; + } + if (sizeof(VOID *) == 4 && pageaddr > 0xffffffffULL) { + uefi_call_wrapper(BS->FreePages, 2, pageaddr, pages); + fwup_warning(L"Got bad allocation at 0x%016x", (UINT64)pageaddr); + return NULL; + } + return (VOID *)(UINTN)pageaddr; +} + +/* + * Free our raw page allocations. + */ +static EFI_STATUS +fwup_free_raw(VOID *addr, UINTN size) +{ + UINTN pages = size / 4096 + ((size % 4096) ? 1 : 0); + return uefi_call_wrapper(BS->FreePages, 2, + (EFI_PHYSICAL_ADDRESS)(UINTN)addr, pages); +} + +VOID * +fwup_malloc (UINTN size) +{ + VOID *addr = AllocatePool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +VOID * +fwup_malloc0 (UINTN size) +{ + VOID *addr = AllocateZeroPool(size); + if (addr == NULL) + fwup_warning(L"Could not allocate %d", size); + return addr; +} + +EFI_STATUS +fwup_time(EFI_TIME *ts) +{ + EFI_TIME_CAPABILITIES timecaps = { 0, }; + return uefi_call_wrapper(RT->GetTime, 2, ts, &timecaps); +} + +EFI_STATUS +fwup_read_file(EFI_FILE_HANDLE fh, UINT8 **buf_out, UINTN *buf_size_out) +{ + const UINTN bs = 512; + UINTN i = 0; + UINTN n_blocks = 4096; + UINT8 *buf = NULL; + + while (1) { + VOID *newb = NULL; + UINTN news = n_blocks * bs * 2; + + newb = fwup_malloc_raw(news); + if (newb == NULL) + return EFI_OUT_OF_RESOURCES; + if (buf != NULL) { + CopyMem(newb, buf, bs * n_blocks); + fwup_free_raw(buf, bs * n_blocks); + } + buf = newb; + n_blocks *= 2; + + for (; i < n_blocks; i++) { + EFI_STATUS rc; + UINTN sz = bs; + + rc = uefi_call_wrapper(fh->Read, 3, fh, &sz, &buf[i * bs]); + if (EFI_ERROR(rc)) { + fwup_free_raw(buf, bs * n_blocks); + fwup_warning(L"Could not read file: %r", rc); + return rc; + } + + if (sz != bs) { + *buf_size_out = bs * i + sz; + *buf_out = buf; + return EFI_SUCCESS; + } + } + } + return EFI_SUCCESS; +} diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-common.h fwupd-1.2.10/plugins/uefi/efi/fwup-common.h --- fwupd-1.0.6/plugins/uefi/efi/fwup-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fwup-efi.h" + +VOID fwup_msleep (unsigned long msecs); +EFI_STATUS fwup_time (EFI_TIME *ts); +EFI_STATUS fwup_read_file (EFI_FILE_HANDLE fh, + UINT8 **buf_out, + UINTN *buf_size_out); +VOID *fwup_malloc_raw (UINTN size); + +VOID *fwup_malloc (UINTN size); +VOID *fwup_malloc0 (UINTN size); + +#define fwup_new(struct_type, n) ((struct_type*)fwup_malloc((n)*sizeof(struct_type))) +#define fwup_new0(struct_type, n) ((struct_type*)fwup_malloc0((n)*sizeof(struct_type))) diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwupdate.c fwupd-1.2.10/plugins/uefi/efi/fwupdate.c --- fwupd-1.0.6/plugins/uefi/efi/fwupdate.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwupdate.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,754 @@ +/* + * Copyright (C) 2014-2018 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-common.h" +#include "fwup-efi.h" +#include "fwup-debug.h" + +#define UNUSED __attribute__((__unused__)) +#define GNVN_BUF_SIZE 1024 +#define FWUP_NUM_CAPSULE_UPDATES_MAX 128 + +typedef struct { + CHAR16 *name; + UINT32 attrs; + UINTN size; + FWUP_UPDATE_INFO *info; +} FWUP_UPDATE_TABLE; + +static VOID +fwup_update_table_free(FWUP_UPDATE_TABLE *update) +{ + FreePool(update->info); + FreePool(update->name); + FreePool(update); +} + +_DEFINE_CLEANUP_FUNCTION0(FWUP_UPDATE_TABLE *, _fwup_update_table_free_p, fwup_update_table_free) +#define _cleanup_update_table __attribute__ ((cleanup(_fwup_update_table_free_p))) + +#define SECONDS 1000000 + +static INTN +fwup_dp_size(EFI_DEVICE_PATH *dp, INTN limit) +{ + INTN ret = 0; + while (1) { + if (limit < 4) + break; + INTN nodelen = DevicePathNodeLength(dp); + if (nodelen > limit) + break; + limit -= nodelen; + ret += nodelen; + + if (IsDevicePathEnd(dp)) + return ret; + dp = NextDevicePathNode(dp); + } + return -1; +} + +static EFI_STATUS +fwup_populate_update_info(CHAR16 *name, FWUP_UPDATE_TABLE *info_out) +{ + EFI_STATUS rc; + FWUP_UPDATE_INFO *info = NULL; + UINTN info_size = 0; + UINT32 attrs = 0; + VOID *info_ptr = NULL; + + rc = fwup_get_variable(name, &fwupdate_guid, &info_ptr, &info_size, &attrs); + if (EFI_ERROR(rc)) + return rc; + info = (FWUP_UPDATE_INFO *)info_ptr; + + if (info_size < sizeof(*info)) { + fwup_warning(L"Update '%s' is is too small", name); + return EFI_INVALID_PARAMETER; + } + + if (info_size - sizeof(EFI_DEVICE_PATH) <= sizeof(*info)) { + fwup_warning(L"Update '%s' is malformed, " + L"and cannot hold a file path", name); + return EFI_INVALID_PARAMETER; + } + + EFI_DEVICE_PATH *hdr = (EFI_DEVICE_PATH *)&info->dp; + INTN is = EFI_FIELD_OFFSET(FWUP_UPDATE_INFO, dp); + if (is > (INTN)info_size) { + fwup_warning(L"Update '%s' has an invalid file path, " + L"device path offset is %d, but total size is %d", + name, is, info_size); + return EFI_INVALID_PARAMETER; + } + + is = info_size - is; + INTN sz = fwup_dp_size(hdr, info_size); + if (sz < 0 || is > (INTN)info_size || is != sz) { + fwup_warning(L"Update '%s' has an invalid file path, " + L"update info size: %d dp size: %d size for dp: %d", + name, info_size, sz, is); + return EFI_INVALID_PARAMETER; + } + + info_out->info = info; + info_out->size = info_size; + info_out->attrs = attrs; + info_out->name = StrDuplicate(name); + if (info_out->name == NULL) { + fwup_warning(L"Could not allocate %d", StrSize(name)); + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_populate_update_table(FWUP_UPDATE_TABLE **updates, UINTN *n_updates_out) +{ + EFI_GUID vendor_guid = empty_guid; + EFI_STATUS rc; + UINTN n_updates = 0; + _cleanup_free CHAR16 *variable_name = NULL; + + /* How much do we trust "size of the VariableName buffer" to mean + * sizeof(vn) and not sizeof(vn)/sizeof(vn[0]) ? */ + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) + return EFI_OUT_OF_RESOURCES; + + while (1) { + UINTN variable_name_size = GNVN_BUF_SIZE; + rc = uefi_call_wrapper(RT->GetNextVariableName, 3, + &variable_name_size, variable_name, + &vendor_guid); + if (rc == EFI_NOT_FOUND) + break; + + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); + return rc; + } + + /* not one of our state variables */ + if (CompareGuid(&vendor_guid, &fwupdate_guid)) + continue; + + /* ignore debugging settings */ + if (StrCmp(variable_name, L"FWUPDATE_VERBOSE") == 0 || + StrCmp(variable_name, L"FWUPDATE_DEBUG_LOG") == 0) + continue; + + if (n_updates > FWUP_NUM_CAPSULE_UPDATES_MAX) { + fwup_warning(L"Ignoring update %s", variable_name); + continue; + } + + fwup_info(L"Found update %s", variable_name); + _cleanup_update_table FWUP_UPDATE_TABLE *update = fwup_malloc0(sizeof(FWUP_UPDATE_TABLE)); + if (update == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_info(variable_name, update); + if (EFI_ERROR(rc)) { + fwup_delete_variable(variable_name, &fwupdate_guid); + fwup_warning(L"Could not populate update info for '%s'", variable_name); + return rc; + } + if (update->info->status & FWUPDATE_ATTEMPT_UPDATE) { + fwup_time(&update->info->time_attempted); + update->info->status = FWUPDATE_ATTEMPTED; + updates[n_updates++] = _steal_pointer(&update); + } + } + + *n_updates_out = n_updates; + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_search_file(EFI_DEVICE_PATH **file_dp, EFI_FILE_HANDLE *fh) +{ + EFI_DEVICE_PATH *dp, *parent_dp; + EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; + EFI_GUID dpp = DEVICE_PATH_PROTOCOL; + UINTN n_handles, count; + EFI_STATUS rc; + _cleanup_free EFI_FILE_HANDLE *devices = NULL; + + rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &sfsp, + NULL, &n_handles, (EFI_HANDLE **)&devices); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not find handles"); + return rc; + } + + dp = *file_dp; + + fwup_debug(L"Searching Device Path: %s...", DevicePathToStr(dp)); + parent_dp = DuplicateDevicePath(dp); + if (parent_dp == NULL) + return EFI_INVALID_PARAMETER; + + dp = parent_dp; + count = 0; + while (1) { + if (IsDevicePathEnd(dp)) + return EFI_INVALID_PARAMETER; + + if (DevicePathType(dp) == MEDIA_DEVICE_PATH && + DevicePathSubType(dp) == MEDIA_FILEPATH_DP) + break; + + dp = NextDevicePathNode(dp); + ++count; + } + + SetDevicePathEndNode(dp); + fwup_debug(L"Device Path prepared: %s", DevicePathToStr(parent_dp)); + + for (UINTN i = 0; i < n_handles; i++) { + EFI_DEVICE_PATH *path; + + rc = uefi_call_wrapper(BS->HandleProtocol, 3, devices[i], &dpp, + (VOID **)&path); + if (EFI_ERROR(rc)) + continue; + + fwup_debug(L"Device supporting SFSP: %s", DevicePathToStr(path)); + + while (!IsDevicePathEnd(path)) { + fwup_debug(L"Comparing: %s and %s", + DevicePathToStr(parent_dp), + DevicePathToStr(path)); + + if (LibMatchDevicePaths(path, parent_dp) == TRUE) { + *fh = devices[i]; + for (UINTN j = 0; j < count; j++) + *file_dp = NextDevicePathNode(*file_dp); + + fwup_debug(L"Match up! Returning %s", + DevicePathToStr(*file_dp)); + return EFI_SUCCESS; + } + + path = NextDevicePathNode(path); + } + } + + fwup_warning(L"Failed to find '%s' DevicePath", DevicePathToStr(*file_dp)); + return EFI_UNSUPPORTED; +} + +static EFI_STATUS +fwup_open_file(EFI_DEVICE_PATH *dp, EFI_FILE_HANDLE *fh) +{ + CONST UINTN devpath_max_size = 1024; /* arbitrary limit */ + EFI_DEVICE_PATH *file_dp = dp; + EFI_GUID sfsp = SIMPLE_FILE_SYSTEM_PROTOCOL; + EFI_FILE_HANDLE device; + EFI_FILE_IO_INTERFACE *drive; + EFI_FILE_HANDLE root; + EFI_STATUS rc; + + rc = uefi_call_wrapper(BS->LocateDevicePath, 3, &sfsp, &file_dp, + (EFI_HANDLE *)&device); + if (EFI_ERROR(rc)) { + rc = fwup_search_file(&file_dp, &device); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not locate device handle: %r", rc); + return rc; + } + } + + if (DevicePathType(file_dp) != MEDIA_DEVICE_PATH || + DevicePathSubType(file_dp) != MEDIA_FILEPATH_DP) { + fwup_warning(L"Could not find appropriate device"); + return EFI_UNSUPPORTED; + } + + UINT16 sz16; + UINTN sz; + CopyMem(&sz16, &file_dp->Length[0], sizeof(sz16)); + sz = sz16; + sz -= 4; + if (sz <= 6 || sz % 2 != 0 || + sz > devpath_max_size * sizeof(CHAR16)) { + fwup_warning(L"Invalid file device path of size %d", sz); + return EFI_INVALID_PARAMETER; + } + + _cleanup_free CHAR16 *filename = fwup_malloc0(sz + sizeof(CHAR16)); + CopyMem(filename, (UINT8 *)file_dp + 4, sz); + + rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, &sfsp, + (VOID **)&drive); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not open device interface: %r", rc); + return rc; + } + fwup_debug(L"Found device"); + + rc = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not open volume: %r", rc); + return rc; + } + fwup_debug(L"Found volume"); + + rc = uefi_call_wrapper(root->Open, 5, root, fh, filename, + EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not open file '%s': %r", filename, rc); + return rc; + } + fwup_debug(L"Found file"); + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_delete_boot_order(CHAR16 *name, EFI_GUID guid) +{ + UINT16 boot_num; + EFI_STATUS rc; + UINTN info_size = 0; + UINT32 attrs = 0; + _cleanup_free VOID *info_ptr = NULL; + _cleanup_free UINT16 *new_info_ptr = NULL; + UINT8 num_found = FALSE; + UINTN new_list_num = 0; + + /* get boot hex number */ + boot_num = xtoi((CHAR16 *)((UINT8 *)name + sizeof(L"Boot"))); + + rc = fwup_get_variable(L"BootOrder", &guid, &info_ptr, &info_size, &attrs); + if (EFI_ERROR(rc)) + return rc; + + new_info_ptr = fwup_malloc(info_size); + if (new_info_ptr == NULL) + return EFI_OUT_OF_RESOURCES; + + for (UINTN i = 0; i < (info_size / sizeof(UINT16)) ; i++) { + if (((UINT16 *)info_ptr)[i] != boot_num) { + new_info_ptr[i] = ((UINT16 *)info_ptr)[i]; + new_list_num++; + + } else { + num_found = TRUE; + } + } + + /* if not in the BootOrder list, do not update BootOrder */ + if (!num_found) + return EFI_SUCCESS; + + rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &guid, + attrs, new_list_num * sizeof(UINT16), + new_info_ptr); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not update variable status for '%s': %r", + name, rc); + return rc; + } + return rc; +} + +/* TODO: move to gnu-efi: https://github.com/vathpela/gnu-efi/issues/7 */ +static BOOLEAN +_StrHasPrefix(IN CONST CHAR16 *s1, IN CONST CHAR16 *s2) +{ + while (*s2) { + if (*s1 == L'\0' || *s1 != *s2) + return FALSE; + s1 += 1; + s2 += 1; + } + return TRUE; +} + +static EFI_STATUS +fwup_delete_boot_entry(VOID) +{ + EFI_STATUS rc; + UINTN variable_name_size = 0; + _cleanup_free CHAR16 *variable_name = NULL; + EFI_GUID vendor_guid = empty_guid; + + variable_name = fwup_malloc0(GNVN_BUF_SIZE * 2); + if (variable_name == NULL) + return EFI_OUT_OF_RESOURCES; + + while (1) { + variable_name_size = GNVN_BUF_SIZE; + rc = uefi_call_wrapper(RT->GetNextVariableName, 3, + &variable_name_size, variable_name, + &vendor_guid); + if (rc == EFI_NOT_FOUND) + break; + /* ignore any huge names */ + if (rc == EFI_BUFFER_TOO_SMALL) + continue; + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable name: %r", rc); + return rc; + } + + /* check if the variable name is Boot#### */ + if (CompareGuid(&vendor_guid, &global_variable_guid) != 0) + continue; + if (StrCmp(variable_name, L"Boot") != 0) + continue; + + UINTN info_size = 0; + _cleanup_free VOID *info_ptr = NULL; + + /* get the data */ + rc = fwup_get_variable(variable_name, &vendor_guid, + &info_ptr, &info_size, NULL); + if (EFI_ERROR(rc)) + return rc; + if (info_size < sizeof(EFI_LOAD_OPTION)) + continue; + + /* + * check if the boot path created by fwupdate, + * check with EFI_LOAD_OPTION description + */ + EFI_LOAD_OPTION *load_op = (EFI_LOAD_OPTION *) info_ptr; + if (_StrHasPrefix(load_op->description, L"Linux Firmware Updater") || + _StrHasPrefix(load_op->description, L"Linux-Firmware-Updater")) { + /* delete the boot path from BootOrder list */ + rc = fwup_delete_boot_order(variable_name, vendor_guid); + if (EFI_ERROR(rc)) { + fwup_warning(L"Failed to delete boot entry from BootOrder"); + return rc; + } + rc = fwup_delete_variable(variable_name, &vendor_guid); + if (EFI_ERROR(rc)) { + fwup_warning(L"Failed to delete boot entry"); + return rc; + } + break; + } + } + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_get_gop_mode(UINT32 *mode, EFI_HANDLE loaded_image) +{ + EFI_HANDLE *handles, gop_handle; + UINTN num_handles; + EFI_STATUS status; + EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + VOID *iface; + + status = LibLocateHandle(ByProtocol, &gop_guid, NULL, &num_handles, + &handles); + if (EFI_ERROR(status)) + return status; + + if (handles == NULL || num_handles == 0) + return EFI_UNSUPPORTED; + + for (UINTN i = 0; i < num_handles; i++) { + gop_handle = handles[i]; + + status = uefi_call_wrapper(BS->OpenProtocol, 6, + gop_handle, &gop_guid, &iface, + loaded_image, 0, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(status)) + continue; + + gop = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)iface; + + *mode = gop->Mode->Mode; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +static inline void +fwup_update_ux_capsule_checksum(UX_CAPSULE_HEADER *payload_hdr) +{ + UINT8 *buf = (UINT8 *)payload_hdr; + UINT8 sum = 0; + + payload_hdr->checksum = 0; + for (UINTN i = 0; i < sizeof(*payload_hdr); i++) + sum = (UINT8) (sum + buf[i]); + payload_hdr->checksum = sum; +} + +static EFI_STATUS +fwup_check_gop_for_ux_capsule(EFI_HANDLE loaded_image, + EFI_CAPSULE_HEADER *capsule) +{ + UX_CAPSULE_HEADER *payload_hdr; + EFI_STATUS rc; + + payload_hdr = (UX_CAPSULE_HEADER *) (((UINT8 *) capsule) + capsule->HeaderSize); + rc = fwup_get_gop_mode(&payload_hdr->mode, loaded_image); + if (EFI_ERROR(rc)) + return EFI_UNSUPPORTED; + + fwup_update_ux_capsule_checksum(payload_hdr); + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_add_update_capsule(FWUP_UPDATE_TABLE *update, EFI_CAPSULE_HEADER **capsule_out, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_out, EFI_HANDLE loaded_image) +{ + EFI_STATUS rc; + EFI_FILE_HANDLE fh = NULL; + UINT8 *fbuf = NULL; + UINTN fsize = 0; + EFI_CAPSULE_HEADER *capsule; + + UINTN cbd_len; + EFI_PHYSICAL_ADDRESS cbd_data; + EFI_CAPSULE_HEADER *cap_out; + + rc = fwup_open_file((EFI_DEVICE_PATH *)update->info->dp_buf, &fh); + if (EFI_ERROR(rc)) + return rc; + + rc = fwup_read_file(fh, &fbuf, &fsize); + if (EFI_ERROR(rc)) + return rc; + + uefi_call_wrapper(fh->Close, 1, fh); + + if (fsize < sizeof(EFI_CAPSULE_HEADER)) { + fwup_warning(L"Invalid capsule size %d", fsize); + return EFI_INVALID_PARAMETER; + } + + fwup_debug(L"Read file; %d bytes", fsize); + fwup_debug(L"updates guid: %g", &update->info->guid); + fwup_debug(L"File guid: %g", fbuf); + + cbd_len = fsize; + cbd_data = (EFI_PHYSICAL_ADDRESS)(UINTN)fbuf; + capsule = cap_out = (EFI_CAPSULE_HEADER *)fbuf; + if (cap_out->Flags == 0 && + CompareGuid(&update->info->guid, &ux_capsule_guid) != 0) { +#if defined(__aarch64__) + cap_out->Flags |= update->info->capsule_flags; +#else + cap_out->Flags |= update->info->capsule_flags | + CAPSULE_FLAGS_PERSIST_ACROSS_RESET | + CAPSULE_FLAGS_INITIATE_RESET; +#endif + } + + if (CompareGuid(&update->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"Checking GOP for ux capsule"); + rc = fwup_check_gop_for_ux_capsule(loaded_image, capsule); + if (EFI_ERROR(rc)) + return EFI_UNSUPPORTED; + } + + cbd_out->Length = cbd_len; + cbd_out->Union.DataBlock = cbd_data; + *capsule_out = cap_out; + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_apply_capsules(EFI_CAPSULE_HEADER **capsules, + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd, + UINTN num_updates, EFI_RESET_TYPE *reset) +{ + UINT64 max_capsule_size; + EFI_STATUS rc; + + /* still try to apply capsule on failure */ + rc = fwup_delete_boot_entry(); + if (EFI_ERROR(rc)) + fwup_warning(L"Could not delete boot entry: %r", rc); + + rc = uefi_call_wrapper(RT->QueryCapsuleCapabilities, 4, capsules, + num_updates, &max_capsule_size, reset); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not query capsule capabilities: %r", rc); + return rc; + } + fwup_debug(L"QueryCapsuleCapabilities: %r max: %ld reset:%d", + rc, max_capsule_size, *reset); + fwup_debug(L"Capsules: %d", num_updates); + + fwup_msleep(1 * SECONDS); + rc = uefi_call_wrapper(RT->UpdateCapsule, 3, capsules, num_updates, + (EFI_PHYSICAL_ADDRESS)(UINTN)cbd); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not apply capsule update: %r", rc); + return rc; + } + + return EFI_SUCCESS; +} + +static EFI_STATUS +fwup_set_update_statuses(FWUP_UPDATE_TABLE **updates) +{ + EFI_STATUS rc; + for (UINTN i = 0; i < FWUP_NUM_CAPSULE_UPDATES_MAX; i++) { + if (updates[i] == NULL || updates[i]->name == NULL) + break; + rc = fwup_set_variable(updates[i]->name, &fwupdate_guid, + updates[i]->info, updates[i]->size, + updates[i]->attrs); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not update variable status for '%s': %r", + updates[i]->name, rc); + return rc; + } + } + return EFI_SUCCESS; +} + +EFI_GUID SHIM_LOCK_GUID = + {0x605dab50,0xe046,0x4300,{0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23}}; + +static VOID +__attribute__((__optimize__("0"))) +fwup_debug_hook(VOID) +{ + EFI_GUID guid = SHIM_LOCK_GUID; + UINTN data = 0; + UINTN data_size = 1; + EFI_STATUS efi_status; + UINT32 attrs; + register volatile int x = 0; + extern char _text UNUSED, _data UNUSED; + + /* shim has done whatever is needed to get a debugger attached */ + efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SHIM_DEBUG", + &guid, &attrs, &data_size, &data); + if (EFI_ERROR(efi_status) || data != 1) { + efi_status = uefi_call_wrapper(RT->GetVariable, 5, + L"FWUPDATE_VERBOSE", + &fwupdate_guid, &attrs, + &data_size, &data); + if (EFI_ERROR(efi_status) || data != 1) + return; + fwup_debug_set_enabled(TRUE); + return; + } + + fwup_debug_set_enabled(TRUE); + if (x) + return; + + x = 1; + fwup_info(L"add-symbol-file "DEBUGDIR + L"fwupdate.efi.debug %p -s .data %p", + &_text, &_data); +} + +EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) +{ + EFI_STATUS rc; + UINTN i, n_updates = 0; + EFI_RESET_TYPE reset_type = EfiResetWarm; + _cleanup_free FWUP_UPDATE_TABLE **updates = NULL; + + InitializeLib(image, systab); + + /* if SHIM_DEBUG is set, fwup_info info for our attached debugger */ + fwup_debug_hook(); + + /* step 1: find and validate update state variables */ + /* XXX TODO: + * 1) survey the reset types first, and separate into groups + * according to them + * 2) if there's more than one, mirror BootCurrent back into BootNext + * so we can do multiple runs + * 3) only select the ones from one type for the first go + */ + updates = fwup_new0(FWUP_UPDATE_TABLE *, FWUP_NUM_CAPSULE_UPDATES_MAX); + if (updates == NULL) + return EFI_OUT_OF_RESOURCES; + rc = fwup_populate_update_table(updates, &n_updates); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not find updates: %r", rc); + return rc; + } + if (n_updates == 0) { + fwup_warning(L"No updates to process. Called in error?"); + return EFI_INVALID_PARAMETER; + } + + /* step 2: Build our data structure and add the capsules to it */ + _cleanup_free EFI_CAPSULE_HEADER **capsules = NULL; + capsules = fwup_new0(EFI_CAPSULE_HEADER *, n_updates + 1); + EFI_CAPSULE_BLOCK_DESCRIPTOR *cbd_data; + UINTN j = 0; + cbd_data = fwup_malloc_raw(sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR)*(n_updates+1)); + if (cbd_data == NULL) + return EFI_OUT_OF_RESOURCES; + for (i = 0; i < n_updates; i++) { + fwup_info(L"Adding new capsule"); + rc = fwup_add_update_capsule(updates[i], &capsules[j], &cbd_data[j], image); + if (EFI_ERROR(rc)) { + /* ignore a failing UX capsule */ + if (rc == EFI_UNSUPPORTED && + CompareGuid(&updates[i]->info->guid, &ux_capsule_guid) == 0) { + fwup_debug(L"GOP unsuitable: %r", rc); + continue; + } + fwup_warning(L"Could not build update list: %r", rc); + return rc; + } + j++; + } + n_updates = j; + fwup_debug(L"n_updates: %d", n_updates); + + cbd_data[i].Length = 0; + cbd_data[i].Union.ContinuationPointer = 0; + + /* step 3: update the state variables */ + rc = fwup_set_update_statuses(updates); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not set update status: %r", rc); + return rc; + } + + /* step 4: apply the capsules */ + rc = fwup_apply_capsules(capsules, cbd_data, n_updates, &reset_type); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not apply capsules: %r", rc); + return rc; + } + + /* step 5: if #4 didn't reboot us, do it manually */ + fwup_info(L"Reset System"); + fwup_msleep(5 * SECONDS); + if (fwup_debug_get_enabled()) + fwup_msleep(30 * SECONDS); + uefi_call_wrapper(RT->ResetSystem, 4, reset_type, EFI_SUCCESS, 0, NULL); + + return EFI_SUCCESS; +} diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-debug.c fwupd-1.2.10/plugins/uefi/efi/fwup-debug.c --- fwupd-1.0.6/plugins/uefi/efi/fwup-debug.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-debug.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +static BOOLEAN debugging = FALSE; + +BOOLEAN +fwup_debug_get_enabled(VOID) +{ + return debugging; +} + +VOID +fwup_debug_set_enabled(BOOLEAN val) +{ + debugging = val; +} + +static VOID +fwupd_debug_efivar_append(CHAR16 *out1) +{ + CHAR16 *name = L"FWUPDATE_DEBUG_LOG"; + UINT32 attrs = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + static BOOLEAN once = TRUE; + if (once) { + once = FALSE; + fwup_delete_variable(name, &fwupdate_guid); + } else { + attrs |= EFI_VARIABLE_APPEND_WRITE; + } + fwup_set_variable(name, &fwupdate_guid, out1, StrSize(out1) - sizeof(CHAR16), attrs); +} + +VOID +fwup_log(FwupLogLevel level, const char *func, const char *file, const int line, CHAR16 *fmt, ...) +{ + va_list args; + _cleanup_free CHAR16 *tmp = NULL; + + va_start(args, fmt); + tmp = VPoolPrint(fmt, args); + va_end(args); + if (tmp == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + + if (debugging) { + _cleanup_free CHAR16 *out1 = NULL; + out1 = PoolPrint(L"%a:%d:%a(): %s", file, line, func, tmp); + if (out1 == NULL) { + Print(L"fwupdate: Allocation for debug log failed!\n"); + return; + } + Print(L"%s\n", out1); + fwupd_debug_efivar_append(out1); + } else { + switch (level) { + case FWUP_DEBUG_LEVEL_DEBUG: + break; + case FWUP_DEBUG_LEVEL_WARNING: + Print(L"WARNING: %s\n", tmp); + break; + default: + Print(L"%s\n", tmp); + break; + } + } +} diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-debug.h fwupd-1.2.10/plugins/uefi/efi/fwup-debug.h --- fwupd-1.0.6/plugins/uefi/efi/fwup-debug.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-debug.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015-2016 Peter Jones + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +typedef enum { + FWUP_DEBUG_LEVEL_DEBUG, + FWUP_DEBUG_LEVEL_INFO, + FWUP_DEBUG_LEVEL_WARNING, + FWUP_DEBUG_LEVEL_LAST +} FwupLogLevel; + +VOID fwup_log (FwupLogLevel level, + const char *func, + const char *file, + const int line, + CHAR16 *fmt, + ...); + +BOOLEAN fwup_debug_get_enabled (VOID); +VOID fwup_debug_set_enabled (BOOLEAN val); + +#define fwup_debug(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_DEBUG, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_info(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_INFO, __func__, __FILE__, __LINE__, fmt, ## args ) +#define fwup_warning(fmt, args...) fwup_log(FWUP_DEBUG_LEVEL_WARNING, __func__, __FILE__, __LINE__, fmt, ## args ) diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-efi.c fwupd-1.2.10/plugins/uefi/efi/fwup-efi.c --- fwupd-1.0.6/plugins/uefi/efi/fwup-efi.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-efi.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include + +#include "fwup-cleanups.h" +#include "fwup-common.h" +#include "fwup-debug.h" +#include "fwup-efi.h" + +EFI_STATUS +fwup_delete_variable(CHAR16 *name, EFI_GUID *guid) +{ + EFI_STATUS rc; + UINT32 attrs = 0; + + /* get the attrs so we can delete it */ + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, NULL, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_NOT_FOUND) { + fwup_debug(L"Not deleting variable '%s' as not found", name); + return EFI_SUCCESS; + } + fwup_debug(L"Could not get variable '%s' for delete: %r", name, rc); + return rc; + } + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, 0, NULL); +} + +EFI_STATUS +fwup_set_variable(CHAR16 *name, EFI_GUID *guid, VOID *data, UINTN size, UINT32 attrs) +{ + return uefi_call_wrapper(RT->SetVariable, 5, name, guid, attrs, size, data); +} + +EFI_STATUS +fwup_get_variable(CHAR16 *name, EFI_GUID *guid, VOID **buf_out, UINTN *buf_size_out, UINT32 *attrs_out) +{ + EFI_STATUS rc; + UINTN size = 0; + UINT32 attrs; + _cleanup_free VOID *buf = NULL; + + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, NULL); + if (EFI_ERROR(rc)) { + if (rc == EFI_BUFFER_TOO_SMALL) { + buf = fwup_malloc(size); + if (buf == NULL) + return EFI_OUT_OF_RESOURCES; + } else if (rc != EFI_NOT_FOUND) { + fwup_debug(L"Could not get variable '%s': %r", name, rc); + return rc; + } + } else { + fwup_debug(L"GetVariable(%s) succeeded with size=0", name); + return EFI_INVALID_PARAMETER; + } + rc = uefi_call_wrapper(RT->GetVariable, 5, name, guid, &attrs, &size, buf); + if (EFI_ERROR(rc)) { + fwup_warning(L"Could not get variable '%s': %r", name, rc); + return rc; + } + *buf_out = _steal_pointer(&buf); + *buf_size_out = size; + *attrs_out = attrs; + return EFI_SUCCESS; +} diff -Nru fwupd-1.0.6/plugins/uefi/efi/fwup-efi.h fwupd-1.2.10/plugins/uefi/efi/fwup-efi.h --- fwupd-1.0.6/plugins/uefi/efi/fwup-efi.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/fwup-efi.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#define FWUPDATE_ATTEMPT_UPDATE 0x00000001 +#define FWUPDATE_ATTEMPTED 0x00000002 + +#define UPDATE_INFO_VERSION 7 + +static __attribute__((__unused__)) EFI_GUID empty_guid = + {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}; +static __attribute__((__unused__))EFI_GUID fwupdate_guid = + {0x0abba7dc,0xe516,0x4167,{0xbb,0xf5,0x4d,0x9d,0x1c,0x73,0x94,0x16}}; +static __attribute__((__unused__))EFI_GUID ux_capsule_guid = + {0x3b8c8162,0x188c,0x46a4,{0xae,0xc9,0xbe,0x43,0xf1,0xd6,0x56,0x97}}; +static __attribute__((__unused__))EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; + +typedef struct { + UINT8 version; + UINT8 checksum; + UINT8 image_type; + UINT8 reserved; + UINT32 mode; + UINT32 x_offset; + UINT32 y_offset; +} __attribute__((__packed__)) UX_CAPSULE_HEADER; + +typedef struct { + UINT32 update_info_version; + + /* stuff we need to apply an update */ + EFI_GUID guid; + UINT32 capsule_flags; + UINT64 hw_inst; + + EFI_TIME time_attempted; + + /* our metadata */ + UINT32 status; + + /* variadic device path */ + union { + EFI_DEVICE_PATH dp; + UINT8 dp_buf[0]; + }; +} __attribute__((__packed__)) FWUP_UPDATE_INFO; + +typedef struct { + UINT32 attributes; + UINT16 file_path_list_length; + CHAR16 *description; +} __attribute__((__packed__)) EFI_LOAD_OPTION; + +EFI_STATUS fwup_delete_variable (CHAR16 *name, + EFI_GUID *guid); +EFI_STATUS fwup_set_variable (CHAR16 *name, + EFI_GUID *guid, + VOID *data, + UINTN size, + UINT32 attrs); +EFI_STATUS fwup_get_variable (CHAR16 *name, + EFI_GUID *guid, + VOID **buf_out, + UINTN *buf_size_out, + UINT32 *attrs_out); diff -Nru fwupd-1.0.6/plugins/uefi/efi/meson.build fwupd-1.2.10/plugins/uefi/efi/meson.build --- fwupd-1.0.6/plugins/uefi/efi/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/efi/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,173 @@ +efi_cc = get_option('efi-cc') +efi_ld = get_option('efi-ld') +efi_ldsdir = get_option('efi-ldsdir') +efi_incdir = get_option('efi-includedir') + +gnu_efi_path_arch = '' +foreach name : [gnu_efi_arch, EFI_MACHINE_TYPE_NAME] + if (gnu_efi_path_arch == '' and name != '' and + cc.has_header('@0@/@1@/efibind.h'.format(efi_incdir, name))) + gnu_efi_path_arch = name + endif +endforeach + +if gnu_efi_path_arch != '' and EFI_MACHINE_TYPE_NAME == '' + error('gnu-efi is available, but EFI_MACHINE_TYPE_NAME is unknown') +endif + +efi_libdir = get_option('efi-libdir') +if efi_libdir == '' + cmd = 'cd /usr/lib/$(@0@ -print-multi-os-directory) && pwd'.format(efi_cc) + ret = run_command('sh', '-c', cmd) + if ret.returncode() == 0 + efi_libdir = ret.stdout().strip() + endif +endif + +have_gnu_efi = gnu_efi_path_arch != '' and efi_libdir != '' + +if not have_gnu_efi + error('gnu-efi support requested, but headers were not found') +endif + +arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch) +if efi_ldsdir == '' + efi_ldsdir = join_paths(efi_libdir, 'gnuefi') + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + if cmd.returncode() != 0 + efi_ldsdir = efi_libdir + cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds)) + if cmd.returncode() != 0 + error('Cannot find @0@'.format(arch_lds)) + endif + endif +endif + +message('efi-libdir: "@0@"'.format(efi_libdir)) +message('efi-ldsdir: "@0@"'.format(efi_ldsdir)) +message('efi-includedir: "@0@"'.format(efi_incdir)) + +debugdir = join_paths (libdir, 'debug') +compile_args = ['-Og', + '-g3', + '--param=ssp-buffer-size=4', + '-fexceptions', + '-Wall', + '-Wextra', + '-Wvla', + '-std=gnu11', + '-fpic', + '-fshort-wchar', + '-ffreestanding', + '-fno-strict-aliasing', + '-fno-stack-protector', + '-fno-stack-check', + '-fno-merge-constants', + '-Wsign-compare', + '-Wno-missing-field-initializers', + '-Wno-address-of-packed-member', + '-grecord-gcc-switches', + '-DDEBUGDIR="@0@"'.format(debugdir), + '-isystem', efi_incdir, + '-isystem', join_paths(efi_incdir, gnu_efi_path_arch)] +if get_option('werror') + compile_args += '-Werror' +endif +if efi_arch == 'x86_64' + compile_args += ['-mno-red-zone', + '-mno-sse', + '-mno-mmx', + '-DEFI_FUNCTION_WRAPPER', + '-DGNU_EFI_USE_MS_ABI'] +elif efi_arch == 'ia32' + compile_args += ['-mno-sse', + '-mno-mmx', + '-mno-red-zone', + '-m32'] +# no special cases for aarch64 or arm +endif + +efi_ldflags = ['-T', + join_paths(efi_ldsdir, arch_lds), + '-shared', + '-Bsymbolic', + '-nostdlib', + '-znocombreloc', + '-L', efi_libdir, + join_paths(efi_ldsdir, 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))] +if efi_arch == 'aarch64' or efi_arch == 'arm' + # Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary' + # instead, and add required symbols manually. + efi_ldflags += ['--defsym=EFI_SUBSYSTEM=0xa'] + efi_format = ['-O', 'binary'] +else + efi_format = ['--target=efi-app-@0@'.format(gnu_efi_arch)] +endif + +libgcc_file_name = run_command(efi_cc, '-print-libgcc-file-name').stdout().strip() +efi_name = 'fwupd@0@.efi'.format(EFI_MACHINE_TYPE_NAME) + +o_file1 = custom_target('fwupdate.o', + input : 'fwupdate.c', + output : 'fwupdate.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file2 = custom_target('fwup-debug.o', + input : 'fwup-debug.c', + output : 'fwup-debug.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file3 = custom_target('fwup-efi.o', + input : 'fwup-efi.c', + output : 'fwup-efi.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) +o_file4 = custom_target('fwup-common.o', + input : 'fwup-common.c', + output : 'fwup-common.o', + command : [efi_cc, '-c', '@INPUT@', '-o', '@OUTPUT@'] + + compile_args) + +so = custom_target('fwup.so', + input : [o_file1, o_file2, o_file3, o_file4], + output : 'fwup.so', + command : [efi_ld, '-o', '@OUTPUT@'] + + efi_ldflags + ['@INPUT@'] + + ['-lefi', '-lgnuefi', libgcc_file_name]) + +app = custom_target(efi_name, + input : so, + output : efi_name, + command : [objcopy, + '-j', '.text', + '-j', '.sdata', + '-j', '.data', + '-j', '.dynamic', + '-j', '.dynsym', + '-j', '.rel', + '-j', '.rela', + '-j', '.reloc'] + + efi_format + + ['@INPUT@', '@OUTPUT@'], + install : true, + install_dir : efi_app_location) + +dbg = custom_target('efi_debug', + input : so, + output : efi_name + '.debug', + command : [objcopy, + '-j', '.text', + '-j', '.sdata', + '-j', '.data', + '-j', '.dynamic', + '-j', '.dynsym', + '-j', '.rel*', + '-j', '.rela*', + '-j', '.reloc', + '-j', '.eh_frame', + '-j', '.debug*', + '-j', '.note.gnu.build-id'] + + efi_format + + ['@INPUT@', '@OUTPUT@'], + install : false, + install_dir : debugdir) diff -Nru fwupd-1.0.6/plugins/uefi/fu-plugin-uefi.c fwupd-1.2.10/plugins/uefi/fu-plugin-uefi.c --- fwupd-1.0.6/plugins/uefi/fu-plugin-uefi.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-plugin-uefi.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,63 +1,46 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2016-2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include -#include #include #include +#include #include -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" -#ifndef HAVE_FWUP_GET_ESP_MOUNTPOINT -#define FWUP_SUPPORTED_STATUS_UNSUPPORTED 0 -#define FWUP_SUPPORTED_STATUS_UNLOCKED 1 -#define FWUP_SUPPORTED_STATUS_LOCKED_CAN_UNLOCK 2 -#define FWUP_SUPPORTED_STATUS_LOCKED_CAN_UNLOCK_NEXT_BOOT 3 -#define FWUPDATE_GUID EFI_GUID(0x0abba7dc,0xe516,0x4167,0xbbf5,0x4d,0x9d,0x1c,0x73,0x94,0x16) +#include "fu-uefi-bgrt.h" +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-vars.h" + +#ifndef HAVE_GIO_2_55_0 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) +#pragma clang diagnostic pop #endif struct FuPluginData { - gboolean ux_capsule; gchar *esp_path; - gint esrt_status; + gboolean require_shim_for_sb; + FuUefiBgrt *bgrt; }; -/* drop when upgrading minimum required version of efivar to 33 */ -#if !defined (efi_guid_ux_capsule) -#define efi_guid_ux_capsule EFI_GUID(0x3b8c8162,0x188c,0x46a4,0xaec9,0xbe,0x43,0xf1,0xd6,0x56,0x97) -#endif - void fu_plugin_init (FuPlugin *plugin) { FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - data->ux_capsule = FALSE; - data->esp_path = NULL; + data->bgrt = fu_uefi_bgrt_new (); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_AFTER, "upower"); - fu_plugin_add_report_metadata (plugin, "FwupdateVersion", LIBFWUP_LIBRARY_VERSION); - fu_plugin_add_report_metadata (plugin, "EfivarVersion", EFIVAR_LIBRARY_VERSION); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "org.uefi.capsule"); + fu_plugin_add_compile_version (plugin, "com.redhat.efivar", EFIVAR_LIBRARY_VERSION); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } void @@ -65,164 +48,48 @@ { FuPluginData *data = fu_plugin_get_data (plugin); g_free (data->esp_path); + g_object_unref (data->bgrt); } -static gchar * -fu_plugin_uefi_guid_to_string (efi_guid_t *guid_raw) -{ - g_autofree gchar *guid = g_strdup ("00000000-0000-0000-0000-000000000000"); - if (efi_guid_to_str (guid_raw, &guid) < 0) - return NULL; - return g_steal_pointer (&guid); -} - -static fwup_resource * -fu_plugin_uefi_find (fwup_resource_iter *iter, const gchar *guid_str, GError **error) -{ - efi_guid_t *guid_raw; - fwup_resource *re_matched = NULL; - fwup_resource *re = NULL; - - /* get the hardware we're referencing */ - while (fwup_resource_iter_next (iter, &re) > 0) { - g_autofree gchar *guid_tmp = NULL; - - /* convert to strings */ - fwup_get_guid (re, &guid_raw); - guid_tmp = fu_plugin_uefi_guid_to_string (guid_raw); - if (guid_tmp == NULL) { - g_warning ("failed to convert guid to string"); - continue; - } - - /* FIXME: also match hardware_instance too */ - if (g_strcmp0 (guid_str, guid_tmp) == 0) { - re_matched = re; - break; - } - } - - /* paradoxically, no hardware matched */ - if (re_matched == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "No UEFI firmware matched %s", - guid_str); - } - - return re_matched; -} - -static void -_fwup_resource_iter_free (fwup_resource_iter *iter) -{ - fwup_resource_iter_destroy (&iter); -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(fwup_resource_iter, _fwup_resource_iter_free); - gboolean fu_plugin_clear_results (FuPlugin *plugin, FuDevice *device, GError **error) { - fwup_resource *re = NULL; - g_autoptr(fwup_resource_iter) iter = NULL; - - /* get the hardware we're referencing */ - fwup_resource_iter_create (&iter); - re = fu_plugin_uefi_find (iter, fu_device_get_guid_default (device), error); - if (re == NULL) - return FALSE; - if (fwup_clear_status (re) < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Cannot create clear UEFI status for %s", - fu_device_get_guid_default (device)); - return FALSE; - } - return TRUE; + FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); + return fu_uefi_device_clear_status (device_uefi, error); } gboolean fu_plugin_get_results (FuPlugin *plugin, FuDevice *device, GError **error) { + FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); + FuUefiDeviceStatus status = fu_uefi_device_get_status (device_uefi); const gchar *tmp; - fwup_resource *re = NULL; - guint32 status = 0; - guint32 version = 0; - time_t when = 0; - g_autoptr(fwup_resource_iter) iter = NULL; - - /* get the hardware we're referencing */ - fwup_resource_iter_create (&iter); - re = fu_plugin_uefi_find (iter, fu_device_get_guid_default (device), error); - if (re == NULL) - return FALSE; - if (fwup_get_last_attempt_info (re, &version, &status, &when) < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Cannot get UEFI status for %s", - fu_device_get_guid_default (device)); - return FALSE; - } - if (status == FWUP_LAST_ATTEMPT_STATUS_SUCCESS) { + g_autofree gchar *err_msg = NULL; + g_autofree gchar *version_str = NULL; + + /* trivial case */ + if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) { fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); + return TRUE; + } + + /* something went wrong */ + if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC || + status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED_TRANSIENT); } else { - g_autofree gchar *err_msg = NULL; - g_autofree gchar *version_str = g_strdup_printf ("%u", version); fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); - tmp = fwup_last_attempt_status_to_string (status); - if (tmp == NULL) { - err_msg = g_strdup_printf ("failed to update to %s", - version_str); - } else { - err_msg = g_strdup_printf ("failed to update to %s: %s", - version_str, tmp); - } - fu_device_set_update_error (device, err_msg); } - return TRUE; -} - -static gboolean -fu_plugin_uefi_update_resource (fwup_resource *re, - guint64 hardware_instance, - GBytes *blob, - GError **error) -{ - int rc; - rc = fwup_set_up_update_with_buf (re, hardware_instance, - g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob)); - if (rc < 0) { - g_autoptr(GString) str = g_string_new (NULL); - rc = 1; - for (int i = 0; rc > 0; i++) { - char *filename = NULL; - char *function = NULL; - char *message = NULL; - int line = 0; - int err = 0; - - rc = efi_error_get (i, &filename, &function, &line, - &message, &err); - if (rc <= 0) - break; - g_string_append_printf (str, "{error #%d} %s:%d %s(): %s: %s\t", - i, filename, line, function, - message, strerror (err)); - } - if (str->len > 1) - g_string_truncate (str, str->len - 1); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "UEFI firmware update failed: %s", - str->str); - return FALSE; + version_str = g_strdup_printf ("%u", fu_uefi_device_get_version_error (device_uefi)); + tmp = fu_uefi_device_status_to_string (status); + if (tmp == NULL) { + err_msg = g_strdup_printf ("failed to update to %s", + version_str); + } else { + err_msg = g_strdup_printf ("failed to update to %s: %s", + version_str, tmp); } + fu_device_set_update_error (device, err_msg); return TRUE; } @@ -297,18 +164,112 @@ return g_bytes_new_take (g_steal_pointer (&buf), buf_idx); } +static guint8 +fu_plugin_uefi_calc_checksum (const guint8 *buf, gsize sz) +{ + guint8 csum = 0; + for (gsize i = 0; i < sz; i++) + csum += buf[i]; + return csum; +} + +static gboolean +fu_plugin_uefi_write_splash_data (FuPlugin *plugin, + FuDevice *device, + GBytes *blob, + GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + guint32 screen_x, screen_y; + gsize buf_size = g_bytes_get_size (blob); + gssize size; + guint32 height, width; + guint8 csum = 0; + efi_ux_capsule_header_t header = { 0 }; + efi_capsule_header_t capsule_header = { + .flags = EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET, + .guid = efi_guid_ux_capsule, + .header_size = sizeof(efi_capsule_header_t), + .capsule_image_size = 0 + }; + g_autofree gchar *fn = NULL; + g_autofree gchar *directory = NULL; + g_autofree gchar *basename = NULL; + g_autoptr(GFile) ofile = NULL; + g_autoptr(GOutputStream) ostream = NULL; + + /* get screen dimensions */ + if (!fu_uefi_get_framebuffer_size (&screen_x, &screen_y, error)) + return FALSE; + if (!fu_uefi_get_bitmap_size ((const guint8 *) g_bytes_get_data (blob, NULL), + buf_size, &width, &height, error)) { + g_prefix_error (error, "splash invalid: "); + return FALSE; + } + + /* save to a predicatable filename */ + directory = fu_uefi_get_esp_path_for_os (data->esp_path); + basename = g_strdup_printf ("fwupd-%s.cap", FU_UEFI_VARS_GUID_UX_CAPSULE); + fn = g_build_filename (directory, "fw", basename, NULL); + if (!fu_common_mkdir_parent (fn, error)) + return FALSE; + ofile = g_file_new_for_path (fn); + ostream = G_OUTPUT_STREAM (g_file_replace (ofile, NULL, FALSE, + G_FILE_CREATE_NONE, NULL, error)); + if (ostream == NULL) + return FALSE; + + capsule_header.capsule_image_size = + g_bytes_get_size (blob) + + sizeof(efi_capsule_header_t) + + sizeof(efi_ux_capsule_header_t); + + header.version = 1; + header.image_type = 0; + header.reserved = 0; + header.x_offset = (screen_x / 2) - (width / 2); + header.y_offset = fu_uefi_bgrt_get_yoffset (data->bgrt) + + fu_uefi_bgrt_get_height (data->bgrt); + + /* header, payload and image has to add to zero */ + csum += fu_plugin_uefi_calc_checksum ((guint8 *) &capsule_header, + sizeof(capsule_header)); + csum += fu_plugin_uefi_calc_checksum ((guint8 *) &header, + sizeof(header)); + csum += fu_plugin_uefi_calc_checksum (g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + header.checksum = 0x100 - csum; + + /* write capsule file */ + size = g_output_stream_write (ostream, &capsule_header, + capsule_header.header_size, NULL, error); + if (size < 0) + return FALSE; + size = g_output_stream_write (ostream, &header, sizeof(header), NULL, error); + if (size < 0) + return FALSE; + size = g_output_stream_write_bytes (ostream, blob, NULL, error); + if (size < 0) + return FALSE; + + /* write display capsule location as UPDATE_INFO */ + if (!fu_uefi_device_write_update_info (FU_UEFI_DEVICE (device), fn, + "fwupd-ux-capsule", + &efi_guid_ux_capsule, error)) + return FALSE; + + /* success */ + return TRUE; +} + static gboolean -fu_plugin_uefi_update_splash (GError **error) +fu_plugin_uefi_update_splash (FuPlugin *plugin, FuDevice *device, GError **error) { - fwup_resource *re = NULL; + FuPluginData *data = fu_plugin_get_data (plugin); guint best_idx = G_MAXUINT; guint32 lowest_border_pixels = G_MAXUINT; -#ifdef HAVE_FWUP_GET_BGRT_INFO - int rc; -#endif guint32 screen_height = 768; guint32 screen_width = 1024; - g_autoptr(fwup_resource_iter) iter = NULL; g_autoptr(GBytes) image_bmp = NULL; struct { @@ -326,19 +287,25 @@ { 0, 0 } }; + /* no UX capsule support, so deleting var if it exists */ + if (fu_device_has_custom_flag (device, "no-ux-capsule")) { + g_debug ("not providing UX capsule"); + return fu_uefi_vars_delete (FU_UEFI_VARS_GUID_FWUPDATE, + "fwupd-ux-capsule", error); + } + /* get the boot graphics resource table data */ -#ifdef HAVE_FWUP_GET_BGRT_INFO - rc = fwup_get_ux_capsule_info (&screen_width, &screen_height); - if (rc < 0) { + if (!fu_uefi_bgrt_get_supported (data->bgrt)) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "failed to get BGRT screen size"); + "BGRT is not supported"); return FALSE; } - g_debug ("BGRT screen size %" G_GUINT32_FORMAT " x%" G_GUINT32_FORMAT, + if (!fu_uefi_get_framebuffer_size (&screen_width, &screen_height, error)) + return FALSE; + g_debug ("framebuffer size %" G_GUINT32_FORMAT " x%" G_GUINT32_FORMAT, screen_width, screen_height); -#endif /* find the 'best sized' pre-generated image */ for (guint i = 0; sizes[i].width != 0; i++) { @@ -374,7 +341,31 @@ return FALSE; /* perform the upload */ - return fu_plugin_uefi_update_resource (re, 0, image_bmp, error); + return fu_plugin_uefi_write_splash_data (plugin, device, image_bmp, error); +} + +static gboolean +fu_plugin_uefi_esp_mounted (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *contents = NULL; + g_auto(GStrv) lines = NULL; + gsize length; + + if (!g_file_get_contents ("/proc/mounts", &contents, &length, error)) + return FALSE; + lines = g_strsplit (contents, "\n", 0); + + for (guint i = 0; lines[i] != NULL; i++) { + if (lines[i] != NULL && g_strrstr (lines[i], data->esp_path)) + return TRUE; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "EFI System partition %s is not mounted", + data->esp_path); + return FALSE; } gboolean @@ -384,42 +375,58 @@ FwupdInstallFlags flags, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - fwup_resource *re = NULL; - guint64 hardware_instance = 0; /* FIXME */ - g_autoptr(fwup_resource_iter) iter = NULL; const gchar *str; + guint32 flashes_left; g_autofree gchar *efibootmgr_path = NULL; g_autofree gchar *boot_variables = NULL; g_autoptr(GError) error_splash = NULL; - /* get the hardware we're referencing */ - fwup_resource_iter_create (&iter); - re = fu_plugin_uefi_find (iter, fu_device_get_guid_default (device), error); - if (re == NULL) - return FALSE; + /* test the flash counter */ + flashes_left = fu_device_get_flashes_left (device); + if (flashes_left > 0) { + g_debug ("%s has %" G_GUINT32_FORMAT " flashes left", + fu_device_get_name (device), + flashes_left); + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && flashes_left <= 2) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s only has %" G_GUINT32_FORMAT " flashes left -- " + "see https://github.com/hughsie/fwupd/wiki/Dell-TPM:-flashes-left for more information.", + fu_device_get_name (device), flashes_left); + return FALSE; + } + } /* TRANSLATORS: this is shown when updating the firmware after the reboot */ str = _("Installing firmware update…"); g_assert (str != NULL); + /* make sure that the ESP is mounted */ + if (g_getenv ("FWUPD_UEFI_ESP_PATH") == NULL) { + if (!fu_plugin_uefi_esp_mounted (plugin, error)) + return FALSE; + } + /* perform the update */ g_debug ("Performing UEFI capsule update"); fu_device_set_status (device, FWUPD_STATUS_SCHEDULING); - - if (data->ux_capsule) { - if (!fu_plugin_uefi_update_splash (&error_splash)) { - g_warning ("failed to upload UEFI UX capsule text: %s", - error_splash->message); - } + if (!fu_plugin_uefi_update_splash (plugin, device, &error_splash)) { + g_debug ("failed to upload UEFI UX capsule text: %s", + error_splash->message); } - if (!fu_plugin_uefi_update_resource (re, hardware_instance, blob_fw, error)) + if (!fu_device_write_firmware (device, blob_fw, flags, error)) return FALSE; + /* record if we had an invalid header during update */ + str = fu_uefi_missing_capsule_header (device) ? "True" : "False"; + fu_plugin_add_report_metadata (plugin, "MissingCapsuleHeader", str); + /* record boot information to system log for future debugging */ - efibootmgr_path = g_find_program_in_path ("efibootmgr"); + efibootmgr_path = fu_common_find_program_in_path ("efibootmgr", NULL); if (efibootmgr_path != NULL) { - if (!g_spawn_command_line_sync ("efibootmgr -v", + g_autofree gchar *cmd = g_strdup_printf ("%s -v", efibootmgr_path); + if (!g_spawn_command_line_sync (cmd, &boot_variables, NULL, NULL, error)) return FALSE; g_message ("Boot Information:\n%s", boot_variables); @@ -428,78 +435,77 @@ return TRUE; } -static AsVersionParseFlag -fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, guint32 uefi_type) +static void +fu_plugin_uefi_register_proxy_device (FuPlugin *plugin, FuDevice *device) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_dev (device); + if (data->esp_path != NULL) + fu_device_set_metadata (FU_DEVICE (dev), "EspPath", data->esp_path); + fu_plugin_device_add (plugin, FU_DEVICE (dev)); +} + +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + if (fu_device_get_metadata (device, "UefiDeviceKind") != NULL) { + if (fu_device_get_guid_default (device) == NULL) { + g_autofree gchar *dbg = fu_device_to_string (device); + g_warning ("cannot create proxy device as no GUID: %s", dbg); + return; + } + fu_plugin_uefi_register_proxy_device (plugin, device); + } +} + +static FwupdVersionFormat +fu_plugin_uefi_get_version_format_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind) { const gchar *content; const gchar *quirk; + g_autofree gchar *group = NULL; /* we have no information for devices */ - if (uefi_type == FWUP_RESOURCE_TYPE_DEVICE_FIRMWARE) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) + return FWUPD_VERSION_FORMAT_TRIPLET; content = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); if (content == NULL) - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; + return FWUPD_VERSION_FORMAT_TRIPLET; /* any quirks match */ - quirk = fu_plugin_lookup_quirk_by_id (plugin, - FU_QUIRKS_UEFI_VERSION_FORMAT, - content); - if (g_strcmp0 (quirk, "none") == 0) - return AS_VERSION_PARSE_FLAG_NONE; - - /* fall back */ - return AS_VERSION_PARSE_FLAG_USE_TRIPLET; -} - -gboolean -fu_plugin_unlock (FuPlugin *plugin, - FuDevice *device, - GError **error) -{ - gint rc; - g_debug ("unlocking UEFI device %s", fu_device_get_id (device)); - rc = fwup_enable_esrt(); - if (rc <= 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to unlock UEFI device"); - return FALSE; - } else if (rc == 1) - g_debug ("UEFI device is already unlocked"); - else if (rc == 2) - g_debug ("Successfully unlocked UEFI device"); - else if (rc == 3) - g_debug ("UEFI device will be unlocked on next reboot"); - return TRUE; + group = g_strdup_printf ("SmbiosManufacturer=%s", content); + quirk = fu_plugin_lookup_quirk_by_id (plugin, group, + FU_QUIRKS_UEFI_VERSION_FORMAT); + if (quirk == NULL) + return FWUPD_VERSION_FORMAT_TRIPLET; + return fwupd_version_format_from_string (quirk); } static const gchar * -fu_plugin_uefi_uefi_type_to_string (guint32 uefi_type) +fu_plugin_uefi_uefi_type_to_string (FuUefiDeviceKind device_kind) { - if (uefi_type == FWUP_RESOURCE_TYPE_UNKNOWN) + if (device_kind == FU_UEFI_DEVICE_KIND_UNKNOWN) return "Unknown Firmware"; - if (uefi_type == FWUP_RESOURCE_TYPE_SYSTEM_FIRMWARE) + if (device_kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) return "System Firmware"; - if (uefi_type == FWUP_RESOURCE_TYPE_DEVICE_FIRMWARE) + if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) return "Device Firmware"; - if (uefi_type == FWUP_RESOURCE_TYPE_UEFI_DRIVER) + if (device_kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) return "UEFI Driver"; - if (uefi_type == FWUP_RESOURCE_TYPE_FMP) + if (device_kind == FU_UEFI_DEVICE_KIND_FMP) return "Firmware Management Protocol"; return NULL; } static gchar * -fu_plugin_uefi_get_name_for_type (FuPlugin *plugin, guint32 uefi_type) +fu_plugin_uefi_get_name_for_type (FuPlugin *plugin, FuUefiDeviceKind device_kind) { GString *display_name; /* set Display Name prefix for capsules that are not PCI cards */ - display_name = g_string_new (fu_plugin_uefi_uefi_type_to_string (uefi_type)); - if (uefi_type == FWUP_RESOURCE_TYPE_DEVICE_FIRMWARE) { + display_name = g_string_new (fu_plugin_uefi_uefi_type_to_string (device_kind)); + if (device_kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { g_string_prepend (display_name, "UEFI "); } else { const gchar *tmp; @@ -512,123 +518,53 @@ return g_string_free (display_name, FALSE); } -static void -fu_plugin_uefi_coldplug_resource (FuPlugin *plugin, fwup_resource *re) +static gboolean +fu_plugin_uefi_coldplug_device (FuPlugin *plugin, FuUefiDevice *dev, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - AsVersionParseFlag parse_flags; - efi_guid_t *guid_raw; - guint32 uefi_type; - guint32 version_raw; - guint64 hardware_instance = 0; /* FIXME */ - g_autofree gchar *guid = NULL; - g_autofree gchar *id = NULL; - g_autofree gchar *name = NULL; - g_autofree gchar *version_lowest = NULL; - g_autofree gchar *version = NULL; - g_autoptr(FuDevice) dev = NULL; - - /* detect the fake GUID used for uploading the image */ - fwup_get_guid (re, &guid_raw); - if (efi_guid_cmp (guid_raw, &efi_guid_ux_capsule) == 0) { - data->ux_capsule = TRUE; - return; - } - - /* convert to strings */ - guid = fu_plugin_uefi_guid_to_string (guid_raw); - if (guid == NULL) { - g_warning ("failed to convert guid to string"); - return; - } - - fwup_get_fw_type (re, &uefi_type); - parse_flags = fu_plugin_uefi_get_version_format_for_type (plugin, uefi_type); - fwup_get_fw_version (re, &version_raw); - version = as_utils_version_from_uint32 (version_raw, parse_flags); - id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT, - guid, hardware_instance); - - dev = fu_device_new (); - if (uefi_type == FWUP_RESOURCE_TYPE_DEVICE_FIRMWARE) { - /* nothing better in the icon naming spec */ - fu_device_add_icon (dev, "audio-card"); - } else { - /* this is probably system firmware */ - fu_device_add_icon (dev, "computer"); - } - fu_device_set_id (dev, id); - fu_device_add_guid (dev, guid); - fu_device_set_version (dev, version); - name = fu_plugin_uefi_get_name_for_type (plugin, uefi_type); - if (name != NULL) - fu_device_set_name (dev, name); - fwup_get_lowest_supported_fw_version (re, &version_raw); - if (version_raw != 0) { - version_lowest = as_utils_version_from_uint32 (version_raw, - parse_flags); - fu_device_set_version_lowest (dev, version_lowest); + FuUefiDeviceKind device_kind; + FwupdVersionFormat version_format; + + /* set default version format */ + device_kind = fu_uefi_device_get_kind (dev); + version_format = fu_plugin_uefi_get_version_format_for_type (plugin, device_kind); + fu_device_set_version_format (FU_DEVICE (dev), version_format); + + /* probe to get add GUIDs (and hence any quirk fixups) */ + if (!fu_device_probe (FU_DEVICE (dev), error)) + return FALSE; + + /* if not already set by quirks */ + if (fu_device_get_custom_flags (FU_DEVICE (dev)) == NULL) { + /* for all Lenovo hardware */ + if (fu_plugin_check_hwid (plugin, "6de5d951-d755-576b-bd09-c5cf66b27234")) { + fu_device_set_custom_flags (FU_DEVICE (dev), "use-legacy-bootmgr-desc"); + fu_plugin_add_report_metadata (plugin, "BootMgrDesc", "legacy"); + } } - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); - if (g_file_test ("/sys/firmware/efi/efivars", G_FILE_TEST_IS_DIR) || - g_file_test ("/sys/firmware/efi/vars", G_FILE_TEST_IS_DIR)) { - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); - } else { - g_warning ("Kernel support for EFI variables missing"); + + /* set fallback name if nothing else is set */ + if (fu_device_get_name (FU_DEVICE (dev)) == 0) { + g_autofree gchar *name = NULL; + name = fu_plugin_uefi_get_name_for_type (plugin, fu_uefi_device_get_kind (dev)); + if (name != NULL) + fu_device_set_name (FU_DEVICE (dev), name); } - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); - fu_plugin_device_add (plugin, dev); + + /* success */ + return TRUE; } static void fu_plugin_uefi_test_secure_boot (FuPlugin *plugin) { - const efi_guid_t guid = EFI_GLOBAL_GUID; const gchar *result_str = "Disabled"; - g_autofree guint8 *data = NULL; - gsize data_size = 0; - guint32 attributes = 0; - gint rc; - - rc = efi_get_variable (guid, "SecureBoot", &data, &data_size, &attributes); - if (rc < 0) - return; - if (data_size >= 1 && data[0] & 1) + if (fu_uefi_secure_boot_enabled ()) result_str = "Enabled"; - g_debug ("SecureBoot is: %s", result_str); fu_plugin_add_report_metadata (plugin, "SecureBoot", result_str); } static gboolean -fu_plugin_uefi_set_custom_mountpoint (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - const gchar *key = "OverrideESPMountPoint"; - - /* load from file and keep @key ref'd for the lifetime of the plugin as - * libfwupdate does not strdup the value in fwup_set_esp_mountpoint() */ - data->esp_path = fu_plugin_get_config_value (plugin, key); - if (data->esp_path != NULL) { - if (!g_file_test (data->esp_path, G_FILE_TEST_IS_DIR)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Invalid %s specified in %s config: %s", - fu_plugin_get_name (plugin), key, - data->esp_path); - - return FALSE; - } -#ifdef HAVE_FWUP_CUSTOM_ESP - fwup_set_esp_mountpoint (data->esp_path); -#endif - } - return TRUE; -} - -static gboolean fu_plugin_uefi_delete_old_capsules (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); @@ -639,7 +575,7 @@ files = fu_common_get_files_recursive (data->esp_path, error); if (files == NULL) return FALSE; - pattern = g_build_filename (data->esp_path, "EFI/*/fw/fwupdate-*.cap", NULL); + pattern = g_build_filename (data->esp_path, "EFI/*/fw/fwupd-*.cap", NULL); for (guint i = 0; i < files->len; i++) { const gchar *fn = g_ptr_array_index (files, i); if (fnmatch (pattern, fn, 0) == 0) { @@ -652,138 +588,321 @@ return TRUE; } -static gboolean -fu_plugin_uefi_delete_old_efivars (FuPlugin *plugin, GError **error) +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) { - char *name = NULL; - efi_guid_t fwupdate_guid = FWUPDATE_GUID; - efi_guid_t *guid = NULL; - int rc; - while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) { - if (efi_guid_cmp (guid, &fwupdate_guid) != 0) - continue; - if (g_str_has_prefix (name, "fwupdate-")) { - g_debug ("deleting %s", name); - rc = efi_del_variable (fwupdate_guid, name); - if (rc < 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "failed to delete efi var %s: %s", - name, strerror (errno)); - return FALSE; - } - } + const guint8 *data; + gsize sz; + g_autoptr(GBytes) bios_information = fu_plugin_get_smbios_data (plugin, 0); + if (bios_information == NULL) { + const gchar *tmp = g_getenv ("FWUPD_DELL_FAKE_SMBIOS"); + if (tmp != NULL) + return TRUE; + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "SMBIOS not supported"); + return FALSE; } - if (rc < 0) { + data = g_bytes_get_data (bios_information, &sz); + if (sz < 0x13) { g_set_error (error, FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "error listing variables: %s", - strerror (errno)); + FWUPD_ERROR_INVALID_FILE, + "offset bigger than size %" G_GSIZE_FORMAT, sz); + return FALSE; + } + if (data[1] < 0x13) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "SMBIOS 2.3 not supported"); + return FALSE; + } + if (!(data[0x13] & (1 << 3))) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "System does not support UEFI mode"); return FALSE; } + /* test for invalid ESP in coldplug, and set the update-error rather + * than showing no output if the plugin had self-disabled here */ return TRUE; } -/* remove when https://github.com/rhboot/efivar/pull/100 merged */ -static int -_efi_get_variable_exists (efi_guid_t guid, const char *name) +static gboolean +fu_plugin_uefi_ensure_esp_path (FuPlugin *plugin, GError **error) { - uint32_t unused_attrs = 0; - return efi_get_variable_attributes (guid, name, &unused_attrs); + FuPluginData *data = fu_plugin_get_data (plugin); + guint64 sz_reqd = FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE; + g_autofree gchar *require_esp_free_space = NULL; + g_autofree gchar *require_shim_for_sb = NULL; + + /* parse free space */ + require_esp_free_space = fu_plugin_get_config_value (plugin, "RequireESPFreeSpace"); + if (require_esp_free_space != NULL) + sz_reqd = fu_common_strtoull (require_esp_free_space); + + /* load from file */ + data->esp_path = fu_plugin_get_config_value (plugin, "OverrideESPMountPoint"); + if (data->esp_path != NULL) { + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_check_esp_path (data->esp_path, &error_local)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "invalid OverrideESPMountPoint=%s specified in config: %s", + data->esp_path, error_local->message); + return FALSE; + } + return fu_uefi_check_esp_free_space (data->esp_path, sz_reqd, error); + } + require_shim_for_sb = fu_plugin_get_config_value (plugin, "RequireShimForSecureBoot"); + if (require_shim_for_sb == NULL || + g_ascii_strcasecmp (require_shim_for_sb, "true") == 0) + data->require_shim_for_sb = TRUE; + + /* try to guess from heuristics */ + data->esp_path = fu_uefi_guess_esp_path (); + if (data->esp_path == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "Unable to determine EFI system partition location, " + "See https://github.com/hughsie/fwupd/wiki/Determining-EFI-system-partition-location"); + return FALSE; + } + + /* check free space */ + if (!fu_uefi_check_esp_free_space (data->esp_path, sz_reqd, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_plugin_uefi_ensure_efivarfs_rw (GError **error) +{ + g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + g_autofree gchar *sysfsefivardir = g_build_filename (sysfsfwdir, "efi", "efivars", NULL); + g_autoptr(GUnixMountEntry) mount = g_unix_mount_at (sysfsefivardir, NULL); + + if (mount == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "%s was not mounted", sysfsefivardir); + return FALSE; + } + if (g_unix_mount_is_readonly (mount)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s is read only", sysfsefivardir); + return FALSE; + } + + return TRUE; } gboolean -fu_plugin_startup (FuPlugin *plugin, GError **error) +fu_plugin_unlock (FuPlugin *plugin, FuDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); + FuUefiDevice *device_uefi = FU_UEFI_DEVICE (device); + FuDevice *device_alt = NULL; + FwupdDeviceFlags device_flags_alt = 0; + guint flashes_left = 0; + guint flashes_left_alt = 0; - /* get the supported status */ - data->esrt_status = fwup_supported (); - if (data->esrt_status == FWUP_SUPPORTED_STATUS_UNSUPPORTED) { - g_set_error_literal (error, + if (fu_uefi_device_get_kind (device_uefi) != + FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Unable to unlock %s", + fu_device_get_name (device)); + return FALSE; + } + + /* for unlocking TPM1.2 <-> TPM2.0 switching */ + g_debug ("Unlocking upgrades for: %s (%s)", fu_device_get_name (device), + fu_device_get_id (device)); + device_alt = fu_device_get_alternate (device); + if (device_alt == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "No alternate device for %s", + fu_device_get_name (device)); + return FALSE; + } + g_debug ("Preventing upgrades for: %s (%s)", fu_device_get_name (device_alt), + fu_device_get_id (device_alt)); + + flashes_left = fu_device_get_flashes_left (device); + flashes_left_alt = fu_device_get_flashes_left (device_alt); + if (flashes_left == 0) { + /* flashes left == 0 on both means no flashes left */ + if (flashes_left_alt == 0) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, - "UEFI firmware updating not supported"); + "ERROR: %s has no flashes left.", + fu_device_get_name (device)); + /* flashes left == 0 on just unlocking device is ownership */ + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ERROR: %s is currently OWNED. " + "Ownership must be removed to switch modes.", + fu_device_get_name (device_alt)); + } return FALSE; } - /* load any overriden options */ - if (!fu_plugin_uefi_set_custom_mountpoint (plugin, error)) + /* clone the info from real device but prevent it from being flashed */ + device_flags_alt = fu_device_get_flags (device_alt); + fu_device_set_flags (device, device_flags_alt); + fu_device_set_flags (device_alt, device_flags_alt & ~FWUPD_DEVICE_FLAG_UPDATABLE); + + /* make sure that this unlocked device can be updated */ + fu_device_set_version (device, "0.0.0.0", FWUPD_VERSION_FORMAT_QUAD); + return TRUE; +} + +static gboolean +fu_plugin_uefi_create_dummy (FuPlugin *plugin, GError **error) +{ + const gchar *key; + g_autoptr(FuDevice) dev = fu_device_new (); + + key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_MANUFACTURER); + if (key != NULL) + fu_device_set_vendor (dev, key); + key = fu_plugin_uefi_get_name_for_type (plugin, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + fu_device_set_name (dev, key); + key = fu_plugin_get_dmi_value (plugin, FU_HWIDS_KEY_BIOS_VERSION); + if (key != NULL) + fu_device_set_version (dev, key, FWUPD_VERSION_FORMAT_PLAIN); + key = "Firmware can not be updated in legacy mode, switch to UEFI mode."; + fu_device_set_update_error (dev, key); + + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_REQUIRE_AC); + + fu_device_add_icon (dev, "computer"); + fu_device_set_plugin (dev, fu_plugin_get_name (plugin)); + fu_device_set_id (dev, "UEFI-dummy"); + fu_device_add_instance_id (dev, "main-system-firmware"); + if (!fu_device_setup (dev, error)) return FALSE; + fu_plugin_device_add (plugin, dev); - /* get the default compiled-in value for the ESP mountpoint */ -#ifdef HAVE_FWUP_GET_ESP_MOUNTPOINT - if (data->esp_path == NULL) - data->esp_path = g_strdup (fwup_get_esp_mountpoint ()); -#endif + return TRUE; +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + const gchar *str; + g_autofree gchar *bootloader = NULL; + g_autofree gchar *esrt_path = NULL; + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error_bootloader = NULL; + g_autoptr(GError) error_efivarfs = NULL; + g_autoptr(GError) error_esp = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) entries = NULL; + + /* are the EFI dirs set up so we can update each device */ + if (!fu_uefi_vars_supported (&error_local)) { + g_warning ("%s", error_local->message); + return fu_plugin_uefi_create_dummy (plugin, error); + } + + /* get the directory of ESRT entries */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + entries = fu_uefi_get_esrt_entry_paths (esrt_path, error); + if (entries == NULL) + return FALSE; + + /* make sure that efivarfs is rw */ + if (!fu_plugin_uefi_ensure_efivarfs_rw (&error_efivarfs)) + g_warning ("%s", error_efivarfs->message); + + /* if secure boot is enabled ensure we have a signed fwupd.efi */ + bootloader = fu_uefi_get_built_app_path (&error_bootloader); + if (bootloader == NULL) { + if (fu_uefi_secure_boot_enabled ()) + g_prefix_error (&error_bootloader, "missing signed bootloader for secure boot: "); + g_warning ("%s", error_bootloader->message); + } + + /* ensure the ESP is detected */ + if (!fu_plugin_uefi_ensure_esp_path (plugin, &error_esp)) + g_warning ("%s", error_esp->message); - /* fall back to a sane default */ - if (data->esp_path == NULL) - data->esp_path = g_strdup ("/boot/efi"); + /* add each device */ + for (guint i = 0; i < entries->len; i++) { + const gchar *path = g_ptr_array_index (entries, i); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to add %s: %s", path, error_parse->message); + continue; + } + fu_device_set_quirks (FU_DEVICE (dev), fu_plugin_get_quirks (plugin)); + if (!fu_plugin_uefi_coldplug_device (plugin, dev, error)) + return FALSE; + if (error_esp != NULL) { + fu_device_set_update_error (FU_DEVICE (dev), error_esp->message); + } else if (error_bootloader != NULL) { + fu_device_set_update_error (FU_DEVICE (dev), error_bootloader->message); + } else if (error_efivarfs != NULL) { + fu_device_set_update_error (FU_DEVICE (dev), error_efivarfs->message); + } else { + fu_device_set_metadata (FU_DEVICE (dev), "EspPath", data->esp_path); + fu_device_set_metadata_boolean (FU_DEVICE (dev), + "RequireShimForSecureBoot", + data->require_shim_for_sb); + fu_device_add_flag (FU_DEVICE (dev), FWUPD_DEVICE_FLAG_UPDATABLE); + } + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* no devices are updatable */ + if (error_esp != NULL || error_bootloader != NULL) + return TRUE; /* delete any existing .cap files to avoid the small ESP partition * from running out of space when we've done lots of firmware updates * -- also if the distro has changed the ESP may be different anyway */ - if (_efi_get_variable_exists (EFI_GLOBAL_GUID, "BootNext") == 0) { + if (fu_uefi_vars_exists (FU_UEFI_VARS_GUID_EFI_GLOBAL, "BootNext")) { g_debug ("detected BootNext, not cleaning up"); } else { if (!fu_plugin_uefi_delete_old_capsules (plugin, error)) return FALSE; - if (!fu_plugin_uefi_delete_old_efivars (plugin, error)) + if (!fu_uefi_vars_delete_with_glob (FU_UEFI_VARS_GUID_FWUPDATE, "fwupd-*", error)) return FALSE; } /* save in report metadata */ g_debug ("ESP mountpoint set as %s", data->esp_path); fu_plugin_add_report_metadata (plugin, "ESPMountPoint", data->esp_path); - return TRUE; -} - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - fwup_resource *re; - g_autoptr(fwup_resource_iter) iter = NULL; - g_autofree gchar *name = NULL; - const gchar *ux_capsule_str = "Disabled"; - - /* create a dummy device so we can unlock the feature */ - if (data->esrt_status == FWUP_SUPPORTED_STATUS_LOCKED_CAN_UNLOCK) { - g_autoptr(FuDevice) dev = fu_device_new (); - name = fu_plugin_uefi_get_name_for_type (plugin, - FWUP_RESOURCE_TYPE_SYSTEM_FIRMWARE); - if (name != NULL) - fu_device_set_name (dev, name); - fu_device_set_id (dev, "UEFI-dummy-dev0"); - fu_device_add_guid (dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); - fu_device_set_version (dev, "0"); - fu_device_add_icon (dev, "computer"); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE); - fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_LOCKED); - fu_plugin_device_add (plugin, dev); - return TRUE; - } - - /* add each device */ - if (fwup_resource_iter_create (&iter) < 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Cannot create fwup iter"); - return FALSE; - } - while (fwup_resource_iter_next (iter, &re) > 0) - fu_plugin_uefi_coldplug_resource (plugin, re); /* for debugging problems later */ fu_plugin_uefi_test_secure_boot (plugin); - if (data->ux_capsule) - ux_capsule_str = "Enabled"; - g_debug ("UX Capsule support : %s", ux_capsule_str); - fu_plugin_add_report_metadata (plugin, "UEFIUXCapsule", ux_capsule_str); + if (!fu_uefi_bgrt_setup (data->bgrt, &error_local)) + g_debug ("BGRT setup failed: %s", error_local->message); + str = fu_uefi_bgrt_get_supported (data->bgrt) ? "Enabled" : "Disabled"; + g_debug ("UX Capsule support : %s", str); + fu_plugin_add_report_metadata (plugin, "UEFIUXCapsule", str); return TRUE; } diff -Nru fwupd-1.0.6/plugins/uefi/fu-self-test.c fwupd-1.2.10/plugins/uefi/fu-self-test.c --- fwupd-1.0.6/plugins/uefi/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-test.h" +#include "fu-ucs2.h" +#include "fu-uefi-bgrt.h" +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-pcrs.h" +#include "fu-uefi-vars.h" + +static void +fu_uefi_pcrs_1_2_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 1); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); +} + +static void +fu_uefi_pcrs_2_0_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + g_autoptr(GPtrArray) pcrXs = NULL; + + g_setenv ("FWUPD_UEFI_TPM2_YAML_DATA", + "sha1 :\n" + " 0 : cbd9e4112727bc75761001abcb2dddd87a66caf5\n" + "sha256 :\n" + " 0 : 122de8b579cce17b0703ca9f9716d6f99125af9569e7303f51ea7f85d317f01e\n", TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_no_error (error); + g_assert_true (ret); + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 2); + pcrXs = fu_uefi_pcrs_get_checksums (pcrs, 999); + g_assert_nonnull (pcrXs); + g_assert_cmpint (pcrXs->len, ==, 0); +} + +static void +fu_uefi_pcrs_2_0_failure_func (void) +{ + gboolean ret; + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error = NULL; + + g_setenv ("FWUPD_UEFI_TPM2_YAML_DATA", + "Something is not working properly!\n" + "999:hello\n" + "0:dave\n" + "\n", TRUE); + + ret = fu_uefi_pcrs_setup (pcrs, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_assert_false (ret); +} + +static void +fu_uefi_ucs2_func (void) +{ + g_autofree guint16 *str1 = NULL; + g_autofree gchar *str2 = NULL; + str1 = fu_uft8_to_ucs2 ("hw!", -1); + g_assert_cmpint (fu_ucs2_strlen (str1, -1), ==, 3); + str2 = fu_ucs2_to_uft8 (str1, -1); + g_assert_cmpstr ("hw!", ==, str2); +} + +static void +fu_uefi_bgrt_func (void) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + g_autoptr(FuUefiBgrt) bgrt = fu_uefi_bgrt_new (); + ret = fu_uefi_bgrt_setup (bgrt, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_true (fu_uefi_bgrt_get_supported (bgrt)); + g_assert_cmpint (fu_uefi_bgrt_get_xoffset (bgrt), ==, 123); + g_assert_cmpint (fu_uefi_bgrt_get_yoffset (bgrt), ==, 456); + g_assert_cmpint (fu_uefi_bgrt_get_width (bgrt), ==, 54); + g_assert_cmpint (fu_uefi_bgrt_get_height (bgrt), ==, 24); +} + +static void +fu_uefi_framebuffer_func (void) +{ + gboolean ret; + guint32 height = 0; + guint32 width = 0; + g_autoptr(GError) error = NULL; + ret = fu_uefi_get_framebuffer_size (&width, &height, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_cmpint (width, ==, 456); + g_assert_cmpint (height, ==, 789); +} + +static void +fu_uefi_bitmap_func (void) +{ + gboolean ret; + gsize sz = 0; + guint32 height = 0; + guint32 width = 0; + g_autofree gchar *fn = NULL; + g_autofree gchar *buf = NULL; + g_autoptr(GError) error = NULL; + + fn = fu_test_get_filename (TESTDATADIR, "test.bmp"); + g_assert (fn != NULL); + ret = g_file_get_contents (fn, &buf, &sz, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_nonnull (buf); + ret = fu_uefi_get_bitmap_size ((guint8 *)buf, sz, &width, &height, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_cmpint (width, ==, 54); + g_assert_cmpint (height, ==, 24); +} + +static void +fu_uefi_device_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(GError) error = NULL; + + fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); + g_assert (fn != NULL); + dev = fu_uefi_device_new_from_entry (fn, &error); + g_assert_nonnull (dev); + g_assert_no_error (error); + + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); + g_assert_cmpint (fu_uefi_device_get_hardware_instance (dev), ==, 0x0); + g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 65586); + g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 65582); + g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 18472960); + g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 0xfe); + g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL); + + /* check enums all converted */ + for (guint i = 0; i < FU_UEFI_DEVICE_STATUS_LAST; i++) + g_assert_nonnull (fu_uefi_device_status_to_string (i)); +} + +static void +fu_uefi_vars_func (void) +{ + gboolean ret; + gsize sz = 0; + guint32 attr = 0; + g_autofree guint8 *data = NULL; + g_autoptr(GError) error = NULL; + + /* check supported */ + ret = fu_uefi_vars_supported (&error); + g_assert_no_error (error); + g_assert_true (ret); + + /* check existing keys */ + g_assert_false (fu_uefi_vars_exists (FU_UEFI_VARS_GUID_EFI_GLOBAL, "NotGoingToExist")); + g_assert_true (fu_uefi_vars_exists (FU_UEFI_VARS_GUID_EFI_GLOBAL, "SecureBoot")); + + /* write and read a key */ + ret = fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test", + (guint8 *) "1", 1, + FU_UEFI_VARS_ATTR_NON_VOLATILE | + FU_UEFI_VARS_ATTR_RUNTIME_ACCESS, + &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test", + &data, &sz, &attr, &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_cmpint (sz, ==, 1); + g_assert_cmpint (attr, ==, FU_UEFI_VARS_ATTR_NON_VOLATILE | + FU_UEFI_VARS_ATTR_RUNTIME_ACCESS); + g_assert_cmpint (data[0], ==, '1'); + + /* delete single key */ + ret = fu_uefi_vars_delete (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test", &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_false (fu_uefi_vars_exists (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test")); + + /* delete multiple keys */ + ret = fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test1", (guint8 *)"1", 1, 0, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test2", (guint8 *)"1", 1, 0, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_uefi_vars_delete_with_glob (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test*", &error); + g_assert_no_error (error); + g_assert_true (ret); + g_assert_false (fu_uefi_vars_exists (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test1")); + g_assert_false (fu_uefi_vars_exists (FU_UEFI_VARS_GUID_EFI_GLOBAL, "Test2")); + + /* read a key that doesn't exist */ + ret = fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_EFI_GLOBAL, "NotGoingToExist", NULL, NULL, NULL, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert_false (ret); +} + +static void +fu_uefi_plugin_func (void) +{ + FuUefiDevice *dev; + g_autofree gchar *esrt_path = NULL; + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) entries = NULL; + + /* add each device */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error); + g_assert_no_error (error); + g_assert_nonnull (entries); + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < entries->len; i++) { + const gchar *path = g_ptr_array_index (entries, i); + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUefiDevice) dev_tmp = fu_uefi_device_new_from_entry (path, &error_local); + if (dev_tmp == NULL) { + g_debug ("failed to add %s: %s", path, error_local->message); + continue; + } + g_ptr_array_add (devices, g_object_ref (dev_tmp)); + } + g_assert_cmpint (devices->len, ==, 2); + + /* system firmware */ + dev = g_ptr_array_index (devices, 0); + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); + g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 65586); + g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 65582); + g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 18472960); + g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 0xfe); + g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL); + + /* system firmware */ + dev = g_ptr_array_index (devices, 1); + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "671d19d0-d43c-4852-98d9-1ce16f9967e4"); + g_assert_cmpint (fu_uefi_device_get_version (dev), ==, 3090287969); + g_assert_cmpint (fu_uefi_device_get_version_lowest (dev), ==, 1); + g_assert_cmpint (fu_uefi_device_get_version_error (dev), ==, 0); + g_assert_cmpint (fu_uefi_device_get_capsule_flags (dev), ==, 32784); + g_assert_cmpint (fu_uefi_device_get_status (dev), ==, FU_UEFI_DEVICE_STATUS_SUCCESS); +} + +static void +fu_uefi_update_info_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuUefiDevice) dev = NULL; + g_autoptr(FuUefiUpdateInfo) info = NULL; + g_autoptr(GError) error = NULL; + + fn = fu_test_get_filename (TESTDATADIR, "efi/esrt/entries/entry0"); + g_assert (fn != NULL); + dev = fu_uefi_device_new_from_entry (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (dev); + g_assert_cmpint (fu_uefi_device_get_kind (dev), ==, FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE); + g_assert_cmpstr (fu_uefi_device_get_guid (dev), ==, "ddc0ee61-e7f0-4e7d-acc5-c070a398838e"); + info = fu_uefi_device_load_update_info (dev, &error); + g_assert_no_error (error); + g_assert_nonnull (info); + g_assert_cmpint (fu_uefi_update_info_get_version (info), ==, 0x7); + g_assert_cmpstr (fu_uefi_update_info_get_guid (info), ==, "697bd920-12cf-4da9-8385-996909bc6559"); + g_assert_cmpint (fu_uefi_update_info_get_capsule_flags (info), ==, 0x50000); + g_assert_cmpint (fu_uefi_update_info_get_hw_inst (info), ==, 0x0); + g_assert_cmpint (fu_uefi_update_info_get_status (info), ==, FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE); + g_assert_cmpstr (fu_uefi_update_info_get_capsule_fn (info), ==, + "/EFI/fedora/fw/fwupd-697bd920-12cf-4da9-8385-996909bc6559.cap"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR, TRUE); + g_setenv ("FWUPD_SYSFSDRIVERDIR", TESTDATADIR, TRUE); + g_setenv ("FWUPD_SYSFSTPMDIR", TESTDATADIR, TRUE); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/uefi/pcrs1.2", fu_uefi_pcrs_1_2_func); + g_test_add_func ("/uefi/pcrs2.0", fu_uefi_pcrs_2_0_func); + g_test_add_func ("/uefi/pcrs2.0{failure}", fu_uefi_pcrs_2_0_failure_func); + g_test_add_func ("/uefi/ucs2", fu_uefi_ucs2_func); + g_test_add_func ("/uefi/variable", fu_uefi_vars_func); + g_test_add_func ("/uefi/bgrt", fu_uefi_bgrt_func); + g_test_add_func ("/uefi/framebuffer", fu_uefi_framebuffer_func); + g_test_add_func ("/uefi/bitmap", fu_uefi_bitmap_func); + g_test_add_func ("/uefi/device", fu_uefi_device_func); + g_test_add_func ("/uefi/update-info", fu_uefi_update_info_func); + g_test_add_func ("/uefi/plugin", fu_uefi_plugin_func); + return g_test_run (); +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-ucs2.c fwupd-1.2.10/plugins/uefi/fu-ucs2.c --- fwupd-1.0.6/plugins/uefi/fu-ucs2.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-ucs2.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-ucs2.h" + +#define ev_bits(val, mask, shift) (((val) & ((mask) << (shift))) >> (shift)) + +gchar * +fu_ucs2_to_uft8 (const guint16 *str, gssize max) +{ + gssize i, j; + gchar *ret; + + if (max < 0) + max = fu_ucs2_strlen (str, max); + ret = g_malloc0 (max * 3 + 1); /* would be s/3/6 if this were UCS-4 */ + for (i = 0, j = 0; i < max && str[i]; i++, j++) { + if (str[i] <= 0x7f) { + ret[j] = str[i]; + } else if (str[i] > 0x7f && str[i] <= 0x7ff) { + ret[j++] = 0xc0 | ev_bits(str[i], 0x1f, 6); + ret[j] = 0x80 | ev_bits(str[i], 0x3f, 0); + } else if (str[i] > 0x7ff /* && str[i] < 0x10000 */ ) { + ret[j++] = 0xe0 | ev_bits(str[i], 0xf, 12); + ret[j++] = 0x80 | ev_bits(str[i], 0x3f, 6); + ret[j] = 0x80 | ev_bits(str[i], 0x3f, 0); + } + } + return ret; +} + +guint16 * +fu_uft8_to_ucs2 (const gchar *str, gssize max) +{ + gssize i, j; + guint16 *ret = g_new0 (guint16, g_utf8_strlen (str, max) + 1); + for (i = 0, j = 0; i < (max >= 0 ? max : i + 1) && str[i] != '\0'; j++) { + guint32 val = 0; + if ((str[i] & 0xe0) == 0xe0 && !(str[i] & 0x10)) { + val = ((str[i+0] & 0x0f) << 10) + |((str[i+1] & 0x3f) << 6) + |((str[i+2] & 0x3f) << 0); + i += 3; + } else if ((str[i] & 0xc0) == 0xc0 && !(str[i] & 0x20)) { + val = ((str[i+0] & 0x1f) << 6) + |((str[i+1] & 0x3f) << 0); + i += 2; + } else { + val = str[i] & 0x7f; + i += 1; + } + ret[j] = val; + } + ret[j] = L'\0'; + return ret; +} + +gsize +fu_ucs2_strlen (const guint16 *str, gssize limit) +{ + gssize i; + for (i = 0; i < (limit >= 0 ? limit : i + 1) && str[i] != L'\0'; i++); + return i; +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-ucs2.h fwupd-1.2.10/plugins/uefi/fu-ucs2.h --- fwupd-1.0.6/plugins/uefi/fu-ucs2.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-ucs2.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +gsize fu_ucs2_strlen (const guint16 *str, + gssize limit); +guint16 *fu_uft8_to_ucs2 (const gchar *str, + gssize max); +gchar *fu_ucs2_to_uft8 (const guint16 *str, + gssize max); diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-bgrt.c fwupd-1.2.10/plugins/uefi/fu-uefi-bgrt.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-bgrt.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-bgrt.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-bgrt.h" +#include "fu-uefi-common.h" + +struct _FuUefiBgrt { + GObject parent_instance; + guint32 xoffset; + guint32 yoffset; + guint32 width; + guint32 height; +}; + +G_DEFINE_TYPE (FuUefiBgrt, fu_uefi_bgrt, G_TYPE_OBJECT) + +gboolean +fu_uefi_bgrt_setup (FuUefiBgrt *self, GError **error) +{ + gsize sz = 0; + guint64 type; + guint64 version; + g_autofree gchar *bgrtdir = NULL; + g_autofree gchar *data = NULL; + g_autofree gchar *imagefn = NULL; + g_autofree gchar *sysfsfwdir = NULL; + + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), FALSE); + + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + bgrtdir = g_build_filename (sysfsfwdir, "acpi", "bgrt", NULL); + if (!g_file_test (bgrtdir, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "BGRT is not supported"); + return FALSE; + } + type = fu_uefi_read_file_as_uint64 (bgrtdir, "type"); + if (type != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "BGRT type was %" G_GUINT64_FORMAT, type); + return FALSE; + } + version = fu_uefi_read_file_as_uint64 (bgrtdir, "version"); + if (version != 1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "BGRT version was %" G_GUINT64_FORMAT, version); + return FALSE; + } + + /* load image */ + self->xoffset = fu_uefi_read_file_as_uint64 (bgrtdir, "xoffset"); + self->yoffset = fu_uefi_read_file_as_uint64 (bgrtdir, "yoffset"); + imagefn = g_build_filename (bgrtdir, "image", NULL); + if (!g_file_get_contents (imagefn, &data, &sz, error)) { + g_prefix_error (error, "failed to load BGRT image: "); + return FALSE; + } + if (!fu_uefi_get_bitmap_size ((guint8 *) data, sz, + &self->width, &self->height, error)) { + g_prefix_error (error, "BGRT image invalid: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +gboolean +fu_uefi_bgrt_get_supported (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), FALSE); + if (self->width == 0 || self->height == 0) + return FALSE; + return TRUE; +} + +guint32 +fu_uefi_bgrt_get_xoffset (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->xoffset; +} + +guint32 +fu_uefi_bgrt_get_yoffset (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->yoffset; +} + +guint32 +fu_uefi_bgrt_get_width (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->width; +} + +guint32 +fu_uefi_bgrt_get_height (FuUefiBgrt *self) +{ + g_return_val_if_fail (FU_IS_UEFI_BGRT (self), 0); + return self->height; +} + +static void +fu_uefi_bgrt_class_init (FuUefiBgrtClass *klass) +{ +} + +static void +fu_uefi_bgrt_init (FuUefiBgrt *self) +{ +} + +FuUefiBgrt * +fu_uefi_bgrt_new (void) +{ + FuUefiBgrt *self; + self = g_object_new (FU_TYPE_UEFI_BGRT, NULL); + return FU_UEFI_BGRT (self); +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-bgrt.h fwupd-1.2.10/plugins/uefi/fu-uefi-bgrt.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-bgrt.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-bgrt.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_BGRT (fu_uefi_bgrt_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiBgrt, fu_uefi_bgrt, FU, UEFI_BGRT, GObject) + +FuUefiBgrt *fu_uefi_bgrt_new (void); +gboolean fu_uefi_bgrt_setup (FuUefiBgrt *self, + GError **error); +gboolean fu_uefi_bgrt_get_supported (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_xoffset (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_yoffset (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_width (FuUefiBgrt *self); +guint32 fu_uefi_bgrt_get_height (FuUefiBgrt *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-bootmgr.c fwupd-1.2.10/plugins/uefi/fu-uefi-bootmgr.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-bootmgr.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-bootmgr.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "fwupd-error.h" + +#include "fu-ucs2.h" +#include "fu-uefi-bootmgr.h" +#include "fu-uefi-common.h" + +/* XXX PJFIX: this should be in efiboot-loadopt.h in efivar */ +#define LOAD_OPTION_ACTIVE 0x00000001 + +static gboolean +fu_uefi_bootmgr_add_to_boot_order (guint16 boot_entry, GError **error) +{ + gsize boot_order_size = 0; + gint rc; + guint i = 0; + guint32 attr = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + g_autofree guint16 *boot_order = NULL; + g_autofree guint16 *new_boot_order = NULL; + + /* get size of the BootOrder */ + rc = efi_get_variable_size (efi_guid_global, "BootOrder", &boot_order_size); + if (rc == ENOENT) { + boot_order_size = 0; + efi_error_clear (); + } else if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_get_variable_size() failed"); + return rc; + } + + /* get the current boot order */ + if (boot_order_size != 0) { + rc = efi_get_variable (efi_guid_global, "BootOrder", + (guint8 **)&boot_order, &boot_order_size, + &attr); + if (rc < 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_get_variable(BootOrder) failed"); + return FALSE; + } + + /* already set next */ + for (i = 0; i < boot_order_size / sizeof (guint16); i++) { + guint16 val = boot_order[i]; + if (val == boot_entry) + return TRUE; + } + } + + /* add the new boot index to the end of the list */ + new_boot_order = g_malloc0 (boot_order_size + sizeof (guint16)); + if (boot_order_size != 0) + memcpy (new_boot_order, boot_order, boot_order_size); + + i = boot_order_size / sizeof (guint16); + new_boot_order[i] = boot_entry; + boot_order_size += sizeof (guint16); + rc = efi_set_variable(efi_guid_global, "BootOrder", + (guint8 *)new_boot_order, boot_order_size, + attr, 0644); + if (rc < 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_set_variable(BootOrder) failed"); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_uefi_setup_bootnext_with_dp (const guint8 *dp_buf, guint8 *opt, gssize opt_size, GError **error) +{ + efi_guid_t *guid = NULL; + efi_load_option *loadopt = NULL; + gchar *name = NULL; + gint rc; + gint set_entries[0x10000 / sizeof(gint)] = {0,}; + gsize var_data_size = 0; + guint16 real_boot16; + guint32 attr; + guint32 boot_next = 0x10000; + g_autofree guint8 *var_data = NULL; + + while ((rc = efi_get_next_variable_name (&guid, &name)) > 0) { + const gchar *desc; + gint div, mod; + gint scanned = 0; + guint16 entry = 0; + g_autofree guint8 *var_data_tmp = NULL; + + if (efi_guid_cmp (guid, &efi_guid_global) != 0) + continue; + rc = sscanf (name, "Boot%hX%n", &entry, &scanned); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to parse Boot entry %s", name); + return FALSE; + } + if (rc != 1) + continue; + if (scanned != 8) + continue; + + div = entry / (sizeof(set_entries[0]) * 8); + mod = entry % (sizeof(set_entries[0]) * 8); + + set_entries[div] |= 1 << mod; + + rc = efi_get_variable (*guid, name, &var_data_tmp, &var_data_size, &attr); + if (rc < 0) { + g_debug ("efi_get_variable(%s) failed", name); + continue; + } + + loadopt = (efi_load_option *)var_data_tmp; + if (!efi_loadopt_is_valid(loadopt, var_data_size)) { + g_debug ("load option was invalid"); + continue; + } + + desc = (const gchar *) efi_loadopt_desc (loadopt, var_data_size); + if (g_strcmp0 (desc, "Linux Firmware Updater") != 0 && + g_strcmp0 (desc, "Linux-Firmware-Updater") != 0) { + g_debug ("description does not match"); + continue; + } + + var_data = g_steal_pointer (&var_data_tmp); + boot_next = entry; + efi_error_clear (); + break; + } + if (rc < 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to find boot variable"); + return FALSE; + } + + /* already exists */ + if (var_data != NULL) { + efi_loadopt_attr_set (loadopt, LOAD_OPTION_ACTIVE); + rc = efi_set_variable (*guid, name, var_data, + var_data_size, attr, 0644); + if (rc < 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "could not set boot variable active"); + return FALSE; + } + + /* create a new one */ + } else { + g_autofree gchar *boot_next_name = NULL; + for (guint32 value = 0; value < 0x10000; value++) { + gint div = value / (sizeof(set_entries[0]) * 8); + gint mod = value % (sizeof(set_entries[0]) * 8); + if (set_entries[div] & (1 << mod)) + continue; + boot_next = value; + break; + } + if (boot_next >= 0x10000) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no free boot variables (tried %x)", + boot_next); + return FALSE; + } + boot_next_name = g_strdup_printf ("Boot%04X", + (guint) (boot_next & 0xffff)); + rc = efi_set_variable (efi_guid_global, boot_next_name, opt, opt_size, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 0644); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "could not set boot variable %s: %d", + boot_next_name, rc); + return FALSE; + } + } + + /* TODO: conditionalize this on the UEFI version? */ + if(!fu_uefi_bootmgr_add_to_boot_order (boot_next, error)) + return FALSE; + + /* set the boot next */ + real_boot16 = boot_next; + rc = efi_set_variable (efi_guid_global, "BootNext", (guint8 *)&real_boot16, 2, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 0644); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "could not set BootNext(%" G_GUINT16_FORMAT ")", + real_boot16); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_uefi_cmp_asset (const gchar *source, const gchar *target) +{ + gsize len = 0; + g_autofree gchar *source_checksum = NULL; + g_autofree gchar *source_data = NULL; + g_autofree gchar *target_checksum = NULL; + g_autofree gchar *target_data = NULL; + + /* nothing in target yet */ + if (!g_file_test (target, G_FILE_TEST_EXISTS)) + return FALSE; + + /* test if the file needs to be updated */ + if (!g_file_get_contents (source, &source_data, &len, NULL)) + return FALSE; + source_checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256, + (guchar *) source_data, len); + if (!g_file_get_contents (target, &target_data, &len, NULL)) + return FALSE; + target_checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256, + (guchar *) target_data, len); + return g_strcmp0 (target_checksum, source_checksum) == 0; +} + +static gboolean +fu_uefi_copy_asset (const gchar *source, const gchar *target, GError **error) +{ + g_autoptr(GFile) source_file = g_file_new_for_path (source); + g_autoptr(GFile) target_file = g_file_new_for_path (target); + + if (!g_file_copy (source_file, + target_file, + G_FILE_COPY_OVERWRITE, + NULL, + NULL, + NULL, + error)) { + g_prefix_error (error, "Failed to copy %s to %s: ", + source, target); + return FALSE; + } + + return TRUE; +} + +gboolean +fu_uefi_bootmgr_bootnext (const gchar *esp_path, + const gchar *description, + FuUefiBootmgrFlags flags, + GError **error) +{ + const gchar *filepath; + gboolean use_fwup_path = FALSE; + gsize loader_sz = 0; + gssize opt_size = 0; + gssize sz, dp_size = 0; + guint32 attributes = LOAD_OPTION_ACTIVE; + g_autofree guint16 *loader_str = NULL; + g_autofree gchar *label = NULL; + g_autofree gchar *shim_app = NULL; + g_autofree gchar *shim_cpy = NULL; + g_autofree guint8 *dp_buf = NULL; + g_autofree guint8 *opt = NULL; + g_autofree gchar *source_app = NULL; + g_autofree gchar *target_app = NULL; + + /* skip for self tests */ + if (g_getenv ("FWUPD_UEFI_ESP_PATH") != NULL) + return TRUE; + + /* if secure boot was turned on this might need to be installed separately */ + source_app = fu_uefi_get_built_app_path (error); + if (source_app == NULL) + return FALSE; + + /* test to make sure shim is there if we need it */ + shim_app = fu_uefi_get_esp_app_path (esp_path, "shim", error); + if (shim_app == NULL) + return FALSE; + if (g_file_test (shim_app, G_FILE_TEST_EXISTS)) { + /* use a custom copy of shim for firmware updates */ + if (flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE) { + shim_cpy = fu_uefi_get_esp_app_path (esp_path, "shimfwupd", error); + if (shim_cpy == NULL) + return FALSE; + if (!fu_uefi_cmp_asset (shim_app, shim_cpy)) { + if (!fu_uefi_copy_asset (shim_app, shim_cpy, error)) + return FALSE; + } + filepath = shim_cpy; + } else { + filepath = shim_app; + } + } else { + if (fu_uefi_secure_boot_enabled () && + (flags & FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB) > 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_BROKEN_SYSTEM, + "Secure boot is enabled, but shim isn't installed to the EFI system partition"); + return FALSE; + } + use_fwup_path = TRUE; + } + + /* test if correct asset in place */ + target_app = fu_uefi_get_esp_app_path (esp_path, "fwupd", error); + if (target_app == NULL) + return FALSE; + if (!fu_uefi_cmp_asset (source_app, target_app)) { + if (!fu_uefi_copy_asset (source_app, target_app, error)) + return FALSE; + } + + /* no shim, so use this directly */ + if (use_fwup_path) + filepath = target_app; + + /* generate device path for target */ + sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR| + EFIBOOT_ABBREV_HD); + if (sz < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_generate_file_device_path(%s) failed", + filepath); + return FALSE; + } + + /* add the fwupdx64.efi ESP path as the shim loadopt data */ + dp_size = sz; + dp_buf = g_malloc0 (dp_size); + if (!use_fwup_path) { + g_autofree gchar *fwup_fs_basename = g_path_get_basename (target_app); + g_autofree gchar *fwup_esp_path = g_strdup_printf ("\\%s", fwup_fs_basename); + loader_str = fu_uft8_to_ucs2 (fwup_esp_path, -1); + loader_sz = fu_ucs2_strlen (loader_str, -1) * 2; + if (loader_sz) + loader_sz += 2; + } + + sz = efi_generate_file_device_path (dp_buf, dp_size, filepath, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR| + EFIBOOT_ABBREV_HD); + if (sz != dp_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_generate_file_device_path(%s) failed", + filepath); + return FALSE; + } + + label = g_strdup (description); + sz = efi_loadopt_create (opt, opt_size, attributes, + (efidp)dp_buf, dp_size, + (guint8 *)label, + (guint8 *)loader_str, loader_sz); + if (sz < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "efi_loadopt_create(%s) failed", + label); + return FALSE; + } + opt = g_malloc0 (sz); + opt_size = sz; + sz = efi_loadopt_create (opt, opt_size, attributes, + (efidp)dp_buf, dp_size, + (guint8 *)label, + (guint8 *)loader_str, loader_sz); + if (sz != opt_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "loadopt size was unreasonable."); + return FALSE; + } + if (!fu_uefi_setup_bootnext_with_dp (dp_buf, opt, opt_size, error)) + return FALSE; + efi_error_clear(); + + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-bootmgr.h fwupd-1.2.10/plugins/uefi/fu-uefi-bootmgr.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-bootmgr.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-bootmgr.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +typedef enum { + FU_UEFI_BOOTMGR_FLAG_NONE = 0, + FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB = 1 << 0, + FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE = 1 << 1, + FU_UEFI_BOOTMGR_FLAG_LAST +} FuUefiBootmgrFlags; + +gboolean fu_uefi_bootmgr_bootnext (const gchar *esp_path, + const gchar *description, + FuUefiBootmgrFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-common.c fwupd-1.2.10/plugins/uefi/fu-uefi-common.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-uefi-common.h" +#include "fu-uefi-vars.h" + +#include "fwupd-common.h" +#include "fwupd-error.h" + +#ifndef HAVE_GIO_2_55_0 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free) +#pragma clang diagnostic pop +#endif + +static const gchar * +fu_uefi_bootmgr_get_suffix (GError **error) +{ + guint64 firmware_bits; + struct { + guint64 bits; + const gchar *arch; + } suffixes[] = { +#if defined(__x86_64__) + { 64, "x64" }, +#elif defined(__aarch64__) + { 64, "aa64" }, +#endif +#if defined(__x86_64__) || defined(__i386__) || defined(__i686__) + { 32, "ia32" }, +#endif + { 0, NULL } + }; + g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + g_autofree gchar *sysfsefidir = g_build_filename (sysfsfwdir, "efi", NULL); + firmware_bits = fu_uefi_read_file_as_uint64 (sysfsefidir, "fw_platform_size"); + if (firmware_bits == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "%s/fw_platform_size cannot be found", + sysfsefidir); + return NULL; + } + for (guint i = 0; suffixes[i].arch != NULL; i++) { + if (firmware_bits != suffixes[i].bits) + continue; + return suffixes[i].arch; + } + + /* this should exist */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "%s/fw_platform_size has unknown value %" G_GUINT64_FORMAT, + sysfsefidir, firmware_bits); + return NULL; +} + +gchar * +fu_uefi_get_esp_app_path (const gchar *esp_path, const gchar *cmd, GError **error) +{ + const gchar *suffix = fu_uefi_bootmgr_get_suffix (error); + g_autofree gchar *base = NULL; + if (suffix == NULL) + return NULL; + base = fu_uefi_get_esp_path_for_os (esp_path); + return g_strdup_printf ("%s/%s%s.efi", base, cmd, suffix); +} + +gchar * +fu_uefi_get_built_app_path (GError **error) +{ + const gchar *extension = ""; + const gchar *suffix; + g_autofree gchar *source_path = NULL; + g_autofree gchar *prefix = NULL; + if (fu_uefi_secure_boot_enabled ()) + extension = ".signed"; + suffix = fu_uefi_bootmgr_get_suffix (error); + if (suffix == NULL) + return NULL; + prefix = fu_common_get_path (FU_PATH_KIND_EFIAPPDIR); + source_path = g_strdup_printf ("%s/fwupd%s.efi%s", + prefix, + suffix, + extension); + if (!g_file_test (source_path, G_FILE_TEST_EXISTS)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "%s cannot be found", + source_path); + return NULL; + } + return g_steal_pointer (&source_path); +} + +gboolean +fu_uefi_get_framebuffer_size (guint32 *width, guint32 *height, GError **error) +{ + guint32 height_tmp; + guint32 width_tmp; + g_autofree gchar *sysfsdriverdir = NULL; + g_autofree gchar *fbdir = NULL; + + sysfsdriverdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_DRIVERS); + fbdir = g_build_filename (sysfsdriverdir, "efi-framebuffer", "efi-framebuffer.0", NULL); + if (!g_file_test (fbdir, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "EFI framebuffer not found"); + return FALSE; + } + height_tmp = fu_uefi_read_file_as_uint64 (fbdir, "height"); + width_tmp = fu_uefi_read_file_as_uint64 (fbdir, "width"); + if (width_tmp == 0 || height_tmp == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "EFI framebuffer has invalid size " + "%"G_GUINT32_FORMAT"x%"G_GUINT32_FORMAT, + width_tmp, height_tmp); + return FALSE; + } + if (width != NULL) + *width = width_tmp; + if (height != NULL) + *height = height_tmp; + return TRUE; +} + +gboolean +fu_uefi_get_bitmap_size (const guint8 *buf, + gsize bufsz, + guint32 *width, + guint32 *height, + GError **error) +{ + guint32 ui32; + + g_return_val_if_fail (buf != NULL, FALSE); + + /* check header */ + if (bufsz < 26) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "blob was too small %" G_GSIZE_FORMAT, bufsz); + return FALSE; + } + if (memcmp (buf, "BM", 2) != 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid BMP header signature"); + return FALSE; + } + + /* starting address */ + ui32 = fu_common_read_uint32 (buf + 10, G_LITTLE_ENDIAN); + if (ui32 < 26) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "BMP header invalid @ %"G_GUINT32_FORMAT"x", ui32); + return FALSE; + } + + /* BITMAPINFOHEADER header */ + ui32 = fu_common_read_uint32 (buf + 14, G_LITTLE_ENDIAN); + if (ui32 < 26 - 14) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "BITMAPINFOHEADER invalid @ %"G_GUINT32_FORMAT"x", ui32); + return FALSE; + } + + /* dimensions */ + if (width != NULL) + *width = fu_common_read_uint32 (buf + 18, G_LITTLE_ENDIAN); + if (height != NULL) + *height = fu_common_read_uint32 (buf + 22, G_LITTLE_ENDIAN); + return TRUE; +} + +gboolean +fu_uefi_secure_boot_enabled (void) +{ + gsize data_size = 0; + g_autofree guint8 *data = NULL; + + if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_EFI_GLOBAL, "SecureBoot", + &data, &data_size, NULL, NULL)) + return FALSE; + if (data_size >= 1 && data[0] & 1) + return TRUE; + return FALSE; +} + +static gint +fu_uefi_strcmp_sort_cb (gconstpointer a, gconstpointer b) +{ + const gchar *stra = *((const gchar **) a); + const gchar *strb = *((const gchar **) b); + return g_strcmp0 (stra, strb); +} + +GPtrArray * +fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, GError **error) +{ + GPtrArray *entries = g_ptr_array_new_with_free_func (g_free); + const gchar *fn; + g_autofree gchar *esrt_entries = NULL; + g_autoptr(GDir) dir = NULL; + + /* search ESRT */ + esrt_entries = g_build_filename (esrt_path, "entries", NULL); + dir = g_dir_open (esrt_entries, 0, error); + if (dir == NULL) + return NULL; + while ((fn = g_dir_read_name (dir)) != NULL) + g_ptr_array_add (entries, g_build_filename (esrt_entries, fn, NULL)); + + /* sort by name */ + g_ptr_array_sort (entries, fu_uefi_strcmp_sort_cb); + return entries; +} + +gchar * +fu_uefi_get_esp_path_for_os (const gchar *esp_path) +{ + const gchar *os_release_id = NULL; +#ifndef EFI_OS_DIR + g_autoptr(GError) error_local = NULL; + g_autoptr(GHashTable) os_release = fwupd_get_os_release (&error_local); + if (os_release != NULL) { + os_release_id = g_hash_table_lookup (os_release, "ID"); + } else { + g_debug ("failed to get ID: %s", error_local->message); + } + if (os_release_id == NULL) + os_release_id = "unknown"; +#else + os_release_id = EFI_OS_DIR; +#endif + return g_build_filename (esp_path, "EFI", os_release_id, NULL); +} + +guint64 +fu_uefi_read_file_as_uint64 (const gchar *path, const gchar *attr_name) +{ + g_autofree gchar *data = NULL; + g_autofree gchar *fn = g_build_filename (path, attr_name, NULL); + if (!g_file_get_contents (fn, &data, NULL, NULL)) + return 0x0; + return fu_common_strtoull (data); +} + +gboolean +fu_uefi_check_esp_free_space (const gchar *path, guint64 required, GError **error) +{ + guint64 fs_free; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileInfo) info = NULL; + + file = g_file_new_for_path (path); + info = g_file_query_filesystem_info (file, + G_FILE_ATTRIBUTE_FILESYSTEM_FREE, + NULL, error); + if (info == NULL) + return FALSE; + fs_free = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE); + if (fs_free < required) { + g_autofree gchar *str_free = g_format_size (fs_free); + g_autofree gchar *str_reqd = g_format_size (required); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s does not have sufficient space, required %s, got %s", + path, str_reqd, str_free); + return FALSE; + } + return TRUE; +} + +gboolean +fu_uefi_check_esp_path (const gchar *path, GError **error) +{ + const gchar *fs_types[] = { "vfat", "ntfs", "exfat", "autofs", NULL }; + g_autoptr(GUnixMountEntry) mount = g_unix_mount_at (path, NULL); + if (mount == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "%s was not mounted", path); + return FALSE; + } + + /* /boot is a special case because systemd sandboxing marks + * it read-only, but we need to write to /boot/EFI + */ + if (g_strcmp0 (path, "/boot") == 0) { + if (!g_file_test ("/boot/EFI", G_FILE_TEST_IS_DIR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s/EFI does not exist", path); + return FALSE; + } + /* /efi is a special case because systemd sandboxing marks + * it read-only, but we need to write to /efi/EFI + */ + } else if (g_strcmp0 (path, "/efi") == 0) { + if (!g_file_test ("/efi/EFI", G_FILE_TEST_IS_DIR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s/EFI does not exist", path); + return FALSE; + } + } else if (g_unix_mount_is_readonly (mount)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s is read only", path); + return FALSE; + } + if (!g_strv_contains (fs_types, g_unix_mount_get_fs_type (mount))) { + g_autofree gchar *supported = g_strjoinv ("|", (gchar **) fs_types); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "%s has an invalid type, expected %s", + path, supported); + return FALSE; + } + return TRUE; +} + +gchar * +fu_uefi_guess_esp_path (void) +{ + const gchar *paths[] = {"/boot/efi", "/boot", "/efi", NULL}; + const gchar *path_tmp; + + /* for the test suite use local directory for ESP */ + path_tmp = g_getenv ("FWUPD_UEFI_ESP_PATH"); + if (path_tmp != NULL) + return g_strdup (path_tmp); + + for (guint i = 0; paths[i] != NULL; i++) { + g_autoptr(GError) error = NULL; + if (!fu_uefi_check_esp_path (paths[i], &error)) { + g_debug ("ignoring ESP path: %s", error->message); + continue; + } + return g_strdup (paths[i]); + } + + return NULL; +} + +gboolean +fu_uefi_prefix_efi_errors (GError **error) +{ + g_autoptr(GString) str = g_string_new (NULL); + for (gint i = 0; ; i++) { + gchar *filename = NULL; + gchar *function = NULL; + gchar *message = NULL; + gint line = 0; + gint err = 0; + if (efi_error_get (i, &filename, &function, &line, + &message, &err) <= 0) + break; + g_string_append_printf (str, "{error #%d} %s:%d %s(): %s: %s\t", + i, filename, line, function, + message, strerror (err)); + } + if (str->len > 1) + g_string_truncate (str, str->len - 1); + g_prefix_error (error, "%s: ", str->str); + return FALSE; +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-common.h fwupd-1.2.10/plugins/uefi/fu-uefi-common.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define EFI_CAPSULE_HEADER_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 +#define EFI_CAPSULE_HEADER_FLAGS_INITIATE_RESET 0x00040000 + +typedef struct __attribute__((__packed__)) { + guint16 year; + guint8 month; + guint8 day; + guint8 hour; + guint8 minute; + guint8 second; + guint8 pad1; + guint32 nanosecond; + guint16 timezone; + guint8 daylight; + guint8 pad2; +} efi_time_t; + +typedef struct __attribute__((__packed__)) { + efi_guid_t guid; + guint32 header_size; + guint32 flags; + guint32 capsule_image_size; +} efi_capsule_header_t; + +typedef struct __attribute__((__packed__)) { + guint8 version; + guint8 checksum; + guint8 image_type; + guint8 reserved; + guint32 mode; + guint32 x_offset; + guint32 y_offset; +} efi_ux_capsule_header_t; + +typedef struct __attribute__((__packed__)) { + guint32 update_info_version; + efi_guid_t guid; + guint32 capsule_flags; + guint64 hw_inst; + efi_time_t time_attempted; + guint32 status; +} efi_update_info_t; + +/* the biggest size SPI part currently seen */ +#define FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE (32 * 1024 * 1024) + +gchar *fu_uefi_get_esp_app_path (const gchar *esp_path, + const gchar *cmd, + GError **error); +gchar *fu_uefi_get_built_app_path (GError **error); +gboolean fu_uefi_get_bitmap_size (const guint8 *buf, + gsize bufsz, + guint32 *width, + guint32 *height, + GError **error); +gboolean fu_uefi_get_framebuffer_size (guint32 *width, + guint32 *height, + GError **error); +gboolean fu_uefi_secure_boot_enabled (void); +gchar *fu_uefi_guess_esp_path (void); +gboolean fu_uefi_check_esp_path (const gchar *path, + GError **error); +gboolean fu_uefi_check_esp_free_space (const gchar *path, + guint64 required, + GError **error); +gchar *fu_uefi_get_esp_path_for_os (const gchar *esp_path); +GPtrArray *fu_uefi_get_esrt_entry_paths (const gchar *esrt_path, + GError **error); +guint64 fu_uefi_read_file_as_uint64 (const gchar *path, + const gchar *attr_name); +gboolean fu_uefi_prefix_efi_errors (GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-device.c fwupd-1.2.10/plugins/uefi/fu-uefi-device.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-device-metadata.h" + +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-devpath.h" +#include "fu-uefi-bootmgr.h" +#include "fu-uefi-pcrs.h" +#include "fu-uefi-vars.h" + +struct _FuUefiDevice { + FuDevice parent_instance; + gchar *fw_class; + FuUefiDeviceKind kind; + guint32 capsule_flags; + guint32 fw_version; + guint32 fw_version_lowest; + FuUefiDeviceStatus last_attempt_status; + guint32 last_attempt_version; + guint64 fmp_hardware_instance; + gboolean missing_header; +}; + +G_DEFINE_TYPE (FuUefiDevice, fu_uefi_device, FU_TYPE_DEVICE) + +const gchar * +fu_uefi_device_kind_to_string (FuUefiDeviceKind kind) +{ + if (kind == FU_UEFI_DEVICE_KIND_UNKNOWN) + return "unknown"; + if (kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) + return "system-firmware"; + if (kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) + return "device-firmware"; + if (kind == FU_UEFI_DEVICE_KIND_UEFI_DRIVER) + return "uefi-driver"; + if (kind == FU_UEFI_DEVICE_KIND_FMP) + return "fmp"; + if (kind == FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE) + return "dell-tpm-firmware"; + return NULL; +} + +static FuUefiDeviceKind +fu_uefi_device_kind_from_string (const gchar *kind) +{ + if (g_strcmp0 (kind, "system-firmware") == 0) + return FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE; + if (g_strcmp0 (kind, "device-firmware") == 0) + return FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE; + if (g_strcmp0 (kind, "uefi-driver") == 0) + return FU_UEFI_DEVICE_KIND_UEFI_DRIVER; + if (g_strcmp0 (kind, "fmp") == 0) + return FU_UEFI_DEVICE_KIND_FMP; + if (g_strcmp0 (kind, "dell-tpm-firmware") == 0) + return FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE; + return FU_UEFI_DEVICE_KIND_UNKNOWN; +} + +const gchar * +fu_uefi_device_status_to_string (FuUefiDeviceStatus status) +{ + if (status == FU_UEFI_DEVICE_STATUS_SUCCESS) + return "success"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL) + return "unsuccessful"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES) + return "insufficient resources"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION) + return "incorrect version"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT) + return "invalid firmware format"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR) + return "authentication signing error"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC) + return "AC power required"; + if (status == FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT) + return "battery level is too low"; + return NULL; +} + +static void +fu_uefi_device_to_string (FuDevice *device, GString *str) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + g_string_append (str, " FuUefiDevice:\n"); + g_string_append_printf (str, " kind:\t\t\t%s\n", + fu_uefi_device_kind_to_string (self->kind)); + g_string_append_printf (str, " fw_class:\t\t\t%s\n", self->fw_class); + g_string_append_printf (str, " capsule_flags:\t\t%" G_GUINT32_FORMAT "\n", + self->capsule_flags); + g_string_append_printf (str, " fw_version:\t\t\t%" G_GUINT32_FORMAT "\n", + self->fw_version); + g_string_append_printf (str, " fw_version_lowest:\t\t%" G_GUINT32_FORMAT "\n", + self->fw_version_lowest); + g_string_append_printf (str, " last_attempt_status:\t%s\n", + fu_uefi_device_status_to_string (self->last_attempt_status)); + g_string_append_printf (str, " last_attempt_version:\t%" G_GUINT32_FORMAT "\n", + self->last_attempt_version); + g_string_append_printf (str, " esp path:\t%s\n", + fu_device_get_metadata (device, "EspPath")); +} + +FuUefiDeviceKind +fu_uefi_device_get_kind (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0); + return self->kind; +} + +guint32 +fu_uefi_device_get_version (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->fw_version; +} + +guint32 +fu_uefi_device_get_version_lowest (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->fw_version_lowest; +} + +guint32 +fu_uefi_device_get_version_error (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->last_attempt_version; +} + +guint64 +fu_uefi_device_get_hardware_instance (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->fmp_hardware_instance; +} + +FuUefiDeviceStatus +fu_uefi_device_get_status (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0); + return self->last_attempt_status; +} + +guint32 +fu_uefi_device_get_capsule_flags (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), 0x0); + return self->capsule_flags; +} + +const gchar * +fu_uefi_device_get_guid (FuUefiDevice *self) +{ + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL); + return self->fw_class; +} + +static gchar * +fu_uefi_device_build_varname (FuUefiDevice *self) +{ + return g_strdup_printf ("fwupd-%s-%"G_GUINT64_FORMAT, + self->fw_class, + self->fmp_hardware_instance); +} + +FuUefiUpdateInfo * +fu_uefi_device_load_update_info (FuUefiDevice *self, GError **error) +{ + gsize datasz = 0; + g_autofree gchar *varname = fu_uefi_device_build_varname (self); + g_autofree guint8 *data = NULL; + g_autoptr(FuUefiUpdateInfo) info = fu_uefi_update_info_new (); + + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* get the existing status */ + if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, varname, + &data, &datasz, NULL, error)) + return NULL; + if (!fu_uefi_update_info_parse (info, data, datasz, error)) + return NULL; + return g_steal_pointer (&info); +} + +gboolean +fu_uefi_device_clear_status (FuUefiDevice *self, GError **error) +{ + efi_update_info_t info; + gsize datasz = 0; + g_autofree gchar *varname = fu_uefi_device_build_varname (self); + g_autofree guint8 *data = NULL; + + g_return_val_if_fail (FU_IS_UEFI_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* get the existing status */ + if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, varname, + &data, &datasz, NULL, error)) + return FALSE; + if (datasz < sizeof(efi_update_info_t)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "EFI variable is corrupt"); + return FALSE; + } + + /* just copy the efi_update_info_t, ignore devpath then save it back */ + memcpy (&info, data, sizeof(info)); + info.status = FU_UEFI_DEVICE_STATUS_SUCCESS; + memcpy (data, &info, sizeof(info)); + return fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_FWUPDATE, varname, + data, datasz, + FU_UEFI_VARS_ATTR_NON_VOLATILE | + FU_UEFI_VARS_ATTR_BOOTSERVICE_ACCESS | + FU_UEFI_VARS_ATTR_RUNTIME_ACCESS, + error); +} + +static guint8 * +fu_uefi_device_build_dp_buf (const gchar *path, gsize *bufsz, GError **error) +{ + gssize req; + gssize sz; + g_autofree guint8 *dp_buf = NULL; + g_autoptr(GPtrArray) dps = NULL; + + /* get the size of the path first */ + req = efi_generate_file_device_path (NULL, 0, path, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR | + EFIBOOT_ABBREV_HD); + if (req < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to efi_generate_file_device_path(%s)", + path); + return NULL; + } + + /* if we just have an end device path, it's not going to work */ + if (req <= 4) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to get valid device_path for (%s)", + path); + return NULL; + } + + /* actually get the path this time */ + dp_buf = g_malloc0 (req); + sz = efi_generate_file_device_path (dp_buf, req, path, + EFIBOOT_OPTIONS_IGNORE_FS_ERROR | + EFIBOOT_ABBREV_HD); + if (sz < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to efi_generate_file_device_path(%s)", + path); + return NULL; + } + + /* parse what we got back from efivar */ + dps = fu_uefi_devpath_parse (dp_buf, (gsize) sz, + FU_UEFI_DEVPATH_PARSE_FLAG_NONE, error); + if (dps == NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "dp_buf", dp_buf, (gsize) sz); + return NULL; + } + + /* success */ + if (bufsz != NULL) + *bufsz = sz; + return g_steal_pointer (&dp_buf); +} + +static GBytes * +fu_uefi_device_fixup_firmware (FuDevice *device, GBytes *fw, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + gsize fw_length; + efi_guid_t esrt_guid; + efi_guid_t payload_guid; + const gchar *data = g_bytes_get_data (fw, &fw_length); + self->missing_header = FALSE; + + /* convert to EFI GUIDs */ + if (efi_str_to_guid (fu_uefi_device_get_guid (self), &esrt_guid) < 0) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Invalid ESRT GUID"); + return NULL; + } + if (fw_length < sizeof(efi_guid_t)) { + g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, + "Invalid payload"); + return NULL; + } + memcpy (&payload_guid, data, sizeof(efi_guid_t)); + + /* ESRT header matches payload */ + if (efi_guid_cmp (&esrt_guid, &payload_guid) == 0) { + g_debug ("ESRT matches payload GUID"); + return g_bytes_new_from_bytes (fw, 0, fw_length); + /* FMP payload */ + } else if (fu_uefi_device_get_kind (self) == FU_UEFI_DEVICE_KIND_FMP) { + g_debug ("performing FMP update"); + return g_bytes_new_from_bytes (fw, 0, fw_length); + /* Missing, add a header */ + } else { + guint header_size = getpagesize(); + guint8 *new_data = g_malloc (fw_length + header_size); + guint8 *capsule = new_data + header_size; + efi_capsule_header_t *header = (efi_capsule_header_t *) new_data; + + g_warning ("missing or invalid embedded capsule header"); + self->missing_header = TRUE; + header->flags = self->capsule_flags; + header->header_size = header_size; + header->capsule_image_size = fw_length + header_size; + memcpy (&header->guid, &esrt_guid, sizeof (efi_guid_t)); + memcpy (capsule, data, fw_length); + + return g_bytes_new_take (new_data, fw_length + header_size); + } +} + +gboolean +fu_uefi_missing_capsule_header (FuDevice *device) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + return self->missing_header; +} + +gboolean +fu_uefi_device_write_update_info (FuUefiDevice *self, + const gchar *filename, + const gchar *varname, + const efi_guid_t *guid, + GError **error) +{ + gsize datasz = 0; + gsize dp_bufsz = 0; + g_autofree guint8 *data = NULL; + g_autofree guint8 *dp_buf = NULL; + efi_update_info_t info = { + .update_info_version = 0x7, + .guid = { 0x0 }, + .capsule_flags = self->capsule_flags, + .hw_inst = self->fmp_hardware_instance, + .time_attempted = { 0x0 }, + .status = FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE, + }; + + /* set the body as the device path */ + if (g_getenv ("FWUPD_UEFI_ESP_PATH") != NULL) { + g_debug ("not building device path, in tests...."); + return TRUE; + } + + /* convert to EFI device path */ + dp_buf = fu_uefi_device_build_dp_buf (filename, &dp_bufsz, error); + if (dp_buf == NULL) { + fu_uefi_prefix_efi_errors (error); + return FALSE; + } + + /* save this header and body to the hardware */ + memcpy (&info.guid, guid, sizeof(efi_guid_t)); + datasz = sizeof(info) + dp_bufsz; + data = g_malloc0 (datasz); + memcpy (data, &info, sizeof(info)); + memcpy (data + sizeof(info), dp_buf, dp_bufsz); + if (!fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_FWUPDATE, varname, + data, datasz, + FU_UEFI_VARS_ATTR_NON_VOLATILE | + FU_UEFI_VARS_ATTR_BOOTSERVICE_ACCESS | + FU_UEFI_VARS_ATTR_RUNTIME_ACCESS, + error)) { + fu_uefi_prefix_efi_errors (error); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_uefi_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags install_flags, + GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + FuUefiBootmgrFlags flags = FU_UEFI_BOOTMGR_FLAG_NONE; + const gchar *bootmgr_desc = "Linux Firmware Updater"; + const gchar *esp_path = fu_device_get_metadata (device, "EspPath"); + efi_guid_t guid; + g_autoptr(GBytes) fixed_fw = NULL; + g_autofree gchar *basename = NULL; + g_autofree gchar *directory = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *varname = fu_uefi_device_build_varname (self); + + /* ensure we have the existing state */ + if (self->fw_class == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot update device info with no GUID"); + return FALSE; + } + + /* save the blob to the ESP */ + directory = fu_uefi_get_esp_path_for_os (esp_path); + basename = g_strdup_printf ("fwupd-%s.cap", self->fw_class); + fn = g_build_filename (directory, "fw", basename, NULL); + if (!fu_common_mkdir_parent (fn, error)) + return FALSE; + fixed_fw = fu_uefi_device_fixup_firmware (device, fw, error); + if (fixed_fw == NULL) + return FALSE; + if (!fu_common_set_contents_bytes (fn, fixed_fw, error)) + return FALSE; + + /* set the blob header shared with fwupd.efi */ + if (efi_str_to_guid (self->fw_class, &guid) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to get convert GUID"); + return FALSE; + } + if (!fu_uefi_device_write_update_info (self, fn, varname, &guid, error)) + return FALSE; + + /* update the firmware before the bootloader runs */ + if (fu_device_get_metadata_boolean (device, "RequireShimForSecureBoot")) + flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_FOR_SB; + if (fu_device_has_custom_flag (device, "use-shim-unique")) + flags |= FU_UEFI_BOOTMGR_FLAG_USE_SHIM_UNIQUE; + + /* some legacy devices use the old name to deduplicate boot entries */ + if (fu_device_has_custom_flag (device, "use-legacy-bootmgr-desc")) + bootmgr_desc = "Linux-Firmware-Updater"; + if (!fu_uefi_bootmgr_bootnext (esp_path, bootmgr_desc, flags, error)) + return FALSE; + + /* success! */ + return TRUE; +} + +static gboolean +fu_uefi_device_add_system_checksum (FuDevice *device, GError **error) +{ + g_autoptr(FuUefiPcrs) pcrs = fu_uefi_pcrs_new (); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; + + /* get all the PCRs */ + if (!fu_uefi_pcrs_setup (pcrs, &error_local)) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED)) { + g_debug ("%s", error_local->message); + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + + /* get all the PCR0s */ + pcr0s = fu_uefi_pcrs_get_checksums (pcrs, 0); + if (pcr0s->len == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no PCR0s detected"); + return FALSE; + } + for (guint i = 0; i < pcr0s->len; i++) { + const gchar *checksum = g_ptr_array_index (pcr0s, i); + fu_device_add_checksum (device, checksum); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_uefi_device_probe (FuDevice *device, GError **error) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (device); + FwupdVersionFormat version_format; + g_autofree gchar *devid = NULL; + g_autofree gchar *guid_strup = NULL; + g_autofree gchar *version_lowest = NULL; + g_autofree gchar *version = NULL; + + /* broken sysfs? */ + if (self->fw_class == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to read fw_class"); + return FALSE; + } + + /* add GUID first, as quirks may set the version format */ + fu_device_add_guid (device, self->fw_class); + + /* set versions */ + version_format = fu_device_get_version_format (device); + version = fu_common_version_from_uint32 (self->fw_version, version_format); + fu_device_set_version (device, version, version_format); + if (self->fw_version_lowest != 0) { + version_lowest = fu_common_version_from_uint32 (self->fw_version_lowest, + version_format); + fu_device_set_version_lowest (device, version_lowest); + } + + /* set flags */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_INTERNAL); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC); + + /* add icons */ + if (self->kind == FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE) { + /* nothing better in the icon naming spec */ + fu_device_add_icon (device, "audio-card"); + } else { + /* this is probably system firmware */ + fu_device_add_icon (device, "computer"); + fu_device_add_instance_id (device, "main-system-firmware"); + } + + /* set the PCR0 as the device checksum */ + if (self->kind == FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE) { + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_device_add_system_checksum (device, &error_local)) + g_warning ("Failed to get PCR0s: %s", error_local->message); + } + + /* Windows seems to be case insensitive, but for convenience we'll + * match the upper case values typically specified in the .inf file */ + guid_strup = g_ascii_strup (self->fw_class, -1); + devid = g_strdup_printf ("UEFI\\RES_{%s}", guid_strup); + fu_device_add_instance_id (device, devid); + return TRUE; +} + +static void +fu_uefi_device_init (FuUefiDevice *self) +{ +} + +static void +fu_uefi_device_finalize (GObject *object) +{ + FuUefiDevice *self = FU_UEFI_DEVICE (object); + + g_free (self->fw_class); + + G_OBJECT_CLASS (fu_uefi_device_parent_class)->finalize (object); +} + +static void +fu_uefi_device_class_init (FuUefiDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + object_class->finalize = fu_uefi_device_finalize; + klass_device->to_string = fu_uefi_device_to_string; + klass_device->probe = fu_uefi_device_probe; + klass_device->write_firmware = fu_uefi_device_write_firmware; +} + +FuUefiDevice * +fu_uefi_device_new_from_entry (const gchar *entry_path, GError **error) +{ + g_autoptr(FuUefiDevice) self = NULL; + g_autofree gchar *fw_class_fn = NULL; + g_autofree gchar *id = NULL; + + g_return_val_if_fail (entry_path != NULL, NULL); + + /* create object */ + self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + + /* read values from sysfs */ + fw_class_fn = g_build_filename (entry_path, "fw_class", NULL); + if (g_file_get_contents (fw_class_fn, &self->fw_class, NULL, NULL)) + g_strdelimit (self->fw_class, "\n", '\0'); + self->capsule_flags = fu_uefi_read_file_as_uint64 (entry_path, "capsule_flags"); + self->kind = fu_uefi_read_file_as_uint64 (entry_path, "fw_type"); + self->fw_version = fu_uefi_read_file_as_uint64 (entry_path, "fw_version"); + self->last_attempt_status = fu_uefi_read_file_as_uint64 (entry_path, "last_attempt_status"); + self->last_attempt_version = fu_uefi_read_file_as_uint64 (entry_path, "last_attempt_version"); + self->fw_version_lowest = fu_uefi_read_file_as_uint64 (entry_path, "lowest_supported_fw_version"); + + /* the hardware instance is not in the ESRT table and we should really + * write the EFI stub to query with FMP -- but we still have not ever + * seen a PCIe device with FMP support... */ + self->fmp_hardware_instance = 0x0; + + /* set ID */ + id = g_strdup_printf ("UEFI-%s-dev%" G_GUINT64_FORMAT, + self->fw_class, self->fmp_hardware_instance); + fu_device_set_id (FU_DEVICE (self), id); + + /* this is invalid */ + if (!fwupd_guid_is_valid (self->fw_class)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "ESRT GUID '%s' was not valid", self->fw_class); + return NULL; + } + + return g_steal_pointer (&self); +} + +FuUefiDevice * +fu_uefi_device_new_from_dev (FuDevice *dev) +{ + const gchar *tmp; + FuUefiDevice *self; + + g_return_val_if_fail (fu_device_get_guid_default (dev) != NULL, NULL); + + /* create virtual object not backed by an ESRT entry */ + self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), dev); + self->fw_class = g_strdup (fu_device_get_guid_default (dev)); + tmp = fu_device_get_metadata (dev, FU_DEVICE_METADATA_UEFI_DEVICE_KIND); + self->kind = fu_uefi_device_kind_from_string (tmp); + self->capsule_flags = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS); + self->fw_version = fu_device_get_metadata_integer (dev, FU_DEVICE_METADATA_UEFI_FW_VERSION); + g_assert (self->fw_class != NULL); + return self; +} + +FuUefiDevice * +fu_uefi_device_new_from_guid (const gchar *guid) +{ + FuUefiDevice *self; + self = g_object_new (FU_TYPE_UEFI_DEVICE, NULL); + self->fw_class = g_strdup (guid); + return self; +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-device.h fwupd-1.2.10/plugins/uefi/fu-uefi-device.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" +#include "fu-uefi-device.h" +#include "fu-uefi-update-info.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_DEVICE (fu_uefi_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiDevice, fu_uefi_device, FU, UEFI_DEVICE, FuDevice) + +typedef enum { + FU_UEFI_DEVICE_KIND_UNKNOWN, + FU_UEFI_DEVICE_KIND_SYSTEM_FIRMWARE, + FU_UEFI_DEVICE_KIND_DEVICE_FIRMWARE, + FU_UEFI_DEVICE_KIND_UEFI_DRIVER, + FU_UEFI_DEVICE_KIND_FMP, + FU_UEFI_DEVICE_KIND_DELL_TPM_FIRMWARE, + FU_UEFI_DEVICE_KIND_LAST +} FuUefiDeviceKind; + +typedef enum { + FU_UEFI_DEVICE_STATUS_SUCCESS = 0x00, + FU_UEFI_DEVICE_STATUS_ERROR_UNSUCCESSFUL = 0x01, + FU_UEFI_DEVICE_STATUS_ERROR_INSUFFICIENT_RESOURCES = 0x02, + FU_UEFI_DEVICE_STATUS_ERROR_INCORRECT_VERSION = 0x03, + FU_UEFI_DEVICE_STATUS_ERROR_INVALID_FORMAT = 0x04, + FU_UEFI_DEVICE_STATUS_ERROR_AUTH_ERROR = 0x05, + FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_AC = 0x06, + FU_UEFI_DEVICE_STATUS_ERROR_PWR_EVT_BATT = 0x07, + FU_UEFI_DEVICE_STATUS_LAST +} FuUefiDeviceStatus; + +FuUefiDevice *fu_uefi_device_new_from_guid (const gchar *guid); +FuUefiDevice *fu_uefi_device_new_from_entry (const gchar *entry_path, + GError **error); +FuUefiDevice *fu_uefi_device_new_from_dev (FuDevice *dev); +gboolean fu_uefi_device_clear_status (FuUefiDevice *self, + GError **error); +FuUefiDeviceKind fu_uefi_device_get_kind (FuUefiDevice *self); +const gchar *fu_uefi_device_get_guid (FuUefiDevice *self); +guint32 fu_uefi_device_get_version (FuUefiDevice *self); +guint32 fu_uefi_device_get_version_lowest (FuUefiDevice *self); +guint32 fu_uefi_device_get_version_error (FuUefiDevice *self); +guint32 fu_uefi_device_get_capsule_flags (FuUefiDevice *self); +guint64 fu_uefi_device_get_hardware_instance (FuUefiDevice *self); +FuUefiDeviceStatus fu_uefi_device_get_status (FuUefiDevice *self); +const gchar *fu_uefi_device_kind_to_string (FuUefiDeviceKind kind); +const gchar *fu_uefi_device_status_to_string (FuUefiDeviceStatus status); +FuUefiUpdateInfo *fu_uefi_device_load_update_info (FuUefiDevice *self, + GError **error); +gboolean fu_uefi_missing_capsule_header (FuDevice *device); +gboolean fu_uefi_device_write_update_info (FuUefiDevice *self, + const gchar *filename, + const gchar *varname, + const efi_guid_t *guid, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-devpath.c fwupd-1.2.10/plugins/uefi/fu-uefi-devpath.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-devpath.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-devpath.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-uefi-devpath.h" + +#include "fwupd-error.h" + +typedef struct { + guint8 type; + guint8 subtype; + GBytes *data; +} FuUefiDevPath; + +static void +fu_uefi_efi_dp_free (FuUefiDevPath *dp) +{ + if (dp->data != NULL) + g_bytes_unref (dp->data); + g_free (dp); +} + +GBytes * +fu_uefi_devpath_find_data (GPtrArray *dps, guint8 type, guint8 subtype, GError **error) +{ + for (guint i = 0; i < dps->len; i++) { + FuUefiDevPath *dp = g_ptr_array_index (dps, i); + if (dp->type == type && dp->subtype == subtype) + return dp->data; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no DP with type 0x%02x and subtype 0x%02x", + type, subtype); + return NULL; +} + +GPtrArray * +fu_uefi_devpath_parse (const guint8 *buf, gsize sz, + FuUefiDevpathParseFlags flags, GError **error) +{ + guint16 offset = 0; + g_autoptr(GPtrArray) dps = NULL; + + /* sanity check */ + if (sz < sizeof(efidp_header)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "const_efidp is corrupt"); + return NULL; + } + + dps = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_efi_dp_free); + while (1) { + FuUefiDevPath *dp; + const efidp_header *hdr = (efidp_header *) (buf + offset); + guint16 hdr_length = GUINT16_FROM_LE(hdr->length); + + /* check if last entry */ + g_debug ("DP type:0x%02x subtype:0x%02x size:0x%04x", + hdr->type, hdr->subtype, hdr->length); + if (hdr->type == EFIDP_END_TYPE && hdr->subtype == EFIDP_END_ENTIRE) + break; + + /* work around a bug in efi_va_generate_file_device_path_from_esp */ + if (offset + sizeof(efidp_header) + hdr->length > sz) { + hdr_length = 0; + fu_common_dump_full (G_LOG_DOMAIN, "efidp", + buf + offset, sz - offset, 32, + FU_DUMP_FLAGS_SHOW_ADDRESSES); + for (guint16 i = offset + 4; i <= sz - 4; i++) { + if (memcmp (buf + i, "\x7f\xff\x04\x00", 4) == 0) { + hdr_length = i - offset; + g_debug ("found END_ENTIRE at 0x%04x", + (guint) (i - offset)); + break; + } + } + if (hdr_length == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DP length invalid and no END_ENTIRE " + "found, possibly data truncation?"); + return NULL; + } + if ((flags & FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DP length invalid, reported 0x%04x, maybe 0x%04x", + hdr->length, hdr_length); + return NULL; + } + g_debug ("DP length invalid! Truncating from 0x%04x to 0x%04x", + hdr->length, hdr_length); + } + + /* add new DP */ + dp = g_new0 (FuUefiDevPath, 1); + dp->type = hdr->type; + dp->subtype = hdr->subtype; + if (hdr_length > 0) + dp->data = g_bytes_new (buf + offset + 4, hdr_length); + g_ptr_array_add (dps, dp); + + /* advance to next DP */ + offset += hdr_length; + if (offset + sizeof(efidp_header) > sz) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "DP length invalid after fixing"); + return NULL; + } + + } + return g_steal_pointer (&dps); +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-devpath.h fwupd-1.2.10/plugins/uefi/fu-uefi-devpath.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-devpath.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-devpath.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +typedef enum { + FU_UEFI_DEVPATH_PARSE_FLAG_NONE = 0, + FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR = 1 << 0, + FU_UEFI_DEVPATH_PARSE_FLAG_LAST +} FuUefiDevpathParseFlags; + +GPtrArray *fu_uefi_devpath_parse (const guint8 *buf, + gsize sz, + FuUefiDevpathParseFlags flags, + GError **error); +GBytes *fu_uefi_devpath_find_data (GPtrArray *dps, + guint8 type, + guint8 subtype, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-pcrs.c fwupd-1.2.10/plugins/uefi/fu-uefi-pcrs.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-pcrs.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-pcrs.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-pcrs.h" + +typedef struct { + guint idx; + gchar *checksum; +} FuUefiPcrItem; + +struct _FuUefiPcrs { + GObject parent_instance; + GPtrArray *items; /* of FuUefiPcrItem */ +}; + +G_DEFINE_TYPE (FuUefiPcrs, fu_uefi_pcrs, G_TYPE_OBJECT) + +static gboolean +_g_string_isxdigit (GString *str) +{ + for (gsize i = 0; i < str->len; i++) { + if (!g_ascii_isxdigit (str->str[i])) + return FALSE; + } + return TRUE; +} + +static void +fu_uefi_pcrs_parse_line (const gchar *line, gpointer user_data) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (user_data); + FuUefiPcrItem *item; + guint64 idx; + g_autofree gchar *idxstr = NULL; + g_auto(GStrv) split = NULL; + g_autoptr(GString) str = NULL; + + /* split into index:hash */ + if (line == NULL || line[0] == '\0') + return; + split = g_strsplit (line, ":", -1); + if (g_strv_length (split) != 2) { + g_debug ("unexpected format, skipping: %s", line); + return; + } + + /* get index */ + idxstr = fu_common_strstrip (split[0]); + idx = fu_common_strtoull (idxstr); + if (idx > 64) { + g_debug ("unexpected index, skipping: %s", idxstr); + return; + } + + /* parse hash */ + str = g_string_new (split[1]); + fu_common_string_replace (str, " ", ""); + if ((str->len != 40 && str->len != 64) || !_g_string_isxdigit (str)) { + g_debug ("not SHA-1 or SHA-256, skipping: %s", split[1]); + return; + } + g_string_ascii_down (str); + item = g_new0 (FuUefiPcrItem, 1); + item->idx = idx; + item->checksum = g_string_free (g_steal_pointer (&str), FALSE); + g_ptr_array_add (self->items, item); + g_debug ("added PCR-%02u=%s", item->idx, item->checksum); +} + +static gboolean +fu_uefi_pcrs_setup_dummy (FuUefiPcrs *self, const gchar *test_yaml, GError **error) +{ + g_auto(GStrv) lines = g_strsplit (test_yaml, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) + fu_uefi_pcrs_parse_line (lines[i], self); + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm12 (FuUefiPcrs *self, const gchar *fn_pcrs, GError **error) +{ + g_auto(GStrv) lines = NULL; + g_autofree gchar *buf_pcrs = NULL; + + /* get entire contents */ + if (!g_file_get_contents (fn_pcrs, &buf_pcrs, NULL, error)) + return FALSE; + + /* find PCR lines */ + lines = g_strsplit (buf_pcrs, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix (lines[i], "PCR-")) + fu_uefi_pcrs_parse_line (lines[i] + 4, self); + } + return TRUE; +} + +static gboolean +fu_uefi_pcrs_setup_tpm20 (FuUefiPcrs *self, const gchar *argv0, GError **error) +{ + const gchar *argv[] = { argv0, NULL }; + return fu_common_spawn_sync (argv, fu_uefi_pcrs_parse_line, self, 1500, NULL, error); +} + +gboolean +fu_uefi_pcrs_setup (FuUefiPcrs *self, GError **error) +{ + g_autofree gchar *devpath = NULL; + g_autofree gchar *sysfstpmdir = NULL; + g_autofree gchar *fn_pcrs = NULL; + const gchar *test_yaml = g_getenv ("FWUPD_UEFI_TPM2_YAML_DATA"); + + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), FALSE); + + /* check the TPM device exists at all */ + sysfstpmdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_TPM); + devpath = g_build_filename (sysfstpmdir, "tpm0", NULL); + if (!g_file_test (devpath, G_FILE_TEST_EXISTS)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPM device found"); + return FALSE; + } + fn_pcrs = g_build_filename (devpath, "pcrs", NULL); + + /* fake device */ + if (test_yaml != NULL) { + if (!fu_uefi_pcrs_setup_dummy (self, test_yaml, error)) + return FALSE; + + /* look for TPM 1.2 */ + } else if (g_file_test (fn_pcrs, G_FILE_TEST_EXISTS)) { + if (!fu_uefi_pcrs_setup_tpm12 (self, fn_pcrs, error)) + return FALSE; + + /* assume TPM 2.0 */ + } else { + g_autofree gchar *argv0 = NULL; + + /* old name, then new name */ + argv0 = fu_common_find_program_in_path ("tpm2_listpcrs", NULL); + if (argv0 == NULL) + argv0 = fu_common_find_program_in_path ("tpm2_pcrlist", error); + if (argv0 == NULL) + return FALSE; + if (!fu_uefi_pcrs_setup_tpm20 (self, argv0, error)) + return FALSE; + } + + /* check we got anything */ + if (self->items->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "no TPMxx measurements found"); + return FALSE; + } + + /* success */ + return TRUE; +} + +GPtrArray * +fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, guint idx) +{ + g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free); + g_return_val_if_fail (FU_IS_UEFI_PCRS (self), NULL); + for (guint i = 0; i < self->items->len; i++) { + FuUefiPcrItem *item = g_ptr_array_index (self->items, i); + if (item->idx == idx) + g_ptr_array_add (array, g_strdup (item->checksum)); + } + return g_steal_pointer (&array); +} + +static void +fu_uefi_pcrs_item_free (FuUefiPcrItem *item) +{ + g_free (item->checksum); + g_free (item); +} + +static void +fu_uefi_pcrs_finalize (GObject *object) +{ + FuUefiPcrs *self = FU_UEFI_PCRS (object); + g_ptr_array_unref (self->items); + G_OBJECT_CLASS (fu_uefi_pcrs_parent_class)->finalize (object); +} + +static void +fu_uefi_pcrs_class_init (FuUefiPcrsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_pcrs_finalize; +} + +static void +fu_uefi_pcrs_init (FuUefiPcrs *self) +{ + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_pcrs_item_free); +} + +FuUefiPcrs * +fu_uefi_pcrs_new (void) +{ + FuUefiPcrs *self; + self = g_object_new (FU_TYPE_UEFI_PCRS, NULL); + return FU_UEFI_PCRS (self); +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-pcrs.h fwupd-1.2.10/plugins/uefi/fu-uefi-pcrs.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-pcrs.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-pcrs.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_PCRS (fu_uefi_pcrs_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiPcrs, fu_uefi_pcrs, FU, UEFI_PCRS, GObject) + +FuUefiPcrs *fu_uefi_pcrs_new (void); +gboolean fu_uefi_pcrs_setup (FuUefiPcrs *self, + GError **error); +GPtrArray *fu_uefi_pcrs_get_checksums (FuUefiPcrs *self, + guint idx); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-tool.c fwupd-1.2.10/plugins/uefi/fu-uefi-tool.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-tool.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-tool.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-ucs2.h" +#include "fu-uefi-common.h" +#include "fu-uefi-device.h" +#include "fu-uefi-update-info.h" +#include "fu-uefi-vars.h" + +/* custom return code */ +#define EXIT_NOTHING_TO_DO 2 + +typedef struct { + GCancellable *cancellable; + GMainLoop *loop; + GOptionContext *context; +} FuUtilPrivate; + +static void +fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ +} + +static void +fu_util_private_free (FuUtilPrivate *priv) +{ + if (priv->context != NULL) + g_option_context_free (priv->context); + g_free (priv); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop + +int +main (int argc, char *argv[]) +{ + gboolean action_enable = FALSE; + gboolean action_info = FALSE; + gboolean action_list = FALSE; + gboolean action_log = FALSE; + gboolean action_set_debug = FALSE; + gboolean action_supported = FALSE; + gboolean action_unset_debug = FALSE; + gboolean action_version = FALSE; + gboolean ret; + gboolean verbose = FALSE; + g_autofree gchar *apply = FALSE; + g_autofree gchar *esp_path = NULL; + g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + const GOptionEntry options[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + /* TRANSLATORS: command line option */ + _("Show extra debugging information"), NULL }, + { "version", '\0', 0, G_OPTION_ARG_NONE, &action_version, + /* TRANSLATORS: command line option */ + _("Display version"), NULL }, + { "log", 'L', 0, G_OPTION_ARG_NONE, &action_log, + /* TRANSLATORS: command line option */ + _("Show the debug log from the last attempted update"), NULL }, + { "list", 'l', 0, G_OPTION_ARG_NONE, &action_list, + /* TRANSLATORS: command line option */ + _("List supported firmware updates"), NULL }, + { "supported", 's', 0, G_OPTION_ARG_NONE, &action_supported, + /* TRANSLATORS: command line option */ + _("Query for firmware update support"), NULL }, + { "info", 'i', 0, G_OPTION_ARG_NONE, &action_info, + /* TRANSLATORS: command line option */ + _("Show the information of firmware update status"), NULL }, + { "enable", 'e', 0, G_OPTION_ARG_NONE, &action_enable, + /* TRANSLATORS: command line option */ + _("Enable firmware update support on supported systems"), NULL }, + { "esp-path", 'p', 0, G_OPTION_ARG_STRING, &esp_path, + /* TRANSLATORS: command line option */ + _("Override the default ESP path"), "PATH" }, + { "set-debug", 'd', 0, G_OPTION_ARG_NONE, &action_set_debug, + /* TRANSLATORS: command line option */ + _("Set the debugging flag during update"), NULL }, + { "unset-debug", 'D', 0, G_OPTION_ARG_NONE, &action_unset_debug, + /* TRANSLATORS: command line option */ + _("Unset the debugging flag during update"), NULL }, + { "apply", 'a', 0, G_OPTION_ARG_STRING, &apply, + /* TRANSLATORS: command line option */ + _("Apply firmware updates"), "GUID" }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* ensure root user */ + if (getuid () != 0 || geteuid () != 0) + /* TRANSLATORS: we're poking around as a power user */ + g_printerr ("%s\n", _("This program may only work correctly as root")); + + /* get a action_list of the commands */ + priv->context = g_option_context_new (NULL); + g_option_context_set_description (priv->context, + "This tool allows an administrator to debug UpdateCapsule operation."); + + /* TRANSLATORS: program name */ + g_set_application_name (_("UEFI Firmware Utility")); + g_option_context_add_main_entries (priv->context, options, NULL); + ret = g_option_context_parse (priv->context, &argc, &argv, &error); + if (!ret) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), + error->message); + return EXIT_FAILURE; + } + + /* set verbose? */ + if (verbose) { + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + } else { + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + fu_util_ignore_cb, NULL); + } + + /* nothing specified */ + if (!action_enable && !action_info && !action_list && !action_log && + !action_set_debug && !action_supported && !action_unset_debug && + !action_version && apply == NULL) { + g_autofree gchar *tmp = NULL; + tmp = g_option_context_get_help (priv->context, TRUE, NULL); + g_printerr ("%s\n\n%s", _("No action specified!"), tmp); + return EXIT_FAILURE; + } + + /* action_version first */ + if (action_version) + g_print ("fwupd version: %s\n", PACKAGE_VERSION); + + /* override the default ESP path */ + if (esp_path != NULL) { + if (!fu_uefi_check_esp_path (esp_path, &error)) { + /* TRANSLATORS: ESP is EFI System Partition */ + g_print ("%s: %s\n", _("ESP specified was not valid"), + error->message); + return EXIT_FAILURE; + } + } else { + esp_path = fu_uefi_guess_esp_path (); + if (esp_path == NULL) { + g_printerr ("Unable to determine EFI system partition " + "location, override using --esp-path\n"); + return EXIT_FAILURE; + } + } + + /* check free space */ + if (!fu_uefi_check_esp_free_space (esp_path, + FU_UEFI_COMMON_REQUIRED_ESP_FREE_SPACE, + &error)) { + g_printerr ("Unable to use EFI system partition: %s\n", error->message); + return EXIT_FAILURE; + } + g_debug ("ESP mountpoint set as %s", esp_path); + + /* show the debug action_log from the last attempted update */ + if (action_log) { + gsize sz = 0; + g_autofree guint8 *buf = NULL; + g_autofree guint16 *buf_ucs2 = NULL; + g_autofree gchar *str = NULL; + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_vars_get_data (FU_UEFI_VARS_GUID_FWUPDATE, + "FWUPDATE_DEBUG_LOG", + &buf, &sz, NULL, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + buf_ucs2 = g_new0 (guint16, (sz / 2) + 1); + memcpy (buf_ucs2, buf, sz); + str = fu_ucs2_to_uft8 (buf_ucs2, sz / 2); + g_print ("%s", str); + } + + if (action_list || action_supported || action_info) { + g_autoptr(GPtrArray) entries = NULL; + g_autofree gchar *esrt_path = NULL; + g_autofree gchar *sysfsfwdir = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the directory of ESRT entries */ + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + esrt_path = g_build_filename (sysfsfwdir, "efi", "esrt", NULL); + entries = fu_uefi_get_esrt_entry_paths (esrt_path, &error_local); + if (entries == NULL) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + + /* add each device */ + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < entries->len; i++) { + const gchar *path = g_ptr_array_index (entries, i); + g_autoptr(GError) error_parse = NULL; + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_entry (path, &error_parse); + if (dev == NULL) { + g_warning ("failed to parse %s: %s", + path, error_parse->message); + continue; + } + fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); + g_ptr_array_add (devices, g_object_ref (dev)); + } + } + + /* action_list action_supported firmware updates */ + if (action_list) { + for (guint i = 0; i < devices->len; i++) { + FuUefiDevice *dev = g_ptr_array_index (devices, i); + g_print ("%s type, {%s} action_version %" G_GUINT32_FORMAT " can be updated " + "to any action_version above %" G_GUINT32_FORMAT "\n", + fu_uefi_device_kind_to_string (fu_uefi_device_get_kind (dev)), + fu_uefi_device_get_guid (dev), + fu_uefi_device_get_version (dev), + fu_uefi_device_get_version_lowest (dev) - 1); + } + } + + /* query for firmware update support */ + if (action_supported) { + if (devices->len > 0) { + g_print ("%s\n", _("Firmware updates are supported on this machine.")); + } else { + g_print ("%s\n", _("Firmware updates are not supported on this machine.")); + } + } + + /* show the information of firmware update status */ + if (action_info) { + for (guint i = 0; i < devices->len; i++) { + FuUefiDevice *dev = g_ptr_array_index (devices, i); + g_autoptr(FuUefiUpdateInfo) info = NULL; + g_autoptr(GError) error_local = NULL; + + /* load any existing update info */ + info = fu_uefi_device_load_update_info (dev, &error_local); + if (info == NULL) { + g_printerr ("failed: %s\n", error_local->message); + continue; + } + g_print ("Information for the update status entry %u:\n", i); + g_print (" Information Version: %" G_GUINT32_FORMAT "\n", + fu_uefi_update_info_get_version (info)); + g_print (" Firmware GUID: {%s}\n", + fu_uefi_update_info_get_guid (info)); + g_print (" Capsule Flags: 0x%08" G_GUINT32_FORMAT "x\n", + fu_uefi_update_info_get_capsule_flags (info)); + g_print (" Hardware Instance: %" G_GUINT64_FORMAT "\n", + fu_uefi_update_info_get_hw_inst (info)); + g_print (" Update Status: %s\n", + fu_uefi_update_info_status_to_string (fu_uefi_update_info_get_status (info))); + g_print (" Capsule File Path: %s\n\n", + fu_uefi_update_info_get_capsule_fn (info)); + } + } + + /* action_enable firmware update support on action_supported systems */ + if (action_enable) { + g_printerr ("Unsupported, use `fwupdmgr unlock`\n"); + return EXIT_FAILURE; + } + + /* set the debugging flag during update */ + if (action_set_debug) { + const guint8 data = 1; + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_vars_set_data (FU_UEFI_VARS_GUID_FWUPDATE, + "FWUPDATE_VERBOSE", + &data, sizeof(data), + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + g_print ("%s\n", _("Enabled fwupdate debugging")); + } + + /* unset the debugging flag during update */ + if (action_unset_debug) { + g_autoptr(GError) error_local = NULL; + if (!fu_uefi_vars_delete (FU_UEFI_VARS_GUID_FWUPDATE, + "FWUPDATE_VERBOSE", + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + g_print ("%s\n", _("Disabled fwupdate debugging")); + } + + /* apply firmware updates */ + if (apply != NULL) { + g_autoptr(FuUefiDevice) dev = fu_uefi_device_new_from_guid (apply); + g_autoptr(GError) error_local = NULL; + g_autoptr(GBytes) fw = fu_common_get_contents_bytes (argv[1], &error_local); + if (fw == NULL) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + fu_device_set_metadata (FU_DEVICE (dev), "EspPath", esp_path); + if (!fu_device_write_firmware (FU_DEVICE (dev), fw, + FWUPD_INSTALL_FLAG_NONE, + &error_local)) { + g_printerr ("failed: %s\n", error_local->message); + return EXIT_FAILURE; + } + } + + /* success */ + return EXIT_SUCCESS; +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-update-info.c fwupd-1.2.10/plugins/uefi/fu-uefi-update-info.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-update-info.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-update-info.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-uefi-devpath.h" +#include "fu-uefi-update-info.h" +#include "fu-uefi-common.h" +#include "fu-ucs2.h" + +#include "fwupd-error.h" + +struct _FuUefiUpdateInfo { + GObject parent_instance; + guint32 version; + gchar *guid; + gchar *capsule_fn; + guint32 capsule_flags; + guint64 hw_inst; + FuUefiUpdateInfoStatus status; +}; + +G_DEFINE_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, G_TYPE_OBJECT) + +const gchar * +fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status) +{ + if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE) + return "attempt-update"; + if (status == FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED) + return "attempted"; + return "unknown"; +} + +static gchar * +fu_uefi_update_info_parse_dp (const guint8 *buf, gsize sz, GError **error) +{ + GBytes *dp_data; + const gchar *data; + gsize ucs2sz = 0; + g_autofree gchar *relpath = NULL; + g_autofree guint16 *ucs2file = NULL; + g_autoptr(GPtrArray) dps = NULL; + + g_return_val_if_fail (buf != NULL, NULL); + g_return_val_if_fail (sz != 0, NULL); + + /* get all headers */ + dps = fu_uefi_devpath_parse (buf, sz, FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR, error); + if (dps == NULL) + return NULL; + dp_data = fu_uefi_devpath_find_data (dps, + EFIDP_MEDIA_TYPE, + EFIDP_MEDIA_FILE, + error); + if (dp_data == NULL) + return NULL; + + /* convert to UTF-8 */ + data = g_bytes_get_data (dp_data, &ucs2sz); + ucs2file = g_new0 (guint16, (ucs2sz / 2) + 1); + memcpy (ucs2file, data, ucs2sz); + relpath = fu_ucs2_to_uft8 (ucs2file, ucs2sz / sizeof (guint16)); + if (relpath == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot convert to UTF-8"); + return NULL; + } + g_strdelimit (relpath, "\\", '/'); + return g_steal_pointer (&relpath); +} + +gboolean +fu_uefi_update_info_parse (FuUefiUpdateInfo *self, const guint8 *buf, gsize sz, GError **error) +{ + efi_update_info_t info; + efi_guid_t guid_tmp; + + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), FALSE); + + if (sz < sizeof(efi_update_info_t)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "EFI variable is corrupt"); + return FALSE; + } + memcpy (&info, buf, sizeof(info)); + self->version = info.update_info_version; + self->capsule_flags = info.capsule_flags; + self->hw_inst = info.hw_inst; + self->status = info.status; + memcpy (&guid_tmp, &info.guid, sizeof(efi_guid_t)); + if (efi_guid_to_str (&guid_tmp, &self->guid) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to convert GUID"); + return FALSE; + } + if (sz > sizeof(efi_update_info_t)) { + self->capsule_fn = fu_uefi_update_info_parse_dp (buf + sizeof(efi_update_info_t), + sz - sizeof(efi_update_info_t), + error); + if (self->capsule_fn == NULL) + return FALSE; + } + return TRUE; +} + +const gchar * +fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); + return self->guid; +} + +const gchar * +fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), NULL); + return self->capsule_fn; +} + +guint32 +fu_uefi_update_info_get_version (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->version; +} + +guint32 +fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->capsule_flags; +} + +guint64 +fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->hw_inst; +} + +FuUefiUpdateInfoStatus +fu_uefi_update_info_get_status (FuUefiUpdateInfo *self) +{ + g_return_val_if_fail (FU_IS_UEFI_UPDATE_INFO (self), 0); + return self->status; +} + +static void +fu_uefi_update_info_finalize (GObject *object) +{ + FuUefiUpdateInfo *self = FU_UEFI_UPDATE_INFO (object); + g_free (self->guid); + g_free (self->capsule_fn); + G_OBJECT_CLASS (fu_uefi_update_info_parent_class)->finalize (object); +} + +static void +fu_uefi_update_info_class_init (FuUefiUpdateInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_uefi_update_info_finalize; +} + +static void +fu_uefi_update_info_init (FuUefiUpdateInfo *self) +{ +} + +FuUefiUpdateInfo * +fu_uefi_update_info_new (void) +{ + FuUefiUpdateInfo *self; + self = g_object_new (FU_TYPE_UEFI_UPDATE_INFO, NULL); + return FU_UEFI_UPDATE_INFO (self); +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-update-info.h fwupd-1.2.10/plugins/uefi/fu-uefi-update-info.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-update-info.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-update-info.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +G_BEGIN_DECLS + +#define FU_TYPE_UEFI_UPDATE_INFO (fu_uefi_update_info_get_type ()) +G_DECLARE_FINAL_TYPE (FuUefiUpdateInfo, fu_uefi_update_info, FU, UEFI_UPDATE_INFO, GObject) + +typedef enum { + FU_UEFI_UPDATE_INFO_STATUS_ATTEMPT_UPDATE = 0x00000001, + FU_UEFI_UPDATE_INFO_STATUS_ATTEMPTED = 0x00000002, +} FuUefiUpdateInfoStatus; + +const gchar *fu_uefi_update_info_status_to_string (FuUefiUpdateInfoStatus status); + +FuUefiUpdateInfo *fu_uefi_update_info_new (void); +gboolean fu_uefi_update_info_parse (FuUefiUpdateInfo *self, + const guint8 *buf, + gsize sz, + GError **error); +guint32 fu_uefi_update_info_get_version (FuUefiUpdateInfo *self); +const gchar *fu_uefi_update_info_get_guid (FuUefiUpdateInfo *self); +const gchar *fu_uefi_update_info_get_capsule_fn (FuUefiUpdateInfo *self); +guint32 fu_uefi_update_info_get_capsule_flags (FuUefiUpdateInfo *self); +guint64 fu_uefi_update_info_get_hw_inst (FuUefiUpdateInfo *self); +FuUefiUpdateInfoStatus fu_uefi_update_info_get_status (FuUefiUpdateInfo *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-vars.c fwupd-1.2.10/plugins/uefi/fu-uefi-vars.c --- fwupd-1.0.6/plugins/uefi/fu-uefi-vars.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-vars.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fu-common.h" +#include "fu-uefi-vars.h" + +#include "fwupd-error.h" + +static gchar * +fu_uefi_vars_get_path (void) +{ + g_autofree gchar *sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + return g_build_filename (sysfsfwdir, "efi", "efivars", NULL); +} + +static gchar * +fu_uefi_vars_get_filename (const gchar *guid, const gchar *name) +{ + g_autofree gchar *efivardir = fu_uefi_vars_get_path (); + return g_strdup_printf ("%s/%s-%s", efivardir, name, guid); +} + +gboolean +fu_uefi_vars_supported (GError **error) +{ + g_autofree gchar *efivardir = fu_uefi_vars_get_path (); + if (!g_file_test (efivardir, G_FILE_TEST_IS_DIR)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "kernel efivars support missing: %s", + efivardir); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_uefi_vars_set_immutable_fd (int fd, + gboolean value, + gboolean *value_old, + GError **error) +{ + guint flags; + gboolean is_immutable; + int rc; + + /* get existing status */ + rc = ioctl (fd, FS_IOC_GETFLAGS, &flags); + if (rc < 0) { + /* check for tmpfs */ + if (errno == ENOTTY || errno == ENOSYS) { + is_immutable = FALSE; + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to get flags: %s", + strerror (errno)); + return FALSE; + } + } else { + is_immutable = (flags & FS_IMMUTABLE_FL) > 0; + } + + /* save the old value */ + if (value_old != NULL) + *value_old = is_immutable; + + /* is this already correct */ + if (value) { + if (is_immutable) + return TRUE; + flags |= FS_IMMUTABLE_FL; + } else { + if (!is_immutable) + return TRUE; + flags &= ~FS_IMMUTABLE_FL; + } + + /* set the new status */ + rc = ioctl (fd, FS_IOC_SETFLAGS, &flags); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to set flags: %s", + strerror (errno)); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_uefi_vars_set_immutable (const gchar *fn, + gboolean value, + gboolean *value_old, + GError **error) +{ + gint fd; + g_autoptr(GInputStream) istr = NULL; + + /* open file readonly */ + fd = open (fn, O_RDONLY); + if (fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + "failed to open: %s", + strerror (errno)); + return FALSE; + } + istr = g_unix_input_stream_new (fd, TRUE); + return fu_uefi_vars_set_immutable_fd (fd, value, value_old, error); +} + +gboolean +fu_uefi_vars_delete (const gchar *guid, const gchar *name, GError **error) +{ + g_autofree gchar *fn = fu_uefi_vars_get_filename (guid, name); + g_autoptr(GFile) file = g_file_new_for_path (fn); + if (!g_file_query_exists (file, NULL)) + return TRUE; + if (!fu_uefi_vars_set_immutable (fn, FALSE, NULL, error)) { + g_prefix_error (error, "failed to set %s as mutable: ", fn); + return FALSE; + } + return g_file_delete (file, NULL, error); +} + +gboolean +fu_uefi_vars_delete_with_glob (const gchar *guid, const gchar *name_glob, GError **error) +{ + const gchar *fn; + g_autofree gchar *nameguid_glob = NULL; + g_autofree gchar *efivardir = fu_uefi_vars_get_path (); + g_autoptr(GDir) dir = g_dir_open (efivardir, 0, error); + if (dir == NULL) + return FALSE; + nameguid_glob = g_strdup_printf ("%s-%s", name_glob, guid); + while ((fn = g_dir_read_name (dir)) != NULL) { + if (fnmatch (nameguid_glob, fn, 0) == 0) { + g_autofree gchar *keyfn = g_build_filename (efivardir, fn, NULL); + g_autoptr(GFile) file = g_file_new_for_path (keyfn); + if (!fu_uefi_vars_set_immutable (keyfn, FALSE, NULL, error)) { + g_prefix_error (error, "failed to set %s as mutable: ", keyfn); + return FALSE; + } + if (!g_file_delete (file, NULL, error)) + return FALSE; + } + } + return TRUE; +} + +gboolean +fu_uefi_vars_exists (const gchar *guid, const gchar *name) +{ + g_autofree gchar *fn = fu_uefi_vars_get_filename (guid, name); + return g_file_test (fn, G_FILE_TEST_EXISTS); +} + +gboolean +fu_uefi_vars_get_data (const gchar *guid, const gchar *name, guint8 **data, + gsize *data_sz, guint32 *attr, GError **error) +{ + gssize attr_sz; + gssize data_sz_tmp; + guint32 attr_tmp; + guint64 sz; + g_autofree gchar *fn = fu_uefi_vars_get_filename (guid, name); + g_autoptr(GFile) file = g_file_new_for_path (fn); + g_autoptr(GFileInfo) info = NULL; + g_autoptr(GInputStream) istr = NULL; + + /* open file as stream */ + istr = G_INPUT_STREAM (g_file_read (file, NULL, error)); + if (istr == NULL) + return FALSE; + info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (istr), + G_FILE_ATTRIBUTE_STANDARD_SIZE, + NULL, error); + if (info == NULL) { + g_prefix_error (error, "failed to get stream info: "); + return FALSE; + } + + /* get total stream size */ + sz = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE); + if (sz < 4) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "efivars file too small: %" G_GUINT64_FORMAT, sz); + return FALSE; + } + + /* read out the attributes */ + attr_sz = g_input_stream_read (istr, &attr_tmp, sizeof(attr_tmp), NULL, error); + if (attr_sz == -1) { + g_prefix_error (error, "failed to read attr: "); + return FALSE; + } + if (attr != NULL) + *attr = attr_tmp; + + /* read out the data */ + data_sz_tmp = sz - sizeof(attr_tmp); + if (data_sz != NULL) + *data_sz = data_sz_tmp; + if (data != NULL) { + g_autofree guint8 *data_tmp = g_malloc0 (data_sz_tmp); + if (!g_input_stream_read_all (istr, data_tmp, data_sz_tmp, + NULL, NULL, error)) { + g_prefix_error (error, "failed to read data: "); + return FALSE; + } + *data = g_steal_pointer (&data_tmp); + } + return TRUE; +} + +gboolean +fu_uefi_vars_set_data (const gchar *guid, const gchar *name, const guint8 *data, + gsize data_sz, guint32 attr, GError **error) +{ + int fd; + gboolean was_immutable; + g_autofree gchar *fn = fu_uefi_vars_get_filename (guid, name); + g_autofree guint8 *buf = g_malloc0 (sizeof(guint32) + data_sz); + g_autoptr(GFile) file = g_file_new_for_path (fn); + g_autoptr(GOutputStream) ostr = NULL; + + /* create empty file so we can clear the immutable bit before writing */ + if (!g_file_query_exists (file, NULL)) { + g_autoptr(GFileOutputStream) ostr_tmp = NULL; + ostr_tmp = g_file_create (file, + G_FILE_CREATE_NONE, + NULL, + error); + if (ostr_tmp == NULL) + return FALSE; + if (!g_output_stream_close (G_OUTPUT_STREAM (ostr_tmp), NULL, error)) + return FALSE; + } + if (!fu_uefi_vars_set_immutable (fn, FALSE, &was_immutable, error)) { + g_prefix_error (error, "failed to set %s as mutable: ", fn); + return FALSE; + } + + /* open file for writing */ + fd = open (fn, O_WRONLY); + if (fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "failed to open %s: %s", + fn, strerror (errno)); + return FALSE; + } + ostr = g_unix_output_stream_new (fd, TRUE); + memcpy (buf, &attr, sizeof(attr)); + memcpy (buf + sizeof(attr), data, data_sz); + if (g_output_stream_write (ostr, buf, sizeof(attr) + data_sz, NULL, error) < 0) + return FALSE; + + /* set as immutable again */ + if (was_immutable && !fu_uefi_vars_set_immutable (fn, TRUE, NULL, error)) { + g_prefix_error (error, "failed to set %s as immutable: ", fn); + return FALSE; + } + + /* success */ + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/uefi/fu-uefi-vars.h fwupd-1.2.10/plugins/uefi/fu-uefi-vars.h --- fwupd-1.0.6/plugins/uefi/fu-uefi-vars.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/fu-uefi-vars.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2015-2017 Peter Jones + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_UEFI_VARS_GUID_EFI_GLOBAL "8be4df61-93ca-11d2-aa0d-00e098032b8c" +#define FU_UEFI_VARS_GUID_FWUPDATE "0abba7dc-e516-4167-bbf5-4d9d1c739416" +#define FU_UEFI_VARS_GUID_UX_CAPSULE "3b8c8162-188c-46a4-aec9-be43f1d65697" + +#define FU_UEFI_VARS_ATTR_NON_VOLATILE (1 << 0) +#define FU_UEFI_VARS_ATTR_BOOTSERVICE_ACCESS (1 << 1) +#define FU_UEFI_VARS_ATTR_RUNTIME_ACCESS (1 << 2) +#define FU_UEFI_VARS_ATTR_HARDWARE_ERROR_RECORD (1 << 3) +#define FU_UEFI_VARS_ATTR_AUTHENTICATED_WRITE_ACCESS (1 << 4) +#define FU_UEFI_VARS_ATTR_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (5 << 0) +#define FU_UEFI_VARS_ATTR_APPEND_WRITE (1 << 6) + +gboolean fu_uefi_vars_supported (GError **error); +gboolean fu_uefi_vars_exists (const gchar *guid, + const gchar *name); +gboolean fu_uefi_vars_get_data (const gchar *guid, + const gchar *name, + guint8 **data, + gsize *data_sz, + guint32 *attr, + GError **error); +gboolean fu_uefi_vars_set_data (const gchar *guid, + const gchar *name, + const guint8 *data, + gsize sz, + guint32 attr, + GError **error); +gboolean fu_uefi_vars_delete (const gchar *guid, + const gchar *name, + GError **error); +gboolean fu_uefi_vars_delete_with_glob (const gchar *guid, + const gchar *name_glob, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/uefi/meson.build fwupd-1.2.10/plugins/uefi/meson.build --- fwupd-1.0.6/plugins/uefi/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,12 +1,29 @@ +subdir('efi') + cargs = ['-DG_LOG_DOMAIN="FuPluginUefi"'] -install_data(['uefi.conf'], - install_dir : join_paths(sysconfdir, 'fwupd') +efi_os_dir = get_option('efi_os_dir') +if efi_os_dir != '' + cargs += '-DEFI_OS_DIR="' + efi_os_dir + '"' +endif + +install_data(['uefi.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') ) shared_module('fu_plugin_uefi', + fu_hash, sources : [ 'fu-plugin-uefi.c', + 'fu-uefi-bgrt.c', + 'fu-ucs2.c', + 'fu-uefi-bootmgr.c', + 'fu-uefi-common.c', + 'fu-uefi-device.c', + 'fu-uefi-devpath.c', + 'fu-uefi-pcrs.c', + 'fu-uefi-update-info.c', + 'fu-uefi-vars.c', ], include_directories : [ include_directories('../..'), @@ -15,9 +32,90 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, - fwup, + efivar, + efiboot, + ], +) + +executable( + 'fwupdate', + resources_src, + fu_hash, + sources : [ + 'fu-uefi-tool.c', + 'fu-uefi-bgrt.c', + 'fu-ucs2.c', + 'fu-uefi-bootmgr.c', + 'fu-uefi-common.c', + 'fu-uefi-device.c', + 'fu-uefi-devpath.c', + 'fu-uefi-pcrs.c', + 'fu-uefi-update-info.c', + 'fu-uefi-vars.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + dependencies : [ + libxmlb, + giounix, + gusb, + gudev, + efivar, + efiboot, + ], + link_with : [ + libfwupdprivate, ], + install : true, + install_dir : join_paths(libexecdir, 'fwupd'), + c_args : cargs, ) + +install_data(['uefi.conf'], + install_dir: join_paths(sysconfdir, 'fwupd') +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'uefi-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-uefi-bgrt.c', + 'fu-uefi-bootmgr.c', + 'fu-uefi-common.c', + 'fu-uefi-device.c', + 'fu-uefi-devpath.c', + 'fu-uefi-pcrs.c', + 'fu-uefi-update-info.c', + 'fu-uefi-vars.c', + 'fu-ucs2.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + dependencies : [ + plugin_deps, + efivar, + efiboot, + ], + link_with : [ + libfwupdprivate, + ], + c_args : cargs + ) + test('uefi-self-test', e) +endif diff -Nru fwupd-1.0.6/plugins/uefi/README.md fwupd-1.2.10/plugins/uefi/README.md --- fwupd-1.0.6/plugins/uefi/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -8,38 +8,46 @@ defines the software interface between an OS and platform firmware. With the UpdateCapsule boot service it can be used to update system firmware. -Build Requirements ------------------- +If you don't want or need this functionality you can use the +`-Dplugin_uefi=false` option. -For UEFI capsule support, you need to install fwupdate 0.5 or later. -* source: https://github.com/rhinstaller/fwupdate -* rpms: https://pjones.fedorapeople.org/fwupdate/ -* debs (Debian): https://tracker.debian.org/pkg/fwupdate -* debs (Ubuntu): https://launchpad.net/ubuntu/+source/fwupdate +Firmware Format +--------------- -If you don't want or need this functionality you can use the -`--disable-uefi` option. +The daemon will decompress the cabinet archive and extract a firmware blob in +EFI capsule file format. + +See https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf +for details. + +This plugin supports the following protocol ID: + + * org.uefi.capsule + +GUID Generation +--------------- + +These devices use the UEFI GUID as provided in the ESRT. Additionally, for the +system device the `main-system-firmware` GUID is also added. + +For compatibility with Windows 10, the plugin also adds GUIDs of the form +`UEFI\RES_{$(esrt)}`. UEFI Unlock Support ------------------- On some Dell systems it is possible to turn on and off UEFI capsule support from within the BIOS. This functionality can also be adjusted -from within the OS by fwupd. This requires using fwupdate 5 or later -and compiling it with libsmbios support. - -When fwupd and fwupdate have been compiled with this support you will -be able to enable UEFI support on the device by using the `unlock` command. +from within the OS by fwupd. This requires compiling with libsmbios support. -Custom EFI System Partition location ---------------------- -`fwupdate` 10 and later allow using an EFI system partition location -at runtime that is different than the location compiled into the library. +When fwupd has been compiled with this support you will be able to enable UEFI +support on the device by using the `unlock` command. -fwupd 1.0.6 and later can take advantage of this feature by allowing -users to modify `/etc/fwupd/uefi.conf`. +Custom EFI System Partition +--------------------------- -An option titled *OverrideESPMountPoint* is available that can be -uncommented and set to any valid directory on the system. +Since version 1.1.0 fwupd will autodetect the ESP when it is mounted on +`/boot/efi`, `/boot`, or `/efi`. A custom EFI system partition location can be +used by modifying *OverrideESPMountPoint* in `/etc/fwupd/uefi.conf`. Setting an invalid directory will disable the fwupd plugin. Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/image and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/image differ diff -Nru fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/status fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/status --- fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/type fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/type --- fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/version fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/version --- fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/xoffset fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/xoffset --- fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/xoffset 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/xoffset 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +123 diff -Nru fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/yoffset fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/yoffset --- fwupd-1.0.6/plugins/uefi/tests/acpi/bgrt/yoffset 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/acpi/bgrt/yoffset 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +456 Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/uefi/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/uefi/tests/efi/efivars/fwupd-ddc0ee61-e7f0-4e7d-acc5-c070a398838e-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 differ diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c fwupd-1.2.10/plugins/uefi/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c --- fwupd-1.0.6/plugins/uefi/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 \ No newline at end of file diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/capsule_flags 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0xfe diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/fw_class 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +ddc0ee61-e7f0-4e7d-acc5-c070a398838e diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/fw_type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +65586 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/last_attempt_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +18472960 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry0/lowest_supported_fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +65582 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/capsule_flags 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/fw_class 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +671d19d0-d43c-4852-98d9-1ce16f9967e4 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/fw_type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/last_attempt_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry1/lowest_supported_fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/capsule_flags 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0x8010 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/fw_class 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +00000000-0000-0000-0000-000000000000 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/fw_type 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +2 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +3090287969 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_status 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/last_attempt_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +0 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version --- fwupd-1.0.6/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/esrt/entries/entry2/lowest_supported_fw_version 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi/fw_platform_size fwupd-1.2.10/plugins/uefi/tests/efi/fw_platform_size --- fwupd-1.0.6/plugins/uefi/tests/efi/fw_platform_size 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi/fw_platform_size 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +64 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height fwupd-1.2.10/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height --- fwupd-1.0.6/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/height 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +789 diff -Nru fwupd-1.0.6/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width fwupd-1.2.10/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width --- fwupd-1.0.6/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/efi-framebuffer/efi-framebuffer.0/width 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +456 diff -Nru fwupd-1.0.6/plugins/uefi/tests/.gitignore fwupd-1.2.10/plugins/uefi/tests/.gitignore --- fwupd-1.0.6/plugins/uefi/tests/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/.gitignore 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +EFI +efi/efivars/fwupd-c34cb672-a81e-5d32-9d89-cbcabe8ec37b-0-0abba7dc-e516-4167-bbf5-4d9d1c739416 Binary files /tmp/tmpQQbJCR/7rYBbtNFzp/fwupd-1.0.6/plugins/uefi/tests/test.bmp and /tmp/tmpQQbJCR/GMbZcPqOnn/fwupd-1.2.10/plugins/uefi/tests/test.bmp differ diff -Nru fwupd-1.0.6/plugins/uefi/tests/tpm0/active fwupd-1.2.10/plugins/uefi/tests/tpm0/active --- fwupd-1.0.6/plugins/uefi/tests/tpm0/active 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/tpm0/active 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/tpm0/caps fwupd-1.2.10/plugins/uefi/tests/tpm0/caps --- fwupd-1.0.6/plugins/uefi/tests/tpm0/caps 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/tpm0/caps 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,3 @@ +Manufacturer: 0x49465800 +TCG version: 1.2 +Firmware version: 6.40 diff -Nru fwupd-1.0.6/plugins/uefi/tests/tpm0/enabled fwupd-1.2.10/plugins/uefi/tests/tpm0/enabled --- fwupd-1.0.6/plugins/uefi/tests/tpm0/enabled 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/tpm0/enabled 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/tpm0/owned fwupd-1.2.10/plugins/uefi/tests/tpm0/owned --- fwupd-1.0.6/plugins/uefi/tests/tpm0/owned 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/tpm0/owned 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +1 diff -Nru fwupd-1.0.6/plugins/uefi/tests/tpm0/pcrs fwupd-1.2.10/plugins/uefi/tests/tpm0/pcrs --- fwupd-1.0.6/plugins/uefi/tests/tpm0/pcrs 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/tests/tpm0/pcrs 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,24 @@ +PCR-00: 3C 97 99 20 C9 00 99 60 09 27 D5 DA B3 81 EB 95 1E 7F C8 68 +PCR-01: CE 9F A4 B2 01 09 D8 81 14 EA 1A 6D 13 94 CD 45 5F 52 69 23 +PCR-02: 47 09 7A 9A AD C3 26 A4 93 91 26 63 A1 6F DF 53 D7 88 96 8E +PCR-03: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-04: A4 A5 87 4C 59 94 8D 9B 93 66 0A F4 19 D8 6F F8 94 36 20 CC +PCR-05: 00 0B 58 00 89 72 EF 6C 2A AC 79 33 C4 AE 67 6B A6 EF CF 6A +PCR-06: B2 A8 3B 0E BF 2F 83 74 29 9A 5B 2B DF C3 1E A9 55 AD 72 36 +PCR-07: 0A 2A 68 15 85 0D AC B2 D1 F4 E0 C1 F4 56 D5 E2 81 08 6D EA +PCR-08: DB A7 29 4E 49 BA D7 9E 53 99 0A 6E 3A CB 52 97 B9 08 3A 66 +PCR-09: 19 F9 6F 10 83 F5 5B 50 98 26 C3 14 73 43 35 21 1F E6 39 E9 +PCR-10: 37 3D 89 9E 10 0D DD 2D 21 B5 F4 96 8D 4F DC A7 6D 1A C7 BD +PCR-11: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-12: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-13: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-14: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-15: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +PCR-17: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-18: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-19: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-20: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-21: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-22: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF +PCR-23: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 diff -Nru fwupd-1.0.6/plugins/uefi/uefi.conf fwupd-1.2.10/plugins/uefi/uefi.conf --- fwupd-1.0.6/plugins/uefi/uefi.conf 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/uefi.conf 2019-07-15 18:25:54.000000000 +0000 @@ -1,5 +1,12 @@ [uefi] -# For fwupdate 10+ allow overriding -# the compiled EFI system partition path +# the shim loader is required to chainload the fwupd EFI binary unless +# the fwupd.efi file has been self-signed manually +RequireShimForSecureBoot=true + +# the EFI system partition path used +# if this is is not /boot/efi, /boot, or /efi #OverrideESPMountPoint= + +# amount of free space required on the ESP, for example using 0x2000000 for 32Mb +#RequireESPFreeSpace= diff -Nru fwupd-1.0.6/plugins/uefi/uefi.quirk fwupd-1.2.10/plugins/uefi/uefi.quirk --- fwupd-1.0.6/plugins/uefi/uefi.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/uefi/uefi.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,22 @@ +# Lenovo ThinkStation P920/P720 +[Guid=cc850e7a-6713-4fe3-8144-321a9e485ae0] +VersionFormat = intel-me +Name = Intel Management Engine + +# Lenovo ThinkStation P520/P520c +[Guid=e3af51e5-5afb-4b48-b5cb-13bf26becaab] +VersionFormat = intel-me +Name = Intel Management Engine + +# Lenovo ThinkStation P330/P330 Tiny & ThinkCentre M920X/M920q +[Guid=5b92717b-2cad-4a96-a13b-9d65781df8bf] +VersionFormat = intel-me2 +Name = Intel Management Engine + +# Star Labs LabTop (Mk III) +[Guid=8265d473-a6c2-42b4-897b-bc220faa2d32] +Flags = use-shim-unique + +# Star Labs Lite (Mk II) +[Guid=797f8bae-0ea2-4c0f-8a30-7d10ccfacbc0] +Flags = use-shim-unique,no-ux-capsule diff -Nru fwupd-1.0.6/plugins/unifying/fu-plugin-unifying.c fwupd-1.2.10/plugins/unifying/fu-plugin-unifying.c --- fwupd-1.0.6/plugins/unifying/fu-plugin-unifying.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-plugin-unifying.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,232 +1,172 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2016-2018 Richard Hughes * - * Copyright (C) 2016 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include #include -#include -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" -#include "lu-context.h" -#include "lu-device.h" -#include "lu-device-peripheral.h" - -struct FuPluginData { - LuContext *ctx; -}; +#include "fu-unifying-bootloader-nordic.h" +#include "fu-unifying-bootloader-texas.h" +#include "fu-unifying-common.h" +#include "fu-unifying-peripheral.h" +#include "fu-unifying-runtime.h" -static gboolean -fu_plugin_unifying_device_added (FuPlugin *plugin, - LuDevice *device, - GError **error) +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) { - g_autoptr(AsProfile) profile = as_profile_new (); - g_autoptr(AsProfileTask) ptask = NULL; - - /* profile */ - ptask = as_profile_start (profile, "FuPluginLu:added{%s}", - fu_device_get_platform_id (FU_DEVICE (device))); - g_assert (ptask != NULL); - - /* open the device */ - if (!lu_device_open (device, error)) + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) return FALSE; - - /* insert to hash */ - fu_plugin_device_add (plugin, FU_DEVICE (device)); - return TRUE; + return fu_device_detach (device, error); } -static gboolean -fu_plugin_unifying_detach_cb (gpointer user_data) +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) { - LuDevice *device = LU_DEVICE (user_data); - g_autoptr(GError) error = NULL; - - /* ditch this device */ - g_debug ("detaching"); - if (!lu_device_detach (device, &error)) { - g_warning ("failed to detach: %s", error->message); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) return FALSE; - } - - return FALSE; + return fu_device_attach (device, error); } -static gboolean -fu_plugin_unifying_attach_cb (gpointer user_data) +gboolean +fu_plugin_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) { - LuDevice *device = LU_DEVICE (user_data); - g_autoptr(GError) error = NULL; - - /* ditch this device */ - g_debug ("attaching"); - if (!lu_device_attach (device, &error)) { - g_warning ("failed to detach: %s", error->message); + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) return FALSE; - } - - return FALSE; + return TRUE; } gboolean -fu_plugin_update_detach (FuPlugin *plugin, FuDevice *dev, GError **error) +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - LuDevice *device = LU_DEVICE (dev); - - /* get device */ - if (!lu_device_open (device, error)) + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} - /* switch to bootloader if required */ - if (!lu_device_has_flag (device, LU_DEVICE_FLAG_REQUIRES_DETACH)) - return TRUE; - - /* wait for device to come back */ - fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); - if (lu_device_has_flag (device, LU_DEVICE_FLAG_DETACH_WILL_REPLUG)) { - g_debug ("doing detach in idle"); - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - fu_plugin_unifying_detach_cb, - g_object_ref (device), - (GDestroyNotify) g_object_unref); - if (!lu_context_wait_for_replug (data->ctx, - device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) - return FALSE; - } else { - g_debug ("doing detach in main thread"); - if (!lu_device_detach (device, error)) - return FALSE; +static gboolean +fu_plugin_unifying_check_supported_device (FuPlugin *plugin, FuDevice *device) +{ + GPtrArray *guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + if (fu_plugin_check_supported (plugin, guid)) + return TRUE; } - return TRUE; + return FALSE; } gboolean -fu_plugin_update_attach (FuPlugin *plugin, FuDevice *dev, GError **error) +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - LuDevice *device = LU_DEVICE (dev); + g_autoptr(FuDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; - /* get device */ - if (!lu_device_open (device, error)) - return FALSE; + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0) + return TRUE; - /* wait for it to appear back in runtime mode if required */ - if (!lu_device_has_flag (device, LU_DEVICE_FLAG_REQUIRES_ATTACH)) + /* logitech */ + if (fu_udev_device_get_vendor (device) != FU_UNIFYING_DEVICE_VID) return TRUE; - /* wait for device to come back */ - fu_device_set_status (dev, FWUPD_STATUS_DEVICE_RESTART); - if (lu_device_has_flag (device, LU_DEVICE_FLAG_ATTACH_WILL_REPLUG)) { - g_debug ("doing attach in idle"); - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - fu_plugin_unifying_attach_cb, - g_object_ref (device), - (GDestroyNotify) g_object_unref); - if (!lu_context_wait_for_replug (data->ctx, - device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) - return FALSE; + /* runtime */ + if (fu_device_has_custom_flag (FU_DEVICE (device), "is-receiver")) { + dev = g_object_new (FU_TYPE_UNIFYING_RUNTIME, + "version-format", FWUPD_VERSION_FORMAT_PLAIN, + NULL); + fu_device_incorporate (dev, FU_DEVICE (device)); } else { - g_debug ("doing attach in main thread"); - if (!lu_device_attach (device, error)) + + /* create device so we can run ->probe() and add UFY GUIDs */ + dev = g_object_new (FU_TYPE_UNIFYING_PERIPHERAL, + "version-format", FWUPD_VERSION_FORMAT_PLAIN, + NULL); + fu_device_incorporate (dev, FU_DEVICE (device)); + if (!fu_device_probe (dev, error)) return FALSE; - } - return TRUE; -} -gboolean -fu_plugin_update_reload (FuPlugin *plugin, FuDevice *dev, GError **error) -{ - LuDevice *device = LU_DEVICE (dev); + /* there are a lot of unifying peripherals, but not all respond + * well to opening -- so limit to ones with issued updates */ + if (!fu_plugin_unifying_check_supported_device (plugin, dev)) { + g_autofree gchar *guids = fu_device_get_guids_as_str (FU_DEVICE (device)); + g_debug ("%s has no updates, so ignoring device", guids); + return TRUE; + } + } - /* get device */ - if (!lu_device_open (device, error)) + /* open to get the version */ + locker = fu_device_locker_new (dev, error); + if (locker == NULL) return FALSE; + fu_plugin_device_add (plugin, dev); return TRUE; } gboolean -fu_plugin_update (FuPlugin *plugin, - FuDevice *dev, - GBytes *blob_fw, - FwupdInstallFlags flags, - GError **error) +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { - LuDevice *device = LU_DEVICE (dev); + g_autoptr(FuDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; - /* get version */ - if (!lu_device_open (device, error)) - return FALSE; - - /* write the firmware */ - fu_device_set_status (dev, FWUPD_STATUS_DEVICE_WRITE); - if (!lu_device_write_firmware (device, blob_fw, error)) - return FALSE; - - /* success */ - return TRUE; -} + /* logitech */ + if (fu_usb_device_get_vid (device) != FU_UNIFYING_DEVICE_VID) + return TRUE; -static void -fu_plugin_unifying_device_added_cb (LuContext *ctx, - LuDevice *device, - FuPlugin *plugin) -{ - g_autoptr(GError) error = NULL; + /* check is bootloader */ + if (!fu_device_has_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + g_debug ("not in bootloader mode, ignoring"); + return TRUE; + } + if (fu_device_has_custom_flag (FU_DEVICE (device), "is-nordic")) { + dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_NORDIC, + "version-format", FWUPD_VERSION_FORMAT_PLAIN, + NULL); + fu_device_incorporate (dev, FU_DEVICE (device)); + } else if (fu_device_has_custom_flag (FU_DEVICE (device), "is-texas")) { + dev = g_object_new (FU_TYPE_UNIFYING_BOOTLOADER_TEXAS, + "version-format", FWUPD_VERSION_FORMAT_PLAIN, + NULL); + fu_device_incorporate (dev, FU_DEVICE (device)); + g_usleep (200*1000); + } - /* add */ - if (!fu_plugin_unifying_device_added (plugin, device, &error)) { - if (g_error_matches (error, + /* not supported */ + if (dev == NULL) { + g_set_error_literal (error, FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED)) { - g_debug ("Failed to add Logitech device: %s", - error->message); - } else { - g_warning ("Failed to add Logitech device: %s", - error->message); - } + FWUPD_ERROR_NOT_SUPPORTED, + "bootloader device not supported"); + return FALSE; } -} -static void -fu_plugin_unifying_device_removed_cb (LuContext *ctx, - LuDevice *device, - FuPlugin *plugin) -{ - fu_plugin_device_remove (plugin, FU_DEVICE (device)); + /* open to get the version */ + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, dev); + return TRUE; } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { - FuPluginData *data = fu_plugin_get_data (plugin); - /* check the kernel has CONFIG_HIDRAW */ if (!g_file_test ("/sys/class/hidraw", G_FILE_TEST_IS_DIR)) { g_set_error_literal (error, @@ -235,39 +175,15 @@ "no kernel support for CONFIG_HIDRAW"); return FALSE; } - - /* coldplug */ - g_signal_connect (data->ctx, "added", - G_CALLBACK (fu_plugin_unifying_device_added_cb), - plugin); - g_signal_connect (data->ctx, "removed", - G_CALLBACK (fu_plugin_unifying_device_removed_cb), - plugin); - lu_context_set_supported (data->ctx, fu_plugin_get_supported (plugin)); - return TRUE; -} - - -gboolean -fu_plugin_coldplug (FuPlugin *plugin, GError **error) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - lu_context_coldplug (data->ctx); - lu_context_set_poll_interval (data->ctx, 5000); return TRUE; } void fu_plugin_init (FuPlugin *plugin) { - FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); - GUsbContext *usb_ctx = fu_plugin_get_usb_context (plugin); - data->ctx = lu_context_new_full (usb_ctx); -} - -void -fu_plugin_destroy (FuPlugin *plugin) -{ - FuPluginData *data = fu_plugin_get_data (plugin); - g_object_unref (data->ctx); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifying"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.logitech.unifyingsigned"); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); } diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader.c fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-unifying-common.h" +#include "fu-unifying-bootloader.h" +#include "fu-unifying-hidpp.h" + +typedef struct +{ + guint16 flash_addr_lo; + guint16 flash_addr_hi; + guint16 flash_blocksize; +} FuUnifyingBootloaderPrivate; + +#define FU_UNIFYING_DEVICE_EP1 0x81 +#define FU_UNIFYING_DEVICE_EP3 0x83 + +G_DEFINE_TYPE_WITH_PRIVATE (FuUnifyingBootloader, fu_unifying_bootloader, FU_TYPE_USB_DEVICE) + +#define GET_PRIVATE(o) (fu_unifying_bootloader_get_instance_private (o)) + +static void +fu_unifying_bootloader_to_string (FuDevice *device, GString *str) +{ + FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); + FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self); + g_string_append_printf (str, " FlashAddrHigh:\t0x%04x\n", + priv->flash_addr_hi); + g_string_append_printf (str, " FlashAddrLow:\t0x%04x\n", + priv->flash_addr_lo); + g_string_append_printf (str, " FlashBlockSize:\t0x%04x\n", + priv->flash_blocksize); +} + +FuUnifyingBootloaderRequest * +fu_unifying_bootloader_request_new (void) +{ + FuUnifyingBootloaderRequest *req = g_new0 (FuUnifyingBootloaderRequest, 1); + return req; +} + +GPtrArray * +fu_unifying_bootloader_parse_requests (FuUnifyingBootloader *self, GBytes *fw, GError **error) +{ + const gchar *tmp; + g_auto(GStrv) lines = NULL; + g_autoptr(GPtrArray) reqs = NULL; + guint32 last_addr = 0; + + reqs = g_ptr_array_new_with_free_func (g_free); + tmp = g_bytes_get_data (fw, NULL); + lines = g_strsplit_set (tmp, "\n\r", -1); + for (guint i = 0; lines[i] != NULL; i++) { + g_autoptr(FuUnifyingBootloaderRequest) payload = NULL; + guint8 rec_type = 0x00; + + /* skip empty lines */ + tmp = lines[i]; + if (strlen (tmp) < 5) + continue; + + payload = fu_unifying_bootloader_request_new (); + payload->len = fu_unifying_buffer_read_uint8 (tmp + 0x01); + if (payload->len > 28) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware data invalid: too large %u bytes", + payload->len); + return NULL; + } + payload->addr = ((guint16) fu_unifying_buffer_read_uint8 (tmp + 0x03)) << 8; + payload->addr |= fu_unifying_buffer_read_uint8 (tmp + 0x05); + + rec_type = fu_unifying_buffer_read_uint8 (tmp + 0x07); + + /* record type of 0xFD indicates signature data */ + if (rec_type == 0xFD) { + payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE; + } else { + payload->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER; + } + + /* read the data, but skip the checksum byte */ + for (guint j = 0; j < payload->len; j++) { + const gchar *ptr = tmp + 0x09 + (j * 2); + if (ptr[0] == '\0') { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware data invalid: expected %u bytes", + payload->len); + return NULL; + } + payload->data[j] = fu_unifying_buffer_read_uint8 (ptr); + } + + /* no need to bound check signature addresses */ + if (payload->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) { + g_ptr_array_add (reqs, g_steal_pointer (&payload)); + continue; + } + + /* skip the bootloader */ + if (payload->addr > fu_unifying_bootloader_get_addr_hi (self)) { + g_debug ("skipping write @ %04x", payload->addr); + continue; + } + + /* skip the header */ + if (payload->addr < fu_unifying_bootloader_get_addr_lo (self)) { + g_debug ("skipping write @ %04x", payload->addr); + continue; + } + + /* make sure firmware addresses only go up */ + if (payload->addr < last_addr) { + g_debug ("skipping write @ %04x", payload->addr); + continue; + } + last_addr = payload->addr; + + /* pending */ + g_ptr_array_add (reqs, g_steal_pointer (&payload)); + } + if (reqs->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "firmware data invalid: no payloads found"); + return NULL; + } + return g_steal_pointer (&reqs); +} + +guint16 +fu_unifying_bootloader_get_addr_lo (FuUnifyingBootloader *self) +{ + FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000); + return priv->flash_addr_lo; +} + +guint16 +fu_unifying_bootloader_get_addr_hi (FuUnifyingBootloader *self) +{ + FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000); + return priv->flash_addr_hi; +} + +guint16 +fu_unifying_bootloader_get_blocksize (FuUnifyingBootloader *self) +{ + FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UNIFYING_BOOTLOADER (self), 0x0000); + return priv->flash_blocksize; +} + +static gboolean +fu_unifying_bootloader_attach (FuDevice *device, GError **error) +{ + FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_REBOOT; + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to attach back to runtime: "); + return FALSE; + } + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static gboolean +fu_unifying_bootloader_set_bl_version (FuUnifyingBootloader *self, GError **error) +{ + guint16 build; + g_autofree gchar *version = NULL; + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + + /* call into hardware */ + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_BL_VERSION; + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to get firmware version: "); + return FALSE; + } + + /* BOTxx.yy_Bzzzz + * 012345678901234 */ + build = (guint16) fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 10) << 8; + build += fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 12); + version = fu_unifying_format_version ("BOT", + fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 3), + fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 6), + build); + if (version == NULL) { + g_prefix_error (error, "failed to format firmware version: "); + return FALSE; + } + fu_device_set_version_bootloader (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_unifying_bootloader_open (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + const guint idx = 0x00; + + /* claim the only interface */ + if (!g_usb_device_claim_interface (usb_device, idx, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "Failed to claim 0x%02x: ", idx); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_unifying_bootloader_setup (FuDevice *device, GError **error) +{ + FuUnifyingBootloaderClass *klass = FU_UNIFYING_BOOTLOADER_GET_CLASS (device); + FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); + FuUnifyingBootloaderPrivate *priv = GET_PRIVATE (self); + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + + /* get memory map */ + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO; + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to get meminfo: "); + return FALSE; + } + if (req->len != 0x06) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to get meminfo: invalid size %02x", + req->len); + return FALSE; + } + + /* parse values */ + priv->flash_addr_lo = fu_common_read_uint16 (req->data + 0, G_BIG_ENDIAN); + priv->flash_addr_hi = fu_common_read_uint16 (req->data + 2, G_BIG_ENDIAN); + priv->flash_blocksize = fu_common_read_uint16 (req->data + 4, G_BIG_ENDIAN); + + /* get bootloader version */ + if (!fu_unifying_bootloader_set_bl_version (self, error)) + return FALSE; + + /* subclassed further */ + if (klass->setup != NULL) + return klass->setup (self, error); + + /* success */ + return TRUE; +} + +static gboolean +fu_unifying_bootloader_close (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + if (usb_device != NULL) { + if (!g_usb_device_release_interface (usb_device, 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + return FALSE; + } + } + return TRUE; +} + +gboolean +fu_unifying_bootloader_request (FuUnifyingBootloader *self, + FuUnifyingBootloaderRequest *req, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize actual_length = 0; + guint8 buf_request[32]; + guint8 buf_response[32]; + + /* build packet */ + memset (buf_request, 0x00, sizeof (buf_request)); + buf_request[0x00] = req->cmd; + buf_request[0x01] = req->addr >> 8; + buf_request[0x02] = req->addr & 0xff; + buf_request[0x03] = req->len; + memcpy (buf_request + 0x04, req->data, 28); + + /* send request */ + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", + buf_request, sizeof (buf_request)); + } + if (usb_device != NULL) { + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_SET, + 0x0200, 0x0000, + buf_request, + sizeof (buf_request), + &actual_length, + FU_UNIFYING_DEVICE_TIMEOUT_MS, + NULL, + error)) { + g_prefix_error (error, "failed to send data: "); + return FALSE; + } + } + + /* no response required when rebooting */ + if (usb_device != NULL && + req->cmd == FU_UNIFYING_BOOTLOADER_CMD_REBOOT) { + g_autoptr(GError) error_ignore = NULL; + if (!g_usb_device_interrupt_transfer (usb_device, + FU_UNIFYING_DEVICE_EP1, + buf_response, + sizeof (buf_response), + &actual_length, + FU_UNIFYING_DEVICE_TIMEOUT_MS, + NULL, + &error_ignore)) { + g_debug ("ignoring: %s", error_ignore->message); + } else { + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", + buf_response, actual_length); + } + } + return TRUE; + } + + /* get response */ + memset (buf_response, 0x00, sizeof (buf_response)); + if (usb_device != NULL) { + if (!g_usb_device_interrupt_transfer (usb_device, + FU_UNIFYING_DEVICE_EP1, + buf_response, + sizeof (buf_response), + &actual_length, + FU_UNIFYING_DEVICE_TIMEOUT_MS, + NULL, + error)) { + g_prefix_error (error, "failed to get data: "); + return FALSE; + } + } else { + /* emulated */ + buf_response[0] = buf_request[0]; + if (buf_response[0] == FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO) { + buf_response[3] = 0x06; /* len */ + buf_response[4] = 0x40; /* lo MSB */ + buf_response[5] = 0x00; /* lo LSB */ + buf_response[6] = 0x6b; /* hi MSB */ + buf_response[7] = 0xff; /* hi LSB */ + buf_response[8] = 0x00; /* bs MSB */ + buf_response[9] = 0x80; /* bs LSB */ + } + actual_length = sizeof (buf_response); + } + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", + buf_response, actual_length); + } + + /* parse response */ + if ((buf_response[0x00] & 0xf0) != req->cmd) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "invalid command response of %02x, expected %02x", + buf_response[0x00], req->cmd); + return FALSE; + } + req->cmd = buf_response[0x00]; + req->addr = ((guint16) buf_response[0x01] << 8) + buf_response[0x02]; + req->len = buf_response[0x03]; + if (req->len > 28) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "invalid data size of %02x", req->len); + return FALSE; + } + memset (req->data, 0x00, 28); + if (req->len > 0) + memcpy (req->data, buf_response + 0x04, req->len); + return TRUE; +} + +static void +fu_unifying_bootloader_init (FuUnifyingBootloader *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard"); + fu_device_set_name (FU_DEVICE (self), "Unifying Receiver"); + fu_device_set_summary (FU_DEVICE (self), "A miniaturised USB wireless receiver (bootloader)"); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} + +static void +fu_unifying_bootloader_class_init (FuUnifyingBootloaderClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + klass_device->to_string = fu_unifying_bootloader_to_string; + klass_device->attach = fu_unifying_bootloader_attach; + klass_device->setup = fu_unifying_bootloader_setup; + klass_usb_device->open = fu_unifying_bootloader_open; + klass_usb_device->close = fu_unifying_bootloader_close; +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader.h fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-usb-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UNIFYING_BOOTLOADER (fu_unifying_bootloader_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuUnifyingBootloader, fu_unifying_bootloader, FU, UNIFYING_BOOTLOADER, FuUsbDevice) + +struct _FuUnifyingBootloaderClass +{ + FuUsbDeviceClass parent_class; + gboolean (*setup) (FuUnifyingBootloader *self, + GError **error); +}; + +typedef enum { + FU_UNIFYING_BOOTLOADER_CMD_GENERAL_ERROR = 0x01, + FU_UNIFYING_BOOTLOADER_CMD_READ = 0x10, + FU_UNIFYING_BOOTLOADER_CMD_WRITE = 0x20, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_ADDR = 0x21, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_VERIFY_FAIL = 0x22, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_NONZERO_START = 0x23, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_CRC = 0x24, + FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE = 0x30, + FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR = 0x31, + FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START = 0x33, + FU_UNIFYING_BOOTLOADER_CMD_GET_HW_PLATFORM_ID = 0x40, + FU_UNIFYING_BOOTLOADER_CMD_GET_FW_VERSION = 0x50, + FU_UNIFYING_BOOTLOADER_CMD_GET_CHECKSUM = 0x60, + FU_UNIFYING_BOOTLOADER_CMD_REBOOT = 0x70, + FU_UNIFYING_BOOTLOADER_CMD_GET_MEMINFO = 0x80, + FU_UNIFYING_BOOTLOADER_CMD_GET_BL_VERSION = 0x90, + FU_UNIFYING_BOOTLOADER_CMD_GET_INIT_FW_VERSION = 0xa0, + FU_UNIFYING_BOOTLOADER_CMD_READ_SIGNATURE = 0xb0, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER = 0xc0, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR= 0xc1, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW = 0xc2, + FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM = 0xd0, + FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR = 0xd1, + FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC = 0xd2, + FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID = 0xd3, + FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER = 0xd4, + FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE = 0xe0, + FU_UNIFYING_BOOTLOADER_CMD_LAST +} FuUnifyingBootloaderCmd; + +/* packet to and from device */ +typedef struct __attribute__((packed)) { + guint8 cmd; + guint16 addr; + guint8 len; + guint8 data[28]; +} FuUnifyingBootloaderRequest; + +FuUnifyingBootloaderRequest *fu_unifying_bootloader_request_new (void); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUnifyingBootloaderRequest, g_free); +#pragma clang diagnostic pop + +GPtrArray *fu_unifying_bootloader_parse_requests (FuUnifyingBootloader *self, + GBytes *fw, + GError **error); +gboolean fu_unifying_bootloader_request (FuUnifyingBootloader *self, + FuUnifyingBootloaderRequest *req, + GError **error); + +guint16 fu_unifying_bootloader_get_addr_lo (FuUnifyingBootloader *self); +guint16 fu_unifying_bootloader_get_addr_hi (FuUnifyingBootloader *self); +guint16 fu_unifying_bootloader_get_blocksize (FuUnifyingBootloader *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-nordic.c fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-nordic.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-nordic.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-nordic.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-unifying-common.h" +#include "fu-unifying-bootloader-nordic.h" + +struct _FuUnifyingBootloaderNordic +{ + FuUnifyingBootloader parent_instance; +}; + +G_DEFINE_TYPE (FuUnifyingBootloaderNordic, fu_unifying_bootloader_nordic, FU_TYPE_UNIFYING_BOOTLOADER) + +static gchar * +fu_unifying_bootloader_nordic_get_hw_platform_id (FuUnifyingBootloader *self, GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_HW_PLATFORM_ID; + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to get HW ID: "); + return NULL; + } + return g_strndup ((const gchar *) req->data, req->len); +} + +static gchar * +fu_unifying_bootloader_nordic_get_fw_version (FuUnifyingBootloader *self, GError **error) +{ + guint16 micro; + + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_GET_FW_VERSION; + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to get firmware version: "); + return NULL; + } + + /* RRRxx.yy_Bzzzz + * 012345678901234*/ + micro = (guint16) fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 10) << 8; + micro += fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 12); + return fu_unifying_format_version ("RQR", + fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 3), + fu_unifying_buffer_read_uint8 ((const gchar *) req->data + 6), + micro); +} + +static gboolean +fu_unifying_bootloader_nordic_setup (FuUnifyingBootloader *self, GError **error) +{ + g_autofree gchar *hw_platform_id = NULL; + g_autofree gchar *version_fw = NULL; + g_autoptr(GError) error_local = NULL; + + /* get MCU */ + hw_platform_id = fu_unifying_bootloader_nordic_get_hw_platform_id (self, error); + if (hw_platform_id == NULL) + return FALSE; + g_debug ("hw-platform-id=%s", hw_platform_id); + + /* get firmware version, which is not fatal */ + version_fw = fu_unifying_bootloader_nordic_get_fw_version (self, &error_local); + if (version_fw == NULL) { + g_warning ("failed to get firmware version: %s", + error_local->message); + fu_device_set_version (FU_DEVICE (self), "RQR12.00_B0000", + FWUPD_VERSION_FORMAT_PLAIN); + } else { + fu_device_set_version (FU_DEVICE (self), version_fw, + FWUPD_VERSION_FORMAT_PLAIN); + } + + return TRUE; +} + +static gboolean +fu_unifying_bootloader_nordic_write_signature (FuUnifyingBootloader *self, + guint16 addr, guint8 len, const guint8 *data, + GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new(); + req->cmd = 0xC0; + req->addr = addr; + req->len = len; + memcpy (req->data, data, req->len); + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to write sig @0x%02x: ", addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: signature is too big", + addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_nordic_write (FuUnifyingBootloader *self, + guint16 addr, guint8 len, const guint8 *data, + GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_WRITE; + req->addr = addr; + req->len = len; + if (req->len > 28) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: data length too large %02x", + addr, req->len); + return FALSE; + } + memcpy (req->data, data, req->len); + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to transfer fw @0x%02x: ", addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_ADDR) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: invalid address", + addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_VERIFY_FAIL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: failed to verify flash content", + addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_NONZERO_START) { + g_debug ("wrote %d bytes at address %04x, value %02x", req->len, + req->addr, req->data[0]); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: only 1 byte write of 0xff supported", + addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_INVALID_CRC) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write @%04x: invalid CRC", + addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_nordic_erase (FuUnifyingBootloader *self, guint16 addr, GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE; + req->addr = addr; + req->len = 0x01; + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to erase fw @0x%02x: ", addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to erase @%04x: invalid page", + addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to erase @%04x: byte 0x00 is not 0xff", + addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_nordic_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); + const FuUnifyingBootloaderRequest *payload; + guint16 addr; + g_autoptr(GPtrArray) reqs = NULL; + + /* erase firmware pages up to the bootloader */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + for (addr = fu_unifying_bootloader_get_addr_lo (self); + addr < fu_unifying_bootloader_get_addr_hi (self); + addr += fu_unifying_bootloader_get_blocksize (self)) { + if (!fu_unifying_bootloader_nordic_erase (self, addr, error)) + return FALSE; + } + + /* transfer payload */ + reqs = fu_unifying_bootloader_parse_requests (self, fw, error); + if (reqs == NULL) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 1; i < reqs->len; i++) { + gboolean res; + payload = g_ptr_array_index (reqs, i); + + if (payload->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) { + res = fu_unifying_bootloader_nordic_write_signature (self, + payload->addr, + payload->len, + payload->data, + error); + } else { + res = fu_unifying_bootloader_nordic_write (self, + payload->addr, + payload->len, + payload->data, + error); + } + + if (!res) + return FALSE; + fu_device_set_progress_full (device, i * 32, reqs->len * 32); + } + + /* send the first managed packet last, excluding the reset vector */ + payload = g_ptr_array_index (reqs, 0); + if (!fu_unifying_bootloader_nordic_write (self, + payload->addr + 1, + payload->len - 1, + payload->data + 1, + error)) + return FALSE; + + if (!fu_unifying_bootloader_nordic_write (self, + 0x0000, + 0x01, + payload->data, + error)) + return FALSE; + + /* mark as complete */ + fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32); + + /* success! */ + return TRUE; +} + +static void +fu_unifying_bootloader_nordic_class_init (FuUnifyingBootloaderNordicClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUnifyingBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass); + klass_device->write_firmware = fu_unifying_bootloader_nordic_write_firmware; + klass_device_bootloader->setup = fu_unifying_bootloader_nordic_setup; +} + +static void +fu_unifying_bootloader_nordic_init (FuUnifyingBootloaderNordic *self) +{ +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-nordic.h fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-nordic.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-nordic.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-nordic.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-unifying-bootloader.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UNIFYING_BOOTLOADER_NORDIC (fu_unifying_bootloader_nordic_get_type ()) +G_DECLARE_FINAL_TYPE (FuUnifyingBootloaderNordic, fu_unifying_bootloader_nordic, FU, UNIFYING_BOOTLOADER_NORDIC, FuUnifyingBootloader) + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-texas.c fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-texas.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-texas.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-texas.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-unifying-common.h" +#include "fu-unifying-bootloader-texas.h" + +struct _FuUnifyingBootloaderTexas +{ + FuUnifyingBootloader parent_instance; +}; + +G_DEFINE_TYPE (FuUnifyingBootloaderTexas, fu_unifying_bootloader_texas, FU_TYPE_UNIFYING_BOOTLOADER) + +static gboolean +fu_unifying_bootloader_texas_erase_all (FuUnifyingBootloader *self, GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM; + req->len = 0x01; /* magic number */ + req->data[0] = 0x00; /* magic number */ + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to erase all pages: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_texas_compute_and_test_crc (FuUnifyingBootloader *self, GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM; + req->len = 0x01; /* magic number */ + req->data[0] = 0x03; /* magic number */ + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to compute and test CRC: "); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "CRC is incorrect"); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_texas_flash_ram_buffer (FuUnifyingBootloader *self, guint16 addr, GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM; + req->addr = addr; + req->len = 0x01; /* magic number */ + req->data[0] = 0x01; /* magic number */ + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to flash ram buffer @%04x: ", addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to flash ram buffer @%04x: invalid flash page", + addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to flash ram buffer @%04x: invalid App JMP vector", + addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to flash ram buffer @%04x: page flashed before page 0", + addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_texas_clear_ram_buffer (FuUnifyingBootloader *self, GError **error) +{ + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + req->cmd = FU_UNIFYING_BOOTLOADER_CMD_FLASH_RAM; + req->addr = 0x0000; + req->len = 0x01; /* magic number */ + req->data[0] = 0x02; /* magic number */ + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, "failed to clear ram buffer @%04x: ", req->addr); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_unifying_bootloader_texas_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuUnifyingBootloader *self = FU_UNIFYING_BOOTLOADER (device); + const FuUnifyingBootloaderRequest *payload; + g_autoptr(GPtrArray) reqs = NULL; + g_autoptr(FuUnifyingBootloaderRequest) req = fu_unifying_bootloader_request_new (); + + /* transfer payload */ + reqs = fu_unifying_bootloader_parse_requests (self, fw, error); + if (reqs == NULL) + return FALSE; + + /* erase all flash pages */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_unifying_bootloader_texas_erase_all (self, error)) + return FALSE; + + /* set existing RAM buffer to 0xff's */ + if (!fu_unifying_bootloader_texas_clear_ram_buffer (self, error)) + return FALSE; + + /* write to RAM buffer */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < reqs->len; i++) { + payload = g_ptr_array_index (reqs, i); + + /* check size */ + if (payload->len != 16) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "payload size invalid @%04x: got 0x%02x", + payload->addr, payload->len); + return FALSE; + } + + /* build packet */ + req->cmd = payload->cmd; + + /* signature addresses do not need to fit inside 128 bytes */ + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) + req->addr = payload->addr; + else + req->addr = payload->addr % 0x80; + + req->len = payload->len; + memcpy (req->data, payload->data, payload->len); + if (!fu_unifying_bootloader_request (self, req, error)) { + g_prefix_error (error, + "failed to write ram buffer @0x%02x: ", + req->addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write ram buffer @%04x: invalid location", + req->addr); + return FALSE; + } + if (req->cmd == FU_UNIFYING_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write ram buffer @%04x: invalid size 0x%02x", + req->addr, req->len); + return FALSE; + } + + /* flush RAM buffer to EEPROM */ + if ((payload->addr + 0x10) % 0x80 == 0 && + req->cmd != FU_UNIFYING_BOOTLOADER_CMD_WRITE_SIGNATURE) { + guint16 addr_start = payload->addr - (7 * 0x10); + g_debug ("addr flush @ 0x%04x for 0x%04x", + payload->addr, addr_start); + if (!fu_unifying_bootloader_texas_flash_ram_buffer (self, + addr_start, + error)) { + g_prefix_error (error, + "failed to flash ram buffer @0x%04x: ", + addr_start); + return FALSE; + } + } + + /* update progress */ + fu_device_set_progress_full (device, i * 32, reqs->len * 32); + } + + /* check CRC */ + if (!fu_unifying_bootloader_texas_compute_and_test_crc (self, error)) + return FALSE; + + /* mark as complete */ + fu_device_set_progress_full (device, reqs->len * 32, reqs->len * 32); + + /* success! */ + return TRUE; +} + +static gboolean +fu_unifying_bootloader_texas_setup (FuUnifyingBootloader *self, GError **error) +{ + fu_device_set_version (FU_DEVICE (self), "RQR24.00_B0000", + FWUPD_VERSION_FORMAT_PLAIN); + return TRUE; +} + +static void +fu_unifying_bootloader_texas_class_init (FuUnifyingBootloaderTexasClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUnifyingBootloaderClass *klass_device_bootloader = FU_UNIFYING_BOOTLOADER_CLASS (klass); + klass_device->write_firmware = fu_unifying_bootloader_texas_write_firmware; + klass_device_bootloader->setup = fu_unifying_bootloader_texas_setup; +} + +static void +fu_unifying_bootloader_texas_init (FuUnifyingBootloaderTexas *self) +{ +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-texas.h fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-texas.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-bootloader-texas.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-bootloader-texas.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-unifying-bootloader.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UNIFYING_BOOTLOADER_TEXAS (fu_unifying_bootloader_texas_get_type ()) +G_DECLARE_FINAL_TYPE (FuUnifyingBootloaderTexas, fu_unifying_bootloader_texas, FU, UNIFYING_BOOTLOADER_TEXAS, FuUnifyingBootloader) + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-common.c fwupd-1.2.10/plugins/unifying/fu-unifying-common.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "fu-unifying-common.h" + +guint8 +fu_unifying_buffer_read_uint8 (const gchar *str) +{ + guint64 tmp; + gchar buf[3] = { 0x0, 0x0, 0x0 }; + memcpy (buf, str, 2); + tmp = g_ascii_strtoull (buf, NULL, 16); + return tmp; +} + +guint16 +fu_unifying_buffer_read_uint16 (const gchar *str) +{ + guint64 tmp; + gchar buf[5] = { 0x0, 0x0, 0x0, 0x0, 0x0 }; + memcpy (buf, str, 4); + tmp = g_ascii_strtoull (buf, NULL, 16); + return tmp; +} + +gchar * +fu_unifying_format_version (const gchar *name, guint8 major, guint8 minor, guint16 build) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; i < 3; i++) { + if (g_ascii_isspace (name[i])) + continue; + g_string_append_c (str, name[i]); + } + g_string_append_printf (str, "%02x.%02x_B%04x", major, minor, build); + return g_string_free (str, FALSE); +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-common.h fwupd-1.2.10/plugins/unifying/fu-unifying-common.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_UNIFYING_DEVICE_VID 0x046d + +#define FU_UNIFYING_DEVICE_PID_RUNTIME 0xc52b +#define FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC 0xaaaa +#define FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC_PICO 0xaaae +#define FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS 0xaaac +#define FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS_PICO 0xaaad + +/* Signed firmware are very long to verify on the device */ +#define FU_UNIFYING_DEVICE_TIMEOUT_MS 20000 + +guint8 fu_unifying_buffer_read_uint8 (const gchar *str); +guint16 fu_unifying_buffer_read_uint16 (const gchar *str); + +gchar *fu_unifying_format_version (const gchar *name, + guint8 major, + guint8 minor, + guint16 build); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp.c fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-unifying-common.h" +#include "fu-unifying-hidpp.h" + +static gchar * +fu_unifying_hidpp_msg_to_string (FuUnifyingHidppMsg *msg) +{ + GString *str = g_string_new (NULL); + const gchar *tmp; + g_autoptr(GError) error = NULL; + g_autoptr(GString) flags_str = g_string_new (NULL); + + g_return_val_if_fail (msg != NULL, NULL); + + if (msg->flags == FU_UNIFYING_HIDPP_MSG_FLAG_NONE) { + g_string_append (flags_str, "none"); + } else { + if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT) + g_string_append (flags_str, "longer-timeout,"); + if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID) + g_string_append (flags_str, "ignore-sub-id,"); + if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID) + g_string_append (flags_str, "ignore-fnct-id,"); + if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID) + g_string_append (flags_str, "ignore-swid,"); + if (str->len > 0) + g_string_truncate (str, str->len - 1); + } + g_string_append_printf (str, "flags: %02x [%s]\n", + msg->flags, + flags_str->str); + g_string_append_printf (str, "report-id: %02x [%s]\n", + msg->report_id, + fu_unifying_hidpp_msg_rpt_id_to_string (msg)); + tmp = fu_unifying_hidpp_msg_dev_id_to_string (msg); + g_string_append_printf (str, "device-id: %02x [%s]\n", + msg->device_id, tmp ); + g_string_append_printf (str, "sub-id: %02x [%s]\n", + msg->sub_id, + fu_unifying_hidpp_msg_sub_id_to_string (msg)); + g_string_append_printf (str, "function-id: %02x [%s]\n", + msg->function_id, + fu_unifying_hidpp_msg_fcn_id_to_string (msg)); + if (!fu_unifying_hidpp_msg_is_error (msg, &error)) { + g_string_append_printf (str, "error: %s\n", + error->message); + } + return g_string_free (str, FALSE); +} + +gboolean +fu_unifying_hidpp_send (FuIOChannel *io_channel, + FuUnifyingHidppMsg *msg, + guint timeout, + GError **error) +{ + gsize len = fu_unifying_hidpp_msg_get_payload_length (msg); + + /* only for HID++2.0 */ + if (msg->hidpp_version >= 2.f) + msg->function_id |= FU_UNIFYING_HIDPP_MSG_SW_ID; + + /* detailed debugging */ + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + g_autofree gchar *str = fu_unifying_hidpp_msg_to_string (msg); + fu_common_dump_raw (G_LOG_DOMAIN, "host->device", (guint8 *) msg, len); + g_print ("%s", str); + } + + /* HID */ + if (!fu_io_channel_write_raw (io_channel, (guint8 *) msg, len, 1500, + FU_IO_CHANNEL_FLAG_FLUSH_INPUT | + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO, error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +gboolean +fu_unifying_hidpp_receive (FuIOChannel *io_channel, + FuUnifyingHidppMsg *msg, + guint timeout, + GError **error) +{ + gsize read_size = 0; + + if (!fu_io_channel_read_raw (io_channel, + (guint8 *) msg, + sizeof(FuUnifyingHidppMsg), + &read_size, + timeout, + FU_IO_CHANNEL_FLAG_SINGLE_SHOT, + error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + + /* check long enough, but allow returning oversize packets */ + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) + fu_common_dump_raw (G_LOG_DOMAIN, "device->host", (guint8 *) msg, read_size); + if (read_size < fu_unifying_hidpp_msg_get_payload_length (msg)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "message length too small, " + "got %" G_GSIZE_FORMAT " expected %" G_GSIZE_FORMAT, + read_size, fu_unifying_hidpp_msg_get_payload_length (msg)); + return FALSE; + } + + /* detailed debugging */ + if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { + g_autofree gchar *str = fu_unifying_hidpp_msg_to_string (msg); + g_print ("%s", str); + } + + /* success */ + return TRUE; +} + +gboolean +fu_unifying_hidpp_transfer (FuIOChannel *io_channel, FuUnifyingHidppMsg *msg, GError **error) +{ + guint timeout = FU_UNIFYING_DEVICE_TIMEOUT_MS; + guint ignore_cnt = 0; + g_autoptr(FuUnifyingHidppMsg) msg_tmp = fu_unifying_hidpp_msg_new (); + + /* increase timeout for some operations */ + if (msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT) + timeout *= 10; + + /* send request */ + if (!fu_unifying_hidpp_send (io_channel, msg, timeout, error)) + return FALSE; + + /* keep trying to receive until we get a valid reply */ + while (1) { + msg_tmp->hidpp_version = msg->hidpp_version; + if (!fu_unifying_hidpp_receive (io_channel, msg_tmp, timeout, error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + + /* we don't know how to handle this report packet */ + if (fu_unifying_hidpp_msg_get_payload_length (msg_tmp) == 0x0) { + g_debug ("HID++1.0 report 0x%02x has unknown length, ignoring", + msg_tmp->report_id); + continue; + } + + /* maybe something is also writing to the device? -- + * we can't use the SwID as this is a HID++2.0 feature */ + if (!fu_unifying_hidpp_msg_is_error (msg_tmp, error)) + return FALSE; + + /* is valid reply */ + if (fu_unifying_hidpp_msg_is_reply (msg, msg_tmp)) + break; + + /* to ensure compatibility when an HID++ 2.0 device is + * connected to an HID++ 1.0 receiver, any feature index + * corresponding to an HID++ 1.0 sub-identifier which could be + * sent by the receiver, must be assigned to a dummy feature */ + if (msg->hidpp_version >= 2.f) { + if (fu_unifying_hidpp_msg_is_hidpp10_compat (msg_tmp)) { + g_debug ("ignoring HID++1.0 reply"); + continue; + } + + /* not us */ + if ((msg->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID) == 0) { + if (!fu_unifying_hidpp_msg_verify_swid (msg_tmp)) { + g_debug ("ignoring reply with SwId 0x%02i, expected 0x%02i", + msg_tmp->function_id & 0x0f, + FU_UNIFYING_HIDPP_MSG_SW_ID); + continue; + } + } + } + + /* hardware not responding */ + if (ignore_cnt++ > 10) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "too many messages to ignore"); + return FALSE; + } + + g_debug ("ignoring message %u", ignore_cnt); + }; + + /* copy over data */ + fu_unifying_hidpp_msg_copy (msg, msg_tmp); + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp.h fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-io-channel.h" + +G_BEGIN_DECLS + +/* + * Based on the HID++ documentation provided by Nestor Lopez Casado at: + * https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing + */ +#define HIDPP_DEVICE_ID_WIRED 0x00 +#define HIDPP_DEVICE_ID_RECEIVER 0xFF +#define HIDPP_DEVICE_ID_UNSET 0xFE + +#define HIDPP_REPORT_NOTIFICATION 0x01 +#define HIDPP_REPORT_ID_SHORT 0x10 +#define HIDPP_REPORT_ID_LONG 0x11 +#define HIDPP_REPORT_ID_VERY_LONG 0x12 + +#define HIDPP_SUBID_VENDOR_SPECIFIC_KEYS 0x03 +#define HIDPP_SUBID_POWER_KEYS 0x04 +#define HIDPP_SUBID_ROLLER 0x05 +#define HIDPP_SUBID_MOUSE_EXTRA_BUTTONS 0x06 +#define HIDPP_SUBID_BATTERY_CHARGING_LEVEL 0x07 +#define HIDPP_SUBID_USER_INTERFACE_EVENT 0x08 +#define HIDPP_SUBID_F_LOCK_STATUS 0x09 +#define HIDPP_SUBID_CALCULATOR_RESULT 0x0A +#define HIDPP_SUBID_MENU_NAVIGATE 0x0B +#define HIDPP_SUBID_FN_KEY 0x0C +#define HIDPP_SUBID_BATTERY_MILEAGE 0x0D +#define HIDPP_SUBID_UART_RX 0x0E +#define HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE 0x17 +#define HIDPP_SUBID_DEVICE_DISCONNECTION 0x40 +#define HIDPP_SUBID_DEVICE_CONNECTION 0x41 +#define HIDPP_SUBID_DEVICE_DISCOVERY 0x42 +#define HIDPP_SUBID_PIN_CODE_REQUEST 0x43 +#define HIDPP_SUBID_RECEIVER_WORKING_MODE 0x44 +#define HIDPP_SUBID_ERROR_MESSAGE 0x45 +#define HIDPP_SUBID_RF_LINK_CHANGE 0x46 +#define HIDPP_SUBID_HCI 0x48 +#define HIDPP_SUBID_LINK_QUALITY 0x49 +#define HIDPP_SUBID_DEVICE_LOCKING_CHANGED 0x4a +#define HIDPP_SUBID_WIRELESS_DEVICE_CHANGE 0x4B +#define HIDPP_SUBID_ACL 0x51 +#define HIDPP_SUBID_VOIP_TELEPHONY_EVENT 0x5B +#define HIDPP_SUBID_LED 0x60 +#define HIDPP_SUBID_GESTURE_AND_AIR 0x65 +#define HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH 0x66 +#define HIDPP_SUBID_TRACEABILITY 0x78 +#define HIDPP_SUBID_SET_REGISTER 0x80 +#define HIDPP_SUBID_GET_REGISTER 0x81 +#define HIDPP_SUBID_SET_LONG_REGISTER 0x82 +#define HIDPP_SUBID_GET_LONG_REGISTER 0x83 +#define HIDPP_SUBID_SET_VERY_LONG_REGISTER 0x84 +#define HIDPP_SUBID_GET_VERY_LONG_REGISTER 0x85 +#define HIDPP_SUBID_ERROR_MSG 0x8F +#define HIDPP_SUBID_ERROR_MSG_20 0xFF + +#define HIDPP_ERR_SUCCESS 0x00 +#define HIDPP_ERR_INVALID_SUBID 0x01 +#define HIDPP_ERR_INVALID_ADDRESS 0x02 +#define HIDPP_ERR_INVALID_VALUE 0x03 +#define HIDPP_ERR_CONNECT_FAIL 0x04 +#define HIDPP_ERR_TOO_MANY_DEVICES 0x05 +#define HIDPP_ERR_ALREADY_EXISTS 0x06 +#define HIDPP_ERR_BUSY 0x07 +#define HIDPP_ERR_UNKNOWN_DEVICE 0x08 +#define HIDPP_ERR_RESOURCE_ERROR 0x09 +#define HIDPP_ERR_REQUEST_UNAVAILABLE 0x0A +#define HIDPP_ERR_INVALID_PARAM_VALUE 0x0B +#define HIDPP_ERR_WRONG_PIN_CODE 0x0C + +/* + * HID++1.0 registers + */ + +#define HIDPP_REGISTER_HIDPP_NOTIFICATIONS 0x00 +#define HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES 0x01 +#define HIDPP_REGISTER_BATTERY_STATUS 0x07 +#define HIDPP_REGISTER_BATTERY_MILEAGE 0x0D +#define HIDPP_REGISTER_PROFILE 0x0F +#define HIDPP_REGISTER_LED_STATUS 0x51 +#define HIDPP_REGISTER_LED_INTENSITY 0x54 +#define HIDPP_REGISTER_LED_COLOR 0x57 +#define HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS 0x61 +#define HIDPP_REGISTER_CURRENT_RESOLUTION 0x63 +#define HIDPP_REGISTER_USB_REFRESH_RATE 0x64 +#define HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT 0xA0 +#define HIDPP_REGISTER_HOT_CONTROL 0xA1 +#define HIDPP_REGISTER_READ_MEMORY 0xA2 +#define HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION 0xB2 +#define HIDPP_REGISTER_PAIRING_INFORMATION 0xB5 +#define HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE 0xF0 +#define HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION 0xF1 + +/* + * HID++2.0 error codes + */ +#define HIDPP_ERROR_CODE_NO_ERROR 0x00 +#define HIDPP_ERROR_CODE_UNKNOWN 0x01 +#define HIDPP_ERROR_CODE_INVALID_ARGUMENT 0x02 +#define HIDPP_ERROR_CODE_OUT_OF_RANGE 0x03 +#define HIDPP_ERROR_CODE_HW_ERROR 0x04 +#define HIDPP_ERROR_CODE_LOGITECH_INTERNAL 0x05 +#define HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX 0x06 +#define HIDPP_ERROR_CODE_INVALID_FUNCTION_ID 0x07 +#define HIDPP_ERROR_CODE_BUSY 0x08 +#define HIDPP_ERROR_CODE_UNSUPPORTED 0x09 + +/* + * HID++2.0 features + */ +#define HIDPP_FEATURE_ROOT 0x0000 +#define HIDPP_FEATURE_I_FEATURE_SET 0x0001 +#define HIDPP_FEATURE_I_FIRMWARE_INFO 0x0003 +#define HIDPP_FEATURE_GET_DEVICE_NAME_TYPE 0x0005 +#define HIDPP_FEATURE_DFU_CONTROL 0x00c1 +#define HIDPP_FEATURE_DFU_CONTROL_SIGNED 0x00c2 +#define HIDPP_FEATURE_DFU 0x00d0 +#define HIDPP_FEATURE_BATTERY_LEVEL_STATUS 0x1000 +#define HIDPP_FEATURE_KBD_REPROGRAMMABLE_KEYS 0x1b00 +#define HIDPP_FEATURE_SPECIAL_KEYS_BUTTONS 0x1b04 +#define HIDPP_FEATURE_MOUSE_POINTER_BASIC 0x2200 +#define HIDPP_FEATURE_ADJUSTABLE_DPI 0x2201 +#define HIDPP_FEATURE_ADJUSTABLE_REPORT_RATE 0x8060 +#define HIDPP_FEATURE_COLOR_LED_EFFECTS 0x8070 +#define HIDPP_FEATURE_ONBOARD_PROFILES 0x8100 +#define HIDPP_FEATURE_MOUSE_BUTTON_SPY 0x8110 + +#include "fu-unifying-hidpp-msg.h" + +gboolean fu_unifying_hidpp_send (FuIOChannel *self, + FuUnifyingHidppMsg *msg, + guint timeout, + GError **error); +gboolean fu_unifying_hidpp_receive (FuIOChannel *self, + FuUnifyingHidppMsg *msg, + guint timeout, + GError **error); +gboolean fu_unifying_hidpp_transfer (FuIOChannel *self, + FuUnifyingHidppMsg *msg, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp-msg.c fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp-msg.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp-msg.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp-msg.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-unifying-hidpp.h" +#include "fu-unifying-hidpp-msg.h" + +FuUnifyingHidppMsg * +fu_unifying_hidpp_msg_new (void) +{ + return g_new0 (FuUnifyingHidppMsg, 1); +} + +const gchar * +fu_unifying_hidpp_msg_dev_id_to_string (FuUnifyingHidppMsg *msg) +{ + g_return_val_if_fail (msg != NULL, NULL); + if (msg->device_id == HIDPP_DEVICE_ID_WIRED) + return "wired"; + if (msg->device_id == HIDPP_DEVICE_ID_RECEIVER) + return "receiver"; + if (msg->device_id == HIDPP_DEVICE_ID_UNSET) + return "unset"; + return NULL; +} + +const gchar * +fu_unifying_hidpp_msg_rpt_id_to_string (FuUnifyingHidppMsg *msg) +{ + g_return_val_if_fail (msg != NULL, NULL); + if (msg->report_id == HIDPP_REPORT_ID_SHORT) + return "short"; + if (msg->report_id == HIDPP_REPORT_ID_LONG) + return "long"; + if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG) + return "very-long"; + return NULL; +} + +gsize +fu_unifying_hidpp_msg_get_payload_length (FuUnifyingHidppMsg *msg) +{ + if (msg->report_id == HIDPP_REPORT_ID_SHORT) + return 0x07; + if (msg->report_id == HIDPP_REPORT_ID_LONG) + return 0x14; + if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG) + return 0x2f; + if (msg->report_id == HIDPP_REPORT_NOTIFICATION) + return 0x08; + return 0x0; +} + +const gchar * +fu_unifying_hidpp_msg_fcn_id_to_string (FuUnifyingHidppMsg *msg) +{ + g_return_val_if_fail (msg != NULL, NULL); + switch (msg->sub_id) { + case HIDPP_SUBID_SET_REGISTER: + case HIDPP_SUBID_GET_REGISTER: + case HIDPP_SUBID_SET_LONG_REGISTER: + case HIDPP_SUBID_GET_LONG_REGISTER: + case HIDPP_SUBID_SET_VERY_LONG_REGISTER: + case HIDPP_SUBID_GET_VERY_LONG_REGISTER: + if (msg->function_id == HIDPP_REGISTER_HIDPP_NOTIFICATIONS) + return "hidpp-notifications"; + if (msg->function_id == HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES) + return "individual-features"; + if (msg->function_id == HIDPP_REGISTER_BATTERY_STATUS) + return "battery-status"; + if (msg->function_id == HIDPP_REGISTER_BATTERY_MILEAGE) + return "battery-mileage"; + if (msg->function_id == HIDPP_REGISTER_PROFILE) + return "profile"; + if (msg->function_id == HIDPP_REGISTER_LED_STATUS) + return "led-status"; + if (msg->function_id == HIDPP_REGISTER_LED_INTENSITY) + return "led-intensity"; + if (msg->function_id == HIDPP_REGISTER_LED_COLOR) + return "led-color"; + if (msg->function_id == HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS) + return "optical-sensor-settings"; + if (msg->function_id == HIDPP_REGISTER_CURRENT_RESOLUTION) + return "current-resolution"; + if (msg->function_id == HIDPP_REGISTER_USB_REFRESH_RATE) + return "usb-refresh-rate"; + if (msg->function_id == HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT) + return "generic-memory-management"; + if (msg->function_id == HIDPP_REGISTER_HOT_CONTROL) + return "hot-control"; + if (msg->function_id == HIDPP_REGISTER_READ_MEMORY) + return "read-memory"; + if (msg->function_id == HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION) + return "device-connection-disconnection"; + if (msg->function_id == HIDPP_REGISTER_PAIRING_INFORMATION) + return "pairing-information"; + if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE) + return "device-firmware-update-mode"; + if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION) + return "device-firmware-information"; + break; + default: + break; + } + return NULL; + +} + +const gchar * +fu_unifying_hidpp_msg_sub_id_to_string (FuUnifyingHidppMsg *msg) +{ + g_return_val_if_fail (msg != NULL, NULL); + if (msg->sub_id == HIDPP_SUBID_VENDOR_SPECIFIC_KEYS) + return "vendor-specific-keys"; + if (msg->sub_id == HIDPP_SUBID_POWER_KEYS) + return "power-keys"; + if (msg->sub_id == HIDPP_SUBID_ROLLER) + return "roller"; + if (msg->sub_id == HIDPP_SUBID_MOUSE_EXTRA_BUTTONS) + return "mouse-extra-buttons"; + if (msg->sub_id == HIDPP_SUBID_BATTERY_CHARGING_LEVEL) + return "battery-charging-level"; + if (msg->sub_id == HIDPP_SUBID_USER_INTERFACE_EVENT) + return "user-interface-event"; + if (msg->sub_id == HIDPP_SUBID_F_LOCK_STATUS) + return "f-lock-status"; + if (msg->sub_id == HIDPP_SUBID_CALCULATOR_RESULT) + return "calculator-result"; + if (msg->sub_id == HIDPP_SUBID_MENU_NAVIGATE) + return "menu-navigate"; + if (msg->sub_id == HIDPP_SUBID_FN_KEY) + return "fn-key"; + if (msg->sub_id == HIDPP_SUBID_BATTERY_MILEAGE) + return "battery-mileage"; + if (msg->sub_id == HIDPP_SUBID_UART_RX) + return "uart-rx"; + if (msg->sub_id == HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE) + return "backlight-duration-update"; + if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCONNECTION) + return "device-disconnection"; + if (msg->sub_id == HIDPP_SUBID_DEVICE_CONNECTION) + return "device-connection"; + if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCOVERY) + return "device-discovery"; + if (msg->sub_id == HIDPP_SUBID_PIN_CODE_REQUEST) + return "pin-code-request"; + if (msg->sub_id == HIDPP_SUBID_RECEIVER_WORKING_MODE) + return "receiver-working-mode"; + if (msg->sub_id == HIDPP_SUBID_ERROR_MESSAGE) + return "error-message"; + if (msg->sub_id == HIDPP_SUBID_RF_LINK_CHANGE) + return "rf-link-change"; + if (msg->sub_id == HIDPP_SUBID_HCI) + return "hci"; + if (msg->sub_id == HIDPP_SUBID_LINK_QUALITY) + return "link-quality"; + if (msg->sub_id == HIDPP_SUBID_DEVICE_LOCKING_CHANGED) + return "device-locking-changed"; + if (msg->sub_id == HIDPP_SUBID_WIRELESS_DEVICE_CHANGE) + return "wireless-device-change"; + if (msg->sub_id == HIDPP_SUBID_ACL) + return "acl"; + if (msg->sub_id == HIDPP_SUBID_VOIP_TELEPHONY_EVENT) + return "voip-telephony-event"; + if (msg->sub_id == HIDPP_SUBID_LED) + return "led"; + if (msg->sub_id == HIDPP_SUBID_GESTURE_AND_AIR) + return "gesture-and-air"; + if (msg->sub_id == HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH) + return "touchpad-multi-touch"; + if (msg->sub_id == HIDPP_SUBID_TRACEABILITY) + return "traceability"; + if (msg->sub_id == HIDPP_SUBID_SET_REGISTER) + return "set-register"; + if (msg->sub_id == HIDPP_SUBID_GET_REGISTER) + return "get-register"; + if (msg->sub_id == HIDPP_SUBID_SET_LONG_REGISTER) + return "set-long-register"; + if (msg->sub_id == HIDPP_SUBID_GET_LONG_REGISTER) + return "get-long-register"; + if (msg->sub_id == HIDPP_SUBID_SET_VERY_LONG_REGISTER) + return "set-very-long-register"; + if (msg->sub_id == HIDPP_SUBID_GET_VERY_LONG_REGISTER) + return "get-very-long-register"; + if (msg->sub_id == HIDPP_SUBID_ERROR_MSG) + return "error-msg"; + if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20) + return "error-msg-v2"; + return NULL; +} + +gboolean +fu_unifying_hidpp_msg_is_reply (FuUnifyingHidppMsg *msg1, FuUnifyingHidppMsg *msg2) +{ + g_return_val_if_fail (msg1 != NULL, FALSE); + g_return_val_if_fail (msg2 != NULL, FALSE); + if (msg1->device_id != msg2->device_id && + msg1->device_id != HIDPP_DEVICE_ID_UNSET && + msg2->device_id != HIDPP_DEVICE_ID_UNSET) + return FALSE; + if (msg1->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID || + msg2->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID) + return TRUE; + if (msg1->sub_id != msg2->sub_id) + return FALSE; + if (msg1->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID || + msg2->flags & FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID) + return TRUE; + if (msg1->function_id != msg2->function_id) + return FALSE; + return TRUE; +} + +/* HID++ error */ +gboolean +fu_unifying_hidpp_msg_is_error (FuUnifyingHidppMsg *msg, GError **error) +{ + g_return_val_if_fail (msg != NULL, FALSE); + if (msg->sub_id == HIDPP_SUBID_ERROR_MSG) { + switch (msg->data[1]) { + case HIDPP_ERR_INVALID_SUBID: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "invalid SubID"); + break; + case HIDPP_ERR_INVALID_ADDRESS: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid address"); + break; + case HIDPP_ERR_INVALID_VALUE: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "invalid value"); + break; + case HIDPP_ERR_CONNECT_FAIL: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "connection request failed"); + break; + case HIDPP_ERR_TOO_MANY_DEVICES: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NO_SPACE, + "too many devices connected"); + break; + case HIDPP_ERR_ALREADY_EXISTS: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_EXISTS, + "already exists"); + break; + case HIDPP_ERR_BUSY: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_BUSY, + "busy"); + break; + case HIDPP_ERR_UNKNOWN_DEVICE: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "unknown device"); + break; + case HIDPP_ERR_RESOURCE_ERROR: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_HOST_UNREACHABLE, + "resource error"); + break; + case HIDPP_ERR_REQUEST_UNAVAILABLE: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_EXISTS, + "request not valid in current context"); + break; + case HIDPP_ERR_INVALID_PARAM_VALUE: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "request parameter has unsupported value"); + break; + case HIDPP_ERR_WRONG_PIN_CODE: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_REFUSED, + "the pin code was wrong"); + break; + default: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "generic failure"); + } + return FALSE; + } + if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20) { + switch (msg->data[1]) { + case HIDPP_ERROR_CODE_INVALID_ARGUMENT: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "Invalid argument 0x%02x", + msg->data[2]); + break; + case HIDPP_ERROR_CODE_OUT_OF_RANGE: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "out of range"); + break; + case HIDPP_ERROR_CODE_HW_ERROR: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_BROKEN_PIPE, + "hardware error"); + break; + case HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "invalid feature index"); + break; + case HIDPP_ERROR_CODE_INVALID_FUNCTION_ID: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "invalid function ID"); + break; + case HIDPP_ERROR_CODE_BUSY: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_BUSY, + "busy"); + break; + case HIDPP_ERROR_CODE_UNSUPPORTED: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "unsupported"); + break; + default: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "generic failure"); + break; + } + return FALSE; + } + return TRUE; +} + +void +fu_unifying_hidpp_msg_copy (FuUnifyingHidppMsg *msg_dst, const FuUnifyingHidppMsg *msg_src) +{ + g_return_if_fail (msg_dst != NULL); + g_return_if_fail (msg_src != NULL); + memset (msg_dst->data, 0x00, sizeof(msg_dst->data)); + msg_dst->device_id = msg_src->device_id; + msg_dst->sub_id = msg_src->sub_id; + msg_dst->function_id = msg_src->function_id; + memcpy (msg_dst->data, msg_src->data, sizeof(msg_dst->data)); +} + +/* filter HID++1.0 messages */ +gboolean +fu_unifying_hidpp_msg_is_hidpp10_compat (FuUnifyingHidppMsg *msg) +{ + g_return_val_if_fail (msg != NULL, FALSE); + if (msg->sub_id == 0x40 || + msg->sub_id == 0x41 || + msg->sub_id == 0x49 || + msg->sub_id == 0x4b || + msg->sub_id == 0x8f) { + return TRUE; + } + return FALSE; +} + +gboolean +fu_unifying_hidpp_msg_verify_swid (FuUnifyingHidppMsg *msg) +{ + g_return_val_if_fail (msg != NULL, FALSE); + if ((msg->function_id & 0x0f) != FU_UNIFYING_HIDPP_MSG_SW_ID) + return FALSE; + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp-msg.h fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp-msg.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-hidpp-msg.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-hidpp-msg.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +typedef enum { + FU_UNIFYING_HIDPP_MSG_FLAG_NONE, + FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT = 1 << 0, + FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID = 1 << 1, + FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID = 1 << 2, + FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID = 1 << 3, + /*< private >*/ + FU_UNIFYING_HIDPP_MSG_FLAG_LAST +} FuUnifyingHidppMsgFlags; + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 device_id; + guint8 sub_id; + guint8 function_id; /* funcId:software_id */ + guint8 data[47]; /* maximum supported by Windows XP SP2 */ + /* not included in the packet sent to the hardware */ + guint32 flags; + guint8 hidpp_version; +} FuUnifyingHidppMsg; + +/* this is specific to fwupd */ +#define FU_UNIFYING_HIDPP_MSG_SW_ID 0x07 + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUnifyingHidppMsg, g_free); +#pragma clang diagnostic pop + +FuUnifyingHidppMsg *fu_unifying_hidpp_msg_new (void); +void fu_unifying_hidpp_msg_copy (FuUnifyingHidppMsg *msg_dst, + const FuUnifyingHidppMsg *msg_src); +gsize fu_unifying_hidpp_msg_get_payload_length (FuUnifyingHidppMsg *msg); +gboolean fu_unifying_hidpp_msg_is_reply (FuUnifyingHidppMsg *msg1, + FuUnifyingHidppMsg *msg2); +gboolean fu_unifying_hidpp_msg_is_hidpp10_compat (FuUnifyingHidppMsg *msg); +gboolean fu_unifying_hidpp_msg_is_error (FuUnifyingHidppMsg *msg, + GError **error); +gboolean fu_unifying_hidpp_msg_verify_swid (FuUnifyingHidppMsg *msg); + +const gchar *fu_unifying_hidpp_msg_dev_id_to_string (FuUnifyingHidppMsg *msg); +const gchar *fu_unifying_hidpp_msg_rpt_id_to_string (FuUnifyingHidppMsg *msg); +const gchar *fu_unifying_hidpp_msg_sub_id_to_string (FuUnifyingHidppMsg *msg); +const gchar *fu_unifying_hidpp_msg_fcn_id_to_string (FuUnifyingHidppMsg *msg); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-peripheral.c fwupd-1.2.10/plugins/unifying/fu-unifying-peripheral.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-peripheral.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-peripheral.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,1007 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-unifying-common.h" +#include "fu-unifying-peripheral.h" +#include "fu-unifying-hidpp.h" + +struct _FuUnifyingPeripheral +{ + FuUdevDevice parent_instance; + guint8 battery_level; + guint8 cached_fw_entity; + guint8 hidpp_id; + guint8 hidpp_version; + gboolean is_updatable; + gboolean is_active; + FuIOChannel *io_channel; + GPtrArray *feature_index; /* of FuUnifyingHidppMap */ +}; + +typedef struct { + guint8 idx; + guint16 feature; +} FuUnifyingHidppMap; + +G_DEFINE_TYPE (FuUnifyingPeripheral, fu_unifying_peripheral, FU_TYPE_UDEV_DEVICE) + +typedef enum { + FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD, + FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL, + FU_UNIFYING_PERIPHERAL_KIND_NUMPAD, + FU_UNIFYING_PERIPHERAL_KIND_MOUSE, + FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD, + FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL, + FU_UNIFYING_PERIPHERAL_KIND_PRESENTER, + FU_UNIFYING_PERIPHERAL_KIND_RECEIVER, + FU_UNIFYING_PERIPHERAL_KIND_LAST +} FuUnifyingPeripheralKind; + +static const gchar * +fu_unifying_peripheral_get_icon (FuUnifyingPeripheralKind kind) +{ + if (kind == FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD) + return "input-keyboard"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL) + return "pda"; // ish + if (kind == FU_UNIFYING_PERIPHERAL_KIND_NUMPAD) + return "input-dialpad"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_MOUSE) + return "input-mouse"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD) + return "input-touchpad"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL) + return "input-mouse"; // ish + if (kind == FU_UNIFYING_PERIPHERAL_KIND_PRESENTER) + return "pda"; // ish + if (kind == FU_UNIFYING_PERIPHERAL_KIND_RECEIVER) + return "preferences-desktop-keyboard"; + return NULL; +} + +static const gchar * +fu_unifying_peripheral_get_summary (FuUnifyingPeripheralKind kind) +{ + if (kind == FU_UNIFYING_PERIPHERAL_KIND_KEYBOARD) + return "Unifying Keyboard"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_REMOTE_CONTROL) + return "Unifying Remote Control"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_NUMPAD) + return "Unifying Number Pad"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_MOUSE) + return "Unifying Mouse"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_TOUCHPAD) + return "Unifying Touchpad"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_TRACKBALL) + return "Unifying Trackball"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_PRESENTER) + return "Unifying Presenter"; + if (kind == FU_UNIFYING_PERIPHERAL_KIND_RECEIVER) + return "Unifying Receiver"; + return NULL; +} + +static const gchar * +fu_unifying_hidpp_feature_to_string (guint16 feature) +{ + if (feature == HIDPP_FEATURE_ROOT) + return "Root"; + if (feature == HIDPP_FEATURE_I_FIRMWARE_INFO) + return "IFirmwareInfo"; + if (feature == HIDPP_FEATURE_GET_DEVICE_NAME_TYPE) + return "GetDevicenameType"; + if (feature == HIDPP_FEATURE_BATTERY_LEVEL_STATUS) + return "BatteryLevelStatus"; + if (feature == HIDPP_FEATURE_DFU_CONTROL) + return "DfuControl"; + if (feature == HIDPP_FEATURE_DFU_CONTROL_SIGNED) + return "DfuControlSigned"; + if (feature == HIDPP_FEATURE_DFU) + return "Dfu"; + return NULL; +} + +static void +fu_unifying_peripheral_refresh_updatable (FuUnifyingPeripheral *self) +{ + /* device can only be upgraded if it is capable, and active */ + if (self->is_updatable && self->is_active) { + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + return; + } + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static gboolean +fu_unifying_peripheral_ping (FuUnifyingPeripheral *self, GError **error) +{ + gdouble version; + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + + /* handle failure */ + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = 0x00; /* rootIndex */ + msg->function_id = 0x01 << 4; /* ping */ + msg->data[0] = 0x00; + msg->data[1] = 0x00; + msg->data[2] = 0xaa; /* user-selected value */ + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED)) { + self->hidpp_version = 1; + return TRUE; + } + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_HOST_UNREACHABLE)) { + self->is_active = FALSE; + fu_unifying_peripheral_refresh_updatable (self); + return TRUE; + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to ping %s: %s", + fu_device_get_name (FU_DEVICE (self)), + error_local->message); + return FALSE; + } + + /* device no longer asleep */ + self->is_active = TRUE; + fu_unifying_peripheral_refresh_updatable (self); + + /* if the HID++ ID is unset, grab it from the reply */ + if (self->hidpp_id == HIDPP_DEVICE_ID_UNSET) { + self->hidpp_id = msg->device_id; + g_debug ("HID++ ID is %02x", self->hidpp_id); + } + + /* format version in BCD format */ + version = (gdouble) msg->data[0] + ((gdouble) msg->data[1]) / 100.f; + self->hidpp_version = (guint) version; + + /* success */ + return TRUE; +} + +static gboolean +fu_unifying_peripheral_close (FuDevice *device, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); + return TRUE; +} + +static gboolean +fu_unifying_peripheral_poll (FuDevice *device, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + const guint timeout = 1; /* ms */ + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open */ + locker = fu_device_locker_new (self, error); + if (locker == NULL) + return FALSE; + + /* flush pending data */ + msg->device_id = self->hidpp_id; + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) { + if (!g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT)) { + g_warning ("failed to get pending read: %s", error_local->message); + return TRUE; + } + /* no data to receive */ + g_clear_error (&error_local); + } + + /* just ping */ + if (!fu_unifying_peripheral_ping (self, &error_local)) { + g_warning ("failed to ping device: %s", error_local->message); + return TRUE; + } + + /* this is the first time the device has been active */ + if (self->feature_index->len == 0) { + fu_device_probe_invalidate (FU_DEVICE (self)); + if (!fu_device_setup (FU_DEVICE (self), error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_unifying_peripheral_open (FuDevice *device, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + const gchar *devpath = g_udev_device_get_device_file (udev_device); + + /* open */ + self->io_channel = fu_io_channel_new_file (devpath, error); + if (self->io_channel == NULL) + return FALSE; + + return TRUE; +} + +static void +fu_unifying_peripheral_to_string (FuDevice *device, GString *str) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + + g_string_append_printf (str, " HidppVersion:\t\t%u\n", self->hidpp_version); + if (self->hidpp_id != HIDPP_DEVICE_ID_UNSET) + g_string_append_printf (str, " HidppId:\t\t0x%02x\n", (guint) self->hidpp_id); + if (self->battery_level != 0) + g_string_append_printf (str, " Battery-level:\t\t%u\n", self->battery_level); + g_string_append_printf (str, " IsUpdatable:\t\t%i\n", self->is_updatable); + g_string_append_printf (str, " IsActive:\t\t%i\n", self->is_active); + for (guint i = 0; i < self->feature_index->len; i++) { + FuUnifyingHidppMap *map = g_ptr_array_index (self->feature_index, i); + g_string_append_printf (str, " Feature%02x:\t\t%s [0x%04x]\n", + map->idx, + fu_unifying_hidpp_feature_to_string (map->feature), + map->feature); + } +} + +static guint8 +fu_unifying_peripheral_feature_get_idx (FuUnifyingPeripheral *self, guint16 feature) +{ + for (guint i = 0; i < self->feature_index->len; i++) { + FuUnifyingHidppMap *map = g_ptr_array_index (self->feature_index, i); + if (map->feature == feature) + return map->idx; + } + return 0x00; +} + +static gboolean +fu_unifying_peripheral_fetch_firmware_info (FuUnifyingPeripheral *self, GError **error) +{ + guint8 idx; + guint8 entity_count; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + + /* get the feature index */ + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_I_FIRMWARE_INFO); + if (idx == 0x00) + return TRUE; + + /* get the entity count */ + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x00 << 4; /* getCount */ + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to get firmware count: "); + return FALSE; + } + entity_count = msg->data[0]; + g_debug ("firmware entity count is %u", entity_count); + + /* get firmware, bootloader, hardware versions */ + for (guint8 i = 0; i < entity_count; i++) { + guint16 build; + g_autofree gchar *version = NULL; + g_autofree gchar *name = NULL; + + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x01 << 4; /* getInfo */ + msg->data[0] = i; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to get firmware info: "); + return FALSE; + } + if (msg->data[1] == 0x00 && + msg->data[2] == 0x00 && + msg->data[3] == 0x00 && + msg->data[4] == 0x00 && + msg->data[5] == 0x00 && + msg->data[6] == 0x00 && + msg->data[7] == 0x00) { + g_debug ("no version set for entity %u", i); + continue; + } + name = g_strdup_printf ("%c%c%c", + msg->data[1], + msg->data[2], + msg->data[3]); + build = ((guint16) msg->data[6]) << 8 | msg->data[7]; + version = fu_unifying_format_version (name, + msg->data[4], + msg->data[5], + build); + g_debug ("firmware entity 0x%02x version is %s", i, version); + if (msg->data[0] == 0) { + fu_device_set_version (FU_DEVICE (self), version, + FWUPD_VERSION_FORMAT_PLAIN); + self->cached_fw_entity = i; + } else if (msg->data[0] == 1) { + fu_device_set_version_bootloader (FU_DEVICE (self), version); + } else if (msg->data[0] == 2) { + fu_device_set_metadata (FU_DEVICE (self), "version-hw", version); + } + } + + /* not an error, the device just doesn't support this */ + return TRUE; +} + +static gboolean +fu_unifying_peripheral_fetch_battery_level (FuUnifyingPeripheral *self, GError **error) +{ + /* try using HID++2.0 */ + if (self->hidpp_version >= 2.f) { + guint8 idx; + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_BATTERY_LEVEL_STATUS); + if (idx != 0x00) { + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x00; /* GetBatteryLevelStatus */ + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to get battery info: "); + return FALSE; + } + if (msg->data[0] != 0x00) + self->battery_level = msg->data[0]; + return TRUE; + } + } + + /* try HID++1.0 battery mileage */ + if (self->hidpp_version == 1.f) { + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = HIDPP_SUBID_GET_REGISTER; + msg->function_id = HIDPP_REGISTER_BATTERY_MILEAGE; + msg->hidpp_version = self->hidpp_version; + if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) { + if (msg->data[0] != 0x00) + self->battery_level = msg->data[0]; + return TRUE; + } + + /* try HID++1.0 battery status instead */ + msg->function_id = HIDPP_REGISTER_BATTERY_STATUS; + if (fu_unifying_hidpp_transfer (self->io_channel, msg, NULL)) { + switch (msg->data[0]) { + case 1: /* 0 - 10 */ + self->battery_level = 5; + break; + case 3: /* 11 - 30 */ + self->battery_level = 20; + break; + case 5: /* 31 - 80 */ + self->battery_level = 55; + break; + case 7: /* 81 - 100 */ + self->battery_level = 90; + break; + default: + g_warning ("unknown battery percentage: 0x%02x", + msg->data[0]); + break; + } + return TRUE; + } + } + + /* not an error, the device just doesn't support any of the methods */ + return TRUE; +} + +static gboolean +fu_unifying_hidpp_feature_search (FuDevice *device, guint16 feature, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + FuUnifyingHidppMap *map; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + + /* find the idx for the feature */ + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = 0x00; /* rootIndex */ + msg->function_id = 0x00 << 4; /* getFeature */ + msg->data[0] = feature >> 8; + msg->data[1] = feature; + msg->data[2] = 0x00; + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, + "failed to get idx for feature %s [0x%04x]: ", + fu_unifying_hidpp_feature_to_string (feature), feature); + return FALSE; + } + + /* zero index */ + if (msg->data[0] == 0x00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "feature %s [0x%04x] not found", + fu_unifying_hidpp_feature_to_string (feature), feature); + return FALSE; + } + + /* add to map */ + map = g_new0 (FuUnifyingHidppMap, 1); + map->idx = msg->data[0]; + map->feature = feature; + g_ptr_array_add (self->feature_index, map); + g_debug ("added feature %s [0x%04x] as idx %02x", + fu_unifying_hidpp_feature_to_string (feature), feature, map->idx); + return TRUE; +} + +static gboolean +fu_unifying_peripheral_probe (FuUdevDevice *device, GError **error) +{ + g_autofree gchar *devid = NULL; + + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "hid", error)) + return FALSE; + + /* nearly... */ + fu_device_set_vendor_id (FU_DEVICE (device), "USB:0x046D"); + + /* this is a non-standard extension */ + devid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X", + fu_udev_device_get_vendor (device), + fu_udev_device_get_model (device)); + fu_device_add_instance_id (FU_DEVICE (device), devid); + return TRUE; +} + +static gboolean +fu_unifying_peripheral_setup (FuDevice *device, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + guint8 idx; + const guint16 map_features[] = { + HIDPP_FEATURE_GET_DEVICE_NAME_TYPE, + HIDPP_FEATURE_I_FIRMWARE_INFO, + HIDPP_FEATURE_BATTERY_LEVEL_STATUS, + HIDPP_FEATURE_DFU_CONTROL, + HIDPP_FEATURE_DFU_CONTROL_SIGNED, + HIDPP_FEATURE_DFU, + HIDPP_FEATURE_ROOT }; + + /* ping device to get HID++ version */ + if (!fu_unifying_peripheral_ping (self, error)) + return FALSE; + + /* add known root for HID++2.0 */ + g_ptr_array_set_size (self->feature_index, 0); + if (self->hidpp_version >= 2.f) { + FuUnifyingHidppMap *map = g_new0 (FuUnifyingHidppMap, 1); + map->idx = 0x00; + map->feature = HIDPP_FEATURE_ROOT; + g_ptr_array_add (self->feature_index, map); + } + + /* map some *optional* HID++2.0 features we might use */ + for (guint i = 0; map_features[i] != HIDPP_FEATURE_ROOT; i++) { + g_autoptr(GError) error_local = NULL; + if (!fu_unifying_hidpp_feature_search (device, + map_features[i], + &error_local)) { + g_debug ("%s", error_local->message); + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT) || + g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_HOST_UNREACHABLE)) { + /* timed out, so not trying any more */ + break; + } + } + } + + /* get the firmware information */ + if (!fu_unifying_peripheral_fetch_firmware_info (self, error)) + return FALSE; + + /* get the battery level */ + if (!fu_unifying_peripheral_fetch_battery_level (self, error)) + return FALSE; + + /* try using HID++2.0 */ + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_GET_DEVICE_NAME_TYPE); + if (idx != 0x00) { + const gchar *tmp; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x02 << 4; /* getDeviceType */ + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to get device type: "); + return FALSE; + } + + /* add nice-to-have data */ + tmp = fu_unifying_peripheral_get_summary (msg->data[0]); + if (tmp != NULL) + fu_device_set_summary (FU_DEVICE (device), tmp); + tmp = fu_unifying_peripheral_get_icon (msg->data[0]); + if (tmp != NULL) + fu_device_add_icon (FU_DEVICE (device), tmp); + } + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL); + if (idx != 0x00) { + self->is_updatable = TRUE; + fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED); + if (idx != 0x00) { + /* check the feature is available */ + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x00 << 4; /* getDfuStatus */ + msg->hidpp_version = self->hidpp_version; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to get DFU status: "); + return FALSE; + } + if ((msg->data[2] & 0x01) > 0) { + g_warning ("DFU mode not available"); + } else { + self->is_updatable = TRUE; + fu_device_remove_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } + } + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU); + if (idx != 0x00) { + self->is_updatable = TRUE; + fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + if (fu_device_get_version (device) == NULL) { + g_debug ("repairing device in bootloader mode"); + fu_device_set_version (FU_DEVICE (device), + "MPK00.00_B0000", + FWUPD_VERSION_FORMAT_PLAIN); + } + } + + /* this device may have changed state */ + fu_unifying_peripheral_refresh_updatable (self); + + /* poll for pings to track active state */ + fu_device_set_poll_interval (device, 30000); + return TRUE; +} + +static gboolean +fu_unifying_peripheral_detach (FuDevice *device, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + guint8 idx; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + + /* this requires user action */ + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL); + if (idx != 0x00) { + msg->report_id = HIDPP_REPORT_ID_LONG; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x01 << 4; /* setDfuControl */ + msg->data[0] = 0x01; /* enterDfu */ + msg->data[1] = 0x00; /* dfuControlParam */ + msg->data[2] = 0x00; /* unused */ + msg->data[3] = 0x00; /* unused */ + msg->data[4] = 'D'; + msg->data[5] = 'F'; + msg->data[6] = 'U'; + msg->hidpp_version = self->hidpp_version; + msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID | + FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to put device into DFU mode: "); + return FALSE; + } + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; + } + + /* this can reboot all by itself */ + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU_CONTROL_SIGNED); + if (idx != 0x00) { + msg->report_id = HIDPP_REPORT_ID_LONG; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x01 << 4; /* setDfuControl */ + msg->data[0] = 0x01; /* startDfu */ + msg->data[1] = 0x00; /* dfuControlParam */ + msg->data[2] = 0x00; /* unused */ + msg->data[3] = 0x00; /* unused */ + msg->data[4] = 'D'; + msg->data[5] = 'F'; + msg->data[6] = 'U'; + msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to put device into DFU mode: "); + return FALSE; + } + return fu_unifying_peripheral_setup (FU_DEVICE (self), error); + } + + /* we don't know how */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no method to detach"); + return FALSE; +} + +static gboolean +fu_unifying_peripheral_check_status (guint8 status, GError **error) +{ + switch (status & 0x7f) { + case 0x00: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "invalid status value 0x%02x", + status); + break; + case 0x01: /* packet success */ + case 0x02: /* DFU success */ + case 0x05: /* DFU success: entity restart required */ + case 0x06: /* DFU success: system restart required */ + /* success */ + return TRUE; + break; + case 0x03: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_PENDING, + "wait for event (command in progress)"); + break; + case 0x04: + case 0x10: /* unknown */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "generic error"); + break; + case 0x11: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad voltage (power too low?)"); + break; + case 0x12: + case 0x14: /* bad magic string */ + case 0x21: /* bad firmware */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unsupported firmware"); + break; + case 0x13: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unsupported encryption mode"); + break; + case 0x15: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "erase failure"); + break; + case 0x16: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "DFU not started"); + break; + case 0x17: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad sequence number"); + break; + case 0x18: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unsupported command"); + break; + case 0x19: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "command in progress"); + break; + case 0x1a: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "address out of range"); + break; + case 0x1b: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unaligned address"); + break; + case 0x1c: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "bad size"); + break; + case 0x1d: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "missing program data"); + break; + case 0x1e: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "missing check data"); + break; + case 0x1f: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "program failed to write"); + break; + case 0x20: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "program failed to verify"); + break; + case 0x22: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "firmware check failure"); + break; + case 0x23: + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "blocked command (restart required)"); + break; + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unhandled status value 0x%02x", + status); + break; + } + return FALSE; +} + +static gboolean +fu_unifying_peripheral_write_firmware_pkt (FuUnifyingPeripheral *self, + guint8 idx, + guint8 cmd, + const guint8 *data, + GError **error) +{ + guint32 packet_cnt; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + g_autoptr(GError) error_local = NULL; + + /* send firmware data */ + msg->report_id = HIDPP_REPORT_ID_LONG; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = cmd << 4; /* dfuStart or dfuCmdDataX */ + msg->hidpp_version = self->hidpp_version; + memcpy (msg->data, data, 16); + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, &error_local)) { + g_prefix_error (error, "failed to supply program data: "); + return FALSE; + } + + /* check error */ + packet_cnt = fu_common_read_uint32 (msg->data, G_BIG_ENDIAN); + g_debug ("packet_cnt=0x%04x", packet_cnt); + if (fu_unifying_peripheral_check_status (msg->data[4], &error_local)) + return TRUE; + + /* fatal error */ + if (!g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_PENDING)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + error_local->message); + return FALSE; + } + + /* wait for the HID++ notification */ + g_debug ("ignoring: %s", error_local->message); + for (guint retry = 0; retry < 10; retry++) { + g_autoptr(FuUnifyingHidppMsg) msg2 = fu_unifying_hidpp_msg_new (); + msg2->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_FNCT_ID; + if (!fu_unifying_hidpp_receive (self->io_channel, msg2, 15000, error)) + return FALSE; + if (fu_unifying_hidpp_msg_is_reply (msg, msg2)) { + g_autoptr(GError) error2 = NULL; + if (!fu_unifying_peripheral_check_status (msg2->data[4], &error2)) { + g_debug ("got %s, waiting a bit longer", error2->message); + continue; + } + return TRUE; + } else { + g_debug ("got wrong packet, continue to wait..."); + } + } + + /* nothing in the queue */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to get event after timeout"); + return FALSE; +} + +static gboolean +fu_unifying_peripheral_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + gsize sz = 0; + const guint8 *data; + guint8 cmd = 0x04; + guint8 idx; + + /* if we're in bootloader mode, we should be able to get this feature */ + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU); + if (idx == 0x00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no DFU feature available"); + return FALSE; + } + + /* flash hardware */ + data = g_bytes_get_data (fw, &sz); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (gsize i = 0; i < sz / 16; i++) { + + /* send packet and wait for reply */ + g_debug ("send data at addr=0x%04x", (guint) i * 16); + if (!fu_unifying_peripheral_write_firmware_pkt (self, + idx, + cmd, + data + (i * 16), + error)) { + g_prefix_error (error, + "failed to write @0x%04x: ", + (guint) i * 16); + return FALSE; + } + + /* use sliding window */ + cmd = (cmd + 1) % 4; + + /* update progress-bar */ + fu_device_set_progress_full (device, i * 16, sz); + } + + return TRUE; +} + +static gboolean +fu_unifying_peripheral_attach (FuDevice *device, GError **error) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (device); + guint8 idx; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + + /* if we're in bootloader mode, we should be able to get this feature */ + idx = fu_unifying_peripheral_feature_get_idx (self, HIDPP_FEATURE_DFU); + if (idx == 0x00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "no DFU feature available"); + return FALSE; + } + + /* reboot back into firmware mode */ + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = self->hidpp_id; + msg->sub_id = idx; + msg->function_id = 0x05 << 4; /* restart */ + msg->data[0] = self->cached_fw_entity; /* fwEntity */ + msg->hidpp_version = self->hidpp_version; + msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SUB_ID | + FU_UNIFYING_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred? + FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to restart device: "); + return FALSE; + } + + /* reprobe */ + if (!fu_unifying_peripheral_setup (device, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static void +fu_unifying_peripheral_finalize (GObject *object) +{ + FuUnifyingPeripheral *self = FU_UNIFYING_PERIPHERAL (object); + g_ptr_array_unref (self->feature_index); + G_OBJECT_CLASS (fu_unifying_peripheral_parent_class)->finalize (object); +} + +static void +fu_unifying_peripheral_class_init (FuUnifyingPeripheralClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fu_unifying_peripheral_finalize; + klass_device->setup = fu_unifying_peripheral_setup; + klass_device->open = fu_unifying_peripheral_open; + klass_device->close = fu_unifying_peripheral_close; + klass_device->write_firmware = fu_unifying_peripheral_write_firmware; + klass_device->attach = fu_unifying_peripheral_attach; + klass_device->detach = fu_unifying_peripheral_detach; + klass_device->poll = fu_unifying_peripheral_poll; + klass_device->to_string = fu_unifying_peripheral_to_string; + klass_device_udev->probe = fu_unifying_peripheral_probe; +} + +static void +fu_unifying_peripheral_init (FuUnifyingPeripheral *self) +{ + self->hidpp_id = HIDPP_DEVICE_ID_UNSET; + self->feature_index = g_ptr_array_new_with_free_func (g_free); + fu_device_add_parent_guid (FU_DEVICE (self), "HIDRAW\\VEN_046D&DEV_C52B"); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-peripheral.h fwupd-1.2.10/plugins/unifying/fu-unifying-peripheral.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-peripheral.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-peripheral.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-udev-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UNIFYING_PERIPHERAL (fu_unifying_peripheral_get_type ()) +G_DECLARE_FINAL_TYPE (FuUnifyingPeripheral, fu_unifying_peripheral, FU, UNIFYING_PERIPHERAL, FuUdevDevice) + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-runtime.c fwupd-1.2.10/plugins/unifying/fu-unifying-runtime.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-runtime.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-runtime.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-unifying-common.h" +#include "fu-unifying-runtime.h" +#include "fu-unifying-hidpp.h" + +struct _FuUnifyingRuntime +{ + FuUdevDevice parent_instance; + guint8 version_bl_major; + gboolean signed_firmware; + FuIOChannel *io_channel; +}; + +G_DEFINE_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU_TYPE_UDEV_DEVICE) + +#ifndef HAVE_GUDEV_232 +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#endif + +static void +fu_unifying_runtime_to_string (FuDevice *device, GString *str) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + g_string_append_printf (str, " SignedFirmware:\t%i\n", self->signed_firmware); +} + +static gboolean +fu_unifying_runtime_enable_notifications (FuUnifyingRuntime *self, GError **error) +{ + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = HIDPP_DEVICE_ID_RECEIVER; + msg->sub_id = HIDPP_SUBID_SET_REGISTER; + msg->function_id = HIDPP_REGISTER_HIDPP_NOTIFICATIONS; + msg->data[0] = 0x00; + msg->data[1] = 0x05; /* Wireless + SoftwarePresent */ + msg->data[2] = 0x00; + msg->hidpp_version = 1; + return fu_unifying_hidpp_transfer (self->io_channel, msg, error); +} + +static gboolean +fu_unifying_runtime_close (FuDevice *device, GError **error) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + if (!fu_io_channel_shutdown (self->io_channel, error)) + return FALSE; + g_clear_object (&self->io_channel); + return TRUE; +} + +static gboolean +fu_unifying_runtime_poll (FuDevice *device, GError **error) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + const guint timeout = 1; /* ms */ + g_autoptr(GError) error_local = NULL; + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* open */ + locker = fu_device_locker_new (self, error); + if (locker == NULL) + return FALSE; + + /* is there any pending data to read */ + msg->hidpp_version = 1; + if (!fu_unifying_hidpp_receive (self->io_channel, msg, timeout, &error_local)) { + if (g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT)) { + return TRUE; + } + g_warning ("failed to get pending read: %s", error_local->message); + return TRUE; + } + + /* HID++1.0 error */ + if (!fu_unifying_hidpp_msg_is_error (msg, &error_local)) { + g_warning ("failed to get pending read: %s", error_local->message); + return TRUE; + } + + /* unifying receiver notification */ + if (msg->report_id == HIDPP_REPORT_ID_SHORT) { + switch (msg->sub_id) { + case HIDPP_SUBID_DEVICE_CONNECTION: + case HIDPP_SUBID_DEVICE_DISCONNECTION: + case HIDPP_SUBID_DEVICE_LOCKING_CHANGED: + g_debug ("device connection event, do something"); + break; + case HIDPP_SUBID_LINK_QUALITY: + g_debug ("ignoring link quality message"); + break; + case HIDPP_SUBID_ERROR_MSG: + g_debug ("ignoring link quality message"); + break; + default: + g_debug ("unknown SubID %02x", msg->sub_id); + break; + } + } + return TRUE; +} + +static gboolean +fu_unifying_runtime_open (FuDevice *device, GError **error) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + const gchar *devpath = g_udev_device_get_device_file (udev_device); + + /* open, but don't block */ + self->io_channel = fu_io_channel_new_file (devpath, error); + if (self->io_channel == NULL) + return FALSE; + + /* poll for notifications */ + fu_device_set_poll_interval (device, 5000); + + /* success */ + return TRUE; +} + +static gboolean +fu_unifying_runtime_probe (FuUdevDevice *device, GError **error) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + guint16 release = 0xffff; + g_autoptr(GUdevDevice) udev_parent = NULL; + + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "usb", error)) + return FALSE; + + /* generate bootloader-specific GUID */ + udev_parent = g_udev_device_get_parent_with_subsystem (udev_device, + "usb", "usb_device"); + if (udev_parent != NULL) { + const gchar *release_str; + release_str = g_udev_device_get_property (udev_parent, "ID_REVISION"); + if (release_str != NULL) + release = g_ascii_strtoull (release_str, NULL, 16); + } + if (release != 0xffff) { + g_autofree gchar *devid2 = NULL; + switch (release &= 0xff00) { + case 0x1200: + /* Nordic */ + devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", + (guint) FU_UNIFYING_DEVICE_VID, + (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_NORDIC); + fu_device_add_counterpart_guid (FU_DEVICE (device), devid2); + self->version_bl_major = 0x01; + break; + case 0x2400: + /* Texas */ + devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", + (guint) FU_UNIFYING_DEVICE_VID, + (guint) FU_UNIFYING_DEVICE_PID_BOOTLOADER_TEXAS); + fu_device_add_counterpart_guid (FU_DEVICE (device), devid2); + self->version_bl_major = 0x03; + break; + default: + g_warning ("bootloader release %04x invalid", release); + break; + } + } + return TRUE; +} + +static gboolean +fu_unifying_runtime_setup_internal (FuDevice *device, GError **error) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + guint8 config[10]; + g_autofree gchar *version_fw = NULL; + + /* read all 10 bytes of the version register */ + memset (config, 0x00, sizeof (config)); + for (guint i = 0x01; i < 0x05; i++) { + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + + /* workaround a bug in the 12.01 firmware, which fails with + * INVALID_VALUE when reading MCU1_HW_VERSION */ + if (i == 0x03) + continue; + + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = HIDPP_DEVICE_ID_RECEIVER; + msg->sub_id = HIDPP_SUBID_GET_REGISTER; + msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION; + msg->data[0] = i; + msg->hidpp_version = 1; + if (!fu_unifying_hidpp_transfer (self->io_channel, msg, error)) { + g_prefix_error (error, "failed to read device config: "); + return FALSE; + } + memcpy (config + (i * 2), msg->data + 1, 2); + } + + /* get firmware version */ + version_fw = fu_unifying_format_version ("RQR", + config[2], + config[3], + (guint16) config[4] << 8 | + config[5]); + fu_device_set_version (device, version_fw, FWUPD_VERSION_FORMAT_PLAIN); + + /* get bootloader version */ + if (self->version_bl_major > 0) { + g_autofree gchar *version_bl = NULL; + version_bl = fu_unifying_format_version ("BOT", + self->version_bl_major, + config[8], + config[9]); + fu_device_set_version_bootloader (FU_DEVICE (device), version_bl); + + /* is the dongle expecting signed firmware */ + if ((self->version_bl_major == 0x01 && config[8] >= 0x04) || + (self->version_bl_major == 0x03 && config[8] >= 0x02)) { + self->signed_firmware = TRUE; + } + } + + /* enable HID++ notifications */ + if (!fu_unifying_runtime_enable_notifications (self, error)) { + g_prefix_error (error, "failed to enable notifications: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_unifying_runtime_setup (FuDevice *device, GError **error) +{ + g_autoptr(GError) error_local = NULL; + for (guint i = 0; i < 5; i++) { + /* HID++1.0 devices have to sleep to allow Solaar to talk to + * the device first -- we can't use the SwID as this is a + * HID++2.0 feature */ + g_usleep (200*1000); + if (fu_unifying_runtime_setup_internal (device, &error_local)) + return TRUE; + if (!g_error_matches (error_local, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + g_clear_error (&error_local); + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; +} + +static gboolean +fu_unifying_runtime_detach (FuDevice *device, GError **error) +{ + FuUnifyingRuntime *self = FU_UNIFYING_RUNTIME (device); + g_autoptr(FuUnifyingHidppMsg) msg = fu_unifying_hidpp_msg_new (); + msg->report_id = HIDPP_REPORT_ID_SHORT; + msg->device_id = HIDPP_DEVICE_ID_RECEIVER; + msg->sub_id = HIDPP_SUBID_SET_REGISTER; + msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE; + msg->data[0] = 'I'; + msg->data[1] = 'C'; + msg->data[2] = 'P'; + msg->hidpp_version = 1; + msg->flags = FU_UNIFYING_HIDPP_MSG_FLAG_LONGER_TIMEOUT; + if (!fu_unifying_hidpp_send (self->io_channel, msg, FU_UNIFYING_DEVICE_TIMEOUT_MS, error)) { + g_prefix_error (error, "failed to detach to bootloader: "); + return FALSE; + } + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + return TRUE; +} + +static void +fu_unifying_runtime_finalize (GObject *object) +{ + G_OBJECT_CLASS (fu_unifying_runtime_parent_class)->finalize (object); +} + +static void +fu_unifying_runtime_class_init (FuUnifyingRuntimeClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fu_unifying_runtime_finalize; + klass_device->open = fu_unifying_runtime_open; + klass_device_udev->probe = fu_unifying_runtime_probe; + klass_device->setup = fu_unifying_runtime_setup; + klass_device->close = fu_unifying_runtime_close; + klass_device->detach = fu_unifying_runtime_detach; + klass_device->poll = fu_unifying_runtime_poll; + klass_device->to_string = fu_unifying_runtime_to_string; +} + +static void +fu_unifying_runtime_init (FuUnifyingRuntime *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_icon (FU_DEVICE (self), "preferences-desktop-keyboard"); + fu_device_set_name (FU_DEVICE (self), "Unifying Receiver"); + fu_device_set_summary (FU_DEVICE (self), "A miniaturised USB wireless receiver"); + fu_device_set_remove_delay (FU_DEVICE (self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); +} diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-runtime.h fwupd-1.2.10/plugins/unifying/fu-unifying-runtime.h --- fwupd-1.0.6/plugins/unifying/fu-unifying-runtime.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-runtime.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2016-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-udev-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UNIFYING_RUNTIME (fu_unifying_runtime_get_type ()) +G_DECLARE_FINAL_TYPE (FuUnifyingRuntime, fu_unifying_runtime, FU, UNIFYING_RUNTIME, FuUdevDevice) + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/unifying/fu-unifying-self-test.c fwupd-1.2.10/plugins/unifying/fu-unifying-self-test.c --- fwupd-1.0.6/plugins/unifying/fu-unifying-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/fu-unifying-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-unifying-common.h" + +static void +fu_unifying_common (void) +{ + guint8 u8; + guint16 u16; + g_autofree gchar *ver1 = NULL; + + u8 = fu_unifying_buffer_read_uint8 ("12"); + g_assert_cmpint (u8, ==, 0x12); + u16 = fu_unifying_buffer_read_uint16 ("1234"); + g_assert_cmpint (u16, ==, 0x1234); + + ver1 = fu_unifying_format_version (" A ", 0x87, 0x65, 0x4321); + g_assert_cmpstr (ver1, ==, "A87.65_B4321"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/unifying/common", fu_unifying_common); + return g_test_run (); +} diff -Nru fwupd-1.0.6/plugins/unifying/lu-common.c fwupd-1.2.10/plugins/unifying/lu-common.c --- fwupd-1.0.6/plugins/unifying/lu-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "lu-common.h" - -guint8 -lu_buffer_read_uint8 (const gchar *str) -{ - guint64 tmp; - gchar buf[3] = { 0x0, 0x0, 0x0 }; - memcpy (buf, str, 2); - tmp = g_ascii_strtoull (buf, NULL, 16); - return tmp; -} - -guint16 -lu_buffer_read_uint16 (const gchar *str) -{ - guint64 tmp; - gchar buf[5] = { 0x0, 0x0, 0x0, 0x0, 0x0 }; - memcpy (buf, str, 4); - tmp = g_ascii_strtoull (buf, NULL, 16); - return tmp; -} - -void -lu_dump_raw (const gchar *title, const guint8 *data, gsize len) -{ - g_autoptr(GString) str = g_string_new (NULL); - if (len == 0) - return; - g_string_append_printf (str, "%s:", title); - for (gsize i = strlen (title); i < 16; i++) - g_string_append (str, " "); - for (gsize i = 0; i < len; i++) { - g_string_append_printf (str, "%02x ", data[i]); - if (i > 0 && i % 32 == 0) - g_string_append (str, "\n"); - } - g_debug ("%s", str->str); -} - -gchar * -lu_format_version (const gchar *name, guint8 major, guint8 minor, guint16 build) -{ - GString *str = g_string_new (NULL); - for (guint i = 0; i < 3; i++) { - if (g_ascii_isspace (name[i])) - continue; - g_string_append_c (str, name[i]); - } - g_string_append_printf (str, "%02x.%02x_B%04x", major, minor, build); - return g_string_free (str, FALSE); -} - -static gboolean -lu_nonblock_flush (gint fd, GError **error) -{ - GPollFD poll[] = { - { - .fd = fd, - .events = G_IO_IN | G_IO_OUT | G_IO_ERR, - }, - }; - while (g_poll (poll, G_N_ELEMENTS(poll), 0) > 0) { - gchar c; - gint r = read (fd, &c, 1); - if (r < 0 && errno != EINTR) - break; - } - return TRUE; -} - -gboolean -lu_nonblock_write (gint fd, - const guint8 *data, - gsize data_sz, - GError **error) -{ - gssize wrote; - - /* sanity check */ - if (fd == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write: fd is not open"); - return FALSE; - } - - /* flush pending reads */ - if (!lu_nonblock_flush (fd, error)) - return FALSE; - - /* write */ - wrote = write (fd, data, data_sz); - if (wrote != (gssize) data_sz) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write: " - "wrote %" G_GSSIZE_FORMAT " of %" G_GSIZE_FORMAT, - wrote, data_sz); - return FALSE; - } - return TRUE; -} - -gboolean -lu_nonblock_read (gint fd, - guint8 *data, - gsize data_sz, - gsize *data_len, - guint timeout, - GError **error) -{ - gssize len = 0; - gint64 ts_start; - GPollFD poll[] = { - { - .fd = fd, - .events = G_IO_IN | G_IO_OUT | G_IO_ERR, - }, - }; - - /* sanity check */ - if (fd == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read: fd is not open"); - return FALSE; - } - - /* do a read with a timeout */ - ts_start = g_get_monotonic_time (); - while (1) { - gint rc; - gint ts_remain = ((g_get_monotonic_time () - ts_start) / 1000) + timeout; - if (ts_remain <= 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT, - "timeout already passed"); - return FALSE; - } - - /* waits for the fd to become ready */ - rc = g_poll (poll, G_N_ELEMENTS (poll), ts_remain); - if (rc < 0) { - if (errno == EINTR) - continue; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "read interrupted: %s", - g_strerror (errno)); - return FALSE; - } else if (rc == 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT, - "timeout"); - return FALSE; - } - - /* read data from fd */ - len = read (fd, data, data_sz); - if (len <= 0) { - if (len == -1 && errno == EINTR) - continue; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to read data: %s", - g_strerror (errno)); - return FALSE; - } - - /* success */ - break; - }; - - /* success */ - if (data_len != NULL) - *data_len = (gsize) len; - return TRUE; -} - -gint -lu_nonblock_open (const gchar *filename, GError **error) -{ - gint fd; - fd = open (filename, O_RDWR | O_NONBLOCK); - if (fd < 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to open %s", filename); - return -1; - } - return fd; -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-common.h fwupd-1.2.10/plugins/unifying/lu-common.h --- fwupd-1.0.6/plugins/unifying/lu-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-common.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_COMMON_H -#define __LU_COMMON_H - -#include - -G_BEGIN_DECLS - -void lu_dump_raw (const gchar *title, - const guint8 *data, - gsize len); - -guint8 lu_buffer_read_uint8 (const gchar *str); -guint16 lu_buffer_read_uint16 (const gchar *str); - -gchar *lu_format_version (const gchar *name, - guint8 major, - guint8 minor, - guint16 build); - -gint lu_nonblock_open (const gchar *filename, - GError **error); -gboolean lu_nonblock_read (gint fd, - guint8 *data, - gsize data_sz, - gsize *data_len, - guint timeout, - GError **error); -gboolean lu_nonblock_write (gint fd, - const guint8 *data, - gsize data_sz, - GError **error); - -G_END_DECLS - -#endif /* __LU_COMMON_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-context.c fwupd-1.2.10/plugins/unifying/lu-context.c --- fwupd-1.0.6/plugins/unifying/lu-context.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-context.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,686 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include -#include - -#include "lu-common.h" -#include "lu-context.h" -#include "lu-device-bootloader-nordic.h" -#include "lu-device-bootloader-texas.h" -#include "lu-device-peripheral.h" -#include "lu-device-runtime.h" -#include "lu-hidpp.h" - -struct _LuContext -{ - GObject parent_instance; - GPtrArray *supported_guids; - GPtrArray *devices; - GHashTable *devices_active; /* LuDevice : 1 */ - GUsbContext *usb_ctx; - GUdevClient *gudev_client; - GHashTable *hash_replug; - gboolean done_coldplug; - GHashTable *hash_devices; - guint poll_id; -}; - -G_DEFINE_TYPE (LuContext, lu_context, G_TYPE_OBJECT) - -enum { - PROP_0, - PROP_USB_CONTEXT, - PROP_LAST -}; - -enum { - SIGNAL_ADDED, - SIGNAL_REMOVED, - SIGNAL_LAST -}; - -static guint signals [SIGNAL_LAST] = { 0 }; - -typedef struct { - GMainLoop *loop; - LuDevice *device; - guint timeout_id; -} GUsbContextReplugHelper; - -GPtrArray * -lu_context_get_devices (LuContext *ctx) -{ - /* ensure we have devices */ - if (!ctx->done_coldplug) - lu_context_coldplug (ctx); - return ctx->devices; -} - -static gboolean -lu_context_check_supported (LuContext *ctx, const gchar *guid) -{ - if (ctx->supported_guids == NULL) { - g_debug ("no list of supported GUIDs so assuming supported"); - return TRUE; - } - for (guint i = 0; i < ctx->supported_guids->len; i++) { - const gchar *guid_tmp = g_ptr_array_index (ctx->supported_guids, i); - if (g_strcmp0 (guid, guid_tmp) == 0) - return TRUE; - } - return FALSE; -} - -void -lu_context_set_supported (LuContext *ctx, GPtrArray *supported_guids) -{ - if (ctx->supported_guids != NULL) - g_ptr_array_unref (ctx->supported_guids); - ctx->supported_guids = g_ptr_array_ref (supported_guids); -} - -static void -lu_device_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - LuContext *ctx = LU_CONTEXT (object); - switch (prop_id) { - case PROP_USB_CONTEXT: - g_value_set_object (value, ctx->usb_ctx); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -lu_device_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - LuContext *ctx = LU_CONTEXT (object); - switch (prop_id) { - case PROP_USB_CONTEXT: - ctx->usb_ctx = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -lu_context_finalize (GObject *object) -{ - LuContext *ctx = LU_CONTEXT (object); - - if (ctx->poll_id != 0) - g_source_remove (ctx->poll_id); - if (ctx->supported_guids != NULL) - g_ptr_array_unref (ctx->supported_guids); - - g_ptr_array_unref (ctx->devices); - g_hash_table_unref (ctx->devices_active); - g_object_unref (ctx->usb_ctx); - g_object_unref (ctx->gudev_client); - g_hash_table_unref (ctx->hash_devices); - g_hash_table_unref (ctx->hash_replug); - G_OBJECT_CLASS (lu_context_parent_class)->finalize (object); -} - -static void -lu_context_class_init (LuContextClass *klass) -{ - GParamSpec *pspec; - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = lu_context_finalize; - object_class->get_property = lu_device_get_property; - object_class->set_property = lu_device_set_property; - - pspec = g_param_spec_object ("usb-context", NULL, NULL, - G_USB_TYPE_CONTEXT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - g_object_class_install_property (object_class, PROP_USB_CONTEXT, pspec); - - signals [SIGNAL_ADDED] = - g_signal_new ("added", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 1, LU_TYPE_DEVICE); - signals [SIGNAL_REMOVED] = - g_signal_new ("removed", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 1, LU_TYPE_DEVICE); -} - -static void -lu_context_device_flags_notify_cb (GObject *obj, - GParamSpec *pspec, - LuContext *ctx) -{ - LuDevice *device = LU_DEVICE (obj); - if (g_hash_table_lookup (ctx->devices_active, device) != NULL) { - if (!lu_device_has_flag (device, LU_DEVICE_FLAG_ACTIVE)) { - g_debug ("existing device now inactive, sending signal"); - g_signal_emit (ctx, signals[SIGNAL_REMOVED], 0, device); - g_hash_table_remove (ctx->devices_active, device); - } - } else { - if (lu_device_has_flag (device, LU_DEVICE_FLAG_ACTIVE)) { - g_debug ("existing device now active, sending signal"); - g_signal_emit (ctx, signals[SIGNAL_ADDED], 0, device); - g_hash_table_insert (ctx->devices_active, device, GINT_TO_POINTER (1)); - } - } -} - -static void -lu_context_add_device (LuContext *ctx, LuDevice *device) -{ - GUsbContextReplugHelper *replug_helper; - g_autoptr(GError) error = NULL; - - g_return_if_fail (LU_IS_CONTEXT (ctx)); - g_return_if_fail (LU_IS_DEVICE (device)); - - g_debug ("device %s added", fu_device_get_platform_id (FU_DEVICE (device))); - - /* HID++1.0 devices have to sleep to allow Solaar to talk to the device - * first -- we can't use the SwID as this is a HID++2.0 feature */ - if (ctx->done_coldplug && - lu_device_get_hidpp_version (device) <= 1.f) { - g_debug ("waiting for device to settle..."); - g_usleep (G_USEC_PER_SEC); - } - - /* try to open */ - if (!lu_device_open (device, &error)) { - if (g_error_matches (error, - G_IO_ERROR, - G_IO_ERROR_HOST_UNREACHABLE)) { - g_debug ("could not open: %s", error->message); - } else { - g_warning ("failed to open: %s", error->message); - } - return; - } - - /* emit */ - g_ptr_array_add (ctx->devices, g_object_ref (device)); - if (lu_device_has_flag (device, LU_DEVICE_FLAG_ACTIVE)) { - g_signal_emit (ctx, signals[SIGNAL_ADDED], 0, device); - g_hash_table_insert (ctx->devices_active, device, GINT_TO_POINTER (1)); - } - g_signal_connect (device, "notify::flags", - G_CALLBACK (lu_context_device_flags_notify_cb), ctx); - - /* if we're waiting for replug, quit the loop */ - replug_helper = g_hash_table_lookup (ctx->hash_replug, - fu_device_get_platform_id (FU_DEVICE (device))); - if (replug_helper != NULL) { - g_debug ("%s is in replug, quitting loop", - fu_device_get_platform_id (FU_DEVICE (device))); - g_main_loop_quit (replug_helper->loop); - } - -} - -static void -lu_context_remove_device (LuContext *ctx, LuDevice *device) -{ - g_return_if_fail (LU_IS_CONTEXT (ctx)); - g_return_if_fail (LU_IS_DEVICE (device)); - - g_debug ("device %s removed", fu_device_get_platform_id (FU_DEVICE (device))); - - /* no longer valid */ - g_object_set (device, - "usb-device", NULL, - "udev-device", NULL, - NULL); - - if (lu_device_has_flag (device, LU_DEVICE_FLAG_ACTIVE)) - g_signal_emit (ctx, signals[SIGNAL_REMOVED], 0, device); - g_ptr_array_remove (ctx->devices, device); -} - -#ifndef HAVE_GUDEV_232 -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) -#endif - -static const gchar * -lu_context_get_platform_id_for_udev_device (GUdevDevice *udev_device) -{ - g_autoptr(GUdevDevice) udev_device1 = NULL; - udev_device1 = g_udev_device_get_parent_with_subsystem (udev_device, - "usb", "usb_device"); - if (udev_device1 == NULL) - return NULL; - return g_udev_device_get_sysfs_path (udev_device1); -} - -static void -lu_context_add_udev_device (LuContext *ctx, GUdevDevice *udev_device) -{ - const gchar *val; - const gchar *platform_id; - guint16 pid; - guint16 vid; - g_autofree gchar *devid = NULL; - g_autoptr(GUdevDevice) udev_parent = NULL; - g_autoptr(LuDevice) device = NULL; - - g_return_if_fail (LU_IS_CONTEXT (ctx)); - - g_debug ("UDEV add %s = %s", - g_udev_device_get_device_file (udev_device), - g_udev_device_get_sysfs_path (udev_device)); - - /* check the vid:pid from property HID_ID=0003:0000046D:0000C52B */ - udev_parent = g_udev_device_get_parent (udev_device); - val = g_udev_device_get_property (udev_parent, "HID_ID"); - if (val == NULL) { - g_debug ("no HID_ID, skipping"); - return; - } - if (strlen (val) != 22) { - g_warning ("property HID_ID invalid '%s', skipping", val); - return; - } - - /* is logitech */ - vid = lu_buffer_read_uint16 (val + 10); - if (vid != LU_DEVICE_VID) { - g_debug ("not a matching vid: %04x", vid); - return; - } - - /* is unifying runtime */ - pid = lu_buffer_read_uint16 (val + 18); - if (pid == LU_DEVICE_PID_RUNTIME) { - platform_id = lu_context_get_platform_id_for_udev_device (udev_device); - device = g_object_new (LU_TYPE_DEVICE_RUNTIME, - "kind", LU_DEVICE_KIND_RUNTIME, - "flags", LU_DEVICE_FLAG_ACTIVE | - LU_DEVICE_FLAG_REQUIRES_DETACH | - LU_DEVICE_FLAG_DETACH_WILL_REPLUG, - "platform-id", platform_id, - "udev-device", udev_device, - "hidpp-id", HIDPP_DEVICE_ID_RECEIVER, - NULL); - g_hash_table_insert (ctx->hash_devices, - g_strdup (fu_device_get_platform_id (FU_DEVICE (device))), - g_object_ref (device)); - lu_context_add_device (ctx, device); - return; - } - - /* is unifying bootloader */ - if (pid == LU_DEVICE_PID_BOOTLOADER_NORDIC || - pid == LU_DEVICE_PID_BOOTLOADER_NORDIC_PICO || - pid == LU_DEVICE_PID_BOOTLOADER_TEXAS || - pid == LU_DEVICE_PID_BOOTLOADER_TEXAS_PICO) { - g_debug ("ignoring bootloader in HID mode"); - return; - } - - /* is peripheral */ - platform_id = g_udev_device_get_sysfs_path (udev_device); - device = g_object_new (LU_TYPE_DEVICE_PERIPHERAL, - "kind", LU_DEVICE_KIND_PERIPHERAL, - "platform-id", platform_id, - "udev-device", udev_device, - NULL); - val = g_udev_device_get_property (udev_parent, "HID_NAME"); - if (val != NULL) { - if (g_str_has_prefix (val, "Logitech ")) - val += 9; - fu_device_set_name (FU_DEVICE (device), val); - } - - /* generate GUID */ - devid = g_strdup_printf ("UFY\\VID_%04X&PID_%04X", vid, pid); - fu_device_add_guid (FU_DEVICE (device), devid); - if (!lu_context_check_supported (ctx, fu_device_get_guid_default (FU_DEVICE (device)))) { - g_debug ("%s not supported, so ignoring device", devid); - return; - } - g_hash_table_insert (ctx->hash_devices, - g_strdup (fu_device_get_platform_id (FU_DEVICE (device))), - g_object_ref (device)); - lu_context_add_device (ctx, device); -} - -static gboolean -g_usb_context_replug_timeout_cb (gpointer user_data) -{ - GUsbContextReplugHelper *replug_helper = (GUsbContextReplugHelper *) user_data; - replug_helper->timeout_id = 0; - g_main_loop_quit (replug_helper->loop); - return FALSE; -} - -static void -g_usb_context_replug_helper_free (GUsbContextReplugHelper *replug_helper) -{ - if (replug_helper->timeout_id != 0) - g_source_remove (replug_helper->timeout_id); - g_main_loop_unref (replug_helper->loop); - g_object_unref (replug_helper->device); - g_free (replug_helper); -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUsbContextReplugHelper, g_usb_context_replug_helper_free); - -gboolean -lu_context_wait_for_replug (LuContext *ctx, - LuDevice *device, - guint timeout_ms, - GError **error) -{ - g_autoptr(GUsbContextReplugHelper) replug_helper = NULL; - const gchar *platform_id; - - g_return_val_if_fail (LU_IS_CONTEXT (ctx), FALSE); - g_return_val_if_fail (LU_IS_DEVICE (device), FALSE); - - /* create a helper */ - replug_helper = g_new0 (GUsbContextReplugHelper, 1); - replug_helper->device = g_object_ref (device); - replug_helper->loop = g_main_loop_new (NULL, FALSE); - replug_helper->timeout_id = g_timeout_add (timeout_ms, - g_usb_context_replug_timeout_cb, - replug_helper); - - /* register */ - platform_id = fu_device_get_platform_id (FU_DEVICE (device)); - g_hash_table_insert (ctx->hash_replug, - g_strdup (platform_id), replug_helper); - - /* wait for timeout, or replug */ - g_main_loop_run (replug_helper->loop); - - /* unregister */ - g_hash_table_remove (ctx->hash_replug, platform_id); - - /* so we timed out; emit the removal now */ - if (replug_helper->timeout_id == 0) { - g_set_error_literal (error, - G_USB_CONTEXT_ERROR, - G_USB_CONTEXT_ERROR_INTERNAL, - "request timed out"); - return FALSE; - } - return TRUE; -} - -static void -lu_context_remove_udev_device (LuContext *ctx, GUdevDevice *udev_device) -{ - /* look for this udev_device in all the objects */ - for (guint i = 0; i < ctx->devices->len; i++) { - LuDevice *device = g_ptr_array_index (ctx->devices, i); - GUdevDevice *udev_device_tmp = lu_device_get_udev_device (device); - if (udev_device_tmp == NULL) - continue; - if (g_strcmp0 (g_udev_device_get_sysfs_path (udev_device_tmp), - g_udev_device_get_sysfs_path (udev_device)) == 0) { - lu_context_remove_device (ctx, device); - break; - } - } -} - -static gboolean -lu_context_poll_cb (gpointer user_data) -{ - LuContext *ctx = LU_CONTEXT (user_data); - - /* do not poll when we're waiting for device replug */ - if (g_hash_table_size (ctx->hash_replug) > 0) { - g_debug ("not polling device as replug in process"); - return TRUE; - } - - for (guint i = 0; i < ctx->devices->len; i++) { - LuDevice *device = g_ptr_array_index (ctx->devices, i); - g_autoptr(GError) error = NULL; - if (!lu_device_open (device, &error)) { - g_debug ("failed to open %s: %s", - fu_device_get_platform_id (FU_DEVICE (device)), - error->message); - continue; - } - if (!lu_device_poll (device, &error)) { - g_debug ("failed to probe %s: %s", - fu_device_get_platform_id (FU_DEVICE (device)), - error->message); - continue; - } - } - return TRUE; -} - -void -lu_context_set_poll_interval (LuContext *ctx, guint poll_interval) -{ - /* enable or change */ - if (poll_interval > 0) { - if (ctx->poll_id > 0) - g_source_remove (ctx->poll_id); - ctx->poll_id = g_timeout_add (poll_interval, - lu_context_poll_cb, - ctx); - return; - } - - /* disable */ - if (poll_interval == 0 && ctx->poll_id != 0) { - g_source_remove (ctx->poll_id); - ctx->poll_id = 0; - return; - } -} - -static void -lu_context_udev_uevent_cb (GUdevClient *gudev_client, - const gchar *action, - GUdevDevice *udev_device, - LuContext *ctx) -{ - if (g_strcmp0 (action, "remove") == 0) { - lu_context_remove_udev_device (ctx, udev_device); - return; - } - if (g_strcmp0 (action, "add") == 0) { - lu_context_add_udev_device (ctx, udev_device); - return; - } -} - -static void -lu_context_init (LuContext *ctx) -{ - const gchar *subsystems[] = { "hidraw", NULL }; - ctx->gudev_client = g_udev_client_new (subsystems); - g_signal_connect (ctx->gudev_client, "uevent", - G_CALLBACK (lu_context_udev_uevent_cb), ctx); - ctx->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - ctx->devices_active = g_hash_table_new (g_direct_hash, g_direct_equal); - ctx->hash_devices = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) g_object_unref); - ctx->hash_replug = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); -} - -void -lu_context_coldplug (LuContext *ctx) -{ - g_autoptr(GList) devices = NULL; - - g_return_if_fail (LU_IS_CONTEXT (ctx)); - - if (ctx->done_coldplug) - return; - - /* coldplug hidraw devices */ - devices = g_udev_client_query_by_subsystem (ctx->gudev_client, "hidraw"); - for (GList *l = devices; l != NULL; l = l->next) { - GUdevDevice *udev_device = G_UDEV_DEVICE (l->data); - lu_context_add_udev_device (ctx, udev_device); - g_object_unref (udev_device); - } - - /* done */ - ctx->done_coldplug = TRUE; -} - -LuDevice * -lu_context_find_by_platform_id (LuContext *ctx, const gchar *platform_id, GError **error) -{ - g_return_val_if_fail (LU_IS_CONTEXT (ctx), NULL); - g_return_val_if_fail (platform_id != NULL, NULL); - - /* ensure we have devices */ - if (!ctx->done_coldplug) - lu_context_coldplug (ctx); - - for (guint i = 0; i < ctx->devices->len; i++) { - LuDevice *device = g_ptr_array_index (ctx->devices, i); - if (g_strcmp0 (fu_device_get_platform_id (FU_DEVICE (device)), platform_id) == 0) - return g_object_ref (device); - } - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "not found %s", platform_id); - return NULL; -} - -static void -lu_context_usb_device_added_cb (GUsbContext *usb_ctx, - GUsbDevice *usb_device, - LuContext *ctx) -{ - g_return_if_fail (LU_IS_CONTEXT (ctx)); - - /* logitech */ - if (g_usb_device_get_vid (usb_device) != LU_DEVICE_VID) - return; - - g_debug ("USB add %s", g_usb_device_get_platform_id (usb_device)); - - /* nordic, in bootloader mode */ - if (g_usb_device_get_pid (usb_device) == LU_DEVICE_PID_BOOTLOADER_NORDIC || - g_usb_device_get_pid (usb_device) == LU_DEVICE_PID_BOOTLOADER_NORDIC_PICO) { - g_autoptr(LuDevice) device = NULL; - device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER_NORDIC, - "kind", LU_DEVICE_KIND_BOOTLOADER_NORDIC, - "flags", LU_DEVICE_FLAG_ACTIVE | - LU_DEVICE_FLAG_REQUIRES_ATTACH | - LU_DEVICE_FLAG_ATTACH_WILL_REPLUG, - "hidpp-id", HIDPP_DEVICE_ID_RECEIVER, - "usb-device", usb_device, - NULL); - lu_context_add_device (ctx, device); - return; - } - - /* texas, in bootloader mode */ - if (g_usb_device_get_pid (usb_device) == LU_DEVICE_PID_BOOTLOADER_TEXAS || - g_usb_device_get_pid (usb_device) == LU_DEVICE_PID_BOOTLOADER_TEXAS_PICO) { - g_autoptr(LuDevice) device = NULL; - device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER_TEXAS, - "kind", LU_DEVICE_KIND_BOOTLOADER_TEXAS, - "flags", LU_DEVICE_FLAG_ACTIVE | - LU_DEVICE_FLAG_REQUIRES_ATTACH | - LU_DEVICE_FLAG_ATTACH_WILL_REPLUG, - "hidpp-id", HIDPP_DEVICE_ID_RECEIVER, - "usb-device", usb_device, - NULL); - lu_context_add_device (ctx, device); - return; - } -} - -static void -lu_context_usb_device_removed_cb (GUsbContext *usb_ctx, - GUsbDevice *usb_device, - LuContext *ctx) -{ - g_return_if_fail (LU_IS_CONTEXT (ctx)); - - /* logitech */ - if (g_usb_device_get_vid (usb_device) != LU_DEVICE_VID) - return; - - /* look for this usb_device in all the objects */ - for (guint i = 0; i < ctx->devices->len; i++) { - LuDevice *device = g_ptr_array_index (ctx->devices, i); - if (lu_device_get_usb_device (device) == usb_device) { - lu_context_remove_device (ctx, device); - break; - } - } -} - -static void -lu_context_init_real (LuContext *ctx) -{ - g_signal_connect (ctx->usb_ctx, "device-added", - G_CALLBACK (lu_context_usb_device_added_cb), - ctx); - g_signal_connect (ctx->usb_ctx, "device-removed", - G_CALLBACK (lu_context_usb_device_removed_cb), - ctx); -} - -LuContext * -lu_context_new (GError **error) -{ - LuContext *ctx = NULL; - g_autoptr(GUsbContext) usb_ctx = NULL; - - usb_ctx = g_usb_context_new (error); - if (usb_ctx == NULL) - return NULL; - ctx = g_object_new (LU_TYPE_CONTEXT, - "usb-context", usb_ctx, - NULL); - lu_context_init_real (ctx); - g_usb_context_enumerate (ctx->usb_ctx); - return ctx; -} - -LuContext * -lu_context_new_full (GUsbContext *usb_ctx) -{ - LuContext *ctx = NULL; - ctx = g_object_new (LU_TYPE_CONTEXT, - "usb-context", usb_ctx, - NULL); - lu_context_init_real (ctx); - return ctx; -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-context.h fwupd-1.2.10/plugins/unifying/lu-context.h --- fwupd-1.0.6/plugins/unifying/lu-context.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-context.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_CONTEXT_H -#define __LU_CONTEXT_H - -#include -#include - -#include "lu-device.h" - -G_BEGIN_DECLS - -#define LU_TYPE_CONTEXT (lu_context_get_type ()) -G_DECLARE_FINAL_TYPE (LuContext, lu_context, LU, CONTEXT, GObject) - -GPtrArray *lu_context_get_devices (LuContext *ctx); -LuDevice *lu_context_find_by_platform_id (LuContext *ctx, - const gchar *platform_id, - GError **error); -void lu_context_coldplug (LuContext *ctx); -void lu_context_set_poll_interval (LuContext *ctx, - guint poll_interval); -void lu_context_set_supported (LuContext *ctx, - GPtrArray *supported_guids); -gboolean lu_context_wait_for_replug (LuContext *ctx, - LuDevice *device, - guint timeout_ms, - GError **error); - -LuContext *lu_context_new (GError **error); -LuContext *lu_context_new_full (GUsbContext *usb_ctx); - -G_END_DECLS - -#endif /* __LU_CONTEXT_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-bootloader.c fwupd-1.2.10/plugins/unifying/lu-device-bootloader.c --- fwupd-1.0.6/plugins/unifying/lu-device-bootloader.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-bootloader.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,425 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include - -#include "lu-common.h" -#include "lu-device-bootloader.h" -#include "lu-hidpp.h" - -typedef struct -{ - guint16 flash_addr_lo; - guint16 flash_addr_hi; - guint16 flash_blocksize; -} LuDeviceBootloaderPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (LuDeviceBootloader, lu_device_bootloader, LU_TYPE_DEVICE) - -#define GET_PRIVATE(o) (lu_device_bootloader_get_instance_private (o)) - -LuDeviceBootloaderRequest * -lu_device_bootloader_request_new (void) -{ - LuDeviceBootloaderRequest *req = g_new0 (LuDeviceBootloaderRequest, 1); - return req; -} - -GPtrArray * -lu_device_bootloader_parse_requests (LuDevice *device, GBytes *fw, GError **error) -{ - const gchar *tmp; - g_auto(GStrv) lines = NULL; - g_autoptr(GPtrArray) reqs = NULL; - guint32 last_addr = 0; - - reqs = g_ptr_array_new_with_free_func (g_free); - tmp = g_bytes_get_data (fw, NULL); - lines = g_strsplit_set (tmp, "\n\r", -1); - for (guint i = 0; lines[i] != NULL; i++) { - g_autoptr(LuDeviceBootloaderRequest) payload = NULL; - guint8 rec_type = 0x00; - - /* skip empty lines */ - tmp = lines[i]; - if (strlen (tmp) < 5) - continue; - - payload = lu_device_bootloader_request_new (); - payload->len = lu_buffer_read_uint8 (tmp + 0x01); - if (payload->len > 28) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware data invalid: too large %u bytes", - payload->len); - return NULL; - } - payload->addr = ((guint16) lu_buffer_read_uint8 (tmp + 0x03)) << 8; - payload->addr |= lu_buffer_read_uint8 (tmp + 0x05); - - rec_type = lu_buffer_read_uint8 (tmp + 0x07); - - /* record type of 0xFD indicates signature data */ - if (rec_type == 0xFD) { - payload->cmd = LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE; - } else { - payload->cmd = LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER; - } - - /* read the data, but skip the checksum byte */ - for (guint j = 0; j < payload->len; j++) { - const gchar *ptr = tmp + 0x09 + (j * 2); - if (ptr[0] == '\0') { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware data invalid: expected %u bytes", - payload->len); - return NULL; - } - payload->data[j] = lu_buffer_read_uint8 (ptr); - } - - /* no need to bound check signature addresses */ - if (payload->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) { - g_ptr_array_add (reqs, g_steal_pointer (&payload)); - continue; - } - - /* skip the bootloader */ - if (payload->addr > lu_device_bootloader_get_addr_hi (device)) { - g_debug ("skipping write @ %04x", payload->addr); - continue; - } - - /* skip the header */ - if (payload->addr < lu_device_bootloader_get_addr_lo (device)) { - g_debug ("skipping write @ %04x", payload->addr); - continue; - } - - /* make sure firmware addresses only go up */ - if (payload->addr < last_addr) { - g_debug ("skipping write @ %04x", payload->addr); - continue; - } - last_addr = payload->addr; - - /* pending */ - g_ptr_array_add (reqs, g_steal_pointer (&payload)); - } - if (reqs->len == 0) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware data invalid: no payloads found"); - return NULL; - } - return g_steal_pointer (&reqs); -} - -guint16 -lu_device_bootloader_get_addr_lo (LuDevice *device) -{ - LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device); - LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader); - g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000); - return priv->flash_addr_lo; -} - -guint16 -lu_device_bootloader_get_addr_hi (LuDevice *device) -{ - LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device); - LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader); - g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000); - return priv->flash_addr_hi; -} - -void -lu_device_bootloader_set_addr_lo (LuDevice *device, guint16 addr) -{ - LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device); - LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader); - priv->flash_addr_lo = addr; -} - -void -lu_device_bootloader_set_addr_hi (LuDevice *device, guint16 addr) -{ - LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device); - LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader); - priv->flash_addr_hi = addr; -} - -guint16 -lu_device_bootloader_get_blocksize (LuDevice *device) -{ - LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device); - LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader); - g_return_val_if_fail (LU_IS_DEVICE (device), 0x0000); - return priv->flash_blocksize; -} - -static gboolean -lu_device_bootloader_attach (LuDevice *device, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_REBOOT; - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to attach back to runtime: "); - return FALSE; - } - return TRUE; -} - -static guint16 -cd_buffer_read_uint16_be (const guint8 *buffer) -{ - guint16 tmp; - memcpy (&tmp, buffer, sizeof(tmp)); - return GUINT16_FROM_BE (tmp); -} - -static gboolean -lu_device_bootloader_open (LuDevice *device, GError **error) -{ - LuDeviceBootloader *device_bootloader = LU_DEVICE_BOOTLOADER (device); - LuDeviceBootloaderPrivate *priv = GET_PRIVATE (device_bootloader); - g_autofree gchar *name = NULL; - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - - /* generate name */ - name = g_strdup_printf ("Unifying [%s]", - lu_device_kind_to_string (lu_device_get_kind (device))); - fu_device_set_name (FU_DEVICE (device), name); - - /* we can flash this */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - - /* get memory map */ - req->cmd = LU_DEVICE_BOOTLOADER_CMD_GET_MEMINFO; - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to get meminfo: "); - return FALSE; - } - if (req->len != 0x06) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to get meminfo: invalid size %02x", - req->len); - return FALSE; - } - - /* parse values */ - priv->flash_addr_lo = cd_buffer_read_uint16_be (req->data + 0); - priv->flash_addr_hi = cd_buffer_read_uint16_be (req->data + 2); - priv->flash_blocksize = cd_buffer_read_uint16_be (req->data + 4); - return TRUE; -} - -static gchar * -lu_device_bootloader_get_bl_version (LuDevice *device, GError **error) -{ - guint16 build; - - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_GET_BL_VERSION; - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to get firmware version: "); - return NULL; - } - - /* BOTxx.yy_Bzzzz - * 012345678901234 */ - build = (guint16) lu_buffer_read_uint8 ((const gchar *) req->data + 10) << 8; - build += lu_buffer_read_uint8 ((const gchar *) req->data + 12); - return lu_format_version ("BOT", - lu_buffer_read_uint8 ((const gchar *) req->data + 3), - lu_buffer_read_uint8 ((const gchar *) req->data + 6), - build); -} - -static gboolean -lu_device_bootloader_probe (LuDevice *device, GError **error) -{ - LuDeviceBootloaderClass *klass = LU_DEVICE_BOOTLOADER_GET_CLASS (device); - g_autofree gchar *version_bl = NULL; - - /* get bootloader version */ - version_bl = lu_device_bootloader_get_bl_version (device, error); - if (version_bl == NULL) - return FALSE; - fu_device_set_version_bootloader (FU_DEVICE (device), version_bl); - - /* subclassed further */ - if (klass->probe != NULL) - return klass->probe (device, error); - return TRUE; -} - -static gboolean -lu_device_bootloader_close (LuDevice *device, GError **error) -{ - GUsbDevice *usb_device = lu_device_get_usb_device (device); - if (usb_device != NULL) { - if (!g_usb_device_release_interface (usb_device, 0x00, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - return FALSE; - } - } - return TRUE; -} - -gboolean -lu_device_bootloader_request (LuDevice *device, - LuDeviceBootloaderRequest *req, - GError **error) -{ - GUsbDevice *usb_device = lu_device_get_usb_device (device); - gsize actual_length = 0; - guint8 buf_request[32]; - guint8 buf_response[32]; - - /* build packet */ - memset (buf_request, 0x00, sizeof (buf_request)); - buf_request[0x00] = req->cmd; - buf_request[0x01] = req->addr >> 8; - buf_request[0x02] = req->addr & 0xff; - buf_request[0x03] = req->len; - memcpy (buf_request + 0x04, req->data, 28); - - /* send request */ - lu_dump_raw ("host->device", buf_request, sizeof (buf_request)); - if (usb_device != NULL) { - if (!g_usb_device_control_transfer (usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - LU_REQUEST_SET_REPORT, - 0x0200, 0x0000, - buf_request, - sizeof (buf_request), - &actual_length, - LU_DEVICE_TIMEOUT_MS, - NULL, - error)) { - g_prefix_error (error, "failed to send data: "); - return FALSE; - } - } - - /* no response required when rebooting */ - if (usb_device != NULL && - req->cmd == LU_DEVICE_BOOTLOADER_CMD_REBOOT) { - g_autoptr(GError) error_ignore = NULL; - if (!g_usb_device_interrupt_transfer (usb_device, - LU_DEVICE_EP1, - buf_response, - sizeof (buf_response), - &actual_length, - LU_DEVICE_TIMEOUT_MS, - NULL, - &error_ignore)) { - g_debug ("ignoring: %s", error_ignore->message); - } else { - lu_dump_raw ("device->host", buf_response, actual_length); - } - return TRUE; - } - - /* get response */ - memset (buf_response, 0x00, sizeof (buf_response)); - if (usb_device != NULL) { - if (!g_usb_device_interrupt_transfer (usb_device, - LU_DEVICE_EP1, - buf_response, - sizeof (buf_response), - &actual_length, - LU_DEVICE_TIMEOUT_MS, - NULL, - error)) { - g_prefix_error (error, "failed to get data: "); - return FALSE; - } - } else { - /* emulated */ - buf_response[0] = buf_request[0]; - if (buf_response[0] == LU_DEVICE_BOOTLOADER_CMD_GET_MEMINFO) { - buf_response[3] = 0x06; /* len */ - buf_response[4] = 0x40; /* lo MSB */ - buf_response[5] = 0x00; /* lo LSB */ - buf_response[6] = 0x6b; /* hi MSB */ - buf_response[7] = 0xff; /* hi LSB */ - buf_response[8] = 0x00; /* bs MSB */ - buf_response[9] = 0x80; /* bs LSB */ - } - actual_length = sizeof (buf_response); - } - lu_dump_raw ("device->host", buf_response, actual_length); - - /* parse response */ - if ((buf_response[0x00] & 0xf0) != req->cmd) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "invalid command response of %02x, expected %02x", - buf_response[0x00], req->cmd); - return FALSE; - } - req->cmd = buf_response[0x00]; - req->addr = ((guint16) buf_response[0x01] << 8) + buf_response[0x02]; - req->len = buf_response[0x03]; - if (req->len > 28) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "invalid data size of %02x", req->len); - return FALSE; - } - memset (req->data, 0x00, 28); - if (req->len > 0) - memcpy (req->data, buf_response + 0x04, req->len); - return TRUE; -} - -static void -lu_device_bootloader_init (LuDeviceBootloader *device) -{ - /* FIXME: we need something better */ - fu_device_add_icon (FU_DEVICE (device), "preferences-desktop-keyboard"); - fu_device_set_summary (FU_DEVICE (device), "A miniaturised USB wireless receiver (bootloader)"); -} - -static void -lu_device_bootloader_class_init (LuDeviceBootloaderClass *klass) -{ - LuDeviceClass *klass_device = LU_DEVICE_CLASS (klass); - klass_device->attach = lu_device_bootloader_attach; - klass_device->open = lu_device_bootloader_open; - klass_device->close = lu_device_bootloader_close; - klass_device->probe = lu_device_bootloader_probe; -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-bootloader.h fwupd-1.2.10/plugins/unifying/lu-device-bootloader.h --- fwupd-1.0.6/plugins/unifying/lu-device-bootloader.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-bootloader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_DEVICE_BOOTLOADER_H -#define __LU_DEVICE_BOOTLOADER_H - -#include - -#include "lu-device.h" - -G_BEGIN_DECLS - -#define LU_TYPE_DEVICE_BOOTLOADER (lu_device_bootloader_get_type ()) -G_DECLARE_DERIVABLE_TYPE (LuDeviceBootloader, lu_device_bootloader, LU, DEVICE_BOOTLOADER, LuDevice) - -struct _LuDeviceBootloaderClass -{ - LuDeviceClass parent_class; - gboolean (*probe) (LuDevice *device, - GError **error); -}; - -typedef enum { - LU_DEVICE_BOOTLOADER_CMD_GENERAL_ERROR = 0x01, - LU_DEVICE_BOOTLOADER_CMD_READ = 0x10, - LU_DEVICE_BOOTLOADER_CMD_WRITE = 0x20, - LU_DEVICE_BOOTLOADER_CMD_WRITE_INVALID_ADDR = 0x21, - LU_DEVICE_BOOTLOADER_CMD_WRITE_VERIFY_FAIL = 0x22, - LU_DEVICE_BOOTLOADER_CMD_WRITE_NONZERO_START = 0x23, - LU_DEVICE_BOOTLOADER_CMD_WRITE_INVALID_CRC = 0x24, - LU_DEVICE_BOOTLOADER_CMD_ERASE_PAGE = 0x30, - LU_DEVICE_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR = 0x31, - LU_DEVICE_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START = 0x33, - LU_DEVICE_BOOTLOADER_CMD_GET_HW_PLATFORM_ID = 0x40, - LU_DEVICE_BOOTLOADER_CMD_GET_FW_VERSION = 0x50, - LU_DEVICE_BOOTLOADER_CMD_GET_CHECKSUM = 0x60, - LU_DEVICE_BOOTLOADER_CMD_REBOOT = 0x70, - LU_DEVICE_BOOTLOADER_CMD_GET_MEMINFO = 0x80, - LU_DEVICE_BOOTLOADER_CMD_GET_BL_VERSION = 0x90, - LU_DEVICE_BOOTLOADER_CMD_GET_INIT_FW_VERSION = 0xa0, - LU_DEVICE_BOOTLOADER_CMD_READ_SIGNATURE = 0xb0, - LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER = 0xc0, - LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR = 0xc1, - LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW = 0xc2, - LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM = 0xd0, - LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR = 0xd1, - LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC = 0xd2, - LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID = 0xd3, - LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER = 0xd4, - LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE = 0xe0, - LU_DEVICE_BOOTLOADER_CMD_LAST -} LuDeviceBootloaderCmd; - -/* packet to and from device */ -typedef struct __attribute__((packed)) { - guint8 cmd; - guint16 addr; - guint8 len; - guint8 data[28]; -} LuDeviceBootloaderRequest; - -LuDeviceBootloaderRequest *lu_device_bootloader_request_new (void); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(LuDeviceBootloaderRequest, g_free); - -GPtrArray *lu_device_bootloader_parse_requests (LuDevice *device, - GBytes *fw, - GError **error); -gboolean lu_device_bootloader_request (LuDevice *device, - LuDeviceBootloaderRequest *req, - GError **error); - -guint16 lu_device_bootloader_get_addr_lo (LuDevice *device); -guint16 lu_device_bootloader_get_addr_hi (LuDevice *device); -void lu_device_bootloader_set_addr_lo (LuDevice *device, - guint16 addr); -void lu_device_bootloader_set_addr_hi (LuDevice *device, - guint16 addr); -guint16 lu_device_bootloader_get_blocksize (LuDevice *device); - -G_END_DECLS - -#endif /* __LU_DEVICE_BOOTLOADER_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-bootloader-nordic.c fwupd-1.2.10/plugins/unifying/lu-device-bootloader-nordic.c --- fwupd-1.0.6/plugins/unifying/lu-device-bootloader-nordic.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-bootloader-nordic.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,288 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include - -#include "lu-common.h" -#include "lu-device-bootloader-nordic.h" - -struct _LuDeviceBootloaderNordic -{ - LuDeviceBootloader parent_instance; -}; - -G_DEFINE_TYPE (LuDeviceBootloaderNordic, lu_device_bootloader_nordic, LU_TYPE_DEVICE_BOOTLOADER) - -static gchar * -lu_device_bootloader_nordic_get_hw_platform_id (LuDevice *device, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_GET_HW_PLATFORM_ID; - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to get HW ID: "); - return NULL; - } - return g_strndup ((const gchar *) req->data, req->len); -} - -static gchar * -lu_device_bootloader_nordic_get_fw_version (LuDevice *device, GError **error) -{ - guint16 micro; - - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_GET_FW_VERSION; - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to get firmware version: "); - return NULL; - } - - /* RRRxx.yy_Bzzzz - * 012345678901234*/ - micro = (guint16) lu_buffer_read_uint8 ((const gchar *) req->data + 10) << 8; - micro += lu_buffer_read_uint8 ((const gchar *) req->data + 12); - return lu_format_version ("RQR", - lu_buffer_read_uint8 ((const gchar *) req->data + 3), - lu_buffer_read_uint8 ((const gchar *) req->data + 6), - micro); -} - -static gboolean -lu_device_bootloader_nordic_probe (LuDevice *device, GError **error) -{ - g_autofree gchar *hw_platform_id = NULL; - g_autofree gchar *version_fw = NULL; - g_autoptr(GError) error_local = NULL; - - /* get MCU */ - hw_platform_id = lu_device_bootloader_nordic_get_hw_platform_id (device, error); - if (hw_platform_id == NULL) - return FALSE; - g_debug ("hw-platform-id=%s", hw_platform_id); - - /* get firmware version, which is not fatal */ - version_fw = lu_device_bootloader_nordic_get_fw_version (device, &error_local); - if (version_fw == NULL) { - g_warning ("failed to get firmware version: %s", - error_local->message); - fu_device_set_version (FU_DEVICE (device), "RQR12.xx_Bxxxx"); - } else { - fu_device_set_version (FU_DEVICE (device), version_fw); - } - - return TRUE; -} - -static gboolean -lu_device_bootloader_nordic_write_signature (LuDevice *device, - guint16 addr, guint8 len, const guint8 *data, - GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new(); - req->cmd = 0xC0; - req->addr = addr; - req->len = len; - memcpy (req->data, data, req->len); - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to write sig @0x%02x: ", addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: signature is too big", - addr); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_nordic_write (LuDevice *device, - guint16 addr, guint8 len, const guint8 *data, - GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_WRITE; - req->addr = addr; - req->len = len; - if (req->len > 28) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: data length too large %02x", - addr, req->len); - return FALSE; - } - memcpy (req->data, data, req->len); - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to transfer fw @0x%02x: ", addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_INVALID_ADDR) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: invalid address", - addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_VERIFY_FAIL) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: failed to verify flash content", - addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_NONZERO_START) { - g_debug ("wrote %d bytes at address %04x, value %02x", req->len, - req->addr, req->data[0]); - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: only 1 byte write of 0xff supported", - addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_INVALID_CRC) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write @%04x: invalid CRC", - addr); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_nordic_erase (LuDevice *device, guint16 addr, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_ERASE_PAGE; - req->addr = addr; - req->len = 0x01; - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to erase fw @0x%02x: ", addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_ERASE_PAGE_INVALID_ADDR) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to erase @%04x: invalid page", - addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_ERASE_PAGE_NONZERO_START) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to erase @%04x: byte 0x00 is not 0xff", - addr); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_nordic_write_firmware (LuDevice *device, GBytes *fw, GError **error) -{ - const LuDeviceBootloaderRequest *payload; - guint16 addr; - g_autoptr(GPtrArray) reqs = NULL; - - /* erase firmware pages up to the bootloader */ - for (addr = lu_device_bootloader_get_addr_lo (device); - addr < lu_device_bootloader_get_addr_hi (device); - addr += lu_device_bootloader_get_blocksize (device)) { - if (!lu_device_bootloader_nordic_erase (device, addr, error)) - return FALSE; - } - - /* transfer payload */ - reqs = lu_device_bootloader_parse_requests (device, fw, error); - if (reqs == NULL) - return FALSE; - - for (guint i = 1; i < reqs->len; i++) { - gboolean res; - payload = g_ptr_array_index (reqs, i); - - if (payload->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) { - res = lu_device_bootloader_nordic_write_signature(device, - payload->addr, - payload->len, - payload->data, - error); - } else { - res = lu_device_bootloader_nordic_write (device, - payload->addr, - payload->len, - payload->data, - error); - } - - if (!res) - return FALSE; - fu_device_set_progress_full (FU_DEVICE (device), i * 32, reqs->len * 32); - } - - /* send the first managed packet last, excluding the reset vector */ - payload = g_ptr_array_index (reqs, 0); - if (!lu_device_bootloader_nordic_write (device, - payload->addr + 1, - payload->len - 1, - payload->data + 1, - error)) - return FALSE; - - if (!lu_device_bootloader_nordic_write (device, - 0x0000, - 0x01, - payload->data, - error)) - return FALSE; - - /* mark as complete */ - fu_device_set_progress_full (FU_DEVICE (device), reqs->len * 32, reqs->len * 32); - - /* success! */ - return TRUE; -} - -static void -lu_device_bootloader_nordic_class_init (LuDeviceBootloaderNordicClass *klass) -{ - LuDeviceClass *klass_device = LU_DEVICE_CLASS (klass); - LuDeviceBootloaderClass *klass_device_bootloader = LU_DEVICE_BOOTLOADER_CLASS (klass); - klass_device->write_firmware = lu_device_bootloader_nordic_write_firmware; - klass_device_bootloader->probe = lu_device_bootloader_nordic_probe; -} - -static void -lu_device_bootloader_nordic_init (LuDeviceBootloaderNordic *device) -{ -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-bootloader-nordic.h fwupd-1.2.10/plugins/unifying/lu-device-bootloader-nordic.h --- fwupd-1.0.6/plugins/unifying/lu-device-bootloader-nordic.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-bootloader-nordic.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_DEVICE_BOOTLOADER_NORDIC_H -#define __LU_DEVICE_BOOTLOADER_NORDIC_H - -#include "lu-device-bootloader.h" - -G_BEGIN_DECLS - -#define LU_TYPE_DEVICE_BOOTLOADER_NORDIC (lu_device_bootloader_nordic_get_type ()) -G_DECLARE_FINAL_TYPE (LuDeviceBootloaderNordic, lu_device_bootloader_nordic, LU, DEVICE_BOOTLOADER_NORDIC, LuDeviceBootloader) - -G_END_DECLS - -#endif /* __LU_DEVICE_BOOTLOADER_NORDIC_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-bootloader-texas.c fwupd-1.2.10/plugins/unifying/lu-device-bootloader-texas.c --- fwupd-1.0.6/plugins/unifying/lu-device-bootloader-texas.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-bootloader-texas.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include - -#include "lu-common.h" -#include "lu-device-bootloader-texas.h" - -struct _LuDeviceBootloaderTexas -{ - LuDeviceBootloader parent_instance; -}; - -G_DEFINE_TYPE (LuDeviceBootloaderTexas, lu_device_bootloader_texas, LU_TYPE_DEVICE_BOOTLOADER) - -static gboolean -lu_device_bootloader_texas_erase_all (LuDevice *device, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM; - req->len = 0x01; /* magic number */ - req->data[0] = 0x00; /* magic number */ - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to erase all pages: "); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_texas_compute_and_test_crc (LuDevice *device, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM; - req->len = 0x01; /* magic number */ - req->data[0] = 0x03; /* magic number */ - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to compute and test CRC: "); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_WRONG_CRC) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "CRC is incorrect"); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_texas_flash_ram_buffer (LuDevice *device, guint16 addr, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM; - req->addr = addr; - req->len = 0x01; /* magic number */ - req->data[0] = 0x01; /* magic number */ - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to flash ram buffer @%04x: ", addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_INVALID_ADDR) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to flash ram buffer @%04x: invalid flash page", - addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_PAGE0_INVALID) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to flash ram buffer @%04x: invalid App JMP vector", - addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM_INVALID_ORDER) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to flash ram buffer @%04x: page flashed before page 0", - addr); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_texas_clear_ram_buffer (LuDevice *device, guint16 addr, GError **error) -{ - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - req->cmd = LU_DEVICE_BOOTLOADER_CMD_FLASH_RAM; - req->addr = addr; - req->len = 0x01; /* magic number */ - req->data[0] = 0x02; /* magic number */ - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, "failed to clear ram buffer @%04x: ", addr); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_bootloader_texas_write_firmware (LuDevice *device, GBytes *fw, GError **error) -{ - const LuDeviceBootloaderRequest *payload; - g_autoptr(GPtrArray) reqs = NULL; - g_autoptr(LuDeviceBootloaderRequest) req = lu_device_bootloader_request_new (); - - /* transfer payload */ - reqs = lu_device_bootloader_parse_requests (device, fw, error); - if (reqs == NULL) - return FALSE; - - /* erase all flash pages */ - if (!lu_device_bootloader_texas_erase_all (device, error)) - return FALSE; - - /* set existing RAM buffer to 0xff's */ - if (!lu_device_bootloader_texas_clear_ram_buffer (device, 0x0000, error)) - return FALSE; - - /* transfer payload */ - for (guint i = 0; i < reqs->len; i++) { - payload = g_ptr_array_index (reqs, i); - - /* check size */ - if (payload->len != 16) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "payload size invalid @%04x: got 0x%02x", - payload->addr, payload->len); - return FALSE; - } - - /* build packet */ - req->cmd = payload->cmd; - - /* signature addresses do not need to fit inside 128 bytes */ - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) - req->addr = payload->addr; - else - req->addr = payload->addr % 0x80; - - req->len = payload->len; - memcpy (req->data, payload->data, payload->len); - if (!lu_device_bootloader_request (device, req, error)) { - g_prefix_error (error, - "failed to write ram bufer @0x%02x: ", - req->addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER_INVALID_ADDR) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write ram buffer @%04x: invalid location", - req->addr); - return FALSE; - } - if (req->cmd == LU_DEVICE_BOOTLOADER_CMD_WRITE_RAM_BUFFER_OVERFLOW) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to write ram buffer @%04x: invalid size 0x%02x", - req->addr, req->len); - return FALSE; - } - - /* flush RAM buffer to EEPROM */ - if ((payload->addr + 0x10) % 0x80 == 0 && - req->cmd != LU_DEVICE_BOOTLOADER_CMD_WRITE_SIGNATURE) { - guint16 addr_start = payload->addr - (7 * 0x10); - g_debug ("addr flush @ 0x%04x for 0x%04x", - payload->addr, addr_start); - if (!lu_device_bootloader_texas_flash_ram_buffer (device, - addr_start, - error)) { - g_prefix_error (error, - "failed to flash ram buffer @0x%04x: ", - addr_start); - return FALSE; - } - } - - /* update progress */ - fu_device_set_progress_full (FU_DEVICE (device), i * 32, reqs->len * 32); - } - - /* check CRC */ - if (!lu_device_bootloader_texas_compute_and_test_crc (device, error)) - return FALSE; - - /* mark as complete */ - fu_device_set_progress_full (FU_DEVICE (device), reqs->len * 32, reqs->len * 32); - - /* success! */ - return TRUE; -} - -static void -lu_device_bootloader_texas_class_init (LuDeviceBootloaderTexasClass *klass) -{ - LuDeviceClass *klass_device = LU_DEVICE_CLASS (klass); - klass_device->write_firmware = lu_device_bootloader_texas_write_firmware; -} - -static void -lu_device_bootloader_texas_init (LuDeviceBootloaderTexas *device) -{ - fu_device_set_version (FU_DEVICE (device), "RQR24.xx_Bxxxx"); -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-bootloader-texas.h fwupd-1.2.10/plugins/unifying/lu-device-bootloader-texas.h --- fwupd-1.0.6/plugins/unifying/lu-device-bootloader-texas.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-bootloader-texas.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_DEVICE_BOOTLOADER_TEXAS_H -#define __LU_DEVICE_BOOTLOADER_TEXAS_H - -#include "lu-device-bootloader.h" - -G_BEGIN_DECLS - -#define LU_TYPE_DEVICE_BOOTLOADER_TEXAS (lu_device_bootloader_texas_get_type ()) -G_DECLARE_FINAL_TYPE (LuDeviceBootloaderTexas, lu_device_bootloader_texas, LU, DEVICE_BOOTLOADER_TEXAS, LuDeviceBootloader) - -G_END_DECLS - -#endif /* __LU_DEVICE_BOOTLOADER_TEXAS_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-device.c fwupd-1.2.10/plugins/unifying/lu-device.c --- fwupd-1.0.6/plugins/unifying/lu-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1133 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "lu-common.h" -#include "lu-device-bootloader-nordic.h" -#include "lu-device-bootloader-texas.h" -#include "lu-device.h" -#include "lu-device-runtime.h" -#include "lu-hidpp.h" - -typedef struct -{ - LuDeviceKind kind; - GUdevDevice *udev_device; - gint udev_device_fd; - GUsbDevice *usb_device; - FuDeviceLocker *usb_device_locker; - gchar *version_hw; - LuDeviceFlags flags; - guint8 hidpp_id; - guint8 battery_level; - gdouble hidpp_version; - GPtrArray *feature_index; -} LuDevicePrivate; - -typedef struct { - guint8 idx; - guint16 feature; -} LuDeviceHidppMap; - -G_DEFINE_TYPE_WITH_PRIVATE (LuDevice, lu_device, FU_TYPE_DEVICE) - -enum { - PROP_0, - PROP_KIND, - PROP_HIDPP_ID, - PROP_FLAGS, - PROP_UDEV_DEVICE, - PROP_USB_DEVICE, - PROP_LAST -}; - -#define GET_PRIVATE(o) (lu_device_get_instance_private (o)) - -LuDeviceKind -lu_device_kind_from_string (const gchar *kind) -{ - if (g_strcmp0 (kind, "runtime") == 0) - return LU_DEVICE_KIND_RUNTIME; - if (g_strcmp0 (kind, "bootloader-nordic") == 0) - return LU_DEVICE_KIND_BOOTLOADER_NORDIC; - if (g_strcmp0 (kind, "bootloader-texas") == 0) - return LU_DEVICE_KIND_BOOTLOADER_TEXAS; - if (g_strcmp0 (kind, "peripheral") == 0) - return LU_DEVICE_KIND_PERIPHERAL; - return LU_DEVICE_KIND_UNKNOWN; -} - -const gchar * -lu_device_kind_to_string (LuDeviceKind kind) -{ - if (kind == LU_DEVICE_KIND_RUNTIME) - return "runtime"; - if (kind == LU_DEVICE_KIND_BOOTLOADER_NORDIC) - return "bootloader-nordic"; - if (kind == LU_DEVICE_KIND_BOOTLOADER_TEXAS) - return "bootloader-texas"; - if (kind == LU_DEVICE_KIND_PERIPHERAL) - return "peripheral"; - return NULL; -} - -static const gchar * -lu_hidpp_feature_to_string (guint16 feature) -{ - if (feature == HIDPP_FEATURE_ROOT) - return "Root"; - if (feature == HIDPP_FEATURE_I_FIRMWARE_INFO) - return "IFirmwareInfo"; - if (feature == HIDPP_FEATURE_GET_DEVICE_NAME_TYPE) - return "GetDevicenameType"; - if (feature == HIDPP_FEATURE_BATTERY_LEVEL_STATUS) - return "BatteryLevelStatus"; - if (feature == HIDPP_FEATURE_DFU_CONTROL) - return "DfuControl"; - if (feature == HIDPP_FEATURE_DFU_CONTROL_SIGNED) - return "DfuControlSigned"; - if (feature == HIDPP_FEATURE_DFU) - return "Dfu"; - return NULL; -} - -static gchar * -lu_device_flags_to_string (LuDeviceFlags flags) -{ - GString *str = g_string_new (NULL); - if (flags & LU_DEVICE_FLAG_REQUIRES_SIGNED_FIRMWARE) - g_string_append (str, "signed-firmware,"); - if (flags & LU_DEVICE_FLAG_REQUIRES_RESET) - g_string_append (str, "requires-reset,"); - if (flags & LU_DEVICE_FLAG_ACTIVE) - g_string_append (str, "active,"); - if (flags & LU_DEVICE_FLAG_IS_OPEN) - g_string_append (str, "is-open,"); - if (flags & LU_DEVICE_FLAG_REQUIRES_ATTACH) - g_string_append (str, "requires-attach,"); - if (flags & LU_DEVICE_FLAG_REQUIRES_DETACH) - g_string_append (str, "requires-detach,"); - if (flags & LU_DEVICE_FLAG_DETACH_WILL_REPLUG) - g_string_append (str, "detach-will-replug,"); - if (str->len == 0) { - g_string_append (str, "none"); - } else { - g_string_truncate (str, str->len - 1); - } - return g_string_free (str, FALSE); -} - -static void -lu_device_to_string (FuDevice *device, GString *str) -{ - LuDevice *self = LU_DEVICE (device); - LuDevicePrivate *priv = GET_PRIVATE (self); - g_autofree gchar *flags_str = NULL; - - g_string_append_printf (str, " Type:\t\t\t%s\n", lu_device_kind_to_string (priv->kind)); - flags_str = lu_device_flags_to_string (priv->flags); - g_string_append_printf (str, " Flags:\t\t%s\n", flags_str); - g_string_append_printf (str, " HidppVersion:\t\t%.2f\n", priv->hidpp_version); - if (priv->hidpp_id != HIDPP_DEVICE_ID_UNSET) - g_string_append_printf (str, " HidppId:\t\t0x%02x\n", (guint) priv->hidpp_id); - if (priv->udev_device_fd > 0) - g_string_append_printf (str, " UdevDevice:\t\t%i\n", priv->udev_device_fd); - if (priv->usb_device != NULL) - g_string_append_printf (str, " UsbDevice:\t\t%p\n", priv->usb_device); - if (priv->version_hw != NULL) - g_string_append_printf (str, " VersionHardware:\t%s\n", priv->version_hw); - if (priv->battery_level != 0) - g_string_append_printf (str, " Battery-level:\t\t%u\n", priv->battery_level); - for (guint i = 0; i < priv->feature_index->len; i++) { - LuDeviceHidppMap *map = g_ptr_array_index (priv->feature_index, i); - g_string_append_printf (str, " Feature%02x:\t\t%s [0x%04x]\n", - map->idx, - lu_hidpp_feature_to_string (map->feature), - map->feature); - } - - /* fixme: superclass? */ - if (LU_IS_DEVICE_BOOTLOADER (device)) { - g_string_append_printf (str, " FlashAddrHigh:\t0x%04x\n", - lu_device_bootloader_get_addr_hi (self)); - g_string_append_printf (str, " FlashAddrLow:\t0x%04x\n", - lu_device_bootloader_get_addr_lo (self)); - g_string_append_printf (str, " FlashBlockSize:\t0x%04x\n", - lu_device_bootloader_get_blocksize (self)); - } -} - -guint8 -lu_device_hidpp_feature_get_idx (LuDevice *device, guint16 feature) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - for (guint i = 0; i < priv->feature_index->len; i++) { - LuDeviceHidppMap *map = g_ptr_array_index (priv->feature_index, i); - if (map->feature == feature) - return map->idx; - } - return 0x00; -} - -guint16 -lu_device_hidpp_feature_find_by_idx (LuDevice *device, guint8 idx) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - for (guint i = 0; i < priv->feature_index->len; i++) { - LuDeviceHidppMap *map = g_ptr_array_index (priv->feature_index, i); - if (map->idx == idx) - return map->feature; - } - return 0x0000; -} - -static void -lu_device_hidpp_dump (LuDevice *device, const gchar *title, const guint8 *data, gsize len) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - g_autofree gchar *title_prefixed = NULL; - if (priv->usb_device != NULL) - title_prefixed = g_strdup_printf ("[USB] %s", title); - else if (priv->udev_device != NULL) - title_prefixed = g_strdup_printf ("[HID] %s", title); - else - title_prefixed = g_strdup_printf ("[EMU] %s", title); - lu_dump_raw (title_prefixed, data, len); -} - -static const gchar * -lu_device_hidpp20_function_to_string (guint16 feature, guint8 function_id) -{ - if (feature == HIDPP_FEATURE_ROOT) { - if (function_id == 0x00) - return "getFeature"; - if (function_id == 0x01) - return "ping"; - return NULL; - } - if (feature == HIDPP_FEATURE_I_FIRMWARE_INFO) { - if (function_id == 0x00) - return "getCount"; - if (function_id == 0x01) - return "getInfo"; - return NULL; - } - if (feature == HIDPP_FEATURE_BATTERY_LEVEL_STATUS) { - if (function_id == 0x00) - return "GetBatteryLevelStatus"; - return NULL; - } - if (feature == HIDPP_FEATURE_DFU_CONTROL) { - if (function_id == 0x00) - return "getDfuControl"; - if (function_id == 0x01) - return "setDfuControl"; - return NULL; - } - if (feature == HIDPP_FEATURE_DFU_CONTROL_SIGNED) { - if (function_id == 0x00) - return "getDfuStatus"; - if (function_id == 0x01) - return "startDfu"; - return NULL; - } - if (feature == HIDPP_FEATURE_DFU) { - if (function_id == 0x00) - return "dfuCmdData0"; - if (function_id == 0x01) - return "dfuCmdData1"; - if (function_id == 0x02) - return "dfuCmdData2"; - if (function_id == 0x03) - return "dfuCmdData3"; - if (function_id == 0x04) - return "dfuStart"; - if (function_id == 0x05) - return "restart"; - return NULL; - } - return NULL; -} - -static gchar * -lu_device_hidpp_msg_to_string (LuDevice *device, LuHidppMsg *msg) -{ - GString *str = g_string_new (NULL); - LuDevicePrivate *priv = GET_PRIVATE (device); - const gchar *tmp; - const gchar *kind_str = lu_device_kind_to_string (priv->kind); - g_autoptr(GError) error = NULL; - g_autoptr(GString) flags_str = g_string_new (NULL); - - g_return_val_if_fail (msg != NULL, NULL); - - g_string_append_printf (str, "device-kind: %s\n", kind_str); - if (msg->flags == LU_HIDPP_MSG_FLAG_NONE) { - g_string_append (flags_str, "none"); - } else { - if (msg->flags & LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT) - g_string_append (flags_str, "longer-timeout,"); - if (msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID) - g_string_append (flags_str, "ignore-sub-id,"); - if (msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID) - g_string_append (flags_str, "ignore-fnct-id,"); - if (msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_SWID) - g_string_append (flags_str, "ignore-swid,"); - if (str->len > 0) - g_string_truncate (str, str->len - 1); - } - g_string_append_printf (str, "flags: %02x [%s]\n", - msg->flags, - flags_str->str); - g_string_append_printf (str, "report-id: %02x [%s]\n", - msg->report_id, - lu_hidpp_msg_rpt_id_to_string (msg)); - tmp = lu_hidpp_msg_dev_id_to_string (msg); - g_string_append_printf (str, "device-id: %02x [%s]\n", - msg->device_id, tmp ); - if (priv->hidpp_version >= 2.f) { - guint16 feature = lu_device_hidpp_feature_find_by_idx (device, msg->sub_id); - guint8 sw_id = msg->function_id & 0x0f; - guint8 function_id = (msg->function_id & 0xf0) >> 4; - g_string_append_printf (str, "feature: %04x [%s]\n", - feature, - lu_hidpp_feature_to_string (feature)); - g_string_append_printf (str, "function-id: %02x [%s]\n", - function_id, - lu_device_hidpp20_function_to_string (feature, function_id)); - g_string_append_printf (str, "sw-id: %02x [%s]\n", - sw_id, - sw_id == LU_HIDPP_MSG_SW_ID ? "fwupd" : "???"); - } else { - g_string_append_printf (str, "sub-id: %02x [%s]\n", - msg->sub_id, - lu_hidpp_msg_sub_id_to_string (msg)); - g_string_append_printf (str, "function-id: %02x [%s]\n", - msg->function_id, - lu_hidpp_msg_fcn_id_to_string (msg)); - } - if (!lu_hidpp_msg_is_error (msg, &error)) { - g_string_append_printf (str, "error: %s\n", - error->message); - } - return g_string_free (str, FALSE); -} - -gboolean -lu_device_hidpp_send (LuDevice *device, - LuHidppMsg *msg, - guint timeout, - GError **error) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - gsize len = lu_hidpp_msg_get_payload_length (msg); - - /* only for HID++2.0 */ - if (lu_device_get_hidpp_version (device) >= 2.f) - msg->function_id |= LU_HIDPP_MSG_SW_ID; - - lu_device_hidpp_dump (device, "host->device", (guint8 *) msg, len); - - /* detailed debugging */ - if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { - g_autofree gchar *str = lu_device_hidpp_msg_to_string (device, msg); - g_print ("%s", str); - } - - /* USB */ - if (priv->usb_device != NULL) { - gsize actual_length = 0; - if (!g_usb_device_control_transfer (priv->usb_device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - LU_REQUEST_SET_REPORT, - 0x0210, 0x0002, - (guint8 *) msg, len, - &actual_length, - timeout, - NULL, - error)) { - g_prefix_error (error, "failed to send data: "); - return FALSE; - } - if (actual_length != len) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to send data: " - "wrote %" G_GSIZE_FORMAT " of %" G_GSIZE_FORMAT, - actual_length, len); - return FALSE; - } - - /* HID */ - } else if (priv->udev_device != NULL) { - if (!lu_nonblock_write (priv->udev_device_fd, - (guint8 *) msg, len, error)) { - g_prefix_error (error, "failed to send: "); - return FALSE; - } - } - - /* success */ - return TRUE; -} - -gboolean -lu_device_hidpp_receive (LuDevice *device, - LuHidppMsg *msg, - guint timeout, - GError **error) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - gsize read_size = 0; - - /* USB */ - if (priv->usb_device != NULL) { - if (!g_usb_device_interrupt_transfer (priv->usb_device, - LU_DEVICE_EP3, - (guint8 *) msg, - sizeof(LuHidppMsg), - &read_size, - timeout, - NULL, - error)) { - g_prefix_error (error, "failed to get data: "); - return FALSE; - } - - /* HID */ - } else if (priv->udev_device != NULL) { - if (!lu_nonblock_read (priv->udev_device_fd, - (guint8 *) msg, - sizeof(LuHidppMsg), - &read_size, - timeout, - error)) { - g_prefix_error (error, "failed to receive: "); - return FALSE; - } - } - - /* check long enough, but allow returning oversize packets */ - lu_device_hidpp_dump (device, "device->host", (guint8 *) msg, read_size); - if (read_size < lu_hidpp_msg_get_payload_length (msg)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "message length too small, " - "got %" G_GSIZE_FORMAT " expected %" G_GSIZE_FORMAT, - read_size, lu_hidpp_msg_get_payload_length (msg)); - return FALSE; - } - - /* detailed debugging */ - if (g_getenv ("FWUPD_UNIFYING_VERBOSE") != NULL) { - g_autofree gchar *str = lu_device_hidpp_msg_to_string (device, msg); - g_print ("%s", str); - } - - /* success */ - return TRUE; -} - -gboolean -lu_device_hidpp_transfer (LuDevice *device, LuHidppMsg *msg, GError **error) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - guint timeout = LU_DEVICE_TIMEOUT_MS; - g_autoptr(LuHidppMsg) msg_tmp = lu_hidpp_msg_new (); - - /* increase timeout for some operations */ - if (msg->flags & LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT) - timeout *= 10; - - /* send request */ - if (!lu_device_hidpp_send (device, msg, timeout, error)) - return FALSE; - - /* keep trying to receive until we get a valid reply */ - while (1) { - if (!lu_device_hidpp_receive (device, msg_tmp, timeout, error)) - return FALSE; - - /* we don't know how to handle this report packet */ - if (lu_hidpp_msg_get_payload_length (msg_tmp) == 0x0) { - g_debug ("HID++1.0 report 0x%02x has unknown length, ignoring", - msg_tmp->report_id); - continue; - } - - if (!lu_hidpp_msg_is_error (msg_tmp, error)) - return FALSE; - - /* is valid reply */ - if (lu_hidpp_msg_is_reply (msg, msg_tmp)) - break; - - /* to ensure compatibility when an HID++ 2.0 device is - * connected to an HID++ 1.0 receiver, any feature index - * corresponding to an HID++ 1.0 sub-identifier which could be - * sent by the receiver, must be assigned to a dummy feature */ - if (lu_device_get_hidpp_version (device) >= 2.f) { - if (lu_hidpp_msg_is_hidpp10_compat (msg_tmp)) { - g_debug ("ignoring HID++1.0 reply"); - continue; - } - - /* not us */ - if ((msg->flags & LU_HIDPP_MSG_FLAG_IGNORE_SWID) == 0) { - if (!lu_hidpp_msg_verify_swid (msg_tmp)) { - g_debug ("ignoring reply with SwId 0x%02i, expected 0x%02i", - msg_tmp->function_id & 0x0f, - LU_HIDPP_MSG_SW_ID); - continue; - } - } - } - - g_debug ("ignoring message"); - - }; - - /* if the HID++ ID is unset, grab it from the reply */ - if (priv->hidpp_id == HIDPP_DEVICE_ID_UNSET) { - priv->hidpp_id = msg_tmp->device_id; - g_debug ("HID++ ID now %02x", priv->hidpp_id); - } - - /* copy over data */ - lu_hidpp_msg_copy (msg, msg_tmp); - return TRUE; -} - -gboolean -lu_device_hidpp_feature_search (LuDevice *device, guint16 feature, GError **error) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - LuDeviceHidppMap *map; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* find the idx for the feature */ - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = priv->hidpp_id; - msg->sub_id = 0x00; /* rootIndex */ - msg->function_id = 0x00 << 4; /* getFeature */ - msg->data[0] = feature >> 8; - msg->data[1] = feature; - msg->data[2] = 0x00; - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, - "failed to get idx for feature %s [0x%04x]: ", - lu_hidpp_feature_to_string (feature), feature); - return FALSE; - } - - /* zero index */ - if (msg->data[0] == 0x00) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "feature %s [0x%04x] not found", - lu_hidpp_feature_to_string (feature), feature); - return FALSE; - } - - /* add to map */ - map = g_new0 (LuDeviceHidppMap, 1); - map->idx = msg->data[0]; - map->feature = feature; - g_ptr_array_add (priv->feature_index, map); - g_debug ("added feature %s [0x%04x] as idx %02x", - lu_hidpp_feature_to_string (feature), feature, map->idx); - return TRUE; -} - -LuDeviceKind -lu_device_get_kind (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->kind; -} - -guint8 -lu_device_get_hidpp_id (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->hidpp_id; -} - -void -lu_device_set_hidpp_id (LuDevice *device, guint8 hidpp_id) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - priv->hidpp_id = hidpp_id; -} - -guint8 -lu_device_get_battery_level (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->battery_level; -} - -void -lu_device_set_battery_level (LuDevice *device, guint8 percentage) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - priv->battery_level = percentage; -} - -gdouble -lu_device_get_hidpp_version (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->hidpp_version; -} - -void -lu_device_set_hidpp_version (LuDevice *device, gdouble hidpp_version) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - priv->hidpp_version = hidpp_version; -} - -const gchar * -lu_device_get_version_hw (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->version_hw; -} - -void -lu_device_set_version_hw (LuDevice *device, const gchar *version_hw) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - g_free (priv->version_hw); - priv->version_hw = g_strdup (version_hw); -} - -gboolean -lu_device_has_flag (LuDevice *device, LuDeviceFlags flag) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return (priv->flags & flag) > 0; -} - -void -lu_device_add_flag (LuDevice *device, LuDeviceFlags flag) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - priv->flags |= flag; - g_object_notify (G_OBJECT (device), "flags"); -} - -void -lu_device_remove_flag (LuDevice *device, LuDeviceFlags flag) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - priv->flags &= ~flag; - g_object_notify (G_OBJECT (device), "flags"); -} - -LuDeviceFlags -lu_device_get_flags (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->flags; -} - -GUdevDevice * -lu_device_get_udev_device (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->udev_device; -} - -GUsbDevice * -lu_device_get_usb_device (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - return priv->usb_device; -} - -gboolean -lu_device_probe (LuDevice *device, GError **error) -{ - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - LuDevicePrivate *priv = GET_PRIVATE (device); - - /* clear the feature map (leaving only the root) */ - g_ptr_array_set_size (priv->feature_index, 0); - - /* probe the hardware */ - if (klass->probe != NULL) - return klass->probe (device, error); - return TRUE; -} - -gboolean -lu_device_open (LuDevice *device, GError **error) -{ - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - LuDevicePrivate *priv = GET_PRIVATE (device); - g_autofree gchar *device_str = NULL; - - g_return_val_if_fail (LU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* already done */ - if (lu_device_has_flag (device, LU_DEVICE_FLAG_IS_OPEN)) - return TRUE; - - /* set default vendor */ - fu_device_set_vendor (FU_DEVICE (device), "Logitech"); - - /* USB */ - if (priv->usb_device != NULL) { - guint8 num_interfaces = 0x01; - g_autofree gchar *devid = NULL; - - /* open device */ - if (priv->usb_device_locker == NULL) { - g_autoptr(FuDeviceLocker) locker = NULL; - g_debug ("opening unifying device using USB"); - locker = fu_device_locker_new (priv->usb_device, error); - if (locker == NULL) - return FALSE; - if (priv->kind == LU_DEVICE_KIND_RUNTIME) - num_interfaces = 0x03; - for (guint i = 0; i < num_interfaces; i++) { - g_debug ("claiming interface 0x%02x", i); - if (!g_usb_device_claim_interface (priv->usb_device, i, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - error)) { - g_prefix_error (error, "Failed to claim 0x%02x: ", i); - return FALSE; - } - } - priv->usb_device_locker = g_steal_pointer (&locker); - } - - /* generate GUID */ - devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - g_usb_device_get_vid (priv->usb_device), - g_usb_device_get_pid (priv->usb_device)); - fu_device_add_guid (FU_DEVICE (device), devid); - - /* HID */ - } else if (priv->udev_device != NULL) { - const gchar *devpath = g_udev_device_get_device_file (priv->udev_device); - g_debug ("opening unifying device using %s", devpath); - priv->udev_device_fd = lu_nonblock_open (devpath, error); - if (priv->udev_device_fd < 0) - return FALSE; - } - - /* subclassed */ - if (klass->open != NULL) { - if (!klass->open (device, error)) { - lu_device_close (device, NULL); - return FALSE; - } - } - lu_device_add_flag (device, LU_DEVICE_FLAG_IS_OPEN); - - /* subclassed */ - if (!lu_device_probe (device, error)) { - lu_device_close (device, NULL); - return FALSE; - } - - /* add known root for HID++2.0 */ - if (lu_device_get_hidpp_version (device) >= 2.f) { - LuDeviceHidppMap *map = g_new0 (LuDeviceHidppMap, 1); - map->idx = 0x00; - map->feature = HIDPP_FEATURE_ROOT; - g_ptr_array_add (priv->feature_index, map); - } - - /* show the device */ - device_str = fu_device_to_string (FU_DEVICE (device)); - g_debug ("%s", device_str); - - /* success */ - return TRUE; -} - -gboolean -lu_device_poll (LuDevice *device, GError **error) -{ - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - if (klass->poll != NULL) { - if (!klass->poll (device, error)) - return FALSE; - } - return TRUE; -} - -/** - * lu_device_close: - * @device: A #LuDevice - * @error: A #GError, or %NULL - * - * Closes the device. - * - * Returns: %TRUE for success - **/ -gboolean -lu_device_close (LuDevice *device, GError **error) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - - g_return_val_if_fail (LU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* not open */ - if (!lu_device_has_flag (device, LU_DEVICE_FLAG_IS_OPEN)) - return TRUE; - - /* subclassed */ - g_debug ("closing device"); - if (klass->close != NULL) { - if (!klass->close (device, error)) - return FALSE; - } - - /* USB */ - if (priv->usb_device_locker != NULL) { - guint8 num_interfaces = 0x01; - if (priv->kind == LU_DEVICE_KIND_RUNTIME) - num_interfaces = 0x03; - for (guint i = 0; i < num_interfaces; i++) { - g_autoptr(GError) error_local = NULL; - g_debug ("releasing interface 0x%02x", i); - if (!g_usb_device_release_interface (priv->usb_device, i, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - &error_local)) { - if (!g_error_matches (error_local, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_INTERNAL)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Failed to release 0x%02x: %s", - i, error_local->message); - return FALSE; - } - } - } - g_clear_object (&priv->usb_device_locker); - } - g_clear_object (&priv->usb_device); - - /* HID */ - if (priv->udev_device != NULL && priv->udev_device_fd > 0) { - if (!g_close (priv->udev_device_fd, error)) - return FALSE; - priv->udev_device_fd = 0; - } - - /* success */ - lu_device_remove_flag (device, LU_DEVICE_FLAG_IS_OPEN); - return TRUE; -} -gboolean -lu_device_detach (LuDevice *device, GError **error) -{ - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - - g_return_val_if_fail (LU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* subclassed */ - g_debug ("detaching device"); - if (klass->detach != NULL) - return klass->detach (device, error); - - /* nothing to do */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "device detach is not supported"); - return FALSE; -} - -gboolean -lu_device_attach (LuDevice *device, GError **error) -{ - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - - g_return_val_if_fail (LU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* check kind */ - if (lu_device_get_kind (device) == LU_DEVICE_KIND_RUNTIME) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "device is not in bootloader state"); - return FALSE; - } - - /* subclassed */ - if (klass->attach != NULL) - return klass->attach (device, error); - - return TRUE; -} - -gboolean -lu_device_write_firmware (LuDevice *device, GBytes *fw, GError **error) -{ - LuDeviceClass *klass = LU_DEVICE_GET_CLASS (device); - - g_return_val_if_fail (LU_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* corrupt */ - if (g_bytes_get_size (fw) < 0x4000) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "firmware is too small"); - return FALSE; - } - - /* call device-specific method */ - if (klass->write_firmware == NULL) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "not supported in %s", - lu_device_kind_to_string (lu_device_get_kind (device))); - return FALSE; - } - - /* call either nordic or texas vfunc */ - return klass->write_firmware (device, fw, error); -} - -#ifndef HAVE_GUDEV_232 -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref) -#endif - -static GUdevDevice * -lu_device_find_udev_device (GUsbDevice *usb_device) -{ - g_autoptr(GUdevClient) gudev_client = g_udev_client_new (NULL); - g_autoptr(GList) devices = NULL; - - devices = g_udev_client_query_by_subsystem (gudev_client, "usb"); - for (GList *l = devices; l != NULL; l = l->next) { - guint busnum; - guint devnum; - g_autoptr(GUdevDevice) udev_device = G_UDEV_DEVICE (l->data); - g_autoptr(GUdevDevice) udev_parent = g_udev_device_get_parent (udev_device); - - busnum = g_udev_device_get_sysfs_attr_as_int (udev_parent, "busnum"); - if (busnum != g_usb_device_get_bus (usb_device)) - continue; - devnum = g_udev_device_get_sysfs_attr_as_int (udev_parent, "devnum"); - if (devnum != g_usb_device_get_address (usb_device)) - continue; - - return g_object_ref (udev_parent); - } - return NULL; -} - -static void -lu_device_update_platform_id (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - if (priv->usb_device != NULL && priv->udev_device == NULL) { - g_autoptr(GUdevDevice) udev_device = NULL; - udev_device = lu_device_find_udev_device (priv->usb_device); - if (udev_device != NULL) { - const gchar *tmp = g_udev_device_get_sysfs_path (udev_device); - fu_device_set_platform_id (FU_DEVICE (device), tmp); - } - } -} - -static void -lu_device_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - LuDevice *device = LU_DEVICE (object); - LuDevicePrivate *priv = GET_PRIVATE (device); - switch (prop_id) { - case PROP_KIND: - g_value_set_uint (value, priv->kind); - break; - case PROP_HIDPP_ID: - g_value_set_uint (value, priv->hidpp_id); - break; - case PROP_FLAGS: - g_value_set_uint64 (value, priv->flags); - break; - case PROP_UDEV_DEVICE: - g_value_set_object (value, priv->udev_device); - break; - case PROP_USB_DEVICE: - g_value_set_object (value, priv->usb_device); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -lu_device_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - LuDevice *device = LU_DEVICE (object); - LuDevicePrivate *priv = GET_PRIVATE (device); - switch (prop_id) { - case PROP_KIND: - priv->kind = g_value_get_uint (value); - break; - case PROP_HIDPP_ID: - priv->hidpp_id = g_value_get_uint (value); - break; - case PROP_FLAGS: - priv->flags = g_value_get_uint64 (value); - break; - case PROP_UDEV_DEVICE: - priv->udev_device = g_value_dup_object (value); - break; - case PROP_USB_DEVICE: - priv->usb_device = g_value_dup_object (value); - lu_device_update_platform_id (device); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -lu_device_finalize (GObject *object) -{ - LuDevice *device = LU_DEVICE (object); - LuDevicePrivate *priv = GET_PRIVATE (device); - - if (priv->usb_device != NULL) - g_object_unref (priv->usb_device); - if (priv->usb_device_locker != NULL) - g_object_unref (priv->usb_device_locker); - if (priv->udev_device != NULL) - g_object_unref (priv->udev_device); - g_ptr_array_unref (priv->feature_index); - g_free (priv->version_hw); - - G_OBJECT_CLASS (lu_device_parent_class)->finalize (object); -} - -static void -lu_device_init (LuDevice *device) -{ - LuDevicePrivate *priv = GET_PRIVATE (device); - priv->hidpp_id = HIDPP_DEVICE_ID_UNSET; - priv->feature_index = g_ptr_array_new_with_free_func (g_free); - fu_device_set_vendor_id (FU_DEVICE (device), "USB:0x046D"); -} - -static void -lu_device_class_init (LuDeviceClass *klass) -{ - GParamSpec *pspec; - GObjectClass *object_class = G_OBJECT_CLASS (klass); - FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); - - object_class->finalize = lu_device_finalize; - object_class->get_property = lu_device_get_property; - object_class->set_property = lu_device_set_property; - klass_device->to_string = lu_device_to_string; - - pspec = g_param_spec_uint ("kind", NULL, NULL, - LU_DEVICE_KIND_UNKNOWN, - LU_DEVICE_KIND_LAST, - LU_DEVICE_KIND_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - g_object_class_install_property (object_class, PROP_KIND, pspec); - - pspec = g_param_spec_uint ("hidpp-id", NULL, NULL, - HIDPP_DEVICE_ID_WIRED, - HIDPP_DEVICE_ID_RECEIVER, - HIDPP_DEVICE_ID_UNSET, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - g_object_class_install_property (object_class, PROP_HIDPP_ID, pspec); - - pspec = g_param_spec_uint64 ("flags", NULL, NULL, - LU_DEVICE_FLAG_NONE, - 0xffff, - LU_DEVICE_FLAG_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - g_object_class_install_property (object_class, PROP_FLAGS, pspec); - - pspec = g_param_spec_object ("udev-device", NULL, NULL, - G_UDEV_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - g_object_class_install_property (object_class, PROP_UDEV_DEVICE, pspec); - - pspec = g_param_spec_object ("usb-device", NULL, NULL, - G_USB_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - g_object_class_install_property (object_class, PROP_USB_DEVICE, pspec); -} - -LuDevice * -lu_device_fake_new (LuDeviceKind kind) -{ - LuDevice *device = NULL; - switch (kind) { - case LU_DEVICE_KIND_BOOTLOADER_NORDIC: - device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER_NORDIC, - "kind", kind, - NULL); - break; - case LU_DEVICE_KIND_BOOTLOADER_TEXAS: - device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER_TEXAS, - "kind", kind, - NULL); - break; - case LU_DEVICE_KIND_RUNTIME: - device = g_object_new (LU_TYPE_DEVICE_RUNTIME, - "kind", kind, - NULL); - break; - default: - break; - } - return device; -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-device.h fwupd-1.2.10/plugins/unifying/lu-device.h --- fwupd-1.0.6/plugins/unifying/lu-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_DEVICE_H -#define __LU_DEVICE_H - -#include -#include - -#include "fu-plugin.h" - -#include "lu-hidpp-msg.h" - -G_BEGIN_DECLS - -#define LU_TYPE_DEVICE (lu_device_get_type ()) -G_DECLARE_DERIVABLE_TYPE (LuDevice, lu_device, LU, DEVICE, FuDevice) - -struct _LuDeviceClass -{ - FuDeviceClass parent_class; - gboolean (*open) (LuDevice *device, - GError **error); - gboolean (*close) (LuDevice *device, - GError **error); - gboolean (*probe) (LuDevice *device, - GError **error); - gboolean (*poll) (LuDevice *device, - GError **error); - gboolean (*attach) (LuDevice *device, - GError **error); - gboolean (*detach) (LuDevice *device, - GError **error); - gboolean (*write_firmware) (LuDevice *device, - GBytes *fw, - GError **error); -}; - -#define LU_DEVICE_VID 0x046d - -#define LU_DEVICE_PID_RUNTIME 0xc52b -#define LU_DEVICE_PID_BOOTLOADER_NORDIC 0xaaaa -#define LU_DEVICE_PID_BOOTLOADER_NORDIC_PICO 0xaaae -#define LU_DEVICE_PID_BOOTLOADER_TEXAS 0xaaac -#define LU_DEVICE_PID_BOOTLOADER_TEXAS_PICO 0xaaad - -#define LU_DEVICE_EP1 0x81 -#define LU_DEVICE_EP3 0x83 -/* Signed firmware are very long to verify on the device */ -#define LU_DEVICE_TIMEOUT_MS 20000 - -typedef enum { - LU_DEVICE_KIND_UNKNOWN, - LU_DEVICE_KIND_RUNTIME, - LU_DEVICE_KIND_BOOTLOADER_NORDIC, - LU_DEVICE_KIND_BOOTLOADER_TEXAS, - LU_DEVICE_KIND_PERIPHERAL, - /*< private >*/ - LU_DEVICE_KIND_LAST -} LuDeviceKind; - -typedef enum { - LU_DEVICE_FLAG_NONE, - LU_DEVICE_FLAG_ACTIVE = 1 << 0, - LU_DEVICE_FLAG_IS_OPEN = 1 << 1, - LU_DEVICE_FLAG_REQUIRES_SIGNED_FIRMWARE = 1 << 3, - LU_DEVICE_FLAG_REQUIRES_RESET = 1 << 4, - LU_DEVICE_FLAG_REQUIRES_ATTACH = 1 << 5, - LU_DEVICE_FLAG_REQUIRES_DETACH = 1 << 6, - LU_DEVICE_FLAG_ATTACH_WILL_REPLUG = 1 << 7, - LU_DEVICE_FLAG_DETACH_WILL_REPLUG = 1 << 8, - /*< private >*/ - LU_DEVICE_FLAG_LAST -} LuDeviceFlags; - -LuDeviceKind lu_device_kind_from_string (const gchar *kind); -const gchar *lu_device_kind_to_string (LuDeviceKind kind); - -LuDeviceKind lu_device_get_kind (LuDevice *device); -guint8 lu_device_get_hidpp_id (LuDevice *device); -void lu_device_set_hidpp_id (LuDevice *device, - guint8 hidpp_id); -guint8 lu_device_get_battery_level (LuDevice *device); -void lu_device_set_battery_level (LuDevice *device, - guint8 percentage); -gdouble lu_device_get_hidpp_version (LuDevice *device); -void lu_device_set_hidpp_version (LuDevice *device, - gdouble hidpp_version); -gboolean lu_device_has_flag (LuDevice *device, - LuDeviceFlags flag); -void lu_device_add_flag (LuDevice *device, - LuDeviceFlags flag); -void lu_device_remove_flag (LuDevice *device, - LuDeviceFlags flag); -LuDeviceFlags lu_device_get_flags (LuDevice *device); -const gchar *lu_device_get_version_hw (LuDevice *device); -void lu_device_set_version_hw (LuDevice *device, - const gchar *version_hw); -GUdevDevice *lu_device_get_udev_device (LuDevice *device); -GUsbDevice *lu_device_get_usb_device (LuDevice *device); - -LuDevice *lu_device_fake_new (LuDeviceKind kind); -gboolean lu_device_open (LuDevice *device, - GError **error); -gboolean lu_device_close (LuDevice *device, - GError **error); -gboolean lu_device_detach (LuDevice *device, - GError **error); -gboolean lu_device_attach (LuDevice *device, - GError **error); -gboolean lu_device_probe (LuDevice *device, - GError **error); -gboolean lu_device_poll (LuDevice *device, - GError **error); -gboolean lu_device_write_firmware (LuDevice *device, - GBytes *fw, - GError **error); -gboolean lu_device_hidpp_send (LuDevice *device, - LuHidppMsg *msg, - guint timeout, - GError **error); -gboolean lu_device_hidpp_receive (LuDevice *device, - LuHidppMsg *msg, - guint timeout, - GError **error); -gboolean lu_device_hidpp_transfer (LuDevice *device, - LuHidppMsg *msg, - GError **error); -gboolean lu_device_hidpp_feature_search (LuDevice *device, - guint16 feature, - GError **error); -guint8 lu_device_hidpp_feature_get_idx (LuDevice *device, - guint16 feature); -guint16 lu_device_hidpp_feature_find_by_idx (LuDevice *device, - guint8 idx); - -G_END_DECLS - -#endif /* __LU_DEVICE_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-peripheral.c fwupd-1.2.10/plugins/unifying/lu-device-peripheral.c --- fwupd-1.0.6/plugins/unifying/lu-device-peripheral.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-peripheral.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,798 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include - -#include "lu-common.h" -#include "lu-device-peripheral.h" -#include "lu-hidpp.h" - -struct _LuDevicePeripheral -{ - LuDevice parent_instance; - guint8 cached_fw_entity; -}; - -G_DEFINE_TYPE (LuDevicePeripheral, lu_device_peripheral, LU_TYPE_DEVICE) - -typedef enum { - LU_DEVICE_PERIPHERAL_KIND_KEYBOARD, - LU_DEVICE_PERIPHERAL_KIND_REMOTE_CONTROL, - LU_DEVICE_PERIPHERAL_KIND_NUMPAD, - LU_DEVICE_PERIPHERAL_KIND_MOUSE, - LU_DEVICE_PERIPHERAL_KIND_TOUCHPAD, - LU_DEVICE_PERIPHERAL_KIND_TRACKBALL, - LU_DEVICE_PERIPHERAL_KIND_PRESENTER, - LU_DEVICE_PERIPHERAL_KIND_RECEIVER, - LU_DEVICE_PERIPHERAL_KIND_LAST -} LuDevicePeripheralKind; - -static const gchar * -lu_device_peripheral_get_icon (LuDevicePeripheralKind kind) -{ - if (kind == LU_DEVICE_PERIPHERAL_KIND_KEYBOARD) - return "input-keyboard"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_REMOTE_CONTROL) - return "pda"; // ish - if (kind == LU_DEVICE_PERIPHERAL_KIND_NUMPAD) - return "input-dialpad"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_MOUSE) - return "input-mouse"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_TOUCHPAD) - return "input-touchpad"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_TRACKBALL) - return "input-mouse"; // ish - if (kind == LU_DEVICE_PERIPHERAL_KIND_PRESENTER) - return "pda"; // ish - if (kind == LU_DEVICE_PERIPHERAL_KIND_RECEIVER) - return "preferences-desktop-keyboard"; - return NULL; -} - -static const gchar * -lu_device_peripheral_get_summary (LuDevicePeripheralKind kind) -{ - if (kind == LU_DEVICE_PERIPHERAL_KIND_KEYBOARD) - return "Unifying Keyboard"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_REMOTE_CONTROL) - return "Unifying Remote Control"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_NUMPAD) - return "Unifying Number Pad"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_MOUSE) - return "Unifying Mouse"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_TOUCHPAD) - return "Unifying Touchpad"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_TRACKBALL) - return "Unifying Trackball"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_PRESENTER) - return "Unifying Presenter"; - if (kind == LU_DEVICE_PERIPHERAL_KIND_RECEIVER) - return "Unifying Receiver"; - return NULL; -} - -static gboolean -lu_device_peripheral_fetch_firmware_info (LuDevice *device, GError **error) -{ - LuDevicePeripheral *self = LU_DEVICE_PERIPHERAL (device); - guint8 idx; - guint8 entity_count; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* get the feature index */ - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_I_FIRMWARE_INFO); - if (idx == 0x00) - return TRUE; - - /* get the entity count */ - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x00 << 4; /* getCount */ - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to get firmware count: "); - return FALSE; - } - entity_count = msg->data[0]; - g_debug ("firmware entity count is %u", entity_count); - - /* get firmware, bootloader, hardware versions */ - for (guint8 i = 0; i < entity_count; i++) { - guint16 build; - g_autofree gchar *version = NULL; - g_autofree gchar *name = NULL; - - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x01 << 4; /* getInfo */ - msg->data[0] = i; - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to get firmware info: "); - return FALSE; - } - if (msg->data[1] == 0x00 && - msg->data[2] == 0x00 && - msg->data[3] == 0x00 && - msg->data[4] == 0x00 && - msg->data[4] == 0x00 && - msg->data[5] == 0x00 && - msg->data[6] == 0x00 && - msg->data[7] == 0x00) { - g_debug ("no version set for entity %u", i); - continue; - } - name = g_strdup_printf ("%c%c%c", - msg->data[1], - msg->data[2], - msg->data[3]); - build = ((guint16) msg->data[6]) << 8 | msg->data[7]; - version = lu_format_version (name, - msg->data[4], - msg->data[5], - build); - g_debug ("firmware entity 0x%02x version is %s", i, version); - if (msg->data[0] == 0) { - fu_device_set_version (device, version); - self->cached_fw_entity = i; - } else if (msg->data[0] == 1) { - fu_device_set_version_bootloader (FU_DEVICE (device), version); - } else if (msg->data[0] == 2) { - lu_device_set_version_hw (device, version); - } - } - - /* not an error, the device just doesn't support this */ - return TRUE; -} - -static gboolean -lu_device_peripheral_fetch_battery_level (LuDevice *device, GError **error) -{ - /* try using HID++2.0 */ - if (lu_device_get_hidpp_version (device) >= 2.f) { - guint8 idx; - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_BATTERY_LEVEL_STATUS); - if (idx != 0x00) { - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x00; /* GetBatteryLevelStatus */ - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to get battery info: "); - return FALSE; - } - if (msg->data[0] != 0x00) - lu_device_set_battery_level (device, msg->data[0]); - return TRUE; - } - } - - /* try HID++1.0 battery mileage */ - if (lu_device_get_hidpp_version (device) == 1.f) { - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = HIDPP_SUBID_GET_REGISTER; - msg->function_id = HIDPP_REGISTER_BATTERY_MILEAGE; - if (lu_device_hidpp_transfer (device, msg, NULL)) { - if (msg->data[0] != 0x00) - lu_device_set_battery_level (device, msg->data[0]); - return TRUE; - } - - /* try HID++1.0 battery status instead */ - msg->function_id = HIDPP_REGISTER_BATTERY_STATUS; - if (lu_device_hidpp_transfer (device, msg, NULL)) { - switch (msg->data[0]) { - case 1: /* 0 - 10 */ - lu_device_set_battery_level (device, 5); - break; - case 3: /* 11 - 30 */ - lu_device_set_battery_level (device, 20); - break; - case 5: /* 31 - 80 */ - lu_device_set_battery_level (device, 55); - break; - case 7: /* 81 - 100 */ - lu_device_set_battery_level (device, 90); - break; - default: - g_warning ("unknown battery percentage: 0x%02x", - msg->data[0]); - break; - } - return TRUE; - } - } - - /* not an error, the device just doesn't support any of the methods */ - return TRUE; -} - -static gboolean -lu_device_peripheral_ping (LuDevice *device, GError **error) -{ - gdouble version; - g_autoptr(GError) error_local = NULL; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* handle failure */ - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = 0x00; /* rootIndex */ - msg->function_id = 0x01 << 4; /* ping */ - msg->data[0] = 0x00; - msg->data[1] = 0x00; - msg->data[2] = 0xaa; /* user-selected value */ - if (!lu_device_hidpp_transfer (device, msg, &error_local)) { - if (g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED)) { - lu_device_set_hidpp_version (device, 1.f); - return TRUE; - } - if (g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_HOST_UNREACHABLE)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_HOST_UNREACHABLE, - "device %s is unreachable: %s", - fu_device_get_name (device), - error_local->message); - lu_device_remove_flag (device, LU_DEVICE_FLAG_ACTIVE); - return FALSE; - } - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to ping %s: %s", - fu_device_get_name (FU_DEVICE (device)), - error_local->message); - return FALSE; - } - - /* format version in BCD format */ - version = (gdouble) msg->data[0] + ((gdouble) msg->data[1]) / 100.f; - lu_device_set_hidpp_version (device, version); - - /* success */ - return TRUE; -} - -static gboolean -lu_device_peripheral_probe (LuDevice *device, GError **error) -{ - guint8 idx; - const guint16 map_features[] = { - HIDPP_FEATURE_GET_DEVICE_NAME_TYPE, - HIDPP_FEATURE_I_FIRMWARE_INFO, - HIDPP_FEATURE_BATTERY_LEVEL_STATUS, - HIDPP_FEATURE_DFU_CONTROL, - HIDPP_FEATURE_DFU_CONTROL_SIGNED, - HIDPP_FEATURE_DFU, - HIDPP_FEATURE_ROOT }; - - /* ping device to get HID++ version */ - if (!lu_device_peripheral_ping (device, error)) - return FALSE; - - /* map some *optional* HID++2.0 features we might use */ - for (guint i = 0; map_features[i] != HIDPP_FEATURE_ROOT; i++) { - g_autoptr(GError) error_local = NULL; - if (!lu_device_hidpp_feature_search (device, - map_features[i], - &error_local)) { - g_debug ("%s", error_local->message); - if (g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT)) { - /* timed out, so not trying any more */ - break; - } - } - } - - /* get the firmware information */ - if (!lu_device_peripheral_fetch_firmware_info (device, error)) - return FALSE; - - /* get the battery level */ - if (!lu_device_peripheral_fetch_battery_level (device, error)) - return FALSE; - - /* try using HID++2.0 */ - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_GET_DEVICE_NAME_TYPE); - if (idx != 0x00) { - const gchar *tmp; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x02 << 4; /* getDeviceType */ - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to get device type: "); - return FALSE; - } - - /* add nice-to-have data */ - tmp = lu_device_peripheral_get_summary (msg->data[0]); - if (tmp != NULL) - fu_device_set_summary (FU_DEVICE (device), tmp); - tmp = lu_device_peripheral_get_icon (msg->data[0]); - if (tmp != NULL) - fu_device_add_icon (FU_DEVICE (device), tmp); - } - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU_CONTROL); - if (idx != 0x00) { - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - lu_device_add_flag (device, LU_DEVICE_FLAG_REQUIRES_DETACH); - } - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU_CONTROL_SIGNED); - if (idx != 0x00) { - /* check the feature is available */ - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x00 << 4; /* getDfuStatus */ - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to get DFU status: "); - return FALSE; - } - if ((msg->data[2] & 0x01) > 0) { - g_warning ("DFU mode not available"); - } else { - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - lu_device_add_flag (device, LU_DEVICE_FLAG_REQUIRES_DETACH); - lu_device_add_flag (device, LU_DEVICE_FLAG_REQUIRES_SIGNED_FIRMWARE); - } - } - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU); - if (idx != 0x00) { - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - lu_device_add_flag (device, LU_DEVICE_FLAG_REQUIRES_ATTACH); - if (fu_device_get_version (device) == NULL) { - g_debug ("repairing device in bootloader mode"); - fu_device_set_version (FU_DEVICE (device), "MPKxx.xx_Bxxxx"); - } - } - - /* this device is active right now */ - lu_device_add_flag (device, LU_DEVICE_FLAG_ACTIVE); - return TRUE; -} - -static gboolean -lu_device_peripheral_detach (LuDevice *device, GError **error) -{ - guint8 idx; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* this requires user action */ - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU_CONTROL); - if (idx != 0x00) { - msg->report_id = HIDPP_REPORT_ID_LONG; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x01 << 4; /* setDfuControl */ - msg->data[0] = 0x01; /* enterDfu */ - msg->data[1] = 0x00; /* dfuControlParam */ - msg->data[2] = 0x00; /* unused */ - msg->data[3] = 0x00; /* unused */ - msg->data[4] = 'D'; - msg->data[5] = 'F'; - msg->data[6] = 'U'; - msg->flags = LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID | - LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to put device into DFU mode: "); - return FALSE; - } - lu_device_add_flag (device, LU_DEVICE_FLAG_REQUIRES_RESET); - return TRUE; - } - - /* this can reboot all by itself */ - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU_CONTROL_SIGNED); - if (idx != 0x00) { - msg->report_id = HIDPP_REPORT_ID_LONG; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x01 << 4; /* setDfuControl */ - msg->data[0] = 0x01; /* startDfu */ - msg->data[1] = 0x00; /* dfuControlParam */ - msg->data[2] = 0x00; /* unused */ - msg->data[3] = 0x00; /* unused */ - msg->data[4] = 'D'; - msg->data[5] = 'F'; - msg->data[6] = 'U'; - msg->flags = LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID; - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to put device into DFU mode: "); - return FALSE; - } - - /* reprobe */ - return lu_device_probe (device, error); - } - - /* we don't know how */ - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "no method to detach"); - return FALSE; -} - -static gboolean -lu_device_peripheral_check_status (guint8 status, GError **error) -{ - switch (status & 0x7f) { - case 0x00: - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "invalid status value 0x%02x", - status); - break; - case 0x01: /* packet success */ - case 0x02: /* DFU success */ - case 0x05: /* DFU success: entity restart required */ - case 0x06: /* DFU success: system restart required */ - /* success */ - return TRUE; - break; - case 0x03: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_PENDING, - "wait for event (command in progress)"); - break; - case 0x04: - case 0x10: /* unknown */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "generic error"); - break; - case 0x11: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "bad voltage (power too low?)"); - break; - case 0x12: - case 0x14: /* bad magic string */ - case 0x21: /* bad firmware */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "unsupported firmware"); - break; - case 0x13: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "unsupported encryption mode"); - break; - case 0x15: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "erase failure"); - break; - case 0x16: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "DFU not started"); - break; - case 0x17: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "bad sequence number"); - break; - case 0x18: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "unsupported command"); - break; - case 0x19: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "command in progress"); - break; - case 0x1a: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "address out of range"); - break; - case 0x1b: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "unaligned address"); - break; - case 0x1c: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "bad size"); - break; - case 0x1d: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "missing program data"); - break; - case 0x1e: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "missing check data"); - break; - case 0x1f: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "program failed to write"); - break; - case 0x20: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "program failed to verify"); - break; - case 0x22: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "firmware check failure"); - break; - case 0x23: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "blocked command (restart required)"); - break; - default: - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "unhandled status value 0x%02x", - status); - break; - } - return FALSE; -} - -static gboolean -lu_device_peripheral_write_firmware_pkt (LuDevice *device, - guint8 idx, - guint8 cmd, - const guint8 *data, - GError **error) -{ - guint32 packet_cnt; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - g_autoptr(GError) error_local = NULL; - - /* send firmware data */ - msg->report_id = HIDPP_REPORT_ID_LONG; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = cmd << 4; /* dfuStart or dfuCmdDataX */ - memcpy (msg->data, data, 16); - if (!lu_device_hidpp_transfer (device, msg, &error_local)) { - g_prefix_error (error, "failed to supply program data: "); - return FALSE; - } - - /* check error */ - packet_cnt = fu_common_read_uint32 (msg->data, G_BIG_ENDIAN); - g_debug ("packet_cnt=0x%04x", packet_cnt); - if (lu_device_peripheral_check_status (msg->data[4], &error_local)) - return TRUE; - - /* fatal error */ - if (!g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_PENDING)) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - error_local->message); - return FALSE; - } - - /* wait for the HID++ notification */ - g_debug ("ignoring: %s", error_local->message); - for (guint retry = 0; retry < 10; retry++) { - g_autoptr(LuHidppMsg) msg2 = lu_hidpp_msg_new (); - msg2->flags = LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID; - if (!lu_device_hidpp_receive (device, msg2, 15000, error)) - return FALSE; - if (lu_hidpp_msg_is_reply (msg, msg2)) { - g_autoptr(GError) error2 = NULL; - if (!lu_device_peripheral_check_status (msg2->data[4], &error2)) { - g_debug ("got %s, waiting a bit longer", error2->message); - continue; - } - return TRUE; - } else { - g_debug ("got wrong packet, continue to wait..."); - } - } - - /* nothing in the queue */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to get event after timeout"); - return FALSE; -} - -static gboolean -lu_device_peripheral_write_firmware (LuDevice *device, GBytes *fw, GError **error) -{ - gsize sz = 0; - const guint8 *data; - guint8 cmd = 0x04; - guint8 idx; - - /* if we're in bootloader mode, we should be able to get this feature */ - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU); - if (idx == 0x00) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "no DFU feature available"); - return FALSE; - } - - /* flash hardware */ - data = g_bytes_get_data (fw, &sz); - for (gsize i = 0; i < sz / 16; i++) { - - /* send packet and wait for reply */ - g_debug ("send data at addr=0x%04x", (guint) i * 16); - if (!lu_device_peripheral_write_firmware_pkt (device, - idx, - cmd, - data + (i * 16), - error)) { - g_prefix_error (error, - "failed to write @0x%04x: ", - (guint) i * 16); - return FALSE; - } - - /* use sliding window */ - cmd = (cmd + 1) % 4; - - /* update progress-bar */ - fu_device_set_progress_full (FU_DEVICE (device), i * 16, sz); - } - - return TRUE; -} - -static gboolean -lu_device_peripheral_attach (LuDevice *device, GError **error) -{ - LuDevicePeripheral *self = LU_DEVICE_PERIPHERAL (device); - guint8 idx; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* if we're in bootloader mode, we should be able to get this feature */ - idx = lu_device_hidpp_feature_get_idx (device, HIDPP_FEATURE_DFU); - if (idx == 0x00) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "no DFU feature available"); - return FALSE; - } - - /* reboot back into firmware mode */ - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = idx; - msg->function_id = 0x05 << 4; /* restart */ - msg->data[0] = self->cached_fw_entity; /* fwEntity */ - msg->flags = LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID | - LU_HIDPP_MSG_FLAG_IGNORE_SWID | // inferred? - LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to restart device: "); - return FALSE; - } - - /* reprobe */ - if (!lu_device_probe (device, error)) - return FALSE; - - /* success */ - return TRUE; -} - -static gboolean -lu_device_peripheral_poll (LuDevice *device, GError **error) -{ - const guint timeout = 1; /* ms */ - g_autoptr(GError) error_local = NULL; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* flush pending data */ - if (!lu_device_hidpp_receive (device, msg, timeout, &error_local)) { - if (!g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT)) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to get pending read: %s", - error_local->message); - return FALSE; - } - } - - /* just ping */ - if (lu_device_has_flag (device, LU_DEVICE_FLAG_ACTIVE)) - return lu_device_peripheral_ping (device, error); - - /* probe, which also involves a ping first */ - return lu_device_probe (device, error); -} - -static void -lu_device_peripheral_finalize (GObject *object) -{ - G_OBJECT_CLASS (lu_device_peripheral_parent_class)->finalize (object); -} - -static void -lu_device_peripheral_class_init (LuDevicePeripheralClass *klass) -{ - LuDeviceClass *klass_device = LU_DEVICE_CLASS (klass); - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = lu_device_peripheral_finalize; - klass_device->probe = lu_device_peripheral_probe; - klass_device->poll = lu_device_peripheral_poll; - klass_device->write_firmware = lu_device_peripheral_write_firmware; - klass_device->attach = lu_device_peripheral_attach; - klass_device->detach = lu_device_peripheral_detach; -} - -static void -lu_device_peripheral_init (LuDevicePeripheral *self) -{ -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-peripheral.h fwupd-1.2.10/plugins/unifying/lu-device-peripheral.h --- fwupd-1.0.6/plugins/unifying/lu-device-peripheral.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-peripheral.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_DEVICE_PERIPHERAL_H -#define __LU_DEVICE_PERIPHERAL_H - -#include "lu-device.h" - -G_BEGIN_DECLS - -#define LU_TYPE_DEVICE_PERIPHERAL (lu_device_peripheral_get_type ()) -G_DECLARE_FINAL_TYPE (LuDevicePeripheral, lu_device_peripheral, LU, DEVICE_PERIPHERAL, LuDevice) - -G_END_DECLS - -#endif /* __LU_DEVICE_PERIPHERAL_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-runtime.c fwupd-1.2.10/plugins/unifying/lu-device-runtime.c --- fwupd-1.0.6/plugins/unifying/lu-device-runtime.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-runtime.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,257 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include - -#include "lu-common.h" -#include "lu-device-runtime.h" -#include "lu-hidpp.h" - -struct _LuDeviceRuntime -{ - LuDevice parent_instance; -}; - -G_DEFINE_TYPE (LuDeviceRuntime, lu_device_runtime, LU_TYPE_DEVICE) - -#ifndef HAVE_GUDEV_232 -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) -#endif - -static gboolean -lu_device_runtime_enable_notifications (LuDevice *device, GError **error) -{ - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = HIDPP_SUBID_SET_REGISTER; - msg->function_id = HIDPP_REGISTER_HIDPP_NOTIFICATIONS; - msg->data[0] = 0x00; - msg->data[1] = 0x05; /* Wireless + SoftwarePresent */ - msg->data[2] = 0x00; - return lu_device_hidpp_transfer (device, msg, error); -} - -static gboolean -lu_device_runtime_open (LuDevice *device, GError **error) -{ - GUdevDevice *udev_device = lu_device_get_udev_device (device); - GUsbDevice *usb_device = lu_device_get_usb_device (device); - guint16 release = 0xffff; - guint8 config[10]; - guint8 version_bl_major = 0; - g_autofree gchar *devid1 = NULL; - g_autofree gchar *version_bl = NULL; - g_autofree gchar *version_fw = NULL; - - /* add a generic GUID */ - devid1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - (guint) LU_DEVICE_VID, - (guint) LU_DEVICE_PID_RUNTIME); - fu_device_add_guid (FU_DEVICE (device), devid1); - - /* generate bootloadder-specific GUID */ - if (usb_device != NULL) { - release = g_usb_device_get_release (usb_device); - } else if (udev_device != NULL) { - g_autoptr(GUdevDevice) udev_parent = NULL; - udev_parent = g_udev_device_get_parent_with_subsystem (udev_device, - "usb", "usb_device"); - if (udev_parent != NULL) { - const gchar *release_str; - release_str = g_udev_device_get_property (udev_parent, "ID_REVISION"); - if (release_str != NULL) - release = g_ascii_strtoull (release_str, NULL, 16); - } - } - if (release != 0xffff) { - g_autofree gchar *devid2 = NULL; - switch (release &= 0xff00) { - case 0x1200: - /* Nordic */ - devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - (guint) LU_DEVICE_VID, - (guint) LU_DEVICE_PID_BOOTLOADER_NORDIC); - fu_device_add_guid (FU_DEVICE (device), devid2); - version_bl_major = 0x01; - break; - case 0x2400: - /* Texas */ - devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - (guint) LU_DEVICE_VID, - (guint) LU_DEVICE_PID_BOOTLOADER_TEXAS); - fu_device_add_guid (FU_DEVICE (device), devid2); - version_bl_major = 0x03; - break; - default: - g_warning ("bootloader release %04x invalid", release); - break; - } - } - - /* read all 10 bytes of the version register */ - memset (config, 0x00, sizeof (config)); - for (guint i = 0x01; i < 0x05; i++) { - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* workaround a bug in the 12.01 firmware, which fails with - * INVALID_VALUE when reading MCU1_HW_VERSION */ - if (i == 0x03) - continue; - - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = HIDPP_SUBID_GET_REGISTER; - msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION; - msg->data[0] = i; - if (!lu_device_hidpp_transfer (device, msg, error)) { - g_prefix_error (error, "failed to read device config: "); - return FALSE; - } - memcpy (config + (i * 2), msg->data + 1, 2); - } - - /* get firmware version */ - version_fw = lu_format_version ("RQR", - config[2], - config[3], - (guint16) config[4] << 8 | - config[5]); - fu_device_set_version (FU_DEVICE (device), version_fw); - - /* get bootloader version */ - if (version_bl_major > 0) { - version_bl = lu_format_version ("BOT", - version_bl_major, - config[8], - config[9]); - fu_device_set_version_bootloader (FU_DEVICE (device), version_bl); - - /* is the dongle expecting signed firmware */ - if ((version_bl_major == 0x01 && config[8] >= 0x04) || - (version_bl_major == 0x03 && config[8] >= 0x02)) { - lu_device_add_flag (device, LU_DEVICE_FLAG_REQUIRES_SIGNED_FIRMWARE); - } - } - - /* enable HID++ notifications */ - if (!lu_device_runtime_enable_notifications (device, error)) { - g_prefix_error (error, "failed to enable notifications: "); - return FALSE; - } - - /* this only exists with the original HID++1.0 version */ - lu_device_set_hidpp_version (device, 1.f); - - /* we can flash this */ - fu_device_add_flag (FU_DEVICE (device), FWUPD_DEVICE_FLAG_UPDATABLE); - - /* only the bootloader can do the update */ - fu_device_set_name (FU_DEVICE (device), "Unifying Receiver"); - - return TRUE; -} - -static gboolean -lu_device_runtime_detach (LuDevice *device, GError **error) -{ - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - msg->report_id = HIDPP_REPORT_ID_SHORT; - msg->device_id = lu_device_get_hidpp_id (device); - msg->sub_id = HIDPP_SUBID_SET_REGISTER; - msg->function_id = HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE; - msg->data[0] = 'I'; - msg->data[1] = 'C'; - msg->data[2] = 'P'; - msg->flags = LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT; - if (!lu_device_hidpp_send (device, msg, LU_DEVICE_TIMEOUT_MS, error)) { - g_prefix_error (error, "failed to detach to bootloader: "); - return FALSE; - } - return TRUE; -} - -static gboolean -lu_device_runtime_poll (LuDevice *device, GError **error) -{ - const guint timeout = 1; /* ms */ - g_autoptr(GError) error_local = NULL; - g_autoptr(LuHidppMsg) msg = lu_hidpp_msg_new (); - - /* is there any pending data to read */ - if (!lu_device_hidpp_receive (device, msg, timeout, &error_local)) { - if (g_error_matches (error_local, - G_IO_ERROR, - G_IO_ERROR_TIMED_OUT)) { - return TRUE; - } - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "failed to get pending read: %s", - error_local->message); - return FALSE; - } - - /* HID++1.0 error */ - if (!lu_hidpp_msg_is_error (msg, error)) - return FALSE; - - /* unifying receiver notification */ - if (msg->report_id == HIDPP_REPORT_ID_SHORT) { - switch (msg->sub_id) { - case HIDPP_SUBID_DEVICE_CONNECTION: - case HIDPP_SUBID_DEVICE_DISCONNECTION: - case HIDPP_SUBID_DEVICE_LOCKING_CHANGED: - g_debug ("device connection event, do something"); - break; - case HIDPP_SUBID_LINK_QUALITY: - g_debug ("ignoring link quality message"); - break; - case HIDPP_SUBID_ERROR_MSG: - g_debug ("ignoring link quality message"); - break; - default: - g_debug ("unknown SubID %02x", msg->sub_id); - break; - } - } - return TRUE; -} - -static void -lu_device_runtime_class_init (LuDeviceRuntimeClass *klass) -{ - LuDeviceClass *klass_device = LU_DEVICE_CLASS (klass); - klass_device->open = lu_device_runtime_open; - klass_device->poll = lu_device_runtime_poll; - klass_device->detach = lu_device_runtime_detach; -} - -static void -lu_device_runtime_init (LuDeviceRuntime *device) -{ - /* FIXME: we need something better */ - fu_device_add_icon (FU_DEVICE (device), "preferences-desktop-keyboard"); - fu_device_set_summary (FU_DEVICE (device), "A miniaturised USB wireless receiver"); -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-device-runtime.h fwupd-1.2.10/plugins/unifying/lu-device-runtime.h --- fwupd-1.0.6/plugins/unifying/lu-device-runtime.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-device-runtime.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_DEVICE_RUNTIME_H -#define __LU_DEVICE_RUNTIME_H - -#include "lu-device.h" - -G_BEGIN_DECLS - -#define LU_TYPE_DEVICE_RUNTIME (lu_device_runtime_get_type ()) -G_DECLARE_FINAL_TYPE (LuDeviceRuntime, lu_device_runtime, LU, DEVICE_RUNTIME, LuDevice) - -G_END_DECLS - -#endif /* __LU_DEVICE_RUNTIME_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-hidpp.h fwupd-1.2.10/plugins/unifying/lu-hidpp.h --- fwupd-1.0.6/plugins/unifying/lu-hidpp.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-hidpp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016-2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU__HIDPP_H -#define __LU__HIDPP_H - -G_BEGIN_DECLS - -#define LU_REQUEST_SET_REPORT 0x09 - -/* - * Based on the HID++ documentation provided by Nestor Lopez Casado at: - * https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing - */ -#define HIDPP_DEVICE_ID_WIRED 0x00 -#define HIDPP_DEVICE_ID_RECEIVER 0xFF -#define HIDPP_DEVICE_ID_UNSET 0xFE - -#define HIDPP_REPORT_NOTIFICATION 0x01 -#define HIDPP_REPORT_ID_SHORT 0x10 -#define HIDPP_REPORT_ID_LONG 0x11 -#define HIDPP_REPORT_ID_VERY_LONG 0x12 - -#define HIDPP_SUBID_VENDOR_SPECIFIC_KEYS 0x03 -#define HIDPP_SUBID_POWER_KEYS 0x04 -#define HIDPP_SUBID_ROLLER 0x05 -#define HIDPP_SUBID_MOUSE_EXTRA_BUTTONS 0x06 -#define HIDPP_SUBID_BATTERY_CHARGING_LEVEL 0x07 -#define HIDPP_SUBID_USER_INTERFACE_EVENT 0x08 -#define HIDPP_SUBID_F_LOCK_STATUS 0x09 -#define HIDPP_SUBID_CALCULATOR_RESULT 0x0A -#define HIDPP_SUBID_MENU_NAVIGATE 0x0B -#define HIDPP_SUBID_FN_KEY 0x0C -#define HIDPP_SUBID_BATTERY_MILEAGE 0x0D -#define HIDPP_SUBID_UART_RX 0x0E -#define HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE 0x17 -#define HIDPP_SUBID_DEVICE_DISCONNECTION 0x40 -#define HIDPP_SUBID_DEVICE_CONNECTION 0x41 -#define HIDPP_SUBID_DEVICE_DISCOVERY 0x42 -#define HIDPP_SUBID_PIN_CODE_REQUEST 0x43 -#define HIDPP_SUBID_RECEIVER_WORKING_MODE 0x44 -#define HIDPP_SUBID_ERROR_MESSAGE 0x45 -#define HIDPP_SUBID_RF_LINK_CHANGE 0x46 -#define HIDPP_SUBID_HCI 0x48 -#define HIDPP_SUBID_LINK_QUALITY 0x49 -#define HIDPP_SUBID_DEVICE_LOCKING_CHANGED 0x4a -#define HIDPP_SUBID_WIRELESS_DEVICE_CHANGE 0x4B -#define HIDPP_SUBID_ACL 0x51 -#define HIDPP_SUBID_VOIP_TELEPHONY_EVENT 0x5B -#define HIDPP_SUBID_LED 0x60 -#define HIDPP_SUBID_GESTURE_AND_AIR 0x65 -#define HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH 0x66 -#define HIDPP_SUBID_TRACEABILITY 0x78 -#define HIDPP_SUBID_SET_REGISTER 0x80 -#define HIDPP_SUBID_GET_REGISTER 0x81 -#define HIDPP_SUBID_SET_LONG_REGISTER 0x82 -#define HIDPP_SUBID_GET_LONG_REGISTER 0x83 -#define HIDPP_SUBID_SET_VERY_LONG_REGISTER 0x84 -#define HIDPP_SUBID_GET_VERY_LONG_REGISTER 0x85 -#define HIDPP_SUBID_ERROR_MSG 0x8F -#define HIDPP_SUBID_ERROR_MSG_20 0xFF - -#define HIDPP_ERR_SUCCESS 0x00 -#define HIDPP_ERR_INVALID_SUBID 0x01 -#define HIDPP_ERR_INVALID_ADDRESS 0x02 -#define HIDPP_ERR_INVALID_VALUE 0x03 -#define HIDPP_ERR_CONNECT_FAIL 0x04 -#define HIDPP_ERR_TOO_MANY_DEVICES 0x05 -#define HIDPP_ERR_ALREADY_EXISTS 0x06 -#define HIDPP_ERR_BUSY 0x07 -#define HIDPP_ERR_UNKNOWN_DEVICE 0x08 -#define HIDPP_ERR_RESOURCE_ERROR 0x09 -#define HIDPP_ERR_REQUEST_UNAVAILABLE 0x0A -#define HIDPP_ERR_INVALID_PARAM_VALUE 0x0B -#define HIDPP_ERR_WRONG_PIN_CODE 0x0C - -/* - * HID++1.0 registers - */ - -#define HIDPP_REGISTER_HIDPP_NOTIFICATIONS 0x00 -#define HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES 0x01 -#define HIDPP_REGISTER_BATTERY_STATUS 0x07 -#define HIDPP_REGISTER_BATTERY_MILEAGE 0x0D -#define HIDPP_REGISTER_PROFILE 0x0F -#define HIDPP_REGISTER_LED_STATUS 0x51 -#define HIDPP_REGISTER_LED_INTENSITY 0x54 -#define HIDPP_REGISTER_LED_COLOR 0x57 -#define HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS 0x61 -#define HIDPP_REGISTER_CURRENT_RESOLUTION 0x63 -#define HIDPP_REGISTER_USB_REFRESH_RATE 0x64 -#define HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT 0xA0 -#define HIDPP_REGISTER_HOT_CONTROL 0xA1 -#define HIDPP_REGISTER_READ_MEMORY 0xA2 -#define HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION 0xB2 -#define HIDPP_REGISTER_PAIRING_INFORMATION 0xB5 -#define HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE 0xF0 -#define HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION 0xF1 - -/* - * HID++2.0 error codes - */ -#define HIDPP_ERROR_CODE_NO_ERROR 0x00 -#define HIDPP_ERROR_CODE_UNKNOWN 0x01 -#define HIDPP_ERROR_CODE_INVALID_ARGUMENT 0x02 -#define HIDPP_ERROR_CODE_OUT_OF_RANGE 0x03 -#define HIDPP_ERROR_CODE_HW_ERROR 0x04 -#define HIDPP_ERROR_CODE_LOGITECH_INTERNAL 0x05 -#define HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX 0x06 -#define HIDPP_ERROR_CODE_INVALID_FUNCTION_ID 0x07 -#define HIDPP_ERROR_CODE_BUSY 0x08 -#define HIDPP_ERROR_CODE_UNSUPPORTED 0x09 - -/* - * HID++2.0 features - */ -#define HIDPP_FEATURE_ROOT 0x0000 -#define HIDPP_FEATURE_I_FEATURE_SET 0x0001 -#define HIDPP_FEATURE_I_FIRMWARE_INFO 0x0003 -#define HIDPP_FEATURE_GET_DEVICE_NAME_TYPE 0x0005 -#define HIDPP_FEATURE_DFU_CONTROL 0x00c1 -#define HIDPP_FEATURE_DFU_CONTROL_SIGNED 0x00c2 -#define HIDPP_FEATURE_DFU 0x00d0 -#define HIDPP_FEATURE_BATTERY_LEVEL_STATUS 0x1000 -#define HIDPP_FEATURE_KBD_REPROGRAMMABLE_KEYS 0x1b00 -#define HIDPP_FEATURE_SPECIAL_KEYS_BUTTONS 0x1b04 -#define HIDPP_FEATURE_MOUSE_POINTER_BASIC 0x2200 -#define HIDPP_FEATURE_ADJUSTABLE_DPI 0x2201 -#define HIDPP_FEATURE_ADJUSTABLE_REPORT_RATE 0x8060 -#define HIDPP_FEATURE_COLOR_LED_EFFECTS 0x8070 -#define HIDPP_FEATURE_ONBOARD_PROFILES 0x8100 -#define HIDPP_FEATURE_MOUSE_BUTTON_SPY 0x8110 - -G_END_DECLS - -#endif /* __LU__HIDPP_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-hidpp-msg.c fwupd-1.2.10/plugins/unifying/lu-hidpp-msg.c --- fwupd-1.0.6/plugins/unifying/lu-hidpp-msg.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-hidpp-msg.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,414 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include -#include - -#include "lu-hidpp.h" -#include "lu-hidpp-msg.h" - -LuHidppMsg * -lu_hidpp_msg_new (void) -{ - return g_new0 (LuHidppMsg, 1); -} - -const gchar * -lu_hidpp_msg_dev_id_to_string (LuHidppMsg *msg) -{ - g_return_val_if_fail (msg != NULL, NULL); - if (msg->device_id == HIDPP_DEVICE_ID_WIRED) - return "wired"; - if (msg->device_id == HIDPP_DEVICE_ID_RECEIVER) - return "receiver"; - if (msg->device_id == HIDPP_DEVICE_ID_UNSET) - return "unset"; - return NULL; -} - -const gchar * -lu_hidpp_msg_rpt_id_to_string (LuHidppMsg *msg) -{ - g_return_val_if_fail (msg != NULL, NULL); - if (msg->report_id == HIDPP_REPORT_ID_SHORT) - return "short"; - if (msg->report_id == HIDPP_REPORT_ID_LONG) - return "long"; - if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG) - return "very-long"; - return NULL; -} - -gsize -lu_hidpp_msg_get_payload_length (LuHidppMsg *msg) -{ - if (msg->report_id == HIDPP_REPORT_ID_SHORT) - return 0x07; - if (msg->report_id == HIDPP_REPORT_ID_LONG) - return 0x14; - if (msg->report_id == HIDPP_REPORT_ID_VERY_LONG) - return 0x2f; - if (msg->report_id == HIDPP_REPORT_NOTIFICATION) - return 0x08; - return 0x0; -} - -const gchar * -lu_hidpp_msg_fcn_id_to_string (LuHidppMsg *msg) -{ - g_return_val_if_fail (msg != NULL, NULL); - switch (msg->sub_id) { - case HIDPP_SUBID_SET_REGISTER: - case HIDPP_SUBID_GET_REGISTER: - case HIDPP_SUBID_SET_LONG_REGISTER: - case HIDPP_SUBID_GET_LONG_REGISTER: - case HIDPP_SUBID_SET_VERY_LONG_REGISTER: - case HIDPP_SUBID_GET_VERY_LONG_REGISTER: - if (msg->function_id == HIDPP_REGISTER_HIDPP_NOTIFICATIONS) - return "hidpp-notifications"; - if (msg->function_id == HIDPP_REGISTER_ENABLE_INDIVIDUAL_FEATURES) - return "individual-features"; - if (msg->function_id == HIDPP_REGISTER_BATTERY_STATUS) - return "battery-status"; - if (msg->function_id == HIDPP_REGISTER_BATTERY_MILEAGE) - return "battery-mileage"; - if (msg->function_id == HIDPP_REGISTER_PROFILE) - return "profile"; - if (msg->function_id == HIDPP_REGISTER_LED_STATUS) - return "led-status"; - if (msg->function_id == HIDPP_REGISTER_LED_INTENSITY) - return "led-intensity"; - if (msg->function_id == HIDPP_REGISTER_LED_COLOR) - return "led-color"; - if (msg->function_id == HIDPP_REGISTER_OPTICAL_SENSOR_SETTINGS) - return "optical-sensor-settings"; - if (msg->function_id == HIDPP_REGISTER_CURRENT_RESOLUTION) - return "current-resolution"; - if (msg->function_id == HIDPP_REGISTER_USB_REFRESH_RATE) - return "usb-refresh-rate"; - if (msg->function_id == HIDPP_REGISTER_GENERIC_MEMORY_MANAGEMENT) - return "generic-memory-management"; - if (msg->function_id == HIDPP_REGISTER_HOT_CONTROL) - return "hot-control"; - if (msg->function_id == HIDPP_REGISTER_READ_MEMORY) - return "read-memory"; - if (msg->function_id == HIDPP_REGISTER_DEVICE_CONNECTION_DISCONNECTION) - return "device-connection-disconnection"; - if (msg->function_id == HIDPP_REGISTER_PAIRING_INFORMATION) - return "pairing-information"; - if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_UPDATE_MODE) - return "device-firmware-update-mode"; - if (msg->function_id == HIDPP_REGISTER_DEVICE_FIRMWARE_INFORMATION) - return "device-firmware-information"; - break; - default: - break; - } - return NULL; - -} - -const gchar * -lu_hidpp_msg_sub_id_to_string (LuHidppMsg *msg) -{ - g_return_val_if_fail (msg != NULL, NULL); - if (msg->sub_id == HIDPP_SUBID_VENDOR_SPECIFIC_KEYS) - return "vendor-specific-keys"; - if (msg->sub_id == HIDPP_SUBID_POWER_KEYS) - return "power-keys"; - if (msg->sub_id == HIDPP_SUBID_ROLLER) - return "roller"; - if (msg->sub_id == HIDPP_SUBID_MOUSE_EXTRA_BUTTONS) - return "mouse-extra-buttons"; - if (msg->sub_id == HIDPP_SUBID_BATTERY_CHARGING_LEVEL) - return "battery-charging-level"; - if (msg->sub_id == HIDPP_SUBID_USER_INTERFACE_EVENT) - return "user-interface-event"; - if (msg->sub_id == HIDPP_SUBID_F_LOCK_STATUS) - return "f-lock-status"; - if (msg->sub_id == HIDPP_SUBID_CALCULATOR_RESULT) - return "calculator-result"; - if (msg->sub_id == HIDPP_SUBID_MENU_NAVIGATE) - return "menu-navigate"; - if (msg->sub_id == HIDPP_SUBID_FN_KEY) - return "fn-key"; - if (msg->sub_id == HIDPP_SUBID_BATTERY_MILEAGE) - return "battery-mileage"; - if (msg->sub_id == HIDPP_SUBID_UART_RX) - return "uart-rx"; - if (msg->sub_id == HIDPP_SUBID_BACKLIGHT_DURATION_UPDATE) - return "backlight-duration-update"; - if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCONNECTION) - return "device-disconnection"; - if (msg->sub_id == HIDPP_SUBID_DEVICE_CONNECTION) - return "device-connection"; - if (msg->sub_id == HIDPP_SUBID_DEVICE_DISCOVERY) - return "device-discovery"; - if (msg->sub_id == HIDPP_SUBID_PIN_CODE_REQUEST) - return "pin-code-request"; - if (msg->sub_id == HIDPP_SUBID_RECEIVER_WORKING_MODE) - return "receiver-working-mode"; - if (msg->sub_id == HIDPP_SUBID_ERROR_MESSAGE) - return "error-message"; - if (msg->sub_id == HIDPP_SUBID_RF_LINK_CHANGE) - return "rf-link-change"; - if (msg->sub_id == HIDPP_SUBID_HCI) - return "hci"; - if (msg->sub_id == HIDPP_SUBID_LINK_QUALITY) - return "link-quality"; - if (msg->sub_id == HIDPP_SUBID_DEVICE_LOCKING_CHANGED) - return "device-locking-changed"; - if (msg->sub_id == HIDPP_SUBID_WIRELESS_DEVICE_CHANGE) - return "wireless-device-change"; - if (msg->sub_id == HIDPP_SUBID_ACL) - return "acl"; - if (msg->sub_id == HIDPP_SUBID_VOIP_TELEPHONY_EVENT) - return "voip-telephony-event"; - if (msg->sub_id == HIDPP_SUBID_LED) - return "led"; - if (msg->sub_id == HIDPP_SUBID_GESTURE_AND_AIR) - return "gesture-and-air"; - if (msg->sub_id == HIDPP_SUBID_TOUCHPAD_MULTI_TOUCH) - return "touchpad-multi-touch"; - if (msg->sub_id == HIDPP_SUBID_TRACEABILITY) - return "traceability"; - if (msg->sub_id == HIDPP_SUBID_SET_REGISTER) - return "set-register"; - if (msg->sub_id == HIDPP_SUBID_GET_REGISTER) - return "get-register"; - if (msg->sub_id == HIDPP_SUBID_SET_LONG_REGISTER) - return "set-long-register"; - if (msg->sub_id == HIDPP_SUBID_GET_LONG_REGISTER) - return "get-long-register"; - if (msg->sub_id == HIDPP_SUBID_SET_VERY_LONG_REGISTER) - return "set-very-long-register"; - if (msg->sub_id == HIDPP_SUBID_GET_VERY_LONG_REGISTER) - return "get-very-long-register"; - if (msg->sub_id == HIDPP_SUBID_ERROR_MSG) - return "error-msg"; - if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20) - return "error-msg-v2"; - return NULL; -} - -gboolean -lu_hidpp_msg_is_reply (LuHidppMsg *msg1, LuHidppMsg *msg2) -{ - g_return_val_if_fail (msg1 != NULL, FALSE); - g_return_val_if_fail (msg2 != NULL, FALSE); - if (msg1->device_id != msg2->device_id && - msg1->device_id != HIDPP_DEVICE_ID_UNSET && - msg2->device_id != HIDPP_DEVICE_ID_UNSET) - return FALSE; - if (msg1->flags & LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID || - msg2->flags & LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID) - return TRUE; - if (msg1->sub_id != msg2->sub_id) - return FALSE; - if (msg1->flags & LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID || - msg2->flags & LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID) - return TRUE; - if (msg1->function_id != msg2->function_id) - return FALSE; - return TRUE; -} - -/* HID++ error */ -gboolean -lu_hidpp_msg_is_error (LuHidppMsg *msg, GError **error) -{ - g_return_val_if_fail (msg != NULL, FALSE); - if (msg->sub_id == HIDPP_SUBID_ERROR_MSG) { - switch (msg->data[1]) { - case HIDPP_ERR_INVALID_SUBID: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "invalid SubID"); - break; - case HIDPP_ERR_INVALID_ADDRESS: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid address"); - break; - case HIDPP_ERR_INVALID_VALUE: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "invalid value"); - break; - case HIDPP_ERR_CONNECT_FAIL: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "connection request failed"); - break; - case HIDPP_ERR_TOO_MANY_DEVICES: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NO_SPACE, - "too many devices connected"); - break; - case HIDPP_ERR_ALREADY_EXISTS: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_EXISTS, - "already exists"); - break; - case HIDPP_ERR_BUSY: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_BUSY, - "busy"); - break; - case HIDPP_ERR_UNKNOWN_DEVICE: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "unknown device"); - break; - case HIDPP_ERR_RESOURCE_ERROR: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_HOST_UNREACHABLE, - "resource error"); - break; - case HIDPP_ERR_REQUEST_UNAVAILABLE: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_EXISTS, - "request not valid in current context"); - break; - case HIDPP_ERR_INVALID_PARAM_VALUE: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "request parameter has unsupported value"); - break; - case HIDPP_ERR_WRONG_PIN_CODE: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_REFUSED, - "the pin code was wrong"); - break; - default: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "generic failure"); - } - return FALSE; - } - if (msg->sub_id == HIDPP_SUBID_ERROR_MSG_20) { - switch (msg->data[1]) { - case HIDPP_ERROR_CODE_INVALID_ARGUMENT: - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "Invalid argument 0x%02x", - msg->data[2]); - break; - case HIDPP_ERROR_CODE_OUT_OF_RANGE: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "out of range"); - break; - case HIDPP_ERROR_CODE_HW_ERROR: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_BROKEN_PIPE, - "hardware error"); - break; - case HIDPP_ERROR_CODE_INVALID_FEATURE_INDEX: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "invalid feature index"); - break; - case HIDPP_ERROR_CODE_INVALID_FUNCTION_ID: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "invalid function ID"); - break; - case HIDPP_ERROR_CODE_BUSY: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_BUSY, - "busy"); - break; - case HIDPP_ERROR_CODE_UNSUPPORTED: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "unsupported"); - break; - default: - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "generic failure"); - break; - } - return FALSE; - } - return TRUE; -} - -void -lu_hidpp_msg_copy (LuHidppMsg *msg_dst, LuHidppMsg *msg_src) -{ - g_return_if_fail (msg_dst != NULL); - g_return_if_fail (msg_src != NULL); - memset (msg_dst->data, 0x00, sizeof(msg_dst->data)); - msg_dst->device_id = msg_src->device_id; - msg_dst->sub_id = msg_src->sub_id; - msg_dst->function_id = msg_src->function_id; - memcpy (msg_dst->data, msg_src->data, sizeof(msg_dst->data)); -} - -/* filter HID++1.0 messages */ -gboolean -lu_hidpp_msg_is_hidpp10_compat (LuHidppMsg *msg) -{ - g_return_val_if_fail (msg != NULL, FALSE); - if (msg->sub_id == 0x40 || - msg->sub_id == 0x41 || - msg->sub_id == 0x49 || - msg->sub_id == 0x4b || - msg->sub_id == 0x8f) { - return TRUE; - } - return FALSE; -} - -gboolean -lu_hidpp_msg_verify_swid (LuHidppMsg *msg) -{ - g_return_val_if_fail (msg != NULL, FALSE); - if ((msg->function_id & 0x0f) != LU_HIDPP_MSG_SW_ID) - return FALSE; - return TRUE; -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-hidpp-msg.h fwupd-1.2.10/plugins/unifying/lu-hidpp-msg.h --- fwupd-1.0.6/plugins/unifying/lu-hidpp-msg.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-hidpp-msg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LU_HIDPP_MSG_H -#define __LU_HIDPP_MSG_H - -#include - -G_BEGIN_DECLS - -typedef enum { - LU_HIDPP_MSG_FLAG_NONE, - LU_HIDPP_MSG_FLAG_LONGER_TIMEOUT = 1 << 0, - LU_HIDPP_MSG_FLAG_IGNORE_SUB_ID = 1 << 1, - LU_HIDPP_MSG_FLAG_IGNORE_FNCT_ID = 1 << 2, - LU_HIDPP_MSG_FLAG_IGNORE_SWID = 1 << 3, - /*< private >*/ - LU_HIDPP_MSG_FLAG_LAST -} LuHidppMsgFlags; - -typedef struct __attribute__((packed)) { - guint8 report_id; - guint8 device_id; - guint8 sub_id; - guint8 function_id; /* funcId:software_id */ - guint8 data[47]; /* maximum supported by Windows XP SP2 */ - /* not included in the packet sent to the hardware */ - guint32 flags; -} LuHidppMsg; - -/* this is specific to fwupd */ -#define LU_HIDPP_MSG_SW_ID 0x07 - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(LuHidppMsg, g_free); - -LuHidppMsg *lu_hidpp_msg_new (void); -void lu_hidpp_msg_copy (LuHidppMsg *msg_dst, - LuHidppMsg *msg_src); -gsize lu_hidpp_msg_get_payload_length (LuHidppMsg *msg); -gboolean lu_hidpp_msg_is_reply (LuHidppMsg *msg1, - LuHidppMsg *msg2); -gboolean lu_hidpp_msg_is_hidpp10_compat (LuHidppMsg *msg); -gboolean lu_hidpp_msg_is_error (LuHidppMsg *msg, - GError **error); -gboolean lu_hidpp_msg_verify_swid (LuHidppMsg *msg); - -const gchar *lu_hidpp_msg_dev_id_to_string (LuHidppMsg *msg); -const gchar *lu_hidpp_msg_rpt_id_to_string (LuHidppMsg *msg); -const gchar *lu_hidpp_msg_sub_id_to_string (LuHidppMsg *msg); -const gchar *lu_hidpp_msg_fcn_id_to_string (LuHidppMsg *msg); - -G_END_DECLS - -#endif /* __LU_HIDPP_MSG_H */ diff -Nru fwupd-1.0.6/plugins/unifying/lu-self-test.c fwupd-1.2.10/plugins/unifying/lu-self-test.c --- fwupd-1.0.6/plugins/unifying/lu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-self-test.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#include "config.h" - -#include -#include - -#include "lu-common.h" - -static void -lu_common_func (void) -{ - guint8 u8; - guint16 u16; - g_autofree gchar *ver1 = NULL; - - u8 = lu_buffer_read_uint8 ("12"); - g_assert_cmpint (u8, ==, 0x12); - u16 = lu_buffer_read_uint16 ("1234"); - g_assert_cmpint (u16, ==, 0x1234); - - ver1 = lu_format_version (" A ", 0x87, 0x65, 0x4321); - g_assert_cmpstr (ver1, ==, "A87.65_B4321"); -} - -int -main (int argc, char **argv) -{ - g_test_init (&argc, &argv, NULL); - - /* only critical and error are fatal */ - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); - - /* tests go here */ - g_test_add_func ("/unifying/common", lu_common_func); - return g_test_run (); -} diff -Nru fwupd-1.0.6/plugins/unifying/lu-tool.c fwupd-1.2.10/plugins/unifying/lu-tool.c --- fwupd-1.0.6/plugins/unifying/lu-tool.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/lu-tool.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,542 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. - */ - -#include "config.h" - -#include -#include - -#include "lu-context.h" -#include "lu-device-bootloader.h" -#include "lu-hidpp.h" - -typedef struct { - GCancellable *cancellable; - GPtrArray *cmd_array; - LuContext *ctx; - LuDeviceKind emulation_kind; -} FuLuToolPrivate; - -static void -lu_tool_private_free (FuLuToolPrivate *priv) -{ - if (priv == NULL) - return; - if (priv->ctx != NULL) - g_object_unref (priv->ctx); - g_object_unref (priv->cancellable); - if (priv->cmd_array != NULL) - g_ptr_array_unref (priv->cmd_array); - g_free (priv); -} -G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuLuToolPrivate, lu_tool_private_free) - -typedef gboolean (*FuLuToolPrivateCb) (FuLuToolPrivate *util, - gchar **values, - GError **error); - -typedef struct { - gchar *name; - gchar *arguments; - gchar *description; - FuLuToolPrivateCb callback; -} FuLuToolItem; - -static void -lu_tool_item_free (FuLuToolItem *item) -{ - g_free (item->name); - g_free (item->arguments); - g_free (item->description); - g_free (item); -} - -static gint -lu_tool_sort_command_name_cb (FuLuToolItem **item1, FuLuToolItem **item2) -{ - return g_strcmp0 ((*item1)->name, (*item2)->name); -} - -static void -lu_tool_add (GPtrArray *array, - const gchar *name, - const gchar *arguments, - const gchar *description, - FuLuToolPrivateCb callback) -{ - g_auto(GStrv) names = NULL; - - g_return_if_fail (name != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (callback != NULL); - - /* add each one */ - names = g_strsplit (name, ",", -1); - for (guint i = 0; names[i] != NULL; i++) { - FuLuToolItem *item = g_new0 (FuLuToolItem, 1); - item->name = g_strdup (names[i]); - if (i == 0) { - item->description = g_strdup (description); - } else { - item->description = g_strdup_printf ("Alias to %s", names[0]); - } - item->arguments = g_strdup (arguments); - item->callback = callback; - g_ptr_array_add (array, item); - } -} - -static gchar * -lu_tool_get_descriptions (GPtrArray *array) -{ - const gsize max_len = 31; - GString *str; - - /* print each command */ - str = g_string_new (""); - for (guint i = 0; i < array->len; i++) { - FuLuToolItem *item = g_ptr_array_index (array, i); - gsize len; - g_string_append (str, " "); - g_string_append (str, item->name); - len = strlen (item->name) + 2; - if (item->arguments != NULL) { - g_string_append (str, " "); - g_string_append (str, item->arguments); - len += strlen (item->arguments) + 1; - } - if (len < max_len) { - for (guint j = len; j < max_len + 1; j++) - g_string_append_c (str, ' '); - g_string_append (str, item->description); - g_string_append_c (str, '\n'); - } else { - g_string_append_c (str, '\n'); - for (guint j = 0; j < max_len + 1; j++) - g_string_append_c (str, ' '); - g_string_append (str, item->description); - g_string_append_c (str, '\n'); - } - } - - /* remove trailing newline */ - if (str->len > 0) - g_string_set_size (str, str->len - 1); - - return g_string_free (str, FALSE); -} - -static gboolean -lu_tool_run (FuLuToolPrivate *priv, - const gchar *command, - gchar **values, - GError **error) -{ - /* find command */ - for (guint i = 0; i < priv->cmd_array->len; i++) { - FuLuToolItem *item = g_ptr_array_index (priv->cmd_array, i); - if (g_strcmp0 (item->name, command) == 0) - return item->callback (priv, values, error); - } - - /* not found */ - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "Command not found"); - return FALSE; -} - -static LuDevice * -lu_get_default_device (FuLuToolPrivate *priv, GError **error) -{ - GPtrArray *devices = NULL; - LuDevice *device = NULL; - - devices = lu_context_get_devices (priv->ctx); - for (guint i = 0; i < devices->len; i++) { - LuDevice *device_tmp = g_ptr_array_index (devices, i); - g_debug ("got %s", lu_device_kind_to_string (lu_device_get_kind (device_tmp))); - if (lu_device_get_kind (device_tmp) != LU_DEVICE_KIND_PERIPHERAL) { - device = g_object_ref (device_tmp); - break; - } - } - - /* nothing supported */ - if (device == NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "No supported device plugged in"); - return NULL; - } - return device; -} - -static gboolean -lu_tool_info_device (LuDevice *device) -{ - g_autofree gchar *str = fu_device_to_string (FU_DEVICE (device)); - g_print ("%s", str); - return TRUE; -} - -static gboolean -lu_tool_info (FuLuToolPrivate *priv, gchar **values, GError **error) -{ - GPtrArray *devices = NULL; - g_autoptr(LuContext) ctx = NULL; - - /* emulated */ - if (priv->emulation_kind != LU_DEVICE_KIND_UNKNOWN) { - g_autoptr(LuDevice) device = NULL; - device = lu_device_fake_new (priv->emulation_kind); - lu_tool_info_device (device); - } - - /* get the devices */ - ctx = lu_context_new (error); - if (ctx == NULL) { - g_prefix_error (error, "Failed to create context: "); - return FALSE; - } - devices = lu_context_get_devices (ctx); - for (guint i = 0; i < devices->len; i++) { - LuDevice *device = g_ptr_array_index (devices, i); - lu_tool_info_device (device); - if (i != devices->len - 1) - g_print ("\n"); - } - return TRUE; -} - -static void -lu_write_progress_cb (FuDevice *device, GParamSpec *pspec, gpointer user_data) -{ - g_print ("Written %u%%\n", fu_device_get_progress (device)); -} - -static gboolean -lu_tool_dump (FuLuToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(GPtrArray) reqs = NULL; - g_autoptr(LuDevice) device = NULL; - g_autoptr(GBytes) fw = NULL; - g_autofree gchar *data = NULL; - gsize len = 0; - - /* check args */ - if (g_strv_length (values) != 1) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Invalid arguments, expected FILENAME" - " -- e.g. `firmware.hex`"); - return FALSE; - } - - /* fake a huge device */ - device = g_object_new (LU_TYPE_DEVICE_BOOTLOADER, NULL); - lu_device_bootloader_set_addr_lo (device, 0x0000); - lu_device_bootloader_set_addr_hi (device, 0xffff); - - /* load file and display */ - if (!g_file_get_contents (values[0], &data, &len, error)) - return FALSE; - fw = g_bytes_new_static (data, len); - reqs = lu_device_bootloader_parse_requests (device, fw, error); - if (reqs == NULL) - return FALSE; - for (guint i = 0; i < reqs->len; i++) { - LuDeviceBootloaderRequest *req = g_ptr_array_index (reqs, i); - g_print ("0x%04x [0x%02x]", req->addr, req->len); - for (guint j = 0; j < req->len; j++) - g_print (" %02x", req->data[j]); - g_print ("\n"); - } - return TRUE; -} - -static gboolean -lu_tool_write (FuLuToolPrivate *priv, gchar **values, GError **error) -{ - gsize len; - g_autofree guint8 *data = NULL; - g_autoptr(GBytes) fw = NULL; - g_autoptr(LuDevice) device = NULL; - - /* check args */ - if (g_strv_length (values) < 1) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Invalid arguments, expected " - "FILENAME [PLATFORM-ID]" - " -- e.g. `firmware.hex`"); - return FALSE; - } - - /* open device */ - if (g_strv_length (values) == 2) { - device = lu_context_find_by_platform_id (priv->ctx, - values[1], - error); - } else if (priv->emulation_kind == LU_DEVICE_KIND_UNKNOWN) { - device = lu_get_default_device (priv, error); - } else { - device = lu_device_fake_new (priv->emulation_kind); - } - if (device == NULL) - return FALSE; - - /* do we need to go into bootloader mode */ - if (lu_device_has_flag (device, LU_DEVICE_FLAG_REQUIRES_DETACH)) { - if (!lu_device_detach (device, error)) - return FALSE; - if (lu_device_has_flag (device, LU_DEVICE_FLAG_DETACH_WILL_REPLUG)) { - if (!lu_context_wait_for_replug (priv->ctx, - device, - FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE, - error)) - return FALSE; - g_usleep (G_USEC_PER_SEC); - g_clear_object (&device); - if (g_strv_length (values) == 2) { - device = lu_context_find_by_platform_id (priv->ctx, - values[1], - error); - } else if (priv->emulation_kind == LU_DEVICE_KIND_UNKNOWN) { - device = lu_get_default_device (priv, error); - } else { - device = lu_device_fake_new (priv->emulation_kind); - } - if (device == NULL) - return FALSE; - if (!lu_device_open (device, error)) { - g_prefix_error (error, "failed to reclaim device: "); - return FALSE; - } - } - } - - /* load firmware file */ - if (!g_file_get_contents (values[0], (gchar **) &data, &len, error)) { - g_prefix_error (error, "Failed to load %s: ", values[0]); - return FALSE; - } - - /* update with data blob */ - fw = g_bytes_new (data, len); - g_signal_connect (device, "notify::progress", - G_CALLBACK (lu_write_progress_cb), NULL); - if (!lu_device_write_firmware (device, fw, error)) - return FALSE; - - /* detach back into runtime */ - if (!lu_device_attach (device, error)) - return FALSE; - - return TRUE; -} - -static gboolean -lu_tool_attach (FuLuToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(LuDevice) device = NULL; - if (g_strv_length (values) == 1) { - device = lu_context_find_by_platform_id (priv->ctx, - values[0], - error); - if (device == NULL) - return FALSE; - } else { - GPtrArray *devices = NULL; - devices = lu_context_get_devices (priv->ctx); - for (guint i = 0; i < devices->len; i++) { - LuDevice *device_tmp = g_ptr_array_index (devices, i); - g_debug ("got %s", lu_device_kind_to_string (lu_device_get_kind (device_tmp))); - if (lu_device_has_flag (device_tmp, LU_DEVICE_FLAG_REQUIRES_ATTACH)) { - device = g_object_ref (device_tmp); - break; - } - } - if (device == NULL) { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "No attachable device plugged in"); - return FALSE; - } - } - if (!lu_device_attach (device, error)) - return FALSE; - return TRUE; -} - -static void -lu_tool_device_added_cb (LuContext* ctx, LuDevice *device, FuLuToolPrivate *priv) -{ - g_print ("ADDED\tLogitech Unifying device %s {%p} [%s]\n", - lu_device_kind_to_string (lu_device_get_kind (device)), - device, fu_device_get_platform_id (FU_DEVICE (device))); - lu_tool_info_device (device); -} - -static void -lu_tool_device_removed_cb (LuContext* ctx, LuDevice *device, FuLuToolPrivate *priv) -{ - g_print ("REMOVED\tLogitech Unifying device %s {%p} [%s]\n", - lu_device_kind_to_string (lu_device_get_kind (device)), - device, fu_device_get_platform_id (FU_DEVICE (device))); -} - -static gboolean -lu_tool_watch (FuLuToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(GMainLoop) loop = g_main_loop_new (NULL, FALSE); - g_signal_connect (priv->ctx, "added", G_CALLBACK (lu_tool_device_added_cb), priv); - g_signal_connect (priv->ctx, "removed", G_CALLBACK (lu_tool_device_removed_cb), priv); - lu_context_coldplug (priv->ctx); - lu_context_set_poll_interval (priv->ctx, 2000); - g_main_loop_run (loop); - return TRUE; -} - -static gboolean -lu_tool_detach (FuLuToolPrivate *priv, gchar **values, GError **error) -{ - g_autoptr(LuDevice) device = NULL; - if (g_strv_length (values) == 1) { - device = lu_context_find_by_platform_id (priv->ctx, - values[0], - error); - } else { - device = lu_get_default_device (priv, error); - } - if (device == NULL) - return FALSE; - if (!lu_device_detach (device, error)) - return FALSE; - return TRUE; -} - -static void -lu_tool_log_handler_cb (const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data) -{ - g_print ("%s\t%s\n", log_domain, message); -} - -int -main (int argc, char **argv) -{ - gboolean verbose = FALSE; - g_autofree gchar *cmd_descriptions = NULL; - g_autofree gchar *emulation_kind = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GOptionContext) context = NULL; - g_autoptr(FuLuToolPrivate) priv = g_new0 (FuLuToolPrivate, 1); - const GOptionEntry options[] = { - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - "Print verbose debug statements", NULL }, - { "emulate", 'e', 0, G_OPTION_ARG_STRING, &emulation_kind, - "Emulate a device type", NULL }, - { NULL} - }; - - /* FIXME: do stuff on ctrl+c */ - priv->cancellable = g_cancellable_new (); - - /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) lu_tool_item_free); - lu_tool_add (priv->cmd_array, - "info", NULL, - "Show information about the device", - lu_tool_info); - lu_tool_add (priv->cmd_array, - "write", "FILENAME", - "Update the firmware", - lu_tool_write); - lu_tool_add (priv->cmd_array, - "dump", "FILENAME", - "Dump the firmware", - lu_tool_dump); - lu_tool_add (priv->cmd_array, - "attach", NULL, - "Attach to firmware mode", - lu_tool_attach); - lu_tool_add (priv->cmd_array, - "watch", NULL, - "Watch for hardare changes", - lu_tool_watch); - lu_tool_add (priv->cmd_array, - "detach", NULL, - "Detach to bootloader mode", - lu_tool_detach); - - /* sort by command name */ - g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) lu_tool_sort_command_name_cb); - - /* get a list of the commands */ - context = g_option_context_new (NULL); - cmd_descriptions = lu_tool_get_descriptions (priv->cmd_array); - g_option_context_set_summary (context, cmd_descriptions); - g_set_application_name ("Logitech Lu Debug Tool"); - g_option_context_add_main_entries (context, options, NULL); - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("%s: %s\n", "Failed to parse arguments", error->message); - return EXIT_FAILURE; - } - - /* emulate */ - priv->emulation_kind = lu_device_kind_from_string (emulation_kind); - if (priv->emulation_kind != LU_DEVICE_KIND_UNKNOWN) - g_log_set_default_handler (lu_tool_log_handler_cb, priv); - - /* get the device */ - priv->ctx = lu_context_new (&error); - if (priv->ctx == NULL) { - g_print ("Failed to open USB devices: %s\n", error->message); - return EXIT_FAILURE; - } - - /* set verbose? */ - if (verbose) - g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); - - /* run the specified command */ - if (!lu_tool_run (priv, argv[1], (gchar**) &argv[2], &error)) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { - g_autofree gchar *tmp = NULL; - tmp = g_option_context_get_help (context, TRUE, NULL); - g_print ("%s\n\n%s", error->message, tmp); - } else { - g_print ("%s\n", error->message); - } - return EXIT_FAILURE; - } - - return 0; -} diff -Nru fwupd-1.0.6/plugins/unifying/meson.build fwupd-1.2.10/plugins/unifying/meson.build --- fwupd-1.0.6/plugins/unifying/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,17 +1,24 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUnifying"'] +install_data([ + 'unifying.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + + shared_module('fu_plugin_unifying', + fu_hash, sources : [ 'fu-plugin-unifying.c', - 'lu-common.c', - 'lu-context.c', - 'lu-device-bootloader.c', - 'lu-device-bootloader-nordic.c', - 'lu-device-bootloader-texas.c', - 'lu-device.c', - 'lu-device-peripheral.c', - 'lu-device-runtime.c', - 'lu-hidpp-msg.c', + 'fu-unifying-bootloader.c', + 'fu-unifying-bootloader-nordic.c', + 'fu-unifying-bootloader-texas.c', + 'fu-unifying-common.c', + 'fu-unifying-hidpp.c', + 'fu-unifying-hidpp-msg.c', + 'fu-unifying-peripheral.c', + 'fu-unifying-runtime.c', ], include_directories : [ include_directories('../..'), @@ -20,49 +27,22 @@ ], install : true, install_dir: plugin_dir, - c_args : cargs, - dependencies : [ - plugin_deps, - gudev, - ], -) - -executable( - 'fu-unifying-util', - sources : [ - 'lu-tool.c', - 'lu-common.c', - 'lu-context.c', - 'lu-device-bootloader.c', - 'lu-device-bootloader-nordic.c', - 'lu-device-bootloader-texas.c', - 'lu-device.c', - 'lu-device-peripheral.c', - 'lu-device-runtime.c', - 'lu-hidpp-msg.c', - ], - include_directories : [ - include_directories('../..'), - include_directories('../../src'), - include_directories('../../libfwupd'), - ], - dependencies : [ - plugin_deps, - gudev, - ], link_with : [ - fwupd, libfwupdprivate, ], c_args : cargs, + dependencies : [ + plugin_deps, + ], ) if get_option('tests') e = executable( 'unifying-self-test', + fu_hash, sources : [ - 'lu-self-test.c', - 'lu-common.c', + 'fu-unifying-self-test.c', + 'fu-unifying-common.c', ], include_directories : [ include_directories('../..'), @@ -70,10 +50,9 @@ ], dependencies : [ plugin_deps, - gudev, ], link_with : [ - fwupd, + libfwupdprivate, ], c_args : cargs, ) diff -Nru fwupd-1.0.6/plugins/unifying/README.md fwupd-1.2.10/plugins/unifying/README.md --- fwupd-1.0.6/plugins/unifying/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -10,12 +10,37 @@ This plugin will not work with the different "Nano" dongle (U0010) as it does not use the Unifying protocol. -Some bootloader protocol infomation was taken from the Mousejack[1] project, +Some bootloader protocol information was taken from the Mousejack[1] project, specifically logitech-usb-restore.py and unifying.py. Other documentation was supplied by Logitech. Additional constants were taken from the Solaar[2] project. +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +a vendor-specific format that appears to be a subset of the Intel HEX format. + +This plugin supports the following protocol IDs: + + * com.logitech.unifying + * com.logitech.unifyingsigned + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values when in DFU mode: + + * `USB\VID_046D&PID_AAAA&REV_0001` + * `USB\VID_046D&PID_AAAA` + * `USB\VID_046D` + +When in runtime mode, the HID raw DeviceInstanceId values are used: + + * `HIDRAW\VEN_046D&DEV_C52B` + * `HIDRAW\VEN_046D` + Design Notes ------------ @@ -25,17 +50,5 @@ means the hardware keeps working while probing, and also allows us to detect paired devices. -Verification ------------- - -If you do not have Unifying hardware you can emulate writing firmware using: - - unifying-tool write file.hex -v --emulate=bootloader-nordic - -This can also be used to produce protocol data to the command line to compare -against USB dumps. This plugin should interact with the hardware exactly like -the Logitech-provided flashing tool, although only a few devices have been -tested. - [1] https://www.mousejack.com/ [2] https://pwr.github.io/Solaar/ diff -Nru fwupd-1.0.6/plugins/unifying/unifying.quirk fwupd-1.2.10/plugins/unifying/unifying.quirk --- fwupd-1.0.6/plugins/unifying/unifying.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/unifying/unifying.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,38 @@ +# Unifying Receiver +[DeviceInstanceId=HIDRAW\VEN_046D&DEV_C52B] +Plugin = unifying +Flags = is-receiver +VendorId=USB:0x046D +InstallDuration = 7 + +# Nordic +[DeviceInstanceId=USB\VID_046D&PID_AAAA] +Plugin = unifying +Flags = is-bootloader,is-nordic +FirmwareSizeMin = 0x4000 +CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 + +# Nordic Pico +[DeviceInstanceId=USB\VID_046D&PID_AAAE] +Plugin = unifying +Flags = is-bootloader,is-nordic +FirmwareSizeMin = 0x4000 +CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 + +# Texas +[DeviceInstanceId=USB\VID_046D&PID_AAAC] +Plugin = unifying +Flags = is-bootloader,is-texas +FirmwareSizeMin = 0x4000 +CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 + +# Texas Pico +[DeviceInstanceId=USB\VID_046D&PID_AAAD] +Plugin = unifying +Flags = is-bootloader,is-texas +FirmwareSizeMin = 0x4000 +CounterpartGuid = HIDRAW\VEN_046D&DEV_C52B +InstallDuration = 7 diff -Nru fwupd-1.0.6/plugins/upower/fu-plugin-upower.c fwupd-1.2.10/plugins/upower/fu-plugin-upower.c --- fwupd-1.0.6/plugins/upower/fu-plugin-upower.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/upower/fu-plugin-upower.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,36 +1,24 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include "fu-plugin.h" #include "fu-plugin-vfuncs.h" +#define MINIMUM_BATTERY_PERCENTAGE 30 + struct FuPluginData { - GDBusProxy *proxy; + GDBusProxy *upower_proxy; + GDBusProxy *display_proxy; }; void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } @@ -38,15 +26,17 @@ fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); - if (data->proxy != NULL) - g_object_unref (data->proxy); + if (data->upower_proxy != NULL) + g_object_unref (data->upower_proxy); + if (data->display_proxy != NULL) + g_object_unref (data->display_proxy); } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - data->proxy = + data->upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL, @@ -55,35 +45,104 @@ "org.freedesktop.UPower", NULL, error); - if (data->proxy == NULL) { + if (data->upower_proxy == NULL) { + g_prefix_error (error, "failed to connect to upower: "); + return FALSE; + } + data->display_proxy = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "org.freedesktop.UPower", + "/org/freedesktop/UPower/devices/DisplayDevice", + "org.freedesktop.UPower.Device", + NULL, + error); + if (data->display_proxy == NULL) { g_prefix_error (error, "failed to connect to upower: "); return FALSE; } + return TRUE; } -gboolean -fu_plugin_update_prepare (FuPlugin *plugin, - FuDevice *device, - GError **error) +static gboolean +fu_plugin_upower_check_percentage_level (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); - g_autoptr(GVariant) value = NULL; + gdouble level; + guint power_type; + g_autoptr(GVariant) percentage_val = NULL; + g_autoptr(GVariant) type_val = NULL; + + /* check that we "have" a battery */ + type_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Type"); + if (type_val == NULL) { + g_warning ("Failed to query power type, assume AC power"); + return TRUE; + } + power_type = g_variant_get_uint32 (type_val); + if (power_type != 2) { + g_debug ("Not running on battery (Type: %u)", power_type); + return TRUE; + } - /* can we only do this on AC power */ - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC)) + /* check percentage high enough */ + percentage_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Percentage"); + if (percentage_val == NULL) { + g_warning ("Failed to query power percentage level, assume enough charge"); return TRUE; - value = g_dbus_proxy_get_cached_property (data->proxy, "OnBattery"); + } + level = g_variant_get_double (percentage_val); + g_debug ("System power source is %.1f%%", level); + + return level >= MINIMUM_BATTERY_PERCENTAGE; +} + +static gboolean +fu_plugin_upower_check_on_battery (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(GVariant) value = NULL; + + value = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery"); if (value == NULL) { g_warning ("failed to get OnBattery value, assume on AC power"); - return TRUE; + return FALSE; } - if (g_variant_get_boolean (value)) { + return g_variant_get_boolean (value); +} + +gboolean +fu_plugin_update_prepare (FuPlugin *plugin, + FwupdInstallFlags flags, + FuDevice *device, + GError **error) +{ + /* not all devices need this */ + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC)) + return TRUE; + + /* determine if operating on AC or battery */ + if (fu_plugin_upower_check_on_battery (plugin) && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_AC_POWER_REQUIRED, "Cannot install update " - "when not on AC power"); + "when not on AC power unless forced"); + return FALSE; + } + + /* deteremine if battery high enough */ + if (!fu_plugin_upower_check_percentage_level (plugin) && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW, + "Cannot install update when battery " + "is not at least %d%% unless forced", + MINIMUM_BATTERY_PERCENTAGE); return FALSE; } return TRUE; diff -Nru fwupd-1.0.6/plugins/upower/meson.build fwupd-1.2.10/plugins/upower/meson.build --- fwupd-1.0.6/plugins/upower/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/plugins/upower/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,6 +1,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginUpower"'] shared_module('fu_plugin_upower', + fu_hash, sources : [ 'fu-plugin-upower.c', ], @@ -11,6 +12,9 @@ ], install : true, install_dir: plugin_dir, + link_with : [ + libfwupdprivate, + ], c_args : cargs, dependencies : [ plugin_deps, diff -Nru fwupd-1.0.6/plugins/wacom-raw/data/hid-recorder.txt fwupd-1.2.10/plugins/wacom-raw/data/hid-recorder.txt --- fwupd-1.0.6/plugins/wacom-raw/data/hid-recorder.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/data/hid-recorder.txt 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,470 @@ +# WCOM4875:00 056A:4875 +# 0x05, 0x0d, // Usage Page (Digitizers) 0 +# 0x09, 0x04, // Usage (Touch Screen) 2 +# 0xa1, 0x01, // Collection (Application) 4 +# 0x85, 0x0c, // Report ID (12) 6 +# 0x95, 0x01, // Report Count (1) 8 +# 0x75, 0x08, // Report Size (8) 10 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 12 +# 0x15, 0x00, // Logical Minimum (0) 15 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 17 +# 0x09, 0x54, // Usage (Contact Count) 19 +# 0x81, 0x02, // Input (Data,Var,Abs) 21 +# 0x05, 0x0d, // Usage Page (Digitizers) 23 +# 0x09, 0x22, // Usage (Finger) 25 +# 0xa1, 0x02, // Collection (Logical) 27 +# 0x09, 0x42, // Usage (Tip Switch) 29 +# 0x15, 0x00, // Logical Minimum (0) 31 +# 0x25, 0x01, // Logical Maximum (1) 33 +# 0x75, 0x01, // Report Size (1) 35 +# 0x95, 0x01, // Report Count (1) 37 +# 0x81, 0x02, // Input (Data,Var,Abs) 39 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 41 +# 0x09, 0x47, // Usage (Confidence) 43 +# 0x81, 0x02, // Input (Data,Var,Abs) 45 +# 0x95, 0x05, // Report Count (5) 47 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 49 +# 0x75, 0x10, // Report Size (16) 51 +# 0x09, 0x51, // Usage (Contact Id) 53 +# 0x95, 0x01, // Report Count (1) 55 +# 0x81, 0x02, // Input (Data,Var,Abs) 57 +# 0x05, 0x01, // Usage Page (Generic Desktop) 59 +# 0x75, 0x10, // Report Size (16) 61 +# 0x95, 0x01, // Report Count (1) 63 +# 0x55, 0x0e, // Unit Exponent (-2) 65 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 67 +# 0x09, 0x30, // Usage (X) 69 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 71 +# 0x35, 0x00, // Physical Minimum (0) 74 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 76 +# 0x81, 0x02, // Input (Data,Var,Abs) 79 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 81 +# 0x09, 0x31, // Usage (Y) 84 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 86 +# 0x81, 0x02, // Input (Data,Var,Abs) 89 +# 0xc0, // End Collection 91 +# 0x05, 0x0d, // Usage Page (Digitizers) 92 +# 0x09, 0x22, // Usage (Finger) 94 +# 0xa1, 0x02, // Collection (Logical) 96 +# 0x09, 0x42, // Usage (Tip Switch) 98 +# 0x15, 0x00, // Logical Minimum (0) 100 +# 0x25, 0x01, // Logical Maximum (1) 102 +# 0x75, 0x01, // Report Size (1) 104 +# 0x95, 0x01, // Report Count (1) 106 +# 0x81, 0x02, // Input (Data,Var,Abs) 108 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 110 +# 0x09, 0x47, // Usage (Confidence) 112 +# 0x81, 0x02, // Input (Data,Var,Abs) 114 +# 0x95, 0x05, // Report Count (5) 116 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 118 +# 0x75, 0x10, // Report Size (16) 120 +# 0x09, 0x51, // Usage (Contact Id) 122 +# 0x95, 0x01, // Report Count (1) 124 +# 0x81, 0x02, // Input (Data,Var,Abs) 126 +# 0x05, 0x01, // Usage Page (Generic Desktop) 128 +# 0x75, 0x10, // Report Size (16) 130 +# 0x95, 0x01, // Report Count (1) 132 +# 0x55, 0x0e, // Unit Exponent (-2) 134 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 136 +# 0x09, 0x30, // Usage (X) 138 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 140 +# 0x35, 0x00, // Physical Minimum (0) 143 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 145 +# 0x81, 0x02, // Input (Data,Var,Abs) 148 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 150 +# 0x09, 0x31, // Usage (Y) 153 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 155 +# 0x81, 0x02, // Input (Data,Var,Abs) 158 +# 0xc0, // End Collection 160 +# 0x05, 0x0d, // Usage Page (Digitizers) 161 +# 0x09, 0x22, // Usage (Finger) 163 +# 0xa1, 0x02, // Collection (Logical) 165 +# 0x09, 0x42, // Usage (Tip Switch) 167 +# 0x15, 0x00, // Logical Minimum (0) 169 +# 0x25, 0x01, // Logical Maximum (1) 171 +# 0x75, 0x01, // Report Size (1) 173 +# 0x95, 0x01, // Report Count (1) 175 +# 0x81, 0x02, // Input (Data,Var,Abs) 177 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 179 +# 0x09, 0x47, // Usage (Confidence) 181 +# 0x81, 0x02, // Input (Data,Var,Abs) 183 +# 0x95, 0x05, // Report Count (5) 185 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 187 +# 0x75, 0x10, // Report Size (16) 189 +# 0x09, 0x51, // Usage (Contact Id) 191 +# 0x95, 0x01, // Report Count (1) 193 +# 0x81, 0x02, // Input (Data,Var,Abs) 195 +# 0x05, 0x01, // Usage Page (Generic Desktop) 197 +# 0x75, 0x10, // Report Size (16) 199 +# 0x95, 0x01, // Report Count (1) 201 +# 0x55, 0x0e, // Unit Exponent (-2) 203 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 205 +# 0x09, 0x30, // Usage (X) 207 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 209 +# 0x35, 0x00, // Physical Minimum (0) 212 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 214 +# 0x81, 0x02, // Input (Data,Var,Abs) 217 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 219 +# 0x09, 0x31, // Usage (Y) 222 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 224 +# 0x81, 0x02, // Input (Data,Var,Abs) 227 +# 0xc0, // End Collection 229 +# 0x05, 0x0d, // Usage Page (Digitizers) 230 +# 0x09, 0x22, // Usage (Finger) 232 +# 0xa1, 0x02, // Collection (Logical) 234 +# 0x09, 0x42, // Usage (Tip Switch) 236 +# 0x15, 0x00, // Logical Minimum (0) 238 +# 0x25, 0x01, // Logical Maximum (1) 240 +# 0x75, 0x01, // Report Size (1) 242 +# 0x95, 0x01, // Report Count (1) 244 +# 0x81, 0x02, // Input (Data,Var,Abs) 246 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 248 +# 0x09, 0x47, // Usage (Confidence) 250 +# 0x81, 0x02, // Input (Data,Var,Abs) 252 +# 0x95, 0x05, // Report Count (5) 254 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 256 +# 0x75, 0x10, // Report Size (16) 258 +# 0x09, 0x51, // Usage (Contact Id) 260 +# 0x95, 0x01, // Report Count (1) 262 +# 0x81, 0x02, // Input (Data,Var,Abs) 264 +# 0x05, 0x01, // Usage Page (Generic Desktop) 266 +# 0x75, 0x10, // Report Size (16) 268 +# 0x95, 0x01, // Report Count (1) 270 +# 0x55, 0x0e, // Unit Exponent (-2) 272 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 274 +# 0x09, 0x30, // Usage (X) 276 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 278 +# 0x35, 0x00, // Physical Minimum (0) 281 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 283 +# 0x81, 0x02, // Input (Data,Var,Abs) 286 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 288 +# 0x09, 0x31, // Usage (Y) 291 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 293 +# 0x81, 0x02, // Input (Data,Var,Abs) 296 +# 0xc0, // End Collection 298 +# 0x05, 0x0d, // Usage Page (Digitizers) 299 +# 0x09, 0x22, // Usage (Finger) 301 +# 0xa1, 0x02, // Collection (Logical) 303 +# 0x09, 0x42, // Usage (Tip Switch) 305 +# 0x15, 0x00, // Logical Minimum (0) 307 +# 0x25, 0x01, // Logical Maximum (1) 309 +# 0x75, 0x01, // Report Size (1) 311 +# 0x95, 0x01, // Report Count (1) 313 +# 0x81, 0x02, // Input (Data,Var,Abs) 315 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 317 +# 0x09, 0x47, // Usage (Confidence) 319 +# 0x81, 0x02, // Input (Data,Var,Abs) 321 +# 0x95, 0x05, // Report Count (5) 323 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 325 +# 0x75, 0x10, // Report Size (16) 327 +# 0x09, 0x51, // Usage (Contact Id) 329 +# 0x95, 0x01, // Report Count (1) 331 +# 0x81, 0x02, // Input (Data,Var,Abs) 333 +# 0x05, 0x01, // Usage Page (Generic Desktop) 335 +# 0x75, 0x10, // Report Size (16) 337 +# 0x95, 0x01, // Report Count (1) 339 +# 0x55, 0x0e, // Unit Exponent (-2) 341 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 343 +# 0x09, 0x30, // Usage (X) 345 +# 0x26, 0xc8, 0x35, // Logical Maximum (13768) 347 +# 0x35, 0x00, // Physical Minimum (0) 350 +# 0x46, 0x72, 0x0d, // Physical Maximum (3442) 352 +# 0x81, 0x02, // Input (Data,Var,Abs) 355 +# 0x46, 0x90, 0x07, // Physical Maximum (1936) 357 +# 0x09, 0x31, // Usage (Y) 360 +# 0x26, 0x40, 0x1e, // Logical Maximum (7744) 362 +# 0x81, 0x02, // Input (Data,Var,Abs) 365 +# 0xc0, // End Collection 367 +# 0x05, 0x0d, // Usage Page (Digitizers) 368 +# 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 370 +# 0x75, 0x10, // Report Size (16) 375 +# 0x95, 0x01, // Report Count (1) 377 +# 0x09, 0x56, // Usage (Scan Time) 379 +# 0x81, 0x02, // Input (Data,Var,Abs) 381 +# 0x85, 0x0c, // Report ID (12) 383 +# 0x09, 0x55, // Usage (Contact Max) 385 +# 0x75, 0x08, // Report Size (8) 387 +# 0x95, 0x01, // Report Count (1) 389 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 391 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 394 +# 0x85, 0x0a, // Report ID (10) 396 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 398 +# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 401 +# 0x96, 0x00, 0x01, // Report Count (256) 403 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 406 +# 0xc0, // End Collection 408 +# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 409 +# 0x09, 0x11, // Usage (Vendor Usage 0x11) 412 +# 0xa1, 0x01, // Collection (Application) 414 +# 0x85, 0x03, // Report ID (3) 416 +# 0xa1, 0x02, // Collection (Logical) 418 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 420 +# 0x75, 0x08, // Report Size (8) 422 +# 0x15, 0x00, // Logical Minimum (0) 424 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 426 +# 0x95, 0x27, // Report Count (39) 429 +# 0x81, 0x02, // Input (Data,Var,Abs) 431 +# 0xc0, // End Collection 433 +# 0x85, 0x02, // Report ID (2) 434 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 436 +# 0x95, 0x01, // Report Count (1) 438 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 440 +# 0x85, 0x03, // Report ID (3) 442 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 444 +# 0x95, 0x3f, // Report Count (63) 446 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 448 +# 0x85, 0x04, // Report ID (4) 450 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 452 +# 0x95, 0x0f, // Report Count (15) 454 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 456 +# 0x85, 0x07, // Report ID (7) 458 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 460 +# 0x96, 0x00, 0x01, // Report Count (256) 462 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 465 +# 0x85, 0x08, // Report ID (8) 467 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 469 +# 0x96, 0x87, 0x00, // Report Count (135) 471 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 474 +# 0x85, 0x09, // Report ID (9) 476 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 478 +# 0x96, 0x3f, 0x00, // Report Count (63) 480 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 483 +# 0x85, 0x0d, // Report ID (13) 485 +# 0x09, 0x00, // Usage (Vendor Usage 0x00) 487 +# 0x95, 0x07, // Report Count (7) 489 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 491 +# 0xc0, // End Collection 493 +# 0x05, 0x0d, // Usage Page (Digitizers) 494 +# 0x09, 0x0e, // Usage (Device Configuration) 496 +# 0xa1, 0x01, // Collection (Application) 498 +# 0x85, 0x0e, // Report ID (14) 500 +# 0x09, 0x23, // Usage (Device Settings) 502 +# 0xa1, 0x02, // Collection (Logical) 504 +# 0x09, 0x52, // Usage (Inputmode) 506 +# 0x09, 0x53, // Usage (Device Index) 508 +# 0x15, 0x00, // Logical Minimum (0) 510 +# 0x25, 0x0a, // Logical Maximum (10) 512 +# 0x75, 0x08, // Report Size (8) 514 +# 0x95, 0x02, // Report Count (2) 516 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 518 +# 0xc0, // End Collection 520 +# 0xc0, // End Collection 521 +# 0x05, 0x0d, // Usage Page (Digitizers) 522 +# 0x09, 0x02, // Usage (Pen) 524 +# 0xa1, 0x01, // Collection (Application) 526 +# 0x85, 0x06, // Report ID (6) 528 +# 0xa4, // Push 530 +# 0x09, 0x20, // Usage (Stylus) 531 +# 0xa1, 0x00, // Collection (Physical) 533 +# 0x09, 0x42, // Usage (Tip Switch) 535 +# 0x09, 0x44, // Usage (Barrel Switch) 537 +# 0x09, 0x45, // Usage (Eraser) 539 +# 0x09, 0x3c, // Usage (Invert) 541 +# 0x09, 0x5a, // Usage (Secondary Barrel Switch) 543 +# 0x09, 0x32, // Usage (In Range) 545 +# 0x15, 0x00, // Logical Minimum (0) 547 +# 0x25, 0x01, // Logical Maximum (1) 549 +# 0x75, 0x01, // Report Size (1) 551 +# 0x95, 0x06, // Report Count (6) 553 +# 0x81, 0x02, // Input (Data,Var,Abs) 555 +# 0x95, 0x02, // Report Count (2) 557 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 559 +# 0x05, 0x01, // Usage Page (Generic Desktop) 561 +# 0x09, 0x30, // Usage (X) 563 +# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 565 +# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 570 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 575 +# 0x55, 0x0d, // Unit Exponent (-3) 577 +# 0x75, 0x10, // Report Size (16) 579 +# 0x95, 0x01, // Report Count (1) 581 +# 0x81, 0x02, // Input (Data,Var,Abs) 583 +# 0x09, 0x31, // Usage (Y) 585 +# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 587 +# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 592 +# 0x81, 0x02, // Input (Data,Var,Abs) 597 +# 0x45, 0x00, // Physical Maximum (0) 599 +# 0x65, 0x00, // Unit (None) 601 +# 0x55, 0x00, // Unit Exponent (0) 603 +# 0x05, 0x0d, // Usage Page (Digitizers) 605 +# 0x09, 0x30, // Usage (Tip Pressure) 607 +# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 609 +# 0x75, 0x10, // Report Size (16) 612 +# 0x81, 0x02, // Input (Data,Var,Abs) 614 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 616 +# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 619 +# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 621 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 624 +# 0x75, 0x10, // Report Size (16) 627 +# 0x81, 0x02, // Input (Data,Var,Abs) 629 +# 0x05, 0x0d, // Usage Page (Digitizers) 631 +# 0x09, 0x5b, // Usage (Transducer Serial Number) 633 +# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 635 +# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 640 +# 0x75, 0x20, // Report Size (32) 645 +# 0x81, 0x02, // Input (Data,Var,Abs) 647 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 649 +# 0x09, 0x00, // Usage (Undefined) 652 +# 0x75, 0x08, // Report Size (8) 654 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 656 +# 0x15, 0x00, // Logical Minimum (0) 659 +# 0x81, 0x02, // Input (Data,Var,Abs) 661 +# 0x05, 0x0d, // Usage Page (Digitizers) 663 +# 0x09, 0x3b, // Usage (Battery Strength) 665 +# 0x81, 0x02, // Input (Data,Var,Abs) 667 +# 0x65, 0x14, // Unit (Degrees,EngRotation) 669 +# 0x55, 0x00, // Unit Exponent (0) 671 +# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 673 +# 0x26, 0x5a, 0x00, // Logical Maximum (90) 676 +# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 679 +# 0x46, 0x5a, 0x00, // Physical Maximum (90) 682 +# 0x75, 0x08, // Report Size (8) 685 +# 0x09, 0x3d, // Usage (X Tilt) 687 +# 0x81, 0x02, // Input (Data,Var,Abs) 689 +# 0x09, 0x3e, // Usage (Y Tilt) 691 +# 0x81, 0x02, // Input (Data,Var,Abs) 693 +# 0xc0, // End Collection 695 +# 0xb4, // Pop 696 +# 0x85, 0x13, // Report ID (19) 697 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 699 +# 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 702 +# 0x96, 0x00, 0x01, // Report Count (256) 704 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 707 +# 0xc0, // End Collection 709 +# 0x06, 0x11, 0xff, // Usage Page (Vendor Usage Page 0xff11) 710 +# 0x09, 0x02, // Usage (Vendor Usage 0x02) 713 +# 0xa1, 0x01, // Collection (Application) 715 +# 0x85, 0x0b, // Report ID (11) 717 +# 0xa4, // Push 719 +# 0x09, 0x20, // Usage (Vendor Usage 0x20) 720 +# 0xa1, 0x00, // Collection (Physical) 722 +# 0x09, 0x42, // Usage (Vendor Usage 0x42) 724 +# 0x09, 0x44, // Usage (Vendor Usage 0x44) 726 +# 0x09, 0x45, // Usage (Vendor Usage 0x45) 728 +# 0x09, 0x3c, // Usage (Vendor Usage 0x3c) 730 +# 0x09, 0x5a, // Usage (Vendor Usage 0x5a) 732 +# 0x09, 0x32, // Usage (Vendor Usage 0x32) 734 +# 0x15, 0x00, // Logical Minimum (0) 736 +# 0x25, 0x01, // Logical Maximum (1) 738 +# 0x75, 0x01, // Report Size (1) 740 +# 0x95, 0x06, // Report Count (6) 742 +# 0x81, 0x02, // Input (Data,Var,Abs) 744 +# 0x95, 0x02, // Report Count (2) 746 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 748 +# 0x05, 0x01, // Usage Page (Generic Desktop) 750 +# 0x09, 0x30, // Usage (X) 752 +# 0x27, 0x70, 0x86, 0x00, 0x00, // Logical Maximum (34416) 754 +# 0x47, 0x70, 0x86, 0x00, 0x00, // Physical Maximum (34416) 759 +# 0x65, 0x11, // Unit (Centimeter,SILinear) 764 +# 0x55, 0x0d, // Unit Exponent (-3) 766 +# 0x75, 0x10, // Report Size (16) 768 +# 0x95, 0x01, // Report Count (1) 770 +# 0x81, 0x02, // Input (Data,Var,Abs) 772 +# 0x09, 0x31, // Usage (Y) 774 +# 0x27, 0x9f, 0x4b, 0x00, 0x00, // Logical Maximum (19359) 776 +# 0x47, 0x9f, 0x4b, 0x00, 0x00, // Physical Maximum (19359) 781 +# 0x81, 0x02, // Input (Data,Var,Abs) 786 +# 0x45, 0x00, // Physical Maximum (0) 788 +# 0x65, 0x00, // Unit (None) 790 +# 0x55, 0x00, // Unit Exponent (0) 792 +# 0x05, 0x0d, // Usage Page (Digitizers) 794 +# 0x09, 0x30, // Usage (Tip Pressure) 796 +# 0x26, 0xff, 0x0f, // Logical Maximum (4095) 798 +# 0x75, 0x10, // Report Size (16) 801 +# 0x81, 0x02, // Input (Data,Var,Abs) 803 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 805 +# 0x09, 0x5b, // Usage (Vendor Usage 0x5b) 808 +# 0x16, 0x00, 0x80, // Logical Minimum (-32768) 810 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 813 +# 0x75, 0x10, // Report Size (16) 816 +# 0x81, 0x02, // Input (Data,Var,Abs) 818 +# 0x05, 0x0d, // Usage Page (Digitizers) 820 +# 0x09, 0x5b, // Usage (Transducer Serial Number) 822 +# 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483648) 824 +# 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 829 +# 0x75, 0x20, // Report Size (32) 834 +# 0x81, 0x02, // Input (Data,Var,Abs) 836 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 838 +# 0x09, 0x00, // Usage (Undefined) 841 +# 0x75, 0x08, // Report Size (8) 843 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 845 +# 0x15, 0x00, // Logical Minimum (0) 848 +# 0x81, 0x02, // Input (Data,Var,Abs) 850 +# 0x05, 0x0d, // Usage Page (Digitizers) 852 +# 0x09, 0x3b, // Usage (Battery Strength) 854 +# 0x81, 0x02, // Input (Data,Var,Abs) 856 +# 0x65, 0x14, // Unit (Degrees,EngRotation) 858 +# 0x55, 0x00, // Unit Exponent (0) 860 +# 0x16, 0xa6, 0xff, // Logical Minimum (-90) 862 +# 0x26, 0x5a, 0x00, // Logical Maximum (90) 865 +# 0x36, 0xa6, 0xff, // Physical Minimum (-90) 868 +# 0x46, 0x5a, 0x00, // Physical Maximum (90) 871 +# 0x75, 0x08, // Report Size (8) 874 +# 0x09, 0x3d, // Usage (X Tilt) 876 +# 0x81, 0x02, // Input (Data,Var,Abs) 878 +# 0x09, 0x3e, // Usage (Y Tilt) 880 +# 0x81, 0x02, // Input (Data,Var,Abs) 882 +# 0xc0, // End Collection 884 +# 0xb4, // Pop 885 +# 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 886 +# 0x75, 0x08, // Report Size (8) 889 +# 0x15, 0x00, // Logical Minimum (0) 891 +# 0x26, 0xff, 0x00, // Logical Maximum (255) 893 +# 0x85, 0x05, // Report ID (5) 896 +# 0x09, 0x00, // Usage (Undefined) 898 +# 0x95, 0x3a, // Report Count (58) 900 +# 0x81, 0x02, // Input (Data,Var,Abs) 902 +# 0x85, 0x10, // Report ID (16) 904 +# 0x09, 0x00, // Usage (Undefined) 906 +# 0x95, 0x14, // Report Count (20) 908 +# 0x81, 0x02, // Input (Data,Var,Abs) 910 +# 0x85, 0x0f, // Report ID (15) 912 +# 0x09, 0x00, // Usage (Undefined) 914 +# 0x95, 0x28, // Report Count (40) 916 +# 0x81, 0x02, // Input (Data,Var,Abs) 918 +# 0x85, 0x0f, // Report ID (15) 920 +# 0x09, 0x00, // Usage (Undefined) 922 +# 0x95, 0x07, // Report Count (7) 924 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 926 +# 0x85, 0x11, // Report ID (17) 928 +# 0x09, 0x00, // Usage (Undefined) 930 +# 0x95, 0x09, // Report Count (9) 932 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 934 +# 0x85, 0x05, // Report ID (5) 936 +# 0x09, 0x00, // Usage (Undefined) 938 +# 0x95, 0x08, // Report Count (8) 940 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 942 +# 0x85, 0x10, // Report ID (16) 944 +# 0x09, 0x00, // Usage (Undefined) 946 +# 0x96, 0x3f, 0x00, // Report Count (63) 948 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 951 +# 0x85, 0x0b, // Report ID (11) 953 +# 0x09, 0x00, // Usage (Undefined) 955 +# 0x96, 0x3f, 0x00, // Report Count (63) 957 +# 0xb1, 0x02, // Feature (Data,Var,Abs) 960 +# 0xc0, // End Collection 962 +# 0x05, 0x01, // Usage Page (Generic Desktop) 963 +# 0x09, 0x02, // Usage (Mouse) 965 +# 0xa1, 0x01, // Collection (Application) 967 +# 0x85, 0x01, // Report ID (1) 969 +# 0x09, 0x01, // Usage (Pointer) 971 +# 0xa1, 0x00, // Collection (Physical) 973 +# 0x05, 0x09, // Usage Page (Button) 975 +# 0x19, 0x01, // Usage Minimum (1) 977 +# 0x29, 0x02, // Usage Maximum (2) 979 +# 0x15, 0x00, // Logical Minimum (0) 981 +# 0x25, 0x01, // Logical Maximum (1) 983 +# 0x95, 0x02, // Report Count (2) 985 +# 0x75, 0x01, // Report Size (1) 987 +# 0x81, 0x02, // Input (Data,Var,Abs) 989 +# 0x95, 0x01, // Report Count (1) 991 +# 0x75, 0x06, // Report Size (6) 993 +# 0x81, 0x03, // Input (Cnst,Var,Abs) 995 +# 0x05, 0x01, // Usage Page (Generic Desktop) 997 +# 0x09, 0x30, // Usage (X) 999 +# 0x09, 0x31, // Usage (Y) 1001 +# 0x26, 0xff, 0x7f, // Logical Maximum (32767) 1003 +# 0x75, 0x10, // Report Size (16) 1006 +# 0x95, 0x02, // Report Count (2) 1008 +# 0x81, 0x02, // Input (Data,Var,Abs) 1010 +# 0xc0, // End Collection 1012 +# 0xc0, // End Collection 1013 diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-plugin-wacom-raw.c fwupd-1.2.10/plugins/wacom-raw/fu-plugin-wacom-raw.c --- fwupd-1.0.6/plugins/wacom-raw/fu-plugin-wacom-raw.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-plugin-wacom-raw.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-wacom-aes-device.h" +#include "fu-wacom-emr-device.h" +#include "fu-wacom-common.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.raw"); + fu_plugin_add_udev_subsystem (plugin, "hidraw"); +} + +gboolean +fu_plugin_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +gboolean +fu_plugin_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +{ + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +gboolean +fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **error) +{ + /* interesting device? */ + if (g_strcmp0 (fu_udev_device_get_subsystem (device), "hidraw") != 0) + return TRUE; + + /* wacom */ + if (fu_udev_device_get_vendor (device) != FU_WACOM_DEVICE_VID) + return TRUE; + + /* no actual device to open */ + if (g_udev_device_get_device_file (fu_udev_device_get_dev (device)) == NULL) + return TRUE; + + /* EMR */ + if (fu_device_has_instance_id (FU_DEVICE (device), "WacomEMR")) { + g_autoptr(FuWacomEmrDevice) dev = fu_wacom_emr_device_new (device); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* AES */ + if (fu_device_has_instance_id (FU_DEVICE (device), "WacomAES")) { + g_autoptr(FuWacomAesDevice) dev = fu_wacom_aes_device_new (device); + g_autoptr(FuDeviceLocker) locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + } + + /* not supported */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Only EMR or AES devices are supported"); + return FALSE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-aes-device.c fwupd-1.2.10/plugins/wacom-raw/fu-wacom-aes-device.c --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-aes-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-aes-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-aes-device.h" + +struct _FuWacomAesDevice { + FuWacomDevice parent_instance; + guint32 hwid; +}; + +G_DEFINE_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU_TYPE_WACOM_DEVICE) + +static gboolean +fu_wacom_aes_device_obtain_hwid (FuWacomAesDevice *self, GError **error) +{ + guint8 cmd[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 }; + guint8 buf[FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ] = { 0x0 }; + + cmd[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID; + cmd[1] = 0x01; /* ?? */ + cmd[2] = 0x01; /* ?? */ + cmd[3] = 0x0f; /* ?? */ + + if (!fu_wacom_device_set_feature (FU_WACOM_DEVICE (self), + cmd, sizeof(cmd), error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + buf[0] = FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID; + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + if (buf[1] == 0xff) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "firmware does not support this feature"); + return FALSE; + } + + /* check magic number */ + if (memcmp (buf, "\x34\x12\x78\x56\x65\x87\x21\x43", 8) != 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "incorrect magic number"); + return FALSE; + } + + /* format the value */ + self->hwid = ((guint32) buf[9]) << 24 | + ((guint32) buf[8]) << 16 | + ((guint32) buf[11]) << 8 | + ((guint32) buf[10]); + return TRUE; + +} + +static gboolean +fu_wacom_aes_query_operation_mode (FuWacomAesDevice *self, GError **error) +{ + guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = { + FU_WACOM_RAW_FW_REPORT_ID, + FU_WACOM_RAW_FW_CMD_QUERY_MODE, + }; + + /* 0x00=runtime, 0x02=bootloader */ + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), buf, sizeof(buf), error)) + return FALSE; + if (buf[1] == 0x00) { + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; + } + if (buf[1] == 0x02) { + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; + } + + /* unsupported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Failed to query operation mode, got 0x%x", + buf[1]); + return FALSE; +} + +static gboolean +fu_wacom_aes_device_setup (FuDevice *device, GError **error) +{ + FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device); + + /* find out if in bootloader mode already */ + if (!fu_wacom_aes_query_operation_mode (self, error)) + return FALSE; + + /* get firmware version */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_set_version (device, "0.0", FWUPD_VERSION_FORMAT_PAIR); + } else { + guint32 fw_ver; + guint8 data[FU_WACOM_RAW_STATUS_REPORT_SZ] = { + FU_WACOM_RAW_STATUS_REPORT_ID, + 0x0 + }; + g_autofree gchar *version = NULL; + g_autoptr(GError) error_local = NULL; + + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + data, sizeof(data), error)) + return FALSE; + fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + version = g_strdup_printf ("%04x.%02x", fw_ver, data[13]); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_PAIR); + + /* get the optional 32 byte HWID and add it as a GUID */ + if (!fu_wacom_aes_device_obtain_hwid (self, &error_local)) { + g_debug ("failed to get HwID: %s", error_local->message); + } else { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("WACOM\\HWID_%04X", self->hwid); + fu_device_add_instance_id (device, devid); + } + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wacom_aes_device_erase_all (FuWacomAesDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, + 2000 * 1000, /* this takes a long time */ + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to send eraseall command: "); + return FALSE; + } + g_usleep (2 * G_USEC_PER_SEC); + return TRUE; +} + +static gboolean +fu_wacom_aes_device_write_block (FuWacomAesDevice *self, + guint32 idx, + guint32 address, + const guint8 *data, + guint16 datasz, + GError **error) +{ + guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self)); + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH, + .echo = (guint8) idx + 1, + .addr = GUINT32_TO_LE(address), + .size8 = datasz / 8, + .data = { 0x00 }, + }; + FuWacomRawResponse rsp = { 0x00 }; + + /* check size */ + if (datasz != blocksz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "block size 0x%x != 0x%x untested", + datasz, (guint) blocksz); + return FALSE; + } + memcpy (&req.data, data, datasz); + + /* write */ + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 1000, + FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) { + g_prefix_error (error, "failed to write block %u: ", idx); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_aes_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error) +{ + FuWacomAesDevice *self = FU_WACOM_AES_DEVICE (device); + + /* erase */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wacom_aes_device_erase_all (self, error)) + return FALSE; + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (!fu_wacom_aes_device_write_block (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + return TRUE; +} + +static void +fu_wacom_aes_device_init (FuWacomAesDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Embedded Wacom AES Device"); +} + +static void +fu_wacom_aes_device_class_init (FuWacomAesDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass); + klass_device->setup = fu_wacom_aes_device_setup; + klass_wac_device->write_firmware = fu_wacom_aes_device_write_firmware; +} + +FuWacomAesDevice * +fu_wacom_aes_device_new (FuUdevDevice *device) +{ + FuWacomAesDevice *self = g_object_new (FU_TYPE_WACOM_AES_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-aes-device.h fwupd-1.2.10/plugins/wacom-raw/fu-wacom-aes-device.h --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-aes-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-aes-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wacom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_AES_DEVICE (fu_wacom_aes_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacomAesDevice, fu_wacom_aes_device, FU, WACOM_AES_DEVICE, FuWacomDevice) + +FuWacomAesDevice *fu_wacom_aes_device_new (FuUdevDevice *device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-common.c fwupd-1.2.10/plugins/wacom-raw/fu-wacom-common.c --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wacom-common.h" + +gboolean +fu_wacom_common_check_reply (const FuWacomRawRequest *req, + const FuWacomRawResponse *rsp, + GError **error) +{ + if (rsp->report_id != FU_WACOM_RAW_BL_REPORT_ID_GET) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "report ID failed, expected 0x%02x, got 0x%02x", + (guint) FU_WACOM_RAW_BL_REPORT_ID_GET, + req->report_id); + return FALSE; + } + if (req->cmd != rsp->cmd) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cmd failed, expected 0x%02x, got 0x%02x", + req->cmd, rsp->cmd); + return FALSE; + } + if (req->echo != rsp->echo) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "echo failed, expected 0x%02x, got 0x%02x", + req->echo, rsp->echo); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, GError **error) +{ + if (rsp->resp == FU_WACOM_RAW_RC_OK) + return TRUE; + if (rsp->resp == FU_WACOM_RAW_RC_BUSY) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_BUSY, + "device is busy"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_MCUTYPE) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "MCU type does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_PID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "PID does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM1) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum1 does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_CHECKSUM2) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "checksum2 does not match"); + return FALSE; + } + if (rsp->resp == FU_WACOM_RAW_RC_TIMEOUT) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "command timed out"); + return FALSE; + } + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "unknown error 0x%02x", rsp->resp); + return FALSE; +} + +gboolean +fu_wacom_common_block_is_empty (const guint8 *data, guint16 datasz) +{ + for (guint16 i = 0; i < datasz; i++) { + if (data[i] != 0xff) + return FALSE; + } + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-common.h fwupd-1.2.10/plugins/wacom-raw/fu-wacom-common.h --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_WACOM_DEVICE_VID 0x056A +#define FU_WACOM_RAW_CMD_RETRIES 1000 + +#define FU_WACOM_RAW_STATUS_REPORT_ID 0x04 +#define FU_WACOM_RAW_STATUS_REPORT_SZ 16 + +#define FU_WACOM_RAW_FW_REPORT_ID 0x02 +#define FU_WACOM_RAW_FW_CMD_QUERY_MODE 0x00 +#define FU_WACOM_RAW_FW_CMD_DETACH 0x02 +#define FU_WACOM_RAW_FW_REPORT_SZ 2 + +#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_ID 0x09 +#define FU_WACOM_RAW_FW_MAINTAIN_REPORT_SZ 64 + +#define FU_WACOM_RAW_BL_REPORT_ID_SET 0x07 +#define FU_WACOM_RAW_BL_REPORT_ID_GET 0x08 + +#define FU_WACOM_RAW_BL_CMD_ERASE_FLASH 0x00 +#define FU_WACOM_RAW_BL_CMD_WRITE_FLASH 0x01 +#define FU_WACOM_RAW_BL_CMD_VERIFY_FLASH 0x02 +#define FU_WACOM_RAW_BL_CMD_ATTACH 0x03 +#define FU_WACOM_RAW_BL_CMD_GET_BLVER 0x04 +#define FU_WACOM_RAW_BL_CMD_GET_MPUTYPE 0x05 +#define FU_WACOM_RAW_BL_CMD_CHECK_MODE 0x07 +#define FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM 0x0e +#define FU_WACOM_RAW_BL_CMD_ALL_ERASE 0x90 + +#define FU_WACOM_RAW_RC_OK 0x00 +#define FU_WACOM_RAW_RC_BUSY 0x80 +#define FU_WACOM_RAW_RC_MCUTYPE 0x0c +#define FU_WACOM_RAW_RC_PID 0x0d +#define FU_WACOM_RAW_RC_CHECKSUM1 0x81 +#define FU_WACOM_RAW_RC_CHECKSUM2 0x82 +#define FU_WACOM_RAW_RC_TIMEOUT 0x87 +#define FU_WACOM_RAW_RC_IN_PROGRESS 0xff + +#define FU_WACOM_RAW_ECHO_DEFAULT g_random_int_range(0xa0,0xfe) + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 cmd; + guint8 echo; + guint32 addr; + guint8 size8; + guint8 data[128]; + guint8 data_unused[121]; +} FuWacomRawRequest; + +typedef struct __attribute__((packed)) { + guint8 report_id; + guint8 cmd; + guint8 echo; + guint8 resp; + guint8 data_unused[132]; +} FuWacomRawResponse; + +gboolean fu_wacom_common_rc_set_error (const FuWacomRawResponse *rsp, + GError **error); +gboolean fu_wacom_common_check_reply (const FuWacomRawRequest *req, + const FuWacomRawResponse *rsp, + GError **error); +gboolean fu_wacom_common_block_is_empty (const guint8 *data, + guint16 datasz); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-device.c fwupd-1.2.10/plugins/wacom-raw/fu-wacom-device.c --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-device.h" +#include "dfu-firmware.h" + +typedef struct +{ + gint fd; + guint flash_block_size; + guint32 flash_base_addr; + guint32 flash_size; +} FuWacomDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuWacomDevice, fu_wacom_device, FU_TYPE_UDEV_DEVICE) + +#define GET_PRIVATE(o) (fu_wacom_device_get_instance_private (o)) + +static void +fu_wacom_device_to_string (FuDevice *device, GString *str) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + g_string_append (str, " FuWacomDevice:\n"); + g_string_append_printf (str, " fd:\t\t\t%i\n", priv->fd); + g_string_append_printf (str, " flash-block-size:\t0x%04x\n", priv->flash_block_size); + g_string_append_printf (str, " flash-base-addr:\t0x%04x\n", priv->flash_base_addr); + g_string_append_printf (str, " flash-size:\t\t0x%04x\n", priv->flash_size); +} + +guint +fu_wacom_device_get_block_sz (FuWacomDevice *self) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + return priv->flash_block_size; +} + +guint +fu_wacom_device_get_base_addr (FuWacomDevice *self) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + return priv->flash_base_addr; +} + +gboolean +fu_wacom_device_check_mpu (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_GET_MPUTYPE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to get MPU type: "); + return FALSE; + } + + /* W9013 */ + if (rsp.resp == 0x2e) { + fu_device_add_instance_id (FU_DEVICE (self), "WacomEMR_W9013"); + return TRUE; + } + + /* W9021 */ + if (rsp.resp == 0x45) { + fu_device_add_instance_id (FU_DEVICE (self), "WacomEMR_W9021"); + return TRUE; + } + + /* unsupported */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "MPU is not W9013 or W9021: 0x%x", + rsp.resp); + return FALSE; +} + +static gboolean +fu_wacom_device_open (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (device)); + + /* open device */ + priv->fd = g_open (g_udev_device_get_device_file (udev_device), O_RDWR); + if (priv->fd < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open %s", + g_udev_device_get_device_file (udev_device)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wacom_device_close (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (!g_close (priv->fd, error)) + return FALSE; + priv->fd = 0; + return TRUE; +} + +static gboolean +fu_wacom_device_probe (FuUdevDevice *device, GError **error) +{ + /* set the physical ID */ + if (!fu_udev_device_set_physical_id (device, "hid", error)) + return FALSE; + return TRUE; +} + +static gboolean +fu_wacom_device_detach (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + guint8 buf[FU_WACOM_RAW_FW_REPORT_SZ] = { + FU_WACOM_RAW_FW_REPORT_ID, + FU_WACOM_RAW_FW_CMD_DETACH, + }; + if (!fu_wacom_device_set_feature (self, buf, sizeof(buf), error)) { + g_prefix_error (error, "failed to switch to bootloader mode: "); + return FALSE; + } + g_usleep (300 * 1000); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_wacom_device_attach (FuDevice *device, GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomRawRequest req = { + .report_id = FU_WACOM_RAW_BL_REPORT_ID_SET, + .cmd = FU_WACOM_RAW_BL_CMD_ATTACH, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + if (!fu_wacom_device_set_feature (self, (const guint8 *) &req, sizeof(req), error)) { + g_prefix_error (error, "failed to switch to runtime mode: "); + return FALSE; + } + /* only required on AES, but harmless for EMR */ + g_usleep (300 * 1000); + fu_device_remove_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + return TRUE; +} + +static gboolean +fu_wacom_device_check_mode (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_CHECK_MODE, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (self, &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to check mode: "); + return FALSE; + } + if (rsp.resp != 0x06) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "check mode failed, mode=0x%02x", + rsp.resp); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_device_set_version_bootloader (FuWacomDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_GET_BLVER, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + FuWacomRawResponse rsp = { 0x00 }; + g_autofree gchar *version = NULL; + if (!fu_wacom_device_cmd (self, &req, &rsp, 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK, error)) { + g_prefix_error (error, "failed to get bootloader version: "); + return FALSE; + } + version = g_strdup_printf ("%u", rsp.resp); + fu_device_set_version_bootloader (FU_DEVICE (self), version); + return TRUE; +} + +static gboolean +fu_wacom_device_write_firmware (FuDevice *device, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + FuWacomDeviceClass *klass = FU_WACOM_DEVICE_GET_CLASS (device); + DfuElement *element; + DfuImage *image; + GBytes *fw_new; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GPtrArray) chunks = NULL; + + /* parse hex file */ + if (!dfu_firmware_parse_data (firmware, fw, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) + return FALSE; + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'ihex', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image_default (firmware); + if (image == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image"); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no element in image"); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + + /* check start address and size */ + if (dfu_element_get_address (element) != priv->flash_base_addr) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "base addr invalid: 0x%05x", + (guint) dfu_element_get_address (element)); + return FALSE; + } + fw_new = dfu_element_get_contents (element); + if (g_bytes_get_size (fw_new) > priv->flash_size) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "size is invalid: 0x%05x", + (guint) g_bytes_get_size (fw_new)); + return FALSE; + } + + /* we're in bootloader mode now */ + if (!fu_wacom_device_check_mode (self, error)) + return FALSE; + if (!fu_wacom_device_set_version_bootloader (self, error)) + return FALSE; + + /* flash chunks */ + chunks = fu_chunk_array_new_from_bytes (fw_new, priv->flash_base_addr, + 0x00, /* page_sz */ + priv->flash_block_size); + return klass->write_firmware (device, chunks, error); +} + +gboolean +fu_wacom_device_set_feature (FuWacomDevice *self, + const guint8 *data, + guint datasz, + GError **error) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + + /* Set Feature */ + fu_common_dump_raw (G_LOG_DOMAIN, "SetFeature", data, datasz); + if (ioctl (priv->fd, HIDIOCSFEATURE(datasz), data) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to SetFeature"); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wacom_device_get_feature (FuWacomDevice *self, + guint8 *data, + guint datasz, + GError **error) +{ + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (ioctl (priv->fd, HIDIOCGFEATURE(datasz), data) < 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to GetFeature"); + return FALSE; + } + fu_common_dump_raw (G_LOG_DOMAIN, "GetFeature", data, datasz); + return TRUE; +} + +gboolean +fu_wacom_device_cmd (FuWacomDevice *self, + FuWacomRawRequest *req, FuWacomRawResponse *rsp, + gulong delay_us, FuWacomDeviceCmdFlags flags, + GError **error) +{ + req->report_id = FU_WACOM_RAW_BL_REPORT_ID_SET; + if (!fu_wacom_device_set_feature (self, (const guint8 *)req, sizeof(*req), error)) { + g_prefix_error (error, "failed to send: "); + return FALSE; + } + if (delay_us > 0) + g_usleep (delay_us); + rsp->report_id = FU_WACOM_RAW_BL_REPORT_ID_GET; + if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) { + g_prefix_error (error, "failed to receive: "); + return FALSE; + } + if (flags & FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK) + return TRUE; + if (!fu_wacom_common_check_reply (req, rsp, error)) + return FALSE; + + /* wait for the command to complete */ + if (flags & FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING && + rsp->resp != FU_WACOM_RAW_RC_OK) { + for (guint i = 0; i < FU_WACOM_RAW_CMD_RETRIES; i++) { + if (delay_us > 0) + g_usleep (delay_us); + if (!fu_wacom_device_get_feature (self, (guint8 *)rsp, sizeof(*rsp), error)) + return FALSE; + if (!fu_wacom_common_check_reply (req, rsp, error)) + return FALSE; + if (rsp->resp != FU_WACOM_RAW_RC_IN_PROGRESS && + rsp->resp != FU_WACOM_RAW_RC_BUSY) + break; + } + } + return fu_wacom_common_rc_set_error (rsp, error); +} + +static gboolean +fu_wacom_device_set_quirk_kv (FuDevice *device, + const gchar *key, + const gchar *value, + GError **error) +{ + FuWacomDevice *self = FU_WACOM_DEVICE (device); + FuWacomDevicePrivate *priv = GET_PRIVATE (self); + if (g_strcmp0 (key, "WacomI2cFlashBlockSize") == 0) { + priv->flash_block_size = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "WacomI2cFlashBaseAddr") == 0) { + priv->flash_base_addr = fu_common_strtoull (value); + return TRUE; + } + if (g_strcmp0 (key, "WacomI2cFlashSize") == 0) { + priv->flash_size = fu_common_strtoull (value); + return TRUE; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_wacom_device_init (FuWacomDevice *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); +} + +static void +fu_wacom_device_class_init (FuWacomDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUdevDeviceClass *klass_device_udev = FU_UDEV_DEVICE_CLASS (klass); + klass_device->to_string = fu_wacom_device_to_string; + klass_device->open = fu_wacom_device_open; + klass_device->close = fu_wacom_device_close; + klass_device->write_firmware = fu_wacom_device_write_firmware; + klass_device->attach = fu_wacom_device_attach; + klass_device->detach = fu_wacom_device_detach; + klass_device->set_quirk_kv = fu_wacom_device_set_quirk_kv; + klass_device_udev->probe = fu_wacom_device_probe; +} diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-device.h fwupd-1.2.10/plugins/wacom-raw/fu-wacom-device.h --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wacom-common.h" +#include "fu-udev-device.h" +#include "dfu-element.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_DEVICE (fu_wacom_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuWacomDevice, fu_wacom_device, FU, WACOM_DEVICE, FuUdevDevice) + +struct _FuWacomDeviceClass +{ + FuUdevDeviceClass parent_class; + gboolean (*write_firmware) (FuDevice *self, + GPtrArray *chunks, + GError **error); +}; + +typedef enum { + FU_WACOM_DEVICE_CMD_FLAG_NONE = 0, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING = 1 << 0, + FU_WACOM_DEVICE_CMD_FLAG_NO_ERROR_CHECK = 1 << 1, +} FuWacomDeviceCmdFlags; + +gboolean fu_wacom_device_set_feature (FuWacomDevice *self, + const guint8 *data, + guint datasz, + GError **error); +gboolean fu_wacom_device_get_feature (FuWacomDevice *self, + guint8 *data, + guint datasz, + GError **error); +gboolean fu_wacom_device_cmd (FuWacomDevice *self, + FuWacomRawRequest *req, + FuWacomRawResponse *rsp, + gulong delay_us, + FuWacomDeviceCmdFlags flags, + GError **error); +gboolean fu_wacom_device_erase_all (FuWacomDevice *self, + GError **error); +gboolean fu_wacom_device_check_mpu (FuWacomDevice *self, + GError **error); +guint fu_wacom_device_get_block_sz (FuWacomDevice *self); +guint fu_wacom_device_get_base_addr (FuWacomDevice *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-emr-device.c fwupd-1.2.10/plugins/wacom-raw/fu-wacom-emr-device.c --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-emr-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-emr-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-chunk.h" +#include "fu-wacom-common.h" +#include "fu-wacom-emr-device.h" + +struct _FuWacomEmrDevice { + FuWacomDevice parent_instance; +}; + +G_DEFINE_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU_TYPE_WACOM_DEVICE) + +static gboolean +fu_wacom_emr_device_setup (FuDevice *device, GError **error) +{ + FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device); + + /* check MPU type */ + if (!fu_wacom_device_check_mpu (FU_WACOM_DEVICE (self), error)) + return FALSE; + + /* get firmware version */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) { + fu_device_set_version (device, "0.0", FWUPD_VERSION_FORMAT_PAIR); + } else { + guint16 fw_ver; + guint8 data[19] = { 0x03, 0x0 }; /* 0x03 is an unknown ReportID */ + g_autofree gchar *version = NULL; + if (!fu_wacom_device_get_feature (FU_WACOM_DEVICE (self), + data, sizeof(data), error)) + return FALSE; + fw_ver = fu_common_read_uint16 (data + 11, G_LITTLE_ENDIAN); + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + version = fu_common_version_from_uint16 (fw_ver, FWUPD_VERSION_FORMAT_PAIR); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_PAIR); + } + + /* success */ + return TRUE; +} + +static guint8 +fu_wacom_emr_device_calc_checksum (guint8 init1, const guint8 *buf, guint8 bufsz) +{ + guint8 sum = 0; + sum += init1; + for (guint i = 0; i < bufsz; i++) + sum += buf[i]; + return ~sum + 1; +} + +static gboolean +fu_wacom_emr_device_w9013_erase_data (FuWacomEmrDevice *self, GError **error) +{ + FuWacomRawResponse rsp = { 0x00 }; + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ERASE_DATAMEM, + .echo = FU_WACOM_RAW_ECHO_DEFAULT, + 0x00 + }; + guint8 *buf = (guint8 *) &req.addr; + buf[0] = 0x00; /* erased block */ + buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00, + (const guint8 *) &req, 4); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to erase datamem: "); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_emr_device_w9013_erase_code (FuWacomEmrDevice *self, + guint8 idx, + guint8 block_nr, + GError **error) +{ + FuWacomRawResponse rsp = { 0x00 }; + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ERASE_FLASH, + .echo = idx, + 0x00 + }; + guint8 *buf = (guint8 *) &req.addr; + buf[0] = block_nr; + buf[1] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x07 + 0x00, + (const guint8 *) &req, 4); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to erase codemem: "); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_device_w9021_erase_all (FuWacomEmrDevice *self, GError **error) +{ + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_ALL_ERASE, + .echo = 0x01, + .addr = 0x00, + }; + FuWacomRawResponse rsp = { 0x00 }; + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, + 2000 * 1000, /* this takes a long time */ + FU_WACOM_DEVICE_CMD_FLAG_POLL_ON_WAITING, error)) { + g_prefix_error (error, "failed to send eraseall command: "); + return FALSE; + } + if (!fu_wacom_common_rc_set_error (&rsp, error)) { + g_prefix_error (error, "failed to erase"); + return FALSE; + } + g_usleep (50); + return TRUE; +} + +static gboolean +fu_wacom_emr_device_write_block (FuWacomEmrDevice *self, + guint32 idx, + guint32 address, + const guint8 *data, + guint16 datasz, + GError **error) +{ + guint blocksz = fu_wacom_device_get_block_sz (FU_WACOM_DEVICE (self)); + FuWacomRawRequest req = { + .cmd = FU_WACOM_RAW_BL_CMD_WRITE_FLASH, + .echo = (guint8) idx + 1, + .addr = GUINT32_TO_LE(address), + .size8 = datasz / 8, + .data = { 0x00 }, + }; + FuWacomRawResponse rsp = { 0x00 }; + + /* check size */ + if (datasz > sizeof(req.data)) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "data size 0x%x too large for packet", + datasz); + return FALSE; + } + if (datasz != blocksz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "block size 0x%x != 0x%x untested", + datasz, (guint) blocksz); + return FALSE; + } + + /* data */ + memcpy (&req.data, data, datasz); + + /* cmd and data checksums */ + req.data[blocksz + 0] = fu_wacom_emr_device_calc_checksum (0x05 + 0x00 + 0x4c + 0x00, + (const guint8 *) &req, 8); + req.data[blocksz + 1] = fu_wacom_emr_device_calc_checksum (0x00, data, datasz); + if (!fu_wacom_device_cmd (FU_WACOM_DEVICE (self), &req, &rsp, 50, + FU_WACOM_DEVICE_CMD_FLAG_NONE, error)) { + g_prefix_error (error, "failed to write at 0x%x: ", address); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wacom_emr_device_write_firmware (FuDevice *device, GPtrArray *chunks, GError **error) +{ + FuWacomEmrDevice *self = FU_WACOM_EMR_DEVICE (device); + guint8 idx = 0; + + /* erase W9013 */ + if (fu_device_has_instance_id (device, "WacomEMR_W9013")) { + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wacom_emr_device_w9013_erase_data (self, error)) + return FALSE; + for (guint i = 127; i >= 8; i--) { + if (!fu_wacom_emr_device_w9013_erase_code (self, idx++, i, error)) + return FALSE; + } + } + + /* erase W9021 */ + if (fu_device_has_instance_id (device, "WacomEMR_W9021")) { + if (!fu_wacom_device_w9021_erase_all (self, error)) + return FALSE; + } + + /* write */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + if (fu_wacom_common_block_is_empty (chk->data, chk->data_sz)) + continue; + if (!fu_wacom_emr_device_write_block (self, + chk->idx, + chk->address, + chk->data, + chk->data_sz, + error)) + return FALSE; + fu_device_set_progress_full (device, (gsize) i, (gsize) chunks->len); + } + + fu_device_set_progress (device, 100); + return TRUE; +} + +static void +fu_wacom_emr_device_init (FuWacomEmrDevice *self) +{ + fu_device_set_name (FU_DEVICE (self), "Embedded Wacom EMR Device"); +} + +static void +fu_wacom_emr_device_class_init (FuWacomEmrDeviceClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuWacomDeviceClass *klass_wac_device = FU_WACOM_DEVICE_CLASS (klass); + klass_device->setup = fu_wacom_emr_device_setup; + klass_wac_device->write_firmware = fu_wacom_emr_device_write_firmware; +} + +FuWacomEmrDevice * +fu_wacom_emr_device_new (FuUdevDevice *device) +{ + FuWacomEmrDevice *self = g_object_new (FU_TYPE_WACOM_EMR_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/wacom-raw/fu-wacom-emr-device.h fwupd-1.2.10/plugins/wacom-raw/fu-wacom-emr-device.h --- fwupd-1.0.6/plugins/wacom-raw/fu-wacom-emr-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/fu-wacom-emr-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wacom-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WACOM_EMR_DEVICE (fu_wacom_emr_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacomEmrDevice, fu_wacom_emr_device, FU, WACOM_EMR_DEVICE, FuUdevDevice) + +FuWacomEmrDevice *fu_wacom_emr_device_new (FuUdevDevice *device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-raw/meson.build fwupd-1.2.10/plugins/wacom-raw/meson.build --- fwupd-1.0.6/plugins/wacom-raw/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,31 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginWacomRaw"'] + +install_data(['wacom-raw.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_wacom_raw', + fu_hash, + sources : [ + 'fu-plugin-wacom-raw.c', + 'fu-wacom-common.c', + 'fu-wacom-device.c', + 'fu-wacom-aes-device.c', + 'fu-wacom-emr-device.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../dfu'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + dfu, + ], +) diff -Nru fwupd-1.0.6/plugins/wacom-raw/README.md fwupd-1.2.10/plugins/wacom-raw/README.md --- fwupd-1.0.6/plugins/wacom-raw/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,36 @@ +Wacom RAW Support +================= + +Introduction +------------ + +This plugin updates integrated Wacom AES and EMR devices. They are typically +connected using I²C and not USB. + +GUID Generation +--------------- + +The HID DeviceInstanceId values are used, e.g. `HIDRAW\VEN_056A&DEV_4875`. + +Additionally, for supported AES devices an extra GUID is added for the hardware +ID (e.g. `WACOM\HWID_%04X`) to further disambiguate the panels. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +Intel HEX file format. + +This plugin supports the following protocol ID: + + * com.wacom.raw + +Quirk use +--------- +This plugin uses the following plugin-specific quirks: + +| Quirk | Description | Minimum fwupd version | +|-------------------------|-------------------------------------|-----------------------| +| `WacomI2cFlashBlockSize`| Block size to transfer firmware | 1.2.4 | +| `WacomI2cFlashBaseAddr` | Base address for firmware | 1.2.4 | +| `WacomI2cFlashSize` | Maximum size of the firmware zone | 1.2.4 | diff -Nru fwupd-1.0.6/plugins/wacom-raw/wacom-raw.quirk fwupd-1.2.10/plugins/wacom-raw/wacom-raw.quirk --- fwupd-1.0.6/plugins/wacom-raw/wacom-raw.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-raw/wacom-raw.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,35 @@ +# Devices that do "replug" and thus don't change VID:PID to the bootloader +# need to have an extra GUID of WacomAES or WacomEMR added so that the flash +# constants are set correctly. + +# Dell XPS-15 9575 +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_4875] +Plugin = wacom_raw +Guid = WacomAES + +# AES bootloader mode +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_0094] +Plugin = wacom_raw +Guid = WacomAES +Flags = is-bootloader + +# EMR bootloader mode +[DeviceInstanceId=HIDRAW\VEN_056A&DEV_012B] +Plugin = wacom_raw +Guid = WacomEMR +Flags = is-bootloader + +[Guid=WacomEMR_W9013] +WacomI2cFlashBlockSize=64 +WacomI2cFlashBaseAddr=0x2000 +WacomI2cFlashSize=0x1e000 + +[Guid=WacomEMR_W9021] +WacomI2cFlashBlockSize=256 +WacomI2cFlashBaseAddr=0x3000 +WacomI2cFlashSize=0x3c000 + +[Guid=WacomAES] +WacomI2cFlashBlockSize=128 +WacomI2cFlashBaseAddr=0x8000 +WacomI2cFlashSize=0x24000 diff -Nru fwupd-1.0.6/plugins/wacom-usb/data/lsusb.txt fwupd-1.2.10/plugins/wacom-usb/data/lsusb.txt --- fwupd-1.0.6/plugins/wacom-usb/data/lsusb.txt 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/data/lsusb.txt 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,58 @@ +Bus 001 Device 023: ID 056a:0378 Wacom Co., Ltd CTL-6100WL [Intuos BT (M)] +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x056a Wacom Co., Ltd + idProduct 0x0378 CTL-6100WL [Intuos BT (M)] + bcdDevice 1.66 + iManufacturer 1 Wacom Co.,Ltd. + iProduct 2 Intuos BT M + iSerial 3 8BH00U2012294 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0022 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 759 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-plugin-wacom-usb.c fwupd-1.2.10/plugins/wacom-usb/fu-plugin-wacom-usb.c --- fwupd-1.0.6/plugins/wacom-usb/fu-plugin-wacom-usb.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-plugin-wacom-usb.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" + +#include "fu-wac-device.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_REQUIRES_QUIRK, FU_QUIRKS_PLUGIN); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, "com.wacom.usb"); +} + +gboolean +fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) +{ + g_autoptr(FuWacDevice) dev = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + dev = fu_wac_device_new (device); + locker = fu_device_locker_new (dev, error); + if (locker == NULL) + return FALSE; + fu_plugin_device_add (plugin, FU_DEVICE (dev)); + return TRUE; +} + +gboolean +fu_plugin_update (FuPlugin *plugin, FuDevice *device, GBytes *blob_fw, + FwupdInstallFlags flags, GError **error) +{ + FuDevice *parent = fu_device_get_parent (device); + g_autoptr(FuDeviceLocker) locker = NULL; + locker = fu_device_locker_new (parent != NULL ? parent : device, error); + if (locker == NULL) + return FALSE; + return fu_device_write_firmware (device, blob_fw, flags, error); +} + +static FuDevice * +fu_plugin_wacom_usb_get_device (GPtrArray *devices) +{ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + if (FU_IS_WAC_DEVICE (dev)) + return dev; + } + return NULL; +} + +gboolean +fu_plugin_composite_cleanup (FuPlugin *plugin, + GPtrArray *devices, + GError **error) +{ + FuDevice *device = fu_plugin_wacom_usb_get_device (devices); + g_autoptr(FuDeviceLocker) locker = NULL; + + /* not us */ + if (device == NULL) + return TRUE; + + /* reboot, which switches the boot index of the firmware */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + return fu_wac_device_update_reset (FU_WAC_DEVICE (device), error); +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-self-test.c fwupd-1.2.10/plugins/wacom-usb/fu-self-test.c --- fwupd-1.0.6/plugins/wacom-usb/fu-self-test.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-common.h" +#include "fu-test.h" +#include "fu-wac-common.h" +#include "fu-wac-firmware.h" + +#include "fwupd-error.h" + +static void +fu_wac_firmware_parse_func (void) +{ + DfuElement *element; + DfuImage *image; + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GBytes) blob_block = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) error = NULL; + + /* parse the test file */ + fn = fu_test_get_filename (TESTDATADIR, "test.wac"); + if (fn == NULL) { + g_test_skip ("no data file found"); + return; + } + bytes = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + ret = fu_wac_firmware_parse_data (firmware, bytes, + DFU_FIRMWARE_PARSE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* get image data */ + image = dfu_firmware_get_image (firmware, 0); + g_assert_nonnull (image); + element = dfu_image_get_element_default (image); + g_assert_nonnull (element); + + /* get block */ + blob_block = dfu_element_get_contents_chunk (element, 0x8008000, + 1024, &error); + g_assert_no_error (error); + g_assert_nonnull (blob_block); + fu_wac_buffer_dump ("IMG", FU_WAC_REPORT_ID_MODULE, + g_bytes_get_data (blob_block, NULL), + g_bytes_get_size (blob_block)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* log everything */ + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + + /* tests go here */ + g_test_add_func ("/wac/firmware{parse}", fu_wac_firmware_parse_func); + return g_test_run (); +} + diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-common.c fwupd-1.2.10/plugins/wacom-usb/fu-wac-common.c --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-wac-common.h" + +guint32 +fu_wac_calculate_checksum32le (const guint8 *data, gsize len) +{ + guint32 csum = 0x0; + g_return_val_if_fail (len % 4 == 0, 0xff); + for (guint i = 0; i < len; i += 4) { + guint32 tmp; + memcpy (&tmp, &data[i], sizeof(guint32)); + csum += GUINT32_FROM_LE (tmp); + } + return GUINT32_TO_LE (csum); +} + +guint32 +fu_wac_calculate_checksum32le_bytes (GBytes *blob) +{ + gsize len = 0; + const guint8 *data = g_bytes_get_data (blob, &len); + return fu_wac_calculate_checksum32le (data, len); +} + +const gchar * +fu_wac_report_id_to_string (guint8 report_id) +{ + if (report_id == FU_WAC_REPORT_ID_FW_DESCRIPTOR) + return "FwDescriptor"; + if (report_id == FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER) + return "SwitchToFlashLoader"; + if (report_id == FU_WAC_REPORT_ID_QUIT_AND_RESET) + return "QuitAndReset"; + if (report_id == FU_WAC_REPORT_ID_READ_BLOCK_DATA) + return "ReadBlockData"; + if (report_id == FU_WAC_REPORT_ID_WRITE_BLOCK) + return "WriteBlock"; + if (report_id == FU_WAC_REPORT_ID_ERASE_BLOCK) + return "EraseBlock"; + if (report_id == FU_WAC_REPORT_ID_SET_READ_ADDRESS) + return "SetReadAddress"; + if (report_id == FU_WAC_REPORT_ID_GET_STATUS) + return "GetStatus"; + if (report_id == FU_WAC_REPORT_ID_UPDATE_RESET) + return "UpdateReset"; + if (report_id == FU_WAC_REPORT_ID_WRITE_WORD) + return "WriteWord"; + if (report_id == FU_WAC_REPORT_ID_GET_PARAMETERS) + return "GetParameters"; + if (report_id == FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR) + return "GetFlashDescriptor"; + if (report_id == FU_WAC_REPORT_ID_GET_CHECKSUMS) + return "GetChecksums"; + if (report_id == FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK) + return "SetChecksumForBlock"; + if (report_id == FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK) + return "CalculateChecksumForBlock"; + if (report_id == FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE) + return "WriteChecksumTable"; + if (report_id == FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX) + return "GetCurrentFirmwareIdx"; + if (report_id == FU_WAC_REPORT_ID_MODULE) + return "Module"; + return NULL; +} + +void +fu_wac_buffer_dump (const gchar *title, guint8 cmd, const guint8 *buf, gsize sz) +{ + g_autofree gchar *tmp = NULL; + if (g_getenv ("FWUPD_WACOM_USB_VERBOSE") == NULL) + return; + tmp = g_strdup_printf ("%s %s (%" G_GSIZE_FORMAT ")", + title, fu_wac_report_id_to_string (cmd), sz); + fu_common_dump_raw (G_LOG_DOMAIN, tmp, buf, sz); +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-common.h fwupd-1.2.10/plugins/wacom-usb/fu-wac-common.h --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_WAC_PACKET_LEN 512 + +#define FU_WAC_REPORT_ID_COMMAND 0x01 +#define FU_WAC_REPORT_ID_STATUS 0x02 +#define FU_WAC_REPORT_ID_CONTROL 0x03 + +#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_MAIN 0x07 +#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_TOUCH 0x07 +#define FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH 0x16 + +#define FU_WAC_REPORT_ID_FW_DESCRIPTOR 0xcb /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER 0xcc /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_QUIT_AND_RESET 0xcd /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_READ_BLOCK_DATA 0xd1 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_WRITE_BLOCK 0xd2 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_ERASE_BLOCK 0xd3 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_SET_READ_ADDRESS 0xd4 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_STATUS 0xd5 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_UPDATE_RESET 0xd6 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_WRITE_WORD 0xd7 /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_PARAMETERS 0xd8 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR 0xd9 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_CHECKSUMS 0xda /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK 0xdb /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK 0xdc /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE 0xde /* SET_FEATURE */ +#define FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX 0xe2 /* GET_FEATURE */ +#define FU_WAC_REPORT_ID_MODULE 0xe4 + +guint32 fu_wac_calculate_checksum32le (const guint8 *data, + gsize len); +guint32 fu_wac_calculate_checksum32le_bytes (GBytes *blob); +const gchar *fu_wac_report_id_to_string (guint8 report_id); +void fu_wac_buffer_dump (const gchar *title, + guint8 cmd, + const guint8 *buf, + gsize sz); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-device.c fwupd-1.2.10/plugins/wacom-usb/fu-wac-device.c --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,914 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-chunk.h" +#include "fu-wac-device.h" +#include "fu-wac-common.h" +#include "fu-wac-firmware.h" +#include "fu-wac-module-bluetooth.h" +#include "fu-wac-module-touch.h" + +#include "dfu-common.h" +#include "dfu-firmware.h" + +typedef struct __attribute__((packed)) { + guint32 start_addr; + guint32 block_sz; + guint16 write_sz; /* bit 15 is write protection flag */ +} FuWacFlashDescriptor; + +typedef enum { + FU_WAC_STATUS_UNKNOWN = 0, + FU_WAC_STATUS_WRITING = 1 << 0, + FU_WAC_STATUS_ERASING = 1 << 1, + FU_WAC_STATUS_ERROR_WRITE = 1 << 2, + FU_WAC_STATUS_ERROR_ERASE = 1 << 3, + FU_WAC_STATUS_WRITE_PROTECTED = 1 << 4, + FU_WAC_STATUS_LAST +} FuWacStatus; + +#define FU_WAC_DEVICE_TIMEOUT 5000 /* ms */ + +struct _FuWacDevice +{ + FuUsbDevice parent_instance; + GPtrArray *flash_descriptors; + GArray *checksums; + guint32 status_word; + guint16 firmware_index; + guint16 loader_ver; + guint16 read_data_sz; + guint16 write_word_sz; + guint16 write_block_sz; /* usb transfer size */ + guint16 nr_flash_blocks; + guint16 configuration; +}; + +G_DEFINE_TYPE (FuWacDevice, fu_wac_device, FU_TYPE_USB_DEVICE) + +static GString * +fu_wac_device_status_to_string (guint32 status_word) +{ + GString *str = g_string_new (NULL); + if (status_word & FU_WAC_STATUS_WRITING) + g_string_append (str, "writing,"); + if (status_word & FU_WAC_STATUS_ERASING) + g_string_append (str, "erasing,"); + if (status_word & FU_WAC_STATUS_ERROR_WRITE) + g_string_append (str, "error-write,"); + if (status_word & FU_WAC_STATUS_ERROR_ERASE) + g_string_append (str, "error-erase,"); + if (status_word & FU_WAC_STATUS_WRITE_PROTECTED) + g_string_append (str, "write-protected,"); + if (str->len == 0) { + g_string_append (str, "none"); + return str; + } + g_string_truncate (str, str->len - 1); + return str; +} + +static gboolean +fu_wav_device_flash_descriptor_is_wp (const FuWacFlashDescriptor *fd) +{ + return fd->write_sz & 0x8000; +} + +static void +fu_wac_device_to_string (FuDevice *device, GString *str) +{ + GPtrArray *children; + FuWacDevice *self = FU_WAC_DEVICE (device); + g_autoptr(GString) status_str = NULL; + + g_string_append (str, " FuWacDevice:\n"); + if (self->firmware_index != 0xffff) { + g_string_append_printf (str, " fw-index: 0x%04x\n", + self->firmware_index); + } + if (self->loader_ver > 0) { + g_string_append_printf (str, " loader-ver: 0x%04x\n", + (guint) self->loader_ver); + } + if (self->read_data_sz > 0) { + g_string_append_printf (str, " read-data-sz: 0x%04x\n", + (guint) self->read_data_sz); + } + if (self->write_word_sz > 0) { + g_string_append_printf (str, " write-word-sz: 0x%04x\n", + (guint) self->write_word_sz); + } + if (self->write_block_sz > 0) { + g_string_append_printf (str, " write-block-sz: 0x%04x\n", + (guint) self->write_block_sz); + } + if (self->nr_flash_blocks > 0) { + g_string_append_printf (str, " nr-flash-blocks: 0x%04x\n", + (guint) self->nr_flash_blocks); + } + if (self->configuration != 0xffff) { + g_string_append_printf (str, " configuration: 0x%04x\n", + (guint) self->configuration); + } + for (guint i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + g_string_append_printf (str, " flash-descriptor-%02u:\n", i); + g_string_append_printf (str, " start-addr:\t0x%08x\n", + (guint) fd->start_addr); + g_string_append_printf (str, " block-sz:\t0x%08x\n", + (guint) fd->block_sz); + g_string_append_printf (str, " write-sz:\t0x%04x\n", + (guint) fd->write_sz & ~0x8000); + g_string_append_printf (str, " protected:\t%s\n", + fu_wav_device_flash_descriptor_is_wp (fd) ? "yes" : "no"); + } + status_str = fu_wac_device_status_to_string (self->status_word); + g_string_append_printf (str, " status:\t\t%s\n", status_str->str); + + /* print children also */ + children = fu_device_get_children (device); + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + g_autofree gchar *tmp = fu_device_to_string (FU_DEVICE (child)); + g_string_append (str, " FuWacDeviceChild:\n"); + g_string_append (str, tmp); + } +} + +gboolean +fu_wac_device_get_feature_report (FuWacDevice *self, + guint8 *buf, gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize sz = 0; + guint8 cmd = buf[0]; + + /* hit hardware */ + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG) == 0) + fu_wac_buffer_dump ("GET", cmd, buf, bufsz); + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_GET, /* bRequest */ + HID_FEATURE | cmd, /* wValue */ + 0x0000, /* wIndex */ + buf, bufsz, &sz, + FU_WAC_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "Failed to get feature report: "); + return FALSE; + } + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG) == 0) + fu_wac_buffer_dump ("GE2", cmd, buf, sz); + + /* check packet */ + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet get bytes %" G_GSIZE_FORMAT + " expected %" G_GSIZE_FORMAT, + sz, bufsz); + return FALSE; + } + if (buf[0] != cmd) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "command response was %i expected %i", + buf[0], cmd); + return FALSE; + } + return TRUE; +} + +gboolean +fu_wac_device_set_feature_report (FuWacDevice *self, + guint8 *buf, gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + gsize sz = 0; + guint8 cmd = buf[0]; + + /* hit hardware */ + fu_wac_buffer_dump ("SET", cmd, buf, bufsz); + if (g_getenv ("FWUPD_WAC_EMULATE") != NULL) + return TRUE; + if (!g_usb_device_control_transfer (usb_device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + HID_REPORT_SET, /* bRequest */ + HID_FEATURE | cmd, /* wValue */ + 0x0000, /* wIndex */ + buf, bufsz, &sz, + FU_WAC_DEVICE_TIMEOUT, + NULL, error)) { + g_prefix_error (error, "Failed to set feature report: "); + return FALSE; + } + + /* check packet */ + if ((flags & FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC) == 0 && sz != bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet sent bytes %" G_GSIZE_FORMAT + " expected %" G_GSIZE_FORMAT, + sz, bufsz); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_wac_device_ensure_flash_descriptors (FuWacDevice *self, GError **error) +{ + gsize sz = (self->nr_flash_blocks * 10) + 1; + g_autofree guint8 *buf = NULL; + + /* already done */ + if (self->flash_descriptors->len > 0) + return TRUE; + + /* hit hardware */ + buf = g_malloc (sz); + memset (buf, 0xff, sz); + buf[0] = FU_WAC_REPORT_ID_GET_FLASH_DESCRIPTOR; + if (!fu_wac_device_get_feature_report (self, buf, sz, + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + for (guint i = 0; i < self->nr_flash_blocks; i++) { + FuWacFlashDescriptor *fd = g_new0 (FuWacFlashDescriptor, 1); + const guint blksz = sizeof(FuWacFlashDescriptor); + fd->start_addr = fu_common_read_uint32 (buf + (i * blksz) + 1, G_LITTLE_ENDIAN); + fd->block_sz = fu_common_read_uint32 (buf + (i * blksz) + 5, G_LITTLE_ENDIAN); + fd->write_sz = fu_common_read_uint16 (buf + (i * blksz) + 9, G_LITTLE_ENDIAN); + g_ptr_array_add (self->flash_descriptors, fd); + } + g_debug ("added %u flash descriptors", self->flash_descriptors->len); + return TRUE; +} + +static gboolean +fu_wac_device_ensure_status (FuWacDevice *self, GError **error) +{ + g_autoptr(GString) str = NULL; + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_STATUS, + [1 ... 4] = 0xff }; + + /* hit hardware */ + buf[0] = FU_WAC_REPORT_ID_GET_STATUS; + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + self->status_word = fu_common_read_uint32 (buf + 1, G_LITTLE_ENDIAN); + str = fu_wac_device_status_to_string (self->status_word); + g_debug ("status now: %s", str->str); + return TRUE; +} + +static gboolean +fu_wac_device_ensure_checksums (FuWacDevice *self, GError **error) +{ + gsize sz = (self->nr_flash_blocks * 4) + 5; + guint32 updater_version; + g_autofree guint8 *buf = g_malloc (sz); + + /* hit hardware */ + memset (buf, 0xff, sz); + buf[0] = FU_WAC_REPORT_ID_GET_CHECKSUMS; + if (!fu_wac_device_get_feature_report (self, buf, sz, + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + updater_version = fu_common_read_uint32 (buf + 1, G_LITTLE_ENDIAN); + g_debug ("updater-version: %" G_GUINT32_FORMAT, updater_version); + + /* get block checksums */ + g_array_set_size (self->checksums, 0); + for (guint i = 0; i < self->nr_flash_blocks; i++) { + guint32 csum = fu_common_read_uint32 (buf + 5 + (i * 4), G_LITTLE_ENDIAN); + g_debug ("checksum block %02u: 0x%08x", i, (guint) csum); + g_array_append_val (self->checksums, csum); + } + g_debug ("added %u checksums", self->flash_descriptors->len); + + return TRUE; +} + + +static gboolean +fu_wac_device_ensure_firmware_index (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_CURRENT_FIRMWARE_IDX, + [1 ... 2] = 0xff }; + + /* hit hardware */ + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + self->firmware_index = fu_common_read_uint16 (buf + 1, G_LITTLE_ENDIAN); + return TRUE; +} + +static gboolean +fu_wac_device_ensure_parameters (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_PARAMETERS, + [1 ... 12] = 0xff }; + + /* hit hardware */ + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) + return FALSE; + + /* parse */ + self->loader_ver = fu_common_read_uint16 (buf + 1, G_LITTLE_ENDIAN); + self->read_data_sz = fu_common_read_uint16 (buf + 3, G_LITTLE_ENDIAN); + self->write_word_sz = fu_common_read_uint16 (buf + 5, G_LITTLE_ENDIAN); + self->write_block_sz = fu_common_read_uint16 (buf + 7, G_LITTLE_ENDIAN); + self->nr_flash_blocks = fu_common_read_uint16 (buf + 9, G_LITTLE_ENDIAN); + self->configuration = fu_common_read_uint16 (buf + 11, G_LITTLE_ENDIAN); + return TRUE; +} + +static gboolean +fu_wac_device_write_block (FuWacDevice *self, + guint32 addr, + GBytes *blob, + GError **error) +{ + const guint8 *tmp; + gsize bufsz = self->write_block_sz + 5; + gsize sz = 0; + g_autofree guint8 *buf = NULL; + + /* check size */ + tmp = g_bytes_get_data (blob, &sz); + if (sz > self->write_block_sz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "packet was too large at %" G_GSIZE_FORMAT " bytes", + sz); + return FALSE; + } + + /* build packet */ + buf = g_malloc (bufsz); + memset (buf, 0xff, bufsz); + buf[0] = FU_WAC_REPORT_ID_WRITE_BLOCK; + fu_common_write_uint32 (buf + 1, addr, G_LITTLE_ENDIAN); + if (sz > 0) + memcpy (buf + 5, tmp, sz); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, bufsz, + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_erase_block (FuWacDevice *self, guint32 addr, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_ERASE_BLOCK, + [1 ... 4] = 0xff }; + + /* build packet */ + fu_common_write_uint32 (buf + 1, addr, G_LITTLE_ENDIAN); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +gboolean +fu_wac_device_update_reset (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_UPDATE_RESET, + [1 ... 4] = 0xff }; + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_set_checksum_of_block (FuWacDevice *self, + guint16 block_nr, + guint32 checksum, + GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_SET_CHECKSUM_FOR_BLOCK, + [1 ... 6] = 0xff }; + + /* build packet */ + fu_common_write_uint16 (buf + 1, block_nr, G_LITTLE_ENDIAN); + fu_common_write_uint32 (buf + 3, checksum, G_LITTLE_ENDIAN); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_calculate_checksum_of_block (FuWacDevice *self, + guint16 block_nr, + GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_CALCULATE_CHECKSUM_FOR_BLOCK, + [1 ... 2] = 0xff }; + + /* build packet */ + fu_common_write_uint16 (buf + 1, block_nr, G_LITTLE_ENDIAN); + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_write_checksum_table (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_WRITE_CHECKSUM_TABLE, + [1 ... 4] = 0xff }; + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_switch_to_flash_loader (FuWacDevice *self, GError **error) +{ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_SWITCH_TO_FLASH_LOADER, + [1] = 0x05, + [2] = 0x6a }; + + /* hit hardware */ + return fu_wac_device_set_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error); +} + +static gboolean +fu_wac_device_write_firmware (FuDevice *device, + GBytes *blob, + FwupdInstallFlags flags, + GError **error) +{ + DfuElement *element; + DfuImage *image; + FuWacDevice *self = FU_WAC_DEVICE (device); + gsize blocks_done = 0; + gsize blocks_total = 0; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + g_autoptr(GHashTable) fd_blobs = NULL; + g_autofree guint32 *csum_local = NULL; + + /* load .wac file, including metadata */ + if (!fu_wac_firmware_parse_data (firmware, blob, + DFU_FIRMWARE_PARSE_FLAG_NONE, + error)) + return FALSE; + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_SREC) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'srec', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* enter flash mode */ + if (!fu_wac_device_switch_to_flash_loader (self, error)) + return FALSE; + + /* get current selected device */ + if (!fu_wac_device_ensure_firmware_index (self, error)) + return FALSE; + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image (firmware, self->firmware_index == 1 ? 1 : 0); + if (image == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image for index %" G_GUINT16_FORMAT, + self->firmware_index); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no element in image %" G_GUINT16_FORMAT, + self->firmware_index); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + + /* get firmware parameters (page sz and transfer sz) */ + if (!fu_wac_device_ensure_parameters (self, error)) + return FALSE; + + /* get the current flash descriptors */ + if (!fu_wac_device_ensure_flash_descriptors (self, error)) + return FALSE; + + /* get the updater protocol version */ + if (!fu_wac_device_ensure_checksums (self, error)) + return FALSE; + + /* clear all checksums of pages */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + if (!fu_wac_device_set_checksum_of_block (self, i, 0x0, error)) + return FALSE; + } + + /* get the blobs for each chunk */ + fd_blobs = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_bytes_unref); + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + GBytes *blob_block; + g_autoptr(GBytes) blob_tmp = NULL; + + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + blob_tmp = dfu_element_get_contents_chunk (element, + fd->start_addr, + fd->block_sz, + NULL); + if (blob_tmp == NULL) + break; + blob_block = dfu_utils_bytes_pad (blob_tmp, fd->block_sz); + g_hash_table_insert (fd_blobs, fd, blob_block); + } + + /* checksum actions post-write */ + blocks_total = g_hash_table_size (fd_blobs) + 2; + + /* write the data into the flash page */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + csum_local = g_new0 (guint32, self->flash_descriptors->len); + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + GBytes *blob_block; + g_autoptr(GPtrArray) chunks = NULL; + + /* if page is protected */ + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + + /* get data for page */ + blob_block = g_hash_table_lookup (fd_blobs, fd); + if (blob_block == NULL) + break; + + /* ignore empty blocks */ + if (fu_common_bytes_is_empty (blob_block)) { + g_debug ("empty block, ignoring"); + fu_device_set_progress_full (device, blocks_done++, blocks_total); + continue; + } + + /* erase entire block */ + if (!fu_wac_device_erase_block (self, i, error)) + return FALSE; + + /* write block in chunks */ + chunks = fu_chunk_array_new_from_bytes (blob_block, + fd->start_addr, + 0, /* page_sz */ + self->write_block_sz); + for (guint j = 0; j < chunks->len; j++) { + FuChunk *chk = g_ptr_array_index (chunks, j); + g_autoptr(GBytes) blob_chunk = g_bytes_new (chk->data, chk->data_sz); + if (!fu_wac_device_write_block (self, chk->address, blob_chunk, error)) + return FALSE; + } + + /* calculate expected checksum and save to device RAM */ + csum_local[i] = fu_wac_calculate_checksum32le_bytes (blob_block); + g_debug ("block checksum %02u: 0x%08x", i, csum_local[i]); + if (!fu_wac_device_set_checksum_of_block (self, i, csum_local[i], error)) + return FALSE; + + /* update device progress */ + fu_device_set_progress_full (device, blocks_done++, blocks_total); + } + + /* calculate CRC inside device */ + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + if (!fu_wac_device_calculate_checksum_of_block (self, i, error)) + return FALSE; + } + + /* update device progress */ + fu_device_set_progress_full (device, blocks_done++, blocks_total); + + /* read all CRC of all pages and verify with local CRC */ + if (!fu_wac_device_ensure_checksums (self, error)) + return FALSE; + for (guint16 i = 0; i < self->flash_descriptors->len; i++) { + FuWacFlashDescriptor *fd = g_ptr_array_index (self->flash_descriptors, i); + GBytes *blob_block; + guint32 csum_rom; + + /* if page is protected */ + if (fu_wav_device_flash_descriptor_is_wp (fd)) + continue; + + /* no more written pages */ + blob_block = g_hash_table_lookup (fd_blobs, fd); + if (blob_block == NULL) + continue; + if (fu_common_bytes_is_empty (blob_block)) + continue; + + /* check checksum matches */ + csum_rom = g_array_index (self->checksums, guint32, i); + if (csum_rom != csum_local[i]) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed local checksum at block %u, " + "got 0x%08x expected 0x%08x", i, + (guint) csum_rom, (guint) csum_local[i]); + return FALSE; + } + g_debug ("matched checksum at block %u of 0x%08x", i, csum_rom); + } + + /* update device progress */ + fu_device_set_progress_full (device, blocks_done++, blocks_total); + + /* store host CRC into flash */ + if (!fu_wac_device_write_checksum_table (self, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, blocks_total, blocks_total); + return TRUE; +} + +static gboolean +fu_wac_device_add_modules_bluetooth (FuWacDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autofree gchar *name = NULL; + g_autofree gchar *version = NULL; + g_autoptr(FuWacModule) module = NULL; + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH, + [1 ... 14] = 0xff }; + + buf[0] = FU_WAC_REPORT_ID_GET_FIRMWARE_VERSION_BLUETOOTH; + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) { + g_prefix_error (error, "Failed to get GetFirmwareVersionBluetooth: "); + return FALSE; + } + + /* success */ + name = g_strdup_printf ("%s [Legacy Bluetooth Module]", + fu_device_get_name (FU_DEVICE (self))); + version = g_strdup_printf ("%x.%x", (guint) buf[2], (guint) buf[1]); + module = fu_wac_module_bluetooth_new (usb_device); + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); + fu_device_set_name (FU_DEVICE (module), name); + fu_device_set_version (FU_DEVICE (module), version, FWUPD_VERSION_FORMAT_PAIR); + return TRUE; +} + +static gboolean +fu_wac_device_add_modules_legacy (FuWacDevice *self, GError **error) +{ + g_autoptr(GError) error_bt = NULL; + + /* optional bluetooth */ + if (!fu_wac_device_add_modules_bluetooth (self, &error_bt)) + g_debug ("no bluetooth hardware: %s", error_bt->message); + + return TRUE; +} + +static gboolean +fu_wac_device_add_modules (FuWacDevice *self, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); + g_autofree gchar *version_bootloader = NULL; + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_FW_DESCRIPTOR, + [1 ... 31] = 0xff }; + + if (!fu_wac_device_get_feature_report (self, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_NONE, + error)) { + g_prefix_error (error, "Failed to get DeviceFirmwareDescriptor: "); + return FALSE; + } + + /* verify bootloader is compatible */ + if (buf[1] != 0x01) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "bootloader major version not compatible"); + return FALSE; + } + + /* verify the number of submodules is possible */ + if (buf[3] > (512 - 4) / 4) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "number of submodules is impossible"); + return FALSE; + } + + /* bootloader version */ + version_bootloader = g_strdup_printf ("%u.%u", buf[1], buf[2]); + fu_device_set_version_bootloader (FU_DEVICE (self), version_bootloader); + + /* get versions of each submodule */ + for (guint8 i = 0; i < buf[3]; i++) { + guint8 fw_type = buf[(i * 4) + 4] & ~0x80; + g_autofree gchar *name = NULL; + g_autofree gchar *version = NULL; + g_autoptr(FuWacModule) module = NULL; + + /* version number is decimal */ + version = g_strdup_printf ("%u.%u", buf[(i * 4) + 5], buf[(i * 4) + 6]); + + switch (fw_type) { + case FU_WAC_MODULE_FW_TYPE_TOUCH: + module = fu_wac_module_touch_new (usb_device); + name = g_strdup_printf ("%s [Touch Module]", + fu_device_get_name (FU_DEVICE (self))); + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); + fu_device_set_name (FU_DEVICE (module), name); + fu_device_set_version (FU_DEVICE (module), version, FWUPD_VERSION_FORMAT_PAIR); + break; + case FU_WAC_MODULE_FW_TYPE_BLUETOOTH: + module = fu_wac_module_bluetooth_new (usb_device); + name = g_strdup_printf ("%s [Bluetooth Module]", + fu_device_get_name (FU_DEVICE (self))); + fu_device_add_child (FU_DEVICE (self), FU_DEVICE (module)); + fu_device_set_name (FU_DEVICE (module), name); + fu_device_set_version (FU_DEVICE (module), version, FWUPD_VERSION_FORMAT_PAIR); + break; + case FU_WAC_MODULE_FW_TYPE_MAIN: + fu_device_set_version (FU_DEVICE (self), version, FWUPD_VERSION_FORMAT_PAIR); + break; + default: + g_warning ("unknown submodule type 0x%0x", fw_type); + break; + } + } + return TRUE; +} + +static gboolean +fu_wac_device_open (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* open device */ + if (!g_usb_device_claim_interface (usb_device, 0x00, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to claim HID interface: "); + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wac_device_setup (FuDevice *device, GError **error) +{ + FuWacDevice *self = FU_WAC_DEVICE (device); + + /* get current status */ + if (!fu_wac_device_ensure_status (self, error)) + return FALSE; + + /* get version of each sub-module */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION)) { + if (!fu_wac_device_add_modules_legacy (self, error)) + return FALSE; + } else { + if (!fu_wac_device_add_modules (self, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_wac_device_close (FuUsbDevice *device, GError **error) +{ + GUsbDevice *usb_device = fu_usb_device_get_dev (device); + + /* reattach wacom.ko */ + if (!g_usb_device_release_interface (usb_device, 0x00, /* HID */ + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + error)) { + g_prefix_error (error, "failed to re-attach interface: "); + return FALSE; + } + + /* The hidcore subsystem uses a generic power_supply that has a deferred + * work item that will lock the device. When removing the power_supply, + * we take the lock, then cancel the work item which needs to take the + * lock too. This needs to be fixed in the kernel, but for the moment + * this should let the kernel unstick itself. */ + g_usleep (20 * 1000); + + /* success */ + return TRUE; +} + +static void +fu_wac_device_init (FuWacDevice *self) +{ + self->flash_descriptors = g_ptr_array_new_with_free_func (g_free); + self->checksums = g_array_new (FALSE, FALSE, sizeof(guint32)); + self->configuration = 0xffff; + self->firmware_index = 0xffff; + fu_device_add_icon (FU_DEVICE (self), "input-tablet"); + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_install_duration (FU_DEVICE (self), 10); +} + +static void +fu_wac_device_finalize (GObject *object) +{ + FuWacDevice *self = FU_WAC_DEVICE (object); + + g_ptr_array_unref (self->flash_descriptors); + g_array_unref (self->checksums); + + G_OBJECT_CLASS (fu_wac_device_parent_class)->finalize (object); +} + +static void +fu_wac_device_class_init (FuWacDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + FuUsbDeviceClass *klass_usb_device = FU_USB_DEVICE_CLASS (klass); + object_class->finalize = fu_wac_device_finalize; + klass_device->write_firmware = fu_wac_device_write_firmware; + klass_device->to_string = fu_wac_device_to_string; + klass_device->setup = fu_wac_device_setup; + klass_usb_device->open = fu_wac_device_open; + klass_usb_device->close = fu_wac_device_close; +} + +FuWacDevice * +fu_wac_device_new (FuUsbDevice *device) +{ + FuWacDevice *self = g_object_new (FU_TYPE_WAC_DEVICE, NULL); + fu_device_incorporate (FU_DEVICE (self), FU_DEVICE (device)); + return self; +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-device.h fwupd-1.2.10/plugins/wacom-usb/fu-wac-device.h --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_DEVICE (fu_wac_device_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacDevice, fu_wac_device, FU, WAC_DEVICE, FuUsbDevice) + +typedef enum { + FU_WAC_DEVICE_FEATURE_FLAG_NONE = 0, + FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC = 1 << 0, + FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG = 1 << 1, + FU_WAC_DEVICE_FEATURE_FLAG_LAST +} FuWacDeviceFeatureFlags; + +FuWacDevice *fu_wac_device_new (FuUsbDevice *device); +gboolean fu_wac_device_update_reset (FuWacDevice *self, + GError **error); +gboolean fu_wac_device_get_feature_report (FuWacDevice *self, + guint8 *buf, + gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error); +gboolean fu_wac_device_set_feature_report (FuWacDevice *self, + guint8 *buf, + gsize bufsz, + FuWacDeviceFeatureFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-firmware.c fwupd-1.2.10/plugins/wacom-usb/fu-wac-firmware.c --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-firmware.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-firmware.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "dfu-element.h" +#include "dfu-format-srec.h" +#include "dfu-image.h" + +#include "fu-wac-firmware.h" + +#include "fwupd-error.h" + +typedef struct { + guint32 addr; + guint32 sz; + guint32 prog_start_addr; +} DfuFirmwareWacHeaderRecord; + +/** + * fu_wac_firmware_parse_data: + * @firmware: a #DfuFirmware + * @bytes: data to parse + * @flags: some #DfuFirmwareParseFlags + * @error: a #GError, or %NULL + * + * Unpacks into a firmware object from DfuSe data. + * + * Returns: %TRUE for success + **/ +gboolean +fu_wac_firmware_parse_data (DfuFirmware *firmware, + GBytes *bytes, + DfuFirmwareParseFlags flags, + GError **error) +{ + gsize len; + guint8 *data; + g_auto(GStrv) lines = NULL; + g_autoptr(GString) image_buffer = NULL; + g_autofree gchar *data_str = NULL; + guint8 images_cnt = 0; + g_autoptr(GPtrArray) header_infos = g_ptr_array_new_with_free_func (g_free); + + /* check the prefix (BE) */ + data = (guint8 *) g_bytes_get_data (bytes, &len); + if (memcmp (data, "WACOM", 5) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid .wac prefix"); + return FALSE; + } + + /* parse each line */ + data_str = g_strndup ((const gchar *) data, len); + lines = g_strsplit (data_str, "\n", -1); + for (guint i = 0; lines[i] != NULL; i++) { + g_autofree gchar *cmd = g_strndup (lines[i], 2); + + /* remove windows line endings */ + g_strdelimit (lines[i], "\r", '\0'); + + /* Wacom-specific metadata */ + if (g_strcmp0 (cmd, "WA") == 0) { + guint cmdlen = strlen (lines[i]); + + /* header info record */ + if (memcmp (lines[i] + 2, "COM", 3) == 0) { + guint8 header_image_cnt = 0; + if (cmdlen != 40) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid header, got %u bytes", + cmdlen); + return FALSE; + } + header_image_cnt = dfu_utils_buffer_parse_uint4 (lines[i] + 5); + for (guint j = 0; j < header_image_cnt; j++) { + DfuFirmwareWacHeaderRecord *hdr = g_new0 (DfuFirmwareWacHeaderRecord, 1); + hdr->addr = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 6); + hdr->sz = dfu_utils_buffer_parse_uint32 (lines[i] + (j * 16) + 14); + g_ptr_array_add (header_infos, hdr); + g_debug ("header_fw%u_addr: 0x%x", j, hdr->addr); + g_debug ("header_fw%u_sz: 0x%x", j, hdr->sz); + } + continue; + } + + /* firmware headline record */ + if (cmdlen == 13) { + DfuFirmwareWacHeaderRecord *hdr; + guint8 idx = dfu_utils_buffer_parse_uint4 (lines[i] + 2); + if (idx == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "headline %u invalid", + idx); + return FALSE; + } + if (idx > header_infos->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "headline %u exceeds header count %u", + idx, header_infos->len); + return FALSE; + } + hdr = g_ptr_array_index (header_infos, idx - 1); + hdr->prog_start_addr = dfu_utils_buffer_parse_uint32 (lines[i] + 3); + if (hdr->prog_start_addr != hdr->addr) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "programming address 0x%x != " + "base address 0x%0x for idx %u", + hdr->prog_start_addr, + hdr->addr, + idx); + return FALSE; + } + g_debug ("programing-start-address: 0x%x", hdr->prog_start_addr); + continue; + } + + g_debug ("unknown Wacom-specific metadata"); + continue; + } + + /* start */ + if (g_strcmp0 (cmd, "S0") == 0) { + if (image_buffer != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "duplicate S0 without S7"); + return FALSE; + } + image_buffer = g_string_new (NULL); + } + + /* these are things we want to include in the image */ + if (g_strcmp0 (cmd, "S0") == 0 || + g_strcmp0 (cmd, "S1") == 0 || + g_strcmp0 (cmd, "S2") == 0 || + g_strcmp0 (cmd, "S3") == 0 || + g_strcmp0 (cmd, "S5") == 0 || + g_strcmp0 (cmd, "S7") == 0 || + g_strcmp0 (cmd, "S8") == 0 || + g_strcmp0 (cmd, "S9") == 0) { + if (image_buffer == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s without S0", cmd); + return FALSE; + } + g_string_append_printf (image_buffer, "%s\n", lines[i]); + } + + /* end */ + if (g_strcmp0 (cmd, "S7") == 0) { + g_autoptr(GBytes) blob = NULL; + g_autoptr(DfuImage) image = dfu_image_new (); + DfuFirmwareWacHeaderRecord *hdr; + + /* get the correct relocated start address */ + if (images_cnt >= header_infos->len) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s without header", cmd); + return FALSE; + } + hdr = g_ptr_array_index (header_infos, images_cnt); + + if (image_buffer == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "%s with missing image buffer", cmd); + return FALSE; + } + + /* parse SREC file and add as image */ + blob = g_bytes_new (image_buffer->str, image_buffer->len); + if (!dfu_image_from_srec (image, blob, hdr->addr, flags, error)) + return FALSE; + + /* the alt-setting is used for the firmware index */ + dfu_image_set_alt_setting (image, images_cnt); + dfu_firmware_add_image (firmware, image); + images_cnt++; + + /* clear the image buffer */ + g_string_free (image_buffer, TRUE); + image_buffer = NULL; + } + } + + /* verify data is complete */ + if (image_buffer != NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "truncated data: no S7"); + return FALSE; + } + + /* ensure this matched the header */ + if (header_infos->len != images_cnt) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "not enough images %u for header count %u", + images_cnt, + header_infos->len); + return FALSE; + } + + /* success */ + dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_SREC); + return TRUE; +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-firmware.h fwupd-1.2.10/plugins/wacom-usb/fu-wac-firmware.h --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-firmware.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-firmware.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "dfu-firmware.h" + +G_BEGIN_DECLS + +gboolean fu_wac_firmware_parse_data (DfuFirmware *firmware, + GBytes *bytes, + DfuFirmwareParseFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-bluetooth.c fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-bluetooth.c --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-bluetooth.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-bluetooth.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wac-common.h" +#include "fu-wac-device.h" +#include "fu-wac-module-bluetooth.h" + +struct _FuWacModuleBluetooth +{ + FuWacModule parent_instance; +}; + +G_DEFINE_TYPE (FuWacModuleBluetooth, fu_wac_module_bluetooth, FU_TYPE_WAC_MODULE) + +#define FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ 256 +#define FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_START 0x3000 +#define FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_STOP 0x8000 + +typedef struct { + guint8 preamble[7]; + guint8 addr[3]; + guint8 crc; + guint8 cdata[FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ]; +} FuWacModuleBluetoothBlockData; + +static void +fu_wac_module_bluetooth_calculate_crc_byte (guint8 *crc, guint8 data) +{ + guint8 c[8]; + guint8 m[8]; + guint8 r[8]; + + /* find out what bits are set */ + for (guint i = 0; i < 8; i++) { + c[i] = (*crc & (1 << i)) != 0; + m[i] = (data & (1 << i)) != 0; + } + + /* do CRC on byte */ + r[7] = (c[7] ^ m[4] ^ c[3] ^ m[3] ^ c[4] ^ m[6] ^ c[1] ^ m[0]); + r[6] = (c[6] ^ m[5] ^ c[2] ^ m[4] ^ c[3] ^ m[7] ^ c[0] ^ m[1]); + r[5] = (c[5] ^ m[6] ^ c[1] ^ m[5] ^ c[2] ^ m[2]); + r[4] = (c[4] ^ m[7] ^ c[0] ^ m[6] ^ c[1] ^ m[3]); + r[3] = (m[7] ^ m[0] ^ c[7] ^ c[0] ^ m[3] ^ c[4] ^ m[6] ^ c[1]); + r[2] = (m[1] ^ c[6] ^ m[0] ^ c[7] ^ m[3] ^ c[4] ^ m[7] ^ c[0] ^ m[6] ^ c[1]); + r[1] = (m[2] ^ c[5] ^ m[1] ^ c[6] ^ m[4] ^ c[3] ^ m[7] ^ c[0]); + r[0] = (m[3] ^ c[4] ^ m[2] ^ c[5] ^ m[5] ^ c[2]); + + /* copy back into CRC */ + *crc = 0; + for (guint i = 0; i < 8; i++) { + if (r[i] == 0) + continue; + *crc |= (1 << i); + } +} + +static guint8 +fu_wac_module_bluetooth_calculate_crc (const guint8 *data, gsize sz) +{ + guint8 crc = 0; + for (gsize i = 0; i < sz; i++) + fu_wac_module_bluetooth_calculate_crc_byte (&crc, data[i]); + return crc; +} + +static GPtrArray * +fu_wac_module_bluetooth_parse_blocks (const guint8 *data, gsize sz, gboolean skip_user_data) +{ + const guint8 preamble[] = {0x02, 0x00, 0x0f, 0x06, 0x01, 0x08, 0x01}; + GPtrArray *blocks = g_ptr_array_new_with_free_func (g_free); + for (guint addr = 0x0; addr < sz; addr += FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ) { + FuWacModuleBluetoothBlockData *bd; + gsize cdata_sz = FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ; + + /* user data area */ + if (skip_user_data && + addr >= FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_START && + addr < FU_WAC_MODULE_BLUETOOTH_ADDR_USERDATA_STOP) + continue; + + bd = g_new0 (FuWacModuleBluetoothBlockData, 1); + memcpy (bd->preamble, preamble, sizeof (preamble)); + bd->addr[0] = (addr >> 16) & 0xff; + bd->addr[1] = (addr >> 8) & 0xff; + bd->addr[2] = addr & 0xff; + memset (bd->cdata, 0xff, FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ); + + /* if file is not in multiples of payload size */ + if (addr + FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ >= sz) + cdata_sz = sz - addr; + memcpy (bd->cdata, data + addr, cdata_sz); + bd->crc = fu_wac_module_bluetooth_calculate_crc (bd->cdata, + FU_WAC_MODULE_BLUETOOTH_PAYLOAD_SZ); + g_ptr_array_add (blocks, bd); + } + return blocks; +} + +static gboolean +fu_wac_module_bluetooth_write_firmware (FuDevice *device, + GBytes *blob, + FwupdInstallFlags flags, + GError **error) +{ + FuWacModule *self = FU_WAC_MODULE (device); + const guint8 *data; + gsize len = 0; + gsize blocks_total = 0; + const guint8 buf_start[] = { 0x00 }; + g_autoptr(GPtrArray) blocks = NULL; + g_autoptr(GBytes) blob_start = g_bytes_new_static (buf_start, 1); + + /* build each data packet */ + data = g_bytes_get_data (blob, &len); + blocks = fu_wac_module_bluetooth_parse_blocks (data, len, TRUE); + blocks_total = blocks->len + 2; + + /* start, which will erase the module */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_START, blob_start, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, 1, blocks_total); + + /* data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < blocks->len; i++) { + FuWacModuleBluetoothBlockData *bd = g_ptr_array_index (blocks, i); + guint8 buf[256+11]; + g_autoptr(GBytes) blob_chunk = NULL; + + /* build data packet */ + memset (buf, 0xff, sizeof(buf)); + memcpy(&buf[0], bd->preamble, 7); + memcpy(&buf[7], bd->addr, 3); + buf[10] = bd->crc; + memcpy (&buf[11], bd->cdata, sizeof(bd->cdata)); + blob_chunk = g_bytes_new (buf, sizeof(buf)); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, + blob_chunk, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, i + 1, blocks_total); + } + + /* end */ + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_END, NULL, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, blocks_total, blocks_total); + return TRUE; +} + +static void +fu_wac_module_bluetooth_init (FuWacModuleBluetooth *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_install_duration (FU_DEVICE (self), 30); +} + +static void +fu_wac_module_bluetooth_class_init (FuWacModuleBluetoothClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_wac_module_bluetooth_write_firmware; +} + +FuWacModule * +fu_wac_module_bluetooth_new (GUsbDevice *usb_device) +{ + FuWacModule *module = NULL; + module = g_object_new (FU_TYPE_WAC_MODULE_BLUETOOTH, + "usb-device", usb_device, + "fw-type", FU_WAC_MODULE_FW_TYPE_BLUETOOTH, + NULL); + return module; +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-bluetooth.h fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-bluetooth.h --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-bluetooth.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-bluetooth.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wac-module.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_MODULE_BLUETOOTH (fu_wac_module_bluetooth_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacModuleBluetooth, fu_wac_module_bluetooth, FU, WAC_MODULE_BLUETOOTH, FuWacModule) + +FuWacModule *fu_wac_module_bluetooth_new (GUsbDevice *usb_device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-module.c fwupd-1.2.10/plugins/wacom-usb/fu-wac-module.c --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-module.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-module.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wac-module.h" +#include "fu-wac-common.h" +#include "fu-wac-device.h" + +#include "dfu-common.h" +#include "dfu-firmware.h" + +#define FU_WAC_MODULE_STATUS_OK 0 +#define FU_WAC_MODULE_STATUS_BUSY 1 +#define FU_WAC_MODULE_STATUS_ERR_CRC 2 +#define FU_WAC_MODULE_STATUS_ERR_CMD 3 +#define FU_WAC_MODULE_STATUS_ERR_HW_ACCESS_FAIL 4 +#define FU_WAC_MODULE_STATUS_ERR_FLASH_NO_SUPPORT 5 +#define FU_WAC_MODULE_STATUS_ERR_MODE_WRONG 6 +#define FU_WAC_MODULE_STATUS_ERR_MPU_NO_SUPPORT 7 +#define FU_WAC_MODULE_STATUS_ERR_VERSION_NO_SUPPORT 8 +#define FU_WAC_MODULE_STATUS_ERR_ERASE 9 +#define FU_WAC_MODULE_STATUS_ERR_WRITE 10 +#define FU_WAC_MODULE_STATUS_ERR_EXIT 11 +#define FU_WAC_MODULE_STATUS_ERR 12 +#define FU_WAC_MODULE_STATUS_ERR_INVALID_OP 13 +#define FU_WAC_MODULE_STATUS_ERR_WRONG_IMAGE 14 + +typedef struct { + GUsbDevice *usb_device; + guint8 fw_type; + guint8 command; + guint8 status; +} FuWacModulePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuWacModule, fu_wac_module, FU_TYPE_DEVICE) +#define GET_PRIVATE(o) (fu_wac_module_get_instance_private (o)) + +enum { + PROP_0, + PROP_FW_TYPE, + PROP_USB_DEVICE, + PROP_LAST +}; + +static const gchar * +fu_wac_module_fw_type_to_string (guint8 fw_type) +{ + if (fw_type == FU_WAC_MODULE_FW_TYPE_TOUCH) + return "touch"; + if (fw_type == FU_WAC_MODULE_FW_TYPE_BLUETOOTH) + return "bluetooth"; + if (fw_type == FU_WAC_MODULE_FW_TYPE_EMR_CORRECTION) + return "emr-correction"; + if (fw_type == FU_WAC_MODULE_FW_TYPE_BLUETOOTH_HID) + return "bluetooth-hid"; + return NULL; +} + +static const gchar * +fu_wac_module_command_to_string (guint8 command) +{ + if (command == FU_WAC_MODULE_COMMAND_START) + return "start"; + if (command == FU_WAC_MODULE_COMMAND_DATA) + return "data"; + if (command == FU_WAC_MODULE_COMMAND_END) + return "end"; + return NULL; +} + +static const gchar * +fu_wac_module_status_to_string (guint8 status) +{ + if (status == FU_WAC_MODULE_STATUS_OK) + return "ok"; + if (status == FU_WAC_MODULE_STATUS_BUSY) + return "busy"; + if (status == FU_WAC_MODULE_STATUS_ERR_CRC) + return "err-crc"; + if (status == FU_WAC_MODULE_STATUS_ERR_CMD) + return "err-cmd"; + if (status == FU_WAC_MODULE_STATUS_ERR_HW_ACCESS_FAIL) + return "err-hw-access-fail"; + if (status == FU_WAC_MODULE_STATUS_ERR_FLASH_NO_SUPPORT) + return "err-flash-no-support"; + if (status == FU_WAC_MODULE_STATUS_ERR_MODE_WRONG) + return "err-mode-wrong"; + if (status == FU_WAC_MODULE_STATUS_ERR_MPU_NO_SUPPORT) + return "err-mpu-no-support"; + if (status == FU_WAC_MODULE_STATUS_ERR_VERSION_NO_SUPPORT) + return "erro-version-no-support"; + if (status == FU_WAC_MODULE_STATUS_ERR_ERASE) + return "err-erase"; + if (status == FU_WAC_MODULE_STATUS_ERR_WRITE) + return "err-write"; + if (status == FU_WAC_MODULE_STATUS_ERR_EXIT) + return "err-exit"; + if (status == FU_WAC_MODULE_STATUS_ERR) + return "err-err"; + if (status == FU_WAC_MODULE_STATUS_ERR_INVALID_OP) + return "err-invalid-op"; + if (status == FU_WAC_MODULE_STATUS_ERR_WRONG_IMAGE) + return "err-wrong-image"; + return NULL; +} + +static void +fu_wac_module_to_string (FuDevice *device, GString *str) +{ + FuWacModule *self = FU_WAC_MODULE (device); + FuWacModulePrivate *priv = GET_PRIVATE (self); + g_string_append (str, " FuWacSubModule:\n"); + g_string_append_printf (str, " fw-type:\t\t%s\n", + fu_wac_module_fw_type_to_string (priv->fw_type)); + g_string_append_printf (str, " status:\t\t%s\n", + fu_wac_module_status_to_string (priv->status)); + g_string_append_printf (str, " command:\t\t%s\n", + fu_wac_module_command_to_string (priv->command)); +} + +static gboolean +fu_wac_module_refresh (FuWacModule *self, GError **error) +{ + FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + FuWacModulePrivate *priv = GET_PRIVATE (self); + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, + [1 ... FU_WAC_PACKET_LEN - 1] = 0xff }; + + /* get from hardware */ + if (!fu_wac_device_get_feature_report (parent_device, buf, sizeof(buf), + FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC | + FU_WAC_DEVICE_FEATURE_FLAG_NO_DEBUG, + error)) { + g_prefix_error (error, "failed to refresh status: "); + return FALSE; + } + + /* check fw type */ + if (priv->fw_type != buf[1]) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Submodule GetFeature fw_Type invalid " + "got 0x%02x expected 0x%02x", + (guint) buf[1], (guint) priv->fw_type); + return FALSE; + } + + /* current phase and status */ + if (priv->command != buf[2] || priv->status != buf[3]) { + priv->command = buf[2]; + priv->status = buf[3]; + g_debug ("command: %s, status: %s", + fu_wac_module_command_to_string (priv->command), + fu_wac_module_status_to_string (priv->status)); + } + + /* success */ + return TRUE; +} + +gboolean +fu_wac_module_set_feature (FuWacModule *self, + guint8 command, + GBytes *blob, /* optional */ + GError **error) +{ + FuWacDevice *parent_device = FU_WAC_DEVICE (fu_device_get_parent (FU_DEVICE (self))); + FuWacModulePrivate *priv = GET_PRIVATE (self); + const guint8 *data; + gsize len = 0; + guint busy_poll_loops = 100; /* 1s */ + guint8 buf[] = { [0] = FU_WAC_REPORT_ID_MODULE, + [1] = priv->fw_type, + [2] = command, + [3 ... FU_WAC_PACKET_LEN - 1] = 0xff }; + + /* verify the size of the blob */ + if (blob != NULL) { + data = g_bytes_get_data (blob, &len); + if (len > 509) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Submodule SetFeature blob larger than " + "buffer %" G_GSIZE_FORMAT, len); + return FALSE; + } + } + + /* build packet */ + if (len > 0) + memcpy (&buf[3], data, len); + + /* tell the daemon the current status */ + switch (command) { + case FU_WAC_MODULE_COMMAND_START: + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); + break; + case FU_WAC_MODULE_COMMAND_DATA: + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); + break; + case FU_WAC_MODULE_COMMAND_END: + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); + break; + default: + break; + } + + /* send to hardware */ + if (!fu_wac_device_set_feature_report (parent_device, buf, len + 3, + FU_WAC_DEVICE_FEATURE_FLAG_ALLOW_TRUNC, + error)) { + g_prefix_error (error, "failed to set module feature: "); + return FALSE; + } + + /* special case StartProgram, as it can take much longer as it is + * erasing the blocks (15s) */ + if (command == FU_WAC_MODULE_COMMAND_START) + busy_poll_loops *= 15; + + /* wait for hardware */ + for (guint i = 0; i < busy_poll_loops; i++) { + if (!fu_wac_module_refresh (self, error)) + return FALSE; + if (priv->status == FU_WAC_MODULE_STATUS_BUSY) { + g_usleep (10000); /* 10ms */ + continue; + } + if (priv->status == FU_WAC_MODULE_STATUS_OK) + break; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to SetFeature: %s", + fu_wac_module_status_to_string (priv->status)); + return FALSE; + } + + /* too many retries */ + if (priv->status != FU_WAC_MODULE_STATUS_OK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Timed out after %u loops with status %s", + busy_poll_loops, + fu_wac_module_status_to_string (priv->status)); + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_wac_module_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_FW_TYPE: + g_value_set_uint (value, priv->fw_type); + break; + case PROP_USB_DEVICE: + g_value_set_object (value, priv->usb_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_wac_module_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_FW_TYPE: + priv->fw_type = g_value_get_uint (value); + break; + case PROP_USB_DEVICE: + g_set_object (&priv->usb_device, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_wac_module_init (FuWacModule *self) +{ +} + +static void +fu_wac_module_constructed (GObject *object) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + g_autofree gchar *devid = NULL; + g_autofree gchar *vendor_id = NULL; + + /* set vendor ID */ + vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); + fu_device_set_vendor_id (FU_DEVICE (self), vendor_id); + + /* set USB physical and logical IDs */ + fu_device_set_physical_id (FU_DEVICE (self), + g_usb_device_get_platform_id (priv->usb_device)); + fu_device_set_logical_id (FU_DEVICE (self), + fu_wac_module_fw_type_to_string (priv->fw_type)); + + /* append the firmware kind to the generated GUID */ + devid = g_strdup_printf ("USB\\VID_%04X&PID_%04X-%s", + g_usb_device_get_vid (priv->usb_device), + g_usb_device_get_pid (priv->usb_device), + fu_wac_module_fw_type_to_string (priv->fw_type)); + fu_device_add_instance_id (FU_DEVICE (self), devid); + + G_OBJECT_CLASS (fu_wac_module_parent_class)->constructed (object); +} + +static void +fu_wac_module_finalize (GObject *object) +{ + FuWacModule *self = FU_WAC_MODULE (object); + FuWacModulePrivate *priv = GET_PRIVATE (self); + if (priv->usb_device != NULL) + g_object_unref (priv->usb_device); + G_OBJECT_CLASS (fu_wac_module_parent_class)->finalize (object); +} + +static void +fu_wac_module_class_init (FuWacModuleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + + /* properties */ + object_class->get_property = fu_wac_module_get_property; + object_class->set_property = fu_wac_module_set_property; + pspec = g_param_spec_object ("usb-device", NULL, NULL, + G_USB_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_USB_DEVICE, pspec); + pspec = g_param_spec_uint ("fw-type", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_FW_TYPE, pspec); + + object_class->constructed = fu_wac_module_constructed; + object_class->finalize = fu_wac_module_finalize; + klass_device->to_string = fu_wac_module_to_string; +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-module.h fwupd-1.2.10/plugins/wacom-usb/fu-wac-module.h --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-module.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-module.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_MODULE (fu_wac_module_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuWacModule, fu_wac_module, FU, WAC_MODULE, FuDevice) + +struct _FuWacModuleClass +{ + FuDeviceClass parent_class; +}; + +#define FU_WAC_MODULE_FW_TYPE_TOUCH 0x00 +#define FU_WAC_MODULE_FW_TYPE_BLUETOOTH 0x01 +#define FU_WAC_MODULE_FW_TYPE_EMR_CORRECTION 0x02 +#define FU_WAC_MODULE_FW_TYPE_BLUETOOTH_HID 0x03 +#define FU_WAC_MODULE_FW_TYPE_MAIN 0x3f + +#define FU_WAC_MODULE_COMMAND_START 0x01 +#define FU_WAC_MODULE_COMMAND_DATA 0x02 +#define FU_WAC_MODULE_COMMAND_END 0x03 + +gboolean fu_wac_module_set_feature (FuWacModule *self, + guint8 command, + GBytes *blob, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-touch.c fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-touch.c --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-touch.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-touch.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-wac-device.h" +#include "fu-wac-module-touch.h" + +#include "fu-chunk.h" +#include "dfu-firmware.h" + +struct _FuWacModuleTouch +{ + FuWacModule parent_instance; +}; + +G_DEFINE_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU_TYPE_WAC_MODULE) + +static gboolean +fu_wac_module_touch_write_firmware (FuDevice *device, + GBytes *blob, + FwupdInstallFlags flags, + GError **error) +{ + DfuElement *element; + DfuImage *image; + FuWacModule *self = FU_WAC_MODULE (device); + gsize blocks_total = 0; + g_autoptr(GPtrArray) chunks = NULL; + g_autoptr(DfuFirmware) firmware = dfu_firmware_new (); + + /* load .hex file */ + if (!dfu_firmware_parse_data (firmware, blob, DFU_FIRMWARE_PARSE_FLAG_NONE, error)) + return FALSE; + + /* check type */ + if (dfu_firmware_get_format (firmware) != DFU_FIRMWARE_FORMAT_INTEL_HEX) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "expected firmware format is 'ihex', got '%s'", + dfu_firmware_format_to_string (dfu_firmware_get_format (firmware))); + return FALSE; + } + + /* use the correct image from the firmware */ + image = dfu_firmware_get_image (firmware, 0); + if (image == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware image"); + return FALSE; + } + element = dfu_image_get_element_default (image); + if (element == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware element"); + return FALSE; + } + g_debug ("using element at addr 0x%0x", + (guint) dfu_element_get_address (element)); + blob = dfu_element_get_contents (element); + + /* build each data packet */ + chunks = fu_chunk_array_new_from_bytes (blob, + dfu_element_get_address (element), + 0x0, /* page_sz */ + 128); /* packet_sz */ + blocks_total = chunks->len + 2; + + /* start, which will erase the module */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_ERASE); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_START, NULL, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, 1, blocks_total); + + /* data */ + fu_device_set_status (device, FWUPD_STATUS_DEVICE_WRITE); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *chk = g_ptr_array_index (chunks, i); + guint8 buf[128+7] = { 0xff }; + g_autoptr(GBytes) blob_chunk = NULL; + + /* build G11T data packet */ + memset (buf, 0xff, sizeof(buf)); + buf[0] = 0x01; /* writing */ + buf[1] = chk->idx + 1; + fu_common_write_uint32 (&buf[2], chk->address, G_LITTLE_ENDIAN); + buf[6] = 0x10; /* no idea! */ + memcpy (&buf[7], chk->data, chk->data_sz); + blob_chunk = g_bytes_new (buf, sizeof(buf)); + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_DATA, + blob_chunk, error)) { + g_prefix_error (error, "failed to write block %u: ", chk->idx); + return FALSE; + } + + /* update progress */ + fu_device_set_progress_full (device, i + 1, blocks_total); + } + + /* end */ + if (!fu_wac_module_set_feature (self, FU_WAC_MODULE_COMMAND_END, NULL, error)) + return FALSE; + + /* update progress */ + fu_device_set_progress_full (device, blocks_total, blocks_total); + return TRUE; +} + +static void +fu_wac_module_touch_init (FuWacModuleTouch *self) +{ + fu_device_add_flag (FU_DEVICE (self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_install_duration (FU_DEVICE (self), 30); +} + +static void +fu_wac_module_touch_class_init (FuWacModuleTouchClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS (klass); + klass_device->write_firmware = fu_wac_module_touch_write_firmware; +} + +FuWacModule * +fu_wac_module_touch_new (GUsbDevice *usb_device) +{ + FuWacModule *module = NULL; + module = g_object_new (FU_TYPE_WAC_MODULE_TOUCH, + "usb-device", usb_device, + "fw-type", FU_WAC_MODULE_FW_TYPE_TOUCH, + NULL); + return module; +} diff -Nru fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-touch.h fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-touch.h --- fwupd-1.0.6/plugins/wacom-usb/fu-wac-module-touch.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/fu-wac-module-touch.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-wac-module.h" + +G_BEGIN_DECLS + +#define FU_TYPE_WAC_MODULE_TOUCH (fu_wac_module_touch_get_type ()) +G_DECLARE_FINAL_TYPE (FuWacModuleTouch, fu_wac_module_touch, FU, WAC_MODULE_TOUCH, FuWacModule) + +FuWacModule *fu_wac_module_touch_new (GUsbDevice *usb_device); + +G_END_DECLS diff -Nru fwupd-1.0.6/plugins/wacom-usb/meson.build fwupd-1.2.10/plugins/wacom-usb/meson.build --- fwupd-1.0.6/plugins/wacom-usb/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,68 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginWacomUsb"'] + +install_data(['wacom-usb.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_wacom_usb', + fu_hash, + sources : [ + 'fu-wac-common.c', + 'fu-wac-device.c', + 'fu-wac-firmware.c', + 'fu-wac-module.c', + 'fu-wac-module-bluetooth.c', + 'fu-wac-module-touch.c', + 'fu-plugin-wacom-usb.c', + ], + include_directories : [ + include_directories('../..'), + include_directories('../dfu'), + include_directories('../../src'), + include_directories('../../libfwupd'), + ], + install : true, + install_dir: plugin_dir, + c_args : cargs, + dependencies : [ + plugin_deps, + ], + link_with : [ + libfwupdprivate, + dfu, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'wacom-usb-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-wac-common.c', + 'fu-wac-firmware.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../dfu'), + include_directories('../..'), + include_directories('../../libfwupd'), + include_directories('../../src'), + ], + dependencies : [ + libxmlb, + gio, + gusb, + gudev, + libm, + ], + link_with : [ + dfu, + libfwupdprivate, + ], + c_args : cargs + ) + test('wacom-usb-self-test', e) +endif diff -Nru fwupd-1.0.6/plugins/wacom-usb/README.md fwupd-1.2.10/plugins/wacom-usb/README.md --- fwupd-1.0.6/plugins/wacom-usb/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,41 @@ +Wacom USB Support +================= + +Introduction +------------ + +Wacom provides interactive pen displays, pen tablets, and styluses to equip and +inspire everyone make the world a more creative place. + +From 2016 Wacom has been using a HID-based proprietary flashing algorithm which +has been documented by support team at Wacom and provided under NDA under the +understanding it would be used to build a plugin under a LGPLv2+ licence. + +Wacom devices are actually composite devices, with the main ARM CPU being +programmed using a more complicated erase, write, verify algorithm based +on a historical update protocol. The "sub-module" devices use a newer protocol, +again based on HID, but are handled differently depending on their type. + +Firmware Format +--------------- + +The daemon will decompress the cabinet archive and extract a firmware blob in +the following formats: + + * Touch module: Intel HEX file format + * Bluetooth module: Unknown airoflash file format + * EMR module: Plain SREC file format + * Main module: SREC file format, with a custom `WACOM` vendor header + +This plugin supports the following protocol ID: + + * com.wacom.usb + +GUID Generation +--------------- + +These devices use the standard USB DeviceInstanceId values, e.g. + + * `USB\VID_056A&PID_0378&REV_0001` + * `USB\VID_056A&PID_0378` + * `USB\VID_056A` diff -Nru fwupd-1.0.6/plugins/wacom-usb/wacom-usb.quirk fwupd-1.2.10/plugins/wacom-usb/wacom-usb.quirk --- fwupd-1.0.6/plugins/wacom-usb/wacom-usb.quirk 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/plugins/wacom-usb/wacom-usb.quirk 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,34 @@ + +# Intuos Pro medium (2nd-gen USB) [PTH-660] +[DeviceInstanceId=USB\VID_056A&PID_0357] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos Pro large (2nd-gen USB) [PTH-860] +[DeviceInstanceId=USB\VID_056A&PID_0358] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos S 3rd-gen (USB) [CTL-4100] +[DeviceInstanceId=USB\VID_056A&PID_0374] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos M 3rd-gen (USB) [NA] +[DeviceInstanceId=USB\VID_056A&PID_0375] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos BT S 3rd-gen (USB) [CTL-4100WL] +[DeviceInstanceId=USB\VID_056A&PID_0376] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos BT M 3rd-gen (USB) [CTL-6100WL] +[DeviceInstanceId=USB\VID_056A&PID_0378] +Plugin = wacom_usb +Flags = use-runtime-version + +# Intuos Pro Small (2nd-gen USB) [PTH-460] +[DeviceInstanceId=USB\VID_056A&PID_0392] +Plugin = wacom_usb diff -Nru fwupd-1.0.6/po/af.po fwupd-1.2.10/po/af.po --- fwupd-1.0.6/po/af.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/af.po 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,418 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# F Wolff , 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Afrikaans (http://www.transifex.com/freedesktop/fwupd/language/af/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: af\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuut oor" +msgstr[1] "%.0f minute oor" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dae" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u uur" +msgstr[1] "%u ure" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuut" +msgstr[1] "%u minute" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekonde" +msgstr[1] "%u sekondes" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Bygevoeg" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Ouderdom" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "’n Bywerking vereis dat die stelsel herbegin om te voltooi." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Antwoord ja op alle vrae" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribute" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Kanselleer" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Gekanselleer" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Verander" + +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolesom" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Vlokkie-ID" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Kies 'n toestel:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Kies 'n vrystelling:" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Opdrag nie gevind nie" + +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Pak tans uit…" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Beskrywing" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Toestel bygevoeg:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Toestel verander:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Toestel verwyder:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Toestelle wat suksesvol bygewerk is:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Toestelle wat nie korrek bygewerk is nie:" + +#. success +msgid "Done!" +msgstr "Klaar!" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Gradeer tans %s af vanaf %s na %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Gradeer tans %s af…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Laai tans af…" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Geaktiveer" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Vee tans uit…" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Kon nie aflaai nie a.g.v. bedienerlimiet" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Kry tans lêer" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Kry tans metadata" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Kry tans handtekening" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Lêernaam" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Lêernaamhandtekening" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Gevind" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Ledig…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installeer tans op %s…" + +msgid "Keyring" +msgstr "Sleutelring" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Minder as een minuut oor" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Laai tans…" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadata-URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadata-URI-handtekening" + +msgid "Mode" +msgstr "Modus" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Naam" + +msgid "OK" +msgstr "Goed" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Wagwoord" + +msgid "Permission denied" +msgstr "Toestemming gewyer" + +msgid "Print the version number" +msgstr "Druk die weergawenommer" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioriteit" + +msgid "Proceed with upload?" +msgstr "Gaan voort met oplaai?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lees tans…" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Streek" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Herinstalleer tans %s met %s… " + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Verwyder" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Internetverbinding is nodig" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Herbegin nou?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Herbegin tans toestel…" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Skeduleer die installasie vir die volgende herbegin indien moontlik" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Skeduleer tans…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Reeksnommer" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Wys toestelle wat nie bygewerk kan word nie" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Toestand" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Opsomming" + +msgid "Target" +msgstr "Teiken" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Oordraggrootte" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipe" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Onbekend" + +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Bywerking se kontrolesom" + +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Bywerking se beskrywing" + +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Bywerking se duur" + +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Bywerking se ligging" + +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Bywerking se naam" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Bywerking se opsomming" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Bywerking se weergawe" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Werk nou by?" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Werk tans %s by vanaf %s na %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Werk tans %s by…" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Oplaaiboodskap:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Laai verslag nou op?" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Gebruikernaam" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifieer tans…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Weergawe" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Wag tans…" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Skryf tans…" diff -Nru fwupd-1.0.6/po/ast.po fwupd-1.2.10/po/ast.po --- fwupd-1.0.6/po/ast.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/ast.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # enolp , 2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Asturian (http://www.transifex.com/freedesktop/fwupd/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,66 @@ "Language: ast\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Anueva'l firmware de preseos en Linux" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Esti proyeutu tien l'oxetivu d'anovar automáticamente'l firmware en Linux d'un mou seguru y fiable. Pues usar un xestor de software GUI como Gnome Software pa ver y aplicar los anovamientos, la ferramienta en llinia de comandos o la interfaz D-Bus direutamente." - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "" - -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "" - #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 msgid "Added" msgstr "Amestóse" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Desanicióse" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Encaboxóse" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Camudóse" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Encaboxóse" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Cifráu" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Alcontróse" #. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 msgid "ID" msgstr "ID" +msgid "Mode" +msgstr "Mou" + #. TRANSLATORS: interface name, e.g. "Flash" #. TRANSLATORS: device name, e.g. 'ColorHug2' #. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 msgid "Name" msgstr "Nome" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Cifráu" - -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Rexón" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Alcontróse" - #. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 msgid "Protocol" msgstr "Protocolu" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Estáu" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Rexón" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Desanicióse" #. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 msgid "Serial" msgstr "Serial" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Mou" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - #. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 msgid "State" msgstr "Estáu" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Estáu" + #. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 msgid "Transfer Size" msgstr "Tamañu de tresferencia" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" - -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "" - -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" - -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "" - -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" - -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "" - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" diff -Nru fwupd-1.0.6/po/ca.po fwupd-1.2.10/po/ca.po --- fwupd-1.0.6/po/ca.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/ca.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,17 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Antoni Bella Pérez , 2017-2018 +# Antoni Bella Pérez , 2017-2019 # Robert Antoni Buj Gelonch , 2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Catalan (http://www.transifex.com/freedesktop/fwupd/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,979 +16,1213 @@ "Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Actualitza el microprogramari del dispositiu a Linux" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Manca %.0f minut" +msgstr[1] "Manquen %.0f minuts" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Aquest projecte pretén fer que actualitzar automàticament el microprogramari a Linux, sigui segur i fiable. Com a IGU, podeu usar un gestor de programari com el Programari GNOME per a veure i aplicar les actualitzacions, directament l'eina de la línia d'ordres o la interfície de D-Bus." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Actualització ME del consumidor %s" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "El procés del «fwupd» és un dimoni senzill que permet que una sessió de programari actualitzi el microprogramari del dispositiu a la màquina local. Està dissenyat per a equips d'escriptori, però aquest projecte també és usable a telèfons, tauletes i servidors sense perifèrics." +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Actualització del controlador %s" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Instal·la microprogramari signat per al sistema" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Actualització ME corporativa de %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Es requereix autenticació per actualitzar el microprogramari en aquesta màquina" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Actualizació del dispositiu %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Instal·la microprogramari sense signar per al sistema" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Actualització del controlador incorporat %s" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Instal·la la versió antiga del microprogramari per al sistema" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Actualització ME de %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Es requereix autenticació per a desactualitzar el microprogramari en aquesta màquina" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Actualizació del sistema %s" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Instal·la microprogramari signat per al dispositiu" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Actualització de %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Es requereix autenticació per actualitzar el microprogramari en un dispositiu extraible" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s té actualitzacions de microprogramari:" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Instal·la microprogramari sense signar per al dispositiu" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dia" +msgstr[1] "%u dies" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Es requereix autenticació per a desactualitzar el microprogramari en un dispositiu extraible" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hora" +msgstr[1] "%u hores" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Desbloqueja el dispositiu per a permetre l'accés" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minut" +msgstr[1] "%u minuts" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Es requereix autenticació per a desbloquejar un dispositiu" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u segon" +msgstr[1] "%u segons" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Actualitza la informació de verificació dels dispositius emmagatzemats" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Activa els dispositius" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Es requereix autenticació per actualitzar les sumes de verificació emmagatzemades pels dispositius" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Activa els dispositius pendents" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Modifica un remot configurat" +msgid "Activate the new firmware on the device" +msgstr "Activa el microprogramari nou al dispositiu" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Es necessita l'autenticació per a modificar un remot configurat emprat per a les actualitzacions del microprogramari" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Activació de l'actualització del microprogramari" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Activa l’actualització del microprogramari per a" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "S'ha afegit" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Antiguitat" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Accepteu i habiliteu el remot?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Àlies per a %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "No s'ha trobat cap ordre" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Permet tornar a la versió anterior del microprogramari" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "S'ha afegit" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Permet tornar a instal·lar les versions de microprogramari existents" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "S'ha eliminat" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Una actualització requereix un reinici per a completar-se." -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "S'ha canviat" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Una actualització requereix que s'aturi el sistema per a finalitzar." -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "S'ha cancel·lat" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Respon sí a totes les preguntes" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Aplica un pedaç binari" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nom" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Aplica les actualizacions de microprogramari" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Xifra" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Microprogramari aprovat:" +msgstr[1] "Microprogramari aprovat:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Regió" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Connecta un dispositiu amb capacitat DFU en temps real" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "S'ha trobat" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Ajunta al mode microprogramari" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protocol" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Atributs" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Estat" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "S'està autenticant..." -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Permís denegat" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Es requereix autenticació per a desactualitzar el microprogramari en un dispositiu extraible" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Sèrie" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Es requereix autenticació per a desactualitzar el microprogramari en aquesta màquina" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Mode" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Es necessita l'autenticació per a modificar un remot configurat emprat per a les actualitzacions del microprogramari" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Temps d'execució" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Es requereix autenticació per a modificar la configuració del dimoni" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Es requereix autenticació per a establir la llista de microprogramari aprovat" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Estat" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Es requereix autenticació per a signar les dades emprant el certificat del client" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Mida a transferir" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Es requereix autenticació per a canviar a la nova versió del micropogramari" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Atributs" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Es requereix autenticació per a desbloquejar un dispositiu" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Peculiaritats" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Es requereix autenticació per actualitzar el microprogramari en un dispositiu extraible" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "Id. xip" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Es requereix autenticació per actualitzar el microprogramari en aquesta màquina" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Converteix el microprogramari al format DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Es requereix autenticació per actualitzar les sumes de verificació emmagatzemades pels dispositius" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Fusiona múltiples fitxers de microprogramari en un de sol" +msgid "Build firmware using a sandbox" +msgstr "Construeix el microprogramari usant un entorn de proves" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Estableix l'ID del proveïdor al fitxer del microprogramari" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Cancel·la" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Estableix l'ID del producte al fitxer del microprogramari" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "S'ha cancel·lat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Estableix l'adreça de l'element al fitxer del microprogramari" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "S'ha canviat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Estableix la mida del microprogramari per a l'objectiu" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Suma de comprovació" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Estableix la versió de llançament al fitxer del microprogramari" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Id. xip" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Estableix el número alternatiu al fitxer del microprogramari" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Trieu un dispositiu:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Estableix el nom alternatiu al fitxer del microprogramari" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Trieu un alliberament:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Connecta un dispositiu amb capacitat DFU en temps real" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Xifra" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Restableix un dispositiu DFU" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Neteja qualsevol actualització programyada per a ser actualitzada sense connexió" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Llegeix el microprogramari des del dispositiu a un fitxer" +msgid "Clears the results from the last update" +msgstr "Esborra els resultats de l'última actualització" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "No s'ha trobat cap ordre" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Llegeix el microprogramari des d'una partició a un fitxer" +msgid "Convert firmware to DFU format" +msgstr "Converteix el microprogramari al format DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Escriu el microprogramari des d'un fitxer a dins del dispositiu" +msgid "Create a binary patch using two files" +msgstr "Crea un pedaç binari emprant dos fitxers" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Escriu el microprogramari des d'un fitxer a dins d'una partició" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Utilitat DFU" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opcions per a la depuració" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "S'està descomprimint..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Llista els dispositius amb capacitat DFU actualment connectats" +msgid "Decrypt firmware data" +msgstr "Desencripta les dades del microprogramari" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Descripció" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "Desconecta el dispositiu amb capacitat DFU actualment connectat" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Bolca els detalls sobre un fitxer de microprogramari" +msgid "Detach to bootloader mode" +msgstr "Separa del mode carregador d'arrencada" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Vigila els dispositius DFU que han estat connectats en calent" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "ID del dispositiu" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Encripta les dades del microprogramari" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "S'ha afegit el dispositiu:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Desencripta les dades del microprogramari" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "S'ha canviat el dispositiu:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "S'ha eliminat el dispositiu:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Els dispositius que s'han actualitzat correctament:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Els dispositius que no s'han actualitzat correctament:" + +msgid "Disabled fwupdate debugging" +msgstr "La depuració del «fwupdate» està inhabilitada" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Estableix les metadades en un fitxer de microprogramari" +msgid "Disables a given remote" +msgstr "Inhabilita un remot indicat" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Mostra la versió" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "No comprovar si hi ha metadades antigues" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "No realitzis el reinici després de l'actualització" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "No comprovar si hi ha un historial sense informar" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "No escriure a la base de dades de l'historial" + +#. success +msgid "Done!" +msgstr "Fet!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Substitueix les dades en un fitxer de microprogramari existent" +msgid "Downgrades the firmware on a device" +msgstr "Desactualitza el microprogramari en un dispositiu" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "S'està desactualitzant %s des de %s a %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "S'està desactualitzant %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "S'està descarregant..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Crea un pedaç binari emprant dos fitxers" +msgid "Dump SMBIOS data from a file" +msgstr "Bolca les dades al SMBIOS des d'un fitxer" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Aplica un pedaç binari" +msgid "Dump details about a firmware file" +msgstr "Bolca els detalls sobre un fitxer de microprogramari" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "Bolca la informació sobre un pedaç binari a la pantalla" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "No s'han pogut carregar les peculiaritats" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "L'ESP especificat no era vàlid" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Utilitat DFU" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Habilita el suport per a l'actualització del microprogramari sobre sistemes compatibles" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Ha fallat en analitzar els arguments" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Habilito aquest remot?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Enumera tots els dispositius de «Synaptics MST»" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Habilitat" + +msgid "Enabled fwupdate debugging" +msgstr "La depuració del «fwupdate» està habilitada" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Instal·la un fitxer de microprogramari en un dispositiu MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Utilitat «Synaptics Multistream Transport»" +msgid "Enables a given remote" +msgstr "Habilita un remot indicat" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "S'està instal·lant l'actualització de microprogramari..." +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Si habiliteu aquesta funcionalitat, ho fareu sota el vostre propi risc, el qual significa que haureu de posar-vos en contacte amb el fabricant original de l'equip quant a qualsevol problema causat per aquestes actualitzacions. A $OS_RELEASE:BUG_REPORT_URL$, només s'han de presentar els problemes amb el procés d'actualització." -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Mostra la informació de depuració per a tots els fitxers" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Si habiliteu aquest remot, ho fareu sota el vostre propi risc." -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Mostra la informació detallada del connector" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Encripta les dades del microprogramari" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opcions per a la depuració" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Esborra tot l'historial de les actualitzacions de microprogramari" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Mostra les opcions per a la depuració" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "S'està esborrant..." #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Surt després d'un petit retard" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Sur una vegada s'hagi carregat el motor" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Dimoni per a l'actualització de microprogramari" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Ha fallat en connectar amb el dimoni" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "La baixada ha fallat a causa del límit del servidor" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Ha fallat en obtenir els dispositius pendents" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Ha fallat en instal·lar l’actualització del microprogramari" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Servei de D-Bus per a l'actualització de microprogramari" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "No s'han pogut carregar les peculiaritats" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Està ociós..." +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Ha fallat en analitzar els arguments" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "S'està descomprimint..." +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Ha fallat en tornar a arrencar" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Ha fallat en establir el mode de presentació" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "S'està carregant..." +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "S'està obtenint el fitxer" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "S'està reiniciant el dispositiu..." +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "S'està obtenint el microprogramari" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "S'està llegint..." +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "S'estan obtenint les metadades" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "S'està escrivint..." +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "S'està obtenint la signatura" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "S'està esborrant..." +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nom del fitxer" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "S'està verificant..." +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Signatura del nom del fitxer" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Planificació..." +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Agent de microprogramari" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "S'està descarregant..." +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "URI base del microprogramari" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "S'està autenticant..." +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Servei de D-Bus per a l'actualització de microprogramari" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "S'està esperant…" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Dimoni per a l'actualització de microprogramari" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Desconegut" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Utilitat per al microprogramari" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Les metadades del microprogramari no s'han actualitzat durant %u dia i podria ser que no estiguin actualitzades." +msgstr[1] "Les metadades del microprogramari no s'han actualitzat durant %u dies i podria ser que no estiguin actualitzades." -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Trieu un dispositiu:" +msgid "Firmware updates are not supported on this machine." +msgstr "Les actualitzacions de microprogramari no estan admeses en aquesta màquina." -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "Les actualitzacions de microprogramari estan admeses en aquesta màquina." -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Els dispositius que no s'han actualitzat correctament:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Etiquetes" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Els dispositius que s'han actualitzat correctament:" +msgid "Force the action ignoring all warnings" +msgstr "Força l'acció ignorant tots els avisos" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Pujo l'informe ara?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "S'ha trobat" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Requereix connexió a Internet" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "No s'ha detectat cap maquinari amb capacitat per a l'actualització del microprogramari" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Obtén tots els dispositius segons la topologia del sistema" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "S'està reinstal·lant %s amb %s... " +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Obtén tots els dispositius i possibles llançaments" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Obté tots els dispositius que admeten actualitzacions de microprogramari" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Obtén tots els connectors habilitats registrats amb el sistema" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Obté la informació sobre un fitxer de microprogramari" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Obtén els remots configurats" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Obté el resultat d'aplicar la funció criptogràfica de resum sobre el microprogramari bolcat" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Obtén la llista del microprogramari aprovat." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Obté la llista d'actualitzacions per al maquinari connectat" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Obté els alliberaments per a un dispositiu" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Obté els resultats de l'última actualització" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Està ociós..." + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Instal·la un blob de microprogramari en un dispositiu" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instal·la un fitxer de microprogramari en aquest maquinari" + +msgid "Install old version of system firmware" +msgstr "Instal·la la versió antiga del microprogramari per al sistema" + +msgid "Install signed device firmware" +msgstr "Instal·la microprogramari signat per al dispositiu" + +msgid "Install signed system firmware" +msgstr "Instal·la microprogramari signat per al sistema" + +msgid "Install unsigned device firmware" +msgstr "Instal·la microprogramari sense signar per al dispositiu" + +msgid "Install unsigned system firmware" +msgstr "Instal·la microprogramari sense signar per al sistema" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instal·lació del microprogramari..." + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "S'està instal·lant l'actualització de microprogramari..." + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "S'està desactualitzant %s des de %s a %s... " +msgid "Installing on %s…" +msgstr "S'està intal·lant a %s…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Keyring" +msgstr " Anell de claus" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Manca menys d'un minut" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Servei de microprogramari del proveïdor Linux (microprogramari estable)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Servei de microprogramari del proveïdor Linux (microprogramari en proves)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Llista els dispositius amb capacitat DFU actualment connectats" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Llista les actualitzacions de microprogramari compatibles" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "S'està carregant..." + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Connectors especíificats manualment a la llista blanca" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Fusiona múltiples fitxers de microprogramari en un de sol" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI de les metadades" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Signatura de l'URI de les metadades" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Les metadades es poden obtenir des del servei de microprogramari del proveïdor Linux." + +#. TRANSLATORS: error message #, c-format -msgid "Updating %s from %s to %s... " -msgstr "S'està actualitzant %s des de %s a %s... " +msgid "Mismatched daemon and client, use %s instead" +msgstr "El dimoni i el client no coincideixin, useu %s en el seu lloc" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Fet!" +msgid "Mode" +msgstr "Mode" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Objectiu" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Modifica un valor de la configuració del dimoni." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modifica un remot indicat" + +msgid "Modify a configured remote" +msgstr "Modifica un remot configurat" + +msgid "Modify daemon configuration" +msgstr "Modifica la configuració del dimoni" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitora el dimoni pels esdeveniments" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nom" + +msgid "No action specified!" +msgstr "No s'ha especificat cap acció!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "No s'ha detectat cap maquinari amb capacitat per a l'actualització del microprogramari" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "No s'ha trobat cap connector" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Actualment, no hi ha cap remot habilitat, de manera que no hi ha metadades disponibles." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "No s’han aplicat les actualitzacions" + +msgid "OK" +msgstr "D'acord" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Passa per alt els avisos del connector" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Preferència sobre el camí ESP predeterminat" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Anul·la els avisos i força l'acció" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Contrasenya" -#: src/fu-util.c:727 msgid "Payload" msgstr "Carrega útil" -#: src/fu-util.c:728 +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Percentatge completat" + +msgid "Permission denied" +msgstr "Permís denegat" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Introduïu un número del 0 al %u: " + +msgid "Print the version number" +msgstr "Imprimeix el número de versió" + +msgid "Print verbose debug statements" +msgstr "Imprimeix les sentències detallades de la depuració" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioritat" + msgid "Proceed with upload?" msgstr "Continuo amb la pujada?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per obtenir més informació:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protocol" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Missatge de la pujada:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Consulta el suport per a l'actualització del microprogramari" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "D'acord" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Peculiaritats" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "S'està obtenint la signatura" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Llegeix el microprogramari des del dispositiu a un fitxer" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "S'estan obtenint les metadades" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Llegeix el microprogramari des d'una partició a un fitxer" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "S'està obtenint el microprogramari" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "S'està llegint..." -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "S'està obtenint el fitxer" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "S'està tornant a arencar..." -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Versió:" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Refresca les metadades des del servidor remot" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Resum" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Regió" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "S'està reinstal·lant %s amb %s... " #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Remot" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "ID remot" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Descripció" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "S'ha eliminat" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Suma de comprovació" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Substitueix les dades en un fitxer de microprogramari existent" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Trieu un alliberament:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI de l'informe" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "Les metadades del microprogramari no s'han actualitzat durant %u dia i podria ser que no estiguin actualitzades." -msgstr[1] "Les metadades del microprogramari no s'han actualitzat durant %u dies i podria ser que no estiguin actualitzades." +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Requereix connexió a Internet" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Actualitzo ara?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Restableix un dispositiu DFU" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s té actualitzacions de microprogramari:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Reinicio ara?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Reinicio el dimoni per a fer efectiu el canvi?" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Versió de l'actualització" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "S'està reiniciant el dispositiu..." -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Actualitza el nom" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Retorna tots els ID del maquinari de la màquina" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Actualitza el resum" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Executa la rutina de neteja de la composició del connector en usar install-blob" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Actualitza l'ID remot:" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Executa la rutina de preparació de la composició del connector en usar install-blob" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Suma de verificació de l'actualització" +msgid "Runtime" +msgstr "Temps d'execució" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Ubicació de l'actualització" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Desa l'estat del dispositiu en un fitxer JSON entre les execucions" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Descripció de l'actualització" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Planifica la instal·lació per al següent reinici quan sigui posible" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "ID remot" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Planificació..." -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Títol" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Sèrie" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Estableix el nom alternatiu al fitxer del microprogramari" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Estableix el número alternatiu al fitxer del microprogramari" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Estableix l'adreça de l'element al fitxer del microprogramari" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Estableix l'ID del producte al fitxer del microprogramari" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Estableix la versió de llançament al fitxer del microprogramari" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Estableix l'indicador de depuració durant l'actualització" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Estableix la mida del microprogramari per a l'objectiu" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Estableix l'ID del proveïdor al fitxer del microprogramari" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Estableix les metadades en un fitxer de microprogramari" + +msgid "Sets the list of approved firmware" +msgstr "Estableix la llista de microprogramari aprovat" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Estableix la llista del microprogramari aprovat." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Comparteix l'historial de microprogramari amb els desenvolupadors" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Mostra les versions del client i el dimoni" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Mostra informació detallada del dimoni per a un domini concret" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Mostra la informació de depuració per a tots els dominis" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostra les opcions per a la depuració" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Mostra els dispositius que no són actualitzables" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mostra la informació de depuració addicional" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Tipus" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Mostra l'historial de les actualitzacions de microprogramari" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr " Anell de claus" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Mostra la informació detallada del connector" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Habilitat" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Mostra el registre de depuració del darrer intent d'actualització" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Antiguitat" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Mostra la informació sobre l'estat de l'actualització del microprogramari" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Prioritat" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Aturar-lo ara?" + +msgid "Sign data using the client certificate" +msgstr "Signa les dades emprant el certificat del client" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Signa les dades emprant el certificat del client" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Nom d'usuari" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Signa les dades pujades amb el certificat del client" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Contrasenya" +msgid "Signature" +msgstr "Signatura" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Nom del fitxer" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifiqueu el proveïdor/ID del producte del dispositiu DFU" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Signatura del nom del fitxer" +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifiqueu el nombre de bytes per a la transferència USB" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI de les metadades" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Estat" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Signatura de l'URI de les metadades" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Estat" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "URI base del microprogramari" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Resum" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "URI de l'informe" +msgid "Target" +msgstr "Objectiu" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "S'ha afegit el dispositiu:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "El LVFS és un servei gratuït que funciona com una entitat legal independent i no té cap vincle amb la $OS_RELEASE:NAME$. És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats. Tot el microprogramari només és proporcionat pel fabricant original dels equips." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "No hi ha cap microprogramari aprovat." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Aquest programa només pot funcionar correctament com a «root»" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Aquest remot conté el microprogramari que no està embargat, però encara l'ha provat el proveïdor del maquinari. Haureu d'assegurar-vos que teniu una manera de baixar manualment el microprogramari si l'actualització del microprogramari no funciona." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Aquesta eina només pot ser usada per l'usuari «root»." -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "S'ha eliminat el dispositiu:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Títol" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "S'ha canviat el dispositiu:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Mida a transferir" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Una actualització requereix un reinici per a completar-se." +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipus" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "Reinicio ara?" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Utilitat per al microprogramari UEFI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Mostra la informació de depuració addicional" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Mostra les versions del client i el dimoni" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Desconegut" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Planifica la instal·lació per al següent reinici quan sigui posible" +msgid "Unlock the device to allow access" +msgstr "Desbloqueja el dispositiu per a permetre l'accés" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Permet tornar a instal·lar les versions de microprogramari existents" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Desbloqueja el dispositiu per accedir al microprogramari" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Permet tornar a la versió anterior del microprogramari" +msgid "Unset the debugging flag during update" +msgstr "No estableixis l'indicador de depuració durant l'actualització" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Passa per alt els avisos del connector" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Versió %s no admesa del dimoni, la versió del client és %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Respon sí a totes les preguntes" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Suma de verificació de l'actualització" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "No comprovar si hi ha un historial sense informar" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Descripció de l'actualització" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "No comprovar si hi ha metadades antigues" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Durada de l'actualització" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "No realitzis el reinici després de l'actualització" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Ubicació de l'actualització" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Obté tots els dispositius que admeten actualitzacions de microprogramari" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Actualitza el nom" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Retorna tots els ID del maquinari de la màquina" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Actualitza l'ID remot:" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Instal·la ara les actualitzacions preparades" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Actualitza el resum" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Mostra l'historial de les actualitzacions de microprogramari" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Versió de l'actualització" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Esborra tot l'historial de les actualitzacions de microprogramari" +msgid "Update all devices that match local metadata" +msgstr "Actualitza tots els dispositius que coincideixin amb les metadades locals" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Comparteix l'historial de microprogramari amb els desenvolupadors" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Que falli en actualitzar és un problema conegut, visiteu aquest URL per obtenir més informació:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Instal·la un fitxer de microprogramari en aquest maquinari" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Actualitzo ara?" + +msgid "Update the stored device verification information" +msgstr "Actualitza la informació de verificació dels dispositius emmagatzemats" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Obté la informació sobre un fitxer de microprogramari" +msgid "Update the stored metadata with current ROM contents" +msgstr "Actualitza les metadades emmagatzemades amb el contingut de la ROM actual" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Obté la llista d'actualitzacions per al maquinari connectat" +msgid "Update the stored metadata with current contents" +msgstr "Actualitza les metadades emmagatzemades amb el contingut actual" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Actualitza tot el microprogramari a les versions més recents" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Obté el resultat d'aplicar la funció criptogràfica de resum sobre el microprogramari bolcat" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "S'està actualitzant %s des de %s a %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Desbloqueja el dispositiu per accedir al microprogramari" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "S'està actualitzant %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Esborra els resultats de l'última actualització" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Missatge de la pujada:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Neteja qualsevol actualització programyada per a ser actualitzada sense connexió" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Pujo l'informe ara?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Obté els resultats de l'última actualització" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "L'enviament dels informes de microprogramari ajudarà als proveïdors de maquinari a identificar amb rapidesa les actualitzacions fallides i satisfactòries sobre els dispositius reals." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Obté els alliberaments per a un dispositiu" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nom d'usuari" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Obtén els remots configurats" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "S'està verificant..." -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Desactualitza el microprogramari en un dispositiu" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versió:" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Refresca les metadades des del servidor remot" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "S'està esperant…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Actualitza les metadades emmagatzemades amb el contingut de la ROM actual" +msgid "Watch DFU devices being hotplugged" +msgstr "Vigila els dispositius DFU que han estat connectats en calent" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Monitora el dimoni pels esdeveniments" +msgid "Watch for hardware changes" +msgstr "Mira per a canvis al maquinari" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Construeix el microprogramari usant un entorn de proves" +msgid "Write firmware from file into device" +msgstr "Escriu el microprogramari des d'un fitxer a dins del dispositiu" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Bolca les dades al SMBIOS des d'un fitxer" +msgid "Write firmware from file into one partition" +msgstr "Escriu el microprogramari des d'un fitxer a dins d'una partició" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Modifica un remot indicat" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "S'està escrivint..." -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Utilitat per al microprogramari" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "És possible que el vostre distribuïdor no hagi verificat cap de les actualitzacions del microprogramari per a la compatibilitat amb el vostre sistema o els dispositius connectats." diff -Nru fwupd-1.0.6/po/cs.po fwupd-1.2.10/po/cs.po --- fwupd-1.0.6/po/cs.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/cs.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,999 +1,935 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Daniel Rusek , 2017 -# Daniel Rusek , 2017 -# Marek Černocký , 2016 +# Ascii Wolf , 2017 +# Ascii Wolf , 2017 +# Marek Černocký , 2016,2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Czech (http://www.transifex.com/freedesktop/fwupd/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Zbývá %.0f minuta" +msgstr[1] "Zbývají %.0f minuty" +msgstr[2] "Zbývá %.0f minut" +msgstr[3] "Zbývá %.0f minuty" -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Aktualizace firmwaru zařízení na Linuxu" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s má aktualizace firmwaru:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Cílem tohoto projektu je učinit aktualizaci firmwaru na Linuxu automatickou, bezpečnou a spolehlivou. Pro zobrazení a aplikaci aktualizací můžete použít GUI správce softwaru typu GNOME Software, nástroj pro příkazovou řádku nebo přímo D-Bus." +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Přidáno" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd je jednoduchý démon, který umožňuje softwaru sezení aktualizovat firmware zařízení na vašem počítači. Je navržen pro stolní počítače, ale je možno jej použít také na telefonech, tabletech a serverech bez monitoru." +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Stáří" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Instalace podepsaného systémového firmwaru" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Odsouhlasit a povolit vzdálený zdroj?" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "K aktualizaci firmwaru na tomto počítači je vyžadováno ověření" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias pro %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Instalace nepodepsaného systémového firmwaru" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Povolit přechod na nižší verze firmwaru" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Instalace starší verze systémového firmwaru" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Povolit reinstalaci stávající verze firmwaru" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "K ponížení verze firmwaru na tomto počítači je vyžadováno ověření" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Některá z aktualizací vyžaduje pro dokončení restart." -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Instalace podepsaného firmwaru zařízení" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Na všechny dotazy odpovědět ano" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "K aktualizaci firmwaru na výměnném zařízení je vyžadováno ověření" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Použít binární záplatu" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Instalace nepodepsaného firmwaru zařízení" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Použít aktualizace firmwaru" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Napojit zařízení podporující DFU zpět do provozního režimu" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Napojit do režimu firmwaru" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Vlastnosti" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autentizuje se…" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "K ponížení verze firmwaru na výměnném zařízení je vyžadováno ověření" +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "K přechodu na nižší verzi firmwaru na výměnném zařízení je vyžadováno ověření" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Odemknutí zařízení pro umožnění přístupu" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "K přechodu na nižší verzi firmwaru na tomto počítači je vyžadováno ověření" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Ke změně nastaveného vzdáleného zdroje, který se používá pro aktualizace firmwaru, je vyžadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Pro odemknutí zařízení je požadováno ověření" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Aktualizace uložené informace o ověření zařízení" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "K aktualizaci uložených kontrolních součtů zařízení je vyžadováno ověření" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Upravit nastavený vzdálený zdroj" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "K aktualizaci firmwaru na výměnném zařízení je vyžadováno ověření" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "K úpravě nastaveného vzdáleného zdroje používaného pro aktualizace firmwaru je vyžadováno ověření" +msgid "Authentication is required to update the firmware on this machine" +msgstr "K aktualizaci firmwaru na tomto počítači je vyžadováno ověření" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Alias pro %s" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "K aktualizaci uložených kontrolních součtů zařízení je vyžadováno ověření" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Příkaz nebyl nalezen" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Sestavit firmware za použití izolovaného prostředí" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Přidáno" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Zrušit" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Odebráno" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Zrušeno" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Změněno" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Zrušeno" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolní součet" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID čipu" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Název" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Vyberte zařízení:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Vyberte verzi:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Šifra" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Oblast" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Nalezeno" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokol" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Stav" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Smazat vše naplánované pro aktualizaci při odpojení" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Smazat výsledky z poslední aktualizace" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Sériové číslo" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Příkaz nebyl nalezen" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Režim" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Převést firmware do formátu DFU" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Vytvořit binární záplatu za použití dvou souborů" -#: plugins/dfu/dfu-tool.c:2115 msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Stav" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Přenášená velikost" +msgstr "DFU" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Nástroj pro práci s DFU" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Zvláštní požadavky" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Volby ladění" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Rozbaluje se…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Převést firmware do formátu DFU" +msgid "Decrypt firmware data" +msgstr "Dešifrovat data firmwaru" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Sloučit více firmwarů do jednoho" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Popis" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Nastavit ID výrobce v souboru s firmwarem" +msgid "Detach currently attached DFU capable device" +msgstr "Odpojit aktuálně napojené zařízení podporující DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Nastavit ID produktu v souboru s firmwarem" +msgid "Detach to bootloader mode" +msgstr "Odpojit do režimu zavaděče" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Nastavit adresu prvku na firmwaru zařízení" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Přidáno zařízení:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Nastavit velikost firmwaru pro cíl" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Změněno zařízení:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Nastavit verzi vydání v souboru s firmwarem" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Odebráno zařízení:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Nastavit alternativní číslo v souboru s firmwarem" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Zařízení, která byla úspěšně aktualizována:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Nastavit alternativní název v souboru s firmwarem" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Zařízení, která nebyla úspěšně aktualizována:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Napojit zařízení podporující DFU zpět do běhového režimu" +msgid "Disabled fwupdate debugging" +msgstr "Vypnout ladění fwupdate" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +msgid "Disables a given remote" +msgstr "Zakázat zadaný vzdálený zdroj" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Přečíst firmware ze zařízení do souboru" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Zobrazit verzi" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Přečíst firmware z jednoho oddílu do souboru" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Nekontrolovat stáří metadat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Zapsat firmware ze souboru do zařízení" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Nekontrolovat restart po aktualizaci" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Zapsat firmware ze souboru do jednoho oddílu" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Nekontrolovat nenahlášení historie" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Nezapisovat do databáze historie" + +#. success +msgid "Done!" +msgstr "Hotovo!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Vypsat právě napojená zařízení podporující DFU" +msgid "Downgrades the firmware on a device" +msgstr "Přejít na nižší verzi firmwaru na zařízení" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Převádí se %s z verze %s na %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Stahuje se…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Odpojit aktuálně napojené zařízení podporující DFU" +msgid "Dump SMBIOS data from a file" +msgstr "Vypsat data SMBIOS ze souboru" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Vypsat podrobnosti o souboru s firmwarem" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Sledovat připojení zařízení podporujících DFU" +msgid "Dump information about a binary patch to the screen" +msgstr "Vypsat na obrazovku informace o binární záplatě" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Zašifrovat data firmwaru" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Určený ESP není platný" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Dešifrovat data firmwaru" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Povolit podporu aktualizace firmwaru na podporovaných systémech" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Nastavit metadata v souboru s firmwarem" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Povolit tento vzdálený zdroj?" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Nahradit data v existujícím souboru s firmwarem" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Povoleno" + +msgid "Enabled fwupdate debugging" +msgstr "Zapnout ladění fwupdate" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Vytvořit binární záplatu za použití dvou souborů" +msgid "Enables a given remote" +msgstr "Povolit zadaný vzdálený zdroj" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Zapnutí této funkcionality je na vaše vlastní riziko, což znamená, že v případě problémů způsobených aktualizací musíte kontaktovat přímo výrobce zařízení. Pouze problémy s aktualizačním procesem jako takovým by měly být hlášeny na $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Povolení tohoto zdroje je na vaše vlastní riziko." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Použít binární záplatu" +msgid "Encrypt firmware data" +msgstr "Zašifrovat data firmwaru" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Vypsat na obrazovku informace o binární záplatě" +msgid "Erase all firmware update history" +msgstr "Smazat veškerou historii aktualizací" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Maže se…" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Skončit po krátké prodlevě" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Skončit po načtení výkonné části" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Nezdařilo se stáhnout kvůli omezením serveru" #. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Nástroj pro práci s DFU" +msgstr "Selhalo načtení zvláštních požadavků" #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "Selhalo zpracování argumentů" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Enumerovat všechny zařízení Synaptics MST" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Zapsat soubor firmwaru do zařízení MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics Multistream Transport Utility" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Stahuje se soubor" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Instaluje se aktualizace firmwaru…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Stahuje se firmware" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Zobrazovat ladicí informace pro všechny soubory" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Stahují se metadata" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Stahuje se podpis" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Volby ladění" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Název souboru" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Zobrazit volby ladění" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Podpis názvu souboru" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Skončit po krátké prodlevě" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Základní URI firmwaru" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Skončit po načtení výkonné části" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Služba D-Bus pro aktualizaci firmwaru" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" msgstr "Démon pro aktualizaci firmwaru" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Služba D-Bus pro aktualizaci firmwaru" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Nástroj pro práci s firmwarem" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Nečinný…" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Metadata firmwaru nebyla akualizována již celý den a nelze je aktualizovat." +msgstr[1] "Metadata firmwaru nebyla akualizována již %u dny a nelze je aktualizovat." +msgstr[2] "Metadata firmwaru nebyla akualizována již %u dní a nelze je aktualizovat." +msgstr[3] "Metadata firmwaru nebyla akualizována již %u dne a nelze je aktualizovat." -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Rozbaluje se firmware…" +msgid "Firmware updates are not supported on this machine." +msgstr "Aktualizace firmwaru nejsou na tomto počítači podporované." -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Načítá se…" +msgid "Firmware updates are supported on this machine." +msgstr "Aktualizace firmwaru jsou na tomto počítači podporované." -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Zařízení se restartuje…" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Nalezeno" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Čte se…" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Zapisuje se…" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Zjistit všechna zařízení podle topologie systému" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Maže se…" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Zjistit všechna zařízení podporující aktualizaci firmwaru" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Ověřuje se…" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Zjistit všechny povolené zásuvné moduly registrované v systému" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Plánuje se…" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Zjistit podrobnosti o souboru s firmwarem" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Stahuje se…" +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Vypsat nastavené vzdálené zdroje" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Ověřuje se…" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Vypsat kryptografický otisk vypsaného firmwaru" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Vypsat seznam aktualizací pro připojený hardware" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Neznámý" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Vypsat vydání pro zařízení" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Vypsat výsledky z poslední aktualizace" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Vyberte zařízení:" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Nečinný…" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Nainstalovat na zařízení binární soubor s firmwarem" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Nainstalovat soubor s firmwarem na tento hardware" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +msgid "Install old version of system firmware" +msgstr "Instalace starší verze systémového firmwaru" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +msgid "Install signed device firmware" +msgstr "Instalace podepsaného firmwaru zařízení" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" +msgid "Install signed system firmware" +msgstr "Instalace podepsaného systémového firmwaru" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Přeinstalovává se %s na %s…" +msgid "Install unsigned device firmware" +msgstr "Instalace nepodepsaného firmwaru zařízení" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Ponižuje se %s z verze %s na %s…" +msgid "Install unsigned system firmware" +msgstr "Instalace nepodepsaného systémového firmwaru" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Instaluje se aktualizace firmwaru…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Aktualizuje se %s z verze %s na %s…" +msgid "Installing on %s…" +msgstr "Instaluje se na zařízení %s…" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Hotovo!" +msgid "Keyring" +msgstr "Klíčenka" -#: src/fu-util.c:726 -msgid "Target" -msgstr "" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Zbývá méně než jedna minuta" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabilní firmware)" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (testovací firmware)" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Vypsat právě napojená zařízení podporující DFU" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "V pořádku" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Vypsat podporované aktualizace firmwarů" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Stahuje se podpis" +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Načítá se…" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Stahují se metadata" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Ručně povolit konkrétní zásuvné moduly" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Stahuje se firmware" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Sloučit více firmwarů do jednoho" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Stahuje se soubor" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI metadat" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Verze" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Podpis URI metadat" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadata lze získat ze služby Linux Vendor Firmware." -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "Vzdálený zdroj" +msgid "Mode" +msgstr "Režim" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Změnit zadaný vzdálený zdroj" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Popis" +msgid "Modify a configured remote" +msgstr "Upravit nastavený vzdálený zdroj" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Kontrolní součet" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Sledovat události démona" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Vyberte verzi:" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Název" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgid "No action specified!" +msgstr "Není určena žádné akce!" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Nebylo nalezeno žádné zařízení schopné aktualizace firmwaru" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s má aktualizace firmwaru:" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nebyl nalezen žádný zásuvný modul" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Zrovna nejsou povolené žádné vzdálené zdroje, takže nejsou k dispozici žádná metadata." -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +msgid "OK" +msgstr "V pořádku" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Verze aktualizace" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Potlačit varování zásuvného modulu" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Přepsat výchozí cestu ESP" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Heslo" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Vzdálené ID aktualizace" +msgid "Payload" +msgstr "Obsah" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Kontrolní součet aktualizace" +msgid "Permission denied" +msgstr "Byl odepřen přístup" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Umístění aktualizace" +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Zadejte prosím číslo od 0 do %u:" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Popis aktualizace" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorita" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Vzdálené ID" +msgid "Proceed with upload?" +msgstr "Pokračovat v nahrávání?" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Název" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Typ" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Dotázat se na podporu aktualizace firmwaru" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Klíčenka" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Zvláštní požadavky" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Povoleno" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Přečíst firmware ze zařízení do souboru" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Věk" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Přečíst firmware z jednoho oddílu do souboru" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Priorita" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Čte se…" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Uživatelské jméno" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Aktualizovat metadata ze vzdáleného serveru" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Heslo" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Oblast" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Název souboru" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Přeinstalovává se %s na %s…" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Podpis názvu souboru" +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Vzdálený zdroj" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI metadat" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "ID vzdáleného zdroje" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Podpis URI metadat" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Odebráno" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Základní URI firmwaru" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Nahradit data ve stávajícím souboru s firmwarem" #. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 msgid "Report URI" -msgstr "" +msgstr "URI hlášení" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Přidáno zařízení:" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Odebráno zařízení:" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Změněno zařízení:" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Vyžaduje připojení k Internetu" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Resetovat zařízení podporující DFU" #. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 msgid "Restart now?" -msgstr "" +msgstr "Restartovat nyní?" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Zobrazovat doplňující informace pro ladění" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Zařízení se restartuje…" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Zobrazit verzi klienta a démonu" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Vrátit všechna ID hardwaru počítače" + +msgid "Runtime" +msgstr "provozní" #. TRANSLATORS: command line option -#: src/fu-util.c:2122 msgid "Schedule installation for next reboot when possible" msgstr "Pokud je to možné, naplánovat instalaci na příští restart" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Povolit reinstalaci stávající verze firmwaru" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Povolit ponížení verze firmwaru" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Potlačit varování zásuvného modulu" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Plánuje se…" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Sériové číslo" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Nastavit alternativní název v souboru s firmwarem" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Nastavit alternativní číslo v souboru s firmwarem" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Nastavit adresu prvku na firmwaru zařízení" #. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Zjistit všechna zařízení podporující aktualizaci firmwaru" +msgid "Set product ID on firmware file" +msgstr "Nastavit ID produktu v souboru s firmwarem" #. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Vrátit všechna ID hardwaru počítače" +msgid "Set release version on firmware file" +msgstr "Nastavit verzi vydání v souboru s firmwarem" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Během aktualizace nastavit příznak ladění" #. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Nainstalovat připravené aktualizace nyní" +msgid "Set the firmware size for the target" +msgstr "Nastavit velikost firmwaru pro cíl" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Set vendor ID on firmware file" +msgstr "Nastavit ID výrobce v souboru s firmwarem" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +msgid "Sets metadata on a firmware file" +msgstr "Nastavit metadata v souboru s firmwarem" #. TRANSLATORS: command description -#: src/fu-util.c:2196 msgid "Share firmware history with the developers" -msgstr "" +msgstr "Sdílet historii firmwaru s vývojáři" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Nainstalovat soubor s firmwarem na tento hardware" +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Zobrazit verzi klienta a démona" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Vypsat podrobnosti o souboru s firmwarem" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Zobrazit volby ladění" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Vypsat seznam aktualizací pro připojený hardware" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Zobrazit zařízení, která nelze aktualizovat" -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Zobrazovat doplňující informace pro ladění" #. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Vypsat kryptografický otisk vypsaného firmwaru" +msgid "Show history of firmware updates" +msgstr "Zobrazit historii aktualizací firmwaru" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Zobrazit podrobné informace o zásuvném modulu" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Zobrazit ladicí záznam z posledního pokusu o aktualizaci" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Zobrazit informace o stavu aktualizace firmwaru" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Stav" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Stav" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Souhrn" + +msgid "Target" +msgstr "Cíl" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS je svobodná služba, které funguje jako nezávislý právní subjekt a nemá žádné vazby na systém $OS_RELEASE:NAME$. Váš distributor nemusí některé z aktualizací firmwaru schválit kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními. Veškerý firmware je poskytován pouze přímo výrobci daných zařízení." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Tento program může správně fungovat jen pod uživatelem root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Tento zdroj obsahuje firmware, který není zakázaný, ale zatím je u výrobce stále ve stádiu testování. Měli byste se ujistit, že znáte způsob, jak se vrátit k předchozí verzi firmwaru, kdyby došlo k selhání." + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Název" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Přenášená velikost" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Typ" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Nástroj pro práci s firmwarem UEFI" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Neznámý" + +msgid "Unlock the device to allow access" +msgstr "Odemknutí zařízení pro umožnění přístupu" #. TRANSLATORS: command description -#: src/fu-util.c:2232 msgid "Unlocks the device for firmware access" msgstr "Odemknout zařízení pro přístup k firmwaru" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Smazat výsledky z poslední aktualizace" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Během aktualizace zrušit příznak ladění" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Smazat všechny aktualizace naplánované pro offline aktualizaci" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Kontrolní součet aktualizace" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Vypsat výsledky z poslední aktualizace" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Popis aktualizace" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Vypsat vydání pro zařízení" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Umístění aktualizace" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Vypsat nastavené vzdálené zdroje" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Název aktualizace" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Ponížit verzi firmwaru na zařízení" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "ID vzdáleného zdroje aktualizace" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Aktualizovat metadata ze vzdáleného serveru" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Souhrn aktualizace" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Verze aktualizace" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "O selhání aktualizace se ví, více informací najdete na této adrese:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Aktualizovat nyní?" + +msgid "Update the stored device verification information" +msgstr "Aktualizace uložené informace o ověření zařízení" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "Aktualizovat uložená metadata pomocí aktuálního obsahu ROM" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Sledovat události démonu" +msgid "Updates all firmware to latest versions available" +msgstr "Aktualizovat všechen firmware na nejnovější dostupné verze" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Aktualizuje se %s z verze %s na %s…" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Nahraná zpráva:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Nahrát hlášení nyní?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Když nahrajete hlášení o firmwaru, pomůžete tím výrobcům hardwaru rychle rozpoznat nezdařené a úspěšné aktualizace na reálných zařízeních." + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Uživatelské jméno" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Ověřuje se…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Verze" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Čeká se…" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Sestavit firmware za použití izolovaného prostředí" +msgid "Watch DFU devices being hotplugged" +msgstr "Sledovat připojení zařízení podporujících DFU" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Vypsat SMBIOS data ze souboru" +msgid "Watch for hardware changes" +msgstr "Sledovat změny hardwaru" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Upraví zadaný vzdálený zdroj" +msgid "Write firmware from file into device" +msgstr "Zapsat firmware ze souboru do zařízení" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Nástroj pro práci s firmwarem" +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Zapsat firmware ze souboru do jednoho oddílu" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Zapisuje se…" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Váš distributor nemusí schválit některé aktualizace firmwaru kvůli kompatibilitě s vaším systémem nebo připojenými zařízeními." diff -Nru fwupd-1.0.6/po/da.po fwupd-1.2.10/po/da.po --- fwupd-1.0.6/po/da.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/da.po 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,1228 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# scootergrisen, 2019 +# scootergrisen, 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Danish (http://www.transifex.com/freedesktop/fwupd/language/da/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: da\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minut tilbage" +msgstr[1] "%.0f minutter tilbage" + +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "%s ME-opdatering for forbruger" + +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Kontrolleropdatering for %s" + +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "%s ME-opdatering for virksomhed" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Enhedsopdatering for %s" + +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Controlleropdatering for indlejret %s" + +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "ME-opdatering for %s" + +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Systemopdatering for %s" + +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Opdatering for %s" + +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s har firmwareopdateringer:" + +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dage" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u time" +msgstr[1] "%u timer" + +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minut" +msgstr[1] "%u minutter" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekund" +msgstr[1] "%u sekunder" + +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktivér enheder" + +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktiverer afventende enheder" + +msgid "Activate the new firmware on the device" +msgstr "Aktivér den nye firmware på enheden" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Aktiverer firmwareopdatering" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Aktiverer firmwareopdatering for" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Tilføjet" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Alder" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Accepter og aktivér fjernen?" + +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias til %s" + +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Tillad nedgradering af firmwareversioner" + +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Tillad geninstallering af eksisterende firmwareversioner" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "For at fuldføre en opdatering skal systemet genstartes." + +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "For at fuldføre en opdatering skal systemet lukkes ned." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Svar ja til alle spørgsmål" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Anvend en binær patch" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Anvend firmwareopdateringer" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Godkendt firmware:" +msgstr[1] "Godkendt firmware:" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Tilkobl enheder som formår DFU tilbage til runtime" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Tilkobl til firmwaretilstand" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attributter" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autentificerer …" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Der kræves autentifikation for at nedgradere firmwaren på en flytbar enhed" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Der kræves autentifikation for at nedgradere firmwaren på maskinen" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Der kræves autentifikation for at redigere en konfigureret fjern som bruges til firmwareopdateringer" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Der kræves autentifikation for at redigere dæmonkonfiguration" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Der kræves autentifikation for at indstille listen over godkendt firmware" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Der kræves autentifikation for at underskrive data med klientcertifikatet" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Der kræves autentifikation for at skifte til den nye firmwareversion" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Der kræves autentifikation for at låse enhed op" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Der kræves autentifikation for at opdatere firmwaren på en flytbar enhed" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Der kræves autentifikation for at opdatere firmwaren på maskinen" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Der kræves autentifikation for at opdatere de gemte checksumme for enheden" + +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Byg firmware med en sandkasse" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Annuller" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Annulleret" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Ændret" + +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Checksum" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip-id" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Vælg en enhed:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Vælg en udgivelse:" + +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Krypteringsalgoritme" + +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Rydder opdateringer som er planlagt til at blive opdateret offline" + +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Rydder resultaterne fra den sidste opdatering" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Kommandoen blev ikke fundet" + +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Konverter firmware til DFU-format" + +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Opret en binær patch ved brug af to filer" + +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU-redskab" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Fejlsøgningsindstillinger" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Udpakker …" + +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Afkryptér firmwaredata" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Beskrivelse" + +#. TRANSLATORS: command description +msgid "Detach currently attached DFU capable device" +msgstr "Frakobl tilkoblede enheder som formår DFU" + +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Frakobl til opstartsindlæsertilstand" + +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Enheds-id" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Enhed tilføjet:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Enhed ændret:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Enhed fjernet:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Enheder som det lykkedes at opdatere:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Enheder som ikke blev opdateret korrekt:" + +msgid "Disabled fwupdate debugging" +msgstr "Deaktivér fejlsøgning af fwupdate" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Deaktiverer en angivet fjern" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Vis version" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Tjek ikke efter gammel metadata" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Tjek ikke om der er genstartet, efter opdatering" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Tjek ikke efter historik som ikke er blevet rapporteret" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Skriv ikke til historikdatabasen" + +#. success +msgid "Done!" +msgstr "Færdig!" + +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "Nedgraderer firmwaren på en enhed" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Nedgraderer %s fra %s til %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Nedgraderer %s …" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Downloader …" + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "Dump SMBIOS-data fra en fil" + +#. TRANSLATORS: command description +msgid "Dump details about a firmware file" +msgstr "Dump detaljer om en firmwarefil" + +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Dump information om en binær patch på skærmen" + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Angivet ESP var ikke gyldig" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Aktivér understøttelse af firmwareopdateringer på systemer som understøtter det" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Aktivér fjernen?" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Aktiveret" + +msgid "Enabled fwupdate debugging" +msgstr "Aktivér fejlsøgning af fwupdate" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Aktiverer en angivet fjern" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Aktivering af funktionen sker på egen risiko. Det betydet at du skal kontakte din oprindelige udstyrsproducent vedrørende eventuelle problemer forårsaget af opdateringerne. Det er kun problemer med selv opdateringsprocessen som skal indsende på $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Aktivering af fjernen sker på egen risiko." + +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Kryptér firmwaredata" + +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Slet al historik over firmwareopdateringer" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Sletter …" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Afslut efter en lille forsinkelse" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Afslut efter motoren er indlæst" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Kunne ikke oprette forbindelse til dæmonen" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Kunne ikke downloade pga. begrænsning på server" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Kunne ikke hente afventende enheder" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Kunne ikke installere firmwareopdateringen" + +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Kunne ikke indlæse quirks" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Kunne ikke fortolke argumenter" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Kunne ikke genstarte" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Kunne ikke indstille splash-tilstand" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Henter fil" + +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Henter firmware" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Henter metadata" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Henter underskrift" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Filnavn" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Filnavnets underskrift" + +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Firmwareagent" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Grund-URI for firmware" + +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "D-Bus-tjeneste for firmwareopdatering" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Firmwareopdateringsdæmon" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmwareredskab" + +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Firmwaremetadata er ikke blevet opdateret i %u dag og kan være forældet." +msgstr[1] "Firmwaremetadata er ikke blevet opdateret i %u dage og kan være forældet." + +msgid "Firmware updates are not supported on this machine." +msgstr "Maskinen understøtter ikke firmwareopdateringer." + +msgid "Firmware updates are supported on this machine." +msgstr "Maskinen understøtter firmwareopdateringer." + +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Flag" + +msgid "Force the action ignoring all warnings" +msgstr "Tving handlingen og ignorer alle advarsler" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Fundet" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Hent alle enheder i henhold til systemets topologi" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Hent alle enheder og mulige udgivelser" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Hent alle enheder som understøtter firmwareopdateringer" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Hent alle aktiverede plugins som er registreret med systemet" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Hent detaljer om en firmwarefil" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Henter de konfigurerede fjerne" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Henter den kryptografiske hash fra den dumpede firmware" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Henter listen over godkendt firmware." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Henter listen over opdateringer for tilsluttet hardware" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Henter resultaterne fra en enhed" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Henter resultaterne fra den sidste opdatering" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Id" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Inaktiv …" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Installer en firmwareblob på en enhed" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Installer en firmwarefil på hardwaren" + +msgid "Install old version of system firmware" +msgstr "Installer gammel version af systemfirmware" + +msgid "Install signed device firmware" +msgstr "Installer enhedsfirmware der er underskrevet" + +msgid "Install signed system firmware" +msgstr "Installer systemfirmware der er underskrevet" + +msgid "Install unsigned device firmware" +msgstr "Installer enhedsfirmware der ikke er underskrevet" + +msgid "Install unsigned system firmware" +msgstr "Installer systemfirmware der ikke er underskrevet" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Installerer firmware …" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Installerer firmwareopdateringer …" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installerer på %s …" + +msgid "Keyring" +msgstr "Nøglering" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Mindre end et minut tilbage" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabilt firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (testning firmware)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Vis tilkoblede enheder som formår DFU" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Vis understøttede firmwareopdateringer" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Indlæser …" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Manuel hvidlistning af bestemte plugins" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Sammenlæg flere firmwarefiler i én" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadata-URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Underskrift for metadata-URI" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadata kan hentes fra Linux Vendor Firmware Service." + +#. TRANSLATORS: error message +#, c-format +msgid "Mismatched daemon and client, use %s instead" +msgstr "Dæmon og klient passer ikke sammen, brug %s i stedet" + +msgid "Mode" +msgstr "Tilstand" + +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Rediger en værdi i dæmonkonfiguration." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Redigerer en angivet fjern" + +msgid "Modify a configured remote" +msgstr "Rediger en konfigureret fjern" + +msgid "Modify daemon configuration" +msgstr "Rediger dæmonkonfiguration" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Overvåg dæmonen for hændelser" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Navn" + +msgid "No action specified!" +msgstr "Der er ikke angivet nogen handling!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Der blev ikke fundet nogen hardware med firmware som kan opdateres" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Der blev ikke fundet nogen plugins" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Der er ikke nogen metadata da der ikke er aktiveret nogen fjerne." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Der blev ikke anvendt nogen opdateringer" + +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Tilsidesæt advarsel for plugin" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Tilsidesæt standard-ESP-stien" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Tilsidesæt advarsler og gennemtving handlingen" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Adgangskode" + +msgid "Payload" +msgstr "Nyttelast" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Procent fuldført" + +msgid "Permission denied" +msgstr "Tilladelse nægtet" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Indtast venligst et tal nummer 0 og %u: " + +msgid "Print the version number" +msgstr "Udskriv versionsnummer" + +msgid "Print verbose debug statements" +msgstr "Udskriv uddybende fejlsøgningsudsagn" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioritet" + +msgid "Proceed with upload?" +msgstr "Fortsæt med upload?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Forespørg om understøttelse af firmwareopdatering" + +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Quirks" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Læs firmware fra enhed ind i en fil" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Læs firmware fra en partition ind i en fil" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Læser …" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Genstarter …" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Genopfrisk metadata fra fjernserver" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Område" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Geninstallerer %s med %s... " + +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Fjern" + +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Fjern-id" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Fjernet" + +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Erstat data i en eksisterende firmwarefil" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Rapport-URI" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Kræver internetforbindelse" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Nulstil en DFU-enhed" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Genstart nu?" + +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Genstart dæmonen så ændringerne kan træde i kraft?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Genstarter enhed …" + +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Returner alle maskinens hardware-id'er" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Kør oprydningsrutinen for pluginkomposition når install-blob bruges" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Kør forberedelsesrutinen for pluginkomposition når install-blob bruges" + +msgid "Runtime" +msgstr "Runtime" + +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Gem enhedens tilstand i en JSON-fil mellem udførsler" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Planlægning af installation ved næste genstart, når det er muligt" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Planlægger …" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serienummer" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Indstil alternativt navn på firmwarefil" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Indstil alternativt tal på firmwarefil" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Indstil elementadresse på firmwarefil" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Indstil producent-id på firmwarefil" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Indstil udgivelsesversion på firmwarefil" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Indstil fejlsøgningsflaget under opdatering" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Indstil firmwarestørrelse på målet" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Indstil producent-id på firmwarefil" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Indstiller metadata på en firmwarefil" + +msgid "Sets the list of approved firmware" +msgstr "Indstiller listen over godkendt firmware" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Indstiller listen over godkendt firmware." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Del historik over firmware med udviklerne" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Vis klient- og dæmonversioner" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Vis uddybende information for dæmon for et bestemt domæne" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Vis fejlsøgningsinformation for alle domæner" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Vis fejlsøgningsindstillinger" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Vis enheder som ikke kan opdateres" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Vis ekstra fejlsøgningsinformation" + +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Vis historik over firmwareopdateringer" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Vis uddybende information om plugin" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Vis fejlsøgningsloggen fra den opdatering der blev forsøgt sidst" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Vis informationen om firmwareopdateringsstatus" + +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Luk ned nu?" + +msgid "Sign data using the client certificate" +msgstr "Underskriv data med klientcertifikat" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Underskriv data med klientcertifikat" + +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Underskriv den uploadede data med klientcertifikatet" + +msgid "Signature" +msgstr "Underskrift" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Angiv producent-/produkt-id('er) for DFU-enhed" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Angiv antal bytes pr. USB-overførsel" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Tilstand" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Opsummering" + +msgid "Target" +msgstr "Mål" + +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS'en er en gratis tjeneste der opererer som en selvstændig juridisk enhed og har ingen forbindelse med $OS_RELEASE:NAME$. Din distributør har måske ikke bekræftet nogen af firmwareopdateringerne for kompatibilitet med dit system eller tilsluttede enheder. Al firmware leveres kun af den oprindelige udstyrsproducent." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Der er ikke nogen godkendt firmware." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Programmet virker måske kun korrekt som root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Fjernen indeholder firmware som der ikke er embargo på, men som stadigvæk testes af hardwareproducenten. Du skal sikre dig at du har en manuel måde til at nedgradere firmwaren på hvis firmwareopdateringen mislykkedes." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Værktøjet kan kun bruges af root-brugeren" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Overførselsstørrelse" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Type" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI-firmwareredskab" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Ukendt" + +msgid "Unlock the device to allow access" +msgstr "Lås enheden op for at tillade adgang" + +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Låser op for enheden for at få adgang til firmwaren" + +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Fjern fejlsøgningsflaget under opdatering" + +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Uunderstøttet dæmonversion %s, klientversionen er %s" + +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Opdateringens checksum" + +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Opdateringens beskrivelse" + +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Opdateringens varighed" + +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Opdateringens placering" + +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Opdateringens navn" + +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Opdateringens fjern-id" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Opdateringens opsummering" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Opdateringens version" + +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Opdater alle enheder som matcher lokale metadata" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Opdateringer som mislykkes er et velkendt problem. Besøg URL'en for mere information:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Opdater nu?" + +msgid "Update the stored device verification information" +msgstr "Opdaterer de gemte informationer om enhedsverifikation" + +#. TRANSLATORS: command description +msgid "Update the stored metadata with current ROM contents" +msgstr "Opdater de gemte metadata med indholdet fra den nuværende ROM" + +#. TRANSLATORS: command description +msgid "Update the stored metadata with current contents" +msgstr "Opdater det gemte metadata med det nuværende indhold" + +#. TRANSLATORS: command description +msgid "Updates all firmware to latest versions available" +msgstr "Opdaterer alle firmware til de seneste versioner" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Opdaterer %s fra %s til %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Opdaterer %s …" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Uploadmeddelelse:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Upload rapport nu?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Upload af firmwarerapporter hjælper hardwareproducenter til hurtigt at identificere opdateringer som fejlede og lykkedes på rigtigt hardware." + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Brugernavn" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verificerer …" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Venter …" + +#. TRANSLATORS: command description +msgid "Watch DFU devices being hotplugged" +msgstr "Hold øje med DFU-enheder som hotplugges" + +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Hold øje med hardwareændringer" + +#. TRANSLATORS: command description +msgid "Write firmware from file into device" +msgstr "Skriv firmware fra fil ind i enhed" + +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Skriv firmware fra fil ind i en partition" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Skriver …" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Din distributør har måske ikke verificeret kompatibiliteten af firmwareopdateringerne med dit system eller tilsluttede enheder." diff -Nru fwupd-1.0.6/po/de.po fwupd-1.2.10/po/de.po --- fwupd-1.0.6/po/de.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/de.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,17 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: +# Ettore Atalan , 2018 # Marco Tedaldi , 2015 # Wolfgang Stöggl , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: German (http://www.transifex.com/freedesktop/fwupd/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,979 +17,851 @@ "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f Minute verbleibt" +msgstr[1] "%.0f Minuten verbleiben" -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "Firmware-Aktualisierungen für %s verfügbar:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Hinzugefügt" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Alter" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Signierte System-Firmware installieren" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Verweis auf %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Auf diesem System ist eine Authentifizierung notwendig, um das Firmware Update durch zu führen" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Herabstufung von Firmware-Versionen zulassen" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Nicht-signierte System-Firmware installieren" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Erneute Installation vorhandener Firmware-Versionen erlauben" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Alte Version der System-Firmware installieren" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Ein Neustart ist erforderlich, um eine Aktualisierung abzuschließen." -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Auf diesem System ist eine Legitimierung erforderlich, um das Firmware-Downgrade durchzuführen" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Alle Fragen mit Ja beantworten" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Signierte Geräte-Firmware installieren" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Binären Patch anwenden" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Legitimierung ist notwendig, um die Firmware auf einem entfernbaren Gerät zu aktualisieren" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Firmware-Aktualisierungen anwenden" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Nicht-signierte Geräte-Firmware installieren" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "DFU-fähiges Gerät wieder zurück in Laufzeit einhängen" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribute" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Authentifizierung …" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Legitimierung ist erforderlich, um das Firmware-Downgrade auf einem entfernbaren Gerät durchzuführen" +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Für eine Herabstufung der Firmware auf einem entfernbaren Gerät ist eine Authentifizierung erforderlich" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Das Gerät entsperren, um Zugriff zu ermöglichen" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Für eine Herabstufung der Firmware auf diesem System ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Legitimation ist zum Entsperren eines Geräts erforderlich" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Für die Aktualisierung der Firmware auf einem entfernbaren Gerät ist eine Authentifizierung erforderlich" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Für die Aktualisierung der Firmware auf diesem System ist eine Authentifizierung erforderlich" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Verweis auf %s" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Eine Authentifizierung ist erforderlich, um die gespeicherten Prüfsummen für das Gerät zu aktualisieren" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Befehl nicht gefunden" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Firmware mit Hilfe einer Sandbox erstellen" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Hinzugefügt" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Abbrechen" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Entfernt" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Abgebrochen" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Geändert" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Abgebrochen" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Prüfsumme" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "Kennung" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip-Kennung" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Name" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Wählen Sie ein Gerät aus:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Wählen Sie eine Version aus:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Verschlüsselungsverfahren" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Bereich" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Bereinigt die Ergebnisse der letzten Aktualisierung" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Gefunden" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Befehl nicht gefunden" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokoll" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Firmware in das DFU-Format konvertieren" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Status" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Binären Patch aus zwei Dateien erstellen" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" +msgid "DFU" +msgstr "DFU" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Seriell" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU-Dienstprogramm" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Modus" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Debug Optionen" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Entpacken …" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Firmware-Daten entschlüsseln" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Zustand" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Beschreibung" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" +#. TRANSLATORS: command description +msgid "Detach currently attached DFU capable device" +msgstr "Derzeit eingehängtes DFU-fähiges Gerät entfernen" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Gerät hinzugefügt:" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Macken" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Gerät geändert:" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Gerät entfernt:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Firmware in das DFU-Format konvertieren" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Erfolgreich aktualisierte Geräte:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Mehrere Firmware-Dateien in eine zusammenführen" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Nicht korrekt aktualisierte Geräte:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Hersteller-Kennung einer Firmware-Datei festlegen" +msgid "Disabled fwupdate debugging" +msgstr "fwupdate-Defektlokalisierung deaktivieren" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Produkt-Kennung einer Firmware-Datei festlegen" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Version anzeigen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Die Elementadresse in Firmware-Datei festlegen" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Nicht auf alte Metadaten prüfen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Die Firmware-Größe für das Ziel festlegen" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Nach der Aktualisierung nicht auf einen Neustart prüfen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Veröffentlichungsversion einer Firmware-Datei festlegen" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Nicht auf nicht erfassten Verlauf prüfen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Alternative Nummer einer Firmware-Datei festlegen" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Nicht in die Verlaufsdatenbank schreiben" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Alternativen Namen einer Firmware-Datei festlegen" +#. success +msgid "Done!" +msgstr "Fertig." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "DFU-fähiges Gerät wieder zurück in Laufzeit einhängen" +msgid "Downgrades the firmware on a device" +msgstr "Stuft die Firmware auf einem Gerät herab" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Herabstufung für %s von %s auf %s wird eingespielt…" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Firmware von Gerät in Datei schreiben" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "%s wird herabgestuft …" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Firmware von einzelner Partition in Datei lesen" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Herunterladen …" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Firmware von Datei auf Gerät schreiben" +msgid "Dump SMBIOS data from a file" +msgstr "SMBIOS-Daten aus einer Datei ausgeben" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Firmware aus Datei in einzelne Partition schreiben" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Derzeit angeschlossene DFU-fähige Geräte auflisten" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Derzeit eingehängtes DFU-fähiges Gerät entfernen" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Details zu einer Firmware-Datei ausgeben" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Geräteanschluss von DFU-Geräten überwachen" +msgid "Dump information about a binary patch to the screen" +msgstr "Informationen über einen binären Patch auf dem Bildschirm ausgeben" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Firmwaredaten verschlüsseln" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Das angegebene ESP war nicht gültig" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Firmwaredaten entschlüsseln" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Firmware-Aktualisierungsunterstützung auf unterstützten Systemen aktivieren" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Metadaten einer Firmware-Datei festlegen" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Aktiviert" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" +msgid "Enabled fwupdate debugging" +msgstr "fwupdate-Defektlokalisierung aktivieren" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Die Aktivierung dieser Funktionalität erfolgt auf eigene Gefahr, d.h. Sie müssen sich bei Problemen, die durch diese Aktualisierungen verursacht werden, an Ihren Erstausrüster wenden. Nur Probleme mit dem Aktualisierungsprozess selbst sollten unter $OS_RELEASE:BUG_REPORT_URL$ eingereicht werden." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" +msgid "Encrypt firmware data" +msgstr "Firmware-Daten verschlüsseln" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" +msgid "Erase all firmware update history" +msgstr "Gesamten Firmware-Aktualisierungsverlauf löschen" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Löschen …" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU-Werkzeug" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Verlassen nach einer kurzen Verzögerung" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Nach dem Laden der Engine beenden" #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "Verarbeitung der Argumente schlug fehl" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Datei wird abgerufen" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Firmware wird abgerufen" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Debuginformationen für alle Dateien anzeigen" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Metadaten werden abgerufen" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Signatur wird abgerufen" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Debug Optionen" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Dateiname" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Debug Optionen anzeigen" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Signatur des Dateinamens" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Verlassen nach einer kurzen Verzögerung" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Firmware Basis-URI" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Nach dem Laden der Engine beenden" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "D-Bus-Dienst für Firmware-Aktualisierung" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" -msgstr "Dienst für Firmware-Aktualisierung" +msgstr "Hintergrundprogramm für Firmware-Aktualisierung" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "D-Bus-Dienst für Firmware-Aktualisierung" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmware-Dienstprogramm" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Bereit …" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Firmware-Metadaten wurden seit %u Tag nicht aktualisiert und sind möglicherweise nicht auf dem neuesten Stand." +msgstr[1] "Firmware-Metadaten wurden seit %u Tagen nicht aktualisiert und sind möglicherweise nicht auf dem neuesten Stand." -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Entpacken …" +msgid "Firmware updates are not supported on this machine." +msgstr "Firmware-Aktualisierungen werden auf diesem System nicht unterstützt." -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Laden …" +msgid "Firmware updates are supported on this machine." +msgstr "Firmware-Aktualisierungen werden auf diesem System unterstützt." -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Gerät wird neu gestartet …" +msgid "Force the action ignoring all warnings" +msgstr "Aktion erzwingen, bei der alle Warnungen ignoriert werden" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Gefunden" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Schreiben …" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Ermittelt alle Geräte gemäß der Systemtopologie" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Überprüfung läuft …" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Alle Geräte ermitteln, die Firmware-Aktualisierungen unterstützen" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Einplanen …" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Alle aktivierten und im System registrierten Plugins ermitteln" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Ermittelt Details über eine Firmware-Datei" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Ermittelt den kryptographischen Hash-Wert der abgelegten Firmware" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Ermittelt die Liste der Aktualisierungen für angeschlossene Hardware" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Unbekannt" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Ermittelt die Versionen für ein Gerät" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Ermittelt die Ergebnisse der letzten Aktualisierung" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Kennung" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Bereit …" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Firmware-Blob auf einem Gerät installieren" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Eine Firmware-Datei auf dieser Hardware installieren" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +msgid "Install old version of system firmware" +msgstr "Alte Version der System-Firmware installieren" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +msgid "Install signed device firmware" +msgstr "Signierte Geräte-Firmware installieren" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Es wurde keine Hardware erkannt, deren Firmware aktualisiert werden kann" +msgid "Install signed system firmware" +msgstr "Signierte System-Firmware installieren" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Erneute Installation von %s mit %s …" +msgid "Install unsigned device firmware" +msgstr "Nicht-signierte Geräte-Firmware installieren" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Downgrade für %s von %s auf %s wird eingespielt …" +msgid "Install unsigned system firmware" +msgstr "Nicht-signierte System-Firmware installieren" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Firmware-Aktualisierung wird installiert …" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Aktualisieren von %s von %s nach %s …" +msgid "Installing on %s…" +msgstr "Wird auf %s installiert …" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Fertig." +msgid "Keyring" +msgstr "Schlüsselbund" -#: src/fu-util.c:726 -msgid "Target" -msgstr "" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Weniger als eine Minute verbleiben" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabile Firmware)" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (Test-Firmware)" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Derzeit angeschlossene DFU-fähige Geräte auflisten" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Unterstützte Firmware-Aktualisierungen auflisten" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "Ok" +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Laden …" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Mehrere Firmware-Dateien in eine zusammenführen" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadaten-URI" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadaten URI-Signatur" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadaten können über den Linux Vendor Firmware Service bezogen werden." -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Version" +msgid "Mode" +msgstr "Modus" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Hintergrundprogramm auf Ereignisse überwachen" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Name" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" +msgid "No action specified!" +msgstr "Keine Aktion angegeben!" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Beschreibung" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Es wurde keine Hardware erkannt, deren Firmware aktualisiert werden kann" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Prüfsumme" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Keine Plugins gefunden" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" +msgid "OK" +msgstr "Ok" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Plugin-Warnung überschreiben" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Standard-ESP-Pfad überschreiben" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Passwort" + +msgid "Payload" +msgstr "Nutzdaten" + +msgid "Permission denied" +msgstr "Berechtigung verweigert" + +#. TRANSLATORS: the user isn't reading the question #, c-format -msgid "%s has firmware updates:" -msgstr "Firmwareaktualisierungen für %s verfügbar:" +msgid "Please enter a number from 0 to %u: " +msgstr "Bitte geben Sie eine Zahl von 0 bis %u ein: " -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +msgid "Print the version number" +msgstr "Versionsnummer ausgeben" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Version aktualisieren" +msgid "Print verbose debug statements" +msgstr "Ausführliche Debug-Anweisungen ausgeben" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorität" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +msgid "Proceed with upload?" +msgstr "Mit dem Hochladen fortfahren?" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokoll" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Prüfsumme aktualisieren" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Abfrage der Unterstützung für Firmware-Aktualisierungen" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Ort aktualisieren" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Macken" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Beschreibung aktualisieren" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Firmware von Gerät in Datei schreiben" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Firmware von einzelner Partition in Datei lesen" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lesen …" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Metadaten von entferntem Server aktualisieren" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Bereich" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Erneute Installation von %s mit %s …" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Entfernt" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Daten in einer bestehenden Firmware-Datei ersetzen" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Bericht-URI" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Erfordert Internetverbindung" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "DFU-Gerät zurücksetzen" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Jetzt neu starten?" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Gerät wird neu gestartet …" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Alle Hardware-Kennungen für das System zurückgeben" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" +msgid "Runtime" +msgstr "Laufzeit" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Installation für den nächsten Neustart planen, falls möglich" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Gerät hinzugefügt:" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Einplanen …" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Gerät entfernt:" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Seriell" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Gerät geändert:" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Alternativen Namen einer Firmware-Datei festlegen" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Alternative Nummer einer Firmware-Datei festlegen" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Die Elementadresse in Firmware-Datei festlegen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Zusätzliche Informationen zur Fehlerdiagnose anzeigen" +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Produkt-Kennung einer Firmware-Datei festlegen" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Veröffentlichungsversion einer Firmware-Datei festlegen" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Firmware-Größe für das Ziel festlegen" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Hersteller-Kennung einer Firmware-Datei festlegen" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Metadaten einer Firmware-Datei festlegen" + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Firmware-Verlauf mit den Entwicklern teilen" #. TRANSLATORS: command line option -#: src/fu-util.c:2119 msgid "Show client and daemon versions" -msgstr "" +msgstr "Client- und Hintergrundprogramm-Versionen anzeigen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Debug Optionen anzeigen" #. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Erneute Installation vorhandener Firmware-Versionen erlauben" +msgid "Show devices that are not updatable" +msgstr "Nicht aktualisierbare Geräte anzeigen" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Einspielen niedrigerer Firmwareversionen zulassen (Downgrade)" +msgid "Show extra debugging information" +msgstr "Zusätzliche Informationen zur Fehlerdiagnose anzeigen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Verlauf von Firmware-Aktualisierungen anzeigen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Ausführliche Informationen zum Plugin anzeigen" #. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +msgid "Show the debug log from the last attempted update" +msgstr "Fehlerprotokoll der letzten versuchten Aktualisierung anzeigen" #. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +msgid "Show the information of firmware update status" +msgstr "Informationen über den Firmware-Aktualisierungsstatus anzeigen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +msgid "Specify the number of bytes per USB transfer" +msgstr "Geben Sie die Anzahl der Bytes pro USB-Übertragung an" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Alle Geräte ermitteln, die Firmware-Aktualisierungen unterstützen" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Zustand" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Vorbereitete Aktualisierungen jetzt installieren" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Zusammenfassung" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Target" +msgstr "Ziel" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "Der LVFS ist ein kostenloser Dienst, der als unabhängige juristische Person arbeitet und keine Verbindung zu $OS_RELEASE:NAME$ hat. Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft. Die gesamte Firmware wird nur vom Originalhersteller zur Verfügung gestellt." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Dieses Programm funktioniert möglicherweise nur als root korrekt" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Eine Firmware-Datei auf dieser Hardware installieren" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Übertragungsgröße" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Ermittelt Details über eine Firmware-Datei" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Typ" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Ermittelt die Liste der Aktualisierungen für angeschlossene Hardware" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI-Firmware-Dienstprogramm" -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Alle Firmware auf die neueste verfügbare Version aktualisieren" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Ermittelt den kryptographischen Hash-Wert der abgelegten Firmware" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Unbekannt" + +msgid "Unlock the device to allow access" +msgstr "Das Gerät entsperren, um Zugriff zu ermöglichen" #. TRANSLATORS: command description -#: src/fu-util.c:2232 msgid "Unlocks the device for firmware access" msgstr "Entsperrt das Gerät für Zugriff auf die Firmware" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Bereinigt die Ergebnisse der letzten Aktualisierung" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Prüfsumme aktualisieren" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Beschreibung aktualisieren" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Ermittelt die Ergebnisse der letzten Aktualisierung" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Ort aktualisieren" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Aktualisierungsname" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Aktualisierungszusammenfassung" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Version aktualisieren" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Metadaten von entferntem Server aktualisieren" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Der Aktualisierungsfehler ist ein bekanntes Problem, besuchen Sie diese URL für weitere Informationen:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Jetzt aktualisieren?" + +msgid "Update the stored device verification information" +msgstr "Gespeicherte Geräteverifizierungsinformationen aktualisieren" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "Gespeicherte Metadaten mit dem aktuellen ROM-Inhalt aktualisieren" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Den Daemon auf Ereignisse überwachen" +msgid "Updates all firmware to latest versions available" +msgstr "Alle Firmware auf die neueste verfügbare Version aktualisieren" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Aktualisieren von %s von %s nach %s …" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s wird aktualisiert …" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Nachricht beim Hochladen:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Bericht jetzt hochladen?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Das Hochladen von Firmware-Berichten hilft Hardwareherstellern, fehlerhafte und erfolgreiche Aktualisierungen auf realen Geräten schnell zu erkennen." + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Benutzername" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Überprüfung …" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Warten …" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" +msgid "Watch DFU devices being hotplugged" +msgstr "Geräteanschluss von DFU-Geräten überwachen" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" +msgid "Watch for hardware changes" +msgstr "Auf Hardware-Änderungen achten" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" +msgid "Write firmware from file into device" +msgstr "Firmware von Datei auf Gerät schreiben" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Firmware-Werkzeug" +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Firmware aus Datei in einzelne Partition schreiben" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Schreiben …" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Möglicherweise hat Ihr Lieferant eine der Firmware-Aktualisierungen nicht auf Kompatibilität mit Ihrem System oder angeschlossenen Geräten überprüft." diff -Nru fwupd-1.0.6/po/en_GB.po fwupd-1.2.10/po/en_GB.po --- fwupd-1.0.6/po/en_GB.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/en_GB.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Richard Hughes , 2015,2017-2018 +# Richard Hughes , 2015,2017-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: English (United Kingdom) (http://www.transifex.com/freedesktop/fwupd/language/en_GB/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,993 @@ "Language: en_GB\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Update device firmware on Linux" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minute remaining" +msgstr[1] "%.0f minutes remaining" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "This project aims to make updating firmware on Linux automatic, safe and reliable. You can either use a GUI software manager like GNOME Software to view and apply updates, the command-line tool or the D-Bus interface directly." +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s has firmware updates:" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "The fwupd process is a simple daemon to allow session software to update device firmware on your local machine. It is designed for desktops, but this project is also usable on phones, tablets and on headless servers." +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u day" +msgstr[1] "%u days" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Install signed system firmware" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hour" +msgstr[1] "%u hours" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Authentication is required to update the firmware on this machine" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minute" +msgstr[1] "%u minutes" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Install unsigned system firmware" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u second" +msgstr[1] "%u seconds" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Install old version of system firmware" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Added" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Authentication is required to downgrade the firmware on this machine" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Age" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Install signed device firmware" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Agree and enable the remote?" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Authentication is required to update the firmware on a removable device" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias to %s" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Install unsigned device firmware" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Allow downgrading firmware versions" + +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Allow re-installing existing firmware versions" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "An update requires a reboot to complete." + +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "An update requires the system to shutdown to complete." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Answer yes to all questions" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Apply a binary patch" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Apply firmware updates" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Attach DFU capable device back to runtime" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Attach to firmware mode" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attributes" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Authenticating…" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" +msgid "Authentication is required to downgrade the firmware on a removable device" msgstr "Authentication is required to downgrade the firmware on a removable device" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Unlock the device to allow access" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Authentication is required to downgrade the firmware on this machine" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Authentication is required to modify a configured remote used for firmware updates" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Authentication is required to unlock a device" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Update the stored device verification information" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Authentication is required to update the stored checksums for the device" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Modify a configured remote" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Authentication is required to update the firmware on a removable device" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Authentication is required to modify a configured remote used for firmware updates" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Authentication is required to update the firmware on this machine" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Alias to %s" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Authentication is required to update the stored checksums for the device" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Command not found" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Build firmware using a sandbox" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Added" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Cancel" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Removed" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Cancelled" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Changed" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Cancelled" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Checksum" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip ID" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Name" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Choose a device:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Choose a release:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Cipher" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Region" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Found" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protocol" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Status" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Clears any updates scheduled to be updated offline" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Permission denied" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Clears the results from the last update" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Serial" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Command not found" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Mode" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Convert firmware to DFU format" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Runtime" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Create a binary patch using two files" -#: plugins/dfu/dfu-tool.c:2115 msgid "DFU" msgstr "DFU" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "State" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU Utility" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Transfer Size" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Debugging Options" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Attributes" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Decompressing…" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Quirks" +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Decrypt firmware data" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "Chip ID" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Description" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Convert firmware to DFU format" +msgid "Detach currently attached DFU capable device" +msgstr "Detach currently attached DFU capable device" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Merge multiple firmware files into one" +msgid "Detach to bootloader mode" +msgstr "Detach to bootloader mode" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Set vendor ID on firmware file" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Device added:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Set product ID on firmware file" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Device changed:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Set element address on firmware file" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Device removed:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Set the firmware size for the target" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Devices that have been updated successfully:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Set release version on firmware file" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Devices that were not updated correctly:" + +msgid "Disabled fwupdate debugging" +msgstr "Disabled fwupdate debugging" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Set alternative number on firmware file" +msgid "Disables a given remote" +msgstr "Disables a given remote" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Set alternative name on firmware file" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Display version" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Attach DFU capable device back to runtime" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Do not check for old metadata" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Reset a DFU device" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Do not check for reboot after update" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Read firmware from device into a file" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Do not check for unreported history" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Read firmware from one partition into a file" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Do not write to the history database" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Write firmware from file into device" +#. success +msgid "Done!" +msgstr "Done!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Write firmware from file into one partition" +msgid "Downgrades the firmware on a device" +msgstr "Downgrades the firmware on a device" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "List currently attached DFU capable devices" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Downgrading %s from %s to %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Downgrading %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Downloading…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Detach currently attached DFU capable device" +msgid "Dump SMBIOS data from a file" +msgstr "Dump SMBIOS data from a file" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Dump details about a firmware file" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Watch DFU devices being hotplugged" +msgid "Dump information about a binary patch to the screen" +msgstr "Dump information about a binary patch to the screen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Encrypt firmware data" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "ESP specified was not valid" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Decrypt firmware data" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Enable firmware update support on supported systems" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Sets metadata on a firmware file" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Enable this remote?" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Replace data in an existing firmware file" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Enabled" + +msgid "Enabled fwupdate debugging" +msgstr "Enabled fwupdate debugging" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Create a binary patch using two files" +msgid "Enables a given remote" +msgstr "Enables a given remote" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Enabling this remote is done at your own risk." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Apply a binary patch" +msgid "Encrypt firmware data" +msgstr "Encrypt firmware data" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Dump information about a binary patch to the screen" +msgid "Erase all firmware update history" +msgstr "Erase all firmware update history" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Erasing…" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Exit after a small delay" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Exit after the engine has loaded" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Failed to download due to server limit" #. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 msgid "Failed to load quirks" msgstr "Failed to load quirks" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU Utility" - #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "Failed to parse arguments" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Enumerate all Synaptics MST devices" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Flash firmware file to MST device" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics Multistream Transport Utility" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Fetching file" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Installing firmware update…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Fetching firmware" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Show debugging information for all files" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Fetching metadata" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Show plugin verbose information" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Fetching signature" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Debugging Options" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Filename" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Show debugging options" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Filename Signature" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Exit after a small delay" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Firmware Base URI" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Exit after the engine has loaded" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Firmware Update D-Bus Service" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" msgstr "Firmware Update Daemon" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Firmware Update D-Bus Service" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmware Utility" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Idle…" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Firmware metadata has not been updated for %u day and may not be up to date." +msgstr[1] "Firmware metadata has not been updated for %u days and may not be up to date." -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Decompressing…" +msgid "Firmware updates are not supported on this machine." +msgstr "Firmware updates are not supported on this machine." -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Loading…" +msgid "Firmware updates are supported on this machine." +msgstr "Firmware updates are supported on this machine." -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Restarting device…" +msgid "Force the action ignoring all warnings" +msgstr "Force the action ignoring all warnings" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Reading…" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Found" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Writing…" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Erasing…" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Get all devices according to the system topology" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Verifying…" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Get all devices that support firmware updates" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Scheduling…" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Get all enabled plugins registered with the system" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Downloading…" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Gets details about a firmware file" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Authenticating…" +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Gets the configured remotes" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Waiting…" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Gets the cryptographic hash of the dumped firmware" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Unknown" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Gets the list of updates for connected hardware" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Gets the releases for a device" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Choose a device:" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Gets the results from the last update" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Devices that were not updated correctly:" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Idle…" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Devices that have been updated successfully:" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Install a firmware blob on a device" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Upload report now?" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Install a firmware file on this hardware" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Requires internet connection" +msgid "Install old version of system firmware" +msgstr "Install old version of system firmware" + +msgid "Install signed device firmware" +msgstr "Install signed device firmware" + +msgid "Install signed system firmware" +msgstr "Install signed system firmware" + +msgid "Install unsigned device firmware" +msgstr "Install unsigned device firmware" + +msgid "Install unsigned system firmware" +msgstr "Install unsigned system firmware" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Installing firmware update…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Installing on %s…" +msgid "Keyring" +msgstr "Keyring" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Less than one minute remaining" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stable firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (testing firmware)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "List currently attached DFU capable devices" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "List supported firmware updates" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Loading…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Manually whitelist specific plugins" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Merge multiple firmware files into one" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadata URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadata URI Signature" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadata can be obtained from the Linux Vendor Firmware Service." + +msgid "Mode" +msgstr "Mode" + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modifies a given remote" + +msgid "Modify a configured remote" +msgstr "Modify a configured remote" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitor the daemon for events" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Name" + +msgid "No action specified!" +msgstr "No action specified!" + +#. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 msgid "No hardware detected with firmware update capability" msgstr "No hardware detected with firmware update capability" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Reinstalling %s with %s... " +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "No plugins found" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "No remotes are currently enabled so no metadata is available." -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Downgrading %s from %s to %s... " +msgid "OK" +msgstr "OK" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Updating %s from %s to %s... " +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Override plugin warning" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Done!" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Override the default ESP path" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Target" +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Password" -#: src/fu-util.c:727 msgid "Payload" msgstr "Payload" -#: src/fu-util.c:728 +msgid "Permission denied" +msgstr "Permission denied" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Please enter a number from 0 to %u: " + +msgid "Print the version number" +msgstr "Print the version number" + +msgid "Print verbose debug statements" +msgstr "Print verbose debug statements" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priority" + msgid "Proceed with upload?" msgstr "Proceed with upload?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protocol" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Query for firmware update support" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "OK" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Quirks" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Fetching signature" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Read firmware from device into a file" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Fetching metadata" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Read firmware from one partition into a file" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Fetching firmware" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Reading…" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Fetching file" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Refresh metadata from remote server" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Version" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Region" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Summary" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Reinstalling %s with %s... " #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Remote" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Remote ID" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Description" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Removed" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Checksum" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Replace data in an existing firmware file" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Choose a release:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Report URI" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Requires internet connection" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Update now?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Reset a DFU device" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s has firmware updates:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Restart now?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Restarting device…" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Update Version" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Return all the hardware IDs for the machine" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Update Name" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Run the plugin composite cleanup routine when using install-blob" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Update Summary" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Run the plugin composite prepare routine when using install-blob" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Update Remote ID" +msgid "Runtime" +msgstr "Runtime" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Update Checksum" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Schedule installation for next reboot when possible" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Update Location" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Scheduling…" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Update Description" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serial" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Remote ID" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Set alternative name on firmware file" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Title" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Set alternative number on firmware file" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Set element address on firmware file" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Set product ID on firmware file" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Set release version on firmware file" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Set the debugging flag during update" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Set the firmware size for the target" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Set vendor ID on firmware file" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Sets metadata on a firmware file" + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Share firmware history with the developers" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Show client and daemon versions" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Show debugging options" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Type" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Show devices that are not updatable" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Keyring" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Show extra debugging information" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Enabled" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Show history of firmware updates" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Age" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Show plugin verbose information" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Priority" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Show the debug log from the last attempted update" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Username" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Show the information of firmware update status" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Password" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Shutdown now?" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Filename" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Specify Vendor/Product ID(s) of DFU device" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Filename Signature" +msgid "Specify the number of bytes per USB transfer" +msgstr "Specify the number of bytes per USB transfer" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "Metadata URI" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "State" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Metadata URI Signature" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Firmware Base URI" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Summary" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "Report URI" +msgid "Target" +msgstr "Target" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Device added:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "This program may only work correctly as root" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Device removed:" +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Device changed:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Title" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Transfer Size" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Type" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Show extra debugging information" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI Firmware Utility" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Show client and daemon versions" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Schedule installation for next reboot when possible" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Unknown" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Allow re-installing existing firmware versions" +msgid "Unlock the device to allow access" +msgstr "Unlock the device to allow access" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Allow downgrading firmware versions" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Unlocks the device for firmware access" #. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Override plugin warning" +msgid "Unset the debugging flag during update" +msgstr "Unset the debugging flag during update" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Answer yes to all questions" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Update Checksum" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Do not check for unreported history" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Update Description" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Do not check for old metadata" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Update Duration" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Update Location" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Get all devices that support firmware updates" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Update Name" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Return all the hardware IDs for the machine" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Update Remote ID" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Install prepared updates now" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Update Summary" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Show history of firmware updates" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Update Version" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Erase all firmware update history" +msgid "Update all devices that match local metadata" +msgstr "Update all devices that match local metadata" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Share firmware history with the developers" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Update failure is a known issue, visit this URL for more information:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Install a firmware file on this hardware" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Update now?" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Gets details about a firmware file" +msgid "Update the stored device verification information" +msgstr "Update the stored device verification information" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Gets the list of updates for connected hardware" +msgid "Update the stored metadata with current ROM contents" +msgstr "Update the stored metadata with current ROM contents" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Updates all firmware to latest versions available" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Gets the cryptographic hash of the dumped firmware" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Updating %s from %s to %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Unlocks the device for firmware access" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Updating %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Clears the results from the last update" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Upload message:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Clears any updates scheduled to be updated offline" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Upload report now?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Gets the results from the last update" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Gets the releases for a device" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Username" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Gets the configured remotes" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifying…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Downgrades the firmware on a device" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Version" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Refresh metadata from remote server" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Waiting…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Update the stored metadata with current ROM contents" +msgid "Watch DFU devices being hotplugged" +msgstr "Watch DFU devices being hotplugged" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Monitor the daemon for events" +msgid "Watch for hardware changes" +msgstr "Watch for hardware changes" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Build firmware using a sandbox" +msgid "Write firmware from file into device" +msgstr "Write firmware from file into device" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Dump SMBIOS data from a file" +msgid "Write firmware from file into one partition" +msgstr "Write firmware from file into one partition" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Modifies a given remote" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Writing…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Firmware Utility" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." diff -Nru fwupd-1.0.6/po/eo.po fwupd-1.2.10/po/eo.po --- fwupd-1.0.6/po/eo.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/eo.po 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,95 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# kristjan , 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Esperanto (http://www.transifex.com/freedesktop/fwupd/language/eo/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: eo\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekundo" +msgstr[1] "%u sekundoj" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Aldonita" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Nuligi" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Nuligita" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Ŝanĝita" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Elektu aparaton:" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Priskribo" + +#. success +msgid "Done!" +msgstr "Farita!" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Trovita" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +msgid "Mode" +msgstr "Reĝimo" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nomo" + +msgid "OK" +msgstr "Bone" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokolo" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Regiono" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Forigita" + +msgid "Target" +msgstr "Celo" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Nekonata" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versio" diff -Nru fwupd-1.0.6/po/eu.po fwupd-1.2.10/po/eu.po --- fwupd-1.0.6/po/eu.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/eu.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # assar , 2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Basque (http://www.transifex.com/freedesktop/fwupd/language/eu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,47 @@ "Language: eu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "" - -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Ez da komandoa aurkitu" - #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 msgid "Added" msgstr "Gehitua" #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Kendua" - -#. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Aldatua" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Ez da komandoa aurkitu" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Aurkitua" #. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 msgid "ID" msgstr "IDa" #. TRANSLATORS: interface name, e.g. "Flash" #. TRANSLATORS: device name, e.g. 'ColorHug2' #. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 msgid "Name" msgstr "Izena" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokoloa" #. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 msgid "Region" msgstr "Eskualdea" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Aurkitua" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokoloa" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Kendua" #. TRANSLATORS: probably not run as root... #. TRANSLATORS: device has failed to report status #. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 msgid "Status" msgstr "Egoera" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" - -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "" - -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" - -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "" - -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" - -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "" - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" diff -Nru fwupd-1.0.6/po/fi.po fwupd-1.2.10/po/fi.po --- fwupd-1.0.6/po/fi.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/fi.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Jiri Grönroos , 2017-2018 +# Kimmo Kujansuu , 2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Finnish (http://www.transifex.com/freedesktop/fwupd/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +16,1213 @@ "Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Päivitä laitteiden firmware-laiteohjelmistoja Linuxilla" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuuttia jäljellä" +msgstr[1] "%.0f minuuttia jäljellä" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "%sKuluttajan ME-päivitys" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "%sOhjaimen päivitys" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Tämän laitteen firmwaren päivittäminen vaatii tunnistautumisen" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "%sYrityksen ME-päivitys" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "%sLaitteen päivitys" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "%sSulautetun ohjaimen päivitys" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "%sME päivitys" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "%sJärjestelmän päivitys" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Erillisen laitteen firmwaren päivittäminen vaatii tunnistautumisen" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "%sPäivitys" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s on laiteohjelmistopäivityksiä:" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%upäivää" +msgstr[1] "%upäivää" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u tuntia" +msgstr[1] "%utuntia" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Laitteen lukituksen avaaminen vaatii tunnistautumisen" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuuttia" +msgstr[1] "%u minuuttia" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u " +msgstr[1] "%u sekunttia" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktivoi laitteet" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktivoi odottavat laitteet" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" +msgid "Activate the new firmware on the device" +msgstr "Aktivoi laitteessa oleva uusi laiteohjelmisto 'firmware'" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Firmware-päivityksen aktivointi" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Komentoa ei löytynyt" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Käynnistä laiteohjelmiston päivitys" #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 msgid "Added" msgstr "Lisätty" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Poistettu" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Ikä" -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Muutettu" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Hyväksy ja ota etäyhteys käyttöön?" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Peruttu" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Peitenimi %s" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Salli firmware-versioiden alentaminen" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nimi" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Salli laiteohjelmiston versioiden asentaminen uudelleen" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Päivitys vaatii uudelleenkäynnistyksen." -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Päivitys edellyttää järjestelmän sammuttamista." -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Vastaa kaikkiin kysymyksiin kyllä" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Käytä binääristä korjaustiedostoa" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Käytä firmware-päivityksiä" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Hyväksytty laiteohjelmisto:" +msgstr[1] "Hyväksytty laiteohjelmisto:" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Kiinnitä DFU-kykyinen laite takaisin ajoon" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Kiinnitä laiteohjelmistotilaan" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Määritteet" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Tunnistaudutaan…" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Todennus on tarpeen, jotta firmware voidaan alentaa siirrettävällä laitteelta" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Todennus on tarpeen tämän laitteen firmwaren alentamiseksi" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Todennusta tarvitaan firmware-päivityksiin käytettävän konfiguroidun etä-ohjaimen muokkaamisessa" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Todennusta tarvitaan taustaprosessin asetusten muokkaamiseen" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Vahvistus on tarpeen hyväksyttyjen laiteohjelmien listan määrittämiseksi" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Autentikointi edellyttää tietojen allekirjoittamista asiakaan sertifikaatin avulla" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Uuden firmware-version käyttöönottoon tarvitaan todennus" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Laitteen lukituksen avaaminen vaatii tunnistautumisen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Erillisen laitteen firmwaren päivittäminen vaatii tunnistautumisen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Tämän laitteen firmwaren päivittäminen vaatii tunnistautumisen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Todennus edellyttää laitteen tallennettujen tarkistussummien päivittämistä" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" +msgid "Build firmware using a sandbox" +msgstr "Rakenna laiteohjelmisto hiekkalaatikon avulla" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Peru" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Peruttu" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Muutettu" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Tarkistussumma" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chip-tunnus" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Valitse laite:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Valitse julkaisu:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Salaus" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Tyhjentää päivitykset, jotka on tarkoitus päivittää offline-tilassa" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" +msgid "Clears the results from the last update" +msgstr "Tyhjennä viimeisimmän päivityksen tulokset" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Komentoa ei löytynyt" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" +msgid "Convert firmware to DFU format" +msgstr "Muunna firmware DFU-muotoon" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" +msgid "Create a binary patch using two files" +msgstr "Luo binäärinen korjaustiedosto käyttäen kahta tiedostoa" + +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU-apuohjelma" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Vianjäljitysvalinnat" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Puretaan…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 msgid "Decrypt firmware data" -msgstr "" +msgstr "Pura firmwaren data" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Kuvaus" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" +msgid "Detach currently attached DFU capable device" +msgstr "Irrota tällä hetkellä liitetty DFU-laite" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" +msgid "Detach to bootloader mode" +msgstr "Irrota käynnistyslataimen tilaan" + +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Laitteen tunnus" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Laite lisätty:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Laite muutettu:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Laite poistettu:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Laitteet, jotka on päivitetty onnistuneesti:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Laitteet, joita ei päivitetty oikein:" + +msgid "Disabled fwupdate debugging" +msgstr "fw-päivityksen virheenkorjaus poistettu" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" +msgid "Disables a given remote" +msgstr "Poista annettu etäyhteys" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Näytä versio" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Älä tarkista vanhoja metatietoja" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Älä tarkista käynnistystä uudelleen päivityksen jälkeen" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Älä tarkista ilmoittamattomasta historiasta" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Älä kirjoita historiatietokantaan" + +#. success +msgid "Done!" +msgstr "Valmis!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" +msgid "Downgrades the firmware on a device" +msgstr "Alentaa laitteen laiteohjelmistoa" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Alenee %s -sta %s tulos %s... " -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Alentaa %s…" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Ladataan…" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" +msgid "Dump SMBIOS data from a file" +msgstr "Pura SMBIOS-tiedot tiedostosta" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" +msgid "Dump details about a firmware file" +msgstr "Tyhjennä laiteohjelmiston tiedot" -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Tulosta tiedot binäärisestä korjaustiedostosta näytölle" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Asennetaan firmware-päivitystä…" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Määritetty ESP ei ollut voimassa" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Ota firmware-päivitystuki käyttöön tuetuissa järjestelmissä" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Ota etäyhteys käyttöön?" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Vianjäljitysvalinnat" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Käytössä" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Näytä vianjäljitysvalinnat" +msgid "Enabled fwupdate debugging" +msgstr "fw-päivityksen virheenkorjaus käytössä" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Ota käyttöön annettu etäyhteys" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Tämän toiminnon käyttöönotto tapahtuu omalla vastuullasi, joten sinun on otettava yhteyttä alkuperäiseen laitevalmistajaan näiden päivitysten aiheuttamista ongelmista. Vain päivitysprosessiin liittyvät ongelmat pitäisi jättää osoitteeseen $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Tämän etä-ohjaimen käyttöönotto tapahtuu omalla vastuullasi." + +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Salaa firmwaren data" + +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Poista kaikki laiteohjelmiston päivityshistoria" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Poistetaan…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Poistu pienen viiveen jälkeen" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" -msgstr "" +msgstr "Poistu kun moottori on ladattu" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Yhteys taustaprosessiin epäonnistui" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Lataaminen epäonnistui palvelimen rajoituksen vuoksi" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Vireillä olevien laitteiden saaminen epäonnistui" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Laiteohjelmiston firmware päivityksen asennus epäonnistui" + +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Quirksin lataaminen epäonnistui" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Argumenttien jäsentäminen epäonnistui" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Käynnistys epäonnistui" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Splash-tilan asettaminen epäonnistui" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Noudetaan tiedosto" + +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Noudetaan firmware" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Noudetaan metatietoja" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Noudetaan allekirjoitus" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Tiedostonimi" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Tiedoston allekirjoitus" #. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" +msgid "Firmware Agent" +msgstr "Firmware-agentti" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Firmware pohja URI" #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" -msgstr "" +msgstr "Laiteohjelmiston päivitys D-Bus-palveluun" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Firmware-päivityksen taustaprosessi" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmware-työkalu" + +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Laiteohjelmiston metatietoja ei ole päivitetty %upäivään ja ne eivät välttämättä ole ajan tasalla." +msgstr[1] "Laiteohjelmiston metatietoja ei ole päivitetty %upäivään ja ne eivät välttämättä ole ajan tasalla." + +msgid "Firmware updates are not supported on this machine." +msgstr "Ohjelmistopäivitys 'firmware' ei tue tätä laitetta" + +msgid "Firmware updates are supported on this machine." +msgstr "Ohjelmistopäivitys 'firmware' tukee tätä laitetta" + +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Liput" + +msgid "Force the action ignoring all warnings" +msgstr "Pakota toimenpide huomioimatta kaikki varoitukset" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Löydetty" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Hae kaikki laitteet järjestelmän topologian mukaisesti" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Hanki kaikki laitteet ja mahdolliset julkaisut" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Hae kaikki laiteohjelmistopäivityksiä tukevat laitteet" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Hanki kaikki järjestelmään rekisteröidyt laajennukset" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Hae tietoja firmware-tiedostosta" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Määrittää konfiguroidut etäyhteydet" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Hae salakirjoituksen kohteena oleva laiteohjelmisto." + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Hae hyväksytty laiteohjelmiston luettelo." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Antaa luettelon liitettyjen laitteiden päivityksistä" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Antaa laitteen julkaisut" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Saat viimeisimmän päivityksen tulokset" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Henkilöllisyys" #. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 msgid "Idle…" msgstr "Jouten…" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Puretaan…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Asenna laiteohjelmiston merkintä laitteeseen" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Asenna laiteohjelmisto tähän laitteistoon" + +msgid "Install old version of system firmware" +msgstr "Asenna vanha firmware versio" + +msgid "Install signed device firmware" +msgstr "Asenna allekirjoitettu laitteen firmware" + +msgid "Install signed system firmware" +msgstr "Asenna allekirjoitettu järjestelmän firmware" + +msgid "Install unsigned device firmware" +msgstr "Asenna allekirjoittamattoman laitteen firmware" + +msgid "Install unsigned system firmware" +msgstr "Asenna allekirjoittamaton järjestelmän firmware" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Asentaa firmwarea…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Asennetaan firmware-päivitystä…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Asentaa %s…" + +msgid "Keyring" +msgstr "Avaimet" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Jäljellä on alle minuutti" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux-toimittajan laiteohjelmisto (vakaa firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux-toimittajan laiteohjelmisto (firmware testaus)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Luettelo tällä hetkellä liitetyistä DFU-laitteista" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Lista tuetuista firmware-päivityksistä" #. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 msgid "Loading…" msgstr "Ladataan…" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Käynnistetään laite uudelleen…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Luetteloi tiettyjä lisäosia manuaalisesti" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Luetaan…" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Yhdistä useita firmware-tiedostoja yhteen" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Kirjoitetaan…" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metatietojen URI" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Poistetaan…" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metatietojen URI-allekirjoitus" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Vahvistetaan…" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metatiedot voidaan hankkia Linux Vendor Firmware -palvelusta." -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Ajoitetaan…" +#. TRANSLATORS: error message +#, c-format +msgid "Mismatched daemon and client, use %s instead" +msgstr "Virheellinen taustaprosessi ja asiakas, käytä sen sijaan %s" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Ladataan…" +msgid "Mode" +msgstr "Malli" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Tunnistaudutaan…" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Muuta taustaprosessin määritysarvoja." -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Odotetaan…" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Muuta annettua etäyhteyttä" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Tuntematon" +msgid "Modify a configured remote" +msgstr "Muokkaa määritettyä etänä" + +msgid "Modify daemon configuration" +msgstr "Muokkaa taustaprosessin kokoonpanoa" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Seuraa tapahtumien taustaprosessia" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nimi" + +msgid "No action specified!" +msgstr "Toimintoa ei ole määritetty!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Ei havaittu sopivaa laitteistoa firmware päivitykselle" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Ei laajennuksia" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Mitään etäyhteyksiä ei ole tällä hetkellä käytössä, joten metatietoja ei ole saatavilla." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Ei soveltuvia päivityksiä" + +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Ohita plugin-varoitus" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Ohita oletusarvoinen ESP-polku" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Ohita varoitukset ja pakota toiminto" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Salasana" + +msgid "Payload" +msgstr "Tietosisältö" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Prosenttiosuus valmis" + +msgid "Permission denied" +msgstr "Lupa kielletty" #. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 #, c-format msgid "Please enter a number from 0 to %u: " -msgstr "" +msgstr "Anna numero 0 -%u" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Valitse laite:" +msgid "Print the version number" +msgstr "Tulosta versionumero" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Print verbose debug statements" +msgstr "Tulosta virheelliset virheilmoitukset" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioriteetti" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +msgid "Proceed with upload?" +msgstr "Jatka lähettämistä?" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokolla" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Kysely firmware-päivityksen tuesta" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Merkintä" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Lue firmware laitteesta tiedostoon" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Lue firmware osiolta tiedostoon" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Luetaan…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Käynnistää..." + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Päivitä etäpalvelimen metatiedot" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Alue" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" -#: src/fu-util.c:651 #, c-format msgid "Reinstalling %s with %s... " -msgstr "" +msgstr "Uudelleenasennus %s kera %s... " -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "" +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Etä" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Etätunnus" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Valmis!" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Poistettu" -#: src/fu-util.c:726 -msgid "Target" -msgstr "" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Vaihda tiedot olemassa olevaan firmware-tiedostoon" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Ilmoita URI" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Vaatii Internet-yhteyden" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Nollaa DFU-laite" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Käynnistä nyt?" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "OK" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Käynnistä taustaprosessi uudelleen, jotta muutos tulee voimaan" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Noudetaan allekirjoitus" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Käynnistetään laite uudelleen…" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Noudetaan metatietoja" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Palauta kaikki laitteen laitteistotunnukset" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Noudetaan firmware" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Suorita plugin-puhdistustoiminto, kun käytät asennus-blobia" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Noudetaan tiedosto" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Asennus-blobia ajamalla käytät yhdistelmän valmiita laajennus rutiineja " -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Versio" +msgid "Runtime" +msgstr "Käyttöaika" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Tallenna laitteen tila JSON-tiedostoon suoritusten välillä" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Ajasta asennus uudelleenkäynnistykselle mahdollisuuksien mukaan" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Ajoitetaan…" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Kuvaus" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Sarjanumero" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Tarkistussumma" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Aseta vaihtoehtoinen nimi firmware-tiedostolle" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Valitse julkaisu:" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Aseta vaihtoehtoinen numero firmware-tiedostolle" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Aseta elementin osoite firmware tiedostoon" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Aseta tuotetunnus firmware tiedostoon" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Aseta julkaisuversio firmware-tiedostosta" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Aseta virheenkorjauksen lippu päivityksen aikana" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Määritä firmwaren kohteen koko" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Aseta toimittajan tunnus firmware tiedostoon" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Asetta metatiedot firmware -tiedostoon" + +msgid "Sets the list of approved firmware" +msgstr "Asettaa listan hyväksytyjä 'firmware' laiteohjelmistoja " + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Asettaa hyväksytyn laiteohjelmiston luettelon." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Jaa laiteohjelmiston historia kehittäjien kanssa" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Näytä asiakas- ja taustaprosessin versiot" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Näytä taustaprosessin täydelliset tiedot tietylle verkkotunnukselle" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Näytä kaikkien verkkotunnusten virheenkorjaustiedot" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Näytä vianjäljitysvalinnat" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Näytä laitteet, joita ei voi päivittää" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Näytä ylimääräiset virheenkorjaustiedot" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Näytä laiteohjelmiston päivitysten historia" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Tyyppi" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Näytä plugin tiedot" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Näytä virheenkorjausloki viimeisestä päivitysyrityksestä" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Näytä tiedot laiteohjelmiston 'firmware' päivitystilasta" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Sammuta nyt?" + +msgid "Sign data using the client certificate" +msgstr "Allekirjoita tietoja käyttämällä asiakkaan sertifikaattia" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Allekirjoita tietoja käyttämällä asiakkaan sertifikaattia" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Kirjoita ladatut tiedot asiakaan sertifikaatilla" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Käyttäjätunnus" +msgid "Signature" +msgstr "Allekirjoitus" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Salasana" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Määritä DFU laitteen toimittaja/tuotetunnus(s)" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Tiedostonimi" +msgid "Specify the number of bytes per USB transfer" +msgstr "Määritä tavujen määrä USB-siirtoa kohti" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Osavaltio" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Tila" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Yhteenveto" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" +msgid "Target" +msgstr "Kohde" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS on ilmainen palvelu, joka toimii itsenäisenä oikeushenkilönä eikä sillä ole yhteyttä $OS_RELEASE:NAME$. Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa. Kaikki laiteohjelmistot on tarkoitettu vain alkuperäisen laitteen valmistajalle." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Hyväksyttyä laiteohjelmistoa ei ole." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Tämä ohjelma voi toimia vain juuressa 'root'" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Tämä sisältää firmwaren, jota ei ole vientikiellossa, mutta jota laitteistotoimittaja testaa edelleen. Varmista, että voit päivittää firmwaren manuaalisesti, jos päivitys epäonnistuu." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Tätä työkalua voi käyttää vain root-käyttäjä" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Laite lisätty:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Otsikko" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Laite poistettu:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Siirron koko" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Laite muutettu:" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tyyppi" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI firmware -apuohjelma" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Tuntematon" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" +msgid "Unlock the device to allow access" +msgstr "Sallia pääsy laitteeseen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Avaa pääsy laitteen laiteohjelmistoon" #. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" +msgid "Unset the debugging flag during update" +msgstr "Poista virheenkorjauksen lippu päivityksen aikana" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Ei tuettu taustaprosessin versio %s, asiakasversio on %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Päivitä tarkistussumma" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Päivitä kuvaus" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Päivitä kesto" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Päivitä sijainti" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Päivitä nimi" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Päivitä etätunnus" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Päivitä yhteenveto" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Päivitä versio" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Update all devices that match local metadata" +msgstr "Päivitä kaikki paikallisia metatietoja vastaavat laitteet" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Päivityksen epäonnistuminen on tunnettu ongelma. Saat lisätietoja tästä URL-osoitteesta:" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Päivitä nyt?" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "" +msgid "Update the stored device verification information" +msgstr "Päivitä laitteen tallennetut vahvistustiedot" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "" +msgid "Update the stored metadata with current ROM contents" +msgstr "Päivitä tallennetut metatiedot nykyisen ROM-sisällön kanssa" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" +msgid "Update the stored metadata with current contents" +msgstr "Päivitä tallennetut metatiedot nykyiseen sisältöön" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" -msgstr "" +msgstr "Päivittää kaikki laiteohjaimet uusimpiin saatavilla oleviin versioihin" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Korotus %s -sta %s tulos %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Päivittää %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Lähetä viesti:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Lataa raportti nyt?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Firmware-raporttien lataaminen auttaa laitteistotoimittajia tunnistamaan nopeasti virheelliset ja onnistuneet päivitykset todellisissa laitteissa." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Käyttäjätunnus" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Vahvistetaan…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versio" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Odotetaan…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" +msgid "Watch DFU devices being hotplugged" +msgstr "Katso, että DFU-laitteet on kytketty" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" +msgid "Watch for hardware changes" +msgstr "Katso laitteiston muutoksia" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" +msgid "Write firmware from file into device" +msgstr "Kirjoita firmware tiedostosta laitteeseen" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" +msgid "Write firmware from file into one partition" +msgstr "Kirjoita firmware tiedostosta osioon" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Kirjoitetaan…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Firmware-työkalu" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Jakelijasi ei ehkä ole tarkistanut mitään laiteohjelmistopäivityksiä, jotka ovat yhteensopivia järjestelmän tai liitettyjen laitteiden kanssa." diff -Nru fwupd-1.0.6/po/fr.po fwupd-1.2.10/po/fr.po --- fwupd-1.0.6/po/fr.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/fr.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Franck , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: French (http://www.transifex.com/freedesktop/fwupd/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,81 @@ "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Une authentification est nécessaire pour mettre à jour le micrologiciel sur cette machine" - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Alias de %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "" - -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "" - -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "" - -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" - -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Echec de l'analyse des paramètres" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Montrer les informations de débogage pour tous les fichiers" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Une authentification est nécessaire pour mettre à jour le micrologiciel sur cette machine" #. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 msgid "Debugging Options" msgstr "Options de débogage" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Montrer les options de débogage" +#. success +msgid "Done!" +msgstr "Terminé !" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Rétrogradation de %s de %s en %s" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Quitter après un bref délai" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Quitter après le chargement du moteur" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Echec de l'analyse des paramètres" #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" msgstr "Service D-Bus de mise à jour des micrologiciels" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Obtenir la liste des périphériques supportant les mises à jour de micrologiciel" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Obtenir les détails d'un fichier de micrologiciel" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Installer un fichier de micrologiciel sur ce matériel" +#. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 msgid "No hardware detected with firmware update capability" msgstr "Aucun matériel ayant des capacités de mise à jour du micrologiciel n'a été détecté" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" -#: src/fu-util.c:651 #, c-format msgid "Reinstalling %s with %s... " msgstr "Réinstallation de %s en %s" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Rétrogradation de %s de %s en %s" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Montrer les options de débogage" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Montre des informations de débogage complémentaires" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 #, c-format msgid "Updating %s from %s to %s... " msgstr "Mise à jour de %s de %s en %s" - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Terminé !" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Montre des informations de débogage complémentaires" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Obtenir la liste des périphériques supportant les mises à jour de micrologiciel" - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Installer immédiatement les mises à jour préparées" - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Installer un fichier de micrologiciel sur ce matériel" - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Obtenir les détails d'un fichier de micrologiciel" - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" diff -Nru fwupd-1.0.6/po/fur.po fwupd-1.2.10/po/fur.po --- fwupd-1.0.6/po/fur.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/fur.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Fabio Tomat , 2017-2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Friulian (http://www.transifex.com/freedesktop/fwupd/language/fur/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,644 @@ "Language: fur\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Inzorne il firmware dal dispositîf su Linux" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s al à inzornaments dal firmware:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Zontât" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Etât" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Instale firmware di sisteme firmât" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias a %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "La autenticazion e je necessarie par inzornâ il firmware su cheste machine" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Permet di tornâ indaûr aes versions di firmware precedentis" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Instale firmware di sisteme cence firme" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Permet di tornâ a instalâ lis versions dai firmware esistentis" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Instale une version vecje dal firmware di sisteme" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Un inzornament al à bisugne che si torni a inviâ il computer par finî." -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Rispuint di sì a dutis lis domandis" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Instasle firmware di dispositîf firmât" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Apliche une patch binarie" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "La autenticazion e je necessarie par inzornâ il firmware suntun dispositîf estraibil" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Atribûts" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Instale firmware di dispositîf cence firme" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Daûr a autenticâ…" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "La autenticazion e je necessarie par tornâ indaûr ae version precedente dal firmware suntun dispositîf estraibil " -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Sbloche il dispositîf par permeti l'acès" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "La autenticazion e je necessarie par tornâ indaûr ae version precedente dal firmware su cheste machine" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "La autenticazion e je necessarie par modificâ un rimot configurât, doprât pai inzornaments dal firmware" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "La autenticazion e je necessarie par sblocâ un dispositîf" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Inzorne lis informazions di verifiche dal dispositîf archiviadis" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "La autenticazion e je necessarie par inzornâ i checksum archiviâts pal dispositîf" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "La autenticazion e je necessarie par inzornâ il firmware suntun dispositîf estraibil" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" +msgid "Authentication is required to update the firmware on this machine" +msgstr "La autenticazion e je necessarie par inzornâ il firmware su cheste machine" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Alias a %s" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "La autenticazion e je necessarie par inzornâ i checksum archiviâts pal dispositîf" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Comant no cjatât" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Costruìs il firmware doprant une ambient isolât - sandbox" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Zontât" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Anule" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Gjavât" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Anulât" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Modificât" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Checksum" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID chip" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Non" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Sielç un dispositîf:" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Sielç une publicazion:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Regjon" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Al nete ducj i inzornaments programâts di fâ fûr rêt" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Cjatât" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Al nete i risultâts dal ultin inzornament" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protocol" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Comant no cjatât" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Stât" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Convertìs il firmware tal formât DFU" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Permès dineât" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Cree une patch binarie doprant doi file" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Seriâl" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opzions di debug" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Modalitât" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Daûr a decomprimi…" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Decifre i dâts dal firmware" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Descrizion" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Stât" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Dispositîf zontât:" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Dispositîf modificât:" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Atribûts" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Dispositîf gjavât:" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Dispositîfs che a son stâts inzornâts cun sucès:" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ID chip" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Dispositîfs che no son stâts inzornâts ben:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" +#. success +msgid "Done!" +msgstr "Fat!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" +msgid "Downgrades the firmware on a device" +msgstr "Al torne indaûr ae version precedente dal firmware suntun dispositîf" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Daûr a tornâ indaûr ae version precedente di %s de %s ae %s... " -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Daûr a discjariâ…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" +msgid "Dump SMBIOS data from a file" +msgstr "Scrîf jù i dâts SMBIOS di un file" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" +msgid "Dump details about a firmware file" +msgstr "Scrîf jù i detais in merit a un file firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" +msgid "Dump information about a binary patch to the screen" +msgstr "Scrîf jù lis informazions sul schermi in merit a une patch binarie " -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Abilitât" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" +msgid "Encrypt firmware data" +msgstr "Cifre i dâts dal firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" +msgid "Erase all firmware update history" +msgstr "Scancele dute la cronologjie dai inzornaments dal firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Daûr a scancelâ…" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Jes dopo un piçul ritart" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Jes dopo che il motôr al à cjariât" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "No si è rivâts a analizâ i argoments" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Non file" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Firme non file" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "URI de base dal firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Servizi D-Bus inzornament firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Demoni di inzornament firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Utilitât firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "I metadâts dal firmware no son stâts inzornâts par %u zornade e a podaressin jessi vielis." +msgstr[1] "I metadâts dal firmware no son stâts inzornâts par %u dîs e a podaressin jessi vielis." -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Cjatât" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" +msgid "GUID" +msgstr "GUID" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" +msgid "Get all devices that support firmware updates" +msgstr "Oten ducj i dispositîfs che a supuartin i inzornaments dal firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" +msgid "Gets details about a firmware file" +msgstr "Al oten detais su un file di firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "" +msgid "Gets the configured remotes" +msgstr "Al oten i rimots configurâts" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Al oten il hash di critografie dal firmware tirât jù" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opzions di debug" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Mostre opzions di debug" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Jes dopo un piçul ritart" +msgid "Gets the list of updates for connected hardware" +msgstr "Al oten la liste di inzornaments pal hardware tacât" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Al oten lis publicazions par un dispositîf" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Demoni di inzornament firmware" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Al oten i risultâts dal ultin inzornament" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Servizi D-Bus inzornament firmware" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" #. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 msgid "Idle…" -msgstr "" +msgstr "In polse…" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instale un file firmware su chest hardware" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" +msgid "Install old version of system firmware" +msgstr "Instale une version vecje dal firmware di sisteme" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" +msgid "Install signed device firmware" +msgstr "Instasle firmware di dispositîf firmât" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" +msgid "Install signed system firmware" +msgstr "Instale firmware di sisteme firmât" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" +msgid "Install unsigned device firmware" +msgstr "Instale firmware di dispositîf cence firme" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" +msgid "Install unsigned system firmware" +msgstr "Instale firmware di sisteme cence firme" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Daûr a instalâ l'inzornament dal firmware…" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" +msgid "Keyring" +msgstr "Puarteclâfs" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Daûr a cjariâ…" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "No cognossût" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Unìs plui file firmware intun" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI metadata" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Sielç un dispositîf:" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Firme dal URI dal metadata" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Mode" +msgstr "Modalitât" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Al modifiche un rimot furnît" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +msgid "Modify a configured remote" +msgstr "Modifiche un rimot configurât" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitore il demoni pai events" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Non" +#. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 msgid "No hardware detected with firmware update capability" -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "" +msgstr "Nissun hardware rilevât un funzionalitâts di inzornament dal firmware" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Fat!" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 msgid "OK" msgstr "Va ben" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Version" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "Rimot" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Descrizion" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Checksum" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Sielç une publicazion:" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Ignore i avertiments dal plugin" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Password" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +msgid "Permission denied" +msgstr "Permès dineât" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 +#. TRANSLATORS: the user isn't reading the question #, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Titul" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Gjenar" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Puarteclâfs" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Abilitât" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" +msgid "Please enter a number from 0 to %u: " +msgstr "Inserìs un numar di 0 a %u: " #. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 msgid "Priority" msgstr "Prioritât" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Non utent" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protocol" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Lei il firmware dal dispositîf intun file" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Password" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Lei il firmware di une partizion intun file" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Non file" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Daûr a lei…" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Firme non file" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Inzorne i metadâts dal servidôr rimot" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Regjon" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Daûr a tornâ a instalâ %s cun %s... " -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Rimot" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "ID rimot" #. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Dispositîf zontât:" +msgid "Removed" +msgstr "Gjavât" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Dispositîf gjavât:" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Sostituìs i dâts intun file di firmware esistent" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Dispositîf modificât:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI segnalazion" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Al à bisugne de conession a internet" #. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 msgid "Restart now?" -msgstr "" +msgstr "Tornâ a inviâ cumò?" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Mostre informazions di debug adizionâls" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Daûr a tornâ a inviâ il dispositîf…" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Mostre versions di client e demoni" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Torne ducj i ID dal hardware pe machine" #. TRANSLATORS: command line option -#: src/fu-util.c:2122 msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" +msgstr "Planifiche la instalazion pe volte sucessive che si torne a inviâ cuant che al è pussibil" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Daûr a planificâ…" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Seriâl" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Met il non alternatîf sul file dal firmware" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Met il numar alternatîf sul file dal firmware" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Met la direzion dal element sul file dal firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Oten ducj i dispositîfs che a supuartin i inzornaments dal firmware" +msgid "Set product ID on firmware file" +msgstr "Met il ID dal prodot sul file dal firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Torne ducj i ID dal hardware pe machine" +msgid "Set release version on firmware file" +msgstr "Met la version di publicazion sul file dal firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Instale inzornaments preparâts cumò" +msgid "Set the firmware size for the target" +msgstr "Met la direzion dal firmware pe destinazion" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Set vendor ID on firmware file" +msgstr "Met il ID dal produtôr sul file dal firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +msgid "Sets metadata on a firmware file" +msgstr "Al stabilìs i metadâts suntun file firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2196 msgid "Share firmware history with the developers" -msgstr "" +msgstr "Condivît la conologjie dai firmware cui svilupadôrs" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Instale un file firmware su chest hardware" +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Mostre versions di client e demoni" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Al oten detais su un file di firmware" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostre opzions di debug" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Al oten la liste di inzornaments pal hardware tacât" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mostre informazions di debug adizionâls" #. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Al inzorne ducj i firmware ae ultime version disponibile" +msgid "Show history of firmware updates" +msgstr "Mostre la cronologjie dai inzoronaments dal firmware" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Mostre lis informazions prolissis dai plugin" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Stât" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Stât" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Sintesi" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titul" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Gjenar" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "No cognossût" + +msgid "Unlock the device to allow access" +msgstr "Sbloche il dispositîf par permeti l'acès" #. TRANSLATORS: command description -#: src/fu-util.c:2232 msgid "Unlocks the device for firmware access" msgstr "Al sbloche il dispositîf pal acès al firmware" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Al nete i risultâts dal ultin inzornament" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Inzorne some di control - checksum" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Al nete ducj i inzornaments programâts di fâ fûr rêt" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Inzorne descrizion" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Al oten i risultâts dal ultin inzornament" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Inzorne posizion" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Inzorne non" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Inzorne ID rimot" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Inzorne sintesi" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Inzorne version" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Il faliment dal inzornament al è un probleme cognossût, visite chest URL par vê plui informazions:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Inzornâ cumò?" + +msgid "Update the stored device verification information" +msgstr "Inzorne lis informazions di verifiche dal dispositîf archiviadis" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" -msgstr "" +msgstr "Inzorne il metadât archiviât cui contignûts ROM atuâi" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" +msgid "Updates all firmware to latest versions available" +msgstr "Al inzorne ducj i firmware ae ultime version disponibile" -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Daûr a inzornâ %s di %s a %s... " + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Non utent" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Daûr a verificâ…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Version" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "In spiete…" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" +msgid "Write firmware from file into device" +msgstr "Scrîf il firmware dal file intal dispositîf" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" +msgid "Write firmware from file into one partition" +msgstr "Scrîf il firmware dal file intune partizion" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Daûr a scrivi…" diff -Nru fwupd-1.0.6/po/he.po fwupd-1.2.10/po/he.po --- fwupd-1.0.6/po/he.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/he.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # dhead666 , 2015 # GenghisKhan , 2015 @@ -9,989 +9,117 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hebrew (http://www.transifex.com/freedesktop/fwupd/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: he\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "ישנם עדכוני קושחה עבור %s:" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "כינוי עבור %s" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 msgid "Authentication is required to update the firmware on this machine" msgstr "אימות משתמש נדרש לעדכון קושחה מערכת זו" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "כינוי עבור %s" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "סכום ביקורת" #. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 msgid "Command not found" msgstr "פקודה לא נמצאה" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "" - -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "" - -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "" - -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" - -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "נכשל בפענוח הארגומנטים" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "הצג מידע ניפוי שגיאות לכל הקבצים" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - #. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 msgid "Debugging Options" msgstr "אפשרויות ניפוי שגיאות" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "הצג אפשרויות ניפוי שגיאות" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "תיאור" + +#. success +msgid "Done!" +msgstr "הסתיים!" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "משנמך גרסת %s מ־%s ל־%s..." #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "יציאה לאחר השהייה קצרה" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "יציאה לאחר טעינת מנוע התכנה" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "שדון עדכון קושחה" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "נכשל בפענוח הארגומנטים" #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" msgstr "שירות D-Bus עדכון קושחה" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "שדון עדכון קושחה" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "מציג כל המכשירים התומכים בעדכוני קושחה" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "מציג פרטים אודות קובץ קושחה" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "מתקין קובץ קושחה בחומרה זו" +#. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 msgid "No hardware detected with firmware update capability" msgstr "לא אותרה חומרה בעלת יכולת עדכון קושחה" +msgid "OK" +msgstr "אישור" + #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" -#: src/fu-util.c:651 #, c-format msgid "Reinstalling %s with %s... " msgstr "מתקין מחדש %s עם %s..." -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "משנמך גרסת %s מ־%s ל־%s..." +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "הצג אפשרויות ניפוי שגיאות" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "הצג מידע ניפוי שגיאות מורחב" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 #, c-format msgid "Updating %s from %s to %s... " msgstr "מעדכן %s מ־%s ל־%s..." -#: src/fu-util.c:694 -msgid "Done!" -msgstr "הסתיים!" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "אישור" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - #. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 msgid "Version" msgstr "גרסא" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "תיאור" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "סכום ביקורת" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "ישנם עדכוני קושחה עבור %s:" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "הצג מידע ניפוי שגיאות מורחב" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "מציג כל המכשירים התומכים בעדכוני קושחה" - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "מתקין כעת עדכונים מוכנים" - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "מתקין קובץ קושחה בחומרה זו" - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "מציג פרטים אודות קובץ קושחה" - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" diff -Nru fwupd-1.0.6/po/hi.po fwupd-1.2.10/po/hi.po --- fwupd-1.0.6/po/hi.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/hi.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Prashant Gupta , 2015 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hindi (http://www.transifex.com/freedesktop/fwupd/language/hi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,81 @@ "Language: hi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "फर्मवेयर अपडेट के लिए प्रमाणीकरण चाहिए " - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "%s का उपनाम " -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "" - -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "" - -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "" - -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" - -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "आर्गुमेंट पार्स करने में असफल " - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "फाइल्स की डिबगिंग की जानकारी दिखाए " - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "फर्मवेयर अपडेट के लिए प्रमाणीकरण चाहिए " #. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 msgid "Debugging Options" msgstr "डिबगिंग के विकल्प " -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "डिबगिंग के विकल्प दिखाए " +#. success +msgid "Done!" +msgstr "हो गया !" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "%s की %s से %s तक अधोगति हो रही है " #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "थोड़ी देरी के बाद बहार जाएँ " #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "इंजन के लोड हो जाने पर बहार जाएँ " -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "आर्गुमेंट पार्स करने में असफल " #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" msgstr "फर्मवेयर अपडेट डी-बस सेवा " -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "फर्मवेयर अपडेट का समर्थन करने वाली सभी युक्तियाँ प्राप्त करें " -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "फर्मवेयर फाइल की अधिक जानकारी प्राप्त करें " -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "फर्मवेयर फाइल को इस हार्डवेयर पर स्थापित करें " +#. TRANSLATORS: nothing attached #. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 msgid "No hardware detected with firmware update capability" msgstr "अपडेट की क्षमता वाला हार्डवेयर उपलब्ध नहीं " #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" -#: src/fu-util.c:651 #, c-format msgid "Reinstalling %s with %s... " msgstr "%s को %s से दोबारा स्थापित करा जा रहा है " -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "%s की %s से %s तक अधोगति हो रही है " +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "डिबगिंग के विकल्प दिखाए " + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "डिबगिंग की अतिरिक्त जानकारी दिखाएँ " #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 #, c-format msgid "Updating %s from %s to %s... " msgstr "%s को %s से %s तक अपडेट करा जा रहा है " - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "हो गया !" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "डिबगिंग की अतिरिक्त जानकारी दिखाएँ " - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "फर्मवेयर अपडेट का समर्थन करने वाली सभी युक्तियाँ प्राप्त करें " - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "तैयार अपडेट अभी स्थापित करें " - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "फर्मवेयर फाइल को इस हार्डवेयर पर स्थापित करें " - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "फर्मवेयर फाइल की अधिक जानकारी प्राप्त करें " - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" diff -Nru fwupd-1.0.6/po/hr.po fwupd-1.2.10/po/hr.po --- fwupd-1.0.6/po/hr.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/hr.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,18 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # FIRST AUTHOR , 2016 # gogo , 2016 -# gogo , 2016-2018 +# gogo , 2016-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Croatian (http://www.transifex.com/freedesktop/fwupd/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,980 +17,1213 @@ "Language: hr\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Nadopunite frimvere uređaja na Linuxu" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuta preostala" +msgstr[1] "%.0f minute preostale" +msgstr[2] "%.0f minuta preostalo" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Svrha ovog projekta je automatsko, sigurno i pouzdano nadopunjivanje frimvera na linuxu. Kako bi vidjeli i primijenili nadopune frimvera možete koristiti upravitelja softverom poput GNOME Softvera, alat naredbenog redka ili izravno D-Bus sučelje." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "%s Potrošački pogon upravljanja (ME) nadopunjen" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "fwupd je jednostavan pozadinski program koji omogućuje softveru sesije nadopunu frimvera uređaja na vašem lokalnom računalu. Dizajniran je za stolna računala, ali ovaj projekt se može koristiti i na mobilnim telefonima, tabletima i poslužiteljima." +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "%s nadopuna upravljača" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Instaliraj frimver potpisan sustavom" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "%s Korporativni pogon upravljanja (ME) nadopunjen" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Potrebna je ovjera za nadopunu frimvera na ovom računalu" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "%s uređaj nadopunjen" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Instaliraj frimver nepotpisan sustavom" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "%s ugrađeni upravljač nadopunjen" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Instaliraj stariju inačicu frimvera sustava" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "%s Pogon upravljanja (ME) nadopunjen" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Potrebna je ovjera za vraćanje starije inačicu frimvera na ovom računalu" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "%s sustav nadopunjen" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Instaliraj frimver potpisan uređajem" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "%s nadopuna" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Potrebna je ovjera za nadopunu frimvera na uklonjivom uređaju" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s ima nadopune frimvera:" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Instaliraj frimver nepotpisan uređajem" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dan" +msgstr[1] "%u dana" +msgstr[2] "%u dana" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Potrebna je ovjera za vraćanje starije inačicu frimvera na uklonjivom uređaju" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u sat" +msgstr[1] "%u sata" +msgstr[2] "%u sati" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Otključaj uređaj za dopuštenje pristupa" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuta" +msgstr[1] "%u minute" +msgstr[2] "%u minuta" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Potrebna je ovjera za otključavanje uređaja" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekunda" +msgstr[1] "%u sekunde" +msgstr[2] "%u sekundi" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Nadopuni spremljenu informaciju provjere uređaja" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktiviraj uređaj" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Potrebna je ovjera za nadopunu spremljenog kontrolnog zbroja uređaja" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktiviraj uređaje na čekanju" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Promijeni zadanu udaljenu lokaciju" +msgid "Activate the new firmware on the device" +msgstr "Aktiviraj novi frimver na uređaju" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Potrebna je ovjera za promjenu udaljene lokacije koja se koristi za nadopunu frimvera" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Aktivacija nadopune frimvera" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Aktivacija nadopune frimvera za" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Dodano" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Dob" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Slažete se s omogućavanjem udaljene lokacije?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Zamjena za %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Naredba nije pronađena" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Dopusti vraćanje starije inačice frimvera" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Dodano" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Dopusti ponovnu instalaciju frimvera postojeće inačice" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Uklonjeno" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Nadopuna zahtijeva ponovno pokretanje za završetak." -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Promijenjeno" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Nadopuna zahtijeva potpuno isključivanje sustava." -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Prekinuto" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Odgovori 'da' na sva pitanja" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Primijeni binarnu zakrpu" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Naziv" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Primijeni nadopune frimvera" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Cipher" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Odobreni frimver:" +msgstr[1] "Odobreni frimveri:" +msgstr[2] "Odobreni frimveri:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Regija" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Poveži DFU sposoban uređaj natrag u vremenu izvršavanja" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Pronađen" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Prebaci u način frimvera" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokol" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Značajke" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Stanje" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Ovjeravanje..." -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Dozvola odbijena" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Potrebna je ovjera za vraćanje starije inačicu frimvera na uklonjivom uređaju" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Serijski broj" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Potrebna je ovjera za vraćanje starije inačicu frimvera na ovom računalu" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Način" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Potrebna je ovjera za promjenu udaljene lokacije koja se koristi za nadopunu frimvera" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Vrijeme trajanja" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Potrebna je ovjera za promjenu podešavanja pozadinskog programa" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Potrebna je ovjera za postavljanje popisa odobrenih frimvera" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Stanje" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Potrebna je ovjera za potpisivanje podataka vjerodajnicom klijenta" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Veličina prijenosa" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Potrebna je ovjera za prebacivanje na novu inačicu frimvera" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Značajke" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Potrebna je ovjera za otključavanje uređaja" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Okolnosti uređaja" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Potrebna je ovjera za nadopunu frimvera na uklonjivom uređaju" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ID čipa" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Potrebna je ovjera za nadopunu frimvera na ovom računalu" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Pretvori firmver u DFU format" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Potrebna je ovjera za nadopunu spremljenog kontrolnog zbroja uređaja" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Spoji više frimver datoteka u jednu" +msgid "Build firmware using a sandbox" +msgstr "Izgradi frimver u osiguranom okruženju" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Postavi ID proizvođača u datoteku firmvera" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Odustani" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Postavi ID proizvoda u datoteku firmvera" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Prekinuto" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Postavi adresu elementa na datoteku frimvera" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Promijenjeno" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Postavi veličinu frimvera za metu" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolni zbroj" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Postavi inačicu izdanja u datoteku firmvera" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID čipa" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Postavi zamjenski broj u datoteku firmvera" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Odaberite uređaj:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Postavi zamjenski naziv u datoteku firmvera" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Odaberi izdanje:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Poveži DFU sposoban uređaj natrag u vremenu izvršavanja" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Cipher" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Vrati na izvorno DFU uređaj" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Uklanja sve nadopune zakazne za izvanmrežno nadopunjivanje" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Očitaj frimver iz uređaja u datoteku" +msgid "Clears the results from the last update" +msgstr "Uklanja rezultate posljednje nadopune" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Naredba nije pronađena" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Očitaj frimver iz jedne particije u datoteku" +msgid "Convert firmware to DFU format" +msgstr "Pretvori firmver u DFU format" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Zapiši frimver iz datoteke u uređaj" +msgid "Create a binary patch using two files" +msgstr "Stvori binarnu zakrpu koristeći dvije datoteke" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Zapiši frimver iz datoteke u jednu particiju uređaja" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU pomagalo" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Mogućnosti otklanjanja greške" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Raspakiravanje..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Prikaži trenutno povezane DFU sposobne uređaje" +msgid "Decrypt firmware data" +msgstr "Dešifriraj podatke frimvera" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Opis" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "Odspoji trenutno povezane DFU sposobne uređaje" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Ispiši opširnije pojedinosti o frimveru u datoteku" +msgid "Detach to bootloader mode" +msgstr "Prebaci u način učitača pokretanja" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Nadgledaj odspajanje DFU uređaja" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "ID uređaja" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Šifriraj podatke frimvera" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Uređaj dodan:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Dešifriraj podatke frimvera" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Uređaj promijenjen:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Uređaj uklonjen:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Uređaji koji su ispravno nadopunjeni:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Uređaji koji nisu ispravno nadopunjeni:" + +msgid "Disabled fwupdate debugging" +msgstr "Onemogući fwupdate otklanjanje grešaka" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Postavlja metapodatke u datoteku frimvera" +msgid "Disables a given remote" +msgstr "Onemogućuje zadane udaljene lokacije" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Prikaži inačicu" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Ne provjeravaj stare metapodatke" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Ne provjeravaj za ponovno pokretanje nakon nadopune" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Ne provjeravaj neprijavljenu povijest" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Ne zapisuj bazu podataka povijesti" + +#. success +msgid "Done!" +msgstr "Završeno!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Zamijeni podatke u postojećoj datoteci frimvera" +msgid "Downgrades the firmware on a device" +msgstr "Vraća stariju inačicu frimvera na uređaju" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Vraćanje %s s inačice %s na inačicu %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Vraćanje %s na stariju inačicu…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Preuzimanje..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Stvori binarnu zakrpu koristeći dvije datoteke" +msgid "Dump SMBIOS data from a file" +msgstr "Ispiši opširnije podatke SMBIOS-a iz datoteke" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Primijeni binarnu zakrpu" +msgid "Dump details about a firmware file" +msgstr "Ispiši opširnije pojedinosti o frimveru u datoteku" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "Ispiši informacije o binarnoj zakrpi na zaslonu" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "Neuspjelo učitavanje okolnosti uređaja" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Određeni ESP nije ispravan" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU pomagalo" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Omogući podršku nadopune frimvera na podržanim sustavima" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Neuspjela obrada argumenata" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Omogući ovu udaljenu lokaciju?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Pobroji sve Synaptics MST uređaje" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Omogućeno" + +msgid "Enabled fwupdate debugging" +msgstr "Omogući fwupdate otklanjanje grešaka" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Zapiši datoteku frimvera u MST uređaj" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics Multistream Transport pomagalo" +msgid "Enables a given remote" +msgstr "Omogućuje zadane udaljene lokacije" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Instalacija nadopune frimvera..." +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Omogućujete ovu funkcionalnost na vlastiti rizik, što znači da morate kontaktirati svog izvornog proizvođača opreme u vezi problema uzrokovanih tim nadopunama. Samo probleme sa samim postupkom nadopune treba prijaviti na $OS_RELEASE:BUG_REPORT_URL$." -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Prikaži informacije otklanjanja greške za sve datoteke" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Ovu udaljenu lokaciju omogućavate na vlastiti rizik." -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Prikaži dodatne informacije priključka" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Šifriraj podatke frimvera" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Mogućnosti otklanjanja greške" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Obriši svu povijest nadopune frimvera" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Prikaži mogućnosti otklanjanja greške" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Brisanje..." #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Izađi nakon kratke odgode" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Izađi nakon učitavanja pogona" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Pozadinski program nadopune frimvera" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Neuspjelo povezivanje s pozadinskim programom" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Neuspjelo preuzimanje zbog ograničenja poslužitelja" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Neuspjeli prikaz uređaja na čekanju" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Neuspjela instalacija nadopune frimvera" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Firmver nadopuna D-Bus usluge" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Neuspjelo učitavanje okolnosti uređaja" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Mirovanje..." +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Neuspjela obrada argumenata" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Raspakiravanje..." +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Neuspjelo ponovno pokretanje" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Učitavanje..." +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Dohvaćanje datoteke" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Ponovno pokretanje uređaja..." +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Dohvaćanje frimvera" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Čitanje..." +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Dohvaćanje metapodataka" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Zapisivanje..." +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Dohvaćanje potpisa" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Brisanje..." +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Naziv datoteke" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Provjeravanje..." +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Potpis naziva datoteke" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Zakazivanje..." +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Firmver agent" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Preuzimanje..." +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Osnovni URI frimvera" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Ovjeravanje..." +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Firmver nadopuna D-Bus usluge" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Čekanje…" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Pozadinski program nadopune frimvera" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Nepoznat" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmver pomagalo" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Metapodaci firmvera nisu nadopunjeni %u dan i možda nisu najnoviji." +msgstr[1] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." +msgstr[2] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Odaberite uređaj:" +msgid "Firmware updates are not supported on this machine." +msgstr "Nadopuna frimvera nije podržana na ovom računalu." -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "Nadopuna frimvera je podržana na ovom računalu." -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Uređaji koji nisu ispravno nadopunjeni:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Oznake" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Uređaji koji su ispravno nadopunjeni:" +msgid "Force the action ignoring all warnings" +msgstr "Prisili radnju zanemarivanja svih upozorenja" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Pošalji izvještaj odmah?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Pronađen" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Potreban je pristup internetu" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Nema otkrivenog hardvera s mogućnosti nadopune frimvera" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Prikaži sve uređaje prema topologiji sustava" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Prikaži sve uređaje i moguća izdanja" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Prikaži sve uređaje koji podržavaju nadopunu frimvera" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Prikaži sve omogućene priključke registrirane sa sustavom" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Prikaži pojedinosti datoteke frimvera" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Prikazuje udaljena podešavanja" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Prikaži kriptografsku jedinstvenu vrijednost opširnijih informacija frimvera" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Prikazuje popis odobrenih frimvera." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Prikaži popis nadopuna za povezani hardver" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Prikazuje izdanja za uređaj" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Prikaži rezultate posljednje nadopune" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Mirovanje..." + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Instaliraj blob frimvera na uređaj" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instaliraj datoteku frimvera na ovaj uređaj" + +msgid "Install old version of system firmware" +msgstr "Instaliraj stariju inačicu frimvera sustava" + +msgid "Install signed device firmware" +msgstr "Instaliraj frimver potpisan uređajem" + +msgid "Install signed system firmware" +msgstr "Instaliraj frimver potpisan sustavom" + +msgid "Install unsigned device firmware" +msgstr "Instaliraj frimver nepotpisan uređajem" + +msgid "Install unsigned system firmware" +msgstr "Instaliraj frimver nepotpisan sustavom" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalacija frimvera…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Instalacija nadopune frimvera..." + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Reinstalling %s with %s... " -msgstr "Ponovna instalacija %s inačice %s... " +msgid "Installing on %s…" +msgstr "Instaliram na %s…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 +msgid "Keyring" +msgstr "Skup ključeva" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Preostalo je manje od minute" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Frimver Usluga Linux Proizvođača (LVFS) (stabilni frimver)." + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Frimver Usluga Linux Proizvođača (LVFS) (testni frimver)." + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Prikaži trenutno povezane DFU sposobne uređaje" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Prikaži nadopune podržanih frimvera" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Učitavanje..." + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Ručno dopusti određene priključke" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Spoji više frimver datoteka u jednu" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI metapodataka" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Potpis URI metapodataka" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metapodaci se mogu dobiti od Frimver Usluge Linux Proizvođača (LVFS)." + +#. TRANSLATORS: error message #, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Vraćanje %s s inačice %s na inačicu %s... " +msgid "Mismatched daemon and client, use %s instead" +msgstr "Pozadinski program i klijent se ne podudaraju, umjesto koristite %s" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Mode" +msgstr "Način" + +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Prilagođava vrijednost podešavanja pozadinskog programa." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Promjena zadane udaljene lokacije" + +msgid "Modify a configured remote" +msgstr "Promijeni zadanu udaljenu lokaciju" + +msgid "Modify daemon configuration" +msgstr "Prilagodi podešavanje pozadinskog programa" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Nadgledaj događaje pozadinskim programom" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Naziv" + +msgid "No action specified!" +msgstr "Nema zadane radnje!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Nema otkrivenog hardvera s mogućnosti nadopune frimvera" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nema pronađenih priključaka" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Trenutno nema omogućenih udaljenih lokacija stoga nema dostupnih metapodataka." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nema primijenjenih nadopuna" + +msgid "OK" +msgstr "U redu" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Zaobiđi upozorenja priključka" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Zaobiđi zadanu ESP putanju" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Zaobiđi upozorenja i prisili radnju" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Lozinka" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Postotak završetka" + +msgid "Permission denied" +msgstr "Dozvola odbijena" + +#. TRANSLATORS: the user isn't reading the question #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Nadopuna %s s inačice %s na inačicu %s... " +msgid "Please enter a number from 0 to %u: " +msgstr "Odaberite broj od 0 do %u: " -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Završeno!" +msgid "Print the version number" +msgstr "Prikaži broj inačice" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Odredište" +msgid "Print verbose debug statements" +msgstr "Zapisuj opširniji izvještaj otklanjanja grešaka" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioritet" -#: src/fu-util.c:728 msgid "Proceed with upload?" msgstr "Nastavi sa slanjem?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Neuspješna nadopuna je poznat problem, posjetite ovaj URL za više informacija:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Pošalji poruku:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Zatraži podršku nadopune frimvera" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "U redu" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Okolnosti uređaja" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Dohvaćanje potpisa" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Očitaj frimver iz uređaja u datoteku" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Dohvaćanje metapodataka" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Očitaj frimver iz jedne particije u datoteku" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Dohvaćanje frimvera" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Čitanje..." -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Dohvaćanje datoteke" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Ponovno pokretanje…" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Inačica" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Osvježi metapodatke s udaljenog poslužitelja" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Sažetak" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Regija" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Ponovna instalacija %s inačice %s... " #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Udaljena lokacija" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Udaljeni ID" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Opis" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Uklonjeno" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Kontrolni zbroj" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Zamijeni podatke u postojećoj datoteci frimvera" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Odaberi izdanje:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI izvještaja" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "Metapodaci firmvera nisu nadopunjeni %u dan i možda nisu najnoviji." -msgstr[1] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." -msgstr[2] "Metapodaci firmvera nisu nadopunjeni %u dana i možda nisu najnoviji." +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Potreban je pristup internetu" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Nadopuni odmah?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Vrati na izvorno DFU uređaj" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s ima nadopune frimvera:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Ponovno pokreni odmah?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Ponovno pokreni pozadinski program kako bi se promjene primijenile?" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Inačica nadopune" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Ponovno pokretanje uređaja..." -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Naziv nadopune" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Vrati sve ID-ove hardvera za uređaj" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Sažetak nadopune" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Pokreni rutinu čišćenja sastavljanja priključka kada se koristi install-blob" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Udaljeni ID nadopune" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Pokreni rutinu pripreme sastavljanja priključka kada se koristi install-blob" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Kontrolni zbroj nadopune" +msgid "Runtime" +msgstr "Vrijeme trajanja" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Lokacija nadopune" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Spremi stanje uređaja u JSON datoteku između izvršavanja" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Opis nadopune" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Zakaži instalaciju pri sljedećem pokretanju kada je moguće" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Udaljeni ID" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Zakazivanje..." -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Naziv" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serijski broj" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Postavi zamjenski naziv u datoteku firmvera" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Postavi zamjenski broj u datoteku firmvera" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Postavi adresu elementa na datoteku frimvera" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Postavi ID proizvoda u datoteku firmvera" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Postavi inačicu izdanja u datoteku firmvera" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Postavi oznaku otklanjanja grešaka tijekom nadopune" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Postavi veličinu frimvera za metu" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Postavi ID proizvođača u datoteku firmvera" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Postavlja metapodatke u datoteku frimvera" + +msgid "Sets the list of approved firmware" +msgstr "Postavlja popis odobrenih frimvera" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Postavlja popis odobrenih frimvera" + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Podijeli povijest frimvera sa razvijateljima" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Prikaži inačicu klijenta i pozadinskog programa" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Prikaži dodatne informacije pozadinskog programa za određenu domenu" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Prikaži informacije otklanjanja greške za sve domene" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Prikaži mogućnosti otklanjanja greške" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Prikaži uređaje koji se ne mogu nadopuniti" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Prikaži dodatne informacije otklanjanja grešaka" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Vrsta" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Prikaži povijest nadopune metapodataka" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Skup ključeva" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Prikaži dodatne informacije priključka" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Omogućeno" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Prikaži zapis otklanjanja grešaka posljednjeg pokušaja nadopune" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Dob" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Prikaži informacije stanja nadopune frimvera" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Prioritet" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Odmah isključi?" + +msgid "Sign data using the client certificate" +msgstr "Potpiši podatke koristeći vjerodajnicu klijenta" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Potpiši podatke koristeći vjerodajnicu klijenta" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Korisničko ime" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Potpiši poslane podatke s vjerodajnicom klijenta" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Lozinka" +msgid "Signature" +msgstr "Potpis" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Naziv datoteke" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Odredi ID-ove Proizvođača/Proizvoda DFU uređaja" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Potpis naziva datoteke" +msgid "Specify the number of bytes per USB transfer" +msgstr "Odredi broj bajtova po USB prijenosu" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI metapodataka" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Stanje" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Potpis URI metapodataka" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Stanje" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Osnovni URI frimvera" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Sažetak" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "URI izvještaja" +msgid "Target" +msgstr "Odredište" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Uređaj dodan:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS (Frimver Usluga Linux Proizvođača) je besplatna usluga koja djeluje kao neovisna pravna osoba i nema veze sa $OS_RELEASE:NAME$. Vaš distributer možda nije provjerio nadopune frimvera za kompatibilnost s vašim sustavom ili priključenim uređajima. Svi frimveri su pružani od strane izvornih proizvođača opreme." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Ne postoji odobreni frimver." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Ovaj program možda radi ispravno samo ako je pokrenut kao korijenski korisnik" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Ova udaljena lokacija sadrži frimver koji nije zabranjen, ali se još uvijek testira od strane proizvođača hardvera. Provjerite da imate način na ručno vraćanje starije inačice frimvera ako nadopuna frimvera ne uspije." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Ovaj alat može koristiti samo korijenski korisnik" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Uređaj uklonjen:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Naziv" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Uređaj promijenjen:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Veličina prijenosa" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Nadopuna zahtijeva ponovno pokretanje za završetak." +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Vrsta" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "Ponovno pokreni odmah?" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI firmver pomagalo" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Prikaži dodatne informacije otklanjanja grešaka" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Prikaži inačicu klijenta i pozadinskog programa" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Nepoznat" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Zakaži instalaciju pri sljedećem pokretanju kada je moguće" +msgid "Unlock the device to allow access" +msgstr "Otključaj uređaj za dopuštenje pristupa" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Dopusti ponovnu instalaciju frimvera postojeće inačice" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Otključava uređaj za pristup frimvera" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Dopusti vraćanje starije inačice frimvera" +msgid "Unset the debugging flag during update" +msgstr "Ukloni oznaku otklanjanja grešaka tijekom nadopune" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Zaobiđi upozorenja priključka" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Nepodržana inačica pozadinskog programa %s, inačica klijenta je %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Odgovori 'da' na sva pitanja" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Kontrolni zbroj nadopune" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Ne provjeravaj neprijavljenu povijest" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Opis nadopune" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Ne provjeravaj stare metapodatke" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Trajanje nadopune" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Ne provjeravaj za ponovno pokretanje nakon nadopune" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Lokacija nadopune" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Prikaži sve uređaje koji podržavaju nadopunu frimvera" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Naziv nadopune" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Vrati sve ID-ove hardvera za uređaj" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Udaljeni ID nadopune" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Instaliraj pripremljene uređaje odmah" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Sažetak nadopune" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Prikaži povijest nadopune metapodataka" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Inačica nadopune" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Obriši svu povijest nadopune frimvera" +msgid "Update all devices that match local metadata" +msgstr "Nadopuni sve uređaje koji se podudaraju s lokalnim metapodacima" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Podijeli povijest frimvera sa razvijateljima" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Neuspješna nadopuna je poznat problem, posjetite ovaj URL za više informacija:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Instaliraj datoteku frimvera na ovaj uređaj" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Nadopuni odmah?" + +msgid "Update the stored device verification information" +msgstr "Nadopuni spremljenu informaciju provjere uređaja" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Prikaži pojedinosti datoteke frimvera" +msgid "Update the stored metadata with current ROM contents" +msgstr "Nadopuni pohranjene metapodatke s trenutnim sadržajem ROM-a" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Prikaži popis nadopuna za povezani hardver" +msgid "Update the stored metadata with current contents" +msgstr "Nadopuni pohranjene metapodatke s trenutnim sadržajem" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Nadopuni sav frimver na najnovije dostupne inačice" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Prikaži kriptografsku jedinstvenu vrijednost opširnijih informacija frimvera" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Nadopuna %s s inačice %s na inačicu %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Otključava uređaj za pristup frimvera" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Nadopunjujem %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Uklanja rezultate posljednje nadopune" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Pošalji poruku:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Uklanja sve nadopune zakazne za izvanmrežno nadopunjivanje" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Pošalji izvještaj odmah?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Prikaži rezultate posljednje nadopune" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Slanje izvještaja frimvera pomaže proizvođačima hardvera brzo otkrivanje nedostatka i brzu nadopunu na stvarnim uređajima." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Prikazuje izdanja za uređaj" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Korisničko ime" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Prikazuje udaljena podešavanja" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Provjeravanje..." -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Vraća stariju inačicu frimvera na uređaju" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Inačica" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Osvježi metapodatke s udaljenog poslužitelja" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Čekanje…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Nadopuni pohranjene metapodatke s trenutnim sadržajem ROM-a" +msgid "Watch DFU devices being hotplugged" +msgstr "Nadgledaj odspajanje DFU uređaja" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Nadgledaj događaje pozadinskim programom" +msgid "Watch for hardware changes" +msgstr "Nadgledaj promjene hardvera" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Izgradi frimver u osiguranom okruženju" +msgid "Write firmware from file into device" +msgstr "Zapiši frimver iz datoteke u uređaj" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Ispiši opširnije podatke SMBIOS-a iz datoteke" +msgid "Write firmware from file into one partition" +msgstr "Zapiši frimver iz datoteke u jednu particiju uređaja" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Promjena zadane udaljene lokacije" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Zapisivanje..." -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Firmver pomagalo" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Vaš distributer možda nije provjerio nadopune frimvera za kompatibilnost s vašim sustavom ili priključenim uređajima." diff -Nru fwupd-1.0.6/po/hu.po fwupd-1.2.10/po/hu.po --- fwupd-1.0.6/po/hu.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/hu.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,19 +1,16 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Balázs Meskó , 2017-2018 -# Balázs Úr , 2015-2018 +# Balázs Meskó , 2017-2019 +# Balázs Úr, 2015-2018 # Gabor Kelemen , 2016 # kelemeng , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Hungarian (http://www.transifex.com/freedesktop/fwupd/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,979 +18,1156 @@ "Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Eszköz firmware frissítése Linuxon" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f perc van hátra" +msgstr[1] "%.0f perc van hátra" + +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "%s vezérlőfrissítés" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "A projekt célja a firmwarek frissítését automatikussá, biztonságossá és megbízhatóvá tétele Linuxon. Használhat grafikus szoftverkezelőket, mint a GNOME Szoftverek a frissítések megtekintéséhez és alkalmazásához, használhatja a parancssoros eszközt, vagy közvetlenül a D-Bus interfészt." +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "%s eszközfrissítés" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "A fwupd folyamat egy egyszerű démon, amely lehetővé teszi más szoftvereknek a számítógép eszközeinek firmware-jének frissítését. Asztali számítógépekre lett tervezve, de használható telefonokon, táblagépeken és képernyő nélküli kiszolgálókon is. " +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "%s beágyazottvezérlő-frissítés" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Aláírt rendszer firmware telepítése" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "%s ME frissítés" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Hitelesítés szükséges a firmware frissítéséhez ezen a gépen" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "%s rendszerfrissítés" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Nem aláírt rendszer firmware telepítése" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "%s frissítés" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "A rendszer firmware régi verziójának telepítése" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s firmware frissítésekkel rendelkezik:" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez ezen a gépen" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u nap" +msgstr[1] "%u nap" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Aláírt eszköz firmware telepítése" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u óra" +msgstr[1] "%u óra" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Hitelesítés szükséges a firmware frissítéséhez egy cserélhető eszközön" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u perc" +msgstr[1] "%u perc" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Nem aláírt eszköz firmware telepítése" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u másodperc" +msgstr[1] "%u másodperc" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez egy cserélhető eszközön" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Eszközök aktiválása" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Eszköz feloldása hozzáférés engedélyezéséhez" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Függőben lévő eszközök aktiválása" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Hitelesítés szükséges az eszköz feloldásához" +msgid "Activate the new firmware on the device" +msgstr "Az új firmware aktiválása az eszközön" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "A tárolt eszközellenőrzési információk frissítése" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Firmware frissítés aktiválása" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Hitelesítés szükséges az eszköz tárolt ellenőrzőösszegeinek frissítéséhez" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Firmware frissítés aktiválása ennél:" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "A beállított távoli tároló módosítása" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Hozzáadva" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Hitelesítés szükséges a firmware frissítéshez beállított távoli tároló módosításához." +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Kor" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Beleegyezik és engedélyezi a távoli tárolót?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Álnév ehhez: %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "A parancs nem található" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Firmware verziók visszafejlesztésének engedélyezése" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Hozzáadva" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Meglévő firmware verziók újratelepítésének engedélyezése" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Eltávolítva" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Egy frissítés újraindítást igényel a befejezéshez." -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Módosítva" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Egy frissítés a rendszer újraindítását igényel a befejezéshez." -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Megszakítva" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Igen az összes kérdésre" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "Azonosító" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Bináris folt alkalmazása" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Név" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Firmware-frissítések alkalmazása" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Titkosító" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Jóváhagyott firmware:" +msgstr[1] "Jóváhagyott firmwarek:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Régió" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "DFU-képes eszköz visszacsatolása a futtatókörnyezethez" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Megtalálva" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Csatlakoztatás a firmware módhoz" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokoll" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribútumok" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Állapot" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Hitelesítés…" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Hozzáférés megtagadva" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez egy cserélhető eszközön" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Sorozat" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Hitelesítés szükséges a firmware visszafejlesztéséhez ezen a gépen" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Mód" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Hitelesítés szükséges a firmware frissítéshez beállított távoli tároló módosításához." -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Futtatókörnyezet" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Hitelesítés szükséges a jóváhagyott firmwarek listájának beállításához" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Hitelesítés szükséges az adatok ügyféltanúsítvánnyal történő aláírásához" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Állapot" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Hitelesítés szükséges az új firmware verzióra váltáshoz" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Átviteli méret" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Hitelesítés szükséges az eszköz feloldásához" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Attribútumok" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Hitelesítés szükséges a firmware frissítéséhez egy cserélhető eszközön" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Kompatibilitási trükkök" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Hitelesítés szükséges a firmware frissítéséhez ezen a gépen" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "Chipazonosító" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Hitelesítés szükséges az eszköz tárolt ellenőrzőösszegeinek frissítéséhez" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Firmware átalakítása DFU formátumra" +msgid "Build firmware using a sandbox" +msgstr "Firmware összeállítása egy homokozóban" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Több firmware fájl egyesítése" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Mégse" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Gyártóazonosító beállítása a firmware fájlon" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Megszakítva" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Termékazonosító beállítása a firmware fájlon" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Módosítva" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Elem címének beállítása a firmware fájlban" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Ellenőrzőösszeg" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "A firmware méretének beállítása a célhoz" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Chipazonosító" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Kiadási verzió beállítása a firmware fájlon" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Válasszon eszközt:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Alternatív szám beállítása a firmware fájlon" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Válasszon kiadást:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Alternatív név beállítása a firmware fájlon" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Titkosító" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "DFU-képes eszköz visszacsatolása a futtatókörnyezethez" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Törli a beütemezett offline frissítéseket" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "DFU eszköz visszaállítása" +msgid "Clears the results from the last update" +msgstr "Törli a legutóbbi frissítésből származó eredményeket" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Firmware beolvasása eszközről egy fájlba" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "A parancs nem található" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Firmware beolvasása egy partícióról fájlba" +msgid "Convert firmware to DFU format" +msgstr "Firmware átalakítása DFU formátumra" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Firmware írása fájlból egy eszközre" +msgid "Create a binary patch using two files" +msgstr "Bináris folt készítése két fájl használatával" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Firmware írása fájlból egy partícióra" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU segédprogram" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Hibakeresési beállítások" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Kibontás…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Jelenleg csatlakoztatott DFU-képes eszközök felsorolása" +msgid "Decrypt firmware data" +msgstr "Firmware adatok visszafejtése" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Leírás" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "Jelenleg csatlakoztatott DFU-képes eszközök leválasztása" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Részletek kiírása egy firmware fájlról" +msgid "Detach to bootloader mode" +msgstr "Leválasztás a indítóbetöltő módhoz" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "DFU-eszközök menet közbeni csatlakoztatásának figyelése" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Eszközazonosító" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Firmware adatok titkosítása" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Eszköz hozzáadva:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Firmware adatok visszafejtése" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Eszköz módosítva:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Eszköz eltávolítva:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Eszközök, melyek sikeresen frissítve lettek:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Eszközök, melyek nem lettek helyesen frissítve:" + +msgid "Disabled fwupdate debugging" +msgstr "Fwupdate hibakeresés letiltva" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Metaadatok beállítása egy firmware fájlon" +msgid "Disables a given remote" +msgstr "Letiltja az adott távoli tárolót" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Verzió megjelenítése" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Ne ellenőrizze a régi metaadatokat" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Ne ellenőrizze az újraindítást a frissítés után" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Ne ellenőrizze a nem jelentett előzményeket" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Ne írjon az előzmények adatbázisába" + +#. success +msgid "Done!" +msgstr "Kész!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Adatok cseréje egy meglévő firmware fájlban" +msgid "Downgrades the firmware on a device" +msgstr "A firmware visszafejlesztése az eszközön" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "%s visszafejlesztése: %s -> %s…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "%s visszaállítása…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Letöltés…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Bináris folt készítése két fájl használatával" +msgid "Dump SMBIOS data from a file" +msgstr "SMBIOS adatok kiírása egy fájlból" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Bináris folt alkalmazása" +msgid "Dump details about a firmware file" +msgstr "Részletek kiírása egy firmware fájlról" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "Információk kiírása a képernyőre a bináris foltról" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "A trükkök betöltése sikertelen" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "A megadott ESP érvénytelen" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU segédprogram" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Firmware frissítési támogatás engedélyezése a támogatott rendszereken" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Nem sikerült feldolgozni az argumentumokat" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Engedélyezi ezt a távoli tárolót?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Az összes Synaptics MST eszköz felsorolása" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Engedélyezve" + +msgid "Enabled fwupdate debugging" +msgstr "Fwupdate hibakeresés engedélyezve" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Firmware fájl beírása az MST eszközbe" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics több adatfolyamos átviteli segédprogram" +msgid "Enables a given remote" +msgstr "Engedélyezi az adott távoli tárolót" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Firmware frissítés telepítése…" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Csak a saját felelősségére engedélyezze ezt a funkciót, amely azt jelenti, hogy az eredeti termék gyártójával kell kapcsolatba lépnie, ha problémát okoz a frissítés. Csak a frissítési folyamattal kapcsolatos problémákat jelentse itt be: $OS_RELEASE:BUG_REPORT_URL$." -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Hibakeresési információk megjelenítése minden fájlnál" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "A saját felelősségére engedélyezze ezt a távoli tárolót." -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Bővítmény bőbeszédű információinak megjelenítése" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Firmware adatok titkosítása" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Hibakeresési beállítások" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Firmware frissítési előzmények törlése" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Hibakeresési beállítások megjelenítése" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Törlés…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Kilépés egy kis késleltetés után" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Kilépés a motor betöltődése után" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Firmware frissítő démon" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "A démonhoz kapcsolódás sikertelen" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "A letöltés kiszolgálókorlát miatt meghiúsult" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "A függőben lévő eszközök lekérése sikertelen" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "A firmware frissítés telepítése sikertelen" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Firmware frissítés D-Bus szolgáltatás" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "A trükkök betöltése sikertelen" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Üresjárat…" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Nem sikerült feldolgozni az argumentumokat" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Kibontás…" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Újraindítás sikertelen" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Az indítóképernyő módjának beállítása sikertelen" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Betöltés…" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Fájl lekérése" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Eszköz újraindítása…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Firmware lekérése" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Olvasás…" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Metaadatok lekérése" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Írás…" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Aláírás lekérése" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Törlés…" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Fájlnév" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Ellenőrzés…" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Fájlnév aláírása" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Ütemezés…" +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Firmware ügynök" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Letöltés…" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Firmware kiindulópont URI" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Hitelesítés…" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Firmware frissítés D-Bus szolgáltatás" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Várakozás…" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Firmware frissítő démon" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Ismeretlen" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmware segédprogram" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." +msgstr[1] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Válasszon eszközt:" +msgid "Firmware updates are not supported on this machine." +msgstr "A firmware frissítések nem támogatottak ezen a gépen." -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "A firmware frissítések támogatottak ezen a gépen." -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Eszközök, melyek nem lettek helyesen frissítve:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Jelzők" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Eszközök, melyek sikeresen frissítve lettek:" +msgid "Force the action ignoring all warnings" +msgstr "A művelet erőltetése, az összes figyelmeztetés mellőzése" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Feltölti most a jelentést?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Megtalálva" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Internetkapcsolat szükséges" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Nem észlelhető firmware frissítési képességgel rendelkező hardver" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Az összes eszköz lekérdezése a rendszer topológiájának megfelelően" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "%s újratelepítése ezzel: %s…" +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Összes eszköz és a lehetséges kiadások lekérése" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "%s visszafejlesztése: %s -> %s…" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Minden eszköz lekérése, amelyek támogatják a firmware frissítéseket" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Az összes rendszeren regisztrált és engedélyezett bővítmény lekérdezése" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Részleteket kér le egy firmware fájlról" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Lekéri a beállított távoli tárolókat" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Lekéri a kiírt firmware kriptográfiai hash-ét" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Lekéri a jóváhagyott firmwarek listáját." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "A frissítések listáját kéri le a csatlakoztatott hardverhez" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Lekéri az eszközhöz tartozó kiadásokat" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "A legutóbbi frissítésből származó eredményeket kéri le" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Azonosító" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Üresjárat…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Firmware blob telepítése egy eszközre" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Egy firmware fájl telepítése ezen a hardveren" + +msgid "Install old version of system firmware" +msgstr "A rendszer firmware régi verziójának telepítése" + +msgid "Install signed device firmware" +msgstr "Aláírt eszköz firmware telepítése" + +msgid "Install signed system firmware" +msgstr "Aláírt rendszer firmware telepítése" + +msgid "Install unsigned device firmware" +msgstr "Nem aláírt eszköz firmware telepítése" + +msgid "Install unsigned system firmware" +msgstr "Nem aláírt rendszer firmware telepítése" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Firmware telepítése…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Firmware frissítés telepítése…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s... " -msgstr "%s frissítése: %s -> %s…" +msgid "Installing on %s…" +msgstr "%s telepítése…" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Kész!" +msgid "Keyring" +msgstr "Kulcstartó" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Cél" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Kevesebb mint egy perc van hátra" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux gyártói firmware szolgáltatás (stabil firmware)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux gyártói firmware szolgáltatás (teszt firmware)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Jelenleg csatlakoztatott DFU-képes eszközök felsorolása" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "A támogatott firmware-frissítések listázása" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Betöltés…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Egyes bővítmények kézi fehérlistára tétele" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Több firmware fájl egyesítése" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metaadat URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metaadat URI aláírása" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "A metaadatok nem szerezhetőek be a Linux gyártói firmware szolgáltatásból." + +msgid "Mode" +msgstr "Mód" + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "A megadott távoli tároló módosítása" + +msgid "Modify a configured remote" +msgstr "A beállított távoli tároló módosítása" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "A démon eseményeinek figyelése" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Név" + +msgid "No action specified!" +msgstr "Nincs művelet megadva!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Nem észlelhető firmware frissítési képességgel rendelkező hardver" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nem található bővítmény" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Jelenleg nincsenek engedélyezett távoli tárolók, így nem érhetőek el metaadatok." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nem lett frissítés alkalmazva" + +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Bővítmény figyelmeztetés felülbírálása" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Az alapértelmezett ESP útvonal felülbírálása" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Jelszó" -#: src/fu-util.c:727 msgid "Payload" msgstr "Tartalom" -#: src/fu-util.c:728 +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Százalék kész" + +msgid "Permission denied" +msgstr "Hozzáférés megtagadva" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Adjon meg egy számot 0 és %u között:" + +msgid "Print the version number" +msgstr "A verziószám kiírása." + +msgid "Print verbose debug statements" +msgstr "Részletes hibakeresési utasítások kiírása" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioritás" + msgid "Proceed with upload?" msgstr "Folytatja a feltöltést?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "A feltöltési hiba ismert probléma, további információkért látogassa meg ezt az URL-t:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokoll" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Feltöltési üzenet:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Firmware frissítési támogatás lekérdezése" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "OK" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Kompatibilitási trükkök" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Aláírás lekérése" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Firmware beolvasása eszközről egy fájlba" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Metaadatok lekérése" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Firmware beolvasása egy partícióról fájlba" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Firmware lekérése" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Olvasás…" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Fájl lekérése" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Újraindítás…" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Verzió" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Metaadatok frissítése a távoli kiszolgálóról" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Összegzés" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Régió" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "%s újratelepítése ezzel: %s…" #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Távoli tároló" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Távoli azonosító" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Leírás" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Eltávolítva" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Ellenőrzőösszeg" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Adatok cseréje egy meglévő firmware fájlban" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Válasszon kiadást:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Jelentési URI" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." -msgstr[1] "A firmware metaadatok %u napja nem lettek frissítve, és lehet hogy elavultak." +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Internetkapcsolat szükséges" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Frissíti most?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "DFU eszköz visszaállítása" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s firmware frissítésekkel rendelkezik:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Újraindítja most?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Eszköz újraindítása…" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Frissítés verziója" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "A géphez tartozó összes hardverazonosító visszaadása" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Frissítés neve" +msgid "Runtime" +msgstr "Futtatókörnyezet" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Frissítés összegzése" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Eszköz állapotának mentése JSON fájlba a végrehajtások között" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Távoli azonosító frissítése" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Telepítés ütemezése a következő újraindításkor, ha lehetséges" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Frissítés ellenőrzőösszege" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Ütemezés…" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Frissítés helye" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Sorozat" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Frissítés leírása" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Alternatív név beállítása a firmware fájlon" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Távoli azonosító" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Alternatív szám beállítása a firmware fájlon" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Cím" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Elem címének beállítása a firmware fájlban" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Termékazonosító beállítása a firmware fájlon" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Kiadási verzió beállítása a firmware fájlon" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "A hibakeresési jelző beállítása frissítéskor" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "A firmware méretének beállítása a célhoz" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Gyártóazonosító beállítása a firmware fájlon" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Metaadatok beállítása egy firmware fájlon" + +msgid "Sets the list of approved firmware" +msgstr "Beállítja a jóváhagyott firmwarek listáját" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Beállítja a jóváhagyott firmwarek listáját." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Firmware frissítése előzmények megosztása a fejlesztőkkel" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Ügyfél és démon verziók megjelenítése" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Hibakeresési beállítások megjelenítése" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Eszközök, melyek nem frissíthetőek" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Típus" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "További hibakeresési információk megjelenítése" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Kulcstartó" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Firmware frissítési előzmények megtekintése" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Engedélyezve" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Bővítmény bőbeszédű információinak megjelenítése" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Kor" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "A legutóbb megpróbált frissítés hibakeresési naplójának megjelenítése" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Prioritás" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "A firmware frissítési állapot információinak megjelenítése" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Felhasználónév" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Leállítja most?" + +msgid "Sign data using the client certificate" +msgstr "Adatok aláírása az ügyféltanúsítvánnyal" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Adatok aláírása az ügyféltanúsítvánnyal" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Jelszó" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Feltöltött adatok aláírása az ügyféltanúsítvánnyal" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Fájlnév" +msgid "Signature" +msgstr "Aláírás" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Fájlnév aláírása" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Adja meg a DFU eszköz gyártó-/termékazonosítóját" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "Metaadat URI" +msgid "Specify the number of bytes per USB transfer" +msgstr "Adja meg az USB átvitelek bájtjainak számát" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Metaadat URI aláírása" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Állapot" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Firmware kiindulópont URI" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Állapot" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "Jelentési URI" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Összegzés" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Eszköz hozzáadva:" +msgid "Target" +msgstr "Cél" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Eszköz eltávolítva:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "Az LVFS egy ingyenes szolgáltatás, amely független jogi entitásként működik, és nincs kapcsolata a $OS_RELEASE:NAME$ operációs rendszerrel. A disztribúció szállítója nem biztos, hogy ellenőrízte kompatibilitási szempontból a firmware frissítést. Mindent firmware-t csak az eredeti termék gyártója biztosít." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Nincs jóváhagyott firmware." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Ez a program jelenleg lehet, hogy csak rendszergazdaként működik" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Ez a távoli tároló olyan firmware-t tartalmaz, amelyre nem vonatkozik embargó, de még teszteli a harvergyártó. Érdemes biztosítani a firmware kézi visszaállításáról, ha a firmware frissítése meghiúsul." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Ezt az eszközt csak a root felhasználó használhatja" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Eszköz módosítva:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Cím" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Egy frissítés újraindítást igényel a befejezéshez." +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Átviteli méret" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "Újraindítja most?" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Típus" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "További hibakeresési információk megjelenítése" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI firmware segédprogram" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Ügyfél és démon verziók megjelenítése" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Telepítés ütemezése a következő újraindításkor, ha lehetséges" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Ismeretlen" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Meglévő firmware verziók újratelepítésének engedélyezése" +msgid "Unlock the device to allow access" +msgstr "Eszköz feloldása hozzáférés engedélyezéséhez" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Firmware verziók visszafejlesztésének engedélyezése" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Eszköz feloldása a firmware eléréséhez" #. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Bővítmény figyelmeztetés felülbírálása" +msgid "Unset the debugging flag during update" +msgstr "A hibakeresési jelző kikapcsolása frissítéskor" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Igen az összes kérdésre" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Frissítés ellenőrzőösszege" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Ne ellenőrizze a nem jelentett előzményeket" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Frissítés leírása" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Ne ellenőrizze a régi metaadatokat" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Frissítés hossza" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Ne ellenőrizze az újraindítást a frissítés után" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Frissítés helye" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Minden eszköz lekérése, amelyek támogatják a firmware frissítéseket" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Frissítés neve" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "A géphez tartoó összes hardverazonosító visszaadása" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Távoli azonosító frissítése" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Az előkészített frissítések telepítés most" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Frissítés összegzése" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Firmware frissítési előzmények megtekintése" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Frissítés verziója" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Firmware frissítési előzmények törlése" +msgid "Update all devices that match local metadata" +msgstr "Az összes olyan eszköz frissítése, amely illeszkedik a helyi metaadatokra" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Firmware frissítése előzmények megosztása a fejlesztőkkel" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "A feltöltési hiba ismert probléma, további információkért látogassa meg ezt az URL-t:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Egy firmware fájl telepítése ezen a hardveren" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Frissíti most?" + +msgid "Update the stored device verification information" +msgstr "A tárolt eszközellenőrzési információk frissítése" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Részleteket kér le egy firmware fájlról" +msgid "Update the stored metadata with current ROM contents" +msgstr "A tárolt metaadatok frissítése a jelenlegi ROM tartalmával" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "A frissítések listáját kéri le a csatlakoztatott hardverhez" +msgid "Update the stored metadata with current contents" +msgstr "A tárolt metaadatok frissítése a jelenlegi tartalommal" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Minden firmware-t az elérhető legfrissebb verziókra frissít" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Lekéri a kiírt firmware kriptográfiai hash-ét" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "%s frissítése: %s -> %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Eszköz feloldása a firmware eléréséhez" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s frissítése…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Törli a legutóbbi frissítésből származó eredményeket" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Feltöltési üzenet:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Törli a beütemezett offline frissítéseket" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Feltölti most a jelentést?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "A legutóbbi frissítésből származó eredményeket kéri le" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "A firmware jelentések segítenek a hardvergyártóknak, hogy gyorsan azonosítsák a hibás és sikeres frissítéseket valós eszközökön." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Lekéri az eszközhöz tartozó kiadásokat" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Felhasználónév" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Lekéri a beállított távoli tárolókat" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Ellenőrzés…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "A firmware visszafejlesztése az eszközön" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Verzió" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Metaadatok frissítése a távoli kiszolgálóról" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Várakozás…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "A tárolt metaadatok frissítése a jelenlegi ROM tartalmával" +msgid "Watch DFU devices being hotplugged" +msgstr "DFU-eszközök menet közbeni csatlakoztatásának figyelése" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "A démon eseményeinek figyelése" +msgid "Watch for hardware changes" +msgstr "Hardverváltozások figyelése" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Firmware összeállítása egy homokozóban" +msgid "Write firmware from file into device" +msgstr "Firmware írása fájlból egy eszközre" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "SMBIOS adatok kiírása egy fájlból" +msgid "Write firmware from file into one partition" +msgstr "Firmware írása fájlból egy partícióra" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "A megadott távoli tároló módosítása" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Írás…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Firmware segédprogram" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "A disztribúció szállítója nem biztos, hogy ellenőrízte a firmware frissítés kompatibilitását a rendszerével és a kapcsolódó eszközeivel." diff -Nru fwupd-1.0.6/po/id.po fwupd-1.2.10/po/id.po --- fwupd-1.0.6/po/id.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/id.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Andika Triwidada , 2017-2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Indonesian (http://www.transifex.com/freedesktop/fwupd/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,978 +15,726 @@ "Language: id\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Perbarui firmware peranti pada Linux" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s memiliki pemutakhiran firmware:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Proyek ini bertujuan membuat pemutakhiran firmware pada Linux otomatis, aman, dan handal. Anda dapat memakai manajer perangkat lunak GUI seperti GNOME Perangkat Lunak untuk melihat dan menerapkan pembaruan, perkakas perintah baris, atau antar muka D-Bus secara langsung." +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Ditambahkan" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Proses fwupd adalah sebuah daemon sederhana yang memungkinkan perangkat lunak sesi memperbarui firmware peranti pada mesin lokal Anda. Ini dirancang untuk desktop, tapi proyek ini juga dapat dipakai pada telepon, tablet, dan server headless." +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Usia" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Pasang firmware sistem yang ditandatangani" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias ke %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Otentikasi diperlukan untuk memutakhirkan firmware pada mesin ini" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Izinkan penuruntingkatan versi firmware" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Pasang firmware sistem yang tak ditandatangani" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Izinkan pemasangan ulang versi firmware yang telah ada" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Pasang versi lama dari firmware sistem" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Suatu pembaruan memerlukan boot ulang agar lengkap." -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Otentikasi diperlukan untuk menuruntingkatkan firmware pada mesin ini" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Jawab ya untuk semua pertanyaan" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Pasang firmware perangkat yang ditandatangani" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Terapkan sebuah patch biner" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Otentikasi diperlukan untuk memutakhirkan firmware pada perangkat lepas pasang" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Cantolkan kembali perangkat mampu-DFU ke runtime" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Pasang firmware perangkat yang tak ditandatangani" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Atribut" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Mengotentikasi..." #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" +msgid "Authentication is required to downgrade the firmware on a removable device" msgstr "Otentikasi diperlukan untuk menuruntingkatkan firmware pada perangkat lepas pasang" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Buka kunci perangkat untuk mengizinkan akses" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Otentikasi diperlukan untuk menuruntingkatkan firmware pada mesin ini" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Otentikasi diperlukan untuk mengubah sebuah remote yang ditata yang dipakai untuk pembaruan firmware" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Otentikasi diperlukan untuk membuka kunci suatu perangkat" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Mutakhirkan informasi verifikasi perangkat yang tersimpan" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Otentikasi diperlukan untuk memutakhirkan checksum tersimpan bagi perangkat" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Ubah suatu remote yang ditata" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Otentikasi diperlukan untuk memutakhirkan firmware pada perangkat lepas pasang" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Otentikasi diperlukan untuk mengubah sebuah remote yang ditata yang dipakai untuk pembaruan firmware" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Alias ke %s" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Otentikasi diperlukan untuk memutakhirkan firmware pada mesin ini" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Perintah tidak ditemukan" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Otentikasi diperlukan untuk memutakhirkan checksum tersimpan bagi perangkat" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Ditambahkan" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Bangun firmware memakai suatu sandbox" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Dihapus" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Dibatalkan" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Diubah" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Dibatalkan" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Checksum" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID Chip" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nama" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Pilih suatu peranti:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Pilih sebuah rilis:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Cipher" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Wilayah" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Ditemukan" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokol" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Status" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Bersihkan semua pembaruan yang dijadwalkan untuk diperbarui luring" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Izin ditolak" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Bersihkan hasil dari pemutakhiran terakhir" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Serial" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Perintah tidak ditemukan" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Mode" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Konversikan firmware ke format DFU" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Runtime" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Buat suatu patch biner mamakai dua berkas" -#: plugins/dfu/dfu-tool.c:2115 msgid "DFU" msgstr "DFU" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Keadaan" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Ukuran Transfer" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Atribut" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Utilitas DFU" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Keanehan" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opsi Pengawakutuan" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ID Chip" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Mendekompresi..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Konversikan firmware ke format DFU" +msgid "Decrypt firmware data" +msgstr "Dekripsikan data firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Gabungkan beberapa berkas firmware menjadi satu" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Deskripsi" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Atur ID vendor pada berkas firmware" +msgid "Detach currently attached DFU capable device" +msgstr "Lepas perangkat mampu-DFU yang kini tercantol" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Atur ID produk pada berkas firmware" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Perangkat ditambahkan:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Atur alamat elemen pada berkas firmware" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Perangkat diubah:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Atur ukuran firmware bagi target" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Perangkat dilepas:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Atur versi rilis pada berkas firmware" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Peranti yang sukses diperbarui:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Atur nomor alternatif pada berkas firmware" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Peranti yang tidak diperbarui dengan benar:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Atur nama alternatif pada berkas firmware" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Jangan periksa untuk metadata lama" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Cantolkan kembali perangkat mampu-DFU ke runtime" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Jangan periksa untuk boot ulang setelah pembaruan" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Reset suatu peranti DFU" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Baca firmware dari perangkat ke dalam suatu berkas" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Jangan periksa untuk riwayat yang tak dilaporkan" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Baca firmware dari satu partisi ke dalam suatu berkas" +#. success +msgid "Done!" +msgstr "Selesai!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Tulis firmware dari berkas ke dalam perangkat" +msgid "Downgrades the firmware on a device" +msgstr "Turuntingkatkan firmware pada suatu peranti" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Tulis firmware dari berkas ke dalam suatu partisi" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Menuruntingkatkan %s dari %s ke %s..." -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Tampilkan daftar perangkat mampu-DFU yang kini tercantol" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Sedang mengunduh..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Lepas perangkat mampu-DFU yang kini tercantol" +msgid "Dump SMBIOS data from a file" +msgstr "Curahkan data SMBIOS dari suatu berkas" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Curahkan rincian tentang suatu berkas firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Amati perangkat DFU yang sedang di-hotplug" +msgid "Dump information about a binary patch to the screen" +msgstr "Curahkan informasi tentang suatu patch biner ke layar" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Difungsikan" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 msgid "Encrypt firmware data" msgstr "Enkripsikan data firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Dekripsikan data firmware" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Atur metadata pada suatu berkas firmware" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Gantikan data dalam suatu berkas firmware yang telah ada" +msgid "Erase all firmware update history" +msgstr "Hapus semua riwayat pembaruan firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Buat suatu patch biner mamakai dua berkas" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Menghapus..." -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Terapkan sebuah patch biner" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Keluar setelah tundaan sejenak" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Curahkan informasi tentang suatu patch biner ke layar" +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Keluar setelah mesin telah dimuat" #. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 msgid "Failed to load quirks" msgstr "Gagal memuat quirk" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Utilitas DFU" - #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "Gagal mengurai argumen" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Enumerasikan semua perangkat MST Synaptics" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Flash-kan berkas firmware ke perangkat MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Utilitas Transport Multistream Synaptics" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Sedang mengambil berkas" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Sedang memasang pembaruan firmware..." +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Sedang mengambil firmware" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Tampilkan informasi pengawakutuan bagi semua berkas" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Sedang mengambil metadata" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Tampilkan informasi rinci pengaya" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Sedang mengambil tanda tangan" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opsi Pengawakutuan" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nama Berkas" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Tampilkan opsi pengawakutuan" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Tanda Tangan Nama Berkas" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Keluar setelah tundaan sejenak" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "URI Basis Firmware" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Keluar setelah mesin telah dimuat" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Layanan D-Bus Pemutakhiran Firmware" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" msgstr "Daemon Pemutakhiran Firmware" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Layanan D-Bus Pemutakhiran Firmware" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Utilitas Firmware" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Menganggur..." +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Metadata firmware belum diperbarui selama %uhari dan mungkin tidak mutakhir." -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Mendekompresi..." +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Ditemukan" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Memuat..." +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Memulai ulang perangkat..." +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Dapatkan semua perangkat yang mendukung pemutakhiran firmware" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Membaca..." +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Dapatkan rincian tentang suatu berkas firmware" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Menulis..." +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Dapatkan remote-remote yang terkonfigurasi" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Menghapus..." +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Dapatkan hash kriptografis dari firmware yang dicurahkan" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Verifikasi..." +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Dapatkan daftar pemutakhiran bagi perangkat keras yang tersambung" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Menjadwalkan..." +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Dapatkan rilis-rilis bagi sebuah peranti" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Sedang mengunduh..." +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Dapatkan hasil dari pemutakhiran terakhir" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Mengotentikasi..." +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Menunggu..." +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Menganggur..." -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Tidak diketahui" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Pasang suatu berkas firmware pada perangkat keras ini" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Install old version of system firmware" +msgstr "Pasang versi lama dari firmware sistem" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Pilih suatu peranti:" +msgid "Install signed device firmware" +msgstr "Pasang firmware perangkat yang ditandatangani" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Install signed system firmware" +msgstr "Pasang firmware sistem yang ditandatangani" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Peranti yang tidak diperbarui dengan benar:" +msgid "Install unsigned device firmware" +msgstr "Pasang firmware perangkat yang tak ditandatangani" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Peranti yang sukses diperbarui:" +msgid "Install unsigned system firmware" +msgstr "Pasang firmware sistem yang tak ditandatangani" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Unggah laporan sekarang?" +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Sedang memasang pembaruan firmware..." -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Memerlukan koneksi internet" +msgid "Keyring" +msgstr "Keyring" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Tidak terdeteksi perangkat keras dengan kapabilitas pemutakhiran firmware" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Tampilkan daftar perangkat mampu-DFU yang kini tercantol" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Memasang ulang %s dengan %s..." +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Memuat..." -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Menuruntingkatkan %s dari %s ke %s..." +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Gabungkan beberapa berkas firmware menjadi satu" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Memutakhirkan %s dari %s ke %s..." +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI Metadata" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Selesai!" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Tanda Tangan URI Metadata" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Target" +msgid "Mode" +msgstr "Mode" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "Payload" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Mengubah suatu remote yang diberikan" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "Lanjutkan mengunggah?" +msgid "Modify a configured remote" +msgstr "Ubah suatu remote yang ditata" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Kegagalan pembaruan adalah masalah yang telah diketahui, kunjungi URL ini untuk informasi lebih lanjut:" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Pantau daemon untuk kejadian" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Pesan unggah:" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nama" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Tidak terdeteksi perangkat keras dengan kapabilitas pemutakhiran firmware" -#: src/fu-util.c:1034 src/fu-util.c:1414 msgid "OK" msgstr "OK" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Sedang mengambil tanda tangan" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Timpa peringatan plugin" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Sedang mengambil metadata" +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Kata Sandi" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Sedang mengambil firmware" +msgid "Payload" +msgstr "Payload" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Sedang mengambil berkas" +msgid "Permission denied" +msgstr "Izin ditolak" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Versi" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioritas" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Ringkasan" +msgid "Proceed with upload?" +msgstr "Lanjutkan mengunggah?" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "Remote" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Keanehan" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Deskripsi" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Baca firmware dari perangkat ke dalam suatu berkas" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Checksum" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Baca firmware dari satu partisi ke dalam suatu berkas" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Pilih sebuah rilis:" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Membaca..." -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "Metadata firmware belum diperbarui selama %uhari dan mungkin tidak mutakhir." +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Segarkan metadata dari server remote" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Perbarui sekarang?" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Wilayah" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" #, c-format -msgid "%s has firmware updates:" -msgstr "%s memiliki pemutakhiran firmware:" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Mutakhirkan Versi" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Nama Pembaruan" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Ringkasan Pembaruan" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Mutakhirkan ID Remote" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Mutakhirkan Checksum" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Mutakhirkan Lokasi" +msgid "Reinstalling %s with %s... " +msgstr "Memasang ulang %s dengan %s..." -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Mutakhirkan Keterangan" +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Remote" #. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 msgid "Remote ID" msgstr "ID Remote" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Judul" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Tipe" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Keyring" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Difungsikan" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Usia" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Prioritas" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Nama Pengguna" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Kata Sandi" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Nama Berkas" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Tanda Tangan Nama Berkas" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI Metadata" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Tanda Tangan URI Metadata" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Dihapus" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "URI Basis Firmware" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Gantikan data dalam suatu berkas firmware yang telah ada" #. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 msgid "Report URI" -msgstr "URI Lapor" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Perangkat ditambahkan:" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Perangkat dilepas:" +msgstr "URI Lapor" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Perangkat diubah:" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Memerlukan koneksi internet" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Suatu pembaruan memerlukan boot ulang agar lengkap." +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Reset suatu peranti DFU" #. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 msgid "Restart now?" msgstr "Mulai ulang sekarang?" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Tampilkan informasi pengawakutuan ekstra" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Memulai ulang perangkat..." -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Tampilkan versi daemon dan klien" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Kembalikan semua ID perangkat keras bagi mesin" + +msgid "Runtime" +msgstr "Runtime" #. TRANSLATORS: command line option -#: src/fu-util.c:2122 msgid "Schedule installation for next reboot when possible" msgstr "Jadwalkan instalasi untuk boot ulang selanjutnya bila mungkin" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Izinkan pemasangan ulang versi firmware yang telah ada" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Izinkan penuruntingkatan versi firmware" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Timpa peringatan plugin" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Menjadwalkan..." -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Jawab ya untuk semua pertanyaan" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serial" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Jangan periksa untuk riwayat yang tak dilaporkan" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Atur nama alternatif pada berkas firmware" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Jangan periksa untuk metadata lama" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Atur nomor alternatif pada berkas firmware" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Jangan periksa untuk boot ulang setelah pembaruan" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Atur alamat elemen pada berkas firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Dapatkan semua perangkat yang mendukung pemutakhiran firmware" +msgid "Set product ID on firmware file" +msgstr "Atur ID produk pada berkas firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Kembalikan semua ID perangkat keras bagi mesin" +msgid "Set release version on firmware file" +msgstr "Atur versi rilis pada berkas firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Pasang pemutakhiran yang disiapkan sekarang" +msgid "Set the firmware size for the target" +msgstr "Atur ukuran firmware bagi target" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Tampilkan riwayat pembaruan firmware" +msgid "Set vendor ID on firmware file" +msgstr "Atur ID vendor pada berkas firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Hapus semua riwayat pembaruan firmware" +msgid "Sets metadata on a firmware file" +msgstr "Atur metadata pada suatu berkas firmware" #. TRANSLATORS: command description -#: src/fu-util.c:2196 msgid "Share firmware history with the developers" msgstr "Bagikan riwayat firmware dengan para pengembang" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Pasang suatu berkas firmware pada perangkat keras ini" +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Tampilkan versi daemon dan klien" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Dapatkan rincian tentang suatu berkas firmware" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Tampilkan opsi pengawakutuan" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Dapatkan daftar pemutakhiran bagi perangkat keras yang tersambung" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Tampilkan informasi pengawakutuan ekstra" #. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Mutakhirkan semua firmware ke versi terbaru yang tersedia" +msgid "Show history of firmware updates" +msgstr "Tampilkan riwayat pembaruan firmware" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Dapatkan hash kriptografis dari firmware yang dicurahkan" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Tampilkan informasi rinci pengaya" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Keadaan" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Ringkasan" + +msgid "Target" +msgstr "Target" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Judul" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Ukuran Transfer" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipe" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Tidak diketahui" + +msgid "Unlock the device to allow access" +msgstr "Buka kunci perangkat untuk mengizinkan akses" #. TRANSLATORS: command description -#: src/fu-util.c:2232 msgid "Unlocks the device for firmware access" msgstr "Buka kunci perangkat bagi akses firmware" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Bersihkan hasil dari pemutakhiran terakhir" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Mutakhirkan Checksum" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Bersihkan semua pembaruan yang dijadwalkan untuk diperbarui luring" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Mutakhirkan Keterangan" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Dapatkan hasil dari pemutakhiran terakhir" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Mutakhirkan Lokasi" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Dapatkan rilis-rilis bagi sebuah peranti" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Nama Pembaruan" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Dapatkan remote-remote yang terkonfigurasi" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Mutakhirkan ID Remote" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Turuntingkatkan firmware pada suatu peranti" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Ringkasan Pembaruan" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Segarkan metadata dari server remote" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Mutakhirkan Versi" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Kegagalan pembaruan adalah masalah yang telah diketahui, kunjungi URL ini untuk informasi lebih lanjut:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Perbarui sekarang?" + +msgid "Update the stored device verification information" +msgstr "Mutakhirkan informasi verifikasi perangkat yang tersimpan" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "Mutakhirkan metadata tersimpan dengan isi ROM saat ini" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Pantau daemon untuk kejadian" +msgid "Updates all firmware to latest versions available" +msgstr "Mutakhirkan semua firmware ke versi terbaru yang tersedia" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Memutakhirkan %s dari %s ke %s..." + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Pesan unggah:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Unggah laporan sekarang?" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nama Pengguna" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifikasi..." + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versi" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Menunggu..." #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Bangun firmware memakai suatu sandbox" +msgid "Watch DFU devices being hotplugged" +msgstr "Amati perangkat DFU yang sedang di-hotplug" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Curahkan data SMBIOS dari suatu berkas" +msgid "Write firmware from file into device" +msgstr "Tulis firmware dari berkas ke dalam perangkat" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Mengubah suatu remote yang diberikan" +msgid "Write firmware from file into one partition" +msgstr "Tulis firmware dari berkas ke dalam suatu partisi" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Utilitas Firmware" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Menulis..." diff -Nru fwupd-1.0.6/po/it.po fwupd-1.2.10/po/it.po --- fwupd-1.0.6/po/it.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/it.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,17 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Gianvito Cavasoli , 2016 -# Milo Casagrande , 2017-2018 +# Milo Casagrande , 2017-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Italian (http://www.transifex.com/freedesktop/fwupd/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,979 +16,1213 @@ "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Aggiorna firmware dispositivi su Linux" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Manca %.0f minuto" +msgstr[1] "Mancano %.0f minuti" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Questo progetto vuole rendere l'aggiornamento di firmware su Linux un processo automatico, sicuro e affidabile. È possibile usare uno strumento grafico come GNOME Software per visualizzare e applicare gli aggiornamenti, oppure lo strumento a riga di comando o l'interfaccia D-Bus." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Aggiornamento Consumer ME di %s" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Il processo fwupd è un demone che consente di aggiornare il firmware di un dispositivo sul proprio computer. È progettato per un ambiente desktop, ma è possibile utilizzarlo anche su telefonini, tablet e server." +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Aggiornamento unità di controllo %s" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Installa firmware firmato di sistema" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Aggiornamento Coporate ME di %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "È richiesto autenticarsi per aggiornare il firmware su questa macchina" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Aggiornamento dispositivo %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Installa firmware non firmato di sistema" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Aggiornamento unità di controllo integrata di %s" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Installa una vecchia versione del firmware di sistema" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Aggiornamento ME di %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "È richiesto autenticarsi tornare al precedente firmware su questa macchina" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Aggiornamento sistema %s" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Installa firmware firmato del dispositivo" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Aggiornamento di %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "È richiesto autenticarsi per aggiornare il firmware su un dispositivo rimovibile" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s ha degli aggiornamenti del firmware:" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Installa firmware non firmato del dispositivo" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u giorno" +msgstr[1] "%u giorni" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "È richiesto autenticarsi per tornare al precedente firmware su un dispositivo rimovibile" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u ora" +msgstr[1] "%u ore" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Sblocco del dispositivo per consentire l'accesso" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuto" +msgstr[1] "%u minuti" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "È richiesto autenticarsi per sbloccare un dispositivo" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u secondo" +msgstr[1] "%u secondi" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Aggiornamento delle informazioni di verifica del dispositivo salvate" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Attiva dispositivi" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "È richiesto autenticarsi per aggiornare il codice di controllo del dispositivo salvato" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Attiva i dispositivi in attesa" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Modifica un remoto configurato" +msgid "Activate the new firmware on the device" +msgstr "Attiva il nuovo firmware sul dispositivo" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "È richiesto autenticarsi per modificare un remoto configurato utilizzato per aggiornamenti firmware" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Attivazione aggiornamento firmware" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Attivazione aggiornamento firmware per" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Aggiunto" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Età" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Accettare e abilitare il remoto?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Alias di %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Comando non trovato" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Consente di tornare alle precedenti versioni del firmware" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Aggiunto" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Consente di reinstallare versioni del firmware esistenti" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Rimosso" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Per essere completato, un aggiornamento richiede un riavvio." -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Modificato" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Per essere completato, un aggiornamento richiede lo spegnimento del sistema." -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Annullato" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Risponde affermativamente a tutte le domande" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "Identificativo" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Applica una patch binaria" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nome" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Applica aggiornamenti firmware" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Cifratura" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Firmware approvato:" +msgstr[1] "Firmware approvati:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Regione" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Collega dispositivo DFU al runtime" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Trovato" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Collega in modalità firmware" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protocollo" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attributi" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Stato" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autenticazione…" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Permesso negato" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "È richiesto autenticarsi per tornare al precedente firmware su un dispositivo rimovibile" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Seriale" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "È richiesto autenticarsi tornare al precedente firmware su questa macchina" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Modalità" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "È richiesto autenticarsi per modificare un remoto configurato utilizzato per aggiornamenti firmware" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Runtime" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "È richiesto autenticarsi per modificare la configurazione del demone" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "È richiesto autenticarsi per impostare l'elenco dei firmware approvati" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Stato" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "È richiesto autenticarsi per firmare i dati utilizzando il certificato del client" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Dimensione trasferimento" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "È richiesto autenticarsi per passare alla nuova versione del firmware " -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Attributi" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "È richiesto autenticarsi per sbloccare un dispositivo" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Stranezze" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "È richiesto autenticarsi per aggiornare il firmware su un dispositivo rimovibile" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ID processore" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "È richiesto autenticarsi per aggiornare il firmware su questa macchina" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Converte il firmware nel formato DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "È richiesto autenticarsi per aggiornare il codice di controllo del dispositivo salvato" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Unisce più file di firmware in uno" +msgid "Build firmware using a sandbox" +msgstr "Compila il firmware utilizzando una sandbox" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Imposta l'identificativo del produttore sul file del firmware" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Annulla" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Imposta l'identificativo del prodotto sul file del firmware" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Annullato" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Imposta l'indirizzo dell'elemento sul file del firmware" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Modificato" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Imposta la dimensione del firmware per la destinazione" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Codice di controllo" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Imposta la versione di rilascio sul file del firmware" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID processore" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Imposta il numero alternativo sul file del firmware" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Scegliere un dispositivo:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Imposta il nome alternativo sul file del firmware" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Scegliere un rilascio:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Collega dispositivo DFU al runtime" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Cifratura" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Ripristina un dispositivo DFU" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Annulla gli aggiornamenti pianificati per essere eseguiti offline" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Legge il firmware dal dispositivo in un file" +msgid "Clears the results from the last update" +msgstr "Pulisce i risultati dell'ultimo aggiornamento" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Comando non trovato" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Legge il firmware da una partizione in un file" +msgid "Convert firmware to DFU format" +msgstr "Converte il firmware nel formato DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Scrive il firmware dal file nel dispositivo" +msgid "Create a binary patch using two files" +msgstr "Crea una patch binaria utilizzando due file" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Scrive il firmware dal file in una partizione" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Strumento DFU" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opzioni di debug" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Estrazione…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Elenca gli attuali dispositivi collegati con supporto DFU" +msgid "Decrypt firmware data" +msgstr "Decifra i dati del firmware" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Descrizione" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "Rimuove l'attuale dispositivo collegato con supporto DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Scarta informazioni su un file di firmware" +msgid "Detach to bootloader mode" +msgstr "Scollega in modalità bootloader" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Controlla i dispositivi DFU che sono collegati a caldo" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "ID dispositivo" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Cifra i dati del firmware" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Dispositivo aggiunto:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Decifra i dati del firmware" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Dispositivo modificato:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Dispositivo rimosso:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Dispositivi aggiornati con successo:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Dispositivi non aggiornati correttamente:" + +msgid "Disabled fwupdate debugging" +msgstr "Debug fwupdate disabilitato" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Imposta i metadati su un file di firmware" +msgid "Disables a given remote" +msgstr "Disabilita un remoto dato" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Visualizza la versione" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Non controlla i metadati vecchi" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Non controlla se è necessario riavviare dopo un aggiornamento" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Non controlla la cronologia non segnalata " + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Non scrive la cronologia" + +#. success +msgid "Done!" +msgstr "Fatto." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Sostituisce i dati su un file di firmware esistente" +msgid "Downgrades the firmware on a device" +msgstr "Ripristina una vecchia versione del firmare su un dispositivo" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Arretramento di %s da %s a %s..." + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Arretramento di %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Scaricamento…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Crea una patch binaria utilizzando due file" +msgid "Dump SMBIOS data from a file" +msgstr "Scarica i dati SMBIOS da un file" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Applica una patch binaria" +msgid "Dump details about a firmware file" +msgstr "Scarta informazioni su un file di firmware" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "Stampa le informazioni riguardo a una patch binaria su schermo" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "Caricamento stranezze non riuscito" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "ESP specificata non era valida" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Strumento DFU" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Abilita il supporto all'aggiornamento firmware sui sistemi compatibili" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Analisi degli argomenti non riuscita" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Abilitare questo remoto?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Elenca tutti i dispositivi Synaptics MST" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Abilitato" + +msgid "Enabled fwupdate debugging" +msgstr "Debug fwupdate abilitato" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Scrive il file di firmware sul dispositivo MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Strumento «Synaptics Multistream Transport»" +msgid "Enables a given remote" +msgstr "Abilita un remoto dato" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Installazione aggiornamento firmware…" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Abilitare questa funzionalità a proprio rischio: in caso di problemi con gli aggiornamenti sarà necessario contattare l'OEM. Solamente i problemi legati al processo di aggiornamento possono essere inviati a $OS_RELEASE:BUG_REPORT_URL$." -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Mostra le informazioni di debug per tutti i file" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Abilitare questo remoto a proprio rischio." -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Mostra informazioni dettagliate del plugin" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Cifra i dati del firmware" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opzioni di debug" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Elimina tutta la cronologia degli aggiornamenti firmware" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Mostra le opzioni di debug" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Eliminazione…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Esce dopo una breve attesa" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Esce dopo che il motore è stato caricato" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Demone di aggiornamento firmware" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Connessione al demone non riuscita" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Scaricamento non riuscito a causa di un limite sul server" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Recupero dei dispositivi in attesa non riuscito" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Installazione aggiornamento firmware non riuscita" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Servizio D-Bus di aggiornamento firmware" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Caricamento stranezze non riuscito" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Inattivo…" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Analisi degli argomenti non riuscita" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Estrazione…" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Riavvio non riuscito" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Impostazione della modalità splash non riuscita" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Caricamento…" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Recupero file" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Riavvio del dispositivo…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Recupero firmware" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Lettura…" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Recupero metadati" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Scrittura…" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Recupero firma" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Eliminazione…" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nome file" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Verifica…" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Firma nome file" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Pianificazione…" +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Strumento firmware" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Scaricamento…" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "URI di base del firmware" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Autenticazione…" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Servizio D-Bus di aggiornamento firmware" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Attesa…" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Demone di aggiornamento firmware" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Sconosciuto" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Strumento gestione firmware" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "I metadati del firmware non sono stati controllati per %u giorno e potrebbero non essere aggiornati." +msgstr[1] "I metadati del firmware non sono stati controllati per %u giorni e potrebbero non essere aggiornati." -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Scegliere un dispositivo:" +msgid "Firmware updates are not supported on this machine." +msgstr "Gli aggiornamenti firmware non sono supportati su questo dispositivo." -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "Gli aggiornamenti firmware sono supportati su questo dispositivo." -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Dispositivi non aggiornati correttamente:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Flag" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Dispositivi aggiornati con successo:" +msgid "Force the action ignoring all warnings" +msgstr "Forza l'azione ignorando gli avvisi" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Caricare il rapporto ora?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Trovato" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Richiede una connessione a Internet" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Non è stato rilevato nessun hardware con capacità di aggiornamento del firmware" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Recupera tutti i dispositivi in base alla topologia di sistema" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Reinstallazione di %s con %s..." +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Ottiene tutti i dispositivi e i possibili rilasci" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Ottiene tutti i dispositivi che supportano gli aggiornamenti del firmware" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Recupera tutti i plugin registrati nel sistema" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Ottiene le informazioni su un file di firmware" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Ottiene i remoti configurati" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Ottiene l'hash crittografico del firmware scartato" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Recupera l'elenco dei firmware approvati." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Ottiene l'elenco degli aggiornamenti per l'hardware connesso" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Ottiene i rilasci di un dispositivo" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Ottiene i risultati dell'ultimo aggiornamento" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Identificativo" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Inattivo…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Installa blob firmware su un dispositivo" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Installa un file di firmware su questo hardware" + +msgid "Install old version of system firmware" +msgstr "Installa una vecchia versione del firmware di sistema" + +msgid "Install signed device firmware" +msgstr "Installa firmware firmato del dispositivo" + +msgid "Install signed system firmware" +msgstr "Installa firmware firmato di sistema" + +msgid "Install unsigned device firmware" +msgstr "Installa firmware non firmato del dispositivo" + +msgid "Install unsigned system firmware" +msgstr "Installa firmware non firmato di sistema" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Installazione firmware…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Installazione aggiornamento firmware…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Arretramento di %s da %s a %s..." +msgid "Installing on %s…" +msgstr "Installazione su %s…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Keyring" +msgstr "Portachiavi" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Manca meno di un minuto" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (firmware stabile)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (firmware in prova)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Elenca gli attuali dispositivi collegati con supporto DFU" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Elenca gli aggiornamenti firmware supportati" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Caricamento…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Abilita manualmente plugin specifici" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Unisce più file di firmware in uno" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI metadati" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Firma URI dei metadati" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadati possono essere scaricati da Linux Vendor Firmware Service." + +#. TRANSLATORS: error message #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Aggiornamento di %s da %s a %s..." +msgid "Mismatched daemon and client, use %s instead" +msgstr "Versioni di demone e client non corrispondenti, usare %s" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Fatto." +msgid "Mode" +msgstr "Modalità" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Obiettivo" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Modifica il valore della configurazione del demone" + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modifica un remoto" + +msgid "Modify a configured remote" +msgstr "Modifica un remoto configurato" + +msgid "Modify daemon configuration" +msgstr "Modifica la configurazione del demone" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Controlla il demone per gli eventi" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nome" + +msgid "No action specified!" +msgstr "Nessuna azione specificata." + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Non è stato rilevato nessun hardware con capacità di aggiornamento del firmware" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Non è stato trovato alcun plugin" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Non è abilitato alcun remoto e non sono disponibili metadati." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Non è stato applicato alcun aggiornamento" + +msgid "OK" +msgstr "Fatto" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Scavalca l'avviso sul plugin" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Sovrascrive il percorso ESP predefinito" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Scavalca gli avvisi e forza l'azione" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Password" -#: src/fu-util.c:727 msgid "Payload" msgstr "Carico" -#: src/fu-util.c:728 +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Percentuale completamento" + +msgid "Permission denied" +msgstr "Permesso negato" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Inserire un numero tra 0 e %u:" + +msgid "Print the version number" +msgstr "Stampa il numero di versione" + +msgid "Print verbose debug statements" +msgstr "Stampa messaggi di debug prolissi" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorità" + msgid "Proceed with upload?" msgstr "Procedere con il caricamento?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Questo è un problema noto, consultare il seguente URL per maggiori informazioni:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protocollo" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Messaggio di caricamento:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Interroga il supporto per gli aggiornamenti firmware" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "Fatto" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Stranezze" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Recupero firma" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Legge il firmware dal dispositivo in un file" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Recupero metadati" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Legge il firmware da una partizione in un file" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Recupero firmware" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lettura…" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Recupero file" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Riavvio…" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Versione" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Ricarica i metadati dal server remoto" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Riepilogo" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Regione" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Reinstallazione di %s con %s..." #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Remoto" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "ID remoto" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Descrizione" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Rimosso" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Codice di controllo" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Sostituisce i dati su un file di firmware esistente" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Scegliere un rilascio:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI del rapporto" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "I metadati del firmware non sono stati controllati per %u giorno e potrebbero non essere aggiornati." -msgstr[1] "I metadati del firmware non sono stati controllati per %u giorni e potrebbero non essere aggiornati." +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Richiede una connessione a Internet" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Aggiornare ora?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Ripristina un dispositivo DFU" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s ha degli aggiornamenti del firmware:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Riavviare ora?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Riavviare il demone per applicare le modifiche?" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Versione aggiornamento" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Riavvio del dispositivo…" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Nome aggiornamento" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Fornisce tutti gli ID hardware per un dispositivo" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Riepilogo aggiornameto" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Esegue la procedura di pulizia del plugin quando si utilizza install-blob" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "ID remoto aggiornamento" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Esegue la procedura di preparazione del plugin quando si utilizza install-blob" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Codice di controllo aggiornamento" +msgid "Runtime" +msgstr "Runtime" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Posizione aggiornamento" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Salva lo stato del dispositivo tra le esecuzioni su un file JSON" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Descrizione aggiornamento" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Pianifica l'installazione al prossimo riavvio quando è possibile" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "ID remoto" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Pianificazione…" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Titolo" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Seriale" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Imposta il nome alternativo sul file del firmware" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Imposta il numero alternativo sul file del firmware" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Imposta l'indirizzo dell'elemento sul file del firmware" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Imposta l'identificativo del prodotto sul file del firmware" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Imposta la versione di rilascio sul file del firmware" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Imposta il flag di debug durante l'aggiornamento" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Imposta la dimensione del firmware per la destinazione" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Imposta l'identificativo del produttore sul file del firmware" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Imposta i metadati su un file di firmware" + +msgid "Sets the list of approved firmware" +msgstr "Imposta l'elenco dei firmware approvati" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Imposta l'elenco dei firmware approvati." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Condivide la cronologia del firmware con gli sviluppatori" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Mostra la versione del client e del demone" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Mostra informazioni prolisse del demone per un dominio" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Mostra informazioni di debug per tutti i domini" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostra le opzioni di debug" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Mostra dispositivi non aggiornabili" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mostra maggiori informazioni di debug" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Tipo" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Mostra la cronologia degli aggiornamenti firmware" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Portachiavi" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Mostra informazioni dettagliate del plugin" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Abilitato" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Mostra debug dell'ultimo tentativo di aggiornamento" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Età" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Mostra informazioni sullo stato degli aggiornamenti firmware" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Priorità" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Spegnere ora?" + +msgid "Sign data using the client certificate" +msgstr "Firma i dati col certificato del client" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Firma i dati col certificato del client" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Nome utente" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Firma i dati caricati col certificato del client" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Password" +msgid "Signature" +msgstr "Firma" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Nome file" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Specifica vendor/ID prodotto di un dispositivo DFU" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Firma nome file" +msgid "Specify the number of bytes per USB transfer" +msgstr "Specifica il numero di byte per trasferimento USB" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI metadati" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Stato" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Firma URI dei metadati" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Stato" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "URI di base del firmware" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Riepilogo" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "URI del rapporto" +msgid "Target" +msgstr "Obiettivo" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Dispositivo aggiunto:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS è un servizio gratuito che opera come entità legale indipendente e non ha alcun legame con $OS_RELEASE:NAME$. Il distributore potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o con i propri dispositivi collegati. Il firmware viene fornito solamente dall'OEM." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Non ci sono firmware approvati." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Questo programma può funzionare correttamente solo come utente root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Questo remoto contiene firmware che non è bloccato, ma è ancora in fase di verifica dal produttore hardware. Assicurarsi di poter ripristinare, manualmente o con altre procedure, il vecchio firmware nel caso in cui l'aggiornamento non riuscisse." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Questo strumento può essere usato solamente dall'utente root" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Dispositivo rimosso:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titolo" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Dispositivo modificato:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Dimensione trasferimento" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Per essere completato, un aggiornamento richiede un riavvio." +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipo" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "Riavviare ora?" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Strumento firmware UEFI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Mostra maggiori informazioni di debug" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Mostra la versione del client e del demone" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Sconosciuto" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Pianifica l'installazione al prossimo riavvio quando è possibile" +msgid "Unlock the device to allow access" +msgstr "Sblocco del dispositivo per consentire l'accesso" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Consente di reinstallare versioni del firmware esistenti" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Sblocca il dispositivo per accedere al firmware" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Consente di tornare alle precedenti versioni del firmware" +msgid "Unset the debugging flag during update" +msgstr "Ripristina il flag di debug durante l'aggiornamento" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Scavalca l'avviso sul plugin" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Demone versione %s non supportato, la versione del client è %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Risponde affermativamente a tutte le domande" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Codice di controllo aggiornamento" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Non controlla la cronologia non segnalata " +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Descrizione aggiornamento" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Non controlla i metadati vecchi" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Durata aggiornamento" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Non controlla se è necessario riavviare dopo un aggiornamento" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Posizione aggiornamento" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Ottiene tutti i dispositivi che supportano gli aggiornamenti del firmware" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Nome aggiornamento" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Fornisce tutti gli ID hardware per un dispositivo" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "ID remoto aggiornamento" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Installa ora gli aggiornamenti preparati" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Riepilogo aggiornameto" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Mostra la cronologia degli aggiornamenti firmware" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Versione aggiornamento" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Elimina tutta la cronologia degli aggiornamenti firmware" +msgid "Update all devices that match local metadata" +msgstr "Aggiorna tutti i dispositivi corrispondenti ai metadati locali" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Condivide la cronologia del firmware con gli sviluppatori" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Questo è un problema noto, consultare il seguente URL per maggiori informazioni:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Installa un file di firmware su questo hardware" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Aggiornare ora?" + +msgid "Update the stored device verification information" +msgstr "Aggiornamento delle informazioni di verifica del dispositivo salvate" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Ottiene le informazioni su un file di firmware" +msgid "Update the stored metadata with current ROM contents" +msgstr "Aggiorna i metadati salvati con gli attuali contenuti della ROM" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Ottiene l'elenco degli aggiornamenti per l'hardware connesso" +msgid "Update the stored metadata with current contents" +msgstr "Aggiorna i metadati salvati con il contenuto attuale" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Aggiorna tutti i firmware all'ultima versione disponibile" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Ottiene l'hash crittografico del firmware scartato" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Aggiornamento di %s da %s a %s..." -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Sblocca il dispositivo per accedere al firmware" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Aggiornamento di %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Pulisce i risultati dell'ultimo aggiornamento" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Messaggio di caricamento:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Annulla gli aggiornamenti pianificati per essere eseguiti offline" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Caricare il rapporto ora?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Ottiene i risultati dell'ultimo aggiornamento" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Inviare resoconti sul firmware aiuta gli sviluppatori a identificare velocemente aggiornamenti eseguiti con successo o non riusciti su dispositivi reali." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Ottiene i rilasci di un dispositivo" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nome utente" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Ottiene i remoti configurati" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifica…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Ripristina una vecchia versione del firmare su un dispositivo" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versione" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Ricarica i metadati dal server remoto" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Attesa…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Aggiorna i metadati salvati con gli attuali contenuti della ROM" +msgid "Watch DFU devices being hotplugged" +msgstr "Controlla i dispositivi DFU che sono collegati a caldo" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Controlla il demone per gli eventi" +msgid "Watch for hardware changes" +msgstr "Controlla le modifiche hardware" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Compila il firmware utilizzando una sandbox" +msgid "Write firmware from file into device" +msgstr "Scrive il firmware dal file nel dispositivo" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Scarica i dati SMBIOS da un file" +msgid "Write firmware from file into one partition" +msgstr "Scrive il firmware dal file in una partizione" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Modifica un remoto" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Scrittura…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Strumento gestione firmware" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "La propria distribuzione potrebbe non aver verificato la compatibilità degli aggiornamenti firmware col proprio sistema o col dispositivo collegato." diff -Nru fwupd-1.0.6/po/its/appdata.its fwupd-1.2.10/po/its/appdata.its --- fwupd-1.0.6/po/its/appdata.its 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/its/appdata.its 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,14 @@ + + + + + diff -Nru fwupd-1.0.6/po/its/appdata.loc fwupd-1.2.10/po/its/appdata.loc --- fwupd-1.0.6/po/its/appdata.loc 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/its/appdata.loc 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,9 @@ + + + + + + + + + diff -Nru fwupd-1.0.6/po/kk.po fwupd-1.2.10/po/kk.po --- fwupd-1.0.6/po/kk.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/kk.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Baurzhan Muftakhidinov , 2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-09-01 14:26+0100\n" -"PO-Revision-Date: 2017-09-01 13:27+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Kazakh (http://www.transifex.com/freedesktop/fwupd/language/kk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,803 +15,35 @@ "Language: kk\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: libdfu/dfu-tool.c:121 plugins/synapticsmst/synapticsmst-tool.c:115 -#: src/fu-util.c:112 -#, c-format -msgid "Alias to %s" -msgstr "" - -#. TRANSLATORS: error message -#: libdfu/dfu-tool.c:194 plugins/synapticsmst/synapticsmst-tool.c:362 -#: src/fu-util.c:176 -msgid "Command not found" -msgstr "" - -#. TRANSLATORS: read from device to host -#: libdfu/dfu-tool.c:1236 -msgid "Reading" -msgstr "Оқылуда" - -#. TRANSLATORS: write from host to device -#: libdfu/dfu-tool.c:1242 -msgid "Writing" -msgstr "Жазылуда" - -#. TRANSLATORS: read from device to host -#: libdfu/dfu-tool.c:1248 -msgid "Verifying" -msgstr "Тексерілуде" - -#. TRANSLATORS: read from device to host -#: libdfu/dfu-tool.c:1254 -msgid "Erasing" -msgstr "Өшірілуде" - -#. TRANSLATORS: waiting for device -#: libdfu/dfu-tool.c:1260 -msgid "Detaching" -msgstr "" - -#. TRANSLATORS: waiting for device -#: libdfu/dfu-tool.c:1266 -msgid "Attaching" -msgstr "" - #. TRANSLATORS: this is when a device is hotplugged -#: libdfu/dfu-tool.c:1487 msgid "Added" msgstr "Қосылған" -#. TRANSLATORS: this is when a device is hotplugged -#: libdfu/dfu-tool.c:1498 -msgid "Removed" -msgstr "Өшірілген" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Бас тартылған" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: libdfu/dfu-tool.c:1507 src/fu-util.c:1251 msgid "Changed" msgstr "Өзгертілген" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: libdfu/dfu-tool.c:1515 src/fu-util.c:1213 -msgid "Cancelled" -msgstr "Бас тартылған" - -#. TRANSLATORS: Appstream ID for the hardware type -#: libdfu/dfu-tool.c:2024 src/fu-util.c:1040 -msgid "ID" -msgstr "" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#: libdfu/dfu-tool.c:2030 libdfu/dfu-tool.c:2036 libdfu/dfu-tool.c:2123 -msgid "Name" -msgstr "" - -#. TRANSLATORS: this is the encryption method used when writing -#: libdfu/dfu-tool.c:2043 -msgid "Cipher" -msgstr "" - -#. TRANSLATORS: these are areas of memory on the chip -#: libdfu/dfu-tool.c:2057 -msgid "Region" -msgstr "" - -#. TRANSLATORS: detected a DFU device -#: libdfu/dfu-tool.c:2092 -msgid "Found" -msgstr "" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: libdfu/dfu-tool.c:2100 -msgid "Protocol" -msgstr "" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: libdfu/dfu-tool.c:2112 libdfu/dfu-tool.c:2115 libdfu/dfu-tool.c:2138 -msgid "Status" -msgstr "" - -#: libdfu/dfu-tool.c:2112 -msgid "Unknown: permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: libdfu/dfu-tool.c:2129 -msgid "Serial" -msgstr "" - -#. TRANSLATORS: device mode, e.g. runtime or DFU -#: libdfu/dfu-tool.c:2134 -msgid "Mode" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: libdfu/dfu-tool.c:2142 -msgid "State" -msgstr "" - -#. TRANSLATORS: transfer size in bytes -#: libdfu/dfu-tool.c:2150 -msgid "Transfer Size" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: libdfu/dfu-tool.c:2158 -msgid "Quirks" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2237 -msgid "Convert firmware to DFU format" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2243 -msgid "Merge multiple firmware files into one" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2249 -msgid "Set vendor ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2255 -msgid "Set product ID on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2261 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2267 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2273 -msgid "Set release version on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2279 -msgid "Set alternative number on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2285 -msgid "Set alternative name on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2291 -msgid "Attach DFU capable device back to runtime" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2297 -msgid "Read firmware from device into a file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2303 -msgid "Read firmware from one partition into a file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2309 -msgid "Write firmware from file into device" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2315 -msgid "Write firmware from file into one partition" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2321 -msgid "List currently attached DFU capable devices" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2327 -msgid "Detach currently attached DFU capable device" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2333 -msgid "Dump details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2339 -msgid "Watch DFU devices being hotplugged" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2345 -msgid "Encrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2351 -msgid "Decrypt firmware data" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2357 -msgid "Sets metadata on a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2363 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2369 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2375 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: libdfu/dfu-tool.c:2381 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: libdfu/dfu-tool.c:2407 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: libdfu/dfu-tool.c:2412 plugins/synapticsmst/synapticsmst-tool.c:439 -#: src/fu-util.c:1733 -msgid "Failed to parse arguments" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:408 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:414 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:434 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:194 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:130 -msgid "Show debugging information for all files" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:180 -msgid "Debugging Options" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:182 -msgid "Show debugging options" -msgstr "" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:863 -msgid "Exit after a small delay" -msgstr "" - -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:866 -msgid "Exit after the engine has loaded" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-main.c:880 -msgid "Firmware Update Daemon" -msgstr "" - -#. TRANSLATORS: program summary -#: src/fu-main.c:885 -msgid "Firmware Update D-Bus Service" -msgstr "" - -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:51 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:55 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:59 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:63 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:67 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:71 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:75 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:79 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:86 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:234 -#, c-format -msgid "Please enter a number from 1 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:277 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:303 -msgid "No hardware detected with firmware update capability" -msgstr "" - -#. TRANSLATOR: the plugin only supports offline -#: src/fu-util.c:337 -msgid "Retrying as an offline update" -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:501 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:508 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:516 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "" - -#: src/fu-util.c:543 -msgid "Done!" -msgstr "" - -#: src/fu-util.c:585 src/fu-util.c:985 -msgid "OK" -msgstr "" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:719 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:722 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:725 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:728 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:898 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:901 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:907 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:915 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:947 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1036 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1046 -msgid "GUID" -msgstr "" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1050 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1054 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1063 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1067 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1078 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1104 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1108 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1113 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1118 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1145 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1152 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1157 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1162 -msgid "Password" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1167 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1172 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: locatation of the local file -#: src/fu-util.c:1177 -msgid "Location" -msgstr "" - -#. TRANSLATORS: locatation of the local file -#: src/fu-util.c:1182 -msgid "Location Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1187 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1192 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1197 -msgid "Firmware Base URI" -msgstr "" +#. TRANSLATORS: read from device to host +msgid "Erasing" +msgstr "Өшірілуде" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1224 -msgid "Device added:" -msgstr "" +#. TRANSLATORS: read from device to host +msgid "Reading" +msgstr "Оқылуда" #. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1234 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1244 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:1568 -msgid "Show extra debugging information" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:1571 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:1574 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:1577 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:1580 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:1583 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1607 -msgid "Get all devices that support firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1613 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1619 -msgid "Install prepared updates now" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1625 -msgid "Install a firmware file on this hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1631 -msgid "Gets details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1637 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1643 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1649 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1655 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1661 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1667 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1673 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1679 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1685 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1691 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1697 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:1703 -msgid "Monitor the daemon for events" -msgstr "" +msgid "Removed" +msgstr "Өшірілген" -#. TRANSLATORS: command description -#: src/fu-util.c:1709 -msgid "Build firmware using a sandbox" -msgstr "" +#. TRANSLATORS: read from device to host +msgid "Verifying" +msgstr "Тексерілуде" -#. TRANSLATORS: program name -#: src/fu-util.c:1728 -msgid "Firmware Utility" -msgstr "" +#. TRANSLATORS: write from host to device +msgid "Writing" +msgstr "Жазылуда" diff -Nru fwupd-1.0.6/po/ko.po fwupd-1.2.10/po/ko.po --- fwupd-1.0.6/po/ko.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/ko.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,17 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Seong-ho Cho , 2017 -# Shinjo Park , 2018 +# Seong-ho Cho , 2017,2019 +# Shinjo Park , 2018-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Korean (http://www.transifex.com/freedesktop/fwupd/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,978 +16,1206 @@ "Language: ko\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "리눅스에서 장치 펌웨어를 업데이트합니다" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "이 프로젝트에서는 리눅스에서 자동으로 안전하고 믿을 수 있게 펌웨어를 업데이트할 수 있게 하려고 합니다. 업데이트를 보고 적용할 때 그놈 소프트웨어, 명령행 도구를 쓰거나 D-Bus 인터페이스를 바로 쓸 수 있습니다." +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f분 남음" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 프로세스는 로컬 머신의 장치 펌웨어를 세션 프로그램에서 업데이트할 수 있게 하는 간단한 데몬입니다. 데스크톱용으로 설계했지만, 전화기, 태블릭, 헤드리스 서버에서도 사용할 수 있습니다." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "%s 소비자용 ME 업데이트" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "서명한 시스템 펌웨어 설치" +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "%s 컨트롤러 업데이트" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "이 머신의 펌웨어를 업데이트하려면 인증이 필요합니다" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "%s 기업용 ME 업데이트" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "서명하지 않은 시스템 펌웨어 설치" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "%s 장치 업데이트" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "시스템 펌웨어 이전 버전 설치" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "%s 임베디드 컨트롤러 업데이트" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "이 머신에 이전 버전의 펌웨어를 설치하려면 인증이 필요합니다" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "%s ME 업데이트" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "서명한 장치 펌웨어 설치" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "%s 시스템 업데이트" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "이동식 장치의 펌웨어를 업데이트하려면 인증이 필요합니다" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "%s 업데이트" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "서명하지 않은 장치 펌웨어 설치" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s의 최신 펌웨어가 있습니다:" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "이동식 장치의 펌웨어를 이전 버전으로 되돌리려면 인증이 필요합니다" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u일" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "접근을 허용하려면 장치 잠금을 해제하십시오" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u시간" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "장치 잠금을 해제하려면 인증이 필요합니다" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u분" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "보관된 장치 검증 정보 업데이트" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u초" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "장치 보관 검사합을 업데이트하려면 인증이 필요합니다 " +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "장치 활성화" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "원격 설정 수정" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "대기 중인 장치 활성화" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "펌웨어 업데이트에 사용할 원격 설정을 수정하려면 인증이 필요합니다" +msgid "Activate the new firmware on the device" +msgstr "장치에 새 펌웨어 활성화" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "%s(으)로 별칭 부여" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "펌웨어 업데이트 활성화 중" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "명령을 찾을 수 없습니다" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "다음 장치의 펌웨어 업데이트 활성화 중:" #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 msgid "Added" msgstr "추가함" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "제거함" - -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "바뀜" - -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "취소함" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "이름" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "경과 기간" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "암호화 방식" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "동의하며 원격 설정을 활성화하시겠습니까?" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "메모리 영역" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "%s의 별칭" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "감지 장치" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "펌웨어 다운그레이드를 허용합니다" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "프로토콜" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "기존 펌웨어 버전 재설치를 허용합니다" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "장치 상태" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "업데이트를 완료하려면 다시 시작해야 합니다." -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "권한 거부" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "업데이트를 완료하려면 시스템을 종료해야 합니다." -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "시리얼" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "모든 질문에 예로 답하기" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "모드" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "바이너리 패치 적용" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "펌웨어 업데이트 적용" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "허용 펌웨어:" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "상태" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "DFU 기능 장치를 런타임에 연결" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "전송 용량" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "펌웨어 모드에 연결" #. TRANSLATORS: device attributes, i.e. things that #. * the device can do -#: plugins/dfu/dfu-tool.c:2139 msgid "Attributes" msgstr "속성" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "특이사항" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "인증 중…" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "칩 ID" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "이동식 장치의 펌웨어를 이전 버전으로 되돌리려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "펌웨어를 DFU 형식으로 변환" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "이 머신에 이전 버전의 펌웨어를 설치하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "다중 펌웨어 파일을 하나로 병합" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "펌웨어 업데이트에 사용할 원격 설정을 수정하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "펌웨어 파일의 제조자 ID 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "데몬 설정을 수정하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "펌웨어 파일의 제품 ID 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "허용된 펌웨어 목록을 설정하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "펌웨어 파일의 구성요소 주소 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "클라이언트 인증서로 데이터를 서명하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "대상 펌웨어 크기 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "새 펌웨어 버전으로 전환하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "펌웨어 파일의 출시 버전 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "장치 잠금을 해제하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "펌웨어 파일의 대체 번호 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "이동식 장치의 펌웨어를 업데이트하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "펌웨어 파일의 대체 명칭 설정" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "이 머신의 펌웨어를 업데이트하려면 인증해야 합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "DFU 기능 장치를 런타임에 연결" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "저장된 체크섬을 업데이트하려면 인증해야 합니다" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "DFU 장치 초기화" +msgid "Build firmware using a sandbox" +msgstr "샌드박스에서 펌웨어를 빌드합니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "장치 펌웨어를 읽어 파일에 기록" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "취소" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "파티션의 펌웨어를 읽어 파일에 기록" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "취소함" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "파일의 펌웨어를 장치에 기록" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "바뀜" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "파일의 펌웨어를 파티션 하나에 기록" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "체크섬" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "현재 연결한 DFU 기능 장치 목록 보기" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "칩 ID" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "현재 연결한 DFU 기능 장치 분리" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "장치를 선택하십시오:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "펌웨어 파일 세부 정보 덤프" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "출시 버전을 선택하십시오:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "DFU 핫 플러그 장치 보기" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "암호화 방식" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "펌웨어 데이터 암호화" +msgid "Clears any updates scheduled to be updated offline" +msgstr "오프라인으로 업데이트할 업데이트를 지웁니다" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "펌웨어 데이터 복호화" +msgid "Clears the results from the last update" +msgstr "최근 업데이트 결과를 지웁니다" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "펌웨어 파일의 메타데이터 설정" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "명령을 찾을 수 없습니다" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "기존 펌웨어 파일의 데이터 교체" +msgid "Convert firmware to DFU format" +msgstr "펌웨어를 DFU 형식으로 변환" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 msgid "Create a binary patch using two files" -msgstr "파일 두 개를 활용하여 바이너리 패치 만들기" +msgstr "파일 두 개를 사용하여 바이너리 패치 만들기" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "바이너리 패치 적용" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "바이너리 패치 정보 덤프 스크린에 출력" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" +msgid "DFU" +msgstr "DFU" #. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 msgid "DFU Utility" msgstr "DFU 유틸리티" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "인자 해석에 실패했습니다" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "모든 시냅틱스 MST 장치에 열거 번호를 부여합니다" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "MST 장치에 펌웨어 파일을 기록합니다" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "시냅틱스 멀티스트림 전송 유틸리티" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "펌웨어 업데이트 설치 중…" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "모든 파일의 디버깅 정보 표시" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "자세한 플러그인 정보 표시" - #. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 msgid "Debugging Options" msgstr "디버깅 옵션" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "디버깅 옵션을 표시합니다" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "짧은 대기 시간 경과 후 나가기" - -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "엔진을 불러온 후 나가기" - -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "펌웨어 업데이트 데몬" - -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "펌웨어 업데이트 D-Bus 서비스" - -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "대기 중…" - #. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 msgid "Decompressing…" msgstr "압축 해제 중…" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "불러오는 중…" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "장치 다시 시작하는 중…" +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "펌웨어 데이터 복호화" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "읽는 중…" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "설명" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "쓰는 중…" +#. TRANSLATORS: command description +msgid "Detach currently attached DFU capable device" +msgstr "현재 연결한 DFU 기능 장치 분리" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "지우는 중…" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "부트로더 모드로 전환" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "검증 중…" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "장치 ID" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "작업 계획 중…" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "장치 추가됨:" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "내려받는 중…" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "장치 상태 바뀜:" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "인증 중…" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "장치 제거됨:" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "기다리는 중…" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "성공적으로 업데이트된 장치:" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "알 수 없음" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "올바르게 업데이트되지 않은 장치:" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Disabled fwupdate debugging" +msgstr "fwupdate 디버깅 비활성화" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "장치를 선택하십시오:" +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "지정한 원격 정보를 비활성화합니다" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "버전 표시" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "오래된 메타데이터 검사하지 않기" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "업데이트 후 다시 시작 검사하지 않기" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "보고되지 않은 과거 기록 검사하지 않기" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "과거 기록 데이터베이스에 기록하지 않기" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "펌웨어 업데이트가 가능한 하드웨어가 없습니다" +#. success +msgid "Done!" +msgstr "완료!" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "%2$s(으)로 %1$s 다시 설치하는 중... " +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "장치 펌웨어 버전을 이전으로 되돌립니다" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second and third are #. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 #, c-format msgid "Downgrading %s from %s to %s... " msgstr "%2$s에서 %3$s(으)로 %1$s 다운그레이드 중... " -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s... " -msgstr "%2$s에서 %3$s(으)로 %1$s 업데이트 중... " +msgid "Downgrading %s…" +msgstr "%s 다운그레이드 중..." -#: src/fu-util.c:694 -msgid "Done!" -msgstr "완료!" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "다운로드 중…" -#: src/fu-util.c:726 -msgid "Target" -msgstr "" +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "파일에 저장된 SMBIOS 데이터 덤프를 출력합니다" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +#. TRANSLATORS: command description +msgid "Dump details about a firmware file" +msgstr "펌웨어 파일 세부 정보 출력" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "바이너리 패치 정보를 화면으로 출력" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "지정한 ESP가 올바르지 않습니다" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "지원하는 시스템의 펌웨어 업데이트 지원 활성화" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "확인" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "이 원격 설정을 활성화하시겠습니까?" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "서명 가져오는 중" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "활성화 여부" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "메타데이터 가져오는 중" +msgid "Enabled fwupdate debugging" +msgstr "fwupdate 디버깅 활성화" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "펌웨어 가져오는 중" +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "지정한 원격 정보를 활성화합니다" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "파일 가져오는 중" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "이 기능의 사용은 본인의 책임이며, 업데이트로 인해서 생긴 문제는 원 장치 제조사에 직접 보고해야 합니다. 업데이트 진행 과정 자체의 문제는 $OS_RELEASE:BUG_REPORT_URL$(으)로 보고해 주십시오." -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "버전" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "이 원격 장치를 설정하는 것은 본인의 책임입니다." -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "펌웨어 데이터 암호화" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "원격" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "모든 펌웨어 업데이트 기록 지우기" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "지우는 중…" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "설명" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "짧은 대기 시간 경과 후 나가기" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "검사합" +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "엔진을 불러온 후 나가기" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "출시 버전을 선택하십시오:" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "데몬에 연결할 수 없음" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "서버 제한으로 파일을 다운로드할 수 없음" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "대기 중인 장치를 가져올 수 없음" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "펌웨어 업데이트를 설치할 수 없음" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "특이 사항을 불러올 수 없음" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "인자 해석에 실패했습니다" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s의 최신 펌웨어가 있습니다:" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "다시 시작할 수 없음" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "스플래시 모드를 설정할 수 없음" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "파일 가져오는 중" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "업데이트 버전" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "펌웨어 가져오는 중" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "메타데이터 가져오는 중" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "서명 가져오는 중" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "파일 이름" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "파일 이름 서명" + +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "펌웨어 에이전트" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "펌웨어 기본 URI" + +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "펌웨어 업데이트 D-Bus 서비스" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "펌웨어 업데이트 데몬" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "펌웨어 유틸리티" + +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "펌웨어 메타데이터가 %u일 동안 업데이트되지 않았으므로 최신 정보가 누락되었을 수도 있습니다." + +msgid "Firmware updates are not supported on this machine." +msgstr "이 머신에서 펌웨어 업데이트를 지원하지 않습니다." + +msgid "Firmware updates are supported on this machine." +msgstr "이 머신에서 펌웨어 업데이트를 지원합니다." + +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "플래그" + +msgid "Force the action ignoring all warnings" +msgstr "모든 경고를 무시하고 작업 강제 진행" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "감지 장치" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "시스템에 연결된 순서대로 모든 장치 목록 가져오기" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "모든 장치와 릴리스 가져오기" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "펌웨어 업데이트를 지원하는 모든 장치 정보를 가져옵니다" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "시스템에 등록된 모든 활성 플러그인 가져오기" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "펌웨어 파일 세부 정보를 가져옵니다" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "원격 설정 정보를 가져옵니다" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "덤프한 펌웨어의 암호화 해시 정보를 가져옵니다" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "허용된 펌웨어 목록을 가져옵니다." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "연결한 하드웨어의 업데이트 목록을 가져옵니다" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "장치 펌웨어 릴리스를 가져옵니다" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "최근 업데이트 결과를 가져옵니다" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "대기 중…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "장치에 펌웨어 파일 설치" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "이 하드웨어에 펌웨어 파일을 설치합니다" + +msgid "Install old version of system firmware" +msgstr "이전 버전 시스템 펌웨어 설치" + +msgid "Install signed device firmware" +msgstr "서명된 장치 펌웨어 설치" + +msgid "Install signed system firmware" +msgstr "서명된 시스템 펌웨어 설치" + +msgid "Install unsigned device firmware" +msgstr "서명되지 않은 장치 펌웨어 설치" + +msgid "Install unsigned system firmware" +msgstr "서명되지 않은 시스템 펌웨어 설치" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "펌웨어 설치 중..." + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "펌웨어 업데이트 설치 중…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "%s에 설치 중..." + +msgid "Keyring" +msgstr "키 모음" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "1분 미만 남음" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "리눅스 제조사 펌웨어 서비스(안정 버전 펌웨어)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "리눅스 제조사 펌웨어 서비스(테스트 버전 펌웨어)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "현재 연결한 DFU 기능 장치 목록 보기" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "지원하는 펌웨어 업데이트 목록 표시" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "불러오는 중…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "지정한 플러그인을 수동으로 허용 목록에 추가" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "다중 펌웨어 파일을 하나로 병합" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "메타데이터 URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "메타데이터 URI 서명" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "리눅스 제조사 펌웨어 서비스에서 메타데이터를 가져올 수 있습니다." + +#. TRANSLATORS: error message +#, c-format +msgid "Mismatched daemon and client, use %s instead" +msgstr "데몬과 클라이언트가 일치하지 않음, %s을(를) 대신 사용함" + +msgid "Mode" +msgstr "모드" + +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "데몬 설정값을 변경합니다." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "지정한 원격 정보를 수정합니다" + +msgid "Modify a configured remote" +msgstr "원격 설정 수정" + +msgid "Modify daemon configuration" +msgstr "데몬 설정 수정" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "데몬 이벤트를 감시합니다" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "이름" + +msgid "No action specified!" +msgstr "동작을 지정하지 않았습니다!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "펌웨어를 업데이트할 수 있는 하드웨어가 없음" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "플러그인을 찾을 수 없음" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "원격 자원이 설정되지 않았으므로 메타데이터를 사용할 수 없습니다." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "적용된 업데이트 없음" + +msgid "OK" +msgstr "확인" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "플러그인 경고 무시" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "기본 ESP 경로 재정의" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "경고를 무시하고 강제로 작업 진행" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "암호" + +msgid "Payload" +msgstr "페이로드" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "진행률" + +msgid "Permission denied" +msgstr "권한 거부" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "0에서 %u까지의 숫자 중 하나를 입력하십시오:" + +msgid "Print the version number" +msgstr "버전 번호 표시" + +msgid "Print verbose debug statements" +msgstr "자세한 디버그 정보 표시" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "우선 순위" + +msgid "Proceed with upload?" +msgstr "업로드를 진행하시겠습니까?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "프로토콜" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "펌웨어 업데이트 지원 조회" + +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "특이 사항" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "장치 펌웨어를 읽어 파일에 기록" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "파티션에서 펌웨어를 읽어 파일에 기록" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "읽는 중…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "다시 시작하는 중..." + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "원격 서버의 메타데이터를 새로 고칩니다" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "메모리 영역" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "%2$s(으)로 %1$s 다시 설치하는 중... " + +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "원격" + +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "원격 ID" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "제거함" + +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "기존 펌웨어 파일의 데이터 교체" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "보고서 URI" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "인터넷 연결 필요" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "DFU 장치 초기화" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "지금 다시 시작하시겠습니까?" + +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "데몬을 다시 시작하여 변경 사항을 적용하시겠습니까?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "장치 다시 시작하는 중…" + +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "머신의 모든 하드웨어 ID를 반환합니다" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "install-blob 사용 시 플러그인 정리 루틴 실행" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "install-blob 사용 시 플러그인 준비 루틴 실행" + +msgid "Runtime" +msgstr "런타임" + +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "실행하는 동안의 장치 상태를 JSON 파일로 저장" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "가능하다면 다음에 다시 시작할 때 설치 예약" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "작업 계획 중…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "시리얼" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "펌웨어 파일의 대체 명칭 설정" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "펌웨어 파일의 대체 번호 설정" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "펌웨어 파일의 구성요소 주소 설정" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "펌웨어 파일의 제품 ID 설정" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "펌웨어 파일의 릴리스 버전 설정" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "업데이트 중 디버깅 플래그 설정" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "대상 펌웨어 크기 설정" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "펌웨어 파일의 제조사 ID 설정" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "펌웨어 파일의 메타데이터 설정" + +msgid "Sets the list of approved firmware" +msgstr "허용된 펌웨어 목록 설정" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "허용된 펌웨어 목록을 설정합니다." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "개발사와 펌웨어 업데이트 기록 공유하기" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "클라이언트와 데몬 버전 표시" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "업데이트 원격 ID" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "지정한 도메인의 자세한 데몬 정보 표시" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "업데이트 검사합" +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "모든 도메인의 디버깅 정보 표시" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "업데이트 위치" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "디버깅 옵션을 표시합니다" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "업데이트 설명" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "업데이트할 수 없는 장치 표시" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "원격 ID" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "추가 디버깅 정보 표시" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "제목" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "펌웨어 업데이트 기록 보기" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "형식" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "자세한 플러그인 정보 표시" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "키 모음" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "마지막으로 시도한 업데이트의 디버그 정보 표시" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "활성화 여부" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "펌웨어 업데이트 상태 표시" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "경과기간" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "지금 종료하시겠습니까?" + +msgid "Sign data using the client certificate" +msgstr "클라이언트 인증서로 데이터 서명" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "클라이언트 인증서로 데이터 서명" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "우선순위" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "클라이언트 인증서로 업로드된 데이터 서명" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "사용자 이름" +msgid "Signature" +msgstr "서명" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "암호" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "DFU 장치의 제조사/제품 ID 지정" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "파일 이름" +msgid "Specify the number of bytes per USB transfer" +msgstr "USB 전송 당 바이트 수 지정" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "파일이름 서명" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "상태" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "메타데이터 URI" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "장치 상태" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "메타데이터 URI 서명" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "요약" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "펌웨어 기본 URI" +msgid "Target" +msgstr "대상" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS는 $OS_RELEASE:NAME$와(과) 별개로 운영되는 독립된 법적 단체에서 운영하는 무료 서비스입니다. 배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결한 장치의 호환성을 검증한다는 보장이 없습니다. 모든 펌웨어는 장치 제조사(OEM)에서 직접 제공합니다." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "허용된 펌웨어가 없습니다." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "이 프로그램은 루트 권한으로만 올바르게 작동할 수도 있습니다" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "이 원격 저장소에서는 하드웨어 제조사에서 검증 단계를 진행 중인 펌웨어를 배포합니다. 펌웨어 업데이트 도중 및 이후 문제가 발생했을 경우를 대비하여 직접 펌웨어를 다운그레이드할 방편을 확보해두시는게 좋습니다." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "이 도구는 루트로만 사용할 수 있습니다" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "장치 추가함:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "제목" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "장치 제거함:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "전송 용량" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "장치 상태 바꿈:" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "형식" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI 펌웨어 유틸리티" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "추가 디버깅 정보 표시" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "알 수 없음" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "클라이언트와 데몬 버전 표시" +msgid "Unlock the device to allow access" +msgstr "접근을 허용하려면 장치 잠금을 해제하십시오" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "가능하다면 다음 재부팅시 설치 예약" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "펌웨어에 접근할 수 있도록 장치 잠금을 해제합니다" #. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "기존 펌웨어 버전 재설치를 허용합니다" +msgid "Unset the debugging flag during update" +msgstr "업데이트 중 디버깅 플래그 설정 해제" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "펌웨어를 이전 버전으로 되돌릴 수 있게 합니다" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "지원하지 않는 데몬 버전 %s, 클라이언트 버전 %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "플러그인 경고 무시" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "업데이트 체크섬" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "업데이트 설명" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "업데이트 예상 시간" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "업데이트 위치" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "업데이트 이름" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "펌웨어 업데이트를 지원하는 모든 장치 정보를 가져옵니다" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "업데이트 원격 ID" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "머신의 모든 하드웨어 ID를 반환합니다" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "업데이트 요약" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "현재 준비한 업데이트를 설치합니다" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "업데이트 버전" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Update all devices that match local metadata" +msgstr "로컬 메타데이터와 일치하는 모든 장치 업데이트" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "알 수 없는 이유로 업데이트가 실패했습니다. 더 많은 정보를 보려면 다음 URL을 참조가힙시오:" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "지금 업데이트하시겠습니까?" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "이 하드웨어에 펌웨어 파일을 설치합니다" +msgid "Update the stored device verification information" +msgstr "저장된 장치 검증 정보 업데이트" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "펌웨어 파일 세부 정보를 가져옵니다" +msgid "Update the stored metadata with current ROM contents" +msgstr "저장된 메타데이터를 현재 ROM 내용으로 업데이트합니다" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "연결한 하드웨어의 업데이트 목록을 가져옵니다" +msgid "Update the stored metadata with current contents" +msgstr "저장된 메타데이터를 현재 내용으로 업데이트" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" -msgstr "모든 펌웨어를 가용 최신 버전으로 업데이트합니다" +msgstr "모든 펌웨어를 사용할 수 있는 최신 버전으로 업데이트합니다" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "덤프 펌웨어의 암호화 해시 정보를 가져옵니다" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "%2$s에서 %3$s(으)로 %1$s 업데이트 중... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "펌웨어 접근시 장치 잠금을 해제합니다" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "%s 업데이트 중..." -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "최근 업데이트 결과를 지웁니다" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "업로드 메시지:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "오프라인으로 업데이트할 업데이트를 지웁니다" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "지금 보고서를 업로드하시겠습니까?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "최근 업데이트 결과를 가져옵니다" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "펌웨어 보고서를 업로드하면 하드웨어 제작사에서 실제 장치에 업데이트를 적용했을 때 성공 및 실패 여부를 빠르게 알 수 있습니다." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "장치에 대한 출시 펌웨어를 가져옵니다" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "사용자 이름" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "원격 설정 정보를 가져옵니다" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "검증 중…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "장치 펌웨어 버전을 이전으로 되돌립니다" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "버전" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "원격 서버의 메타데이터를 새로 고칩니다" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "기다리는 중…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "현재 ROM에 저장한 메타데이터를 업데이트합니다" +msgid "Watch DFU devices being hotplugged" +msgstr "DFU 핫 플러그 장치 보기" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "데몬 이벤트를 감시합니다" +msgid "Watch for hardware changes" +msgstr "하드웨어 변경 사항 감시" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "샌드박스에서 펌웨어를 빌드합니다" +msgid "Write firmware from file into device" +msgstr "파일의 펌웨어를 장치에 기록" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "파일의 SMBIOS 데이터 덤프를 출력합니다" +msgid "Write firmware from file into one partition" +msgstr "파일의 펌웨어를 파티션 하나에 기록" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "주어진 원격 정보를 수정합니다" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "쓰는 중…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "펌웨어 유틸리티" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "배포판 개발사에서 펌웨어 업데이트와 시스템 및 연결된 장치간의 호환성을 검증한다는 보장이 없습니다." diff -Nru fwupd-1.0.6/po/ky.po fwupd-1.2.10/po/ky.po --- fwupd-1.0.6/po/ky.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/ky.po 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,70 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# Ilyas Bakirov , 2018 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Kyrgyz (http://www.transifex.com/freedesktop/fwupd/language/ky/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ky\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Кошулду" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Чиптин ID'си" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Табылды" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. show message in progressbar +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing %s" +msgstr "Орнотулууда: %s" + +msgid "Mode" +msgstr "Режими" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Протокол" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Окуулууда..." + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Абалы" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Статус" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Белгисиз" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Жазылууда..." + +msgid "fwupd" +msgstr "fwupd" diff -Nru fwupd-1.0.6/po/LINGUAS fwupd-1.2.10/po/LINGUAS --- fwupd-1.0.6/po/LINGUAS 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/LINGUAS 2019-07-15 18:25:54.000000000 +0000 @@ -1,8 +1,11 @@ +af ast ca cs +da de en_GB +eo eu fi fr @@ -15,6 +18,8 @@ it kk ko +ky +lt nl oc pl diff -Nru fwupd-1.0.6/po/lt.po fwupd-1.2.10/po/lt.po --- fwupd-1.0.6/po/lt.po 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/lt.po 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,1119 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fwupd package. +# +# Translators: +# Moo, 2019 +msgid "" +msgstr "" +"Project-Id-Version: fwupd\n" +"Report-Msgid-Bugs-To: \n" +"Language-Team: Lithuanian (http://www.transifex.com/freedesktop/fwupd/language/lt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: lt\n" +"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);\n" + +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "%s valdiklio atnaujinimas" + +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "%s įrenginio atnaujinimas" + +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "%s įtaisytojo valdiklio atnaujinimas" + +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "%s ME atnaujinimas" + +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "%s sisteminis atnaujinimas" + +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "%s atnaujinimas" + +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s turi programinės aparatinės įrangos atnaujinimų:" + +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktyvuoti įrenginius" + +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktyvuoti laukiančius įrenginius" + +msgid "Activate the new firmware on the device" +msgstr "Aktyvuoti naują programinę aparatinę įrangą įrenginyje" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Aktyvuojamas programinės aparatinės įrangos atnaujinimas" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Aktyvuojama programinė aparatinė įranga, skirta" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Pridėtas" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Amžius" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Sutikti ir įjungti šią nuotolinę saugyklą?" + +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alternatyvusis %s pavadinimas" + +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Leisti sendinti programinės aparatinės įrangos versijas" + +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Leisti iš naujo įdiegti esamas programinės aparatinės įrangos versijas" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Atnaujinimo užbaigimui, reikia paleisti sistemą iš naujo." + +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Atnaujinimo užbaigimui, reikia išjungti sistemą." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Atsakyti taip į visus klausimus" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Taikyti dvejetainę pataisą" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Taikyti programinės aparatinės įrangos atnaujinimus" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Prijungti ĮPAĮA įgalintą įrenginį atgal prie vykdymo aplinkos" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Pridėti į programinės aparatinės įrangos veikseną" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Požymiai" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Nustatoma tapatybė…" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Norint keičiamajame įrenginyje sendinti programinę aparatinę įrangą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Norint šiame kompiuteryje sendinti programinę aparatinę įrangą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Norint modifikuoti programinės aparatinės įrangos atnaujinimams naudojamą sukonfigūruotą saugyklą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Norint nustatyti patvirtintos programinės aparatinės įrangos sąrašą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Norint pasirašyti duomenis naudojant kliento liudijimą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Norint perjungti į naują programinės aparatinės įrangos versiją, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Norint atrakinti įrenginį, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Norint keičiamajame įrenginyje atnaujinti programinę aparatinę įrangą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Norint šiame kompiuteryje atnaujinti programinę aparatinę įrangą, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Norint atnaujinti įrenginiui saugomas kontrolines sumas, reikalingas tapatybės nustatymas" + +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Sukurti programinę aparatinę įrangą, naudojant smėliadėžę" + +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Atsisakyti" + +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Atsisakyta" + +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Pakeistas" + +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolinė suma" + +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Lusto ID" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Pasirinkite įrenginį:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Pasirinkite laidą:" + +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Šifras" + +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Išvalo visus autonominiam atnaujinimui suplanuotus atnaujinimus" + +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Išvalo rezultatus iš paskutinio atnaujinimo" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Komanda nerasta" + +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Konvertuoti programinę aparatinė įrangą į ĮPAĮA formatą" + +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Sukurti dvejetainę pataisą, naudojant du failus" + +msgid "DFU" +msgstr "ĮPAĮA" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "ĮPAĮA paslaugų programa" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Derinimo parametrai" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Išskleidžiama…" + +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Iššifruoti programinės aparatinės įrangos duomenis" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Aprašas" + +#. TRANSLATORS: command description +msgid "Detach currently attached DFU capable device" +msgstr "Atjungti šiuo metu prijungtą ĮPAĮA įgalintą įrenginį" + +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Atskirti į pradinio įkėliklio veikseną" + +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Įrenginio ID" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Pridėtas įrenginys:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Pakeistas įrenginys:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Pašalintas įrenginys:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Įrenginiai, kurie buvo sėkmingai atnaujinti:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Įrenginiai, kurie nebuvo teisingai atnaujinti:" + +msgid "Disabled fwupdate debugging" +msgstr "Išjungtas fwupdate derinimas" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Išjungia nurodytą nuotolinę saugyklą" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Rodyti versiją" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Netikrinti ar yra senų metaduomenų" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Po atnaujinimo netikrinti ar buvo paleidimas iš naujo" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Netikrinti ar yra istorijos apie kurią nepranešta" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Nerašyti į istorijos duomenų bazę" + +#. success +msgid "Done!" +msgstr "Atlikta!" + +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "Sendina programinę aparatinę įrangą įrenginyje" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Sendinama %s iš %s į %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Sendinamas %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Atsisiunčiama…" + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "Iškloti SMBIOS duomenis iš failo" + +#. TRANSLATORS: command description +msgid "Dump details about a firmware file" +msgstr "Iškloti išsamesnę informaciją apie programinės aparatinės įrangos failą" + +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Iškloti į ekraną informaciją apie dvejetainę pataisą" + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Nurodytas ESS (angl. ESP) nebuvo teisingas" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Įjungti programinės aparatinės įrangos atnaujinimo palaikymą palaikomose sistemose" + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Įjungti šią nuotolinę saugyklą?" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Įjungta" + +msgid "Enabled fwupdate debugging" +msgstr "Įjungtas fwupdate derinimas" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Įjungia nurodytą nuotolinę saugyklą" + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Šios nuotolinės saugyklos įjungimas yra jūsų pačių rizika." + +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Šifruoti programinės aparatinės įrangos duomenis" + +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Ištrinti visą programinės aparatinės įrangos atnaujinimų istoriją" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Ištrinama…" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Išeiti po nedidelės delsos" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Išeiti, įkėlus modulį" + +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Nepavyko prisijungti prie tarnybos" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Nepavyko atsisiųsti dėl serverio apribojimo" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Nepavyko gauti laukiančių įrenginių" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Nepavyko įdiegti programinės aparatinės įrangos atnaujinimo" + +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Nepavyko įkelti gudrybių" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Nepavyko išanalizuoti argumentų" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Nepavyko paleisti iš naujo" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Nepavyko nustatyti prisistatymo lango veikseną" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Gaunamas failas" + +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Gaunama programinė aparatinė įranga" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Gaunami metaduomenys" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Gaunamas parašas" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Failo pavadinimas" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Failo pavadinimo parašas" + +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Programinės aparatinės įrangos agentas" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Pagrindinis programinės aparatinės įrangos URI" + +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Programinės aparatinės įrangos atnaujinimo D-Bus tarnyba" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Programinės aparatinės įrangos atnaujinimo tarnyba" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Programinės aparatinės įrangos paslaugų programa" + +msgid "Firmware updates are not supported on this machine." +msgstr "Šiame kompiuteryje programinės aparatinės įrangos atnaujinimai yra neprieinami." + +msgid "Firmware updates are supported on this machine." +msgstr "Šiame kompiuteryje yra prieinami programinės aparatinės įrangos atnaujinimai." + +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Vėliavėlės" + +msgid "Force the action ignoring all warnings" +msgstr "Priverstinai atlikti veiksmą nepaisant visų įspėjimų" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Rastas" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Gauti visus įrenginius pagal sistemos topologiją" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Gauti visus įrenginius ir galimas laidas" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Gauti visus įrenginius, kurie palaiko programinės aparatinės įrangos atnaujinimus" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Gauti visus įjungtus sistemoje registruotus įskiepius" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Gauna išsamesnę informaciją apie programinės aparatinės įrangos failą" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Gauna sukonfigūruotas nuotolines saugyklas" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Gauna išklotos programinės aparatinės įrangos šifravimo maišą" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Gauna patvirtintos programinės aparatinės įrangos sąrašą." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Gauna atnaujinimų sąrašą prijungtai aparatinei įrangai" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Gauna laidas įrenginiui" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Gauna rezultatus iš paskutinio atnaujinimo" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Neveiklus…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Įdiegti įrenginyje programinės aparatinės įrangos dvejetainį išplėstinį objektą" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Įdiegti šioje aparatinėje įrangoje programinės aparatinės įrangos failą" + +msgid "Install old version of system firmware" +msgstr "Įdiegti senąją sistemos programinės aparatinės įrangos versiją" + +msgid "Install signed device firmware" +msgstr "Įdiegti pasirašytą įrenginio programinę aparatinę įrangą" + +msgid "Install signed system firmware" +msgstr "Įdiegti pasirašytą sistemos programinę aparatinę įrangą" + +msgid "Install unsigned device firmware" +msgstr "Įdiegti nepasirašytą įrenginio programinę aparatinę įrangą" + +msgid "Install unsigned system firmware" +msgstr "Įdiegti nepasirašytą sistemos programinę aparatinę įrangą" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Įdiegiama programinė aparatinė įranga…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Įdiegiamas programinės aparatinės įrangos atnaujinimas…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Įdiegiama ties %s…" + +msgid "Keyring" +msgstr "Raktinė" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Liko mažiau kaip viena minutė" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux tiekėjų programinės aparatinės įrangos paslauga (stabili programinė aparatinė įranga)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux tiekėjų programinės aparatinės įrangos paslauga (testuojama programinė aparatinė įranga)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Išvardyti šiuo metu prijungtus ĮPAĮA įgalintus įrenginius" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Išvardyti prieinamus programinės aparatinės įrangos atnaujinimus" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Įkeliama…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Rankiniu būdu įtraukti tam tikrus įskiepius į baltąjį sąrašą" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Sujungti kelis programinės aparatinės įrangos failus į vieną" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metaduomenų URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metaduomenų URI parašas" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metaduomenys gali būti gauti iš Linux tiekėjų programinės aparatinės įrangos paslaugos." + +msgid "Mode" +msgstr "Veiksena" + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modifikuoja nurodytą nuotolinę saugyklą" + +msgid "Modify a configured remote" +msgstr "Modifikuoti sukonfigūruotą nuotolinę saugyklą" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Stebėti tarnybą, ar yra įvykių" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Pavadinimas" + +msgid "No action specified!" +msgstr "Nenurodytas joks veiksmas!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Neaptikta jokios aparatinės įrangos su programinės aparatinės įrangos atnaujinimo galimybėmis" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nerasta jokių įskiepių" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Šiuo metu nėra įjungtos jokios nuotolinės saugyklos, taigi, nėra prieinami jokie metaduomenys." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nebuvo pritaikyti jokie atnaujinimai" + +msgid "OK" +msgstr "Gerai" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Nustelbti įskiepio įspėjimą" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Nustelbti numatytąjį ESS (angl. ESP) kelią" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Slaptažodis" + +msgid "Payload" +msgstr "Naudingoji apkrova" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Užbaigta procentinė dalis" + +msgid "Permission denied" +msgstr "Leidimas atmestas" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Įveskite skaičių nuo 0 iki %u: " + +msgid "Print the version number" +msgstr "Parodyti versijos numerį" + +msgid "Print verbose debug statements" +msgstr "Parodyti išsamius derinimo teiginius" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Pirmenybė" + +msgid "Proceed with upload?" +msgstr "Tęsti išsiuntimą?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokolas" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Užklausti programinės aparatinės įrangos atnaujinimų palaikymo" + +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Gudrybės" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Skaityti programinę aparatinę įrangą iš įrenginio į failą" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Skaityti programinę aparatinę įrangą iš vieno skaidinio į failą" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Skaitoma…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Paleidžiama iš naujo…" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Iš naujo įkelti metaduomenis iš nuotolinio serverio" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Sritis" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Iš naujo įdiegiama %s su %s... " + +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Nuotolinė saugykla" + +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Nuotolinės saugyklos ID" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Pašalintas" + +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Pakeisti duomenis esamame programinės aparatinės įrangos faile" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Ataskaitų URI" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Reikalauja interneto ryšio" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Atstatyti ĮPAĮA įrenginį" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Paleisti iš naujo dabar?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Įrenginys paleidžiamas iš naujo…" + +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Grąžinti visus kompiuterio aparatinės įrangos ID" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Paleisti sudėtinę įskiepio išvalymo programą, naudojant install-blob" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Paleisti sudėtinę įskiepio paruošimo programą, naudojant install-blob" + +msgid "Runtime" +msgstr "Vykdymo aplinka" + +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Įrašyti įrenginio būseną tarp paleidimų į JSON failą" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Kai įmanoma, suplanuoti įdiegimą kitam paleidimui iš naujo" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Suplanuojama…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serijos numeris" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Nustatyti programinės aparatinės įrangos faile alternatyvų pavadinimą" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Nustatyti programinės aparatinės įrangos faile alternatyvų skaičių" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Nustatyti elemento adresą programinės aparatinės įrangos faile" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Nustatyti programinės aparatinės įrangos faile produkto ID" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Nustatyti programinės aparatinės įrangos faile laidos versiją" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Atnaujinimo metu nustatyti derinimo vėliavėlę" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Nustatyti programinės aparatinės įrangos dydį, skirtą paskirties objektui" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Nustatyti programinės aparatinės įrangos faile tiekėjo ID" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Nustato metaduomenis programinės aparatinės įrangos faile" + +msgid "Sets the list of approved firmware" +msgstr "Nustato patvirtintą programinės aparatinės įrangos sąrašą" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Nustato patvirtintos programinės aparatinės įrangos sąrašą." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Bendrinti programinės aparatinės įrangos istoriją su plėtotojais" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Rodyti kliento ir tarnybos versijas" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Rodyti derinimo parametrus" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Rodyti negalimus atnaujinti įrenginius" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Rodyti papildomą derinimo informaciją" + +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Rodyti programinės aparatinės įrangos atnaujinimų istoriją" + +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Rodyti išsamią įskiepio informaciją" + +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Rodyti derinimo žurnalą iš paskutinio bandyto atnaujinimo" + +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Rodyti programinės aparatinės įrangos atnaujinimo būseną" + +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Išjungti dabar?" + +msgid "Sign data using the client certificate" +msgstr "Pasirašyti duomenis, naudojant kliento liudijimą" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Pasirašyti duomenis, naudojant kliento liudijimą" + +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Pasirašyti išsiunčiamus duomenis naudojant kliento liudijimą" + +msgid "Signature" +msgstr "Parašas" + +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Nurodyti ĮPAĮA įrenginio tiekėją/produkto ID" + +msgid "Specify the number of bytes per USB transfer" +msgstr "Nurodyti baitų skaičių tenkantį vienam USB persiuntimui" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Būsena" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Būsena" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Santrauka" + +msgid "Target" +msgstr "Paskirtis" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Nėra jokios patvirtintos programinės aparatinės įrangos." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Ši programa gali tinkamai veikti tik pagrindinio naudotojo teisėmis" + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Šį įrankį gali naudoti tik pagrindinis naudotojas" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Pavadinimas" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Persiuntimo dydis" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipas" + +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI programinės aparatinės įrangos paslaugų programa" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Nežinoma" + +msgid "Unlock the device to allow access" +msgstr "Atrakinti įrenginį, kad būtų leista prieiga" + +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Atrakina įrenginį programinės aparatinės įrangos prieigai" + +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "Atnaujinimo metu panaikinti derinimo vėliavėlės nustatymą" + +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Atnaujinimo kontrolinė suma" + +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Atnaujinimo aprašas" + +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Atnaujinimo trukmė" + +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Atnaujinimo vieta" + +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Atnaujinimo pavadinimas" + +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Atnaujinimų nuotolinės saugyklos ID" + +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Atnaujinimo santrauka" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Atnaujinimo versija" + +#. TRANSLATORS: command description +msgid "Update all devices that match local metadata" +msgstr "Atnaujinti visus įrenginius, kurie atitinka vietinius metaduomenis" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Atnaujinimo nesėkmė yra žinoma problema, išsamesnei informacijai apsilankykite šiame URL:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Atnaujinti dabar?" + +msgid "Update the stored device verification information" +msgstr "Atnaujinti saugomo įrenginio patikrinimo informaciją" + +#. TRANSLATORS: command description +msgid "Update the stored metadata with current ROM contents" +msgstr "Atnaujinti saugomus metaduomenis esamu ROM turiniu" + +#. TRANSLATORS: command description +msgid "Update the stored metadata with current contents" +msgstr "Atnaujinti saugomus metaduomenis esamu turiniu" + +#. TRANSLATORS: command description +msgid "Updates all firmware to latest versions available" +msgstr "Atnaujina visą programinę aparatinę įrangą iki naujausios prieinamos versijos" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Atnaujinama %s iš %s į %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Atnaujinama %s…" + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Išsiuntimo žinutė:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Išsiųsti ataskaitą dabar?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Programinės aparatinės įrangos ataskaitų išsiuntimas padeda aparatinės įrangos tiekėjams greitai atpažinti nesėkmingus bei sėkmingus atnaujinimus tikruose įrenginiuose." + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Naudotojo vardas" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Patikrinama…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versija" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Laukiama…" + +#. TRANSLATORS: command description +msgid "Watch DFU devices being hotplugged" +msgstr "Stebėti ĮPAĮA įrenginius, kurie atnaujinami nepaleidžiant iš naujo" + +#. TRANSLATORS: command description +msgid "Watch for hardware changes" +msgstr "Stebėti aparatinės įrangos pakeitimus" + +#. TRANSLATORS: command description +msgid "Write firmware from file into device" +msgstr "Rašyti programinę aparatinę įrangą iš failo į įrenginį" + +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Rašyti programinę aparatinę įrangą iš failo į vieną skaidinį" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Rašoma…" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Gali būti, kad jūsų platintojas, suderinamumui su jūsų sistema ar prijungtais įrenginiais, nėra patvirtinęs jokių programinės aparatinės įrangos atnaujinimų." diff -Nru fwupd-1.0.6/po/make-images fwupd-1.2.10/po/make-images --- fwupd-1.0.6/po/make-images 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/make-images 2019-07-15 18:25:54.000000000 +0000 @@ -1,25 +1,11 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 """ This thing rasterizes text for use later """ # pylint: disable=wrong-import-position,too-many-locals,unused-argument # pylint: disable=invalid-name,too-many-instance-attributes """ - Licensed under the GNU General Public License Version 2 - - 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 2 of the License, 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, see . - +SPDX-License-Identifier: LGPL-2.1+ """ @@ -191,6 +177,7 @@ if len(sys.argv) != 4: usage(1) - r = Rasterizer(label=sys.argv[1], modir=sys.argv[2], + label = os.fsencode(sys.argv[1]).decode('utf-8') + r = Rasterizer(label=label, modir=sys.argv[2], linguas=sys.argv[3]) r.render() diff -Nru fwupd-1.0.6/po/make-images.sh fwupd-1.2.10/po/make-images.sh --- fwupd-1.0.6/po/make-images.sh 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/make-images.sh 2019-07-15 18:25:54.000000000 +0000 @@ -5,8 +5,12 @@ # # Distributed under terms of the GPLv2 license. # -install -m 0755 -d ${MESON_INSTALL_DESTDIR_PREFIX}/share/locale/ -${MESON_SOURCE_ROOT}/po/make-images "Installing firmware update…" ${MESON_INSTALL_DESTDIR_PREFIX}/share/locale/ ${MESON_SOURCE_ROOT}/po/LINGUAS -for x in ${MESON_INSTALL_DESTDIR_PREFIX}/share/locale/*/LC_IMAGES/*.bmp ; do + +LOCALEDIR="${DESTDIR}$1" +PYTHON3="$2" + +install -m 0755 -d $LOCALEDIR +${PYTHON3} ${MESON_SOURCE_ROOT}/po/make-images "Installing firmware update…" $LOCALEDIR ${MESON_SOURCE_ROOT}/po/LINGUAS +for x in ${LOCALEDIR}/*/LC_IMAGES/*.bmp ; do gzip -fn9 ${x} done diff -Nru fwupd-1.0.6/po/meson.build fwupd-1.2.10/po/meson.build --- fwupd-1.0.6/po/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -5,6 +5,12 @@ ] ) -if get_option('plugin_uefi_labels') -meson.add_install_script('make-images.sh') +if get_option('plugin_uefi') +meson.add_install_script('make-images.sh', localedir, python3.path()) endif + +run_target('fix-translations', + command: [ + join_paths(meson.source_root(), 'contrib/fix_translations.py'), + join_paths(meson.source_root(), 'po') + ]) diff -Nru fwupd-1.0.6/po/nl.po fwupd-1.2.10/po/nl.po --- fwupd-1.0.6/po/nl.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/nl.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Richard E. van der Luit , 2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Dutch (http://www.transifex.com/freedesktop/fwupd/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,418 @@ "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s heeft firmware-updates:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Toegevoegd" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias voor %s" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Ondertekende systeemfirmware installeren" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Downgraden van oude firmware-versies toestaan" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Om de firmware op deze computer bij te werken moet u toestemming verlenen" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Herinstalleren van bestaande firmware-versies toestaan" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Niet-ondertekende systeemfirmware installeren" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Apparaat geschikt voor DFU aankoppelen aan de runtime" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Oude versie van systeemfirmware installeren" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Om de firmware op een verwijderbaar apparaat te downgraden moet u toestemming verlenen" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Om de firmware op deze computer te downgraden moet u toestemming verlenen" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Ondertekende apparaatfirmware installeren" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Om de firmware op een verwijderbaar apparaat bij te werken moet u toestemming verlenen" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Niet-ondertekende apparaatfirmware installeren" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Om de firmware op een verwijderbaar apparaat te downgraden moet u toestemming verlenen" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Ontgrendel het apparaat om toegang te verlenen" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Om een apparaat te ontgrendelen moet u toestemming verlenen" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Opgeslagen apparaatverificatie-informatie bijwerken" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Om de opgeslagen controlesommen op het apparaat bij te werken moet u toestemming verlenen" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Om de firmware op een verwijderbaar apparaat bij te werken moet u toestemming verlenen" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Alias voor %s" - -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "De opdracht kon niet worden gevonden" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Om de firmware op deze computer bij te werken moet u toestemming verlenen" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Toegevoegd" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Om de opgeslagen controlesommen op het apparaat bij te werken moet u toestemming verlenen" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Verwijderd" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Geannuleerd" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Gewijzigd" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Geannuleerd" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Naam" - #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Cipher" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Gebied" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Gevonden" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protocol" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Status" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Serienummer" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Modus" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Status" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Overdrachtsgrootte" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Eigenaardigheden" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Wist de resultaten van de laatste update" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "De opdracht kon niet worden gevonden" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 msgid "Convert firmware to DFU format" msgstr "Firmware converteren naar DFU-formaat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Meerdere firmware-bestanden samenvoegen tot één bestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Leveranciers-ID instellen op het firmware-bestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Product-ID instellen op het firmware-bestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Elementadres instellen op het firmware-bestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Firmwaregrootte instellen voor het doel" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Uitgave-versie instellen op het firmware-bestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Alternatief nummer instellen op het firmware-bestand" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU-hulpmiddel" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Alternatieve naam instellen op het firmware-bestand" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Foutopsporingsopties" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Apparaat geschikt voor DFU aankoppelen aan de runtime" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Bezig met uitpakken..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +msgid "Decrypt firmware data" +msgstr "Firmware-gegevens ontsleutelen" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Firmware van het apparaat uitlezen naar een bestand" +msgid "Detach currently attached DFU capable device" +msgstr "Momenteel aangekoppeld voor DFU geschikt apparaat afkoppelen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Firmware van één partitie uitlezen naar een bestand" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Apparaat toegevoegd:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Firmware van een bestand naar een apparaat schrijven" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Apparaat gewijzigd:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Firmware van een bestand naar één partitie schrijven" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Apparaat verwijderd:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Lijst weergeven van momenteel aangekoppelde voor DFU geschikte apparaten" +#. success +msgid "Done!" +msgstr "Afgerond!" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Momenteel aangekoppeld voor DFU geschikt apparaat afkoppelen" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Bezig met downgraden van %s van %s naar %s..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Details over een firmware-bestand wegschrijven" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Het hotpluggen van DFU-apparaten weergeven" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 msgid "Encrypt firmware data" msgstr "Firmware-gegevens versleutelen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Firmware-gegevens ontsleutelen" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Stelt metadata in op een firmware-bestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Gegevens vervangen in een bestaand firmwarebestand" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU-hulpmiddel" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Het doorvoeren van argumenten is mislukt" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Lijst weergeven van alle Synaptics MST-apparaten" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Firmwarebestand flashen naar MST-apparaat" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics Multistream Transport Utility" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Foutopsporingsinformatie weergeven voor alle bestanden" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Foutopsporingsopties" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Foutopsporingsopties weergeven" - #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Afsluiten na een korte vertraging" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Afsluiten nadat de engine geladen is" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Firmware Update Daemon" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Het doorvoeren van argumenten is mislukt" #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" msgstr "Firmware Update D-Bus-dienst" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Slaapt..." - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Bezig met uitpakken..." - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Bezig met laden..." - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Bezig met herstarten van apparaat..." - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Bezig met schrijven..." - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Bezig met valideren..." - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Bezig met inplannen..." - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Onbekend" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" - -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Geen hardware aangetroffen die in staat is firmware bij te werken" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Bezig met herinstalleren van %s met %s..." - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Bezig met downgraden van %s van %s naar %s..." - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Bezig met bijwerken van %s van %s naar %s..." - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Afgerond!" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "Oké" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Firmware Update Daemon" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Firmware-hulpmiddel" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s heeft firmware-updates:" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Gevonden" -#: src/fu-util.c:1540 msgid "GUID" msgstr "GUID" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Versie bijwerken" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Alle apparaten verkrijgen die firmware-updates ondersteunen" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Verkrijgt details over een firmware-bestand" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Controlesom bijwerken" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Verkrijgen cryptografische som van de weggeschreven firmware" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Locatie bijwerken" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Verkrijgt een lijst van updates voor verbonden hardware" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Omschrijving bijwerken" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Verkrijgt de resultaten van de laatste update" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Slaapt..." -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Een firmware-bestand op deze hardware installeren" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" +msgid "Install old version of system firmware" +msgstr "Oude versie van systeemfirmware installeren" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" +msgid "Install signed device firmware" +msgstr "Ondertekende apparaatfirmware installeren" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" +msgid "Install signed system firmware" +msgstr "Ondertekende systeemfirmware installeren" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" +msgid "Install unsigned device firmware" +msgstr "Niet-ondertekende apparaatfirmware installeren" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" +msgid "Install unsigned system firmware" +msgstr "Niet-ondertekende systeemfirmware installeren" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Lijst weergeven van momenteel aangekoppelde voor DFU geschikte apparaten" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Bezig met laden..." -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Meerdere firmware-bestanden samenvoegen tot één bestand" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" +msgid "Mode" +msgstr "Modus" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "De achtergrondservice controleren op gebeurtenissen" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Naam" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Geen hardware aangetroffen die in staat is firmware bij te werken" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Apparaat toegevoegd:" +msgid "OK" +msgstr "Oké" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Apparaat verwijderd:" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Pluginwaarschuwing negeren" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Apparaat gewijzigd:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protocol" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Eigenaardigheden" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Firmware van het apparaat uitlezen naar een bestand" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Extra foutopsporingsinformatie weergeven" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Firmware van één partitie uitlezen naar een bestand" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Metadata verversen vanuit externe server" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "De installatie inplannen voor de volgende herstart, indien mogelijk" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Gebied" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Herinstalleren van bestaande firmware-versies toestaan" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Bezig met herinstalleren van %s met %s..." -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Downgraden van oude firmware-versies toestaan" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Verwijderd" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Pluginwaarschuwing negeren" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Gegevens vervangen in een bestaand firmwarebestand" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Bezig met herstarten van apparaat..." #. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +msgid "Schedule installation for next reboot when possible" +msgstr "De installatie inplannen voor de volgende herstart, indien mogelijk" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Bezig met inplannen..." -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serienummer" #. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Alle apparaten verkrijgen die firmware-updates ondersteunen" +msgid "Set alternative name on firmware file" +msgstr "Alternatieve naam instellen op het firmware-bestand" #. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" +msgid "Set alternative number on firmware file" +msgstr "Alternatief nummer instellen op het firmware-bestand" #. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Voorbereide updates nu installeren" +msgid "Set element address on firmware file" +msgstr "Elementadres instellen op het firmware-bestand" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Set product ID on firmware file" +msgstr "Product-ID instellen op het firmware-bestand" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +msgid "Set release version on firmware file" +msgstr "Uitgave-versie instellen op het firmware-bestand" #. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +msgid "Set the firmware size for the target" +msgstr "Firmwaregrootte instellen voor het doel" #. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Een firmware-bestand op deze hardware installeren" +msgid "Set vendor ID on firmware file" +msgstr "Leveranciers-ID instellen op het firmware-bestand" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Verkrijgt details over een firmware-bestand" +msgid "Sets metadata on a firmware file" +msgstr "Stelt metadata in op een firmware-bestand" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Verkrijgt een lijst van updates voor verbonden hardware" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Foutopsporingsopties weergeven" -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Werkt alle firmware bij naar de nieuwste versies die beschikbaar zijn" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Extra foutopsporingsinformatie weergeven" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Verkrijgen cryptografische som van de weggeschreven firmware" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Status" -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Ontgrendelt het apparaat voor firmware-toegang" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Wist de resultaten van de laatste update" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Overdrachtsgrootte" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Onbekend" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Verkrijgt de resultaten van de laatste update" +msgid "Unlock the device to allow access" +msgstr "Ontgrendel het apparaat om toegang te verlenen" #. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" +msgid "Unlocks the device for firmware access" +msgstr "Ontgrendelt het apparaat voor firmware-toegang" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Controlesom bijwerken" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Omschrijving bijwerken" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Metadata verversen vanuit externe server" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Locatie bijwerken" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Versie bijwerken" + +msgid "Update the stored device verification information" +msgstr "Opgeslagen apparaatverificatie-informatie bijwerken" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "De opgeslagen metadata bijwerken met de huidige ROM-inhoud" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "De achtergrondservice controleren op gebeurtenissen" +msgid "Updates all firmware to latest versions available" +msgstr "Werkt alle firmware bij naar de nieuwste versies die beschikbaar zijn" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Bezig met bijwerken van %s van %s naar %s..." + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Bezig met valideren..." #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" +msgid "Watch DFU devices being hotplugged" +msgstr "Het hotpluggen van DFU-apparaten weergeven" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" +msgid "Write firmware from file into device" +msgstr "Firmware van een bestand naar een apparaat schrijven" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" +msgid "Write firmware from file into one partition" +msgstr "Firmware van een bestand naar één partitie schrijven" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Firmware-hulpmiddel" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Bezig met schrijven..." diff -Nru fwupd-1.0.6/po/oc.po fwupd-1.2.10/po/oc.po --- fwupd-1.0.6/po/oc.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/oc.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Cédric Valmary , 2016 # Cédric Valmary , 2016 @@ -9,9 +9,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Occitan (post 1500) (http://www.transifex.com/freedesktop/fwupd/language/oc/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,979 +16,157 @@ "Language: oc\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Apondut" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Aliàs de %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Comanda pas trobada" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Apondut" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Suprimit" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Anullat" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Cambiat" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Anullat" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nom" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Soma de contraròtle" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Cipher" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Region" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Trobat" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Estatut" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Mòde" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Estat" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Comanda pas trobada" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Quirks" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opcions de desbugatge" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Descripcion" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "" +#. success +msgid "Done!" +msgstr "Acabat !" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Retrogradacion de %s de %s en %s " -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Quitar aprèp un brèu relambi" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "" +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Quitar aprèp lo cargament del motor" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Fracàs de l'analisi dels paramètres" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Servici D-Bus de mesa a jorn dels micrologicials" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Trobat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" +msgid "GUID" +msgstr "GUID" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" +msgid "Get all devices that support firmware updates" +msgstr "Obténer la lista dels periferics que supòrtan las mesas a jorn de micrologicial" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" +msgid "Gets details about a firmware file" +msgstr "Obténer los detalhs d'un fichièr de micrologicial" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" +msgid "Install a firmware file on this hardware" +msgstr "Installar un fichièr de micrologicial sus aqueste material" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" +msgid "Mode" +msgstr "Mòde" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nom" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Cap de material amb de capacitats de mesa a jorn del micrologicial es pas estat detectat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" +msgid "OK" +msgstr "D'acòrdi" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Quirks" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Region" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Reïnstallacion de %s en %s " -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Suprimit" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostrar las opcions de desbugatge" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mòstra d'informacions de desbugatge complementàrias" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Estat" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Estatut" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Fracàs de l'analisi dels paramètres" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Mostrar las informacions de desbugatge per totes los fichièrs" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opcions de desbugatge" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Mostrar las opcions de desbugatge" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Quitar aprèp un brèu relambi" - -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Quitar aprèp lo cargament del motor" - -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" - -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Servici D-Bus de mesa a jorn dels micrologicials" - -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" - -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Cap de material amb de capacitats de mesa a jorn del micrologicial es pas estat detectat" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Reïnstallacion de %s en %s " - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Retrogradacion de %s de %s en %s " - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Mesa a jorn de %s de %s en %s " - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Acabat !" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "D'acòrdi" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Mesa a jorn de %s de %s en %s " #. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 msgid "Version" msgstr "Version" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Descripcion" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Soma de contraròtle" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Mòstra d'informacions de desbugatge complementàrias" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Obténer la lista dels periferics que supòrtan las mesas a jorn de micrologicial" - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Installar immediatament las mesas a jorn preparadas" - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Installar un fichièr de micrologicial sus aqueste material" - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Obténer los detalhs d'un fichièr de micrologicial" - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "" diff -Nru fwupd-1.0.6/po/pl.po fwupd-1.2.10/po/pl.po --- fwupd-1.0.6/po/pl.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/pl.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Piotr Drąg , 2015-2018 +# Piotr Drąg , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Polish (http://www.transifex.com/freedesktop/fwupd/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,981 +15,1227 @@ "Language: pl\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Aktualizowanie oprogramowania sprzętowego w systemie Linux" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Pozostała %.0f minuta" +msgstr[1] "Pozostały %.0f minuty" +msgstr[2] "Pozostało %.0f minut" +msgstr[3] "Pozostało %.0f minut" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Celem projektu jest automatyczne, bezpieczne i pewne aktualizowanie oprogramowania sprzętowego w systemie Linux. Można używać graficznego menedżera oprogramowania, takiego jak Menedżer oprogramowania GNOME do wyświetlania i zastosowywania aktualizacji, narzędzia wiersza poleceń lub bezpośrednio interfejsu D-Bus." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Aktualizacja podsystemu ME użytkownika końcowego urządzenia %s" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Proces fwupd to prosta usługa umożliwiająca aktualizowanie oprogramowania sprzętowego komputera w sesji użytkownika. Jest zaprojektowana dla komputerów osobistych, ale można jej używać także na telefonach, tabletach i serwerach bez monitorów." +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Aktualizacja kontrolera %s" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Instalacja podpisanego oprogramowania sprzętowego komputera" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Aktualizacja firmowego podsystemu ME urządzenia %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować oprogramowanie sprzętowe tego komputera" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Aktualizacja urządzenia %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Instalacja niepodpisanego oprogramowania sprzętowego komputera" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Aktualizacja wbudowanego kontrolera %s" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Instalacja poprzedniej wersji oprogramowania sprzętowego komputera" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Aktualizacja podsystemu ME urządzenia %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzednią wersję oprogramowania sprzętowego tego komputera" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Aktualizacja komputera %s" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Instalacja podpisanego oprogramowania sprzętowego urządzenia" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Aktualizacja urządzenia %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować oprogramowanie sprzętowe wymiennego urządzenia" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "Dostępne są aktualizacje oprogramowania sprzętowego dla urządzenia %s:" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Instalacja niepodpisanego oprogramowania sprzętowego urządzenia" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dzień" +msgstr[1] "%u dni" +msgstr[2] "%u dni" +msgstr[3] "%u dni" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzednią wersję oprogramowania sprzętowego urządzenia wymiennego" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u godzina" +msgstr[1] "%u godziny" +msgstr[2] "%u godzin" +msgstr[3] "%u godzin" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Odblokowanie urządzenia" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuta" +msgstr[1] "%u minuty" +msgstr[2] "%u minut" +msgstr[3] "%u minut" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Wymagane jest uwierzytelnienie, aby odblokować urządzenie" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekunda" +msgstr[1] "%u sekundy" +msgstr[2] "%u sekund" +msgstr[3] "%u sekund" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Aktualizacja przechowywanych informacji o poprawności urządzenia" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Aktywuje urządzenia" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować przechowywane sumy kontrolne dla urządzenia" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Aktywuje oczekujące urządzenia" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Modyfikacja skonfigurowanego repozytorium" +msgid "Activate the new firmware on the device" +msgstr "Aktywacja nowego oprogramowania sprzętowego na urządzeniu" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Wymagane jest uwierzytelnienie, aby zmodyfikować skonfigurowane repozytorium używane do aktualizacji oprogramowania sprzętowego" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Aktywowanie aktualizacji oprogramowania sprzętowego" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Aktywowanie aktualizacji oprogramowania sprzętowego dla" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Dodano" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Wiek" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Wyrazić zgodę i włączyć repozytorium?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Alias do „%s”" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Nie odnaleziono polecenia" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Umożliwia instalowanie poprzednich wersji oprogramowania sprzętowego" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Dodano" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Umożliwia ponowne instalowanie istniejących wersji oprogramowania sprzętowego" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Usunięto" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Zmieniono" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Ukończenie aktualizacji wymaga wyłączenia komputera." -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Anulowano" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Odpowiada tak na wszystkie pytania" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "Identyfikator" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Zastosowuje binarną łatę" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nazwa" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Zastosowuje aktualizacje oprogramowania sprzętowego" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Szyfr" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Zatwierdzone oprogramowanie sprzętowe:" +msgstr[1] "Zatwierdzone oprogramowanie sprzętowe:" +msgstr[2] "Zatwierdzone oprogramowanie sprzętowe:" +msgstr[3] "Zatwierdzone oprogramowanie sprzętowe:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Region" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Podłącza urządzenie DFU z powrotem do uruchamiania systemu" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Odnaleziono" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Podłącza do trybu oprogramowania sprzętowego" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokół" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Atrybuty" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Stan" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Uwierzytelnianie…" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Brak uprawnień" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzednią wersję oprogramowania sprzętowego urządzenia wymiennego" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Numer seryjny" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Wymagane jest uwierzytelnienie, aby zainstalować poprzednią wersję oprogramowania sprzętowego tego komputera" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Tryb" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Wymagane jest uwierzytelnienie, aby zmodyfikować skonfigurowane repozytorium używane do aktualizacji oprogramowania sprzętowego" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Uruchamianie systemu" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Wymagane jest uwierzytelnienie, aby zmodyfikować konfigurację usługi" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Wymagane jest uwierzytelnienie, aby ustawić listę zatwierdzonego oprogramowania sprzętowego" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Stan" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Wymagane jest uwierzytelnienie, aby podpisać dane za pomocą certyfikatu klienta" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Rozmiar przesyłania" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Wymagane jest uwierzytelnienie, aby przełączyć na nową wersję oprogramowania sprzętowego" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Atrybuty" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Wymagane jest uwierzytelnienie, aby odblokować urządzenie" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Poprawki" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować oprogramowanie sprzętowe wymiennego urządzenia" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "Identyfikator układu" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować oprogramowanie sprzętowe tego komputera" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Konwertuje oprogramowanie sprzętowe do formatu DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Wymagane jest uwierzytelnienie, aby zaktualizować przechowywane sumy kontrolne dla urządzenia" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Łączy wiele plików oprogramowania sprzętowego w jeden plik" +msgid "Build firmware using a sandbox" +msgstr "Buduje oprogramowanie sprzętowe za pomocą piaskownicy" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Ustawia identyfikator producenta pliku oprogramowania sprzętowego" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Anuluj" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Ustawia identyfikator produktu pliku oprogramowania sprzętowego" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Anulowano" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Ustawia adres elementu pliku oprogramowania sprzętowego" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Zmieniono" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Ustawia rozmiar oprogramowania sprzętowego dla celu" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Suma kontrolna" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Ustawia wersję wydania pliku oprogramowania sprzętowego" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Identyfikator układu" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Ustawia alternatywny numer pliku oprogramowania sprzętowego" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Wybór urządzenia:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Ustawia alternatywną nazwę pliku oprogramowania sprzętowego" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Wybór wydania:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Podłącza urządzenie DFU z powrotem do uruchamiania systemu" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Szyfr" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Przywraca urządzenie DFU" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Usuwa wszystkie zaplanowane aktualizacje w trybie offline" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Odczytuje oprogramowanie sprzętowe z urządzenia do pliku" +msgid "Clears the results from the last update" +msgstr "Usuwa wyniki z ostatniej aktualizacji" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Nie odnaleziono polecenia" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Odczytuje oprogramowanie sprzętowe z jednej partycji do pliku" +msgid "Convert firmware to DFU format" +msgstr "Konwertuje oprogramowanie sprzętowe do formatu DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Zapisuje oprogramowanie sprzętowe z pliku na urządzenie" +msgid "Create a binary patch using two files" +msgstr "Tworzy binarną łatę z dwóch plików" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Zapisuje oprogramowanie sprzętowe z pliku na jedną partycję" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Narzędzie DFU" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opcje debugowania" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Dekompresowanie…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Wyświetla listę obecnie podłączonych urządzeń DFU" +msgid "Decrypt firmware data" +msgstr "Odszyfrowuje dane oprogramowania sprzętowego" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Opis" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "Odłącza obecnie podłączone urządzenie DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Zrzuca informacje o pliku oprogramowania sprzętowego" +msgid "Detach to bootloader mode" +msgstr "Odłącza do trybu programu startowego" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Obserwuje podłączanie urządzeń DFU w czasie działania" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Identyfikator urządzenia" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Szyfruje dane oprogramowania sprzętowego" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Dodano urządzenie:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Odszyfrowuje dane oprogramowania sprzętowego" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Zmieniono urządzenie:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Usunięto urządzenie:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Pomyślnie zaktualizowane urządzenia:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Urządzenia, które nie zostały poprawnie zaktualizowane:" + +msgid "Disabled fwupdate debugging" +msgstr "Wyłączono debugowanie fwupdate" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Ustawia metadane pliku oprogramowania sprzętowego" +msgid "Disables a given remote" +msgstr "Wyłącza podane repozytorium" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Wyświetla wersję" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Bez sprawdzania przestarzałych metadanych" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Bez sprawdzania potrzeby ponownego uruchomienia po aktualizacji" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Bez sprawdzania niezgłoszonej historii" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Bez zapisywania do bazy danych historii" + +#. success +msgid "Done!" +msgstr "Gotowe." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Zastępuje dane w istniejącym pliku oprogramowania sprzętowego" +msgid "Downgrades the firmware on a device" +msgstr "Instaluje poprzednią wersję oprogramowania sprzętowego urządzenia" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Instalowanie poprzedniej wersji %s z %s do %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Instalowanie poprzedniej wersji urządzenia %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Pobieranie…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Tworzy binarną łatę z dwóch plików" +msgid "Dump SMBIOS data from a file" +msgstr "Zrzuca dane SMBIOS z pliku" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Zastosowuje binarną łatę" +msgid "Dump details about a firmware file" +msgstr "Zrzuca informacje o pliku oprogramowania sprzętowego" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "Zrzuca informacje o binarnej łacie na ekran" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "Wczytanie poprawek się nie powiodło" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Podana partycja ESP nie jest prawidłowa" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Narzędzie DFU" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Włącza obsługę aktualizacji oprogramowania sprzętowego na obsługiwanych systemach" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Przetworzenie parametrów się nie powiodło" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Włączyć to repozytorium?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Wylicza wszystkie urządzenia MST firmy Synaptics" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Włączone" + +msgid "Enabled fwupdate debugging" +msgstr "Włączono debugowanie fwupdate" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Zapisuje oprogramowanie sprzętowe w urządzeniu MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Narzędzie wielostrumieniowego przesyłania Synaptics" +msgid "Enables a given remote" +msgstr "Włącza podane repozytorium" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Instalowanie aktualizacji oprogramowania sprzętowego…" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Włączenie tej funkcjonalności jest wykonywane na własne ryzyko, co oznacza, że należy skontaktować się z oryginalnym producentem sprzętu w sprawie ewentualnych problemów spowodowanych przez te aktualizacje. Tylko problemy z samym procesem aktualizacji powinny być zgłaszane pod adresem $OS_RELEASE:BUG_REPORT_URL$." -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Wyświetla informacje o debugowaniu dla wszystkich plików" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Włączenie tego repozytorium wykonywane jest na własne ryzyko." -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Wyświetla więcej informacji o wtyczkach" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Szyfruje dane oprogramowania sprzętowego" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opcje debugowania" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Usuwa całą historię aktualizacji oprogramowania sprzętowego" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Wyświetla opcje debugowania" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Usuwanie zawartości…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Kończy działanie po małym opóźnieniu" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Kończy działanie po wczytaniu mechanizmu" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Usługa aktualizacji oprogramowania sprzętowego" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Połączenie z usługą się nie powiodło" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Pobranie się nie powiodło z powodu ograniczenia serwera" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Uzyskanie oczekujących urządzeń się nie powiodło" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Zainstalowanie aktualizacji oprogramowania sprzętowego się nie powiodło" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Usługa D-Bus aktualizacji oprogramowania sprzętowego" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Wczytanie poprawek się nie powiodło" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Bezczynne…" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Przetworzenie parametrów się nie powiodło" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Dekompresowanie…" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Ponowne uruchomienie się nie powiodło" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Ustawienie trybu ekranu wczytywania się nie powiodło" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Wczytywanie…" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Pobieranie pliku" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Ponowne uruchamianie urządzenia…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Pobieranie oprogramowania sprzętowego" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Odczytywanie…" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Pobieranie metadanych" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Zapisywanie…" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Pobieranie podpisu" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Usuwanie zawartości…" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nazwa pliku" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Sprawdzanie poprawności…" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Podpis nazwy pliku" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Planowanie…" +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Agent oprogramowania sprzętowego" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Pobieranie…" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Podstawowy adres URI oprogramowania sprzętowego" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Uwierzytelnianie…" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Usługa D-Bus aktualizacji oprogramowania sprzętowego" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Oczekiwanie…" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Usługa aktualizacji oprogramowania sprzętowego" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Nieznane" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Narzędzie oprogramowania sprzętowego" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dzień i mogą nie być aktualne." +msgstr[1] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." +msgstr[2] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." +msgstr[3] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Wybór urządzenia:" +msgid "Firmware updates are not supported on this machine." +msgstr "Aktualizacje oprogramowania sprzętowego nie są obsługiwane na tym komputerze." -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "Aktualizacje oprogramowania sprzętowego są obsługiwane na tym komputerze." -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Urządzenia, które nie zostały poprawnie zaktualizowane:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Flagi" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Pomyślnie zaktualizowane urządzenia:" +msgid "Force the action ignoring all warnings" +msgstr "Wymusza działanie ignorując wszystkie ostrzeżenia" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Wysłać zgłoszenie?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Odnaleziono" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Wymaga połączenia z Internetem" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Nie wykryto sprzętu z możliwością aktualizacji jego oprogramowania" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Uzyskuje wszystkie urządzenia zgodnie z topologią komputera" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Ponowne instalowanie %s za pomocą %s… " +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Uzyskuje wszystkie urządzenia i możliwe wydania" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Uzyskuje wszystkie urządzenia obsługujące aktualizacje oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Uzyskuje wszystkie włączone wtyczki zarejestrowane na komputerze" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Uzyskuje informacje o pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Uzyskuje skonfigurowane repozytoria" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Uzyskuje kryptograficzną sumę kontrolną zrzuconego oprogramowania sprzętowego" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Uzyskuje listę zatwierdzonego oprogramowania sprzętowego." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Uzyskuje listę aktualizacji dla podłączonego sprzętu" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Uzyskuje wydania dla urządzenia" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Uzyskuje wyniki z ostatniej aktualizacji" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Identyfikator" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Bezczynne…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Instaluje zamknięte oprogramowanie sprzętowe na urządzeniu" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instaluje plik oprogramowania sprzętowego na tym sprzęcie" + +msgid "Install old version of system firmware" +msgstr "Instalacja poprzedniej wersji oprogramowania sprzętowego komputera" + +msgid "Install signed device firmware" +msgstr "Instalacja podpisanego oprogramowania sprzętowego urządzenia" + +msgid "Install signed system firmware" +msgstr "Instalacja podpisanego oprogramowania sprzętowego komputera" + +msgid "Install unsigned device firmware" +msgstr "Instalacja niepodpisanego oprogramowania sprzętowego urządzenia" + +msgid "Install unsigned system firmware" +msgstr "Instalacja niepodpisanego oprogramowania sprzętowego komputera" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalowanie oprogramowania sprzętowego…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Instalowanie aktualizacji oprogramowania sprzętowego…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Instalowanie poprzedniej wersji %s z %s do %s… " +msgid "Installing on %s…" +msgstr "Instalowanie na urządzeniu %s…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Keyring" +msgstr "Baza kluczy" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Pozostała mniej niż jedna minuta" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabilne oprogramowanie sprzętowe)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (testowe oprogramowanie sprzętowe)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Wyświetla listę obecnie podłączonych urządzeń DFU" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Wyświetla listę obsługiwanych aktualizacji oprogramowania sprzętowego" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Wczytywanie…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Ręcznie wstawia podane wtyczki na białą listę" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Łączy wiele plików oprogramowania sprzętowego w jeden plik" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Adres URI metadanych" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Podpis adresu URI metadanych" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadane można uzyskać z serwisu Linux Vendor Firmware Service." + +#. TRANSLATORS: error message #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Aktualizowanie %s z wersji %s do %s… " +msgid "Mismatched daemon and client, use %s instead" +msgstr "Niezgodna usługa i klient, proszę użyć %s zamiast tego" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Gotowe." +msgid "Mode" +msgstr "Tryb" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Cel" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Modyfikuje wartość konfiguracji usługi." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modyfikuje podane repozytorium" + +msgid "Modify a configured remote" +msgstr "Modyfikacja skonfigurowanego repozytorium" + +msgid "Modify daemon configuration" +msgstr "Modyfikacja konfiguracji usługi" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitoruje zdarzenia usługi" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Nazwa" + +msgid "No action specified!" +msgstr "Nie podano działania." + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Nie wykryto sprzętu z możliwością aktualizacji jego oprogramowania" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nie odnaleziono wtyczek" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Żadne repozytoria nie są obecnie włączone, więc żadne metadane nie są dostępne." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nie zastosowano żadnych aktualizacji" + +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Zastępuje ostrzeżenie wtyczki" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Zastępuje domyślną ścieżkę ESP" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Zastępuje ostrzeżenia i wymusza działanie" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Hasło" -#: src/fu-util.c:727 msgid "Payload" msgstr "Dane" -#: src/fu-util.c:728 +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Procent ukończenia" + +msgid "Permission denied" +msgstr "Brak uprawnień" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Proszę podać liczbę od 0 do %u:" + +msgid "Print the version number" +msgstr "Wyświetla numer wersji" + +msgid "Print verbose debug statements" +msgstr "Wyświetla więcej komunikatów debugowania" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Priorytet" + msgid "Proceed with upload?" msgstr "Kontynuować wysyłanie?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Niepowodzenie aktualizacji to znany problem, pod tym adresem dostępnych jest więcej informacji:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokół" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Komunikat wysyłania:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Odpytuje obsługę aktualizacji oprogramowania sprzętowego" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "OK" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Poprawki" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Pobieranie podpisu" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Odczytuje oprogramowanie sprzętowe z urządzenia do pliku" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Pobieranie metadanych" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Odczytuje oprogramowanie sprzętowe z jednej partycji do pliku" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Pobieranie oprogramowania sprzętowego" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Odczytywanie…" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Pobieranie pliku" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Ponowne uruchamianie…" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Wersja" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Odświeża metadane ze zdalnego serwera" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Podsumowanie" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Region" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Ponowne instalowanie %s za pomocą %s… " #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Repozytorium" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "Adres URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Identyfikator repozytorium" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Opis" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Usunięto" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Suma kontrolna" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Zastępuje dane w istniejącym pliku oprogramowania sprzętowego" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Wybór wydania:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Adres URI zgłoszenia" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dzień i mogą nie być aktualne." -msgstr[1] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." -msgstr[2] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." -msgstr[3] "Metadane oprogramowania sprzętowego nie zostały zaktualizowane przez %u dni i mogą nie być aktualne." +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Wymaga połączenia z Internetem" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Zaktualizować teraz?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Przywraca urządzenie DFU" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "Dostępne są aktualizacje oprogramowania sprzętowego dla urządzenia %s:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Uruchomić ponownie?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Uruchomić usługę ponownie, aby uwzględnić zmianę?" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Wersja aktualizacji" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Ponowne uruchamianie urządzenia…" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Nazwa aktualizacji" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Zwraca wszystkie identyfikatory sprzętu dla komputera" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Podsumowanie aktualizacji" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Wykonuje procedurę czyszczenia składania wtyczki podczas używania „install-blob”" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Identyfikator repozytorium aktualizacji" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Wykonuje procedurę przygotowania składania wtyczki podczas używania „install-blob”" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Suma kontrolna aktualizacji" +msgid "Runtime" +msgstr "Uruchamianie systemu" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Położenie aktualizacji" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Zapisuje stan urządzenia do pliku JSON między wykonaniami" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Opis aktualizacji" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Planuje instalację podczas następnego ponownego uruchomienia" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Identyfikator repozytorium" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Planowanie…" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Tytuł" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Numer seryjny" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Ustawia alternatywną nazwę pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Ustawia alternatywny numer pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Ustawia adres elementu pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Ustawia identyfikator produktu pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Ustawia wersję wydania pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Ustawia flagę debugowania podczas aktualizacji" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Ustawia rozmiar oprogramowania sprzętowego dla celu" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Ustawia identyfikator dostawcy pliku oprogramowania sprzętowego" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Ustawia metadane pliku oprogramowania sprzętowego" + +msgid "Sets the list of approved firmware" +msgstr "Ustawienie listy zatwierdzonego oprogramowania sprzętowego" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Ustawia listę zatwierdzonego oprogramowania sprzętowego." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Udostępnia historię oprogramowania sprzętowego programistom" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Wyświetla wersje klienta i usługi" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Wyświetla więcej informacji o usłudze dla konkretnej domeny" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Wyświetla informacje o debugowaniu dla wszystkich domen" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Wyświetla opcje debugowania" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Wyświetla urządzenia, których nie można aktualizować" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Wyświetla dodatkowe informacje o debugowaniu" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Typ" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Wyświetla historię aktualizacji oprogramowania sprzętowego" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Baza kluczy" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Wyświetla więcej informacji o wtyczkach" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Włączone" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Wyświetla dziennik debugowania z ostatniej aktualizacji" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Wiek" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Wyświetla informacje o stanie aktualizacji oprogramowania sprzętowego" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Priorytet" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Wyłączyć teraz?" + +msgid "Sign data using the client certificate" +msgstr "Podpisanie danych za pomocą certyfikatu klienta" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Podpisanie danych za pomocą certyfikatu klienta" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Nazwa użytkownika" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Podpisuje wysłane dane za pomocą certyfikatu klienta" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Hasło" +msgid "Signature" +msgstr "Podpis" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Nazwa pliku" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Podaje identyfikatory dostawcy/produktu urządzenia DFU" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Podpis nazwy pliku" +msgid "Specify the number of bytes per USB transfer" +msgstr "Podaje liczbę bajtów na przesyłanie USB" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "Adres URI metadanych" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Stan" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Podpis adresu URI metadanych" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Stan" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Podstawowy adres URI oprogramowania sprzętowego" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Podsumowanie" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "Adres URI zgłoszenia" +msgid "Target" +msgstr "Cel" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Dodano urządzenie:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS to wolny serwis działający jako niezależny podmiot prawny niemający związków z systemem $OS_RELEASE:NAME$. Dystrybutor używanego systemu mógł nie zweryfikować żadnych aktualizacji oprogramowania sprzętowego pod kątem zgodności z używanym komputerem lub podłączonymi urządzeniami. Każde oprogramowanie sprzętowe jest dostarczane wyłącznie przez oryginalnego producenta sprzętu." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Nie ma zatwierdzonego oprogramowania sprzętowego." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Ten program może działać poprawnie tylko jako root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "To repozytorium zawiera oprogramowanie sprzętowe nieobjęte embargo, ale nadal testowane przez dostawcę sprzętu. Należy upewnić się, że istnieje możliwość ręcznego zainstalowania poprzedniej wersji oprogramowania sprzętowego w razie niepowodzenia aktualizacji." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "To narzędzie może być używane tylko przez użytkownika root" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Usunięto urządzenie:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Tytuł" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Zmieniono urządzenie:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Rozmiar przesyłania" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Ukończenie aktualizacji wymaga ponownego uruchomienia." +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Typ" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "Uruchomić ponownie?" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Narzędzie oprogramowania sprzętowego UEFI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Wyświetla dodatkowe informacje o debugowaniu" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "Adres URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Wyświetla wersje klienta i usługi" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Nieznane" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Planuje instalację podczas następnego ponownego uruchomienia" +msgid "Unlock the device to allow access" +msgstr "Odblokowanie urządzenia" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Umożliwia ponowne instalowanie istniejących wersji oprogramowania sprzętowego" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Odblokowuje urządzenie" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Umożliwia instalowanie poprzednich wersji oprogramowania sprzętowego" +msgid "Unset the debugging flag during update" +msgstr "Usuwa flagę debugowania podczas aktualizacji" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Zastępuje ostrzeżenie wtyczki" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Nieobsługiwana wersja usługi %s, wersja klienta to %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Odpowiada tak na wszystkie pytania" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Suma kontrolna aktualizacji" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Bez sprawdzania niezgłoszonej historii" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Opis aktualizacji" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Bez sprawdzania przestarzałych metadanych" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Czas trwania aktualizacji" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Bez sprawdzania potrzeby ponownego uruchomienia po aktualizacji" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Położenie aktualizacji" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Uzyskuje wszystkie urządzenia obsługujące aktualizacje oprogramowania sprzętowego" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Nazwa aktualizacji" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Zwraca wszystkie identyfikatory sprzętu dla komputera" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Identyfikator repozytorium aktualizacji" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Instaluje przygotowaną aktualizację teraz" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Podsumowanie aktualizacji" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Wyświetla historię aktualizacji oprogramowania sprzętowego" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Wersja aktualizacji" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Usuwa całą historię aktualizacji oprogramowania sprzętowego" +msgid "Update all devices that match local metadata" +msgstr "Aktualizuje wszystkie urządzenia pasujące do lokalnych metadanych" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Udostępnia historię oprogramowania sprzętowego programistom" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Niepowodzenie aktualizacji to znany problem, pod tym adresem dostępnych jest więcej informacji:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Instaluje plik oprogramowania sprzętowego na tym sprzęcie" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Zaktualizować teraz?" + +msgid "Update the stored device verification information" +msgstr "Aktualizacja przechowywanych informacji o poprawności urządzenia" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Uzyskuje informacje o pliku oprogramowania sprzętowego" +msgid "Update the stored metadata with current ROM contents" +msgstr "Aktualizuje przechowywane metadane bieżącą zawartością pamięci ROM" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Uzyskuje listę aktualizacji dla podłączonego sprzętu" +msgid "Update the stored metadata with current contents" +msgstr "Aktualizuje przechowywane metadane obecną zawartością" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Aktualizuje całe oprogramowanie sprzętowe do najnowszych dostępnych wersji" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Uzyskuje kryptograficzną sumę kontrolną zrzuconego oprogramowania sprzętowego" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Aktualizowanie %s z wersji %s do %s… " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Odblokowuje urządzenie" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Aktualizowanie urządzenia %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Usuwa wyniki z ostatniej aktualizacji" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Komunikat wysyłania:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Usuwa wszystkie zaplanowane aktualizacje w trybie offline" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Wysłać zgłoszenie?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Uzyskuje wyniki z ostatniej aktualizacji" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Wysyłanie zgłoszeń o oprogramowaniu sprzętowym pomaga dostawcom sprzętu szybko identyfikować nieudane i udane aktualizacje na prawdziwych urządzeniach." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Uzyskuje wydania dla urządzenia" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nazwa użytkownika" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Uzyskuje skonfigurowane repozytoria" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Sprawdzanie poprawności…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Instaluje poprzednią wersję oprogramowania sprzętowego urządzenia" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Wersja" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Odświeża metadane ze zdalnego serwera" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Oczekiwanie…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Aktualizuje przechowywane metadane bieżącą zawartością pamięci ROM" +msgid "Watch DFU devices being hotplugged" +msgstr "Obserwuje podłączanie urządzeń DFU w czasie działania" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Monitoruje zdarzenia usługi" +msgid "Watch for hardware changes" +msgstr "Obserwuje zmiany sprzętu" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Buduje oprogramowanie sprzętowe za pomocą piaskownicy" +msgid "Write firmware from file into device" +msgstr "Zapisuje oprogramowanie sprzętowe z pliku na urządzenie" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Zrzuca dane SMBIOS z pliku" +msgid "Write firmware from file into one partition" +msgstr "Zapisuje oprogramowanie sprzętowe z pliku na jedną partycję" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Modyfikuje podane repozytorium" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Zapisywanie…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Narzędzie oprogramowania sprzętowego" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Używana dystrybucja mogła nie sprawdzić zgodności aktualizacji oprogramowania sprzętowego z komputerem i podłączonymi urządzeniami." diff -Nru fwupd-1.0.6/po/POTFILES.in fwupd-1.2.10/po/POTFILES.in --- fwupd-1.0.6/po/POTFILES.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/POTFILES.in 2019-07-15 18:25:54.000000000 +0000 @@ -1,9 +1,15 @@ -data/org.freedesktop.fwupd.metainfo.xml +data/remotes.d/lvfs.metainfo.xml +data/remotes.d/lvfs-testing.metainfo.xml policy/org.freedesktop.fwupd.policy.in plugins/dfu/dfu-tool.c -plugins/synapticsmst/synapticsmst-tool.c plugins/uefi/fu-plugin-uefi.c +plugins/uefi/fu-uefi-tool.c +src/fu-agent.c +src/fu-config.c src/fu-debug.c src/fu-main.c +src/fu-offline.c +src/fu-tool.c src/fu-progressbar.c src/fu-util.c +src/fu-util-common.c diff -Nru fwupd-1.0.6/po/POTFILES.skip fwupd-1.2.10/po/POTFILES.skip --- fwupd-1.0.6/po/POTFILES.skip 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/po/POTFILES.skip 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1 @@ +data/org.freedesktop.fwupd.metainfo.xml diff -Nru fwupd-1.0.6/po/pt_BR.po fwupd-1.2.10/po/pt_BR.po --- fwupd-1.0.6/po/pt_BR.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/pt_BR.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,20 +1,17 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Derek W. Stavis , 2015 # Derek W. Stavis , 2016 # Derek W. Stavis , 2015-2016 -# Rafael Fontenelle , 2017 -# Rafael Fontenelle , 2015-2018 +# Rafael Fontenelle , 2017-2018 +# Rafael Fontenelle , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/freedesktop/fwupd/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,979 +19,1213 @@ "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Atualize firmware de dispositivos no Linux" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Esse projeto visa tornar a atualização de firmware no Linux automática, segura e confiável. você pode usar um gerenciador de software GUI, como o GNOME Software, para ver e aplicar atualizações, a ferramenta de linha de comando ou a interface D-Bus diretamente." +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0f minuto restante" +msgstr[1] "%.0f minutos restantes" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "O fwupd processa é um daemon simples para permitir que software sessão atualizem firmware de dispositivo em seu computador local. É projetado para computadores de mesa, mas esse projeto também é usável em telefones, tablets e em servidores \"headless\" (sem monitor, teclado e mouse)." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Atualização consumidor-final de ME para %s " -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Instalar firmware assinado no sistema" +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Atualização do controlador %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "É requerida autenticação para atualizar o firmware nesta máquina" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Atualização corporativa de ME para %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Instalar firmware não assinado no sistema" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Atualização do dispositivo %s" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Instalar versão antiga do firmware no sistema" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Atualização do controlador embarcado %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "É requerida autenticação para voltar a versão do firmware nesta máquina" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Atualização do ME %s" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Instalar firmware assinado no dispositivo" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Atualização do sistema %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "É requerida autenticação para atualizar o firmware em dispositivo removível" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Atualização de %s" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Instalar firmware não assinado no dispositivo" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s tem atualizações de firmware:" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "É requerida autenticação para voltar a versão do firmware em um dispositivo removível" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dia" +msgstr[1] "%u dias" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Desbloquear o dispositivo para permitir acesso" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u hora" +msgstr[1] "%u horas" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "É requerida autenticação para desbloquear um dispositivo" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u minuto" +msgstr[1] "%u minutos" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Atualizar as informações de verificação do dispositivo armazenado" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u segundo" +msgstr[1] "%u segundos" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "É requerida autenticação para atualizar as somas de verificação armazenadas para o dispositivo" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Ativa dispositivos" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Modificar um remoto configurado" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Ativa dispositivos pendentes" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "É requerida autenticação para modificar um remoto configurado usado para atualizações de firmware" +msgid "Activate the new firmware on the device" +msgstr "Ativar o novo firmware no dispositivo" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Atalho para %s" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Ativando atualização de firmware" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Comando não encontrado" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Ativando atualização de firmware para" #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 msgid "Added" msgstr "Adicionado" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Removido" - -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Alterado" - -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Cancelado" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Nome" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Idade" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Cifra" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Concordar e habilitar o remoto?" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Região" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Atalho para %s" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Encontrado" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Permite fazer downgrade de versões de firmware" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protocolo" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Permite reinstalar versões existentes de firmware" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Status" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Uma atualização requer uma reinicialização para completar." -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Permissão negada" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Uma atualização requer que o sistema seja desligado por completo." -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Serial" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Responde sim para todas as perguntas" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Modo" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Aplica um patch binário" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Runtime" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Aplica atualizações de firmware" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Firmware aprovado:" +msgstr[1] "Firmwares aprovados:" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Estado" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Anexa um dispositivo com capacidade de DFU em tempo real" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Tamanho da transferência" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Modo anexar ao firmware" #. TRANSLATORS: device attributes, i.e. things that #. * the device can do -#: plugins/dfu/dfu-tool.c:2139 msgid "Attributes" msgstr "Atributos" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Gambiarra" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autenticando…" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ID do chip" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "É requerida autenticação para fazer downgrade da versão do firmware em um dispositivo removível" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Converte um firmware para formato DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "É requerida autenticação para fazer downgrade da versão do firmware nesta máquina" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Mescla múltiplos arquivos de firmware em um" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "É requerida autenticação para modificar um remoto configurado usado para atualizações de firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Define o ID de fabricante no arquivo de firmware" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "É requerida autenticação para modificar uma configuração de daemon" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Define o ID de produto no arquivo de firmware" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "É requirida autenticação para definir a lista de firmwares aprovados" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Define o endereço do elemento no arquivo de firmware" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "É requirida autenticação para assinar dados usando o certificado client" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Define o tamanho do firmware para o alvo" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "É requirida autenticação para alternar para nova versão de firmware" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Define a versão de lançamento no arquivo de firmware" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "É requerida autenticação para desbloquear um dispositivo" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Define o número alternativo no arquivo de firmware" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "É requerida autenticação para atualizar o firmware em dispositivo removível" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Define o nome alternativo no arquivo de firmware" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "É requerida autenticação para atualizar o firmware nesta máquina" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Anexa um dispositivo com capacidade de DFU em tempo real" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "É requerida autenticação para atualizar as somas de verificação armazenadas para o dispositivo" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Redefine um dispositivo DFU" +msgid "Build firmware using a sandbox" +msgstr "Compila o firmware usando um sandbox" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Lê o firmware do dispositivo para um arquivo" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Cancelar" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Lê o firmware de uma partição para um arquivo" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Cancelado" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Escreve um firmware do arquivo para o dispositivo" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Alterado" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Escreve um firmware do arquivo para uma partição" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Soma de verificação" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Lista os dispositivos atualmente anexados com capacidade de DFU" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ID do chip" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Desanexa dispositivos atualmente anexados com capacidade de DFU" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Escolha um dispositivo:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Despeja os detalhes sobre um arquivo firmware" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Escolha um lançamento:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Monitora dispositivos DFU sendo conectados" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Cifra" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Criptografa os dados do firmware" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Limpa quaisquer atualizações agendadas a serem atualizadas desconectadas" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Descriptografa os dados do firmware" +msgid "Clears the results from the last update" +msgstr "Limpa os resultados da última atualização" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Define os metadados em um arquivo de firmware" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Comando não encontrado" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Substitui os dados em um arquivo de firmware existente" +msgid "Convert firmware to DFU format" +msgstr "Converte um firmware para formato DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 msgid "Create a binary patch using two files" msgstr "Cria um patch binário usando dois arquivos" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Aplicar um patch binário" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Despeja informações sobre um patch binário na tela" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "Falha ao carregar peculiaridades" +msgid "DFU" +msgstr "DFU" #. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 msgid "DFU Utility" msgstr "Utilitário DFU" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Falha ao interpretar argumentos" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Opções de depuração" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Descomprimindo…" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Enumera todos os dispositivos MST da Synaptics" +msgid "Decrypt firmware data" +msgstr "Descriptografa os dados do firmware" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Descrição" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Instala o arquivo firmware em um dispositivo MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Utilitário de Synaptics Multistream Transport" +msgid "Detach currently attached DFU capable device" +msgstr "Desanexa dispositivos atualmente anexados com capacidade de DFU" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Instalando atualização de firmware…" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Modo desanexar ao gerenciador de boot" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Mostrar informações de depuração para todos os arquivos" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "ID do dispositivo" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Mostra informação verbosa de plugin" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Dispositivo adicionado:" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Opções de depuração" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Dispositivo modificado:" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Mostrar opções de depuração" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Dispositivo removido:" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Sair após pequeno atraso" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Dispositivos que foram atualizados com sucesso:" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Sair após o carregamento do motor" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Dispositivos que não foram atualizados com sucesso:" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Daemon de Atualização de Firmware" +msgid "Disabled fwupdate debugging" +msgstr "Depuração de fwupdate desabilitada" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Serviço D-Bus de Atualização de Firmware" +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Desabilita um remoto dado" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Ocioso…" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Exibe a versão" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Descomprimindo…" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Não verifica por metadados antigos" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Carregando…" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Não verifica por reinicialização após atualizar" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Reiniciando dispositivo…" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Não verifica por histórico não relatado" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Lendo…" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Não escreve no banco de dados de histórico" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Escrevendo…" +#. success +msgid "Done!" +msgstr "Feito!" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Apagando…" +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "Faz downgrade da versão do firmware em um dispositivo" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Verificando…" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Fazendo downgrade de %s de %s para %s… " -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Agendando…" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Fazendo downgrade %s…" #. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 msgid "Downloading…" msgstr "Baixando…" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Autenticando…" +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "Despeja dados SMBIOS a partir de um arquivo" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Aguardando…" +#. TRANSLATORS: command description +msgid "Dump details about a firmware file" +msgstr "Despeja os detalhes sobre um arquivo firmware" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Desconhecido" +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Despeja informações sobre um patch binário na tela" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "O ESP especificado não era válido" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Escolha um dispositivo:" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Habilita suporte a atualização de firmware em sistemas suportados" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Habilitar esse remoto?" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Dispositivos que não foram atualizados com sucesso:" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Habilitado" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Dispositivos que foram atualizados com sucesso:" +msgid "Enabled fwupdate debugging" +msgstr "Depuração de fwupdate habilitada" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Enviar relatório agora?" +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Habilita um remoto dado" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Requer conexão com a Internet" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "A habilitação dessa funcionalidade é feita por sua conta e risco, o que significa que você precisa entrar em contato com o fabricante do equipamento original sobre quaisquer problemas causados por essas atualizações. Somente problemas com o processo de atualização devem ser relatados em $ OS_RELEASE: BUG_REPORT_URL $." -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Nenhum periférico com capacidade de atualização de firmware foi detectado" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "A habilitação deste remoto é feito a seu próprio custo e risco." -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Reinstalando %s com %s..." +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Criptografa os dados do firmware" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Revertendo %s de %s para %s..." +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Apaga todo histórico de atualização de firmware" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Atualizando %s de %s para %s..." +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Apagando…" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Feito!" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Sair após pequeno atraso" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Alvo" +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Sair após o carregamento do motor" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "Carga" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Falha ao se conectar ao daemon" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Falha ao baixar em razão de limite do servidor" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Falha ao obter dispositivos pendentes" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Falha ao instalar a atualização de firmware" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "Proceder com o envio?" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Falha ao carregar peculiaridades" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Falha ao interpretar argumentos" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Falha ao reinicializar" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Falha ao definir o modo splash" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "OK" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Obtendo arquivo" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Obtendo assinatura" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Obtendo firmware" #. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 msgid "Fetching metadata" msgstr "Obtendo metadados" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Obtendo firmware" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Obtendo assinatura" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Obtendo arquivo" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Nome de arquivo" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Versão" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Resumo" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Assinatura de nome de arquivo" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "Remoto" +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Agente de firmware" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "URI base de firmware" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Descrição" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Serviço D-Bus de Atualização de Firmware" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Soma de verificação" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Daemon de Atualização de Firmware" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Escolha um lançamento:" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Utilitário de Firmware" #. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 #, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." msgstr[0] "Os metadados do firmware não foram atualizados a %u dia e podem não estar atualizados." -msgstr[1] "Os metadados do firmware não foram atualizados para %u dias e podem não estar atualizados." +msgstr[1] "Os metadados do firmware não foram atualizados a %u dias e podem não estar atualizados." -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Atualizar agora?" +msgid "Firmware updates are not supported on this machine." +msgstr "Não há suporte a atualizações de firmware nessa máquina." -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s tem atualizações:" +msgid "Firmware updates are supported on this machine." +msgstr "Há suporte a atualizações de firmware nesta máquina." + +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Sinalizadores" + +msgid "Force the action ignoring all warnings" +msgstr "Força a ação ignorando todos avisos" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Encontrado" -#: src/fu-util.c:1540 msgid "GUID" msgstr "GUID" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Versão da atualização" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Obtém todos os dispositivos de acordo com a topologia do sistema" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Obtém todos os dispositivos e lançamentos possíveis" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Obtém todos os dispositivos que oferecem suporte às atualizações de firmware" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Obtém todos os plugins registrados com o sistema" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Obtém detalhes sobre um arquivo de firmware" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Obtém os remotos configurados" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Obtém o hash criptográfico do firmware despejado" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Obtém a lista de firmwares aprovados." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Obtém a lista de atualizações para os hardwares conectados" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Obtém os lançamentos para um dispositivo" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Obtém os resultados da última atualização" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Ocioso…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Instala um blob de firmware em um dispositivos" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Instala um arquivo de firmware neste periférico" + +msgid "Install old version of system firmware" +msgstr "Instalar versão antiga do firmware no sistema" + +msgid "Install signed device firmware" +msgstr "Instalar firmware assinado no dispositivo" + +msgid "Install signed system firmware" +msgstr "Instalar firmware assinado no sistema" + +msgid "Install unsigned device firmware" +msgstr "Instalar firmware não assinado no dispositivo" + +msgid "Install unsigned system firmware" +msgstr "Instalar firmware não assinado no sistema" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Instalando o firmware…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Instalando atualização de firmware…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Instalando em %s…" + +msgid "Keyring" +msgstr "Chaveiro" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Menos que um minuto restante" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (firmware estável)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (firmware de teste)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Lista os dispositivos atualmente anexados com capacidade de DFU" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Lista atualizações de firmware suportadas" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Carregando…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Insere manualmente na lista branca plugins específicos" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Mescla múltiplos arquivos de firmware em um" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI de metadados" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Assinatura de URI de metadados" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadados podem ser obtidos do Linux Vendor Firmware Service." + +#. TRANSLATORS: error message +#, c-format +msgid "Mismatched daemon and client, use %s instead" +msgstr "Daemon e cliente incompatíveis, use %s" + +msgid "Mode" +msgstr "Modo" + +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Modifica o valor de uma configuração do daemon." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modifica um remoto dado" + +msgid "Modify a configured remote" +msgstr "Modificar um remoto configurado" + +msgid "Modify daemon configuration" +msgstr "Modificar a configuração do daemon" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Monitora o daemon por eventos" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' #. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Atualizar nome" +msgid "Name" +msgstr "Nome" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Atualizar resumo" +msgid "No action specified!" +msgstr "Nenhuma ação especificada!" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Atualização de ID remoto" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Nenhum periférico com capacidade de atualização de firmware foi detectado" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Soma de verificação da atualização" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Nenhum plugin localizado" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Nenhum remoto está atualmente habilitado, então nenhum metadado está disponível." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Nenhuma atualização foi aplicada" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Local da atualização" +msgid "OK" +msgstr "OK" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Sobrepõe um aviso de plugin" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Substitui o caminho ESP padrão" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Anula avisos e força a ação" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Senha" + +msgid "Payload" +msgstr "Carga" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Percentagem concluída" + +msgid "Permission denied" +msgstr "Permissão negada" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Por favor, insira um número de 0 a %u: " + +msgid "Print the version number" +msgstr "Imprime o número de versão" + +msgid "Print verbose debug statements" +msgstr "Imprime instruções de depuração verbosas" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioridade" + +msgid "Proceed with upload?" +msgstr "Proceder com o envio?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protocolo" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Consulta por suporte a atualização de firmware" + +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Peculiaridades" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Lê o firmware do dispositivo para um arquivo" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Lê o firmware de uma partição para um arquivo" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Lendo…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Reinicializando…" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Renova metadados do servidor remoto" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Região" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Reinstalando %s com %s… " + +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Remoto" + +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "ID remoto" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Removido" + +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Substitui os dados em um arquivo de firmware existente" + +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI do relatório" + +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Requer conexão com a Internet" + +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Redefine um dispositivo DFU" + +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Reiniciar agora?" + +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Reiniciar o daemon para tornar a mudança efetiva?" + +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Reiniciando dispositivo…" + +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Retorna todos os IDs de hardware para a máquina" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Executa a rotina de limpeza da composição de plugin ao usar install-blob" + +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Executa a rotina de preparação da composição de plugin ao usar install-blob" + +msgid "Runtime" +msgstr "Runtime" + +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Salva o estado do dispositivo em um arquivo JSON entre execuções" + +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Agenda instalação para próxima reinicialização quando possível" + +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Agendando…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serial" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Define o nome alternativo no arquivo de firmware" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Define o número alternativo no arquivo de firmware" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Define o endereço do elemento no arquivo de firmware" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Define o ID de produto no arquivo de firmware" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Define a versão de lançamento no arquivo de firmware" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Define a opção de depuração durante atualização" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Define o tamanho do firmware para o alvo" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Define o ID de fornecedor no arquivo de firmware" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Define os metadados em um arquivo de firmware" + +msgid "Sets the list of approved firmware" +msgstr "Define a lista de firmwares aprovados" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Define a lista de firmware aprovados." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Compartilha histórico de firmware com os desenvolvedores" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Mostra as versões do cliente e do daemon" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Mostrar informações detalhadas do daemon para um domínio em particular" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Mostrar informações de depuração para todos domínios" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Mostrar opções de depuração" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Descrição da atualização" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Mostra dispositivos que não são atualizáveis" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "ID remoto" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Mostra informações adicionais de depuração" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Título" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Mostra histórico de atualizações de firmware" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Tipo" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Mostra informação verbosa de plugin" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Chaveiro" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Mostra o registro log de depuração da tentativa mais recente de atualização" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Habilitado" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Mostra as informações do status de atualização de firmware" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Idade" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Desligar agora?" + +msgid "Sign data using the client certificate" +msgstr "Assina dados usando o certificado cliente" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Assina dados usando o certificado cliente" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Prioridade" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Assina os dados enviados com o certificado cliente" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Nome de usuário" +msgid "Signature" +msgstr "Assinatura" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Senha" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Especifica ID(s) de Fornecedor/Produto de dispositivo DFU" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Nome de arquivo" +msgid "Specify the number of bytes per USB transfer" +msgstr "Especifica o número de bytes por transferência USB" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Assinatura de nome de arquivo" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Estado" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI de metadados" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Assinatura de URI de metadados" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Resumo" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "URI base de firmware" +msgid "Target" +msgstr "Alvo" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "URI do relatório" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "O LVFS é um serviço livre que opera como uma entidade legal independente e tem nenhuma conexão com $OS_RELEASE:NAME$. Seu distribuidor pode não ter verificado alguma das atualizações de firmware por compatibilidade com seu sistema ou dispositivos conectados. Todo firmware é fornecido apenas pelo fabricante do equipamento original." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Nenhum firmware aprovado." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Esse programa só pode funcionar corretamente como root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Este remoto contém firmware que não está embargado, mas ainda está sendo testado pelo fornecedor do hardware. Você deve garantir que você tenha uma maneira de fazer downgrade manual do firmware se a atualização do firmware falhar." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Essa ferramenta só pode ser usada pelo usuário root" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Dispositivo adicionado:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Título" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Dispositivo removido:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Tamanho da transferência" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Dispositivo modificado:" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Tipo" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Utilitário de Firmware UEFI" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Mostrar informações adicionais de depuração" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Desconhecido" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Mostra as versões do cliente e do daemon" +msgid "Unlock the device to allow access" +msgstr "Desbloquear o dispositivo para permitir acesso" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Agenda instalação para próxima reinicialização quando possível" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Desbloqueia o dispositivo para acesso do firmware" #. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Permitir reinstalar versões existentes de firmware" +msgid "Unset the debugging flag during update" +msgstr "Desativa a opção de depuração durante atualização" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Permitir reverter versões de firmware" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Sem suporte ao daemon na versão %s, a versão do cliente é %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Sobrepõe um aviso de plug-in" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Soma de verificação da atualização" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Responde sim para todas as perguntas" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Descrição da atualização" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Não verifica por histórico não relatado" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Duração da atualização" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Não verifica por metadados antigos" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Local da atualização" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Nome da atualização" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Obter todos os dispositivos que suportam atualizações de firmware" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "ID remoto da atualização" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Retorna todos os IDs de hardware para a máquina" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Resumo da atualização" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Instalar as atualizações preparadas agora" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Versão da atualização" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Mostra histórico de atualizações de firmware" +msgid "Update all devices that match local metadata" +msgstr "Atualiza todos os dispositivos que correspondem aos metadados locais" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Apaga todo histórico de atualização de firmware" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "A falha de atualização é um problema conhecido, visite essa URL para mais informações:" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Compartilha histórico de firmware com os desenvolvedores" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Atualizar agora?" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Instalar um arquivo de firmware neste periférico" +msgid "Update the stored device verification information" +msgstr "Atualizar as informações de verificação do dispositivo armazenado" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Obtém detalhes sobre um arquivo de firmware" +msgid "Update the stored metadata with current ROM contents" +msgstr "Atualiza os metadados armazenados com o conteúdo da ROM atual" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Obtém a lista de atualizações para os periféricos conectados" +msgid "Update the stored metadata with current contents" +msgstr "Atualiza os metadados armazenados com o conteúdo atual" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Atualiza todos os firmwares para a última versão disponível" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Obtém o hash criptográfico do firmware despejado" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Atualizando %s de %s para %s… " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Desbloqueia o dispositivo para acesso do firmware" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Atualizando %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Limpa os resultados da última atualização" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Mensagem enviada:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Limpa quaisquer atualizações agendadas a serem atualizadas desconectadas" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Enviar relatório agora?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Obtém os resultados da última atualização" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "O envio de relatórios de firmware ajuda os fornecedores de hardware a identificar rapidamente atualizações com falha e êxito em dispositivos reais." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Obtém os lançamentos para um dispositivo" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Nome de usuário" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Obtém os remotos configurados" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verificando…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Retrocede a versão do firmware em um dispositivo" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Versão" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Renova metadados do servidor remoto" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Aguardando…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Atualiza os metadados armazenados com o conteúdo da ROM atual" +msgid "Watch DFU devices being hotplugged" +msgstr "Monitora dispositivos DFU sendo conectados" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Monitora o daemon por eventos" +msgid "Watch for hardware changes" +msgstr "Monitora alterações no hardware" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Compila o firmware usando um sandbox" +msgid "Write firmware from file into device" +msgstr "Escreve um firmware do arquivo para o dispositivo" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Despeja dados SMBIOS a partir de um arquivo" +msgid "Write firmware from file into one partition" +msgstr "Escreve um firmware do arquivo para uma partição" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Modifica um remoto dado" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Escrevendo…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Utilitário de Firmware" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Seu distribuidor pode não ter verificado qualquer das atualizações de firmware para compatibilidade com seu sistema ou dispositivos conectados." diff -Nru fwupd-1.0.6/po/ru.po fwupd-1.2.10/po/ru.po --- fwupd-1.0.6/po/ru.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/ru.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,17 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Igor , 2017 -# Serge Vylekzhanin , 2015-2018 +# Serge Vylekzhanin , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Russian (http://www.transifex.com/freedesktop/fwupd/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,981 +16,1227 @@ "Language: ru\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Обновить микропрограмму устройства на Linux" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Целью этого проекта является безопасная и надёжная автоматизация обновления микропрограмм в Linux. Для просмотра и применения обновлений вы можете использовать как графический диспетчер программного обеспечения, такой как GNOME Software, так и инструментарий командной строки или даже непосредственно D-Bus интерфейс." +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Осталась %.0f минута" +msgstr[1] "Осталось %.0f минуты" +msgstr[2] "Осталось %.0f минут" +msgstr[3] "Осталось %.0f минут" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Процесс fwupd является простой фоновой службой, позволяющей сеансовому программному обеспечению обновлять микропрограммы устройств на вашем компьютере. Он разработан для настольных компьютеров, но этот проект также годен для использования на телефонах, планшетах и безмониторных серверах." +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Обновление подсистемы Consumer МЕ устройства %s" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Установить подписанную системную микропрограмму" +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Обновление контроллера %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Для обновления микропрограммы на этой машине требуется аутентификация" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Обновление подсистемы Corporate МЕ устройства %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Установить неподписанную системную микропрограмму" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Обновление устройства %s" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Установить старую версию системной микропрограммы" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Обновление встроенного контроллера %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Для понижения версии микропрограммы на этой машине требуется аутентификация" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Обновление подсистемы МЕ устройства %s" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Установить подписанную микропрограмму устройства" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Обновление системы %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Для обновления микропрограммы на съёмном устройстве требуется аутентификация" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Обновление устройства %s" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Установить неподписанную микропрограмму устройства" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "У устройства %s есть обновления прошивки:" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Для понижения версии микропрограммы на съёмном устройстве требуется аутентификация" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u день" +msgstr[1] "%u дня" +msgstr[2] "%u дней" +msgstr[3] "%u дней" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Разблокировать устройство для получения доступа" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u час" +msgstr[1] "%u часа" +msgstr[2] "%u часов" +msgstr[3] "%u часов" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Для разблокировки устройства требуется аутентификация" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u минута" +msgstr[1] "%u минуты" +msgstr[2] "%u минут" +msgstr[3] "%u минут" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Обновление хранимой проверочной информации устройства" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u секунда" +msgstr[1] "%u секунды" +msgstr[2] "%u секунд" +msgstr[3] "%u секунд" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Для обновления хранимых контрольных сумм устройства требуется аутентификация" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Активировать устройства" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Изменить настроенное дистанционное устройство" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Активировать ожидающие устройства" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Для модификации настроенного дистанционного устройства, используемого для обновления микропрограммы, необходима аутентификация" +msgid "Activate the new firmware on the device" +msgstr "Активировать новую прошивку на устройстве" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Псевдоним %s" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Активация обновления прошивки" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Команда не найдена" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Активация обновления прошивки для" #. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 msgid "Added" msgstr "Добавлено" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Удалено" - -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Изменено" - -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Отменено" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Наименование" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Возраст" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Шифр" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Согласиться и активировать репозиторий?" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Регион" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Псевдоним %s" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Найдено" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Разрешить понижение версий прошивок" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Протокол" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Разрешить повторную установку существующих версий прошивок" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Статус" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Завершение обновления требует перезагрузки." -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Доступ запрещен" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Завершение обновления требует выключения системы." -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Порядковое" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Ответить да на все вопросы" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Режим" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Применить бинарный патч" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Применить обновления прошивки" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Одобренная прошивка:" +msgstr[1] "Одобренная прошивка:" +msgstr[2] "Одобренная прошивка:" +msgstr[3] "Одобренная прошивка:" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Состояние" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Вернуть устройство с возможностями DFU к использованию" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Размер передачи" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Подключить в режим прошивки" #. TRANSLATORS: device attributes, i.e. things that #. * the device can do -#: plugins/dfu/dfu-tool.c:2139 msgid "Attributes" msgstr "Атрибуты" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Проблемы" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Аутентификация…" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ID чипа" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Для понижения версии прошивки на съёмном устройстве требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Преобразовать микропрограмму в формат DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Для понижения версии прошивки на этой машине требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Объединить несколько файлов микропрограмм в один" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Для модификации настроенного репозитория, используемого для обновления прошивки, требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Установить идентификатор производителя для файла микропрограммы" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Для изменения настроек фоновой службы требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Установить идентификатор продукта для файла микропрограммы" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Для установки списка одобренных прошивок требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Установить адрес элемента для файла микропрограммы" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Для подписи данных с использованием сертификата клиента требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Установить размер микропрограммы для конечного объекта" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Для переключения на новую версию прошивки требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Установить версию выпуска для файла микропрограммы" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Для разблокировки устройства требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Установить альтернативный номер для файла микропрограммы" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Для обновления прошивки на съёмном устройстве требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Установить альтернативное наименование для файла микропрограммы" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Для обновления прошивки на этой машине требуется аутентификация" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Вернуть устройство с возможностями DFU к использованию" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Для обновления хранимых контрольных сумм устройства требуется аутентификация" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Восстановить исходное состояние устройства DFU" +msgid "Build firmware using a sandbox" +msgstr "Собрать прошивку, используя песочницу" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Считать микропрограмму из устройства файл" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Отменить" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Считать микропрограмму из одного раздела в файл" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Отменено" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Записать микропрограмму из файла на устройство" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Изменено" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Записать микропрограмму из файла на один раздел" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Контрольная сумма" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Вывести список подсоединённых сейчас устройств с возможностями DFU" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Идентификатор чипа" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Отсоединить подсоединённое сейчас устройство с возможностями DFU" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Выберите устройство:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Создать дамп данных по файлу микропрограммы" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Выберите релиз:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Наблюдать за устройствами DFU, которые являются подключёнными" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Шифр" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Зашифровать данные микропрограммы" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Очистить все обновления, которые запланированы для автономного режима" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Расшифровать данные микропрограммы" +msgid "Clears the results from the last update" +msgstr "Очистить результаты c последнего обновления" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Устанавливает метаданные файла микропрограммы" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Команда не найдена" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Заменить данные в существующем файле микропрограммы" +msgid "Convert firmware to DFU format" +msgstr "Преобразовать прошивку в формат DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 msgid "Create a binary patch using two files" msgstr "Создать бинарный патч на основе двух файлов" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Применить бинарный патч" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Вывести дамп информации о бинарном патче на экран" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" +msgid "DFU" +msgstr "DFU" #. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 msgid "DFU Utility" msgstr "Средство работы с DFU" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Не удалось разобрать аргументы" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Параметры отладки" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Перечислить все устройства Synaptics MST" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Распаковка…" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Записать файл микропрограммы на устройство MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Средство многопоточной передачи Synaptics" +msgid "Decrypt firmware data" +msgstr "Расшифровать данные прошивки" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Установка обновления микропрограммы..." +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Описание" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Показать отладочную информацию для всех файлов" +#. TRANSLATORS: command description +msgid "Detach currently attached DFU capable device" +msgstr "Отсоединить подсоединённое сейчас устройство с возможностями DFU" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Показать подробную информацию о приложении" +#. TRANSLATORS: command description +msgid "Detach to bootloader mode" +msgstr "Отключить в режим загрузчика" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Параметры отладки" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Идентификатор устройства" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Показать параметры отладки" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Добавлено устройство:" + +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Заменено устройство:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Удалено устройство:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Устройства, которые были успешно обновлены:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Устройства, которые не были правильно обновлены:" + +msgid "Disabled fwupdate debugging" +msgstr "Отладка fwupdate деактивирована" + +#. TRANSLATORS: command description +msgid "Disables a given remote" +msgstr "Деактивировать данный репозиторий" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Показать версию" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Не проверять старые метаданные" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Не проверять перезагрузку после обновления" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Не проверять незарегистрированную историю" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Не сохранять в базу данных истории" + +#. success +msgid "Done!" +msgstr "Готово!" + +#. TRANSLATORS: command description +msgid "Downgrades the firmware on a device" +msgstr "Понизить версию прошивки на устройстве" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Понижение версии прошивки устройства %s с %s на %s…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Понижение версии прошивки устройства %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Получение..." + +#. TRANSLATORS: command description +msgid "Dump SMBIOS data from a file" +msgstr "Записать данные SMBIOS из файла" + +#. TRANSLATORS: command description +msgid "Dump details about a firmware file" +msgstr "Создать дамп подробных данных о файле прошивки" + +#. TRANSLATORS: command description +msgid "Dump information about a binary patch to the screen" +msgstr "Вывести дамп информации о бинарном патче на экран" + +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Указанный раздел ESP недействителен" + +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Активировать поддержку обновлений прошивки в поддерживаемых системах." + +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Активировать этот репозиторий?" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Активировано" + +msgid "Enabled fwupdate debugging" +msgstr "Отладка fwupdate активирована" + +#. TRANSLATORS: command description +msgid "Enables a given remote" +msgstr "Активировать данный репозиторий" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Активирование этого функционала осуществляется на ваш страх и риск. Это означает, что вам следует обратиться к производителю оборудования относительно любых проблем, вызванных этими обновлениями. Только проблемы с фактическим процессом обновления следует сообщать в $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Активация этого репозитория осуществляется на свой страх и риск." + +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Зашифровать данные прошивки" + +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Стереть всю историю обновлений прошивки" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Стирание…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Выйти после небольшой задержки" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Выйти после загрузки движка" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Не удалось подключиться к фоновой службе" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Не удалось загрузить из-за ограничения сервера" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Не удалось получить ожидающие устройства" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Не удалось установить обновление прошивки" + +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Не удалось загрузить странности" + +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Не удалось разобрать аргументы" + +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Не удалось перезагрузить" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Не удалось установить режим заставки" + +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Получение файла" + +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Получение прошивки" + +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Получение метаданных" + +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Получение подписи" + +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Имя файла" + +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Подпись имени файла" + #. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Служба обновления микропрограммы" +msgid "Firmware Agent" +msgstr "Агент прошивки" + +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Базовый URI прошивки" #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" -msgstr "D-Bus служба обновления микропрограммы" +msgstr "D-Bus служба обновления прошивки" + +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Фоновая служба обновления прошивки" + +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Средство работы с прошивками" + +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Метаданные прошивки не обновлялись в течение %u дня и могут быть устаревшими." +msgstr[1] "Метаданные прошивки не обновлялись в течение %u дней и могут быть устаревшими." +msgstr[2] "Метаданные прошивки не обновлялись в течение %u дней и могут быть устаревшими." +msgstr[3] "Метаданные прошивки не обновлялись в течение %u дней и могут быть устаревшими." + +msgid "Firmware updates are not supported on this machine." +msgstr "Обновления прошивки не поддерживаются на этой машине." + +msgid "Firmware updates are supported on this machine." +msgstr "Обновления прошивки поддерживаются на этой машине." + +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Флаги" + +msgid "Force the action ignoring all warnings" +msgstr "Выполнить действие, игнорируя все предупреждения" + +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Найдено" + +msgid "GUID" +msgstr "GUID" + +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Получить все устройства в соответствии с топологией системы" + +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Получить все устройства и возможные выпуски" + +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Получить все устройства, которые поддерживают обновления прошивки" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Получить все активированные плагины, зарегистрированные в системе" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Получить сведения о файле прошивки" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Получить настроенные репозитории" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Получить криптографической хэш дампа прошивки" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Получить список одобренных прошивок." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Получить список обновлений для подключенного оборудования" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Получить релизы для устройства" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Получить результаты с последнего обновления" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" #. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 msgid "Idle…" msgstr "Бездействие…" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Распаковка…" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Установить двоичную прошивку на устройство" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Установить файл прошивки на это оборудование" + +msgid "Install old version of system firmware" +msgstr "Установить старую версию системной прошивки" + +msgid "Install signed device firmware" +msgstr "Установить подписанную прошивку устройства" + +msgid "Install signed system firmware" +msgstr "Установить подписанную системную прошивку" + +msgid "Install unsigned device firmware" +msgstr "Установить неподписанную прошивку устройства" + +msgid "Install unsigned system firmware" +msgstr "Установить неподписанную системную прошивку" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Установка прошивки…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Установка обновления прошивки…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Installing on %s…" +msgstr "Установка на устройство %s…" + +msgid "Keyring" +msgstr "Хранилище ключей" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Осталось меньше минуты" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (стабильная прошивка)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (тестовая прошивка)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Вывести список подсоединённых сейчас устройств с возможностями DFU" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Вывести список поддерживаемых обновлений прошивки" #. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 msgid "Loading…" msgstr "Загрузка…" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Перезапуск устройства…" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Изменить вручную белый список определённых плагинов" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Чтение…" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Объединить несколько файлов прошивок в один файл" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Запись…" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI метаданных" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Стирание…" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Подпись URI метаданных" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Проверка…" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Метаданные можно получить в Linux Vendor Firmware Service." -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Планировка…" +#. TRANSLATORS: error message +#, c-format +msgid "Mismatched daemon and client, use %s instead" +msgstr "Несовместимые фоновая служба и клиент, используйте %s" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Получение..." +msgid "Mode" +msgstr "Режим" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Аутентификация…" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Изменить значение в конфигурации фоновой службы." -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Ожидание…" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Модифицировать данный репозиторий" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Неизвестно" +msgid "Modify a configured remote" +msgstr "Изменить настроенный репозиторий" + +msgid "Modify daemon configuration" +msgstr "Изменить настройки фоновой службы" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Следить за событиями в фоновой службе" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Наименование" + +msgid "No action specified!" +msgstr "Не определено никаких действий." + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Не обнаружено оборудования с возможностью обновления прошивки" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Плагины не найдены" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "В настоящее время репозитории не активированы, поэтому метаданные недоступны." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Обновления не были применены" + +msgid "OK" +msgstr "ОК" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Переопределить предупреждение плагина" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Переопределить путь ESP по умолчанию" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Отменить предупреждения и выполнить действие" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Пароль" + +msgid "Payload" +msgstr "Полезная нагрузка" + +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Процент завершения" + +msgid "Permission denied" +msgstr "Доступ запрещен" #. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 #, c-format msgid "Please enter a number from 0 to %u: " -msgstr "" +msgstr "Пожалуйста, введите число от 0 до %u:" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Выберите устройство:" +msgid "Print the version number" +msgstr "Напечатать номер версии" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Print verbose debug statements" +msgstr "Напечатать подробные отладочные отчёты" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Приоритет" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +msgid "Proceed with upload?" +msgstr "Продолжить загрузку?" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Протокол" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Запросить поддержку обновления прошивки" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Не обнаружено оборудования с возможностью обновления микропрограммы" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Странности" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Считать прошивку из устройства в файл" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Считать прошивку из одного раздела в файл" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Чтение…" + +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Перезагрузка…" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Обновить метаданные с удаленного сервера" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Регион" #. TRANSLATORS: the first replacement is a display name #. * e.g. "ColorHugALS" and the second is a version number #. * e.g. "1.2.3" -#: src/fu-util.c:651 #, c-format msgid "Reinstalling %s with %s... " msgstr "Переустановка %s с %s…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Понижение версии %s с %s на %s…" +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Репозиторий" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Обновление %s с %s на %s…" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Идентификатор репозитория" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Готово!" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Удалено" -#: src/fu-util.c:726 -msgid "Target" -msgstr "" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Заменить данные в существующем файле прошивки" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "URI для отчета" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Требуется подключение к сети Интернет" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Восстановить исходное состояние устройства DFU" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Перезагрузить сейчас?" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "ОК" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Перезапустить фоновую службу, чтобы изменения вступили в силу?" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Получение подписи" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Перезапуск устройства…" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Получение метаданных" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Показать идентификаторы всех устройств на машине" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Получение микропрограммы" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Запустить процедуру очистки составного плагина, используя двоичную установку" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Получение файла" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Запустить процедуру подготовки составного плагина, используя двоичную установку" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Версия" +msgid "Runtime" +msgstr "Время выполнения" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Сохранить состояние устройства в файл JSON между выполнениями" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "Дистанционное устройство" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Запланировать установку на следующую перезагрузку, если это возможно" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Планировка…" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Описание" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Порядковое" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Контрольная сумма" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Установить альтернативное наименование для файла прошивки" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Выберите релиз:" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Установить альтернативный номер для файла прошивки" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Установить адрес элемента для файла прошивки" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Установить идентификатор продукта для файла прошивки" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "У %s есть обновления микропрограммы:" +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Установить версию выпуска для файла прошивки" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Установить флаг отладки во время обновления" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Установить размер прошивки для конечного объекта" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Установить идентификатор производителя для файла прошивки" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Установить метаданные файла прошивки" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +msgid "Sets the list of approved firmware" +msgstr "Установить список одобренных прошивок" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Версия обновления" +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Установить список одобренных прошивок." -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Поделиться историей прошивки с разработчиками" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Показать версии клиента и фоновой службы" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Удалённый ID обновления" +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Показать подробную информацию о фоновой службе для определенного домена" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Контрольная сумма обновления" +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Показать отладочную информацию для всех доменов" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Расположение обновления" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Показать параметры отладки" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Описание обновления" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Показать необновляемые устройства" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Удалённый ID" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Показать дополнительную отладочную информацию" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Заголовок" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Показать историю обновлений прошивки" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Тип" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Показать подробную информацию о плагине" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Хранилище ключей" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Показать журнал отладки с последней попытки обновления" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Включено" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Показать информацию о состоянии обновления прошивки" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Возраст" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Выключить сейчас?" + +msgid "Sign data using the client certificate" +msgstr "Подписать данные с использованием сертификата клиента" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Подписать данные с использованием сертификата клиента" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Приоритет" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Подписать загруженные данные с использованием сертификата клиента" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Имя пользователя" +msgid "Signature" +msgstr "Подпись" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Пароль" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Определить идентификатор(ы) поставщика / продукта устройства DFU" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Имя файла" +msgid "Specify the number of bytes per USB transfer" +msgstr "Определить количество байтов на передачу USB" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Подпись имени файла" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Состояние" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI метаданных" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Статус" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Подпись URI метаданных" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Сводка" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "База URI микропрограммы" +msgid "Target" +msgstr "Цель" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS — это бесплатный сервис, действующий как независимое юридическое лицо, которое не имеет связи с системой $OS_RELEASE:NAME$. Ваш распространитель системы может не проверять какие-либо обновления прошивки на совместимость с системой или подключенными устройствами. Каждая прошивка поставляется только производителем оригинального оборудования." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Одобренной прошивки нет." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Эта программа может корректно работать только как root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Этот репозиторий содержит прошивки, которое не запрещены, но все еще тестируются производителем оборудования. Вы должны убедиться, что у вас есть способ вручную понизить версию прошивки устройства в случае сбоя при обновлении." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Этот инструмент может использовать только пользователь root" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Добавлено устройство:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Заголовок" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Изъято устройство:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Размер передачи" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Заменено устройство:" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Тип" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Средство для прошивки UEFI" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Показать дополнительную отладочную информацию" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Неизвестно" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Показать версии клиента и фоновой службы" +msgid "Unlock the device to allow access" +msgstr "Разблокировать устройство для получения доступа" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Планирование установки на следующую перезагрузку, если это возможно" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Разблокировать устройство для доступа к прошивке" #. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Разрешить повторную установку существующих версий микропрограмм" +msgid "Unset the debugging flag during update" +msgstr "Снять флаг отладки во время обновления" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Разрешить понижение версий микропрограмм" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Неподдерживаемая фоновая служба версии %s, клиент версии %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Переопределить предупреждение приложения" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Контрольная сумма обновления" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Описание обновления" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Продолжительность обновления" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Расположение обновления" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Наименование обновления" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Получить все устройства, которые поддерживают обновления микропрограммы" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Обновить идентификатор репозитория" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Показать ID всех устройств на машине" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Сводка обновления" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Установить подготовленные обновления сейчас" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Версия обновления" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Update all devices that match local metadata" +msgstr "Обновить все устройства, которые соответствуют локальным метаданным" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Ошибка обновления — известная проблема, посетите этот URL для получения дополнительной информации:" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Обновить сейчас?" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Установить файл микропрограммы на это оборудование" +msgid "Update the stored device verification information" +msgstr "Обновить хранимую проверочную информацию устройства" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Получает сведения о файле микропрограммы" +msgid "Update the stored metadata with current ROM contents" +msgstr "Обновить сохранённые метаданные с текущим содержимым ПЗУ" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Получает список обновлений для подключенного оборудования" +msgid "Update the stored metadata with current contents" +msgstr "Обновить сохраненные метаданные с текущим содержимым" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" -msgstr "Обновляет все микропрограммы до их последних доступных версий" +msgstr "Обновить все прошивки до их последних доступных версий" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Получает криптографической хэш дампа микропрограммы" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Обновление %s с %s на %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Разблокирует устройство для доступа к микропрограмме" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Обновление устройства %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Очищает результаты c последнего обновления" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Загрузить сообщение:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Очищает все обновления, которые запланированы для автономного режима" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Загрузить отчет сейчас?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Получает результаты с последнего обновления" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Загрузка отчетов о прошивке помогает поставщикам оборудования быстро определять неудачные и успешные обновления на реальных устройствах." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Получает релизы для устройства" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Имя пользователя" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Получает настроенные дистанционные устройства" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Проверка…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Скачивает микропрограмму на устройство" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Версия" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Обновить метаданные с удаленного сервера" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Ожидание…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Обновить хранимые метаданные с текущим содержимым ПЗУ" +msgid "Watch DFU devices being hotplugged" +msgstr "Следить за устройствами DFU, которые являются подключёнными" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Следить за событиями в фоновой службе" +msgid "Watch for hardware changes" +msgstr "Следить за аппаратными изменениями" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Собрать микропрограмму с помощью песочницы" +msgid "Write firmware from file into device" +msgstr "Записать прошивку из файла на устройство" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Записать данные SMBIOS из файла" +msgid "Write firmware from file into one partition" +msgstr "Записать прошивку из файла на один раздел" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Модифицирует данное дистанционное устройство" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Запись…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Средство работы с микропрограммами" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Ваш распространитель системы может не проверять какие-либо обновления прошивки на совместимость с системой или подключенными устройствами." diff -Nru fwupd-1.0.6/po/sk.po fwupd-1.2.10/po/sk.po --- fwupd-1.0.6/po/sk.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/sk.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,997 +1,386 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Dušan Kazik , 2015-2017 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Slovak (http://www.transifex.com/freedesktop/fwupd/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sk\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "Pre zariadenie %s sú dostupné aktualizácie firmvéru:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Pridané" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Prezývka príkazu %s" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Nainštaluje podpísaný firmvér systému" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Umožní zníženie verzií firmvéru" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Na aktualizovanie firmvéru v tomto počítači je potrebné overenie totožnosti" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Umožní preinštalovanie existujúcich vedzií firmvéru" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Nainštaluje nepodpísaný firmvér systému" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Zavedie zariadenie DFU späť do prevádzky" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Nainštaluje staršiu verziu firmvéru systému" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Vyžaduje sa overenie totožnosti na prechod na staršiu verziu firmvéru vymeniteľného zariadenia" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Vyžaduje sa overenie totožnosti na prechod na staršiu verziu firmvéru v tomto počítači" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Nainštaluje podpísaný firmvér zariadenia" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Vyžaduje sa overenie totožnosti na aktualizovanie firmvéru vymeniteľného zariadenia " - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Nainštaluje nepodpísaný firmvér zariadenia" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Vyžaduje sa overenie totožnosti na prechod na staršiu verziu firmvéru vymeniteľného zariadenia" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Odomknúť zariadenie na umožnenie prístupu" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Na odomknutie zariadenia sa vyžaduje overenie totožnosti" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Vyžaduje sa overenie totožnosti na aktualizovanie firmvéru vymeniteľného zariadenia " #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Prezývka príkazu %s" - -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Príkaz nenájdený" - -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Pridané" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Na aktualizovanie firmvéru v tomto počítači je potrebné overenie totožnosti" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Odstránené" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Zrušené" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Zmenené" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Zrušené" - -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" - -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Názov" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrolný medzisúčet" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Šifra" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Oblasť" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Nájdené" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokol" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Stav" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Sériové číslo" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Režim" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" - -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Stav" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Veľkosť prenosu" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" - -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Neobvyklé požiadavky" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Vymaže výsledky z poslednej aktualizácie" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Príkaz nenájdený" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 msgid "Convert firmware to DFU format" msgstr "Skonvertuje firmvér do formátu DFU" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Zlúči viacero súborov s firmvérami do jedného" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Nastaví ID výrobcu pre súbor s firmvérom" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Nastaví ID produktu pre súbor s firmvérom" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Nastaví verziu vydania pre súbor s firmvérom" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Nastaví alternatívne číslo pre súbor s firmvérom" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Nástroj pre DFU" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Nastaví alternatívny názov pre súbor s firmvérom" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Voľby ladenia" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Zavedie zariadenie DFU späť do prevádzky" +msgid "Decrypt firmware data" +msgstr "Dešifruje údaje firmvéru" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Popis" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Prečíta firmvér zo zariadenia do súboru" +msgid "Detach currently attached DFU capable device" +msgstr "Odpojí aktuálne pripojené zariadenie DFU" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Prečíta firmvér z jedného oddielu do súboru" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Pridané zariadenie:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Zapíše firmvér zo súboru do zariadenia" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Zmenené zariadenie:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Zapíše firmvér zo súboru do jedného oddielu" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Odstránené zariadenie:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Vypíše zoznam aktuálne pripojených zariadení DFU" +#. success +msgid "Done!" +msgstr "Hotovo!" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Odpojí aktuálne pripojené zariadenie DFU" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Vracia sa %s z verzie %s na verziu %s... " #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Zahodí podrobnosti o súbore s firmvérom" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Sleduje pripojenie zariadení DFU" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 msgid "Encrypt firmware data" msgstr "Zašifruje údaje firmvéru" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Dešifruje údaje firmvéru" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Nastaví metaúdaje pre súbor s firmvérom" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Nástroj pre DFU" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Zlyhalo analyzovanie parametrov" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Zobrazí ladiace informácie pre všetky súbory" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Voľby ladenia" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Zobrazí voľby ladenia" - #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Skončí po krátkom oneskorení" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Skončí po načítaní jadra" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Démon aktualizácie firmvéru" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Zlyhalo analyzovanie parametrov" #. TRANSLATORS: program summary -#: src/fu-main.c:1058 msgid "Firmware Update D-Bus Service" msgstr "Služba zbernice D-Bus na aktualizovanie firmvéru" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" - -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Nezistil sa žiadny hardvér s možnosťou aktualizácie firmvéru" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Preinštalováva sa %s verziou %s... " - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Vracia sa %s z verzie %s na verziu %s... " - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Aktualizuje sa %s z verzie %s na verziu %s... " - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Hotovo!" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "OK" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Verzia" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Popis" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Kontrolný medzisúčet" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "Pre zariadenie %s sú dostupné aktualizácie firmvéru:" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Verzia aktualizácie" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Kontrolný medzisúčet aktualizácie" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Umiestnenie aktualizácie" - -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Popis aktualizácie" - -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Démon aktualizácie firmvéru" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Nástroj pre firmvéry" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Nájdené" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Získa všetky zariadenia, ktoré podporujú aktualizovanie firmvéru" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Získa podrobnosti o súbore firmvéru" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Získa kryptografický medzisúčet stiahnutého firmvéru" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Získa zoznam aktualizácií pre pripojený hardvér" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Získa výsledky z poslednej aktualizácie" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Nainštaluje súbor firmvéru do tohoto hardvéru" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" +msgid "Install old version of system firmware" +msgstr "Nainštaluje staršiu verziu firmvéru systému" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" +msgid "Install signed device firmware" +msgstr "Nainštaluje podpísaný firmvér zariadenia" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" +msgid "Install signed system firmware" +msgstr "Nainštaluje podpísaný firmvér systému" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +msgid "Install unsigned device firmware" +msgstr "Nainštaluje nepodpísaný firmvér zariadenia" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Pridané zariadenie:" +msgid "Install unsigned system firmware" +msgstr "Nainštaluje nepodpísaný firmvér systému" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Odstránené zariadenie:" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Vypíše zoznam aktuálne pripojených zariadení DFU" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Zmenené zariadenie:" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Zlúči viacero súborov s firmvérami do jedného" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +msgid "Mode" +msgstr "Režim" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Sleduje démona kvôli udalostiam" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Zobrazovať dodatočné ladiace informácie" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Názov" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Nezistil sa žiadny hardvér s možnosťou aktualizácie firmvéru" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" +msgid "OK" +msgstr "OK" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Umožní preinštalovanie existujúcich vedzií firmvéru" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokol" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Umožní zníženie verzií firmvéru" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Neobvyklé požiadavky" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Prečíta firmvér zo zariadenia do súboru" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Prečíta firmvér z jedného oddielu do súboru" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Obnoví metaúdaje zo vzdialeného servera" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Oblasť" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Preinštalováva sa %s verziou %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Získa všetky zariadenia, ktoré podporujú aktualizovanie firmvéru" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Odstránené" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Sériové číslo" #. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Nainštaluje pripravené aktualizácie ihneď" +msgid "Set alternative name on firmware file" +msgstr "Nastaví alternatívny názov pre súbor s firmvérom" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +msgid "Set alternative number on firmware file" +msgstr "Nastaví alternatívne číslo pre súbor s firmvérom" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +msgid "Set product ID on firmware file" +msgstr "Nastaví ID produktu pre súbor s firmvérom" #. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +msgid "Set release version on firmware file" +msgstr "Nastaví verziu vydania pre súbor s firmvérom" #. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Nainštaluje súbor firmvéru do tohoto hardvéru" +msgid "Set vendor ID on firmware file" +msgstr "Nastaví ID výrobcu pre súbor s firmvérom" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Získa podrobnosti o súbore firmvéru" +msgid "Sets metadata on a firmware file" +msgstr "Nastaví metaúdaje pre súbor s firmvérom" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Získa zoznam aktualizácií pre pripojený hardvér" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Zobrazí voľby ladenia" -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Aktualizuje všetok firmvér na najnovšiu dostupnú verziu" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Zobrazovať dodatočné ladiace informácie" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Získa kryptografický medzisúčet stiahnutého firmvéru" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Stav" -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Odomkne zariadenie pre prístup k firmvéru" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Stav" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Vymaže výsledky z poslednej aktualizácie" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Veľkosť prenosu" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" +msgid "Unlock the device to allow access" +msgstr "Odomknúť zariadenie na umožnenie prístupu" #. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Získa výsledky z poslednej aktualizácie" +msgid "Unlocks the device for firmware access" +msgstr "Odomkne zariadenie pre prístup k firmvéru" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Kontrolný medzisúčet aktualizácie" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Popis aktualizácie" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Umiestnenie aktualizácie" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Obnoví metaúdaje zo vzdialeného servera" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Verzia aktualizácie" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "Aktualizuje uložené metaúdaje s aktuálnym obsahom pamäte ROM" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Sleduje démona kvôli udalostiam" +msgid "Updates all firmware to latest versions available" +msgstr "Aktualizuje všetok firmvér na najnovšiu dostupnú verziu" -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Aktualizuje sa %s z verzie %s na verziu %s... " + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Verzia" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" +msgid "Watch DFU devices being hotplugged" +msgstr "Sleduje pripojenie zariadení DFU" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" +msgid "Write firmware from file into device" +msgstr "Zapíše firmvér zo súboru do zariadenia" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Nástroj pre firmvéry" +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "Zapíše firmvér zo súboru do jedného oddielu" diff -Nru fwupd-1.0.6/po/sr.po fwupd-1.2.10/po/sr.po --- fwupd-1.0.6/po/sr.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/sr.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Miloš Popović , 2016 # Марко М. Костић (Marko M. Kostić) , 2015-2018 @@ -10,9 +10,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Serbian (http://www.transifex.com/freedesktop/fwupd/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,980 +17,728 @@ "Language: sr\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Ажурирајте фирмвер уређаја на Линуксу" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s има ажурирања за фирмвер:" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Сврха овог пројекта је да учини ажурирање фирмвера на Линуксу лаким, безбедним и поузданим. Можете користити графичког управника програма као што су то Гномови Програми да бисте гледали и примењивали исправке, командну алатку или D-Bus интерфејс директно." +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Додао" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Fwupd процес је једноставан демно који омогућава програмиму у сесији да ажурира фирмвер уређаја на вашој локалној машини. Намењен је за стоне рачунаре али је овај пројекат могуће користити на телефонима, таблетима и безглавим серверима." +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Старост" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Инсталирајте потписани системски фирмвер" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Алијас на %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Потребна је пријава за ажурирање фирмвера на овој машини" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Дозволи уназађивање издања фирмвера" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Инсталирајте непотписани системски фирмвер" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Дозволи поновно инсталирање већ постојећих издања фирмвера" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Инсталирајте старо издање системског фирмвера" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Потребно је поново покретање да би се исправка применила." -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Потребна је пријава за уназађивање фирмвера на овој машини" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Одговори са да на сва питања" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Инсталирајте потписани фирмвер за уређаје" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Примени бинарну закрпу" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Потребна је пријава за ажурирање фирмвера на преносивом уређају" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Закачи уређај способан за ДФУ назад на извршно окружење" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Инсталирајте непотписани фирмвер за уређаје" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Особине" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Идентификујем…" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" +msgid "Authentication is required to downgrade the firmware on a removable device" msgstr "Потребна је пријава за уназађивање фирмвера на преносивом уређају" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Откључајте уређај да бисте дозволили приступ" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Потребна је пријава за уназађивање фирмвера на овој машини" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Идентификовање је потребно за измену подешеног удаљеног сервера који се користи за ажурирања фирмвера" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Потребна је пријава за откључавање уређаја" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Ажурирајте причуване податке потврђивања уређаја" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Потребна је пријава за ажурирање причуваних сума провере за уређај" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Измени подешени удаљени сервер" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Потребна је пријава за ажурирање фирмвера на преносивом уређају" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Идентификовање је потребно за измену подешеног удаљеног сервера који се користи за ажурирања фирмвера" - -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Алијас на %s" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Потребна је пријава за ажурирање фирмвера на овој машини" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Наредба није пронађена" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Потребна је пријава за ажурирање причуваних сума провере за уређај" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Додао" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Изгради фирмвер унутар кутије" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Уклонио" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Отказао" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Променио" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Отказао" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Чек-сума" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ИБ" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "ИБ чипа" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Назив" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Изаберите уређај:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Изаберите издање:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Шифрар" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Област" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Нашао" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Протокол" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Статус" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Очисти сва ажурирања заказана за ажурирање ван мреже" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Приступ је одбијен" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Чисти резултате последњег ажурирања" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Серијски" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Наредба није пронађена" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Режим" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Претвори фирмвер у ДФУ формат" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Извршно окружење" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Направи бинарну закрпу уз помоћ две датотеке" -#: plugins/dfu/dfu-tool.c:2115 msgid "DFU" msgstr "ДФУ" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Стање" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Величина преноса" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Особине" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "ДФУ алатка" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Непрецизности" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Опције отклањања проблема" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "ИБ чипа" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Распакујем…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Претвори фирмвер у ДФУ формат" +msgid "Decrypt firmware data" +msgstr "Дешифруј податке у фирмверу" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Споји више датотека са фирмвером у једну" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Опис" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Подеси ИБ продавца на датотеци са фирмвером" +msgid "Detach currently attached DFU capable device" +msgstr "Откачи тренутно закачен уређај способан за ДФУ" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Подеси ИБ производа на датотеци са фирмвером" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Додат је уређај:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Подешава адресу елемента на датотеци фирмвера" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Промењен је уређај:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Подешава величину фирмвера за мету" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Уклоњен је уређај:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Подеси издање објаве на датотеци са фирмвером" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Уређаји који су ажурирани исправно:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Подеси алтернативни број на датотеци са фирмвером" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Уређаји који нису ажурирани исправно:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Подеси алтернативно име на датотеци са фирмвером" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Не проверавај старе метаподатке" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Закачи уређај способан за ДФУ назад на извршно окружење" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Не проверавај да ли је потребно поновно покретање након ажурирања" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Ресетуј ДФУ уређај" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Исчитај фирмвер са уређаја у датотеку" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Не проверавај непослати историјат" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Исчитај фирмвер са једне партиције у датотеку" +#. success +msgid "Done!" +msgstr "Урађено!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Упиши фирмвер из датотеке у уређај" +msgid "Downgrades the firmware on a device" +msgstr "Уназађује фирмвер на уређају" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Упиши фирмвер из датотеке у једну партицију" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Уназађујем %s са %s на %s..." -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Прикажи списак закачених уређаја способних за ДФУ" +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Преузимам…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Откачи тренутно закачен уређај способан за ДФУ" +msgid "Dump SMBIOS data from a file" +msgstr "Ишчитај SMBIOS податке из датотеке" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Истовари детаље о датотеци са фирмвером" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Надгледај ДФУ уређаје док се каче на живо" +msgid "Dump information about a binary patch to the screen" +msgstr "Избаци податке о бинарној закрпи на екран" + +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Омогућено" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 msgid "Encrypt firmware data" msgstr "Шифруј податке у фирмверу" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Дешифруј податке у фирмверу" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Подешава метаподатке у датотеци фирмвера" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Замењује податке у постојећој датотеци фирмвера" +msgid "Erase all firmware update history" +msgstr "Обриши сав историјат ажурирања фирмвера" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Направи бинарну закрпу уз помоћ две датотеке" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Бришем…" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Примени бинарну закрпу" +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Изађи након малог застоја" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Избаци податке о бинарној закрпи на екран" +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Изађи након учитавања мотора" #. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 msgid "Failed to load quirks" msgstr "Нисам могао да учитам ћефове" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "ДФУ алатка" - #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "Не могу да обрадим аргументе" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Набраја све МСТ уређаје Синаптика" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Флешује датотеку фирмвера на МСТ уређај" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Синаптикова вишетоковна алатка преноса" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Добављам датотеку" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Инсталирам ажурирање фирмвера…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Добављам фирмвер" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Прикажи податке о отклањању проблема за све датотеке" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Добављам мета-податке" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Прикажи опширне податке о прикључку" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Добављам потпис" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Опције отклањања проблема" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Назив датотеке" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Прикажи опције за отклањање проблема" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Потпис назива датотеке" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Изађи након малог застоја" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Основни URI фирмвера" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Изађи након учитавања мотора" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Д-Бус услуга ажурирања фирмвера" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" msgstr "Демон за ажурирање фирмвера" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Д-Бус услуга ажурирања фирмвера" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Алатка за фирмвер" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Мирујем…" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Метаподаци фирмвера нису ажурирани %u дан и можда су застарели." +msgstr[1] "Метаподаци фирмвера нису ажурирани %u дана и можда су застарели." +msgstr[2] "Метаподаци фирмвера нису ажурирани %u дана и можда су застарели." -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Распакујем…" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Нашао" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Учитавам…" +msgid "GUID" +msgstr "ГУИД" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Поново покрећем уређај…" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Добави све уређаје који подржавају ажурирање фирмвера" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Читам…" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Добави појединости о датотеци са фирмвером" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Пишем…" +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Добавља подешена удаљена места" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Бришем…" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Добавља криптографски хеш извађеног фирмвера" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Проверавам…" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Добави списак свих ажурирања за повезани уређај" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Заказујем…" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Добавља издања за уређај" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Преузимам…" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Добавља резултате последњег ажурирања" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Идентификујем…" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ИБ" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Чекам…" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Мирујем…" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Непознато" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Инсталирај датотеку са фирмвером на овај уређај" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Install old version of system firmware" +msgstr "Инсталирајте старо издање системског фирмвера" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Изаберите уређај:" +msgid "Install signed device firmware" +msgstr "Инсталирајте потписани фирмвер за уређаје" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Install signed system firmware" +msgstr "Инсталирајте потписани системски фирмвер" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Уређаји који нису ажурирани исправно:" +msgid "Install unsigned device firmware" +msgstr "Инсталирајте непотписани фирмвер за уређаје" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Уређаји који су ажурирани исправно:" +msgid "Install unsigned system firmware" +msgstr "Инсталирајте непотписани системски фирмвер" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Отпремити извештај сада?" +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Инсталирам ажурирање фирмвера…" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Захтева везу са интернетом" +msgid "Keyring" +msgstr "Привезак" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Нема хардвера којем се може ажурирати фирмвер" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Прикажи списак закачених уређаја способних за ДФУ" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Поново инсталирам %s са %s..." +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Учитавам…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Уназађујем %s са %s на %s..." +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Споји више датотека са фирмвером у једну" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "Ажурирам %s са %s на %s..." +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "URI метаподатака" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Урађено!" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Потпис URI-ја метаподатака" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Мета" +msgid "Mode" +msgstr "Режим" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "Товар" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Мења дати удаљени сервер" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "Наставити са отпремањем?" +msgid "Modify a configured remote" +msgstr "Измени подешени удаљени сервер" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Узрок неуспеха ажурирања је познат, погледајте ову адресу за више података:" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Прати демона за догађајима" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Отпремна порука:" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Назив" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Нема хардвера којем се може ажурирати фирмвер" -#: src/fu-util.c:1034 src/fu-util.c:1414 msgid "OK" msgstr "У реду" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Добављам потпис" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Превазилази упозорења прикључка" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Добављам мета-податке" +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Лозинка" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Добављам фирмвер" +msgid "Payload" +msgstr "Товар" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Добављам датотеку" +msgid "Permission denied" +msgstr "Приступ је одбијен" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Издање" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Важност" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Сажетак" +msgid "Proceed with upload?" +msgstr "Наставити са отпремањем?" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "Удаљени" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Протокол" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "УРИ" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Непрецизности" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Опис" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Исчитај фирмвер са уређаја у датотеку" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Чек-сума" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Исчитај фирмвер са једне партиције у датотеку" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Изаберите издање:" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Читам…" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "Метаподаци фирмвера нису ажурирани %u дан и можда су застарели." -msgstr[1] "Метаподаци фирмвера нису ажурирани %u дана и можда су застарели." -msgstr[2] "Метаподаци фирмвера нису ажурирани %u дана и можда су застарели." +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Освежава метаподатке са удаљеног сервера" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Ажурирати сада?" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Област" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" #, c-format -msgid "%s has firmware updates:" -msgstr "%s има ажурирања за фирмвер:" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "ГУИД" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Верзија ажурирања" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Назив ажурирања" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Сажетак ажурирања" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "ИБ удаљене исправке" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Сума провере ажурирања" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Место ажурирања" +msgid "Reinstalling %s with %s... " +msgstr "Поново инсталирам %s са %s..." -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Опис ажурирања" +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "Удаљени" #. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 msgid "Remote ID" msgstr "Удаљени ИБ" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Наслов" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Врста" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Привезак" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Омогућено" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Старост" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Важност" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Корисничко име" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Лозинка" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Назив датотеке" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Потпис назива датотеке" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "URI метаподатака" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Потпис URI-ја метаподатака" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Уклонио" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Основни URI фирмвера" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Замењује податке у постојећој датотеци фирмвера" #. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 msgid "Report URI" -msgstr "URI извештаја" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Додат је уређај:" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Уклоњен је уређај:" +msgstr "URI извештаја" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Промењен је уређај:" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Захтева везу са интернетом" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Потребно је поново покретање да би се исправка применила." +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Ресетуј ДФУ уређај" #. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 msgid "Restart now?" msgstr "Поново покренути сада?" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Прикажи додатне податке за отклањање проблема" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Поново покрећем уређај…" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Прикажи издања клијента и демона" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Враћа све ИБ-јеве хардвера на машини" + +msgid "Runtime" +msgstr "Извршно окружење" #. TRANSLATORS: command line option -#: src/fu-util.c:2122 msgid "Schedule installation for next reboot when possible" msgstr "Заказује инсталирање за следеће подизање система када је могуће" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Дозволи поновно инсталирање већ постојећих издања фирмвера" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Дозволи уназађивање издања фирмвера" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Превазилази упозорења прикључка" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Заказујем…" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Одговори са да на сва питања" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Серијски" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Не проверавај непослати историјат" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Подеси алтернативно име на датотеци са фирмвером" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Не проверавај старе метаподатке" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Подеси алтернативни број на датотеци са фирмвером" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Не проверавај да ли је потребно поновно покретање након ажурирања" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Подешава адресу елемента на датотеци фирмвера" #. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Добави све уређаје који подржавају ажурирање фирмвера" +msgid "Set product ID on firmware file" +msgstr "Подеси ИБ производа на датотеци са фирмвером" #. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Враћа све ИБ-јеве хардвера на машини" +msgid "Set release version on firmware file" +msgstr "Подеси издање објаве на датотеци са фирмвером" #. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Инсталирај припремљена ажурирања сад" +msgid "Set the firmware size for the target" +msgstr "Подешава величину фирмвера за мету" #. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Прикажи историјат ажурирања фирмвера" +msgid "Set vendor ID on firmware file" +msgstr "Подеси ИБ продавца на датотеци са фирмвером" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Обриши сав историјат ажурирања фирмвера" +msgid "Sets metadata on a firmware file" +msgstr "Подешава метаподатке у датотеци фирмвера" #. TRANSLATORS: command description -#: src/fu-util.c:2196 msgid "Share firmware history with the developers" msgstr "Подели историјат фирмвера са програмерима" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Инсталирај датотеку са фирмвером на овај уређај" +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Прикажи издања клијента и демона" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Добави појединости о датотеци са фирмвером" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Прикажи опције за отклањање проблема" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Добави списак свих ажурирања за повезани уређај" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Прикажи додатне податке за отклањање проблема" #. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "Ажурира сав фирмвер на последња доступна издања" +msgid "Show history of firmware updates" +msgstr "Прикажи историјат ажурирања фирмвера" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Добавља криптографски хеш извађеног фирмвера" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Прикажи опширне податке о прикључку" + +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Стање" + +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Статус" + +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Сажетак" + +msgid "Target" +msgstr "Мета" + +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Наслов" + +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Величина преноса" + +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Врста" + +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "УРИ" + +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Непознато" + +msgid "Unlock the device to allow access" +msgstr "Откључајте уређај да бисте дозволили приступ" #. TRANSLATORS: command description -#: src/fu-util.c:2232 msgid "Unlocks the device for firmware access" msgstr "Откључава уређај за приступ фирмверу" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Чисти резултате последњег ажурирања" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Сума провере ажурирања" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Очисти сва ажурирања заказана за ажурирање ван мреже" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Опис ажурирања" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Добавља резултате последњег ажурирања" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Место ажурирања" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Добавља издања за уређај" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Назив ажурирања" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Добавља подешена удаљена места" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "ИБ удаљене исправке" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Уназађује фирмвер на уређају" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Сажетак ажурирања" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Освежава метаподатке са удаљеног сервера" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Верзија ажурирања" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Узрок неуспеха ажурирања је познат, погледајте ову адресу за више података:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Ажурирати сада?" + +msgid "Update the stored device verification information" +msgstr "Ажурирајте причуване податке потврђивања уређаја" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "Ажурирај ускладиштене метаподатке са тренутним садржајима РОМ-а" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Прати демона за догађајима" +msgid "Updates all firmware to latest versions available" +msgstr "Ажурира сав фирмвер на последња доступна издања" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Ажурирам %s са %s на %s..." + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Отпремна порука:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Отпремити извештај сада?" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Корисничко име" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Проверавам…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Издање" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Чекам…" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Изгради фирмвер унутар кутије" +msgid "Watch DFU devices being hotplugged" +msgstr "Надгледај ДФУ уређаје док се каче на живо" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Ишчитај SMBIOS податке из датотеке" +msgid "Write firmware from file into device" +msgstr "Упиши фирмвер из датотеке у уређај" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Мења дати удаљени сервер" +msgid "Write firmware from file into one partition" +msgstr "Упиши фирмвер из датотеке у једну партицију" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Алатка за фирмвер" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Пишем…" diff -Nru fwupd-1.0.6/po/sv.po fwupd-1.2.10/po/sv.po --- fwupd-1.0.6/po/sv.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/sv.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,19 +1,17 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Anders Jonsson , 2017 +# Anders Jonsson , 2017,2019 # Andreas Henriksson , 2017 -# Josef Andersson , 2015,2017 +# Josef Andersson , 2015,2017-2018 # Josef Andersson , 2015,2017 +# Sebastian Rasmussen , 2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Swedish (http://www.transifex.com/freedesktop/fwupd/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,979 +19,973 @@ "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Uppdatera enhetens fasta programvara på Linux" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "%.0fminut kvarstår" +msgstr[1] "%.0f minuter kvarstår" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Detta projekt strävar efter att göra uppdatering av fast programvara på Linux automatisk, säker och pålitlig. Du kan antingen använda ett grafiskt användargränssnitt som GNOME Programvara för att granska och applicera uppdateringar, ett kommandoradsverktyg eller direkt mot D-Bus gränssnittet." +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s har uppdateringar för fast programvara:" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Fwupd-processen är en enkel demon som tillåter sessions-programvara att uppdatera enheters fasta programvara på din lokala maskin. Det är utformat för skrivbordsmiljöer, men detta projekt är också användbart på telefoner, surfplattor och skärmlösa servrar." +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u dag" +msgstr[1] "%u dagar" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Installera signerad fast programvara för systemet" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u timme" +msgstr[1] "%u timmar" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Autentisering krävs för att uppdatera den fasta programvaran för denna maskin" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%uminut" +msgstr[1] "%u minuter" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Installera osignerad fast programvara för systemet" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u sekund" +msgstr[1] "%u sekunder" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Installera en gammal version av fast programvara för systemet" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Tillagd" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Autentisering krävs för att nedgradera den fasta programvaran på denna maskin" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Ålder" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Installera signerad fast programvara för enhet" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Samtyck och aktivera fjärren?" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Autentisering krävs för att uppdatera den fasta programvaran på en flyttbar enhet" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "Alias för %s" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Installera osignerad fast programvara för enhet" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Tillåt att nedgradera versioner av fast programvara" + +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Tillåt att installera om befintliga versioner av fast programvara" + +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "En uppdatering kräver en omstart för att färdigställas." + +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Svara ja på alla frågor" + +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Applicera en binär lagning" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Tillämpa uppdateringar för fast programvara" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Anslut DFU-kapabel enhet till körtid" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Fäst till fast programvaruläge" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Attribut" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Autentiserar..." #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" +msgid "Authentication is required to downgrade the firmware on a removable device" msgstr "Autentisering krävs för att nedgradera den fasta programvaran för en flyttbar enhet" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Lås upp enheten för att tillåta åtkomst" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Autentisering krävs för att nedgradera den fasta programvaran på denna maskin" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Autenticering krävs för att få ändra en konfigurerad fjärrkälla som används för fast programvaru-uppdateringar." #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Autentisering krävs för att låsa upp en enhet" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Uppdatera den lagrade enhetens verifikationsinformation" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Autentisering krävs för att uppdatera den lagrade kontrollsumman för enheten" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Modifiera en konfigurerad fjärrkälla" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Autentisering krävs för att uppdatera den fasta programvaran på en flyttbar enhet" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Autenticering krävs för att få ändra en konfigurerad fjärrkälla som används för fast programvaru-uppdateringar." +msgid "Authentication is required to update the firmware on this machine" +msgstr "Autentisering krävs för att uppdatera den fasta programvaran för denna maskin" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "Alias för %s" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Autentisering krävs för att uppdatera den lagrade kontrollsumman för enheten" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Kommandot hittades inte" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "Bygg fast programvara med en sandlåda" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Tillagd" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Avbryt" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Borttagen" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Avbruten" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "Ändrad" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Avbruten" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Kontrollsumma" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Krets id" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Namn" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Välj en enhet:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Välj en utgåva:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "Chiffer" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Område" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Hittad" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Protokoll" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Status" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "Rensa eventuella uppdateringar som schemalagts att bli tillämpade frånkopplade" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Åtkomst nekad" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "Rensar resultaten från senaste uppdateringen" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Serienr" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Kommandot hittades inte" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Läge" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Konvertera fast programvara till DFU-format" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "Skapa en binär lagning från två filer" -#: plugins/dfu/dfu-tool.c:2115 msgid "DFU" -msgstr "" +msgstr "DFU" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Tillstånd" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU-verktyg" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Överföringsstorlek" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Felsökningsalternativ" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Attribut" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Dekomprimerar…" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Speciallösningar" +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Dekryptera fast programvarudata" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "Krets id" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Beskrivning" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Konvertera fast programvara till DFU-format" +msgid "Detach currently attached DFU capable device" +msgstr "Koppla från anslutna DFU-kapabla enheter" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Sammanfoga flera fasta programvaror till en" +msgid "Detach to bootloader mode" +msgstr "Koppla från till starthanterarläge" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Ange tillverkar-ID för den fasta programvarufilen" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Enhet tillagd:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Ange produkt-ID för den fasta programvarufilen" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Enhet ändrad:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Ange elementadress för den fasta programvarufilen" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Enhet borttagen:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Ange fast programvarustorlek för målet" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Enheter som har uppdaterats:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Ange utgåveversion för den fasta programvarufilen" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Enheter som inte uppdaterades korrekt:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Ange alternativ siffra för den fasta programvarufilen" +msgid "Disabled fwupdate debugging" +msgstr "Inaktiverade fwupdate-felsökning" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Ange alternativt namn för den fasta programvarufilen" +msgid "Disables a given remote" +msgstr "Inaktiverar en given fjärr." -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Anslut DFU-kapabel enhet till körtid" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Visa version" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Omstart av en DFU-enhet" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Kontrollera inte gammal metadata" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Läs fast programvara från enhet till fil" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Kontrollera inte om det krävs omstart efter uppdatering" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Läs fast programvara från en partition till fil" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Kontrollera inte ej rapporterad historik" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Skriv fast programvara från fil till enhet" +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Skriv inte till historikdatabasen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Skriv fast programvara från fil till partition" +#. success +msgid "Done!" +msgstr "Klar!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Lista aktuella anslutna DFU-kapabla enheter" +msgid "Downgrades the firmware on a device" +msgstr "Nergradera fast programvara på en enhet" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Nedgraderar %s från %s till %s… " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Nedgraderar %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Laddar ner..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "Koppla från anslutna DFU-kapabla enheter" +msgid "Dump SMBIOS data from a file" +msgstr "Dumpa SMBIOS data från en fil" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "Skriv ut detaljer om fast programvarufil" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Övervaka anslutna DFU-enheter" +msgid "Dump information about a binary patch to the screen" +msgstr "Dumpa informationen om en binär lagning till skärmen" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Kryptera fast programvarudata" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Angiven ESP var inte giltig" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Dekryptera fast programvarudata" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Aktivera stöd för uppdatering av fast programvara på system som stöds" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Ange metadata på fast programvarufil" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Aktivera denna fjärr?" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Ersätt data i en befintlig fast programvarufil" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Aktiverad" + +msgid "Enabled fwupdate debugging" +msgstr "Aktiverade fwupdate-felsökning" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Skapa en binär lagning från två filer" +msgid "Enables a given remote" +msgstr "Aktiverar en given fjärr." + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Att aktivera denna funktionalitet görs på egen risk, vilket betyder att du måste kontakta den ursprungliga tillverkaren av din utrustning om problem som orsakas av dessa uppdateringar. Endast problem med själva uppdateringsprocessen ska rapporteras på $OS_RELEASE:BUG_REPORT_URL$." + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Att aktivera denna fjärr görs på egen risk." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Applicera en binär lagning" +msgid "Encrypt firmware data" +msgstr "Kryptera fast programvarudata" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "Dumpa informationen om en binär lagning till skärmen" +msgid "Erase all firmware update history" +msgstr "Ta bort alla historik för fast programvara" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Raderar..." + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "Avsluta efter en kort fördröjning" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "Avsluta efter att motorn har lästs in" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Misslyckades med hämtning på grund av servergräns" #. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU-verktyg" +msgstr "Misslyckades med att läsa in speciallösning" #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "Misslyckades med att tolka argument" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Räkna upp alla Synaptic MST-enheter" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Skriv fast programvarufil till MST-enhet" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics Multistream Transport-verktyg" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Hämtar fil" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Installerar uppdatering för fast programvara…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Hämtar fast programvara" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Visa felsökningsinformation för alla filer" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Hämtar metainformation" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Visa utförlig information om insticksmodul" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Hämtar signatur" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Felsökningsalternativ" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Filnamn" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Visa felsökningsalternativ" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Filnamn Signatur" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "Avsluta efter en kort fördröjning" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Fast programvara bas-URI" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "Avsluta efter att motorn har lästs in" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Firmware Update D-Bus-tjänst" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" msgstr "Uppgraderingsdemon för fast programvara" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Firmware Update D-Bus-tjänst" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Fast programvaruverktyg" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Väntar…" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Metadata för fast programvara har inte uppdaterats på %udag och kan vara utdaterad." +msgstr[1] "Metadata för fast programvara har inte uppdaterats på %udagar och kan vara utdaterad." -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Dekomprimerar…" +msgid "Firmware updates are not supported on this machine." +msgstr "Uppdateringar av fast programvara stöds inte på denna maskin." -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Läser in…" +msgid "Firmware updates are supported on this machine." +msgstr "Uppdateringar av fast programvara stöds på denna maskin." -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Startar om enhet…" +msgid "Force the action ignoring all warnings" +msgstr "Tvinga åtgärden, ignorera alla varningar" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Läser..." +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Hittad" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Skriver…" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Raderar..." +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Hämta alla enheter enligt systemets topologi" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Verifierar…" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Hämta alla enheter som stödjer uppdateringar av fast programvara" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Schemalägger…" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Erhåll alla aktiverade insticksmoduler som är registrerade i systemet" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Laddar ner..." +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Hämtar detaljer om en fast programvarufil" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Autentiserar..." +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Ger de konfigurerade fjärrkällorna" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Väntar..." +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Hämtar den kryptografiska hashen för den utskrivna versionen av den fasta programvaran" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Okänd" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Hämtar listan över uppdateringar för ansluten hårdvara" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Erhåll utgåvan för en enhet" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Välj en enhet:" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Hämtar resultaten från senaste uppdateringen" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Väntar…" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Installera en fast programvaru-blob på en enhet" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Installera en fast programvarufil på denna hårdvara" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" +msgid "Install old version of system firmware" +msgstr "Installera en gammal version av fast programvara för systemet" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Ingen uppdateringsbar hårdvara upptäcktes" +msgid "Install signed device firmware" +msgstr "Installera signerad fast programvara för enhet" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Återinstallerar %s med %s… " +msgid "Install signed system firmware" +msgstr "Installera signerad fast programvara för systemet" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Nedgraderar %s från %s till %s… " +msgid "Install unsigned device firmware" +msgstr "Installera osignerad fast programvara för enhet" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Install unsigned system firmware" +msgstr "Installera osignerad fast programvara för systemet" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Installerar uppdatering för fast programvara…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Uppdaterar %s från %s till %s... " +msgid "Installing on %s…" +msgstr "Installerar på %s…" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Klar!" +msgid "Keyring" +msgstr "Nyckelring" -#: src/fu-util.c:726 -msgid "Target" -msgstr "" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Mindre än en minut kvarstår" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux Vendor Firmware Service (stabil fastprogramvara)" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux Vendor Firmware Service (fastprogramvara för testning)" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Lista aktuella anslutna DFU-kapabla enheter" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Lista uppdateringar för fast programvara som stöds" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Läser in…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Vitlista manuellt specifika insticksmoduler" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Sammanfoga flera fasta programvaror till en" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Metadata URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Metadata URI Signatur" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Metadata kan hämtas från Linux Vendor Firmware Service." + +msgid "Mode" +msgstr "Läge" + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Modifierar en given fjärrkälla" + +msgid "Modify a configured remote" +msgstr "Modifiera en konfigurerad fjärrkälla" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Övervaka demonen för händelser" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Namn" + +msgid "No action specified!" +msgstr "Ingen åtgärd angiven!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Ingen uppdateringsbar hårdvara upptäcktes" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Inga insticksmoduler hittades" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Inga fjärrar är aktiverade för närvarande, så ingen metadata är tillgänglig." -#: src/fu-util.c:1034 src/fu-util.c:1414 msgid "OK" msgstr "OK" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Hämtar signatur" +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Åsidosätt insticksmodulvarning" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Hämtar metainformation" +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Åsidosätt standardsökväg för ESP" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Hämtar fast programvara" +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Lösenord" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Hämtar fil" +msgid "Payload" +msgstr "Nyttolast" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Version" +msgid "Permission denied" +msgstr "Åtkomst nekad" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Ange en siffra mellan 0 och %u: " + +msgid "Print the version number" +msgstr "Skriv ut versionsnumret" + +msgid "Print verbose debug statements" +msgstr "Skriv ut utförliga felsökningssatser" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Prioritet" + +msgid "Proceed with upload?" +msgstr "Fortsätt med att skicka upp?" + +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Protokoll" + +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Fråga efter stöd för uppdatering av fast programvara" + +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Speciallösningar" + +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Läs fast programvara från enhet till fil" + +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Läs fast programvara från en partition till fil" + +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Läser..." + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Uppdatera metadata från fjärrserver" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Område" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Återinstallerar %s med %s… " #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Fjärrkälla" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Fjärrkälla-id" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Beskrivning" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Borttagen" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Kontrollsumma" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Ersätt data i en befintlig fast programvarufil" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Välj en utgåva:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Rapport-uri" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Kräver internetanslutning" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Omstart av en DFU-enhet" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s har uppdateringar för fast programvara:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Starta om nu?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Startar om enhet…" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Uppdateringsversion" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Returnera alla hårdvaru-id för maskinen" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" +msgid "Runtime" +msgstr "Exekvering" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Schemalägg om möjligt installationen till nästa uppstart" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Uppdatera fjärrkällans id" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Schemalägger…" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Uppdateringskontrollsumma" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Serienr" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Uppdateringsplats" +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Ange alternativt namn för den fasta programvarufilen" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Uppdateringsbeskrivning" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Ange alternativ siffra för den fasta programvarufilen" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Fjärrkälla-id" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Ange elementadress för den fasta programvarufilen" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Titel" +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Ange produkt-ID för den fasta programvarufilen" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Ange utgåveversion för den fasta programvarufilen" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Ställ in felsökningsflaggan under uppdatering" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Ange fast programvarustorlek för målet" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Ange tillverkar-ID för den fasta programvarufilen" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Ange metadata på fast programvarufil" + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Dela fast programvaruhistorik med utvecklarna" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Typ" +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Visa klient- och demon-version" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Nyckelring" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Visa felsökningsalternativ" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Aktiverad" +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Visa enheter som inte kan uppdateras" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Ålder" +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Visa extra felsökningsinformation" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Prioritet" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Visa historik över fasta programvaruuppdateringar" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Användarnamn" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Visa utförlig information om insticksmodul" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Lösenord" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Visa felsökningsloggen från det senaste uppdateringsförsöket" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Filnamn" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Visa information om uppdateringsstatus för fast programvara" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Filnamn Signatur" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Ange Tillverkar-/Produkt-ID för DFU-enhet" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "Metadata URI" +msgid "Specify the number of bytes per USB transfer" +msgstr "Ange antalet byte per USB-överföring" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Metadata URI Signatur" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Tillstånd" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Fast programvara bas-URI" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Status" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Sammanfattning" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Enhet tillagd:" +msgid "Target" +msgstr "Mål" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Enhet borttagen:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS är en fri tjänst som fungerar som en oberoende juridisk person och har ingen koppling till $OS_RELEASE:NAME$. Din distributör kanske inte har bekräftat att någon av de fasta programvaruuppdateringarna är kompatibla med ditt system eller anslutna enheter. All fast programvara tillhandahålls endast av den ursprungliga tillverkaren av utrustning." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Detta program kommer endast fungera korrekt som root" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Enhet ändrad:" +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "Denna fjärrkälla innehåller fast programvara som inte är under embargo, men fortfarande testas av hårdvarutillverkare. Du bör säkerställa att du har ett sätt att manuellt nedgradera den fasta programvaran om uppdateringen misslyckas." -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Titel" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Överföringsstorlek" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Visa extra felsökningsinformation" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Typ" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Visa klient- och demon-version" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Verktyg för fast UEFI-programvara" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Schemalägg om möjligt installationen till nästa uppstart" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Tillåt att installera om befintliga versioner av fast programvara" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Okänd" -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Tillåt att nedgradera versioner av fast programvara" +msgid "Unlock the device to allow access" +msgstr "Lås upp enheten för att tillåta åtkomst" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Åsidosätt tilläggsvarning" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Låser upp enheten för fast programvaruåtkomst" #. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" +msgid "Unset the debugging flag during update" +msgstr "Ta bort felsökningsflaggan under uppdatering" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Uppdateringskontrollsumma" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Uppdateringsbeskrivning" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Uppdateringslängd" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Hämta alla enheter som stödjer uppdateringar av fast programvara" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Uppdateringsplats" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Returnera alla hårdvaru-id för maskinen" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Uppdatera namn" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Installera förberedda uppdateringar nu" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Uppdatera fjärrkällans id" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Uppdateringssammanfattning" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Uppdateringsversion" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Misslyckad uppdatering är ett känt fel, besök denna url för mer information:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Installera en fast programvarufil på denna hårdvara" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Uppdatera nu?" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Hämtar detaljer om en fast programvarufil" +msgid "Update the stored device verification information" +msgstr "Uppdatera den lagrade enhetens verifikationsinformation" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Hämtar listan över uppdateringar för ansluten hårdvara" +msgid "Update the stored metadata with current ROM contents" +msgstr "Uppdatera den lagrade metadatan med aktuellt ROM-innehåll" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Uppdaterar all fast programvara till de senast tillgängliga versionerna" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Hämtar den kryptografiska hashen för den utskrivna versionen av den fasta programvaran" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Uppdaterar %s från %s till %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Låser upp enheten för fast programvaruåtkomst" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Uppdaterar %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Rensar resultaten från senaste uppdateringen" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Uppladdningsmeddelande:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Rensa eventuella uppdateringar som schemalagts att bli tillämpade frånkopplade" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Skicka upp rapport nu?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Hämtar resultaten från senaste uppdateringen" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Att skicka upp rapporter för fastprogramvara hjälper hårdvaruförsäljare att snabbt identifiera trasiga och fungerande uppdateringar på riktiga enheter." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Erhåll utgåvan för en enhet" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Användarnamn" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Ger de konfigurerade fjärrkällorna" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Verifierar…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Nergradera fast programvara på en enhet" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Version" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Uppdatera metadata från fjärrserver" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Väntar..." #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Uppdatera den lagrade metadatan med aktuellt ROM-innehåll" +msgid "Watch DFU devices being hotplugged" +msgstr "Övervaka anslutna DFU-enheter" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Övervaka demonen för händelser" +msgid "Watch for hardware changes" +msgstr "Övervaka hårdvaruändringar" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Bygg fast programvara med en sandlåda" +msgid "Write firmware from file into device" +msgstr "Skriv fast programvara från fil till enhet" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Dumpa SMBIOS data från en fil" +msgid "Write firmware from file into one partition" +msgstr "Skriv fast programvara från fil till partition" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Modifierar en given fjärrkälla" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Skriver…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Fast programvaruverktyg" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Din distributör kanske inte har verifierat någon av uppdateringarna av fastprogramvara för kompatibilitet med ditt system eller anslutna enheter." diff -Nru fwupd-1.0.6/po/test-deps fwupd-1.2.10/po/test-deps --- fwupd-1.0.6/po/test-deps 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/test-deps 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 """ Check dependencies needed for rasterization """ """ - Licensed under the GNU General Public License Version 2 - - 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 2 of the License, 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, see . - + SPDX-License-Identifier: LGPL-2.1+ """ import sys diff -Nru fwupd-1.0.6/po/tr.po fwupd-1.2.10/po/tr.po --- fwupd-1.0.6/po/tr.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/tr.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Muhammet Kara , 2016 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Turkish (http://www.transifex.com/freedesktop/fwupd/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,979 +15,211 @@ "Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "" - -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "" - -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "İmzalı sistem ürün yazılımını yükle" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Eklendi" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Bu makine üzerindeki ürün yazılımını güncellemek için kimlik doğrulama gerekir" - -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "İmzasız sistem ürün yazılımını yükle" - -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Eski sürüm sistem ürün yazılımını yükle" +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Çıkarılabilir aygıt üzerindeki ürün yazılımının sürümünü düşürmek için kimlik doğrulama gerekir" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 msgid "Authentication is required to downgrade the firmware on this machine" msgstr "Bu makine üzerindeki ürün yazılımının sürümünü indirmek için kimlik doğrulama gerekir" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "İmzalı aygıt ürün yazılımını yükle" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Çıkarılabilir aygıt üzerindeki ürün yazılımını güncellemek için kimlik doğrulama gerekir" - -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "İmzasız aygıt ürün yazılımını yükle" - -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Çıkarılabilir aygıt üzerindeki ürün yazılımının sürümünü düşürmek için kimlik doğrulama gerekir" - -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Erişime izin vermek için cihazın kilidini açın" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "Bir cihazın kilidini açmak için kimlik doğrulama gerekir" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Çıkarılabilir aygıt üzerindeki ürün yazılımını güncellemek için kimlik doğrulama gerekir" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "" +msgid "Authentication is required to update the firmware on this machine" +msgstr "Bu makine üzerindeki ürün yazılımını güncellemek için kimlik doğrulama gerekir" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "İptal Edildi" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Değişti" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Şifreleme" #. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 msgid "Command not found" msgstr "Komut bulunamadı" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Eklendi" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "Ürün yazılımını DFU biçimine dönüştür" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Kaldırıldı" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Açılıyor…" + +#. TRANSLATORS: command description +msgid "Decrypt firmware data" +msgstr "Ürün yazılımı verisinin şifresini açın" #. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Değişti" +msgid "Device added:" +msgstr "Aygıt eklendi:" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "İptal Edildi" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Aygıt değişti:" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "Kimlik (ID)" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Aygıt çıkarıldı:" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "İsim" +#. success +msgid "Done!" +msgstr "Bitti!" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Şifreleme" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Ürün yazılımı verisini şifreleyin" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Bölge" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Ürün Yazılımı Yardımcı Programı" #. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 msgid "Found" msgstr "Bulundu" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "İletişim kuralı" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Durum" - -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "" - -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Seri" - -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Kip" +msgid "GUID" +msgstr "GUID" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Kimlik (ID)" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Boşta…" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Evre" +msgid "Install old version of system firmware" +msgstr "Eski sürüm sistem ürün yazılımını yükle" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "" +msgid "Install signed device firmware" +msgstr "İmzalı aygıt ürün yazılımını yükle" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "" +msgid "Install signed system firmware" +msgstr "İmzalı sistem ürün yazılımını yükle" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "" +msgid "Install unsigned device firmware" +msgstr "İmzasız aygıt ürün yazılımını yükle" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "" +msgid "Install unsigned system firmware" +msgstr "İmzasız sistem ürün yazılımını yükle" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Ürün yazılımını DFU biçimine dönüştür" +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Yükleniyor…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 msgid "Merge multiple firmware files into one" msgstr "Birden çok ürün yazılımı dosyasını tek dosyada birleştir" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Ürün yazılımı dosyası üzerindeki üretici kimliğini ayarlayın" +msgid "Mode" +msgstr "Kip" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Ürün yazılımı dosyası üzerindeki ürün kimliğini ayarlayın" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "İsim" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Ürün yazılımı güncelleme yeteneğine sahip donanım saptanamadı" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "" +msgid "OK" +msgstr "Tamam" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "İletişim kuralı" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Bölge" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Kaldırıldı" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Cihaz yeniden başlatılıyor…" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Zamanlanıyor…" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Seri" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "" +msgid "Set product ID on firmware file" +msgstr "Ürün yazılımı dosyası üzerindeki ürün kimliğini ayarlayın" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "" +msgid "Set vendor ID on firmware file" +msgstr "Ürün yazılımı dosyası üzerindeki üretici kimliğini ayarlayın" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "" +msgid "Sets metadata on a firmware file" +msgstr "Ürün yazılımı dosyası üzerindeki üst veriyi ayarlar" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Evre" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Durum" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Bilinmiyor" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "" +msgid "Unlock the device to allow access" +msgstr "Erişime izin vermek için cihazın kilidini açın" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Ürün yazılımı verisini şifreleyin" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Ürün yazılımı verisinin şifresini açın" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Ürün yazılımı dosyası üzerindeki üst veriyi ayarlar" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "" - -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "" - -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "" - -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "" - -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "" - -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "" - -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "" - -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "" - -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "" - -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "" - -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "" - -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "" - -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Boşta…" - -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Açılıyor…" - -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Yükleniyor…" - -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Cihaz yeniden başlatılıyor…" - -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "" - -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Yazılıyor…" - -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "" - -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Doğrulanıyor…" - -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Zamanlanıyor…" - -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "" - -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "" - -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "" - -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Bilinmiyor" - -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "" - -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" - -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "" - -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "" - -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "" - -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Ürün yazılımı güncelleme yeteneğine sahip donanım saptanamadı" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "" - -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 -#, c-format -msgid "Updating %s from %s to %s... " -msgstr "" - -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Bitti!" - -#: src/fu-util.c:726 -msgid "Target" -msgstr "" - -#: src/fu-util.c:727 -msgid "Payload" -msgstr "" - -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "" - -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "" - -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "Tamam" - -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "" - -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "" - -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "" - -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "" - -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "" - -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "" - -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "" - -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "" - -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "" - -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "" -msgstr[1] "" - -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "" - -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "" - -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" - -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Güncelleme Sürümü" - -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "" - -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "" - -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "" - -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Güncelleme Sağlaması" - -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Güncelleme Konumu" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Güncelleme Sağlaması" #. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 msgid "Update Description" msgstr "Güncelleme Açıklaması" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "" - -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "" - -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "" - -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "" - -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "" - -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "" - -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "" - -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "" - -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "" - -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "" - -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Aygıt eklendi:" - -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Aygıt çıkarıldı:" - -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Aygıt değişti:" - -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "" - -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "" - -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "" - -#. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Güncelleme Konumu" -#. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Güncelleme Sürümü" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Doğrulanıyor…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Ürün Yazılımı Yardımcı Programı" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Yazılıyor…" diff -Nru fwupd-1.0.6/po/uk.po fwupd-1.2.10/po/uk.po --- fwupd-1.0.6/po/uk.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/uk.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,997 +1,1241 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Yuri Chornoivan , 2015-2018 +# Yuri Chornoivan , 2015-2019 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Ukrainian (http://www.transifex.com/freedesktop/fwupd/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "Лишилася %.0f хвилина" +msgstr[1] "Лишилося %.0f хвилини" +msgstr[2] "Лишилося %.0f хвилин" +msgstr[3] "Лишилася %.0f хвилина" -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "Оновлення мікропрограм пристроїв у Linux" +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "Оновлення %s Consumer ME" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "Метою цього проекту є автоматизація оновлення мікропрограм обладнання у Linux, безпечно і надійно. Для перегляду і застосування оновлень ви можете скористатися або програмою для керування програмним забезпеченням, зокрема Програмними засобами GNOME, або інструментом командного рядка, або безпосередньо інтерфейсом D-Bus." +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "Оновлення для контролера %s" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "Процес fwupd є простою фоновою службою, яка надає змогу оновлювати мікропрограми пристроїв на вашому локальному комп’ютері у межах сеансу користування. Програму розроблено для робочих станцій, але нею можна скористатися на телефонах, планшетах та серверах без дисплеїв." +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "Оновлення %s Corporate ME" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "Встановити підписану мікропрограму системи" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "Оновлення для пристрою %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "Щоб отримати доступ до оновлення мікропрограми цього комп’ютера, вам слід пройти розпізнавання" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "Оновлення для вбудованого контролера %s" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "Встановити непідписану мікропрограму системи" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "Оновлення ME %s" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "Встановити стару версію мікропрограми системи" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "Оновлення системи %s" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "Для встановлення застарілої версії мікропрограми на цей комп’ютер слід пройти розпізнавання" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "Оновлення для %s" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "Встановити підписану мікропрограму пристрою" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s має такі оновлення мікропрограми:" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "Для оновлення мікропрограми на портативному пристрої слід пройти розпізнавання" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u день" +msgstr[1] "%u дні" +msgstr[2] "%u днів" +msgstr[3] "%u день" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "Встановити непідписану мікропрограму пристрою" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u година" +msgstr[1] "%u години" +msgstr[2] "%u годин" +msgstr[3] "%u година" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "Для встановлення застарілої версії мікропрограми на портативний пристрій слід пройти розпізнавання" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u хвилина" +msgstr[1] "%u хвилини" +msgstr[2] "%u хвилин" +msgstr[3] "%u хвилина" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "Розблокування пристрою для отримання доступу" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u секунда" +msgstr[1] "%u секунди" +msgstr[2] "%u секунд" +msgstr[3] "%u секунда" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "Щоб розблокувати пристрій, слід пройти розпізнавання" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "Задіяти пристрої" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "Оновлення збережених даних щодо верифікації пристрою" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "Задіяти пристрої у черзі очікування" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "Щоб отримати доступ до оновлення збережених контрольних сум для пристрою, вам слід пройти розпізнавання" +msgid "Activate the new firmware on the device" +msgstr "Активація нової мікропрограми на пристрої" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "Зміна налаштованих віддалених пристроїв" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "Активуємо оновлення мікропрограми" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "Для внесення змін до записів налаштованих віддалених пристроїв, які використовуються для оновлення мікропрограм, слід пройти розпізнавання" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "Активуємо оновлення мікропрограми для" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "Додано" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "Вік" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "Згодні, увімкнути віддалене сховище?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "Інша назва %s" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "Такої команди не знайдено" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "Дозволити зниження версій мікропрограми" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "Додано" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "Дозволити повторне встановлення наявних версій мікропрограми" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "Вилучено" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "Для завершення оновлення слід перезавантажити систему." -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "Змінено" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "Для завершення оновлення систему слід вимкнути." -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "Скасовано" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "Відповідати «так» на усі питання" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "Ід." +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "Застосувати бінарну латку" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "Назва" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "Застосувати оновлення мікропрограми" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "Шифр" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "Схвалена мікропрограма:" +msgstr[1] "Схвалені мікропрограми:" +msgstr[2] "Схвалені мікропрограми:" +msgstr[3] "Схвалена мікропрограма:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "Регіон" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "Повернути пристрій із можливостями DFU до використання" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "Знайдено" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "Долучитися до режиму мікропрограми" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "Протокол" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "Атрибути" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "Стан" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "Проходимо розпізнавання…" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "Доступ заборонено" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "Для встановлення застарілої версії мікропрограми на портативний пристрій слід пройти розпізнавання" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "Порядкове" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "Для встановлення застарілої версії мікропрограми на цей комп’ютер слід пройти розпізнавання" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "Режим" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "Для внесення змін до записів налаштованих віддалених пристроїв, які використовуються для оновлення мікропрограм, слід пройти розпізнавання" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "Час обробляння" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "Для внесення змін до налаштувань фонової служби слід пройти розпізнавання" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "Щоб встановити список схвалених мікропрограм, вам слід пройти розпізнавання" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "Стан" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "Щоб підписати дані за допомогою клієнтського сертифіката, вам слід пройти розпізнавання" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "Об’єм перенесеного" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "Щоб перемкнутися на нову версію мікропрограми, вам слід пройти розпізнавання" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "Атрибути" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "Щоб розблокувати пристрій, слід пройти розпізнавання" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "Негаразди" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "Для оновлення мікропрограми на портативному пристрої слід пройти розпізнавання" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "Ід. чипа" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "Щоб отримати доступ до оновлення мікропрограми цього комп’ютера, вам слід пройти розпізнавання" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "Перетворити мікропрограму у формат DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "Щоб отримати доступ до оновлення збережених контрольних сум для пристрою, вам слід пройти розпізнавання" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "Об’єднати декілька файлів мікропрограм у один" +msgid "Build firmware using a sandbox" +msgstr "Зібрати мікропрограму за допомогою пісочниці" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "Встановити ідентифікатор виробника для файла мікропрограми" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "Скасувати" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "Встановити ідентифікатор продукту для файла мікропрограми" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "Скасовано" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "Встановити адресу елемента для файла мікропрограми" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "Змінено" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "Встановити розмір мікропрограми для призначення" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "Контрольна сума" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "Встановити версію випуску для файла мікропрограми" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "Ід. чипа" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "Встановити альтернативний номер для файла мікропрограми" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "Виберіть пристрій:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "Встановити альтернативну назву для файла мікропрограми" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "Виберіть випуск:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "Повернути пристрій із можливостями DFU до використання" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "Шифр" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "Відновити початковий стан пристрою DFU" +msgid "Clears any updates scheduled to be updated offline" +msgstr "Спорожняє список усіх оновлень, які заплановано для автономного режиму" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "Прочитати мікропрограму з пристрою до файла" +msgid "Clears the results from the last update" +msgstr "Вилучає результати останнього оновлення" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "Такої команди не знайдено" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "Прочитати мікропрограму з одного розділу до файла" +msgid "Convert firmware to DFU format" +msgstr "Перетворити мікропрограму у формат DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "Записати мікропрограму з файла на пристрій" +msgid "Create a binary patch using two files" +msgstr "Створити бінарну латку на основі двох файлів" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "Записати мікропрограму з файла на один розділ" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "Засіб роботи з DFU" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "Параметри діагностики" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "Розпаковування…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "Вивести поточний список долучених пристроїв із можливостями DFU" +msgid "Decrypt firmware data" +msgstr "Розшифрувати дані мікропрограми" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "Опис" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "Від’єднати поточний з’єднаний пристрій із можливостями DFU" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "Створити дамп даних щодо файла мікропрограми" +msgid "Detach to bootloader mode" +msgstr "Від'єднатися до режиму завантажувача" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "Спостерігати за пристроями DFU, які з’єднують із комп’ютером" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "Ід. пристрою" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "Зашифрувати дані мікропрограми" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "Додано пристрій:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "Розшифрувати дані мікропрограми" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "Змінено пристрій:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "Вилучено пристрій:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "Пристрої, для яких вдалося успішно оновити дані:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "Пристрої, для яких не вдалося оновити дані належним чином:" + +msgid "Disabled fwupdate debugging" +msgstr "Вимкнено діагностику fwupdate" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "Встановлює метадані щодо файла мікпропрограми" +msgid "Disables a given remote" +msgstr "Вимикає вказане віддалене сховище" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "Показати версію" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "Не перевіряти, чи є застарілі метадані" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "Не перевіряти, чи слід перезавантажуватися після оновлення" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "Не перевіряти, чи є ненадіслані звіти у журналі" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "Не записувати дані до бази даних журналу" + +#. success +msgid "Done!" +msgstr "Виконано!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "Замінити дані у наявному файлі мікропрограми" +msgid "Downgrades the firmware on a device" +msgstr "Знижує версію мікропрограми на пристрої" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "Знижуємо версію %s з %s до %s... " + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "Знижуємо версію %s…" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "Отримуємо дані…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "Створити бінарну латку на основі двох файлів" +msgid "Dump SMBIOS data from a file" +msgstr "Записати дані SMBIOS з файла" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "Застосувати бінарну латку" +msgid "Dump details about a firmware file" +msgstr "Створити дамп даних щодо файла мікропрограми" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "Вивести дамп інформації щодо бінарної латки на екран" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "Не вдалося завантажити коригування" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "Вказаний ESP є некоректним" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "Засіб роботи з DFU" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "Увімкнути підтримку оновлення мікропрограми на підтримуваних системах" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "Не вдалося обробити аргументи" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "Увімкнути це віддалене сховище?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "Нумерувати усі пристрої MST Synaptics" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "Увімкнено" + +msgid "Enabled fwupdate debugging" +msgstr "Увімкнено діагностику fwupdate" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "Записати файл мікропрограми на пристрій MST" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Засіб багатопотокового передавання Synaptics" +msgid "Enables a given remote" +msgstr "Вмикає вказане віддалене сховище" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "Встановлюємо оновлення мікропрограми…" +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "Наслідки вмикання цієї можливості покладаються на вас. Це означає, що усі проблеми, пов'язані із цими оновленнями, ви маєте вирішувати із виробником обладнання. Повідомляти розробникам дистрибутива за адресою $OS_RELEASE:BUG_REPORT_URL$ слід лише про помилки у процесі оновлення." -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "Показувати діагностичні дані для всіх файлів" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "Вмикання цього віддаленого сховища виконано під вашу відповідальність." -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "Показати докладні відомості щодо додатків" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "Зашифрувати дані мікропрограми" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "Параметри діагностики" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "Витерти увесь журнал оновлень мікропрограми" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "Показувати параметри діагностики" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "Витираємо…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "Завершити роботу з невеличкою затримкою" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "Завершити роботу після завантаження рушія" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "Служба оновлення мікропрограми" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "Не вдалося встановити з'єднання із фоновою службою" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "Не вдалося отримати через обмеження сервера" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "Не вдалося отримати список пристроїв у черзі очікування" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "Не вдалося встановити оновлення мікропрограми" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "Служба D-Bus оновлення мікропрограми" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "Не вдалося завантажити коригування" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "Бездіяльність…" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "Не вдалося обробити аргументи" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "Розпаковування…" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "Не вдалося перезавантажити" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "Не вдалося встановити режим вітання" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "Завантаження…" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "Отримуємо файл" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "Перезапускаємо пристрій…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "Отримуємо мікропрограму" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "Читаємо…" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "Отримуємо метадані" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "Записуємо…" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "Отримуємо підпис" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "Витираємо…" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "Назва файла" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "Перевіряємо…" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "Підпис назви файла" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "Плануємо…" +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "Агент мікропрограм" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "Отримуємо дані…" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "Основна адреса мікропрограми" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "Проходимо розпізнавання…" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "Служба D-Bus оновлення мікропрограми" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "Очікуємо…" +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "Служба оновлення мікропрограми" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "Невідомий" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "Засіб роботи з мікропрограмами" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "Метадані мікропрограми не оновлювалися %u день, можливо, вони вже не є актуальними." +msgstr[1] "Метадані мікропрограми не оновлювалися %u дні, можливо, вони вже не є актуальними." +msgstr[2] "Метадані мікропрограми не оновлювалися %u днів, можливо, вони вже не є актуальними." +msgstr[3] "Метадані мікропрограми не оновлювалися %u днів, можливо, вони вже не є актуальними." -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "Виберіть пристрій:" +msgid "Firmware updates are not supported on this machine." +msgstr "На цьому комп'ютері не передбачено підтримки оновлення мікропрограми." -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "На цьому комп'ютері передбачено підтримку оновлень мікропрограми." -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "Пристрої, для яких не вдалося оновити дані належним чином:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "Прапорці" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "Пристрої, для яких вдалося успішно оновити дані:" +msgid "Force the action ignoring all warnings" +msgstr "Виконати дію примусово, ігноруючи усі попередження" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "Вивантажити звіт зараз?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "Знайдено" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "Потребує з'єднання із інтернетом" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "Не виявлено обладнання із передбаченою можливістю оновлення мікропрограми" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "Отримати список усіх пристроїв за топологією системи" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "Повторно встановлюємо %s з номером версії %s... " +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "Отримати список усіх пристроїв та можливих випусків" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "Отримати список усіх пристроїв, у яких передбачено оновлення мікропрограми" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "Отримати список усіх додатків, які зареєстровано у системі" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "Отримати параметри файла мікропрограми" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "Отримує налаштовані віддалені пристрої" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "Отримує криптографічні хеш-суми для дампів мікропрограм" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "Отримує список схвалених мікропрограм." + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "Отримує список оновлень для з’єднаного обладнання" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "Отримує випуски для пристрою" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "Отримує результати з останнього оновлення" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "Ід." + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "Бездіяльність…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "Встановити бінарну мікропрограму на пристрій" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "Встановити файл мікропрограми на це обладнання" + +msgid "Install old version of system firmware" +msgstr "Встановити стару версію мікропрограми системи" + +msgid "Install signed device firmware" +msgstr "Встановити підписану мікропрограму пристрою" + +msgid "Install signed system firmware" +msgstr "Встановити підписану мікропрограму системи" + +msgid "Install unsigned device firmware" +msgstr "Встановити непідписану мікропрограму пристрою" + +msgid "Install unsigned system firmware" +msgstr "Встановити непідписану мікропрограму системи" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "Встановлюємо мікропрограму…" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "Встановлюємо оновлення мікропрограми…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "Знижуємо версію %s з %s до %s... " +msgid "Installing on %s…" +msgstr "Встановлюємо на %s…" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Keyring" +msgstr "Сховище ключів" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "Лишилося менше за хвилину" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Служба надання мікропрограм для Linux від виробника (стабільна мікропрограма)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Служба надання мікропрограм для Linux від виробника (тестова мікропрограма)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "Вивести поточний список долучених пристроїв із можливостями DFU" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "Показати список підтримуваних оновлень мікропрограми" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "Завантаження…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "Вручну додати певні додатки до «білого» списку" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "Об’єднати декілька файлів мікропрограм у один" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "Адреса метаданих" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "Підпис адреси метаданих" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "Метадані можна отримати від служби надання мікропрограм для Linux від виробника." + +#. TRANSLATORS: error message #, c-format -msgid "Updating %s from %s to %s... " -msgstr "Оновлюємо %s з %s до %s... " +msgid "Mismatched daemon and client, use %s instead" +msgstr "Невідповідність фонової служби і клієнта, скористайтеся краще %s" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "Виконано!" +msgid "Mode" +msgstr "Режим" -#: src/fu-util.c:726 -msgid "Target" -msgstr "Ціль" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "Змінює значення налаштування фонової служби." + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "Змінює вказаний запис віддаленого пристрою" + +msgid "Modify a configured remote" +msgstr "Зміна налаштованих віддалених пристроїв" + +msgid "Modify daemon configuration" +msgstr "Зміна налаштувань фонової служби" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "Стежити за подіями у фоновій службі" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "Назва" + +msgid "No action specified!" +msgstr "Не вказано дії!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "Не виявлено обладнання із передбаченою можливістю оновлення мікропрограми" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "Додатків не знайдено" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "Зараз не увімкнено жодного віддаленого сховища, отже, метадані недоступні." + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "Не застосовано жодного оновлення" + +msgid "OK" +msgstr "Гаразд" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "Перевизначити попередження для додатка" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "Перевизначити типовий шлях до ESP" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "Не зважати на попередження і примусово виконати дію" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "Пароль" -#: src/fu-util.c:727 msgid "Payload" msgstr "Вміст" -#: src/fu-util.c:728 +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "Відсоток виконання" + +msgid "Permission denied" +msgstr "Доступ заборонено" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "Будь ласка, введіть число від 0 до %u: " + +msgid "Print the version number" +msgstr "Вивести номер версії" + +msgid "Print verbose debug statements" +msgstr "Вивести докладні діагностичні повідомлення" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "Пріоритетність" + msgid "Proceed with upload?" msgstr "Продовжити вивантаження?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "Нам відомо про помилку під час оновлення. Будь ласка, відвідайте цю адресу, щоб дізнатися більше:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "Протокол" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "Повідомлення про вивантаження:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "Опитати щодо підтримки оновлення мікропрограми" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "Гаразд" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "Негаразди" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "Отримуємо підпис" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "Прочитати мікропрограму з пристрою до файла" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "Отримуємо метадані" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "Прочитати мікропрограму з одного розділу до файла" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "Отримуємо мікропрограму" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "Читаємо…" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "Отримуємо файл" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "Перезавантажуємо…" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "Версія" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "Оновити метадані з віддаленого сервера" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "Резюме" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "Регіон" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "Повторно встановлюємо %s з номером версії %s... " #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "Віддалений пристрій" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "Адреса" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "Віддалений ідентифікатор" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "Опис" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "Вилучено" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "Контрольна сума" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "Замінити дані у наявному файлі мікропрограми" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "Виберіть випуск:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "Адреса звіту" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "Метадані мікропрограми не оновлювалися %u день, можливо, вони вже не є актуальними." -msgstr[1] "Метадані мікропрограми не оновлювалися %u дні, можливо, вони вже не є актуальними." -msgstr[2] "Метадані мікропрограми не оновлювалися %u днів, можливо, вони вже не є актуальними." +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "Потребує з'єднання із інтернетом" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "Оновити зараз?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "Відновити початковий стан пристрою DFU" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s має такі оновлення мікропрограми:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "Перезавантажити зараз?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "Перезапустити фонову службу, щоб зміни набули чинності?" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "Версія оновлення" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "Перезапускаємо пристрій…" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "Назва оновлення" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "Повернути усі ідентифікатори апаратного забезпечення комп’ютера" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "Резюме оновлення" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "Запустити процедуру чищення композиції додатків при використанні install-blob" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "Оновити віддалений ідентифікатор" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "Запустити процедуру приготування композиції додатків при використанні install-blob" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "Контрольна сума оновлення" +msgid "Runtime" +msgstr "Час обробляння" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "Місце оновлення" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "Зберігати стан пристрою до файла JSON між виконаннями" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "Опис оновлення" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "Якщо можливо, запланувати встановлення на наступне перезавантаження" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "Віддалений ідентифікатор" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "Плануємо…" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "Заголовок" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "Порядкове" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "Встановити альтернативну назву для файла мікропрограми" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "Встановити альтернативний номер для файла мікропрограми" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "Встановити адресу елемента для файла мікропрограми" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "Встановити ідентифікатор продукту для файла мікропрограми" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "Встановити версію випуску для файла мікропрограми" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "Встановити під час оновлення прапорець діагностики" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "Встановити розмір мікропрограми для призначення" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "Встановити ідентифікатор виробника для файла мікропрограми" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "Встановлює метадані щодо файла мікпропрограми" + +msgid "Sets the list of approved firmware" +msgstr "Встановлення списку схвалених мікропрограм" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "Встановлює список схвалених мікропрограм." + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "Поділитися журналом оновлень із розробниками" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "Вивести дані щодо версій клієнат і фонової служби" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "Показати докладні дані фонової служби для певного домену" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "Показати діагностичні дані для усіх доменів" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "Показувати параметри діагностики" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "Показати пристрої, оновлення для яких неможливе" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "Показати додаткові діагностичні дані" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "Тип" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "Показати журнал оновлень мікропрограми" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "Сховище ключів" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "Показати докладні відомості щодо додатків" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "Увімкнено" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "Показати діагностичний журнал щодо останньої спроби оновлення" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "Вік" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "Показати дані щодо стану оновлення мікропрограми" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "Пріоритетність" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "Вимкнути зараз?" + +msgid "Sign data using the client certificate" +msgstr "Підписування даних клієнтським сертифікатом" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "Підписування даних клієнтським сертифікатом" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "Користувач" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "Підписати вивантажені дані клієнтським сертифікатом" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "Пароль" +msgid "Signature" +msgstr "Підпис" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "Назва файла" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "Вказати ідентифікатори виробника/продукту пристрою DFU" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "Підпис назви файла" +msgid "Specify the number of bytes per USB transfer" +msgstr "Вказати кількість байтів на один пакет передавання даних USB" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "Адреса метаданих" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "Стан" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "Підпис адреси метаданих" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "Стан" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "Основна адреса мікропрограми" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "Резюме" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "Адреса звіту" +msgid "Target" +msgstr "Ціль" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "Додано пристрій:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS є безкоштовною службою, яка працює як незалежна юридична одиниця і не має зв'язку з $OS_RELEASE:NAME$. Розробники вашої операційної системи, можливо, не перевіряли жодні з цих оновлень на сумісність із системою або з'єднаними із комп'ютером пристроями. Усі мікропрограми надаються лише самими виробниками обладнання." + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "Немає схвалених мікропрограм." + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "Програма зможе працювати належними чином лише від імені користувача root" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "У цьому сховищі міститься мікропрограма, встановлювати яку не заборонено, але яка усе ще перебуває у процесі тестування виробником обладнання. Вам слід переконатися, що ви зможете встановити стабільну версію мікропрограми, якщо процедура оновлення зазнає невдачі." + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "Цим інструментом може користуватися лише root" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "Вилучено пристрій:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "Заголовок" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "Змінено пристрій:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "Об’єм перенесеного" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "Для завершення оновлення слід перезавантажити систему." +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "Тип" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "Перезавантажити зараз?" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "Засіб роботи із мікропрограмами UEFI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "Показати додаткові діагностичні дані" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "Адреса" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "Вивести дані щодо версій клієнат і фонової служби" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "Невідомий" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "Якщо можливо, запланувати встановлення на наступне перезавантаження" +msgid "Unlock the device to allow access" +msgstr "Розблокування пристрою для отримання доступу" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "Дозволити повторне встановлення наявних версій мікропрограми" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "Розблоковує пристрій для доступу до мікропрограми" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "Дозволити зниження версій мікропрограми" +msgid "Unset the debugging flag during update" +msgstr "Зняти під час оновлення прапорець діагностики" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "Перевизначити попередження для додатка" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "Непідтримувана версія фонової служби %s, версія клієнта — %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "Відповідати «так» на усі питання" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "Контрольна сума оновлення" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "Не перевіряти, чи є ненадіслані звіти у журналі" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "Опис оновлення" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "Не перевіряти, чи є застарілі метадані" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "Тривалість оновлення" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "Не перевіряти, чи слід перезавантажуватися після оновлення" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "Місце оновлення" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "Отримати список усіх пристроїв, у яких передбачено оновлення мікропрограми" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "Назва оновлення" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "Повернути усі ідентифікатори апаратного забезпечення комп’ютера" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "Оновити віддалений ідентифікатор" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "Встановити приготовані оновлення зараз" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "Резюме оновлення" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "Показати журнал оновлень мікропрограми" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "Версія оновлення" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "Витерти увесь журнал оновлень мікропрограми" +msgid "Update all devices that match local metadata" +msgstr "Оновити усі пристрої, які відповідають локальним метаданим" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "Поділитися журналом оновлень із розробниками" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "Нам відомо про помилку під час оновлення. Будь ласка, відвідайте цю адресу, щоб дізнатися більше:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "Встановити файл мікропрограми на це обладнання" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "Оновити зараз?" + +msgid "Update the stored device verification information" +msgstr "Оновлення збережених даних щодо верифікації пристрою" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "Отримати параметри файла мікропрограми" +msgid "Update the stored metadata with current ROM contents" +msgstr "Оновити збережені метадані на основі поточного вмісту ROM" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "Отримує список оновлень для з’єднаного обладнання" +msgid "Update the stored metadata with current contents" +msgstr "Оновити збережені метадані поточними даними" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "Оновлює усі мікропрограми до найновіших доступних версій" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "Отримує криптографічні хеш-суми для дампів мікропрограм" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "Оновлюємо %s з %s до %s... " -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "Розблоковує пристрій для доступу до мікропрограми" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "Оновлюємо %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "Вилучає результати останнього оновлення" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "Повідомлення про вивантаження:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "Спорожняє список усіх оновлень, які заплановано для автономного режиму" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "Вивантажити звіт зараз?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "Отримує результати з останнього оновлення" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "Вивантаження звітів щодо мікропрограм допомагає виробникам обладнання швидко виявляти проблеми та дізнаватися про успішне оновлення на реальних пристроях." -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "Отримує випуски для пристрою" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "Користувач" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "Отримує налаштовані віддалені пристрої" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "Перевіряємо…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "Знижує версію мікропрограми на пристрої" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "Версія" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "Оновити метадані з віддаленого сервера" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "Очікуємо…" #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "Оновити збережені метадані на основі поточного вмісту ROM" +msgid "Watch DFU devices being hotplugged" +msgstr "Спостерігати за пристроями DFU, які з’єднують із комп’ютером" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "Стежити за подіями у фоновій службі" +msgid "Watch for hardware changes" +msgstr "Спостерігати за змінами у обладнанні" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "Зібрати мікропрограму за допомогою пісочниці" +msgid "Write firmware from file into device" +msgstr "Записати мікропрограму з файла на пристрій" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "Записати дані SMBIOS з файла" +msgid "Write firmware from file into one partition" +msgstr "Записати мікропрограму з файла на один розділ" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "Змінює вказаний запис віддаленого пристрою" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "Записуємо…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "Засіб роботи з мікропрограмами" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "Виробник вашого дистрибутива може не перевіряти усі оновлення мікропрограми на сумісність із вашою системою або з’єднаними із нею пристроями." diff -Nru fwupd-1.0.6/po/zh_CN.po fwupd-1.2.10/po/zh_CN.po --- fwupd-1.0.6/po/zh_CN.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/zh_CN.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,10 +1,10 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: # Boyuan Yang <073plan@gmail.com>, 2017 -# Dz Chen , 2016-2017 +# Dingzhong Chen , 2016-2019 # Mingcong Bai , 2017-2018 # Mingye Wang , 2016 # Mingye Wang , 2015 @@ -12,9 +12,6 @@ msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Chinese (China) (http://www.transifex.com/freedesktop/fwupd/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,978 +19,1206 @@ "Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "更新 Linux 上的设备固件" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "还剩 %.0f 分钟" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "本项目的目标是让 Linux 上更新固件的流程变得自动化、安全又可靠。您既可以使用如 GNOME 软件这样的软件包管理器查看和应用更新,也可以直接使用命令行工具或者 D-Bus 接口。" +#. TRANSLATORS: ME stands for Management Engine, where +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Consumer ME Update" +msgstr "%s 消费者 ME 更新" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 的进程作为一个简单的守护程序,可以让会话软件更新您本地机器的设备固件。它为桌面环境设计,但该项目可以应用在手机、平板电脑和服务器上。" +#. TRANSLATORS: the controller is a device that has other devices +#. * plugged into it, for example ThunderBolt, FireWire or USB, +#. * the first %s is the device name, e.g. 'Intel ThunderBolt` +#, c-format +msgid "%s Controller Update" +msgstr "%s 控制器更新" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "安装已签名的系统固件" +#. TRANSLATORS: ME stands for Management Engine (with Intel AMT), +#. * where the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Corporate ME Update" +msgstr "%s 企业 ME 更新" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "需要认证:在此机器上升级固件" +#. TRANSLATORS: a specific part of hardware, +#. * the first %s is the device name, e.g. 'Unifying Receiver` +#, c-format +msgid "%s Device Update" +msgstr "%s 设备更新" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "安装未签名的系统固件" +#. TRANSLATORS: the EC is typically the keyboard controller chip, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Embedded Controller Update" +msgstr "%s 嵌入式控制器更新" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "安装旧版本的系统固件" +#. TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s ME Update" +msgstr "%s 管理引擎(ME)更新" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "需要认证:在此机器上降级固件" +#. TRANSLATORS: the entire system, e.g. all internal devices, +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s System Update" +msgstr "%s 系统更新" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "安装已签名的设备固件" +#. TRANSLATORS: this is the fallback where we don't know if the release +#. * is updating the system, the device, or a device class, or something else +#. -- +#. * the first %s is the device name, e.g. 'ThinkPad P50` +#, c-format +msgid "%s Update" +msgstr "%s 更新" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "需要认证:在可移动设备上升级固件" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s 有固件更新:" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "安装未签名的设备固件" +#. TRANSLATORS: duration in days! +#, c-format +msgid "%u day" +msgid_plural "%u days" +msgstr[0] "%u 天" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" -msgstr "需要认证:在可移动设备上降级固件" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u hour" +msgid_plural "%u hours" +msgstr[0] "%u 小时" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "解锁设备以允许访问" +#. TRANSLATORS: duration in minutes +#, c-format +msgid "%u minute" +msgid_plural "%u minutes" +msgstr[0] "%u 分钟" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 -msgid "Authentication is required to unlock a device" -msgstr "需要认证:解锁设备" +#. TRANSLATORS: duration in seconds +#, c-format +msgid "%u second" +msgid_plural "%u seconds" +msgstr[0] "%u 秒" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "更新存储的设备验证信息" +#. TRANSLATORS: command description +msgid "Activate devices" +msgstr "激活设备" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "需要认证:为设备更新存储的校验和" +#. TRANSLATORS: command description +msgid "Activate pending devices" +msgstr "激活待处理的设备" -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "修改已配置的远程位置" +msgid "Activate the new firmware on the device" +msgstr "激活设备上的新固件" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "需要认证:修改用于固件更新的已配置远程位置" +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update" +msgstr "正在激活固件更新" + +#. TRANSLATORS: shown when shutting down to switch to the new version +msgid "Activating firmware update for" +msgstr "正在激活固件更新给" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "已添加" + +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "已发布时间" + +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "同意并启用此远程功能吗?" #. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 #, c-format msgid "Alias to %s" msgstr "%s 的别名" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "未找到命令" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "允许降级固件版本" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "已添加" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "允许重新安装现有的固件版本" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "已移除" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "更新需要重启设备才能完成。" -#. TRANSLATORS: this is when a device is hotplugged -#. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 -msgid "Changed" -msgstr "已变更" +#. TRANSLATORS: explain why we want to shutdown +msgid "An update requires the system to shutdown to complete." +msgstr "更新需要系统关机才能完成。" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "已取消" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "一律用“是”回答问题" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "应用二进制补丁" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "名称" +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "应用固件更新" -#. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 -msgid "Cipher" -msgstr "加密" +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "Approved firmware:" +msgid_plural "Approved firmware:" +msgstr[0] "批准的固件:" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "区域" +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "将可固件升级 (DFU) 的设备重新附到运行时上" -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "找到" +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "附加到固件模式" -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "协议" +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "属性" -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "状况" +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "正在认证…" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "拒绝授权" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on a removable device" +msgstr "需要认证:在可移动设备上降级固件" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "串口" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "需要认证:在此机器上降级固件" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "模式" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "需要认证:修改用于固件更新的已配置远程位置" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "运行时" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify daemon configuration" +msgstr "需要认证:修改守护进程配置" -#: plugins/dfu/dfu-tool.c:2115 -msgid "DFU" -msgstr "DFU" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to set the list of approved firmware" +msgstr "需要认证:设定批准固件的列表" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "状态" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to sign data using the client certificate" +msgstr "需要认证:使用客户端证书签名数据" -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "传输大小" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to switch to the new firmware version" +msgstr "需要认证:切换到新固件版本" -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "属性" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to unlock a device" +msgstr "需要认证:解锁设备" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "特异情况" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on a removable device" +msgstr "需要认证:在可移动设备上升级固件" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "芯片 ID" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the firmware on this machine" +msgstr "需要认证:在此机器上升级固件" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "将固件转换为固件升级(DFU)格式" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "需要认证:为设备更新存储的校验和" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "将多个固件文件合并为一个" +msgid "Build firmware using a sandbox" +msgstr "使用沙箱生成固件" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "设置固件文件上的供应商 ID" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "取消" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "设置固件文件上的产品 ID" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "已取消" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "设置固件文件上的元件地址" +#. TRANSLATORS: this is when a device is hotplugged +#. TRANSLATORS: this is when the daemon state changes +msgid "Changed" +msgstr "已变更" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "为目标固件设置大小" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "校验和" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "设置固件文件上的发布版本" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "芯片 ID" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "设置固件文件上的替代数字" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "选择设备:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "设置固件文件上的替代名称" +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "选择发行版本:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "将可固件升级 (DFU) 的设备重新附到运行时上" +#. TRANSLATORS: this is the encryption method used when writing +msgid "Cipher" +msgstr "加密" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "重置一个 DFU 设备" +msgid "Clears any updates scheduled to be updated offline" +msgstr "清除任何计划的离线更新" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "将来自设备的固件读入文件" +msgid "Clears the results from the last update" +msgstr "清除从最后一次更新获取的结果" + +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "未找到命令" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "将来自分区的固件读入文件" +msgid "Convert firmware to DFU format" +msgstr "将固件转换为固件升级(DFU)格式" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "将来自文件的固件写入设备" +msgid "Create a binary patch using two files" +msgstr "使用两个文件创建二进制补丁" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "将来自文件的固件写入分区" +msgid "DFU" +msgstr "DFU" + +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "固件更新实用程序" + +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "调试选项" + +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "正在解压缩…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "列出当前连接的可固件升级的设备" +msgid "Decrypt firmware data" +msgstr "解密固件数据" + +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "描述" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 msgid "Detach currently attached DFU capable device" msgstr "断开当前连接的可固件升级的设备" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 -msgid "Dump details about a firmware file" -msgstr "转储有关某固件文件的详细信息" +msgid "Detach to bootloader mode" +msgstr "拆离到引导加载器模式" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "注意被热插入的固件升级 (DFU) 设备" +#. TRANSLATORS: ID for hardware, typically a SHA1 sum +msgid "Device ID" +msgstr "设备 ID" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "加密固件数据" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "已添加设备:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "解密固件数据" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "已更改设备:" + +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "已移除设备:" + +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "成功更新的设备:" + +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "未正确更新的设备:" + +msgid "Disabled fwupdate debugging" +msgstr "禁用 fwupdate 调试" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "设置固件文件上的元数据" +msgid "Disables a given remote" +msgstr "禁用指定远程功能" + +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "显示版本" + +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "不要查找老的元数据" + +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "不要在更新后检查是否需要重启" + +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "不要查找未报告历史" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "不要写入历史数据库" + +#. success +msgid "Done!" +msgstr "完成!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "用已有的固件文件替换数据" +msgid "Downgrades the firmware on a device" +msgstr "降级设备上的固件" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "正在降级 %s,从 %s 到 %s…" + +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Downgrading %s…" +msgstr "正在下载 %s……" + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "正在下载..." #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "使用两个文件创建二进制补丁" +msgid "Dump SMBIOS data from a file" +msgstr "从文件转储 SMBIOS 数据" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "应用二进制补丁" +msgid "Dump details about a firmware file" +msgstr "转储有关某固件文件的详细信息" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 msgid "Dump information about a binary patch to the screen" msgstr "将二进制补丁信息输出到屏幕" -#. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 -msgid "Failed to load quirks" -msgstr "载入特定问题失败" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "指定的 ESP 无效" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "固件更新实用程序" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "在所支持的系统上启用固件更新的支持" -#. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 -msgid "Failed to parse arguments" -msgstr "未能解析参数" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "要启用此远程功能吗?" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "枚举所有 Synaptics MST 设备" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "已启用" + +msgid "Enabled fwupdate debugging" +msgstr "启用 fwupdate 调试" #. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "刷写固件文件到 MST 设备" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics 多流传输工具" +msgid "Enables a given remote" +msgstr "启用指定远程功能" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "正在安装固件更新..." +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "启用此功能的风险自负,这意味着你必须就这些更新引起的任何问题与原始设备制造商联系。只有更新过程本身的问题可以提交到 $OS_RELEASE:BUG_REPORT_URL$。" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "显示所有文件的调试信息" +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "启用此远程功能后果自负。" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "显示插件详细回显信息" +#. TRANSLATORS: command description +msgid "Encrypt firmware data" +msgstr "加密固件数据" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "调试选项" +#. TRANSLATORS: command description +msgid "Erase all firmware update history" +msgstr "清楚所有固件更新历史" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "显示调试选项" +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "正在擦除…" #. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 msgid "Exit after a small delay" msgstr "在短暂的延迟后退出" #. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 msgid "Exit after the engine has loaded" msgstr "在引擎加载后退出" -#. TRANSLATORS: program name -#: src/fu-main.c:1053 -msgid "Firmware Update Daemon" -msgstr "固件更新守护程序" +#. TRANSLATORS: we could not talk to the fwupd daemon +msgid "Failed to connect to daemon" +msgstr "连接到守护进程失败" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "由于服务器限制而下载失败" + +#. TRANSLATORS: we could not get the devices to update offline +msgid "Failed to get pending devices" +msgstr "获取待处理的设备失败" + +#. TRANSLATORS: we could not install for some reason +msgid "Failed to install firmware update" +msgstr "安装固件更新失败" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "固件更新 D-Bus 服务" +#. TRANSLATORS: quirks are device-specific workarounds +msgid "Failed to load quirks" +msgstr "载入特定问题失败" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "空闲…" +#. TRANSLATORS: the user didn't read the man page +msgid "Failed to parse arguments" +msgstr "未能解析参数" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "正在解压缩…" +#. TRANSLATORS: we could not reboot for some reason +msgid "Failed to reboot" +msgstr "重启失败" + +#. TRANSLATORS: we could not talk to plymouth +msgid "Failed to set splash mode" +msgstr "设定启动屏幕模式失败" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "正在加载…" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "正在获取文件" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "正在重启设备…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "正在获取固件" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "正在读取…" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "正在获取元信息" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "正在写入…" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "正在获取签名" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "正在擦除…" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "文件名" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "正在验证…" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "文件名签名" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "正在计划…" +#. TRANSLATORS: program name +msgid "Firmware Agent" +msgstr "固件代理" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "正在下载..." +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "固件库 URI" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "正在认证…" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "固件更新 D-Bus 服务" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "等待中..." +#. TRANSLATORS: program name +msgid "Firmware Update Daemon" +msgstr "固件更新守护程序" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "未知" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "固件实用程序" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 #, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "固件元数据已有 %u 天未更新,数据可能不是最新的。" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "选择一个设备:" +msgid "Firmware updates are not supported on this machine." +msgstr "此机器不支持固件更新。" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +msgid "Firmware updates are supported on this machine." +msgstr "此机器支持固件更新。" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "未正确更新的设备:" +#. TRANSLATORS: section header for firmware flags +msgid "Flags" +msgstr "标志" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "成功更新的设备:" +msgid "Force the action ignoring all warnings" +msgstr "强制操作忽略所有警告" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "要上传报告吗?" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "找到" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "需要互联网连接" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "没有检测到支持更新固件的硬件" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "根据系统拓扑获取所有设备" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "正在重新安装 %s,使用 %s…" +#. TRANSLATORS: command description +msgid "Get all devices and possible releases" +msgstr "获取所有设备和可用版本" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "获得所有支持更新固件的硬件列表" + +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "获取所有在系统注册的启用插件" + +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "获取有关某固件文件的详细信息" + +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "获取已配置的远程位置" + +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "获取转储出的固件的校验和" + +#. TRANSLATORS: firmware approved by the admin +msgid "Gets the list of approved firmware." +msgstr "获取批准固件的列表。" + +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "获取已连接硬件的可用更新列表" + +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "获取用于设备的发行版本" + +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "从最后一次更新中获取结果" + +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" + +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "空闲…" + +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "在设备上安装固件比特块" + +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "在此硬件上安装固件文件" + +msgid "Install old version of system firmware" +msgstr "安装旧版本的系统固件" + +msgid "Install signed device firmware" +msgstr "安装已签名的设备固件" + +msgid "Install signed system firmware" +msgstr "安装已签名的系统固件" + +msgid "Install unsigned device firmware" +msgstr "安装未签名的设备固件" + +msgid "Install unsigned system firmware" +msgstr "安装未签名的系统固件" + +#. TRANSLATORS: console message when no Plymouth is installed +msgid "Installing Firmware…" +msgstr "正在安装固件……" + +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "正在安装固件更新..." + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "正在降级 %s,从 %s 到 %s…" +msgid "Installing on %s…" +msgstr "正在安装到 %s……" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +msgid "Keyring" +msgstr "密钥环" + +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "还剩不到一分钟" + +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux 供应商固件服务(稳定固件)" + +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux 供应商固件服务(测试固件)" + +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "列出当前连接的可固件升级的设备" + +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "列出所支持固件的更新" + +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "正在加载…" + +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "将指定插件手动加入白名单" + +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "将多个固件文件合并为一个" + +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "元数据 URI" + +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "元数据 URI 签名" + +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "可从 Linux 供应商固件服务获取元数据。" + +#. TRANSLATORS: error message #, c-format -msgid "Updating %s from %s to %s... " -msgstr "正在更新 %s,从 %s 到 %s…" +msgid "Mismatched daemon and client, use %s instead" +msgstr "守护进程与客户端不匹配,使用 %s 来代替" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "完成!" +msgid "Mode" +msgstr "模式" -#: src/fu-util.c:726 -msgid "Target" -msgstr "目标" +#. TRANSLATORS: sets something in daemon.conf +msgid "Modifies a daemon configuration value." +msgstr "修改守护进程配置值。" + +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "修改给定的远程位置" + +msgid "Modify a configured remote" +msgstr "修改已配置的远程位置" + +msgid "Modify daemon configuration" +msgstr "修改守护进程配置" + +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "监视守护程序里的事件" + +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "名称" + +msgid "No action specified!" +msgstr "未指定操作!" + +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "没有检测到支持更新固件的硬件" + +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "未找到插件" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "当前尚未启用任何远程功能,因此无可用元数据。" + +#. TRANSLATORS: nothing was updated offline +msgid "No updates were applied" +msgstr "没有应用任何更新" + +msgid "OK" +msgstr "确定" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "忽略插件警告" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "覆盖默认的 ESP 路径" + +#. TRANSLATORS: command line option +msgid "Override warnings and force the action" +msgstr "覆盖警告并强制执行操作" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "密码" -#: src/fu-util.c:727 msgid "Payload" msgstr "载荷" -#: src/fu-util.c:728 +#. TRANSLATORS: console message when not using plymouth +msgid "Percentage complete" +msgstr "完成百分比" + +msgid "Permission denied" +msgstr "拒绝授权" + +#. TRANSLATORS: the user isn't reading the question +#, c-format +msgid "Please enter a number from 0 to %u: " +msgstr "请输入一个 0 到 %u 之间的数字:" + +msgid "Print the version number" +msgstr "打印版本号" + +msgid "Print verbose debug statements" +msgstr "打印详细调试语句" + +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "优先级" + msgid "Proceed with upload?" msgstr "确定要上传吗?" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "更新失败为已知问题,请访问此 URL 以获取详情:" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "协议" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "上传消息:" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "查询固件更新的支持" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "确定" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "特异情况" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "正在获取签名" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "将来自设备的固件读入文件" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "正在获取元信息" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "将来自分区的固件读入文件" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "正在获取固件" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "正在读取…" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "正在获取文件" +#. TRANSLATORS: console message when not using plymouth +msgid "Rebooting…" +msgstr "正在重启……" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "版本" +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "刷新来自远程服务器的元数据" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "概览" +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "区域" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "正在重新安装 %s,使用 %s…" #. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 msgid "Remote" msgstr "远程" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +#. TRANSLATORS: remote identifier, e.g. lvfs-testing +msgid "Remote ID" +msgstr "远程 ID" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "描述" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "已移除" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "校验和" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "用已有的固件文件替换数据" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "选择发行版本:" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "报告 URI" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "固件元数据已有 %u 天未更新,数据可能不是最新的。" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "需要互联网连接" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "现在更新吗?" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "重置一个 DFU 设备" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 -#, c-format -msgid "%s has firmware updates:" -msgstr "%s 有固件更新:" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "要现在重启设备吗?" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: configuration changes only take effect on restart +msgid "Restart the daemon to make the change effective?" +msgstr "重启守护进程以让更改生效?" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "更新版本" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "正在重启设备…" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "更新名称" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "返回机器的所有硬件 ID" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "更新概览" +#. TRANSLATORS: command line option +msgid "Run the plugin composite cleanup routine when using install-blob" +msgstr "当使用安装比特块时运行插件组合清理例程" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "更新远程 ID" +#. TRANSLATORS: command line option +msgid "Run the plugin composite prepare routine when using install-blob" +msgstr "当使用安装比特块时运行插件组合准备例程" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "更新校验和" +msgid "Runtime" +msgstr "运行时" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "更新位置" +#. TRANSLATORS: command line option +msgid "Save device state into a JSON file between executions" +msgstr "在执行之间保存设备状态到 JSON 文件" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "更新说明" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "如有可能,安排安装到下次重启" -#. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 -msgid "Remote ID" -msgstr "远程 ID" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "正在计划…" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "标题" +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "串口" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "设置固件文件上的替代名称" + +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "设置固件文件上的替代数字" + +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "设置固件文件上的元件地址" + +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "设置固件文件上的产品 ID" + +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "设置固件文件上的发布版本" + +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "更新期间设定调试标志" + +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "为目标固件设置大小" + +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "设置固件文件上的供应商 ID" + +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "设置固件文件上的元数据" + +msgid "Sets the list of approved firmware" +msgstr "设定批准固件的列表" + +#. TRANSLATORS: firmware approved by the admin +msgid "Sets the list of approved firmware." +msgstr "设定批准固件的列表。" + +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "与开发者分享固件历史" + +#. TRANSLATORS: command line option +msgid "Show client and daemon versions" +msgstr "显示客户端及守护程序版本" + +#. TRANSLATORS: this is for daemon development +msgid "Show daemon verbose information for a particular domain" +msgstr "显示特定域的守护进程详细信息" + +#. TRANSLATORS: turn on all debugging +msgid "Show debugging information for all domains" +msgstr "显示所有域的调试信息" + +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "显示调试选项" + +#. TRANSLATORS: command line option +msgid "Show devices that are not updatable" +msgstr "显示不可更新的设备" + +#. TRANSLATORS: command line option +msgid "Show extra debugging information" +msgstr "显示额外调试信息" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "类型" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "显示固件更新历史" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "密钥环" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "显示插件详细回显信息" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "已启用" +#. TRANSLATORS: command line option +msgid "Show the debug log from the last attempted update" +msgstr "显示上次尝试更新的调试日志" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "已发布时间" +#. TRANSLATORS: command line option +msgid "Show the information of firmware update status" +msgstr "显示固件更新状态的信息" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "优先级" +#. TRANSLATORS: shutdown to apply the update +msgid "Shutdown now?" +msgstr "现在关机?" + +msgid "Sign data using the client certificate" +msgstr "使用客户端证书签名数据" + +msgctxt "command-description" +msgid "Sign data using the client certificate" +msgstr "使用客户端证书签名数据" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "用户名" +#. TRANSLATORS: command line option +msgid "Sign the uploaded data with the client certificate" +msgstr "以客户端证书签名上传的数据" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "密码" +msgid "Signature" +msgstr "签名" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "文件名" +msgid "Specify Vendor/Product ID(s) of DFU device" +msgstr "指定 DFU 设备的供应商/产品 ID" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "文件名签名" +msgid "Specify the number of bytes per USB transfer" +msgstr "指定每次 USB 传输的字节数" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "元数据 URI" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "状态" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "元数据 URI 签名" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "状况" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "固件库 URI" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "概览" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "报告 URI" +msgid "Target" +msgstr "目标" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "已添加设备:" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS 是个免费服务,以独立法律实体运作,与 $OS_RELEASE:NAME$ 无关。你的发行商可能未对固件更新与你的系统或连接的设备兼容性做过任何验证。所有固件都由原始设备制造商提供。" + +#. TRANSLATORS: approved firmware has been checked by +#. * the domain administrator +msgid "There is no approved firmware." +msgstr "没有批准的固件。" + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "此程序只能以 root 身份正常运行" + +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "此远程源包含未禁止的固件,但其仍经过硬件供应商测试。你应该确保如果固件更新失败时你能够降级固件。" + +#. TRANSLATORS: the user needs to stop playing with stuff +msgid "This tool can only be used by the root user" +msgstr "此工具只能由 root 用户使用" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "已移除设备:" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "标题" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "已更改设备:" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "传输大小" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "更新需要重启设备才能完成。" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "类型" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "要现在重启设备吗?" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "固件 UEFI 实用工具" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "显示额外调试信息" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command line option -#: src/fu-util.c:2119 -msgid "Show client and daemon versions" -msgstr "显示客户端及守护程序版本" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "未知" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "如有可能,安排安装到下次重启" +msgid "Unlock the device to allow access" +msgstr "解锁设备以允许访问" -#. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "允许重新安装现有的固件版本" +#. TRANSLATORS: command description +msgid "Unlocks the device for firmware access" +msgstr "为固件访问解锁设备" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "允许降级固件版本" +msgid "Unset the debugging flag during update" +msgstr "更新期间取消设定调试标志" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "忽略插件警告" +#. TRANSLATORS: error message +#, c-format +msgid "Unsupported daemon version %s, client version is %s" +msgstr "未受支持的守护进程版本 %s,客户端版本为 %s" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "一律用“是”回答问题" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "更新校验和" -#. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "不要查找未报告历史" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "更新说明" -#. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "不要查找老的元数据" +#. TRANSLATORS: section header for the amount +#. * of time it takes to install the update +msgid "Update Duration" +msgstr "更新时长" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "不要在更新后检查是否需要重启" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "更新位置" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "获得所有支持更新固件的硬件列表" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "更新名称" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "返回机器的所有硬件 ID" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "更新远程 ID" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "现在安装准备好的更新" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "更新概览" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "显示固件更新历史" +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "更新版本" #. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "清楚所有固件更新历史" +msgid "Update all devices that match local metadata" +msgstr "更新所有符合本地元数据的设备" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "与开发者分享固件历史" +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "更新失败为已知问题,请访问此 URL 以获取详情:" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "安装此硬件上的固件文件" +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "现在更新吗?" + +msgid "Update the stored device verification information" +msgstr "更新存储的设备验证信息" #. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "获取有关某固件文件的详细信息" +msgid "Update the stored metadata with current ROM contents" +msgstr "使用目前的 ROM 内容更新存储的元数据" #. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "获取已连接硬件的可用更新列表" +msgid "Update the stored metadata with current contents" +msgstr "使用当前内容更新存储的元数据" #. TRANSLATORS: command description -#: src/fu-util.c:2220 msgid "Updates all firmware to latest versions available" msgstr "将所有固件都更新为最新版本" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "获取转储出的固件的校验和" +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "正在更新 %s,从 %s 到 %s…" -#. TRANSLATORS: command description -#: src/fu-util.c:2232 -msgid "Unlocks the device for firmware access" -msgstr "为固件访问解锁设备" +#. TRANSLATORS: %1 is a device name +#, c-format +msgid "Updating %s…" +msgstr "正在更新 %s……" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "清除从最后一次更新获取的结果" +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "上传消息:" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "清除任何计划的离线更新" +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "要上传报告吗?" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "从最后一次更新中获取结果" +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "上传固件报告可帮助硬件供应商尽快确定真实设备上更新的成功及失败案例。" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "获取用于设备的发行版本" +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "用户名" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "获取已配置的远程位置" +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "正在验证…" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "降级设备上的固件" +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "版本" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "刷新来自远程服务器的元数据" +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "等待中..." #. TRANSLATORS: command description -#: src/fu-util.c:2280 -msgid "Update the stored metadata with current ROM contents" -msgstr "使用目前的 ROM 内容更新存储的元数据" +msgid "Watch DFU devices being hotplugged" +msgstr "注意被热插入的固件升级 (DFU) 设备" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "监视守护程序里的事件" +msgid "Watch for hardware changes" +msgstr "监视硬件更改" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "使用沙箱生成固件" +msgid "Write firmware from file into device" +msgstr "将来自文件的固件写入设备" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "从文件转储 SMBIOS 数据" +msgid "Write firmware from file into one partition" +msgstr "将来自文件的固件写入分区" -#. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "修改给定的远程位置" +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "正在写入…" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "固件实用程序" +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "您的发行商可能尚未认证任何固件的系统及设备兼容性。" diff -Nru fwupd-1.0.6/po/zh_TW.po fwupd-1.2.10/po/zh_TW.po --- fwupd-1.0.6/po/zh_TW.po 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/po/zh_TW.po 2019-07-15 18:25:54.000000000 +0000 @@ -1,16 +1,13 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the fwupd package. -# +# # Translators: -# Cheng-Chia Tseng , 2017 +# Cheng-Chia Tseng , 2017-2018 msgid "" msgstr "" "Project-Id-Version: fwupd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-12 10:37+0000\n" -"PO-Revision-Date: 2018-03-12 10:37+0000\n" -"Last-Translator: Richard Hughes \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/freedesktop/fwupd/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -18,978 +15,913 @@ "Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: data/org.freedesktop.fwupd.metainfo.xml:7 -msgid "fwupd" -msgstr "fwupd" - -#: data/org.freedesktop.fwupd.metainfo.xml:8 -msgid "Update device firmware on Linux" -msgstr "在 Linux 上更新裝置韌體" +#. more than a minute +#, c-format +msgid "%.0f minute remaining" +msgid_plural "%.0f minutes remaining" +msgstr[0] "剩下 %.0f 分鐘" -#: data/org.freedesktop.fwupd.metainfo.xml:10 -msgid "" -"This project aims to make updating firmware on Linux automatic, safe and " -"reliable. You can either use a GUI software manager like GNOME Software to " -"view and apply updates, the command-line tool or the D-Bus interface " -"directly." -msgstr "本專案宗旨在於讓 Linux 上的韌體更新能自動、安全、可靠。您可以使用圖形介面的軟體管理員,如《GNOME 軟體》來檢視並套用更新,或用指令列工具,或甚至直接用 D-Bus 介面。" +#. TRANSLATORS: first replacement is device name +#, c-format +msgid "%s has firmware updates:" +msgstr "%s 有韌體更新:" -#: data/org.freedesktop.fwupd.metainfo.xml:16 -msgid "" -"The fwupd process is a simple daemon to allow session software to update " -"device firmware on your local machine. It is designed for desktops, but this" -" project is also usable on phones, tablets and on headless servers." -msgstr "fwupd 程序是個簡易幕後程式,允許工作階段軟體更新您本地端機器上的裝置韌體。它主要設計給桌面電腦使用,但本專案也能用於手機、平板,或是指令列介面伺服器。" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Added" +msgstr "已加入" -#: policy/org.freedesktop.fwupd.policy.in:17 -msgid "Install signed system firmware" -msgstr "安裝已簽署的系統韌體" +#. TRANSLATORS: the age of the metadata +msgid "Age" +msgstr "年紀" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:19 -#: policy/org.freedesktop.fwupd.policy.in:30 -msgid "Authentication is required to update the firmware on this machine" -msgstr "必須先通過身份核對才能更新這臺機器上的韌體" +#. TRANSLATORS: should the remote still be enabled +msgid "Agree and enable the remote?" +msgstr "同意並且啟用遠端站點?" -#: policy/org.freedesktop.fwupd.policy.in:28 -msgid "Install unsigned system firmware" -msgstr "安裝未簽署的系統韌體" +#. TRANSLATORS: this is a command alias, e.g. 'get-devices' +#, c-format +msgid "Alias to %s" +msgstr "%s 的別名" -#: policy/org.freedesktop.fwupd.policy.in:39 -msgid "Install old version of system firmware" -msgstr "安裝舊版本的系統韌體" +#. TRANSLATORS: command line option +msgid "Allow downgrading firmware versions" +msgstr "允許降級韌體版本" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:41 -msgid "Authentication is required to downgrade the firmware on this machine" -msgstr "必須先通過身份核對才能降級這臺機器上的韌體" +#. TRANSLATORS: command line option +msgid "Allow re-installing existing firmware versions" +msgstr "允許重新安裝既有的韌體版本" -#: policy/org.freedesktop.fwupd.policy.in:50 -msgid "Install signed device firmware" -msgstr "安裝已簽署的裝置韌體" +#. TRANSLATORS: explain why we want to reboot +msgid "An update requires a reboot to complete." +msgstr "有更新必須重新開機才能完成。" -#. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:52 -#: policy/org.freedesktop.fwupd.policy.in:63 -msgid "" -"Authentication is required to update the firmware on a removable device" -msgstr "必須先通過身份核對才能更新可移除裝置上的韌體" +#. TRANSLATORS: command line option +msgid "Answer yes to all questions" +msgstr "全部的問題都回答是" -#: policy/org.freedesktop.fwupd.policy.in:61 -#: policy/org.freedesktop.fwupd.policy.in:72 -msgid "Install unsigned device firmware" -msgstr "安裝未簽署的裝置韌體" +#. TRANSLATORS: command description +msgid "Apply a binary patch" +msgstr "套用二進位補丁" + +#. TRANSLATORS: command line option +msgid "Apply firmware updates" +msgstr "套用韌體更新" + +#. TRANSLATORS: command description +msgid "Attach DFU capable device back to runtime" +msgstr "將 DFU 能力裝置接回執行時期" + +#. TRANSLATORS: command description +msgid "Attach to firmware mode" +msgstr "連接至韌體模式" + +#. TRANSLATORS: device attributes, i.e. things that +#. * the device can do +msgid "Attributes" +msgstr "特性" + +#. TRANSLATORS: waiting for user to authenticate +msgid "Authenticating…" +msgstr "核對中…" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:74 -msgid "" -"Authentication is required to downgrade the firmware on a removable device" +msgid "Authentication is required to downgrade the firmware on a removable device" msgstr "必須先通過身份核對才能降級可移除裝置上的韌體" -#: policy/org.freedesktop.fwupd.policy.in:83 -msgid "Unlock the device to allow access" -msgstr "解鎖裝置以允許存取" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to downgrade the firmware on this machine" +msgstr "必須先通過身份核對才能降級這臺機器上的韌體" + +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to modify a configured remote used for firmware updates" +msgstr "必須通過身份核對才能修改設定作韌體更新的遠端站點" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:85 msgid "Authentication is required to unlock a device" msgstr "必須先通過身份核對才能解鎖裝置" -#: policy/org.freedesktop.fwupd.policy.in:94 -msgid "Update the stored device verification information" -msgstr "更新儲存的裝置核驗資訊" - #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:96 -msgid "" -"Authentication is required to update the stored checksums for the device" -msgstr "必須先通過身份核對才能更新裝置的儲存校驗計算碼" - -#: policy/org.freedesktop.fwupd.policy.in:105 -msgid "Modify a configured remote" -msgstr "修改設定的遠端" +msgid "Authentication is required to update the firmware on a removable device" +msgstr "必須先通過身份核對才能更新可移除裝置上的韌體" #. TRANSLATORS: this is the PolicyKit modal dialog -#: policy/org.freedesktop.fwupd.policy.in:107 -msgid "" -"Authentication is required to modify a configured remote used for firmware " -"updates" -msgstr "必須通過身份核對才能修改設定作韌體更新的遠端" +msgid "Authentication is required to update the firmware on this machine" +msgstr "必須先通過身份核對才能更新這臺機器上的韌體" -#. TRANSLATORS: this is a command alias, e.g. 'get-devices' -#: plugins/dfu/dfu-tool.c:124 plugins/synapticsmst/synapticsmst-tool.c:105 -#: src/fu-util.c:120 -#, c-format -msgid "Alias to %s" -msgstr "%s 的別名" +#. TRANSLATORS: this is the PolicyKit modal dialog +msgid "Authentication is required to update the stored checksums for the device" +msgstr "必須先通過身份核對才能更新裝置的儲存校驗計算碼" -#. TRANSLATORS: error message -#: plugins/dfu/dfu-tool.c:192 plugins/synapticsmst/synapticsmst-tool.c:347 -#: src/fu-util.c:184 -msgid "Command not found" -msgstr "找不到指令" +#. TRANSLATORS: command description +msgid "Build firmware using a sandbox" +msgstr "使用沙箱建置韌體" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1458 -msgid "Added" -msgstr "已加入" +#. TRANSLATORS: this is to abort the interactive prompt +msgid "Cancel" +msgstr "取消" -#. TRANSLATORS: this is when a device is hotplugged -#: plugins/dfu/dfu-tool.c:1469 -msgid "Removed" -msgstr "已移除" +#. TRANSLATORS: this is when a device ctrl+c's a watch +msgid "Cancelled" +msgstr "已取消" #. TRANSLATORS: this is when a device is hotplugged #. TRANSLATORS: this is when the daemon state changes -#: plugins/dfu/dfu-tool.c:1478 src/fu-util.c:1768 msgid "Changed" msgstr "已變更" -#. TRANSLATORS: this is when a device ctrl+c's a watch -#: plugins/dfu/dfu-tool.c:1486 src/fu-util.c:1730 -msgid "Cancelled" -msgstr "已取消" +#. TRANSLATORS: section header for firmware checksum +#. TRANSLATORS: remote checksum +msgid "Checksum" +msgstr "校驗計算碼" -#. TRANSLATORS: Appstream ID for the hardware type -#: plugins/dfu/dfu-tool.c:1978 src/fu-util.c:1549 -msgid "ID" -msgstr "ID" +#. TRANSLATORS: chip ID, e.g. "0x58200204" +msgid "Chip ID" +msgstr "晶片 ID" -#. TRANSLATORS: interface name, e.g. "Flash" -#. TRANSLATORS: device name, e.g. 'ColorHug2' -#. TRANSLATORS: section header for the release name -#: plugins/dfu/dfu-tool.c:1984 plugins/dfu/dfu-tool.c:1990 -#: plugins/dfu/dfu-tool.c:2104 src/fu-util.c:1321 -msgid "Name" -msgstr "名稱" +#. TRANSLATORS: get interactive prompt +msgid "Choose a device:" +msgstr "選擇裝置:" + +#. TRANSLATORS: get interactive prompt +msgid "Choose a release:" +msgstr "選擇發行版:" #. TRANSLATORS: this is the encryption method used when writing -#: plugins/dfu/dfu-tool.c:1997 msgid "Cipher" msgstr "加密法" -#. TRANSLATORS: these are areas of memory on the chip -#: plugins/dfu/dfu-tool.c:2011 -msgid "Region" -msgstr "地區" - -#. TRANSLATORS: detected a DFU device -#: plugins/dfu/dfu-tool.c:2064 -msgid "Found" -msgstr "找到" - -#. TRANSLATORS: DFU protocol version, e.g. 1.1 -#: plugins/dfu/dfu-tool.c:2072 -msgid "Protocol" -msgstr "協定" - -#. TRANSLATORS: probably not run as root... -#. TRANSLATORS: device has failed to report status -#. TRANSLATORS: device status, e.g. "OK" -#: plugins/dfu/dfu-tool.c:2082 plugins/dfu/dfu-tool.c:2091 -#: plugins/dfu/dfu-tool.c:2097 plugins/dfu/dfu-tool.c:2119 -msgid "Status" -msgstr "狀態" +#. TRANSLATORS: command description +msgid "Clears any updates scheduled to be updated offline" +msgstr "清除任何排程好的離線更新" -#: plugins/dfu/dfu-tool.c:2082 -msgid "Permission denied" -msgstr "請求許可遭拒" +#. TRANSLATORS: command description +msgid "Clears the results from the last update" +msgstr "清除上次更新的結果" -#. TRANSLATORS: serial number, e.g. '00012345' -#: plugins/dfu/dfu-tool.c:2110 -msgid "Serial" -msgstr "序號" +#. TRANSLATORS: error message +msgid "Command not found" +msgstr "找不到指令" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Mode" -msgstr "模式" +#. TRANSLATORS: command description +msgid "Convert firmware to DFU format" +msgstr "將韌體轉換為 DFU 格式" -#: plugins/dfu/dfu-tool.c:2115 -msgid "Runtime" -msgstr "執行時期" +#. TRANSLATORS: command description +msgid "Create a binary patch using two files" +msgstr "根據兩份檔案製作二進位補丁" -#: plugins/dfu/dfu-tool.c:2115 msgid "DFU" msgstr "DFU" -#. TRANSLATORS: device state, i.e. appIDLE -#: plugins/dfu/dfu-tool.c:2123 -msgid "State" -msgstr "狀態" - -#. TRANSLATORS: transfer size in bytes -#: plugins/dfu/dfu-tool.c:2131 -msgid "Transfer Size" -msgstr "傳輸大小" - -#. TRANSLATORS: device attributes, i.e. things that -#. * the device can do -#: plugins/dfu/dfu-tool.c:2139 -msgid "Attributes" -msgstr "特性" +#. TRANSLATORS: DFU stands for device firmware update +msgid "DFU Utility" +msgstr "DFU 公用程式" -#. TRANSLATORS: device quirks, i.e. things that -#. * it does that we have to work around -#: plugins/dfu/dfu-tool.c:2147 -msgid "Quirks" -msgstr "奇技淫巧" +#. TRANSLATORS: for the --verbose arg +msgid "Debugging Options" +msgstr "除錯選項" -#. TRANSLATORS: chip ID, e.g. "0x58200204" -#: plugins/dfu/dfu-tool.c:2154 -msgid "Chip ID" -msgstr "晶片 ID" +#. TRANSLATORS: decompressing the firmware file +msgid "Decompressing…" +msgstr "解壓縮中…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2234 -msgid "Convert firmware to DFU format" -msgstr "將韌體轉換為 DFU 格式" +msgid "Decrypt firmware data" +msgstr "解密韌體資料" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2240 -msgid "Merge multiple firmware files into one" -msgstr "合併多份韌體檔案為一份" +#. TRANSLATORS: section header for firmware description +msgid "Description" +msgstr "描述說明" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2246 -msgid "Set vendor ID on firmware file" -msgstr "設定韌體檔案廠商 ID" +msgid "Detach currently attached DFU capable device" +msgstr "解開目前接上的 DFU 能力裝置" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2252 -msgid "Set product ID on firmware file" -msgstr "設定韌體檔案產品 ID" +msgid "Detach to bootloader mode" +msgstr "斷開至開機載入器模式" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2258 -msgid "Set element address on firmware file" -msgstr "設定韌體檔案元素位址" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device added:" +msgstr "裝置已加入:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2264 -msgid "Set the firmware size for the target" -msgstr "設定目標的韌體檔案大小" +#. TRANSLATORS: this is when a device has been updated +msgid "Device changed:" +msgstr "裝置已變更:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2270 -msgid "Set release version on firmware file" -msgstr "設定韌體檔案發行版本" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Device removed:" +msgstr "裝置已移除:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2276 -msgid "Set alternative number on firmware file" -msgstr "設定韌體檔案替代編號" +#. TRANSLATORS: a list of successful updates +msgid "Devices that have been updated successfully:" +msgstr "成功更新的裝置:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2282 -msgid "Set alternative name on firmware file" -msgstr "設定韌體檔案替代名稱" +#. TRANSLATORS: a list of failed updates +msgid "Devices that were not updated correctly:" +msgstr "無法正確更新的裝置:" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2288 -msgid "Attach DFU capable device back to runtime" -msgstr "將 DFU 能力裝置接回執行時期" +msgid "Disabled fwupdate debugging" +msgstr "已停用 fwupdate 除錯" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2294 -msgid "Reset a DFU device" -msgstr "重設 DFU 裝置" +msgid "Disables a given remote" +msgstr "停用指定的遠端站點" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2300 -msgid "Read firmware from device into a file" -msgstr "將裝置的韌體讀取為檔案" +#. TRANSLATORS: command line option +msgid "Display version" +msgstr "顯示版本" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2306 -msgid "Read firmware from one partition into a file" -msgstr "從一分割區將韌體讀取為檔案" +#. TRANSLATORS: command line option +msgid "Do not check for old metadata" +msgstr "不要檢查中介資料是否老舊" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2312 -msgid "Write firmware from file into device" -msgstr "從檔案將韌體寫入裝置" +#. TRANSLATORS: command line option +msgid "Do not check for reboot after update" +msgstr "不要檢查是否更新後要重新開機" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2318 -msgid "Write firmware from file into one partition" -msgstr "從檔案將韌體寫入一分割區" +#. TRANSLATORS: command line option +msgid "Do not check for unreported history" +msgstr "不要檢查是否有尚未報告的歷史" + +#. TRANSLATORS: command line option +msgid "Do not write to the history database" +msgstr "不要寫入歷史資料庫中" + +#. success +msgid "Done!" +msgstr "完成!" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2324 -msgid "List currently attached DFU capable devices" -msgstr "列出目前接上的 DFU 能力裝置" +msgid "Downgrades the firmware on a device" +msgstr "降級裝置的韌體" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Downgrading %s from %s to %s... " +msgstr "正將 %s 從 %s 版降級至 %s 版... " + +#. TRANSLATORS: downloading from a remote server +msgid "Downloading…" +msgstr "下載中…" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2330 -msgid "Detach currently attached DFU capable device" -msgstr "解開目前接上的 DFU 能力裝置" +msgid "Dump SMBIOS data from a file" +msgstr "從檔案傾印 SMBIOUS 資料" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2336 msgid "Dump details about a firmware file" msgstr "傾印韌體檔案的相關細節" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2342 -msgid "Watch DFU devices being hotplugged" -msgstr "監看 DFU 裝置熱插拔的過程" +msgid "Dump information about a binary patch to the screen" +msgstr "傾印二進位補丁相關資訊至螢幕上" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2348 -msgid "Encrypt firmware data" -msgstr "加密韌體資料" +#. TRANSLATORS: ESP is EFI System Partition +msgid "ESP specified was not valid" +msgstr "指定的 ESP 無效" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2354 -msgid "Decrypt firmware data" -msgstr "解密韌體資料" +#. TRANSLATORS: command line option +msgid "Enable firmware update support on supported systems" +msgstr "對支援的系統啟用韌體更新支援" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2360 -msgid "Sets metadata on a firmware file" -msgstr "設定韌體檔案的中介資料" +#. TRANSLATORS: Turn on the remote +msgid "Enable this remote?" +msgstr "啟用此遠端站點?" -#. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2366 -msgid "Replace data in an existing firmware file" -msgstr "取代既有韌體檔案中的資料" +#. TRANSLATORS: if the remote is enabled +msgid "Enabled" +msgstr "啟用" + +msgid "Enabled fwupdate debugging" +msgstr "已啟用 fwupdate 除錯" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2372 -msgid "Create a binary patch using two files" -msgstr "根據兩份檔案製作二進位補丁" +msgid "Enables a given remote" +msgstr "啟用指定的遠端站點" + +msgid "Enabling this functionality is done at your own risk, which means you have to contact your original equipment manufacturer regarding any problems caused by these updates. Only problems with the update process itself should be filed at $OS_RELEASE:BUG_REPORT_URL$." +msgstr "啟用此功能必須自負風險。這代表若您遭遇到這些更新導致的任何問題,您必須向原始設備供應商聯絡並反應。只有在您遇到更新過程本身的問題時,才是向 $OS_RELEASE:BUG_REPORT_URL$ 回報。" + +#. TRANSLATORS: show the user a warning +msgid "Enabling this remote is done at your own risk." +msgstr "若要啟用此遠端站點,請自負風險。" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2378 -msgid "Apply a binary patch" -msgstr "套用二進位補丁" +msgid "Encrypt firmware data" +msgstr "加密韌體資料" #. TRANSLATORS: command description -#: plugins/dfu/dfu-tool.c:2384 -msgid "Dump information about a binary patch to the screen" -msgstr "傾印二進位補丁相關資訊至螢幕上" +msgid "Erase all firmware update history" +msgstr "抹除所有韌體更新歷史" + +#. TRANSLATORS: erasing contents of the flash chips +msgid "Erasing…" +msgstr "抹除中…" + +#. TRANSLATORS: exit after we've started up, used for user profiling +msgid "Exit after a small delay" +msgstr "經過一段短暫延遲後便離開" + +#. TRANSLATORS: exit straight away, used for automatic profiling +msgid "Exit after the engine has loaded" +msgstr "引擎載入後離開" + +#. TRANSLATORS: the server is rate-limiting downloads +msgid "Failed to download due to server limit" +msgstr "因伺服器限制而下載失敗" #. TRANSLATORS: quirks are device-specific workarounds -#: plugins/dfu/dfu-tool.c:2396 msgid "Failed to load quirks" msgstr "無法載入奇技淫巧" -#. TRANSLATORS: DFU stands for device firmware update -#: plugins/dfu/dfu-tool.c:2418 -msgid "DFU Utility" -msgstr "DFU 公用程式" - #. TRANSLATORS: the user didn't read the man page -#: plugins/dfu/dfu-tool.c:2423 plugins/synapticsmst/synapticsmst-tool.c:424 -#: src/fu-util.c:2339 msgid "Failed to parse arguments" msgstr "無法解析引數" -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:393 -msgid "Enumerate all Synaptics MST devices" -msgstr "枚舉所有 Synaptics MST 裝置" - -#. TRANSLATORS: command description -#: plugins/synapticsmst/synapticsmst-tool.c:399 -msgid "Flash firmware file to MST device" -msgstr "刷寫韌體檔案至 MST 裝置" - -#: plugins/synapticsmst/synapticsmst-tool.c:419 -msgid "Synaptics Multistream Transport Utility" -msgstr "Synaptics 多串流傳輸公用程式" +#. TRANSLATORS: downloading unknown file +msgid "Fetching file" +msgstr "擷取檔案中" -#. TRANSLATORS: this is shown when updating the firmware after the reboot -#: plugins/uefi/fu-plugin-uefi.c:403 -msgid "Installing firmware update…" -msgstr "安裝韌體更新中…" +#. TRANSLATORS: downloading new firmware file +msgid "Fetching firmware" +msgstr "擷取韌體中" -#. TRANSLATORS: turn on all debugging -#: src/fu-debug.c:128 -msgid "Show debugging information for all files" -msgstr "顯示所有檔案的除錯資訊" +#. TRANSLATORS: downloading new metadata file +msgid "Fetching metadata" +msgstr "擷取中介資料中" -#. TRANSLATORS: this is for plugin development -#: src/fu-debug.c:131 -msgid "Show plugin verbose information" -msgstr "顯示插件詳盡資訊" +#. TRANSLATORS: downloading new signing file +msgid "Fetching signature" +msgstr "擷取簽章中" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:186 -msgid "Debugging Options" -msgstr "除錯選項" +#. TRANSLATORS: filename of the local file +msgid "Filename" +msgstr "檔名" -#. TRANSLATORS: for the --verbose arg -#: src/fu-debug.c:188 -msgid "Show debugging options" -msgstr "顯示除錯選項" +#. TRANSLATORS: filename of the local file +msgid "Filename Signature" +msgstr "檔名簽章" -#. TRANSLATORS: exit after we've started up, used for user profiling -#: src/fu-main.c:1036 -msgid "Exit after a small delay" -msgstr "經過一段短暫延遲後便離開" +#. TRANSLATORS: remote URI +msgid "Firmware Base URI" +msgstr "韌體基礎 URI" -#. TRANSLATORS: exit straight away, used for automatic profiling -#: src/fu-main.c:1039 -msgid "Exit after the engine has loaded" -msgstr "引擎載入後離開" +#. TRANSLATORS: program summary +msgid "Firmware Update D-Bus Service" +msgstr "韌體更新 D-Bus 服務" #. TRANSLATORS: program name -#: src/fu-main.c:1053 msgid "Firmware Update Daemon" msgstr "韌體更新幕後程式" -#. TRANSLATORS: program summary -#: src/fu-main.c:1058 -msgid "Firmware Update D-Bus Service" -msgstr "韌體更新 D-Bus 服務" +#. TRANSLATORS: program name +msgid "Firmware Utility" +msgstr "韌體公用程式" -#. TRANSLATORS: daemon is inactive -#: src/fu-progressbar.c:52 -msgid "Idle…" -msgstr "閒置…" +#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 +#, c-format +msgid "Firmware metadata has not been updated for %u day and may not be up to date." +msgid_plural "Firmware metadata has not been updated for %u days and may not be up to date." +msgstr[0] "韌體中介資料已有 %u 天未更新,可能不是最新狀態。" -#. TRANSLATORS: decompressing the firmware file -#: src/fu-progressbar.c:56 -msgid "Decompressing…" -msgstr "解壓縮中…" +msgid "Firmware updates are not supported on this machine." +msgstr "此機器沒有韌體更新支援。" -#. TRANSLATORS: parsing the firmware information -#: src/fu-progressbar.c:60 -msgid "Loading…" -msgstr "載入中…" +msgid "Firmware updates are supported on this machine." +msgstr "此機器有韌體更新支援。" -#. TRANSLATORS: restarting the device to pick up new F/W -#: src/fu-progressbar.c:64 -msgid "Restarting device…" -msgstr "重新啓動裝置中…" +#. TRANSLATORS: detected a DFU device +msgid "Found" +msgstr "找到" -#. TRANSLATORS: reading from the flash chips -#: src/fu-progressbar.c:68 -msgid "Reading…" -msgstr "讀取中…" +msgid "GUID" +msgstr "GUID" -#. TRANSLATORS: writing to the flash chips -#: src/fu-progressbar.c:72 -msgid "Writing…" -msgstr "寫入中…" +#. TRANSLATORS: command description +msgid "Get all devices according to the system topology" +msgstr "取得根據系統拓樸而得的所有裝置" -#. TRANSLATORS: erasing contents of the flash chips -#: src/fu-progressbar.c:76 -msgid "Erasing…" -msgstr "抹除中…" +#. TRANSLATORS: command description +msgid "Get all devices that support firmware updates" +msgstr "取得所有支援韌體更新的裝置" -#. TRANSLATORS: verifying we wrote the firmware correctly -#: src/fu-progressbar.c:80 -msgid "Verifying…" -msgstr "核驗中…" +#. TRANSLATORS: command description +msgid "Get all enabled plugins registered with the system" +msgstr "取得所有系統中註冊的啟用插件" -#. TRANSLATORS: scheduing an update to be done on the next boot -#: src/fu-progressbar.c:84 -msgid "Scheduling…" -msgstr "排程中…" +#. TRANSLATORS: command description +msgid "Gets details about a firmware file" +msgstr "取得韌體檔案的相關細節" -#. TRANSLATORS: downloading from a remote server -#: src/fu-progressbar.c:88 -msgid "Downloading…" -msgstr "下載中…" +#. TRANSLATORS: command description +msgid "Gets the configured remotes" +msgstr "取得設定的遠端站點" -#. TRANSLATORS: waiting for user to authenticate -#: src/fu-progressbar.c:92 -msgid "Authenticating…" -msgstr "核對中…" +#. TRANSLATORS: command description +msgid "Gets the cryptographic hash of the dumped firmware" +msgstr "取得傾印韌體檔案的加密雜湊" -#. TRANSLATORS: waiting for device to do something -#: src/fu-progressbar.c:96 -msgid "Waiting…" -msgstr "等候中…" +#. TRANSLATORS: command description +msgid "Gets the list of updates for connected hardware" +msgstr "取得連接硬體的更新清單" -#. TRANSLATORS: currect daemon status is unknown -#: src/fu-progressbar.c:103 -msgid "Unknown" -msgstr "未知" +#. TRANSLATORS: command description +msgid "Gets the releases for a device" +msgstr "取得裝置的發行版本" -#. TRANSLATORS: the user isn't reading the question -#: src/fu-util.c:242 -#, c-format -msgid "Please enter a number from 0 to %u: " -msgstr "" +#. TRANSLATORS: command description +msgid "Gets the results from the last update" +msgstr "取得上次更新的結果" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:305 -msgid "Choose a device:" -msgstr "選擇裝置:" +#. TRANSLATORS: Appstream ID for the hardware type +msgid "ID" +msgstr "ID" -#. TRANSLATORS: this is to abort the interactive prompt -#: src/fu-util.c:307 -msgid "Cancel" -msgstr "" +#. TRANSLATORS: daemon is inactive +msgid "Idle…" +msgstr "閒置…" -#. TRANSLATORS: a list of failed updates -#: src/fu-util.c:427 -msgid "Devices that were not updated correctly:" -msgstr "無法正確更新的裝置:" +#. TRANSLATORS: command description +msgid "Install a firmware blob on a device" +msgstr "在裝置上安裝韌體 blob" -#. TRANSLATORS: a list of successful updates -#: src/fu-util.c:441 -msgid "Devices that have been updated successfully:" -msgstr "成功更新的裝置:" +#. TRANSLATORS: command description +msgid "Install a firmware file on this hardware" +msgstr "在此硬體安裝韌體檔案" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:455 -msgid "Upload report now?" -msgstr "是否立刻上傳報告?" +msgid "Install old version of system firmware" +msgstr "安裝舊版本的系統韌體" -#. TRANSLATORS: metadata is downloaded from the Internet -#: src/fu-util.c:457 src/fu-util.c:1490 -msgid "Requires internet connection" -msgstr "必須有網際網路連線" +msgid "Install signed device firmware" +msgstr "安裝已簽署的裝置韌體" -#. TRANSLATORS: nothing attached that can be upgraded -#: src/fu-util.c:479 -msgid "No hardware detected with firmware update capability" -msgstr "未偵測到具備韌體更新能力的硬體" +msgid "Install signed system firmware" +msgstr "安裝已簽署的系統韌體" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second is a version number -#. * e.g. "1.2.3" -#: src/fu-util.c:651 -#, c-format -msgid "Reinstalling %s with %s... " -msgstr "正重新安裝 %s %s 版…" +msgid "Install unsigned device firmware" +msgstr "安裝未簽署的裝置韌體" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:658 -#, c-format -msgid "Downgrading %s from %s to %s... " -msgstr "正降級 %s 從 %s 版至 %s 版…" +msgid "Install unsigned system firmware" +msgstr "安裝未簽署的系統韌體" -#. TRANSLATORS: the first replacement is a display name -#. * e.g. "ColorHugALS" and the second and third are -#. * version numbers e.g. "1.2.3" -#: src/fu-util.c:666 +#. TRANSLATORS: this is shown when updating the firmware after the reboot +msgid "Installing firmware update…" +msgstr "安裝韌體更新中…" + +#. TRANSLATORS: %1 is a device name #, c-format -msgid "Updating %s from %s to %s... " -msgstr "正更新 %s 從 %s 版至 %s 版…" +msgid "Installing on %s…" +msgstr "正安裝到 %s…" -#: src/fu-util.c:694 -msgid "Done!" -msgstr "完成!" +msgid "Keyring" +msgstr "鑰匙圈" -#: src/fu-util.c:726 -msgid "Target" -msgstr "目標" +#. TRANSLATORS: time remaining for completing firmware flash +msgid "Less than one minute remaining" +msgstr "剩不到一分鐘" -#: src/fu-util.c:727 -msgid "Payload" -msgstr "酬載" +msgid "Linux Vendor Firmware Service (stable firmware)" +msgstr "Linux 廠商韌體服務(穩定版韌體)" -#: src/fu-util.c:728 -msgid "Proceed with upload?" -msgstr "繼續上傳?" +msgid "Linux Vendor Firmware Service (testing firmware)" +msgstr "Linux 廠商韌體服務(測試中韌體)" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:807 -msgid "Update failure is a known issue, visit this URL for more information:" -msgstr "更新失敗是已知議題,請造訪此 URL 瞭解更多資訊:" +#. TRANSLATORS: command description +msgid "List currently attached DFU capable devices" +msgstr "列出目前接上的 DFU 能力裝置" -#. TRANSLATORS: the server sent the user a small message -#: src/fu-util.c:811 -msgid "Upload message:" -msgstr "上傳訊息:" +#. TRANSLATORS: command line option +msgid "List supported firmware updates" +msgstr "列出支援的韌體更新" -#: src/fu-util.c:1034 src/fu-util.c:1414 -msgid "OK" -msgstr "確定" +#. TRANSLATORS: parsing the firmware information +msgid "Loading…" +msgstr "載入中…" -#. TRANSLATORS: downloading new signing file -#: src/fu-util.c:1139 -msgid "Fetching signature" -msgstr "擷取簽章中" +#. TRANSLATORS: command line option +msgid "Manually whitelist specific plugins" +msgstr "手動白名單指定插件" -#. TRANSLATORS: downloading new metadata file -#: src/fu-util.c:1142 -msgid "Fetching metadata" -msgstr "擷取中介資料中" +#. TRANSLATORS: command description +msgid "Merge multiple firmware files into one" +msgstr "合併多份韌體檔案為一份" -#. TRANSLATORS: downloading new firmware file -#: src/fu-util.c:1145 -msgid "Fetching firmware" -msgstr "擷取韌體中" +#. TRANSLATORS: remote URI +msgid "Metadata URI" +msgstr "中介資料 URI" -#. TRANSLATORS: downloading unknown file -#: src/fu-util.c:1148 -msgid "Fetching file" -msgstr "擷取檔案中" +#. TRANSLATORS: remote URI +msgid "Metadata URI Signature" +msgstr "中介資料 URI 簽章" -#. TRANSLATORS: section header for release version number -#: src/fu-util.c:1318 -msgid "Version" -msgstr "版本" +#. TRANSLATORS: explain why no metadata available +msgid "Metadata can be obtained from the Linux Vendor Firmware Service." +msgstr "中介資料可從 Linux 廠商韌體服務取得。" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1324 -msgid "Summary" -msgstr "摘要" +msgid "Mode" +msgstr "模式" -#. TRANSLATORS: section header for the remote the file is coming from -#: src/fu-util.c:1327 -msgid "Remote" -msgstr "遠端" +#. TRANSLATORS: command description +msgid "Modifies a given remote" +msgstr "修改指定的遠端站點" -#. TRANSLATORS: section header for firmware URI -#: src/fu-util.c:1330 -msgid "URI" -msgstr "URI" +msgid "Modify a configured remote" +msgstr "修改設定的遠端站點" -#. TRANSLATORS: section header for firmware description -#: src/fu-util.c:1336 -msgid "Description" -msgstr "描述說明" +#. TRANSLATORS: command description +msgid "Monitor the daemon for events" +msgstr "監控幕後程式是否有活動" -#. TRANSLATORS: section header for firmware checksum -#. TRANSLATORS: remote checksum -#: src/fu-util.c:1344 src/fu-util.c:1640 -msgid "Checksum" -msgstr "校驗計算碼" +#. TRANSLATORS: interface name, e.g. "Flash" +#. TRANSLATORS: device name, e.g. 'ColorHug2' +#. TRANSLATORS: section header for the release name +msgid "Name" +msgstr "名稱" -#. TRANSLATORS: get interactive prompt -#: src/fu-util.c:1376 -msgid "Choose a release:" -msgstr "選擇發行版:" +msgid "No action specified!" +msgstr "未指定動作!" -#. TRANSLATORS: the metadata is very out of date; %u is a number > 1 -#: src/fu-util.c:1480 -#, c-format -msgid "" -"Firmware metadata has not been updated for %u day and may not be up to date." -msgid_plural "" -"Firmware metadata has not been updated for %u days and may not be up to " -"date." -msgstr[0] "韌體中介資料已有 %u 天未更新,可能不是最新狀態。" +#. TRANSLATORS: nothing attached +#. TRANSLATORS: nothing attached that can be upgraded +msgid "No hardware detected with firmware update capability" +msgstr "未偵測到具備韌體更新能力的硬體" -#. TRANSLATORS: ask the user if we can update the metadata -#: src/fu-util.c:1488 -msgid "Update now?" -msgstr "是否立刻更更新?" +#. TRANSLATORS: nothing found +msgid "No plugins found" +msgstr "找不到插件" + +#. TRANSLATORS: explain why no metadata available +msgid "No remotes are currently enabled so no metadata is available." +msgstr "目前沒有啟用的遠端站點,因而沒有中介資料可用。" -#. TRANSLATORS: first replacement is device name -#: src/fu-util.c:1533 +msgid "OK" +msgstr "確定" + +#. TRANSLATORS: command line option +msgid "Override plugin warning" +msgstr "凌駕插件警告" + +#. TRANSLATORS: command line option +msgid "Override the default ESP path" +msgstr "凌駕預設 ESP 路徑" + +#. TRANSLATORS: remote filename base +msgid "Password" +msgstr "密碼" + +msgid "Payload" +msgstr "酬載" + +msgid "Permission denied" +msgstr "請求許可遭拒" + +#. TRANSLATORS: the user isn't reading the question #, c-format -msgid "%s has firmware updates:" -msgstr "%s 有韌體更新:" +msgid "Please enter a number from 0 to %u: " +msgstr "請輸入 0 到 %u 之間的數字:" -#: src/fu-util.c:1540 -msgid "GUID" -msgstr "GUID" +#. TRANSLATORS: the numeric priority +msgid "Priority" +msgstr "優先等級" -#. TRANSLATORS: section header for firmware version -#: src/fu-util.c:1552 -msgid "Update Version" -msgstr "更新版本" +msgid "Proceed with upload?" +msgstr "繼續上傳?" -#. TRANSLATORS: section header for the release name -#: src/fu-util.c:1556 -msgid "Update Name" -msgstr "更新名稱" +#. TRANSLATORS: DFU protocol version, e.g. 1.1 +msgid "Protocol" +msgstr "協定" -#. TRANSLATORS: section header for the release one line summary -#: src/fu-util.c:1559 -msgid "Update Summary" -msgstr "更新摘要" +#. TRANSLATORS: command line option +msgid "Query for firmware update support" +msgstr "查詢韌體更新支援" -#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing -#: src/fu-util.c:1562 -msgid "Update Remote ID" -msgstr "更新遠端 ID" +#. TRANSLATORS: device quirks, i.e. things that +#. * it does that we have to work around +msgid "Quirks" +msgstr "奇技淫巧" -#. TRANSLATORS: section header for firmware checksum -#: src/fu-util.c:1571 -msgid "Update Checksum" -msgstr "更新校驗計算碼" +#. TRANSLATORS: command description +msgid "Read firmware from device into a file" +msgstr "將裝置的韌體讀取為檔案" -#. TRANSLATORS: section header for firmware remote http:// -#: src/fu-util.c:1575 -msgid "Update Location" -msgstr "更新位置" +#. TRANSLATORS: command description +msgid "Read firmware from one partition into a file" +msgstr "從一分割區將韌體讀取為檔案" -#. TRANSLATORS: section header for long firmware desc -#: src/fu-util.c:1586 -msgid "Update Description" -msgstr "更新描述說明" +#. TRANSLATORS: reading from the flash chips +msgid "Reading…" +msgstr "讀取中…" + +#. TRANSLATORS: command description +msgid "Refresh metadata from remote server" +msgstr "重整遠端伺服器的中介資料" + +#. TRANSLATORS: these are areas of memory on the chip +msgid "Region" +msgstr "地區" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second is a version number +#. * e.g. "1.2.3" +#, c-format +msgid "Reinstalling %s with %s... " +msgstr "正將 %s 重新安裝為 %s 版... " + +#. TRANSLATORS: section header for the remote the file is coming from +msgid "Remote" +msgstr "遠端" #. TRANSLATORS: remote identifier, e.g. lvfs-testing -#: src/fu-util.c:1618 msgid "Remote ID" msgstr "遠端 ID" -#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" -#: src/fu-util.c:1622 -msgid "Title" -msgstr "標題" +#. TRANSLATORS: this is when a device is hotplugged +msgid "Removed" +msgstr "已移除" -#. TRANSLATORS: remote type, e.g. remote or local -#: src/fu-util.c:1626 -msgid "Type" -msgstr "類型" +#. TRANSLATORS: command description +msgid "Replace data in an existing firmware file" +msgstr "取代既有韌體檔案中的資料" -#: src/fu-util.c:1631 -msgid "Keyring" -msgstr "鑰匙圈" +#. TRANSLATORS: URI to send success/failure reports +msgid "Report URI" +msgstr "報告 URI" -#. TRANSLATORS: if the remote is enabled -#: src/fu-util.c:1636 -msgid "Enabled" -msgstr "啟用" +#. TRANSLATORS: metadata is downloaded from the Internet +msgid "Requires internet connection" +msgstr "必須有網際網路連線" -#. TRANSLATORS: the age of the metadata -#: src/fu-util.c:1667 -msgid "Age" -msgstr "年紀" +#. TRANSLATORS: command description +msgid "Reset a DFU device" +msgstr "重設 DFU 裝置" -#. TRANSLATORS: the numeric priority -#: src/fu-util.c:1674 -msgid "Priority" -msgstr "優先等級" +#. TRANSLATORS: reboot to apply the update +msgid "Restart now?" +msgstr "是否立刻重新啟動?" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1679 -msgid "Username" -msgstr "使用者名稱" +#. TRANSLATORS: restarting the device to pick up new F/W +msgid "Restarting device…" +msgstr "重新啓動裝置中…" -#. TRANSLATORS: remote filename base -#: src/fu-util.c:1684 -msgid "Password" -msgstr "密碼" +#. TRANSLATORS: command description +msgid "Return all the hardware IDs for the machine" +msgstr "回傳所有機器的硬體 ID" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1689 -msgid "Filename" -msgstr "檔名" +msgid "Runtime" +msgstr "執行時期" -#. TRANSLATORS: filename of the local file -#: src/fu-util.c:1694 -msgid "Filename Signature" -msgstr "檔名簽章" +#. TRANSLATORS: command line option +msgid "Schedule installation for next reboot when possible" +msgstr "安排下次重新開機時若可行便安裝" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1699 -msgid "Metadata URI" -msgstr "中介資料 URI" +#. TRANSLATORS: scheduing an update to be done on the next boot +msgid "Scheduling…" +msgstr "排程中…" + +#. TRANSLATORS: serial number, e.g. '00012345' +msgid "Serial" +msgstr "序號" + +#. TRANSLATORS: command description +msgid "Set alternative name on firmware file" +msgstr "設定韌體檔案替代名稱" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1704 -msgid "Metadata URI Signature" -msgstr "中介資料 URI 簽章" +#. TRANSLATORS: command description +msgid "Set alternative number on firmware file" +msgstr "設定韌體檔案替代編號" -#. TRANSLATORS: remote URI -#: src/fu-util.c:1709 -msgid "Firmware Base URI" -msgstr "韌體基礎 URI" +#. TRANSLATORS: command description +msgid "Set element address on firmware file" +msgstr "設定韌體檔案元素位址" -#. TRANSLATORS: URI to send success/failure reports -#: src/fu-util.c:1714 -msgid "Report URI" -msgstr "報告 URI" +#. TRANSLATORS: command description +msgid "Set product ID on firmware file" +msgstr "設定韌體檔案產品 ID" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1741 -msgid "Device added:" -msgstr "裝置已加入:" +#. TRANSLATORS: command description +msgid "Set release version on firmware file" +msgstr "設定韌體檔案發行版本" -#. TRANSLATORS: this is when a device is hotplugged -#: src/fu-util.c:1751 -msgid "Device removed:" -msgstr "裝置已移除:" +#. TRANSLATORS: command line option +msgid "Set the debugging flag during update" +msgstr "在更新期間設定除錯旗標" -#. TRANSLATORS: this is when a device has been updated -#: src/fu-util.c:1761 -msgid "Device changed:" -msgstr "裝置已變更:" +#. TRANSLATORS: command description +msgid "Set the firmware size for the target" +msgstr "設定目標的韌體檔案大小" -#. TRANSLATORS: explain why we want to upload -#: src/fu-util.c:1952 -msgid "An update requires a reboot to complete." -msgstr "有更新必須重新開機才能完成。" +#. TRANSLATORS: command description +msgid "Set vendor ID on firmware file" +msgstr "設定韌體檔案廠商 ID" -#. TRANSLATORS: reboot to apply the update -#: src/fu-util.c:1954 -msgid "Restart now?" -msgstr "是否立刻重新啟動?" +#. TRANSLATORS: command description +msgid "Sets metadata on a firmware file" +msgstr "設定韌體檔案的中介資料" -#. TRANSLATORS: command line option -#: src/fu-util.c:2116 -msgid "Show extra debugging information" -msgstr "顯示額外除錯資訊" +#. TRANSLATORS: command description +msgid "Share firmware history with the developers" +msgstr "和開發者分享韌體歷史" #. TRANSLATORS: command line option -#: src/fu-util.c:2119 msgid "Show client and daemon versions" msgstr "顯示客戶端與幕後程式版本" -#. TRANSLATORS: command line option -#: src/fu-util.c:2122 -msgid "Schedule installation for next reboot when possible" -msgstr "安排下次重新開機時若可行便安裝" +#. TRANSLATORS: for the --verbose arg +msgid "Show debugging options" +msgstr "顯示除錯選項" #. TRANSLATORS: command line option -#: src/fu-util.c:2125 -msgid "Allow re-installing existing firmware versions" -msgstr "允許重新安裝既有的韌體版本" +msgid "Show devices that are not updatable" +msgstr "顯示不可更新的裝置" #. TRANSLATORS: command line option -#: src/fu-util.c:2128 -msgid "Allow downgrading firmware versions" -msgstr "允許降級韌體版本" +msgid "Show extra debugging information" +msgstr "顯示額外除錯資訊" -#. TRANSLATORS: command line option -#: src/fu-util.c:2131 -msgid "Override plugin warning" -msgstr "凌駕插件警告" +#. TRANSLATORS: command description +msgid "Show history of firmware updates" +msgstr "顯示韌體更新的歷史" -#. TRANSLATORS: command line option -#: src/fu-util.c:2134 -msgid "Answer yes to all questions" -msgstr "全部的問題都回答是" +#. TRANSLATORS: this is for plugin development +msgid "Show plugin verbose information" +msgstr "顯示插件詳盡資訊" #. TRANSLATORS: command line option -#: src/fu-util.c:2137 -msgid "Do not check for unreported history" -msgstr "不要檢查是否有尚未報告的歷史" +msgid "Show the debug log from the last attempted update" +msgstr "顯示從上次試圖更新起的除錯紀錄" #. TRANSLATORS: command line option -#: src/fu-util.c:2140 -msgid "Do not check for old metadata" -msgstr "不要檢查中介資料是否老舊" +msgid "Show the information of firmware update status" +msgstr "顯示韌體更新狀態的資訊" -#. TRANSLATORS: command line option -#: src/fu-util.c:2143 -msgid "Do not check for reboot after update" -msgstr "不要檢查是否更新後要重新開機" +#. TRANSLATORS: device state, i.e. appIDLE +msgid "State" +msgstr "狀態" -#. TRANSLATORS: command description -#: src/fu-util.c:2166 -msgid "Get all devices that support firmware updates" -msgstr "取得所有支援韌體更新的裝置" +#. TRANSLATORS: probably not run as root... +#. TRANSLATORS: device has failed to report status +#. TRANSLATORS: device status, e.g. "OK" +msgid "Status" +msgstr "狀態" -#. TRANSLATORS: command description -#: src/fu-util.c:2172 -msgid "Return all the hardware IDs for the machine" -msgstr "回傳所有機器的硬體 ID" +#. TRANSLATORS: section header for the release one line summary +msgid "Summary" +msgstr "摘要" -#. TRANSLATORS: command description -#: src/fu-util.c:2178 -msgid "Install prepared updates now" -msgstr "立刻安裝準備的更新" +msgid "Target" +msgstr "目標" -#. TRANSLATORS: command description -#: src/fu-util.c:2184 -msgid "Show history of firmware updates" -msgstr "顯示韌體更新的歷史" +#. TRANSLATORS: do not translate the variables marked using $ +msgid "The LVFS is a free service that operates as an independent legal entity and has no connection with $OS_RELEASE:NAME$. Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices. All firmware is provided only by the original equipment manufacturer." +msgstr "LVFS(Linux 廠商韌體服務,Linux Vendor Firmware Service)是由獨立法人運作的免費服務,而與 $OS_RELEASE:NAME$ 沒有關聯。您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。所有本服務中的韌體僅由原始設備製造商提供。" + +#. TRANSLATORS: we're poking around as a power user +msgid "This program may only work correctly as root" +msgstr "此程式僅有 root 身份才能正常運作" -#. TRANSLATORS: command description -#: src/fu-util.c:2190 -msgid "Erase all firmware update history" -msgstr "抹除所有韌體更新歷史" +msgid "This remote contains firmware which is not embargoed, but is still being tested by the hardware vendor. You should ensure you have a way to manually downgrade the firmware if the firmware update fails." +msgstr "這個遠端站點包含未列入禁運,但仍處於硬體廠商測試階段的韌體。您應該確保自己在韌體更新失敗時有方法能夠手動降級韌體。" -#. TRANSLATORS: command description -#: src/fu-util.c:2196 -msgid "Share firmware history with the developers" -msgstr "和開發者分享韌體歷史" +#. TRANSLATORS: remote title, e.g. "Linux Vendor Firmware Service" +msgid "Title" +msgstr "標題" -#. TRANSLATORS: command description -#: src/fu-util.c:2202 -msgid "Install a firmware file on this hardware" -msgstr "在此硬體安裝韌體檔案" +#. TRANSLATORS: transfer size in bytes +msgid "Transfer Size" +msgstr "傳輸大小" -#. TRANSLATORS: command description -#: src/fu-util.c:2208 -msgid "Gets details about a firmware file" -msgstr "取得韌體檔案的相關細節" +#. TRANSLATORS: remote type, e.g. remote or local +msgid "Type" +msgstr "類型" -#. TRANSLATORS: command description -#: src/fu-util.c:2214 -msgid "Gets the list of updates for connected hardware" -msgstr "取得連接硬體的更新清單" +#. TRANSLATORS: program name +msgid "UEFI Firmware Utility" +msgstr "UEFI 韌體公用程式" -#. TRANSLATORS: command description -#: src/fu-util.c:2220 -msgid "Updates all firmware to latest versions available" -msgstr "將所有韌體更新至可用的最新版本" +#. TRANSLATORS: section header for firmware URI +msgid "URI" +msgstr "URI" -#. TRANSLATORS: command description -#: src/fu-util.c:2226 -msgid "Gets the cryptographic hash of the dumped firmware" -msgstr "取得傾印韌體檔案的加密雜湊" +#. TRANSLATORS: currect daemon status is unknown +msgid "Unknown" +msgstr "未知" + +msgid "Unlock the device to allow access" +msgstr "解鎖裝置以允許存取" #. TRANSLATORS: command description -#: src/fu-util.c:2232 msgid "Unlocks the device for firmware access" msgstr "解鎖裝置以供韌體存取" -#. TRANSLATORS: command description -#: src/fu-util.c:2238 -msgid "Clears the results from the last update" -msgstr "清除上次更新的結果" +#. TRANSLATORS: command line option +msgid "Unset the debugging flag during update" +msgstr "取消更新期間的除錯旗標設定" -#. TRANSLATORS: command description -#: src/fu-util.c:2244 -msgid "Clears any updates scheduled to be updated offline" -msgstr "清除任何排程好的離線更新" +#. TRANSLATORS: section header for firmware checksum +msgid "Update Checksum" +msgstr "更新校驗計算碼" -#. TRANSLATORS: command description -#: src/fu-util.c:2250 -msgid "Gets the results from the last update" -msgstr "取得上次更新的結果" +#. TRANSLATORS: section header for long firmware desc +msgid "Update Description" +msgstr "更新描述說明" -#. TRANSLATORS: command description -#: src/fu-util.c:2256 -msgid "Gets the releases for a device" -msgstr "取得裝置的發行版本" +#. TRANSLATORS: section header for firmware remote http:// +msgid "Update Location" +msgstr "更新位置" -#. TRANSLATORS: command description -#: src/fu-util.c:2262 -msgid "Gets the configured remotes" -msgstr "取得設定的遠端" +#. TRANSLATORS: section header for the release name +msgid "Update Name" +msgstr "更新名稱" -#. TRANSLATORS: command description -#: src/fu-util.c:2268 -msgid "Downgrades the firmware on a device" -msgstr "降級裝置的韌體" +#. TRANSLATORS: section header for remote ID, e.g. lvfs-testing +msgid "Update Remote ID" +msgstr "更新遠端 ID" -#. TRANSLATORS: command description -#: src/fu-util.c:2274 -msgid "Refresh metadata from remote server" -msgstr "重整遠端伺服器的中介資料" +#. TRANSLATORS: section header for the release one line summary +msgid "Update Summary" +msgstr "更新摘要" + +#. TRANSLATORS: section header for firmware version +msgid "Update Version" +msgstr "更新版本" + +#. TRANSLATORS: the server sent the user a small message +msgid "Update failure is a known issue, visit this URL for more information:" +msgstr "更新失敗是已知議題,請造訪此 URL 瞭解更多資訊:" + +#. TRANSLATORS: ask the user if we can update the metadata +msgid "Update now?" +msgstr "是否立刻更更新?" + +msgid "Update the stored device verification information" +msgstr "更新儲存的裝置核驗資訊" #. TRANSLATORS: command description -#: src/fu-util.c:2280 msgid "Update the stored metadata with current ROM contents" msgstr "以目前 ROM 內容更新儲存的中介資料" #. TRANSLATORS: command description -#: src/fu-util.c:2286 -msgid "Monitor the daemon for events" -msgstr "監控幕後程式是否有活動" +msgid "Updates all firmware to latest versions available" +msgstr "將所有韌體更新至可用的最新版本" + +#. TRANSLATORS: the first replacement is a display name +#. * e.g. "ColorHugALS" and the second and third are +#. * version numbers e.g. "1.2.3" +#, c-format +msgid "Updating %s from %s to %s... " +msgstr "正將 %s 從 %s 版升級至 %s 版... " + +#. TRANSLATORS: the server sent the user a small message +msgid "Upload message:" +msgstr "上傳訊息:" + +#. TRANSLATORS: ask the user to upload +msgid "Upload report now?" +msgstr "是否立刻上傳報告?" + +#. TRANSLATORS: explain why we want to upload +msgid "Uploading firmware reports helps hardware vendors to quickly identify failing and successful updates on real devices." +msgstr "上傳韌體報告可以協助硬體廠商快速辨識出更新作業在真實裝置上是失敗還成功。" + +#. TRANSLATORS: remote filename base +msgid "Username" +msgstr "使用者名稱" + +#. TRANSLATORS: verifying we wrote the firmware correctly +msgid "Verifying…" +msgstr "核驗中…" + +#. TRANSLATORS: section header for release version number +msgid "Version" +msgstr "版本" + +#. TRANSLATORS: waiting for device to do something +msgid "Waiting…" +msgstr "等候中…" #. TRANSLATORS: command description -#: src/fu-util.c:2292 -msgid "Build firmware using a sandbox" -msgstr "使用沙箱建置韌體" +msgid "Watch DFU devices being hotplugged" +msgstr "監看 DFU 裝置熱插拔的過程" #. TRANSLATORS: command description -#: src/fu-util.c:2298 -msgid "Dump SMBIOS data from a file" -msgstr "從檔案傾印 SMBIOUS 資料" +msgid "Watch for hardware changes" +msgstr "監看硬體是否有變更" #. TRANSLATORS: command description -#: src/fu-util.c:2304 -msgid "Modifies a given remote" -msgstr "修改指定的遠端" +msgid "Write firmware from file into device" +msgstr "從檔案將韌體寫入裝置" -#. TRANSLATORS: program name -#: src/fu-util.c:2334 -msgid "Firmware Utility" -msgstr "韌體公用程式" +#. TRANSLATORS: command description +msgid "Write firmware from file into one partition" +msgstr "從檔案將韌體寫入一分割區" + +#. TRANSLATORS: writing to the flash chips +msgid "Writing…" +msgstr "寫入中…" + +#. TRANSLATORS: show the user a warning +msgid "Your distributor may not have verified any of the firmware updates for compatibility with your system or connected devices." +msgstr "您的系統散布商可能尚未驗證過任何韌體更新與您系統間或連接裝置上的相容性。" diff -Nru fwupd-1.0.6/policy/meson.build fwupd-1.2.10/policy/meson.build --- fwupd-1.0.6/policy/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/policy/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,43 +1,25 @@ install_data('org.freedesktop.fwupd.rules', install_dir : join_paths(datadir, 'polkit-1', 'rules.d')) -#meson 0.41.0 added support for data_dirs argument -if meson.version().version_compare('>=0.41.0') - #newer polkit has the ITS rules included - if polkit.version().version_compare('>0.113') - i18n.merge_file( - input: 'org.freedesktop.fwupd.policy.in', - output: 'org.freedesktop.fwupd.policy', - install: true, - install_dir: join_paths(datadir, 'polkit-1', 'actions') , - type: 'xml', - po_dir: join_paths(meson.source_root(), 'po') - ) - #older polkit is missing ITS rules and will fail - else - i18n.merge_file( - input: 'org.freedesktop.fwupd.policy.in', - output: 'org.freedesktop.fwupd.policy', - install: true, - install_dir: join_paths(datadir, 'polkit-1', 'actions') , - type: 'xml', - data_dirs: join_paths(meson.source_root(), 'policy'), - po_dir: join_paths(meson.source_root(), 'po') - ) - endif -#older polkit and older meson, need to do some custom targets -#see https://github.com/hughsie/fwupd/issues/107 +#newer polkit has the ITS rules included +if polkit.version().version_compare('>0.113') + i18n.merge_file( + input: 'org.freedesktop.fwupd.policy.in', + output: 'org.freedesktop.fwupd.policy', + install: true, + install_dir: join_paths(datadir, 'polkit-1', 'actions') , + type: 'xml', + po_dir: join_paths(meson.source_root(), 'po') + ) +#older polkit is missing ITS rules and will fail else - envbin = find_program('env') - gettext_data_dir = 'GETTEXTDATADIRS=' + join_paths(meson.source_root(), 'policy') - custom_target('org.freedesktop.fwupd.policy', + i18n.merge_file( input: 'org.freedesktop.fwupd.policy.in', output: 'org.freedesktop.fwupd.policy', - command: [envbin, gettext_data_dir, 'msgfmt', '--xml', - '--template', '@INPUT@', - '-d', join_paths(meson.source_root(), 'po'), - '-o', '@OUTPUT@'], install: true, - install_dir: join_paths(datadir, 'polkit-1', 'actions') - ) + install_dir: join_paths(datadir, 'polkit-1', 'actions') , + type: 'xml', + data_dirs: join_paths(meson.source_root(), 'policy'), + po_dir: join_paths(meson.source_root(), 'po') + ) endif diff -Nru fwupd-1.0.6/policy/org.freedesktop.fwupd.policy.in fwupd-1.2.10/policy/org.freedesktop.fwupd.policy.in --- fwupd-1.0.6/policy/org.freedesktop.fwupd.policy.in 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/policy/org.freedesktop.fwupd.policy.in 2019-07-15 18:25:54.000000000 +0000 @@ -90,6 +90,28 @@ + + Modify daemon configuration + + Authentication is required to modify daemon configuration + + auth_admin + no + auth_admin_keep + + + + + Activate the new firmware on the device + + Authentication is required to switch to the new firmware version + + auth_admin + no + auth_admin_keep + + + Update the stored device verification information @@ -108,6 +130,28 @@ auth_admin no + auth_admin_keep + + + + + Sets the list of approved firmware + + Authentication is required to set the list of approved firmware + + auth_admin + no + auth_admin_keep + + + + + Sign data using the client certificate + + Authentication is required to sign data using the client certificate + + auth_admin + no auth_admin_keep diff -Nru fwupd-1.0.6/README.md fwupd-1.2.10/README.md --- fwupd-1.0.6/README.md 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -3,6 +3,8 @@ [![Build Status](https://travis-ci.org/hughsie/fwupd.png?branch=master)](https://travis-ci.org/hughsie/fwupd) [![Coverity Scan Build Status](https://scan.coverity.com/projects/10744/badge.svg)](https://scan.coverity.com/projects/10744) +[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/fwupd) + This project aims to make updating firmware on Linux automatic, safe and reliable. Additional information is available at the website: https://fwupd.org @@ -70,17 +72,44 @@ Only updates that were distributed from the LVFS will be reported to the LVFS. +Enterprise Use +-------------- + +The flow of updates can be controlled in the enterprise using the +"approved updates" feature. This allows the domain administrator to filter +the possible updates from a central server (e.g. the LVFS, or a mirror) +to only firmware that have been tested specifically in your organisation. + +The list of approved updates can be enabled by adding `ApprovalRequired=true` +to the remote configuration file, e.g. `lvfs.conf`. Once enabled, the +list of approved updates can be set in `daemon.conf` using a comma delimited list. + +For example: + + ApprovedFirmware=foo,bar + +Where `foo,bar` refers to the container checksums that would correspond +to two updates in the metadata file. + +Additionally, the list of approved firmware can be supplemented using +`fwupdmgr set-approved-firmware baz` or using the D-Bus interface. + Other frontends ------------------- -Currently [GNOME Software](https://wiki.gnome.org/Apps/Software) is the only graphical -frontend available. When compiled with firmware support, it will check for updates -periodically and automatically download firmware in the background. - -After the firmware has been downloaded a popup will be displayed in Gnome Software -to perform the update. - -On Dell IoT gateways, [Wyse Cloud Client Manager (CCM)](http://www.dell.com/us/business/p/wyse-cloud-client-manager/pd) -has been built with fwupd support. -The remote administration interface can be used to download and deploy -firmware updates. + 1. [GNOME Software](https://wiki.gnome.org/Apps/Software) is the graphical + frontend available. When compiled with firmware support, it will check for + updates periodically and automatically download firmware in the background. + After the firmware has been downloaded a popup will be displayed in Gnome + Software to perform the update. + +2. [KDE Discover](https://userbase.kde.org/Discover) is the software centre, + generally bundled with KDE Plasma. With the release of + [KDE Plasma 5.14](https://www.kde.org/announcements/plasma-5.14.0.php), + a new fwupd backend has been implemented in KDE Discover for firmware updates. + These firmware updates are shown with other system updates. + +3. [Wyse Management Suite](https://www.dell.com/en-us/work/shop/wyse-endpoints-and-software/wyse-management-suite/spd/wyse-wms) + A software suite available on Dell IoT gateways and Wyse thin clients with built-in fwupd support. + The remote administration interface can be used to download and deploy firmware + updates. diff -Nru fwupd-1.0.6/RELEASE fwupd-1.2.10/RELEASE --- fwupd-1.0.6/RELEASE 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/RELEASE 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,23 @@ fwupd Release Notes -1. Write NEWS entries for fwupd in the same format as usual. +Write release entries: -git shortlog 1.0.5.. | grep -i -v trivial | grep -v Merge > NEWS.new - -Version 1.0.6 -~~~~~~~~~~~~~ -Released: 2018-xx-xx - -New Features: -Bugfixes: +git log --format="%s" --cherry-pick --right-only 1.2.9... | grep -i -v trivial | grep -v Merge | sort | uniq +Add any user visible changes into ../data/org.freedesktop.fwupd.metainfo.xml +appstream-util appdata-to-news ../data/org.freedesktop.fwupd.metainfo.xml > NEWS Update translations: ninja-build fwupd-pot tx push --source -tx pull --all --minimum-perc=5 +tx pull --all --force --minimum-perc=5 +ninja-build fix-translations git add ../po/*.po 2. Commit changes to git: -# MAKE SURE THESE ARE CORRECT -export release_ver="1.0.6" +# MAKE SURE THIS IS CORRECT +export release_ver="1.2.10" git commit -a -m "Release fwupd ${release_ver}" git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}" @@ -33,7 +29,7 @@ ninja dist -3a. Generate the additon verification metadata +3a. Generate the additional verification metadata gpg -b -a meson-dist/fwupd-${release_ver}.tar.xz diff -Nru fwupd-1.0.6/SECURITY.md fwupd-1.2.10/SECURITY.md --- fwupd-1.0.6/SECURITY.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/SECURITY.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,34 @@ +# Security Policy + +Due to the nature of what we are doing, fwupd takes security very seriously. +If you have any concerns please let us know. + +## Supported Versions + +The `1.2.x` and `1.1.x` branches are fully supported by the upstream authors. +Additonally, the `1.0.x` branch is supported for security and bug fixes. + +Older releases than this are unsupported by upstream but may be supported by +your distributor or distribution. If you open an issue with one of these older +releases the very first question from us is going to be asking if it's fixed on +a supported branch. You can use the flatpak or snap packages if your distributor +is unwilling to update to a supported version. + +| Version | Supported | +| ------- | ------------------ | +| 1.2.x | :heavy_check_mark: | +| 1.1.x | :heavy_check_mark: | +| 1.0.x | :white_check_mark: | +| 0.9.x | :x: | +| 0.8.x | :x: | + +## Reporting a Vulnerability + +If you find a vulnerability in fwupd your first thing you should do is email +all the maintainers, which are currently listed in the `MAINTAINERS` file in +this repository. + +Failing that, please report the issue against the `fwupd` component in Red Hat +bugzilla, with the security checkbox set. You should get a response within 3 +days. We have no bug bountry program, but we're happy to credit you in updates +if this is what you would like us to do. diff -Nru fwupd-1.0.6/snap/hooks/install fwupd-1.2.10/snap/hooks/install --- fwupd-1.0.6/snap/hooks/install 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/snap/hooks/install 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,21 @@ +#!/bin/sh -e + +install_if_missing() { + if [ "$2" != "/" ]; then + mkdir -p $(dirname ${2}/${1}) + fi + install -m 644 -C ${SNAP}/${1} ${2}/${1} +} + +#install policykit rules and actions +install_if_missing share/polkit-1/actions/org.freedesktop.fwupd.policy /usr +install_if_missing share/polkit-1/rules.d/org.freedesktop.fwupd.rules /usr +#install dbus related items +install_if_missing share/dbus-1/system-services/org.freedesktop.fwupd.service /usr +install_if_missing share/dbus-1/interfaces/org.freedesktop.fwupd.xml /usr +install_if_missing etc/dbus-1/system.d/org.freedesktop.fwupd.conf / +#activation via systemd +install_if_missing etc/systemd/system/fwupd-activate.service / +systemctl daemon-reload +systemctl enable fwupd-activate +systemctl start fwupd-activate diff -Nru fwupd-1.0.6/snap/hooks/remove fwupd-1.2.10/snap/hooks/remove --- fwupd-1.0.6/snap/hooks/remove 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/snap/hooks/remove 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,7 @@ +#!/bin/sh -e + +#activation via systemd +systemctl stop fwupd-activate +systemctl disable fwupd-activate +rm /etc/systemd/system/fwupd-activate.service -f +systemctl daemon-reload diff -Nru fwupd-1.0.6/snap/snapcraft.yaml fwupd-1.2.10/snap/snapcraft.yaml --- fwupd-1.0.6/snap/snapcraft.yaml 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/snap/snapcraft.yaml 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,360 @@ +name: fwupd +version-script: cat $SNAPCRAFT_STAGE/version +version: 'daily' +summary: A standalone version of fwupd to install newer firmware updates +description: | + This is a tool that can be used to install firmware updates on devices + not yet supported by the version of fwupd distributed with the OS. + +grade: stable +confinement: classic + +architectures: + - amd64 + +apps: + dfu-tool: + command: dfu-tool.wrapper + fwupdtool: + command: fwupdtool.wrapper + completer: + share/bash-completion/completions/fwupdtool + fwupd: + command: fwupd.wrapper + daemon: simple + fwupdmgr: + command: fwupdmgr.wrapper + completer: + share/bash-completion/completions/fwupdmgr + +parts: + libefivar-dev: + plugin: make + make-parameters: + - prefix=/ + - libdir=/lib + source: https://github.com/rhboot/efivar/releases/download/37/efivar-37.tar.bz2 + build-packages: + - libpopt-dev + prime: + - -include + - -bin + - -share/man + - -lib/pkgconfig + #adjust the paths from libefivar + libefivar-fixpkgconfig: + plugin: make + source: contrib/snap/libefivar-fixpkgconfig + make-parameters: + - SNAPCRAFT_STAGE=$SNAPCRAFT_STAGE + after: [libefivar-dev] + libsmbios: + plugin: autotools + source: https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz + build-packages: + - libxml2-dev + - pkg-config + - autoconf + - automake + - libtool + - autopoint + prime: + - -include/ + - -lib/pkgconfig + - -lib/python3.5 + - -sbin/ + - -share/ + - -etc/ + - -lib/*.a + meson: + plugin: python + source: https://github.com/mesonbuild/meson/releases/download/0.47.2/meson-0.47.2.tar.gz + build-packages: + - ninja-build + prime: + - -bin + - -etc + - -lib + - -share + - -usr + gudev: + plugin: autotools + source: https://github.com/GNOME/libgudev/archive/232.tar.gz + configflags: + - --disable-umockdev + build-packages: + - libglib2.0-dev + - pkg-config + - libudev-dev + - gtk-doc-tools + - gnome-common + prime: + - -include + - -lib/girepository-1.0 + - -lib/pkgconfig + - -share/ + # this is for the library only, we don't care about the daemon "in-snap" + modemmanager: + plugin: autotools + source: https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git + source-tag: 1.10.0 + after: [gudev, gettext] + # build without these; system daemon needs them + configflags: + - --without-mbim + - --without-qmi + prime: + - -include + - -etc + - -sbin + - -bin + - -share + - -lib/*.*a + - -lib/pkgconfig + - -lib/ModemManager + - -lib/systemd + - -lib/udev + - -lib/girepository-1.0 + libmbim: + plugin: autotools + source: https://gitlab.freedesktop.org/mobile-broadband/libmbim.git + source-tag: 1.18.0 + after: [gudev, gettext, modemmanager] + # build without these; system daemon needs them + configflags: + - --without-udev + prime: + - -include + - -etc + - -sbin + - -bin + - -share + - -lib/*.*a + - -lib/pkgconfig + - -lib/ModemManager + - -lib/systemd + - -lib/udev + - -lib/girepository-1.0 + libqmi: + plugin: autotools + source: https://gitlab.freedesktop.org/mobile-broadband/libqmi.git + source-tag: 1.23.1 + after: [gudev, gettext, modemmanager, libmbim] + # build without these; system daemon needs them + configflags: + - --without-udev + prime: + - -include + - -etc + - -sbin + - -bin + - -share + - -lib/*.*a + - -lib/pkgconfig + - -lib/ModemManager + - -lib/systemd + - -lib/udev + - -lib/girepository-1.0 + libusb: + plugin: autotools + source: https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2 + configflags: + - --disable-static + prime: + - -include/ + - -lib/pkgconfig + gusb: + plugin: meson + source: https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz + meson-parameters: [--prefix=/, + -Dtests=false, + -Dvapi=false, + -Ddocs=false] + build-packages: + - libgirepository1.0-dev + prime: + - -bin/ + - -include + - -share + - -lib/*/pkgconfig + - -lib/*/girepository-1.0 + after: [meson, libusb] + gnu-efi: + plugin: make + source: http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.5.tar.bz2 + make-parameters: + - PREFIX=/usr + make-install-var: INSTALLROOT + prime: + - -usr/include/ + - -usr/lib + #fetch the latest version of the signed bootloader + #this might not match our fwupdx64.efi, but it's better than nothing + fwup-efi-signed: + build-packages: + - python3-apt + plugin: make + source: contrib/snap/fwup-efi-signed + #needed for UEFI plugin to build UX labels + build-introspection: + plugin: nil + stage-packages: + - python3-gi + - python3-gi-cairo + - python3-pil + prime: + - -etc + - -usr + - -lib + - -var + #0.19.8.1 adds support for GETTEXTDATADIRS which is needed by meson's msgfmthelper + gettext: + source: https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.xz + plugin: autotools + build-packages: + - bison + - libunistring-dev + - libxml2-dev + configflags: + - --prefix=/usr + - --disable-static + - --disable-curses + - --disable-java + - --enable-relocatable + - --without-emacs + - --without-included-glib + - --without-included-libunistring + - --without-included-libxml + stage-packages: + - libunistring0 + - libxml2 + - libgomp1 + prime: + - -**/*.a + - -**/*.la + - -usr/bin + - -usr/include + - -usr/lib/gettext + - -usr/share + fwupd: + plugin: meson + meson-parameters: [--prefix=/, + -Defi-includedir=$SNAPCRAFT_STAGE/usr/include/efi, + -Defi-ldsdir=$SNAPCRAFT_STAGE/usr/lib, + -Defi-libdir=$SNAPCRAFT_STAGE/usr/lib, + -Dtests=false, + -Ddaemon=true, + -Dgtkdoc=false, + -Dintrospection=false, + -Dman=false, + -Dplugin_modem_manager=true, + -Dudevdir=$SNAPCRAFT_STAGE/lib/udev, + "-Dlibxmlb:gtkdoc=false", + "-Dlibxmlb:introspection=false", + -Dpkcs7=false] + source: . + source-type: git + override-build: | + snapcraftctl build + echo $(git describe HEAD --always) > $SNAPCRAFT_STAGE/version + build-packages: + - bash-completion + - gcab + - gnutls-dev + - libarchive-dev + - libcairo-dev + - libelf-dev + - libftdi1-dev + - libgcab-dev + - libglib2.0-dev + - libgpgme11-dev + - libjson-glib-dev + - libpango1.0-dev + - libpci-dev + - libpolkit-gobject-1-dev + - libsoup2.4-dev + - libsqlite3-dev + - locales + - pkg-config + - uuid-dev + stage-packages: + - libgcab-1.0-0 + - libarchive13 + - libassuan0 + - liblcms2-2 + - libelf1 + - libgpgme11 + - libjson-glib-1.0-0 + - libpolkit-gobject-1-0 + - libsoup2.4-1 + - glib-networking + - libglib2.0-bin + prime: + # we explicitly don't want /usr/bin/gpgconf + # this will cause gpgme to error finding it + # but that also avoids trying to use non-existent + # /usr/bin/gpg2 + - -usr/bin + - -usr/sbin + - -usr/share/man + - -usr/share/GConf + - -etc/X11 + - -etc/ldap + - -etc/logcheck + - -usr/lib/dconf + - -usr/lib/gcc + - -usr/lib/glib-networking + - -usr/lib/gnupg2 + - -usr/lib/sasl2 + - -usr/lib/systemd + - -usr/lib/*/audit + - -usr/share/glib-2.0/schemas + - -usr/share/X11 + - -include + - -lib/udev + - -lib/*/pkgconfig + - -usr/share/lintian + - -usr/share/pkgconfig + - -usr/share/installed-tests + - -usr/share/polkit-1 + - -usr/share/vala + - -usr/share/doc + - -usr/share/gnupg2 + - -usr/share/info + - -usr/share/gir-1.0 + - -usr/share/upstart + - -usr/lib/*/pkgconfig + after: [gudev, gusb, gnu-efi, libefivar-fixpkgconfig, libsmbios, build-introspection, gettext, modemmanager, libmbim, libqmi] + fix-bash-completion: + plugin: make + source: contrib/snap/fix-bash-completion + after: [fwupd] + activate-shutdown: + plugin: make + source: contrib/snap/activate-shutdown + after: [fwupd] + update-mime: + plugin: make + source: contrib/snap/update-mime + stage-packages: + - shared-mime-info + - gsettings-desktop-schemas + - libxml2 + prime: + - -usr/bin + - -usr/share/doc + - -usr/share/doc-base + - -usr/share/man + - -usr/share/lintian + - -usr/share/pkgconfig + - -usr/share/GConf + after: [fwupd] + fwupd-wrappers: + plugin: dump + source: contrib/snap + stage: + - dfu-tool.wrapper + - fwupd-command + - fwupdtool.wrapper + - fwupd.wrapper + - fwupdmgr.wrapper diff -Nru fwupd-1.0.6/src/fu-agent.c fwupd-1.2.10/src/fu-agent.c --- fwupd-1.0.6/src/fu-agent.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-agent.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuAgent" + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fu-common.h" +#include "fu-util-common.h" +#include "fwupd-device-private.h" +#include "fwupd-enums-private.h" + +struct FuUtilPrivate { + GCancellable *cancellable; + GMainLoop *loop; + GOptionContext *context; + FwupdClient *client; +}; + +static gboolean +fu_util_add_devices_json (FuUtilPrivate *priv, JsonBuilder *builder, GError **error) +{ + g_autoptr(GPtrArray) devs = NULL; + + /* get results from daemon */ + devs = fwupd_client_get_devices (priv->client, priv->cancellable, error); + if (devs == NULL) + return FALSE; + + json_builder_set_member_name (builder, "Devices"); + json_builder_begin_array (builder); + for (guint i = 0; i < devs->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devs, i); + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + /* add all releases that could be applied */ + rels = fwupd_client_get_releases (priv->client, + fwupd_device_get_id (dev), + priv->cancellable, + &error_local); + if (rels == NULL) { + g_debug ("not adding releases to device: %s", + error_local->message); + } else { + for (guint j = 0; j < rels->len; j++) { + FwupdRelease *rel = g_ptr_array_index (rels, j); + fwupd_device_add_release (dev, rel); + } + } + + /* add to builder */ + json_builder_begin_object (builder); + fwupd_device_to_json (dev, builder); + json_builder_end_object (builder); + } + json_builder_end_array (builder); + return TRUE; +} + +static gboolean +fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *data = NULL; + g_autoptr(JsonBuilder) builder = NULL; + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; + + /* check args */ + if (g_strv_length (values) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* create header */ + builder = json_builder_new (); + json_builder_begin_object (builder); + if (!fu_util_add_devices_json (priv, builder, error)) + return FALSE; + json_builder_end_object (builder); + + /* export as a string */ + json_root = json_builder_get_root (builder); + json_generator = json_generator_new (); + json_generator_set_pretty (json_generator, TRUE); + json_generator_set_root (json_generator, json_root); + data = json_generator_to_data (json_generator, NULL); + if (data == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Failed to convert to JSON string"); + return FALSE; + } + + /* just print */ + g_print ("%s\n", data); + return TRUE; +} + +static void +fu_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ +} + +static gboolean +fu_util_sigint_cb (gpointer user_data) +{ + FuUtilPrivate *priv = (FuUtilPrivate *) user_data; + g_debug ("Handling SIGINT"); + g_cancellable_cancel (priv->cancellable); + return FALSE; +} + +static void +fu_util_private_free (FuUtilPrivate *priv) +{ + if (priv->client != NULL) + g_object_unref (priv->client); + g_main_loop_unref (priv->loop); + g_object_unref (priv->cancellable); + g_option_context_free (priv->context); + g_free (priv); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop + +int +main (int argc, char *argv[]) +{ + gboolean ret; + gboolean verbose = FALSE; + g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) cmd_array = fu_util_cmd_array_new (); + g_autofree gchar *cmd_descriptions = NULL; + const GOptionEntry options[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + /* TRANSLATORS: command line option */ + _("Show extra debugging information"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* ensure D-Bus errors are registered */ + fwupd_error_quark (); + + /* create helper object */ + priv->loop = g_main_loop_new (NULL, FALSE); + priv->client = fwupd_client_new (); + + /* add commands */ + fu_util_cmd_array_add (cmd_array, + "get-devices", NULL, + /* TRANSLATORS: command description */ + _("Get all devices and possible releases"), + fu_util_get_devices); + + /* sort by command name */ + fu_util_cmd_array_sort (cmd_array); + + /* do stuff on ctrl+c */ + priv->cancellable = g_cancellable_new (); + g_unix_signal_add_full (G_PRIORITY_DEFAULT, + SIGINT, fu_util_sigint_cb, + priv, NULL); + + /* get a list of the commands */ + priv->context = g_option_context_new (NULL); + cmd_descriptions = fu_util_cmd_array_to_string (cmd_array); + g_option_context_set_summary (priv->context, cmd_descriptions); + g_option_context_set_description (priv->context, + "This tool can be used from other tools and from shell scripts."); + + /* TRANSLATORS: program name */ + g_set_application_name (_("Firmware Agent")); + g_option_context_add_main_entries (priv->context, options, NULL); + ret = g_option_context_parse (priv->context, &argc, &argv, &error); + if (!ret) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), + error->message); + return EXIT_FAILURE; + } + + /* set verbose? */ + if (verbose) { + g_setenv ("G_MESSAGES_DEBUG", "all", FALSE); + } else { + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, + fu_util_ignore_cb, NULL); + } + + /* run the specified command */ + ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); + if (!ret) { + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) { + g_autofree gchar *tmp = NULL; + tmp = g_option_context_get_help (priv->context, TRUE, NULL); + g_print ("%s\n\n%s", error->message, tmp); + return EXIT_FAILURE; + } + g_print ("%s\n", error->message); + return EXIT_FAILURE; + } + + /* success */ + return EXIT_SUCCESS; +} diff -Nru fwupd-1.0.6/src/fu-archive.c fwupd-1.2.10/src/fu-archive.c --- fwupd-1.0.6/src/fu-archive.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-archive.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuArchive" + +#include "config.h" + +#include +#include +#include + +#include "fu-archive.h" + +/** + * SECTION:fu-archive + * @title: FuArchive + * @short_description: an in-memory archive decompressor + */ + +struct _FuArchive { + GObject parent_instance; + GHashTable *entries; +}; + +G_DEFINE_TYPE (FuArchive, fu_archive, G_TYPE_OBJECT) + +static void +fu_archive_finalize (GObject *obj) +{ + FuArchive *self = FU_ARCHIVE (obj); + + g_hash_table_unref (self->entries); + G_OBJECT_CLASS (fu_archive_parent_class)->finalize (obj); +} + +static void +fu_archive_class_init (FuArchiveClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_archive_finalize; +} + +static void +fu_archive_init (FuArchive *self) +{ + self->entries = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_bytes_unref); +} + +/** + * fu_archive_lookup_by_fn: + * @self: A #FuArchive + * @fn: A filename + * @error: A #GError, or %NULL + * + * Finds the blob referenced by filename + * + * Returns: (transfer none): a #GBytes, or %NULL if the filename was not found + **/ +GBytes * +fu_archive_lookup_by_fn (FuArchive *self, const gchar *fn, GError **error) +{ + GBytes *fw; + + g_return_val_if_fail (FU_IS_ARCHIVE (self), NULL); + g_return_val_if_fail (fn != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + fw = g_hash_table_lookup (self->entries, fn); + if (fw == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no blob for %s", fn); + } + return fw; +} + +/** + * fu_archive_iterate: + * @self: A #FuArchive + * @callback: A #FuArchiveIterateFunc. + * @user_data: User data. + * + * Iterates over the archive contents, calling the given function for each + * of the files found. + */ +void +fu_archive_iterate (FuArchive *self, FuArchiveIterateFunc callback, gpointer user_data) +{ + GHashTableIter iter; + gpointer key, value; + + g_return_if_fail (FU_IS_ARCHIVE (self)); + g_return_if_fail (callback != NULL); + + g_hash_table_iter_init (&iter, self->entries); + while (g_hash_table_iter_next (&iter, &key, &value)) + callback (self, (const gchar *)key, (GBytes *)value, user_data); +} + +/* workaround the struct types of libarchive */ +typedef struct archive _archive_read_ctx; + +static void +_archive_read_ctx_free (_archive_read_ctx *arch) +{ + archive_read_close (arch); + archive_read_free (arch); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_read_ctx, _archive_read_ctx_free) + +static gboolean +fu_archive_load (FuArchive *self, GBytes *blob, FuArchiveFlags flags, GError **error) +{ + int r; + g_autoptr(_archive_read_ctx) arch = NULL; + + /* decompress anything matching either glob */ + arch = archive_read_new (); + if (arch == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "libarchive startup failed"); + return FALSE; + } + archive_read_support_format_all (arch); + archive_read_support_filter_all (arch); + r = archive_read_open_memory (arch, + (void *) g_bytes_get_data (blob, NULL), + (size_t) g_bytes_get_size (blob)); + if (r != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot open: %s", + archive_error_string (arch)); + return FALSE; + } + while (TRUE) { + const gchar *fn; + gint64 bufsz; + gssize rc; + struct archive_entry *entry; + g_autofree gchar *fn_key = NULL; + g_autofree guint8 *buf = NULL; + + r = archive_read_next_header (arch, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read header: %s", + archive_error_string (arch)); + return FALSE; + } + + /* only extract if valid */ + fn = archive_entry_pathname (entry); + if (fn == NULL) + continue; + bufsz = archive_entry_size (entry); + if (bufsz > 1024 * 1024 * 1024) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read huge files"); + return FALSE; + } + buf = g_malloc (bufsz); + rc = archive_read_data (arch, buf, (gsize) bufsz); + if (rc < 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot read data: %s", + archive_error_string (arch)); + return FALSE; + } + if (rc != bufsz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "read %" G_GSSIZE_FORMAT " of %" G_GINT64_FORMAT, + rc, bufsz); + return FALSE; + } + if (flags & FU_ARCHIVE_FLAG_IGNORE_PATH) { + fn_key = g_path_get_basename (fn); + } else { + fn_key = g_strdup (fn); + } + g_debug ("adding %s [%" G_GINT64_FORMAT "]", fn_key, bufsz); + g_hash_table_insert (self->entries, + g_steal_pointer (&fn_key), + g_bytes_new_take (g_steal_pointer (&buf), bufsz)); + } + + /* success */ + return TRUE; +} + +/** + * fu_archive_new: + * @data: A #GBytes + * @flags: A #FuArchiveFlags, e.g. %FU_ARCHIVE_FLAG_NONE + * @error: A #GError, or %NULL + * + * Parses @data as an archive and decompresses all files to memory blobs. + * + * Returns: a #FuArchive, or %NULL if the archive was invalid in any way. + **/ +FuArchive * +fu_archive_new (GBytes *data, FuArchiveFlags flags, GError **error) +{ + g_autoptr(FuArchive) self = g_object_new (FU_TYPE_ARCHIVE, NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (!fu_archive_load (self, data, flags, error)) + return NULL; + return g_steal_pointer (&self); +} diff -Nru fwupd-1.0.6/src/fu-archive.h fwupd-1.2.10/src/fu-archive.h --- fwupd-1.0.6/src/fu-archive.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-archive.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_ARCHIVE (fu_archive_get_type ()) + +G_DECLARE_FINAL_TYPE (FuArchive, fu_archive, FU, ARCHIVE, GObject) + +/** + * FuArchiveFlags: + * @FU_ARCHIVE_FLAG_NONE: No flags set + * @FU_ARCHIVE_FLAG_IGNORE_PATH: Ignore any path component + * + * The flags to use when loading the archive. + **/ +typedef enum { + FU_ARCHIVE_FLAG_NONE = 0, + FU_ARCHIVE_FLAG_IGNORE_PATH = 1 << 0, + /*< private >*/ + FU_ARCHIVE_FLAG_LAST +} FuArchiveFlags; + +/** + * FuArchiveIterateFunc: + * @self: A #FuArchive. + * @filename: A filename. + * @bytes: The blob referenced by @filename. + * @user_data: User data. + * + * Specifies the type of archive iteration function. + */ +typedef void (*FuArchiveIterateFunc) (FuArchive *self, + const gchar *filename, + GBytes *bytes, + gpointer user_data); + +FuArchive *fu_archive_new (GBytes *data, + FuArchiveFlags flags, + GError **error); +GBytes *fu_archive_lookup_by_fn (FuArchive *self, + const gchar *fn, + GError **error); +void fu_archive_iterate (FuArchive *self, + FuArchiveIterateFunc callback, + gpointer user_data); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-chunk.c fwupd-1.2.10/src/fu-chunk.c --- fwupd-1.0.6/src/fu-chunk.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-chunk.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuChunk" + +#include "config.h" + +#include + +#include "fu-chunk.h" + +/** + * fu_chunk_new: + * @idx: the packet number + * @page: the hardware memory page + * @address: the address *within* the page + * @data: the data + * @data_sz: size of @data_sz + * + * Creates a new packet of chunked data. + * + * Return value: (transfer full): a #FuChunk + **/ +FuChunk * +fu_chunk_new (guint32 idx, + guint32 page, + guint32 address, + const guint8 *data, + guint32 data_sz) +{ + FuChunk *item = g_new0 (FuChunk, 1); + item->idx = idx; + item->page = page; + item->address = address; + item->data = data; + item->data_sz = data_sz; + return item; +} + +/** + * fu_chunk_to_string: + * @item: a #FuChunk + * + * Converts the chunked packet to a string representation. + * + * Return value: (transfer full): A string + **/ +gchar * +fu_chunk_to_string (FuChunk *item) +{ + g_autoptr(GString) str = g_string_new (NULL); + if (item->data != NULL) { + for (guint32 i = 0; i < item->data_sz; i++) { + gchar tmp = (gchar) item->data[i]; + if (tmp == 0x00) + break; + g_string_append_c (str, g_ascii_isalnum (tmp) ? tmp : '?'); + } + } + return g_strdup_printf ("#%02" G_GUINT32_FORMAT ": page:%02x " + "addr:%04x len:%02" G_GUINT32_FORMAT " %s", + item->idx, + (guint) item->page, + (guint) item->address, + item->data_sz, + str->str); +} + +/** + * fu_chunk_array_to_string: + * @chunks: (element-type FuChunk): array of packets + * + * Converts all the chunked packets in an array to a string representation. + * + * Return value: (transfer full): A string + **/ +gchar * +fu_chunk_array_to_string (GPtrArray *chunks) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; i < chunks->len; i++) { + FuChunk *item = g_ptr_array_index (chunks, i); + g_autofree gchar *tmp = fu_chunk_to_string (item); + g_string_append_printf (str, "%s\n", tmp); + } + return g_string_free (str, FALSE); +} + +/** + * fu_chunk_array_new: + * @data: a linear blob of memory, or %NULL + * @data_sz: size of @data_sz + * @addr_start: the hardware address offset, or 0 + * @page_sz: the hardware page size, or 0 + * @packet_sz: the transfer size, or 0 + * + * Chunks a linear blob of memory into packets, ensuring each packet does not + * cross a package boundary and is less that a specific transfer size. + * + * Return value: (element-type FuChunk): array of packets + **/ +GPtrArray * +fu_chunk_array_new (const guint8 *data, + guint32 data_sz, + guint32 addr_start, + guint32 page_sz, + guint32 packet_sz) +{ + GPtrArray *segments = NULL; + guint32 page_old = G_MAXUINT32; + guint32 idx; + guint32 last_flush = 0; + + g_return_val_if_fail (data_sz > 0, NULL); + + segments = g_ptr_array_new_with_free_func (g_free); + for (idx = 1; idx < data_sz; idx++) { + guint32 page = 0; + if (page_sz > 0) + page = (addr_start + idx) / page_sz; + if (page_old == G_MAXUINT32) { + page_old = page; + } else if (page != page_old) { + const guint8 *data_offset = data != NULL ? data + last_flush : 0x0; + guint32 address_offset = addr_start + last_flush; + if (page_sz > 0) + address_offset %= page_sz; + g_ptr_array_add (segments, + fu_chunk_new (segments->len, + page_old, + address_offset, + data_offset, + idx - last_flush)); + last_flush = idx; + page_old = page; + continue; + } + if (packet_sz > 0 && idx - last_flush >= packet_sz) { + const guint8 *data_offset = data != NULL ? data + last_flush : 0x0; + guint32 address_offset = addr_start + last_flush; + if (page_sz > 0) + address_offset %= page_sz; + g_ptr_array_add (segments, + fu_chunk_new (segments->len, + page, + address_offset, + data_offset, + idx - last_flush)); + last_flush = idx; + continue; + } + } + if (last_flush != idx) { + const guint8 *data_offset = data != NULL ? data + last_flush : 0x0; + guint32 address_offset = addr_start + last_flush; + guint32 page = 0; + if (page_sz > 0) { + address_offset %= page_sz; + page = (addr_start + (idx - 1)) / page_sz; + } + g_ptr_array_add (segments, + fu_chunk_new (segments->len, + page, + address_offset, + data_offset, + data_sz - last_flush)); + } + return segments; +} + +/** + * fu_chunk_array_new_from_bytes: + * @blob: a #GBytes + * @addr_start: the hardware address offset, or 0 + * @page_sz: the hardware page size, or 0 + * @packet_sz: the transfer size, or 0 + * + * Chunks a linear blob of memory into packets, ensuring each packet does not + * cross a package boundary and is less that a specific transfer size. + * + * Return value: (element-type FuChunk): array of packets + **/ +GPtrArray * +fu_chunk_array_new_from_bytes (GBytes *blob, + guint32 addr_start, + guint32 page_sz, + guint32 packet_sz) +{ + gsize sz; + const guint8 *data = g_bytes_get_data (blob, &sz); + return fu_chunk_array_new (data, (guint32) sz, + addr_start, page_sz, packet_sz); +} diff -Nru fwupd-1.0.6/src/fu-chunk.h fwupd-1.2.10/src/fu-chunk.h --- fwupd-1.0.6/src/fu-chunk.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-chunk.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +typedef struct { + guint32 idx; + guint32 page; + guint32 address; + const guint8 *data; + guint32 data_sz; +} FuChunk; + +FuChunk *fu_chunk_new (guint32 idx, + guint32 page, + guint32 address, + const guint8 *data, + guint32 data_sz); +gchar *fu_chunk_to_string (FuChunk *item); + +gchar *fu_chunk_array_to_string (GPtrArray *chunks); +GPtrArray *fu_chunk_array_new (const guint8 *data, + guint32 data_sz, + guint32 addr_start, + guint32 page_sz, + guint32 packet_sz); +GPtrArray *fu_chunk_array_new_from_bytes (GBytes *blob, + guint32 addr_start, + guint32 page_sz, + guint32 packet_sz); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-common.c fwupd-1.2.10/src/fu-common.c --- fwupd-1.0.6/src/fu-common.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuCommon" + #include #include @@ -27,7 +14,9 @@ #include #include #include +#include #include +#include #include "fwupd-error.h" @@ -117,7 +106,7 @@ /** * fu_common_get_files_recursive: - * @directory: a directory name + * @path: a directory name * @error: A #GError or %NULL * * Returns every file found under @directory, and any subdirectory. @@ -364,6 +353,47 @@ g_ptr_array_add (argv, g_strdup (split[i])); } +gchar * +fu_common_find_program_in_path (const gchar *basename, GError **error) +{ + gchar *fn = g_find_program_in_path (basename); + if (fn == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing executable %s in PATH", + basename); + return NULL; + } + return fn; +} + +static gboolean +fu_common_test_namespace_support (GError **error) +{ + /* test if CONFIG_USER_NS is valid */ + if (!g_file_test ("/proc/self/ns/user", G_FILE_TEST_IS_SYMLINK)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "missing CONFIG_USER_NS in kernel"); + return FALSE; + } + if (g_file_test ("/proc/sys/kernel/unprivileged_userns_clone", G_FILE_TEST_EXISTS)) { + g_autofree gchar *clone = NULL; + if (!g_file_get_contents ("/proc/sys/kernel/unprivileged_userns_clone", &clone, NULL, error)) + return FALSE; + if (g_ascii_strtoll (clone, NULL, 10) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "unprivileged user namespace clones disabled by distro"); + return FALSE; + } + } + return TRUE; +} + /** * fu_common_firmware_builder: * @bytes: The data to use @@ -390,6 +420,8 @@ { gint rc = 0; g_autofree gchar *argv_str = NULL; + g_autofree gchar *bwrap_fn = NULL; + g_autofree gchar *localstatebuilderdir = NULL; g_autofree gchar *localstatedir = NULL; g_autofree gchar *output2_fn = NULL; g_autofree gchar *standard_error = NULL; @@ -403,6 +435,15 @@ g_return_val_if_fail (output_fn != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* find bwrap in the path */ + bwrap_fn = fu_common_find_program_in_path ("bwrap", error); + if (bwrap_fn == NULL) + return NULL; + + /* test if CONFIG_USER_NS is valid */ + if (!fu_common_test_namespace_support (error)) + return NULL; + /* untar file to temp location */ tmpdir = g_dir_make_tmp ("fwupd-gen-XXXXXX", error); if (tmpdir == NULL) @@ -411,22 +452,23 @@ return NULL; /* this is shared with the plugins */ - localstatedir = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", "builder", NULL); + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + localstatebuilderdir = g_build_filename (localstatedir, "builder", NULL); /* launch bubblewrap and generate firmware */ - g_ptr_array_add (argv, g_strdup ("bwrap")); + g_ptr_array_add (argv, g_steal_pointer (&bwrap_fn)); fu_common_add_argv (argv, "--die-with-parent"); fu_common_add_argv (argv, "--ro-bind /usr /usr"); + fu_common_add_argv (argv, "--ro-bind /lib /lib"); + fu_common_add_argv (argv, "--ro-bind /lib64 /lib64"); + fu_common_add_argv (argv, "--ro-bind /bin /bin"); + fu_common_add_argv (argv, "--ro-bind /sbin /sbin"); fu_common_add_argv (argv, "--dir /tmp"); fu_common_add_argv (argv, "--dir /var"); fu_common_add_argv (argv, "--bind %s /tmp", tmpdir); - if (g_file_test (localstatedir, G_FILE_TEST_EXISTS)) - fu_common_add_argv (argv, "--ro-bind %s /boot", localstatedir); + if (g_file_test (localstatebuilderdir, G_FILE_TEST_EXISTS)) + fu_common_add_argv (argv, "--ro-bind %s /boot", localstatebuilderdir); fu_common_add_argv (argv, "--dev /dev"); - fu_common_add_argv (argv, "--symlink usr/lib /lib"); - fu_common_add_argv (argv, "--symlink usr/lib64 /lib64"); - fu_common_add_argv (argv, "--symlink usr/bin /bin"); - fu_common_add_argv (argv, "--symlink usr/sbin /sbin"); fu_common_add_argv (argv, "--chdir /tmp"); fu_common_add_argv (argv, "--unshare-all"); fu_common_add_argv (argv, "/tmp/%s", script_fn); @@ -448,9 +490,12 @@ if (standard_output != NULL && standard_output[0] != '\0') g_debug ("console output was: %s", standard_output); if (rc != 0) { + FwupdError code = FWUPD_ERROR_INTERNAL; + if (errno == ENOTTY) + code = FWUPD_ERROR_PERMISSION_DENIED; g_set_error (error, FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, + code, "failed to build firmware: %s", standard_error); return NULL; @@ -477,6 +522,7 @@ GSource *source; GInputStream *stream; GCancellable *cancellable; + guint timeout_id; } FuCommonSpawnHelper; static void fu_common_spawn_create_pollable_source (FuCommonSpawnHelper *helper); @@ -538,22 +584,46 @@ static void fu_common_spawn_helper_free (FuCommonSpawnHelper *helper) { + g_object_unref (helper->cancellable); if (helper->stream != NULL) g_object_unref (helper->stream); if (helper->source != NULL) g_source_destroy (helper->source); if (helper->loop != NULL) g_main_loop_unref (helper->loop); + if (helper->timeout_id != 0) + g_source_remove (helper->timeout_id); g_free (helper); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCommonSpawnHelper, fu_common_spawn_helper_free) +#pragma clang diagnostic pop + +static gboolean +fu_common_spawn_timeout_cb (gpointer user_data) +{ + FuCommonSpawnHelper *helper = (FuCommonSpawnHelper *) user_data; + g_cancellable_cancel (helper->cancellable); + g_main_loop_quit (helper->loop); + helper->timeout_id = 0; + return G_SOURCE_REMOVE; +} + +static void +fu_common_spawn_cancelled_cb (GCancellable *cancellable, FuCommonSpawnHelper *helper) +{ + /* just propagate */ + g_cancellable_cancel (helper->cancellable); +} /** * fu_common_spawn_sync: * @argv: The argument list to run * @handler_cb: (scope call): A #FuOutputHandler or %NULL * @handler_user_data: the user data to pass to @handler_cb + * @timeout_ms: a timeout in ms, or 0 for no limit * @cancellable: a #GCancellable, or %NULL * @error: A #GError or %NULL * @@ -566,11 +636,13 @@ fu_common_spawn_sync (const gchar * const * argv, FuOutputHandler handler_cb, gpointer handler_user_data, + guint timeout_ms, GCancellable *cancellable, GError **error) { g_autoptr(FuCommonSpawnHelper) helper = NULL; g_autoptr(GSubprocess) subprocess = NULL; g_autofree gchar *argv_str = NULL; + gulong cancellable_id = 0; /* create subprocess */ argv_str = g_strjoinv (" ", (gchar **) argv); @@ -586,9 +658,26 @@ helper->handler_user_data = handler_user_data; helper->loop = g_main_loop_new (NULL, FALSE); helper->stream = g_subprocess_get_stdout_pipe (subprocess); - helper->cancellable = cancellable; + + /* always create a cancellable, and connect up the parent */ + helper->cancellable = g_cancellable_new (); + if (cancellable != NULL) { + cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fu_common_spawn_cancelled_cb), + helper, NULL); + } + + /* allow timeout */ + if (timeout_ms > 0) { + helper->timeout_id = g_timeout_add (timeout_ms, + fu_common_spawn_timeout_cb, + helper); + } fu_common_spawn_create_pollable_source (helper); g_main_loop_run (helper->loop); + g_cancellable_disconnect (cancellable, cancellable_id); + if (g_cancellable_set_error_if_cancelled (helper->cancellable, error)) + return FALSE; return g_subprocess_wait_check (subprocess, cancellable, error); } @@ -596,7 +685,7 @@ * fu_common_write_uint16: * @buf: A writable buffer * @val_native: a value in host byte-order - * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * * Writes a value to a buffer using a specified endian. **/ @@ -621,7 +710,7 @@ * fu_common_write_uint32: * @buf: A writable buffer * @val_native: a value in host byte-order - * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * * Writes a value to a buffer using a specified endian. **/ @@ -645,7 +734,7 @@ /** * fu_common_read_uint16: * @buf: A readable buffer - * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * * Read a value from a buffer using a specified endian. * @@ -672,7 +761,7 @@ /** * fu_common_read_uint32: * @buf: A readable buffer - * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * * Read a value from a buffer using a specified endian. * @@ -695,3 +784,578 @@ } return val_native; } + +/** + * fu_common_strtoull: + * @str: A string, e.g. "0x1234" + * + * Converts a string value to an integer. Values are assumed base 10, unless + * prefixed with "0x" where they are parsed as base 16. + * + * Returns: integer value, or 0x0 for error + **/ +guint64 +fu_common_strtoull (const gchar *str) +{ + guint base = 10; + if (str == NULL) + return 0x0; + if (g_str_has_prefix (str, "0x")) { + str += 2; + base = 16; + } + return g_ascii_strtoull (str, NULL, base); +} + +/** + * fu_common_strstrip: + * @str: A string, e.g. " test " + * + * Removes leading and trailing whitespace from a constant string. + * + * Returns: newly allocated string + **/ +gchar * +fu_common_strstrip (const gchar *str) +{ + guint head = G_MAXUINT; + guint tail = 0; + + g_return_val_if_fail (str != NULL, NULL); + + /* find first non-space char */ + for (guint i = 0; str[i] != '\0'; i++) { + if (str[i] != ' ') { + head = i; + break; + } + } + if (head == G_MAXUINT) + return g_strdup (""); + + /* find last non-space char */ + for (guint i = head; str[i] != '\0'; i++) { + if (str[i] != ' ') + tail = i; + } + return g_strndup (str + head, tail - head + 1); +} + +static const GError * +fu_common_error_array_find (GPtrArray *errors, FwupdError error_code) +{ + for (guint j = 0; j < errors->len; j++) { + const GError *error = g_ptr_array_index (errors, j); + if (g_error_matches (error, FWUPD_ERROR, error_code)) + return error; + } + return NULL; +} + +static guint +fu_common_error_array_count (GPtrArray *errors, FwupdError error_code) +{ + guint cnt = 0; + for (guint j = 0; j < errors->len; j++) { + const GError *error = g_ptr_array_index (errors, j); + if (g_error_matches (error, FWUPD_ERROR, error_code)) + cnt++; + } + return cnt; +} + +static gboolean +fu_common_error_array_matches_any (GPtrArray *errors, FwupdError *error_codes) +{ + for (guint j = 0; j < errors->len; j++) { + const GError *error = g_ptr_array_index (errors, j); + gboolean matches_any = FALSE; + for (guint i = 0; error_codes[i] != FWUPD_ERROR_LAST; i++) { + if (g_error_matches (error, FWUPD_ERROR, error_codes[i])) { + matches_any = TRUE; + break; + } + } + if (!matches_any) + return FALSE; + } + return TRUE; +} + +/** + * fu_common_error_array_get_best: + * @errors: (element-type GError): array of errors + * + * Finds the 'best' error to show the user from a array of errors, creating a + * completely bespoke error where required. + * + * Returns: (transfer full): a #GError, never %NULL + **/ +GError * +fu_common_error_array_get_best (GPtrArray *errors) +{ + FwupdError err_prio[] = { FWUPD_ERROR_INVALID_FILE, + FWUPD_ERROR_VERSION_SAME, + FWUPD_ERROR_VERSION_NEWER, + FWUPD_ERROR_NOT_SUPPORTED, + FWUPD_ERROR_INTERNAL, + FWUPD_ERROR_NOT_FOUND, + FWUPD_ERROR_LAST }; + FwupdError err_all_uptodate[] = { FWUPD_ERROR_VERSION_SAME, + FWUPD_ERROR_NOT_FOUND, + FWUPD_ERROR_NOT_SUPPORTED, + FWUPD_ERROR_LAST }; + FwupdError err_all_newer[] = { FWUPD_ERROR_VERSION_NEWER, + FWUPD_ERROR_VERSION_SAME, + FWUPD_ERROR_NOT_FOUND, + FWUPD_ERROR_NOT_SUPPORTED, + FWUPD_ERROR_LAST }; + + /* are all the errors either GUID-not-matched or version-same? */ + if (fu_common_error_array_count (errors, FWUPD_ERROR_VERSION_SAME) > 1 && + fu_common_error_array_matches_any (errors, err_all_uptodate)) { + return g_error_new (FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "All updatable firmware is already installed"); + } + + /* are all the errors either GUID-not-matched or version same or newer? */ + if (fu_common_error_array_count (errors, FWUPD_ERROR_VERSION_NEWER) > 1 && + fu_common_error_array_matches_any (errors, err_all_newer)) { + return g_error_new (FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "All updatable devices already have newer versions"); + } + + /* get the most important single error */ + for (guint i = 0; err_prio[i] != FWUPD_ERROR_LAST; i++) { + const GError *error_tmp = fu_common_error_array_find (errors, err_prio[i]); + if (error_tmp != NULL) + return g_error_copy (error_tmp); + } + + /* fall back to something */ + return g_error_new (FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No supported devices found"); +} + +/** + * fu_common_get_path: + * @path_kind: A #FuPathKind e.g. %FU_PATH_KIND_DATADIR_PKG + * + * Gets a fwupd-specific system path. These can be overridden with various + * environment variables, for instance %FWUPD_DATADIR. + * + * Returns: a system path, or %NULL if invalid + **/ +gchar * +fu_common_get_path (FuPathKind path_kind) +{ + const gchar *tmp; + g_autofree gchar *basedir = NULL; + + switch (path_kind) { + /* /var */ + case FU_PATH_KIND_LOCALSTATEDIR: + tmp = g_getenv ("FWUPD_LOCALSTATEDIR"); + if (tmp != NULL) + return g_strdup (tmp); + tmp = g_getenv ("SNAP_USER_DATA"); + if (tmp != NULL) + return g_build_filename (tmp, LOCALSTATEDIR, NULL); + return g_build_filename (LOCALSTATEDIR, NULL); + /* /sys/firmware */ + case FU_PATH_KIND_SYSFSDIR_FW: + tmp = g_getenv ("FWUPD_SYSFSFWDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/firmware"); + /* /sys/class/tpm */ + case FU_PATH_KIND_SYSFSDIR_TPM: + tmp = g_getenv ("FWUPD_SYSFSTPMDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/class/tpm"); + /* /sys/bus/platform/drivers */ + case FU_PATH_KIND_SYSFSDIR_DRIVERS: + tmp = g_getenv ("FWUPD_SYSFSDRIVERDIR"); + if (tmp != NULL) + return g_strdup (tmp); + return g_strdup ("/sys/bus/platform/drivers"); + /* /etc */ + case FU_PATH_KIND_SYSCONFDIR: + tmp = g_getenv ("FWUPD_SYSCONFDIR"); + if (tmp != NULL) + return g_strdup (tmp); + tmp = g_getenv ("SNAP_USER_DATA"); + if (tmp != NULL) + return g_build_filename (tmp, SYSCONFDIR, NULL); + return g_strdup (SYSCONFDIR); + /* /usr/lib//fwupd-plugins-3 */ + case FU_PATH_KIND_PLUGINDIR_PKG: + tmp = g_getenv ("FWUPD_PLUGINDIR"); + if (tmp != NULL) + return g_strdup (tmp); + tmp = g_getenv ("SNAP"); + if (tmp != NULL) + return g_build_filename (tmp, PLUGINDIR, NULL); + return g_build_filename (PLUGINDIR, NULL); + /* /usr/share/fwupd */ + case FU_PATH_KIND_DATADIR_PKG: + tmp = g_getenv ("FWUPD_DATADIR"); + if (tmp != NULL) + return g_strdup (tmp); + tmp = g_getenv ("SNAP"); + if (tmp != NULL) + return g_build_filename (tmp, DATADIR, PACKAGE_NAME, NULL); + return g_build_filename (DATADIR, PACKAGE_NAME, NULL); + /* /usr/libexec/fwupd/efi */ + case FU_PATH_KIND_EFIAPPDIR: + tmp = g_getenv ("FWUPD_EFIAPPDIR"); + if (tmp != NULL) + return g_strdup (tmp); +#ifdef EFI_APP_LOCATION + tmp = g_getenv ("SNAP"); + if (tmp != NULL) + return g_build_filename (tmp, EFI_APP_LOCATION, NULL); + return g_strdup (EFI_APP_LOCATION); +#else + return NULL; +#endif + /* /etc/fwupd */ + case FU_PATH_KIND_SYSCONFDIR_PKG: + basedir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); + return g_build_filename (basedir, PACKAGE_NAME, NULL); + /* /var/lib/fwupd */ + case FU_PATH_KIND_LOCALSTATEDIR_PKG: + basedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR); + return g_build_filename (basedir, "lib", PACKAGE_NAME, NULL); + /* /var/cache/fwupd */ + case FU_PATH_KIND_CACHEDIR_PKG: + basedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR); + return g_build_filename (basedir, "cache", PACKAGE_NAME, NULL); + case FU_PATH_KIND_POLKIT_ACTIONS: +#ifdef POLKIT_ACTIONDIR + return g_strdup (POLKIT_ACTIONDIR); +#else + return NULL; +#endif + /* this shouldn't happen */ + default: + g_warning ("cannot build path for unknown kind %u", path_kind); + } + + return NULL; +} + +/** + * fu_common_string_replace: + * @string: The #GString to operate on + * @search: The text to search for + * @replace: The text to use for substitutions + * + * Performs multiple search and replace operations on the given string. + * + * Returns: the number of replacements done, or 0 if @search is not found. + * + * Since: 1.2.0 + **/ +guint +fu_common_string_replace (GString *string, const gchar *search, const gchar *replace) +{ + gchar *tmp; + guint count = 0; + gsize search_idx = 0; + gsize replace_len; + gsize search_len; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (search != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + /* nothing to do */ + if (string->len == 0) + return 0; + + search_len = strlen (search); + replace_len = strlen (replace); + + do { + tmp = g_strstr_len (string->str + search_idx, -1, search); + if (tmp == NULL) + break; + + /* advance the counter in case @replace contains @search */ + search_idx = (gsize) (tmp - string->str); + + /* reallocate the string if required */ + if (search_len > replace_len) { + g_string_erase (string, + (gssize) search_idx, + (gssize) (search_len - replace_len)); + memcpy (tmp, replace, replace_len); + } else if (search_len < replace_len) { + g_string_insert_len (string, + (gssize) search_idx, + replace, + (gssize) (replace_len - search_len)); + /* we have to treat this specially as it could have + * been reallocated when the insertion happened */ + memcpy (string->str + search_idx, replace, replace_len); + } else { + /* just memcmp in the new string */ + memcpy (tmp, replace, replace_len); + } + search_idx += replace_len; + count++; + } while (TRUE); + + return count; +} + +/** + * fu_common_dump_full: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @data: buffer to print + * @len: the size of @data + * @columns: break new lines after this many bytes + * @flags: some #FuDumpFlags, e.g. %FU_DUMP_FLAGS_SHOW_ASCII + * + * Dumps a raw buffer to the screen. + * + * Since: 1.2.4 + **/ +void +fu_common_dump_full (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len, + guint columns, + FuDumpFlags flags) +{ + g_autoptr(GString) str = g_string_new (NULL); + + /* optional */ + if (title != NULL) + g_string_append_printf (str, "%s:", title); + + /* if more than can fit on one line then start afresh */ + if (len > columns || flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) { + g_string_append (str, "\n"); + } else { + for (gsize i = str->len; i < 16; i++) + g_string_append (str, " "); + } + + /* offset line */ + if (flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) { + g_string_append (str, " │ "); + for (gsize i = 0; i < columns; i++) + g_string_append_printf (str, "%02x ", (guint) i); + g_string_append (str, "\n───────┼"); + for (gsize i = 0; i < columns; i++) + g_string_append (str, "───"); + g_string_append_printf (str, "\n0x%04x │ ", (guint) 0); + } + + /* print each row */ + for (gsize i = 0; i < len; i++) { + g_string_append_printf (str, "%02x ", data[i]); + + /* optionally print ASCII char */ + if (flags & FU_DUMP_FLAGS_SHOW_ASCII) { + if (g_ascii_isprint (data[i])) + g_string_append_printf (str, "[%c] ", data[i]); + else + g_string_append (str, "[?] "); + } + + /* new row required */ + if (i > 0 && i != len - 1 && (i + 1) % columns == 0) { + g_string_append (str, "\n"); + if (flags & FU_DUMP_FLAGS_SHOW_ADDRESSES) + g_string_append_printf (str, "0x%04x │ ", (guint) i + 1); + } + } + g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", str->str); +} + +/** + * fu_common_dump_raw: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @data: buffer to print + * @len: the size of @data + * + * Dumps a raw buffer to the screen. + * + * Since: 1.2.2 + **/ +void +fu_common_dump_raw (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len) +{ + FuDumpFlags flags = FU_DUMP_FLAGS_NONE; + if (len > 64) + flags |= FU_DUMP_FLAGS_SHOW_ADDRESSES; + fu_common_dump_full (log_domain, title, data, len, 32, flags); +} + +/** + * fu_common_dump_bytes: + * @log_domain: log domain, typically %G_LOG_DOMAIN or %NULL + * @title: prefix title, or %NULL + * @bytes: a #GBytes + * + * Dumps a byte buffer to the screen. + * + * Since: 1.2.2 + **/ +void +fu_common_dump_bytes (const gchar *log_domain, + const gchar *title, + GBytes *bytes) +{ + gsize len = 0; + const guint8 *data = g_bytes_get_data (bytes, &len); + fu_common_dump_raw (log_domain, title, data, len); +} + +/** + * fu_common_bytes_align: + * @bytes: a #GBytes + * @blksz: block size in bytes + * @padval: the byte used to pad the byte buffer + * + * Aligns a block of memory to @blksize using the @padval value; if + * the block is already aligned then the original @bytes is returned. + * + * Returns: (transfer full): a #GBytes, possibly @bytes + * + * Since: 1.2.4 + **/ +GBytes * +fu_common_bytes_align (GBytes *bytes, gsize blksz, gchar padval) +{ + const guint8 *data; + gsize sz; + + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (blksz > 0, NULL); + + /* pad */ + data = g_bytes_get_data (bytes, &sz); + if (sz % blksz != 0) { + gsize sz_align = ((sz / blksz) + 1) * blksz; + guint8 *data_align = g_malloc (sz_align); + memcpy (data_align, data, sz); + memset (data_align + sz, padval, sz_align - sz); + g_debug ("aligning 0x%x bytes to 0x%x", + (guint) sz, (guint) sz_align); + return g_bytes_new_take (data_align, sz_align); + } + + /* perfectly aligned */ + return g_bytes_ref (bytes); +} + +/** + * fu_common_bytes_is_empty: + * @bytes: a #GBytes + * + * Checks if a byte array are just empty (0xff) bytes. + * + * Return value: %TRUE if @bytes is empty + **/ +gboolean +fu_common_bytes_is_empty (GBytes *bytes) +{ + gsize sz = 0; + const guint8 *buf = g_bytes_get_data (bytes, &sz); + for (gsize i = 0; i < sz; i++) { + if (buf[i] != 0xff) + return FALSE; + } + return TRUE; +} + +/** + * fu_common_bytes_compare: + * @bytes1: a #GBytes + * @bytes2: another #GBytes + * @error: A #GError or %NULL + * + * Checks if a byte array are just empty (0xff) bytes. + * + * Return value: %TRUE if @bytes1 and @bytes2 are identical + **/ +gboolean +fu_common_bytes_compare (GBytes *bytes1, GBytes *bytes2, GError **error) +{ + const guint8 *buf1; + const guint8 *buf2; + gsize bufsz1; + gsize bufsz2; + + g_return_val_if_fail (bytes1 != NULL, FALSE); + g_return_val_if_fail (bytes2 != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not the same length */ + buf1 = g_bytes_get_data (bytes1, &bufsz1); + buf2 = g_bytes_get_data (bytes2, &bufsz2); + if (bufsz1 != bufsz2) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "got %" G_GSIZE_FORMAT " bytes, expected " + "%" G_GSIZE_FORMAT, bufsz1, bufsz2); + return FALSE; + } + + /* check matches */ + for (guint i = 0x0; i < bufsz1; i++) { + if (buf1[i] != buf2[i]) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "got 0x%02x, expected 0x%02x @ 0x%04x", + buf1[i], buf2[i], i); + return FALSE; + } + } + + /* success */ + return TRUE; +} + +/** + * fu_common_realpath: + * @filename: a filename + * @error: A #GError or %NULL + * + * Finds the canonicalized absolute filename for a path. + * + * Return value: A filename, or %NULL if invalid or not found + **/ +gchar * +fu_common_realpath (const gchar *filename, GError **error) +{ + char full_tmp[PATH_MAX]; + + g_return_val_if_fail (filename != NULL, NULL); + + if (realpath (filename, full_tmp) == NULL) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "cannot resolve path: %s", + strerror (errno)); + return NULL; + } + return g_strdup (full_tmp); +} diff -Nru fwupd-1.0.6/src/fu-common-cab.c fwupd-1.2.10/src/fu-common-cab.c --- fwupd-1.0.6/src/fu-common-cab.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-common-cab.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuCommonCab" + #include "config.h" #include @@ -28,7 +15,9 @@ #include "fwupd-error.h" -#ifdef HAVE_GCAB_1_0 +#ifndef HAVE_GCAB_1_0 +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCabCabinet, g_object_unref) +#endif static GCabFile * _gcab_cabinet_get_file_by_name (GCabCabinet *cabinet, const gchar *basename) @@ -36,50 +25,82 @@ GPtrArray *folders = gcab_cabinet_get_folders (cabinet); for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); +#ifdef HAVE_GCAB_1_0 GCabFile *cabfile = gcab_folder_get_file_by_name (cabfolder, basename); if (cabfile != NULL) return cabfile; +#else + g_autoptr(GSList) files = gcab_folder_get_files (cabfolder); + for (GSList *l = files; l != NULL; l = l->next) { + GCabFile *cabfile = GCAB_FILE (l->data); + if (g_strcmp0 (gcab_file_get_extract_name (cabfile), basename) == 0) + return cabfile; + } +#endif } return NULL; } -/* sets the firmware and signature blobs on AsRelease */ +#ifndef HAVE_GCAB_1_0 +static GBytes * +_gcab_file_get_bytes (GCabFile *cabfile) +{ + GBytes *blob = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(GError) error_local = NULL; + + fn = g_build_filename (g_object_get_data (G_OBJECT (cabfile), + "fwupd::DecompressPath"), + gcab_file_get_extract_name (cabfile), + NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to read temp file: %s", error_local->message); + return NULL; + } + return blob; +} +#endif + +/* sets the firmware and signature blobs on XbNode */ static gboolean -fu_common_store_from_cab_release (AsRelease *release, GCabCabinet *cabinet, GError **error) +fu_common_store_from_cab_release (XbNode *release, GCabCabinet *cabinet, GError **error) { - AsChecksum *csum_tmp; GCabFile *cabfile; GBytes *blob; - guint64 size; - g_autofree gchar *basename = NULL; - g_autofree gchar *checksum = NULL; + const gchar *csum_filename = NULL; const gchar *suffixes[] = { "asc", "p7b", "p7c", NULL }; + g_autofree gchar *basename = NULL; + g_autofree gchar *release_key = NULL; + g_autoptr(XbNode) csum_tmp = NULL; + g_autoptr(XbNode) nsize = NULL; /* ensure we always have a content checksum */ - csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum_tmp == NULL) { - g_autoptr(AsChecksum) csum = as_checksum_new (); - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - /* if this isn't true, a firmware needs to set in - * the metainfo.xml file something like: - * */ - as_checksum_set_filename (csum, "firmware.bin"); - as_release_add_checksum (release, csum); - csum_tmp = csum; - } + csum_tmp = xb_node_query_first (release, "checksum[@target='content']", NULL); + if (csum_tmp != NULL) + csum_filename = xb_node_get_attr (csum_tmp, "filename"); + + /* if this isn't true, a firmware needs to set in the metainfo.xml file + * something like: */ + if (csum_filename == NULL) + csum_filename = "firmware.bin"; /* get the main firmware file */ - basename = g_path_get_basename (as_checksum_get_filename (csum_tmp)); + basename = g_path_get_basename (csum_filename); cabfile = _gcab_cabinet_get_file_by_name (cabinet, basename); if (cabfile == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "cannot find %s in archive", - as_checksum_get_filename (csum_tmp)); + basename); return FALSE; } +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -89,35 +110,41 @@ } /* set the blob */ - as_release_set_blob (release, basename, blob); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", basename); + xb_node_set_data (release, release_key, blob); - /* set if unspecified, but error out if specified and incorrect */ - size = as_release_get_size (release, AS_SIZE_KIND_INSTALLED); - if (size == 0) { - as_release_set_size (release, AS_SIZE_KIND_INSTALLED, - g_bytes_get_size (blob)); - } else if (size != g_bytes_get_size (blob)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "contents size invalid, expected " - "%" G_GSIZE_FORMAT ", got %" G_GUINT64_FORMAT, - g_bytes_get_size (blob), size); - return FALSE; + /* set as metadata if unset, but error if specified and incorrect */ + nsize = xb_node_query_first (release, "size[@type='installed']", NULL); + if (nsize != NULL) { + guint64 size = fu_common_strtoull (xb_node_get_text (nsize)); + if (size != g_bytes_get_size (blob)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "contents size invalid, expected " + "%" G_GSIZE_FORMAT ", got %" G_GUINT64_FORMAT, + g_bytes_get_size (blob), size); + return FALSE; + } + } else { + guint64 size = g_bytes_get_size (blob); + g_autoptr(GBytes) blob_sz = g_bytes_new (&size, sizeof(guint64)); + xb_node_set_data (release, "fwupd::ReleaseSize", blob_sz); } /* set if unspecified, but error out if specified and incorrect */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); - if (as_checksum_get_value (csum_tmp) == NULL) { - as_checksum_set_value (csum_tmp, checksum); - } else if (g_strcmp0 (checksum, as_checksum_get_value (csum_tmp)) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "contents checksum invalid, expected %s, got %s", - checksum, - as_checksum_get_value (csum_tmp)); - return FALSE; + if (csum_tmp != NULL && xb_node_get_text (csum_tmp) != NULL) { + g_autofree gchar *checksum = NULL; + checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + if (g_strcmp0 (checksum, xb_node_get_text (csum_tmp)) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "contents checksum invalid, expected %s, got %s", + checksum, + xb_node_get_text (csum_tmp)); + return FALSE; + } } /* if the signing file exists, set that too */ @@ -126,7 +153,12 @@ basename_sig = g_strdup_printf ("%s.%s", basename, suffixes[i]); cabfile = _gcab_cabinet_get_file_by_name (cabinet, basename_sig); if (cabfile != NULL) { + g_autofree gchar *release_key_sig = NULL; +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error (error, FWUPD_ERROR, @@ -135,7 +167,9 @@ basename_sig); return FALSE; } - as_release_set_blob (release, basename_sig, blob); + release_key_sig = g_strdup_printf ("fwupd::ReleaseBlob(%s)", + basename_sig); + xb_node_set_data (release, release_key_sig, blob); } } @@ -143,21 +177,24 @@ return TRUE; } -/* adds each GCabFile to the store */ +/* adds each GCabFile to the silo */ static gboolean -fu_common_store_from_cab_file (AsStore *store, GCabCabinet *cabinet, +fu_common_store_from_cab_file (XbBuilder *builder, GCabCabinet *cabinet, GCabFile *cabfile, GError **error) { GBytes *blob; - GPtrArray *releases; - g_autoptr(AsApp) app = NULL; g_autoptr(GError) error_local = NULL; -#if !AS_CHECK_VERSION(0,7,5) - g_autofree gchar *cache_fn = NULL; -#endif + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + + /* rewrite to be under a components root */ + xb_builder_source_set_prefix (source, "components"); /* parse file */ +#ifdef HAVE_GCAB_1_0 blob = gcab_file_get_bytes (cabfile); +#else + blob = _gcab_file_get_bytes (cabfile); +#endif if (blob == NULL) { g_set_error_literal (error, FWUPD_ERROR, @@ -165,9 +202,10 @@ "no GBytes from GCabFile"); return FALSE; } - app = as_app_new (); -#if AS_CHECK_VERSION(0,7,5) - if (!as_app_parse_data (app, blob, AS_APP_PARSE_FLAG_NONE, &error_local)) { + if (!xb_builder_source_load_xml (source, + g_bytes_get_data (blob, NULL), + XB_BUILDER_SOURCE_FLAG_NONE, + &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, @@ -175,54 +213,15 @@ error_local->message); return FALSE; } -#else - cache_fn = g_build_filename (LOCALSTATEDIR, "cache", "fwupd", - gcab_file_get_extract_name (cabfile), NULL); - if (!fu_common_mkdir_parent (cache_fn, error)) - return FALSE; - if (!g_file_set_contents (cache_fn, g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob), &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_WRITE, - "could not save temporary MetaInfo XML to %s: %s", - cache_fn, error_local->message); - return FALSE; - } - if (!as_app_parse_file (app, cache_fn, AS_APP_PARSE_FLAG_NONE, &error_local)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "could not parse MetaInfo XML: %s", - error_local->message); - return FALSE; - } -#endif - - /* process each listed release */ - releases = as_app_get_releases (app); - if (releases->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no releases in metainfo file"); - return FALSE; - } - for (guint i = 0; i < releases->len; i++) { - AsRelease *release = g_ptr_array_index (releases, i); - g_debug ("processing release: %s", as_release_get_version (release)); - if (!fu_common_store_from_cab_release (release, cabinet, error)) - return FALSE; - } + xb_builder_import_source (builder, source); /* success */ - as_store_add_app (store, app); return TRUE; } -/* adds each GCabFolder to the store */ +/* adds each GCabFolder to the silo */ static gboolean -fu_common_store_from_cab_folder (AsStore *store, GCabCabinet *cabinet, +fu_common_store_from_cab_folder (XbBuilder *builder, GCabCabinet *cabinet, GCabFolder *cabfolder, GError **error) { g_autoptr(GSList) cabfiles = gcab_folder_get_files (cabfolder); @@ -230,8 +229,8 @@ GCabFile *cabfile = GCAB_FILE (l->data); const gchar *fn = gcab_file_get_extract_name (cabfile); g_debug ("processing file: %s", fn); - if (as_format_guess_kind (fn) == AS_FORMAT_KIND_METAINFO) { - if (!fu_common_store_from_cab_file (store, cabinet, cabfile, error)) { + if (g_str_has_suffix (fn, ".metainfo.xml")) { + if (!fu_common_store_from_cab_file (builder, cabinet, cabfile, error)) { g_prefix_error (error, "%s could not be loaded: ", gcab_file_get_extract_name (cabfile)); return FALSE; @@ -244,11 +243,12 @@ typedef struct { guint64 size_total; guint64 size_max; + const gchar *decompress_path; GError *error; } FuCommonCabHelper; static gboolean -as_cab_store_file_cb (GCabFile *file, gpointer user_data) +fu_common_store_file_cb (GCabFile *file, gpointer user_data) { FuCommonCabHelper *helper = (FuCommonCabHelper *) user_data; g_autofree gchar *basename = NULL; @@ -291,34 +291,135 @@ /* ignore the dirname completely */ basename = g_path_get_basename (name); gcab_file_set_extract_name (file, basename); + +#ifndef HAVE_GCAB_1_0 + /* set this for old versions of GCab */ + g_object_set_data_full (G_OBJECT (file), + "fwupd::DecompressPath", + g_strdup (helper->decompress_path), + g_free); +#endif + + return TRUE; +} + +static gint +fu_common_cab_sort_cb (XbBuilderNode *bn1, XbBuilderNode *bn2, gpointer user_data) +{ + guint64 prio1 = xb_builder_node_get_attr_as_uint (bn1, "priority"); + guint64 prio2 = xb_builder_node_get_attr_as_uint (bn2, "priority"); + if (prio1 > prio2) + return -1; + if (prio1 < prio2) + return 1; + return 0; +} + +static gboolean +fu_common_cab_sort_priority_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + xb_builder_node_sort_children (bn, fu_common_cab_sort_cb, user_data); + return TRUE; +} + +static XbBuilderNode * +_xb_builder_node_get_child_by_element_attr (XbBuilderNode *bn, + const gchar *element, + const gchar *attr_name, + const gchar *attr_value) +{ + GPtrArray *bcs = xb_builder_node_get_children (bn); + for (guint i = 0; i < bcs->len; i++) { + XbBuilderNode *bc = g_ptr_array_index (bcs, i); + if (g_strcmp0 (xb_builder_node_get_element (bc), element) != 0) + continue; + if (g_strcmp0 (xb_builder_node_get_attr (bc, "type"), "container") == 0) + return g_object_ref (bc); + } + return NULL; +} + +static gboolean +fu_common_cab_set_container_checksum_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) +{ + + const gchar *container_checksum = (const gchar *) user_data; + g_autoptr(XbBuilderNode) csum = NULL; + + /* not us */ + if (g_strcmp0 (xb_builder_node_get_element (bn), "release") != 0) + return TRUE; + + /* verify it exists */ + csum = _xb_builder_node_get_child_by_element_attr (bn, "checksum", + "target", "container"); + if (csum == NULL) { + csum = xb_builder_node_insert (bn, "checksum", + "target", "container", + NULL); + } + + /* verify it is correct */ + if (g_strcmp0 (xb_builder_node_get_text (csum), container_checksum) != 0) { + g_debug ("invalid container checksum %s, fixing up to %s", + xb_builder_node_get_text (csum), container_checksum); + xb_builder_node_set_text (csum, container_checksum, -1); + } return TRUE; } /** - * fu_common_store_from_cab_bytes: + * fu_common_cab_build_silo: * @blob: A readable blob * @size_max: The maximum size of the archive * @error: A #FuEndianType, e.g. %G_LITTLE_ENDIAN * - * Create an AppStream store from a cabinet archive. + * Create an AppStream silo from a cabinet archive. * - * Returns: a store, or %NULL on error + * Returns: a #XbSilo, or %NULL on error **/ -AsStore * -fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) +XbSilo * +fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error) { - FuCommonCabHelper helper = { 0 }; + FuCommonCabHelper helper = { + .size_total = 0, + .size_max = size_max, + .error = NULL, + }; GPtrArray *folders; - g_autoptr(AsStore) store = as_store_new (); + g_autofree gchar *container_checksum = NULL; +#ifndef HAVE_GCAB_1_0 + g_autofree gchar *tmp_path = NULL; + g_autoptr(GFile) tmp_file = NULL; +#endif + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderFixup) fixup = NULL; + g_autoptr(XbBuilderFixup) fixup2 = NULL; g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); g_autoptr(GError) error_local = NULL; g_autoptr(GInputStream) ip = NULL; + g_autoptr(GPtrArray) components = NULL; + + /* sort the components by priority */ + fixup = xb_builder_fixup_new ("OrderByPriority", + fu_common_cab_sort_priority_cb, + NULL, NULL); + xb_builder_fixup_set_max_depth (fixup, 0); + xb_builder_add_fixup (builder, fixup); /* load from a seekable stream */ ip = g_memory_input_stream_new_from_bytes (blob); if (!gcab_cabinet_load (cabinet, ip, NULL, error)) return NULL; +#ifdef HAVE_GCAB_1_0 /* check the size is sane */ if (gcab_cabinet_get_size (cabinet) > size_max) { g_autofree gchar *sz_val = g_format_size (gcab_cabinet_get_size (cabinet)); @@ -332,9 +433,8 @@ } /* decompress the file to memory */ - helper.size_max = size_max; if (!gcab_cabinet_extract_simple (cabinet, NULL, - as_cab_store_file_cb, &helper, + fu_common_store_file_cb, &helper, NULL, &error_local)) { g_set_error_literal (error, FWUPD_ERROR, @@ -342,6 +442,29 @@ error_local->message); return NULL; } +#else + /* decompress to /tmp */ + tmp_path = g_dir_make_tmp ("fwupd-XXXXXX", &error_local); + if (tmp_path == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to create temp dir: %s", + error_local->message); + return NULL; + } + helper.decompress_path = tmp_path; + tmp_file = g_file_new_for_path (tmp_path); + if (!gcab_cabinet_extract_simple (cabinet, tmp_file, + fu_common_store_file_cb, &helper, + NULL, &error_local)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + error_local->message); + return NULL; + } +#endif /* the file callback set an error */ if (helper.error != NULL) { @@ -349,53 +472,65 @@ return NULL; } + /* verbose profiling */ + if (g_getenv ("FWUPD_VERBOSE") != NULL) { + xb_builder_set_profile_flags (builder, + XB_SILO_PROFILE_FLAG_XPATH | + XB_SILO_PROFILE_FLAG_DEBUG); + } + /* look at each folder */ folders = gcab_cabinet_get_folders (cabinet); for (guint i = 0; i < folders->len; i++) { GCabFolder *cabfolder = GCAB_FOLDER (g_ptr_array_index (folders, i)); g_debug ("processing folder: %u/%u", i + 1, folders->len); - if (!fu_common_store_from_cab_folder (store, cabinet, cabfolder, error)) + if (!fu_common_store_from_cab_folder (builder, cabinet, cabfolder, error)) return NULL; } - /* did we get any valid AsApps */ - if (as_store_get_size (store) == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "archive contained no valid metadata"); + /* ensure the container checksum is always set */ + container_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + fixup2 = xb_builder_fixup_new ("SetContainerChecksum", + fu_common_cab_set_container_checksum_cb, + container_checksum, NULL); + xb_builder_add_fixup (builder, fixup2); + + /* did we get any valid files */ + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) return NULL; - } - - /* success */ - return g_steal_pointer (&store); -} - -#else - -AsStore * -fu_common_store_from_cab_bytes (GBytes *blob, guint64 size_max, GError **error) -{ - g_autoptr(AsStore) store = as_store_new (); - g_autoptr(GError) error_local = NULL; - /* this is klunky as we have to write actual files to /tmp */ - if (!as_store_from_bytes (store, blob, NULL, &error_local)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - error_local->message); + components = xb_silo_query (silo, "components/component", 0, &error_local); + if (components == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "archive contained no valid metadata: %s", + error_local->message); return NULL; } - /* did we get any valid AsApps */ - if (as_store_get_size (store) == 0) { - g_set_error_literal (error, + /* process each listed release */ + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + g_autoptr(GPtrArray) releases = NULL; + releases = xb_node_query (component, "releases/release", 0, &error_local); + if (releases == NULL) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "archive contained no valid metadata"); - return FALSE; + "no releases in metainfo file: %s", + error_local->message); + return NULL; + } + for (guint j = 0; j < releases->len; j++) { + XbNode *rel = g_ptr_array_index (releases, j); + g_debug ("processing release: %s", xb_node_get_attr (rel, "version")); + if (!fu_common_store_from_cab_release (rel, cabinet, error)) + return NULL; + } } - return g_steal_pointer (&store); + + /* success */ + return g_steal_pointer (&silo); } -#endif diff -Nru fwupd-1.0.6/src/fu-common-cab.h fwupd-1.2.10/src/fu-common-cab.h --- fwupd-1.0.6/src/fu-common-cab.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-common-cab.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,31 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COMMON_CAB_H -#define __FU_COMMON_CAB_H +#pragma once + +#include -#include +G_BEGIN_DECLS -AsStore *fu_common_store_from_cab_bytes (GBytes *blob, +XbSilo *fu_common_cab_build_silo (GBytes *blob, guint64 size_max, GError **error); -#endif /* __FU_COMMON_CAB_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-common-guid.c fwupd-1.2.10/src/fu-common-guid.c --- fwupd-1.0.6/src/fu-common-guid.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-common-guid.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include "fu-common-guid.h" + +/** + * fu_common_guid_is_plausible: + * @buf: a buffer of data + * + * Checks whether a chunk of memory looks like it could be a GUID. + * + * Returns: TRUE if it looks like a GUID, FALSE if not + * + * Since: 1.2.5 + **/ +gboolean +fu_common_guid_is_plausible (const guint8 *buf) +{ + guint guint_sum = 0; + + for (guint i = 0; i < 16; i++) + guint_sum += buf[i]; + if (guint_sum == 0x00) + return FALSE; + if (guint_sum < 0xff) + return FALSE; + return TRUE; +} diff -Nru fwupd-1.0.6/src/fu-common-guid.h fwupd-1.2.10/src/fu-common-guid.h --- fwupd-1.0.6/src/fu-common-guid.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-common-guid.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean fu_common_guid_is_plausible (const guint8 *buf); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-common.h fwupd-1.2.10/src/fu-common.h --- fwupd-1.0.6/src/fu-common.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,38 +1,92 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_COMMON_H__ -#define __FU_COMMON_H__ +#pragma once #include +G_BEGIN_DECLS + +/** + * FuAppFlags: + * @FU_APP_FLAGS_NONE: No flags set + * @FU_APP_FLAGS_NO_IDLE_SOURCES: Disallow idle sources + * + * The flags to use when loading an application. + **/ +typedef enum { + FU_APP_FLAGS_NONE = 0, + FU_APP_FLAGS_NO_IDLE_SOURCES = 1 << 0, + /*< private >*/ + FU_APP_FLAGS_LAST +} FuAppFlags; + +/** + * FuDumpFlags: + * @FU_DUMP_FLAGS_NONE: No flags set + * @FU_DUMP_FLAGS_SHOW_ASCII: Show ASCII in debugging dumps + * @FU_DUMP_FLAGS_SHOW_ADDRESSES: Show addresses in debugging dumps + * + * The flags to use when configuring debugging + **/ +typedef enum { + FU_DUMP_FLAGS_NONE = 0, + FU_DUMP_FLAGS_SHOW_ASCII = 1 << 0, + FU_DUMP_FLAGS_SHOW_ADDRESSES = 1 << 1, + /*< private >*/ + FU_DUMP_FLAGS_LAST +} FuDumpFlags; + +/** + * FuPathKind: + * @FU_PATH_KIND_CACHEDIR_PKG: The cache directory (IE /var/cache/fwupd) + * @FU_PATH_KIND_DATADIR_PKG: The non-volatile data store (IE /usr/share/fwupd) + * @FU_PATH_KIND_EFIAPPDIR: The location to store EFI apps before install (IE /usr/libexec/fwupd/efi) + * @FU_PATH_KIND_LOCALSTATEDIR: The local state directory (IE /var) + * @FU_PATH_KIND_LOCALSTATEDIR_PKG: The local state directory for the package (IE /var/lib/fwupd) + * @FU_PATH_KIND_PLUGINDIR_PKG: The location to look for plugins for package (IE /usr/lib/[triplet]/fwupd-plugins-3) + * @FU_PATH_KIND_SYSCONFDIR: The configuration location (IE /etc) + * @FU_PATH_KIND_SYSCONFDIR_PKG: The package configuration location (IE /etc/fwupd) + * @FU_PATH_KIND_SYSFSDIR_FW: The sysfs firmware location (IE /sys/firmware) + * @FU_PATH_KIND_SYSFSDIR_DRIVERS: The platform sysfs directory (IE /sys/bus/platform/drivers) + * @FU_PATH_KIND_SYSFSDIR_TPM: The TPM sysfs directory (IE /sys/class/tpm) + * @FU_PATH_KIND_POLKIT_ACTIONS The directory for policy kit actions (IE /usr/share/polkit-1/actions/) + * + * Path types to use when dynamically determining a path at runtime + **/ +typedef enum { + FU_PATH_KIND_CACHEDIR_PKG, + FU_PATH_KIND_DATADIR_PKG, + FU_PATH_KIND_EFIAPPDIR, + FU_PATH_KIND_LOCALSTATEDIR, + FU_PATH_KIND_LOCALSTATEDIR_PKG, + FU_PATH_KIND_PLUGINDIR_PKG, + FU_PATH_KIND_SYSCONFDIR, + FU_PATH_KIND_SYSCONFDIR_PKG, + FU_PATH_KIND_SYSFSDIR_FW, + FU_PATH_KIND_SYSFSDIR_DRIVERS, + FU_PATH_KIND_SYSFSDIR_TPM, + FU_PATH_KIND_POLKIT_ACTIONS, + /*< private >*/ + FU_PATH_KIND_LAST +} FuPathKind; + typedef void (*FuOutputHandler) (const gchar *line, gpointer user_data); gboolean fu_common_spawn_sync (const gchar * const *argv, FuOutputHandler handler_cb, gpointer handler_user_data, + guint timeout_ms, GCancellable *cancellable, GError **error); +gchar *fu_common_get_path (FuPathKind path_kind); +gchar *fu_common_realpath (const gchar *filename, + GError **error); gboolean fu_common_rmtree (const gchar *directory, GError **error); GPtrArray *fu_common_get_files_recursive (const gchar *path, @@ -54,6 +108,31 @@ const gchar *script_fn, const gchar *output_fn, GError **error); +GError *fu_common_error_array_get_best (GPtrArray *errors); +guint64 fu_common_strtoull (const gchar *str); +gchar *fu_common_find_program_in_path (const gchar *basename, + GError **error); +gchar *fu_common_strstrip (const gchar *str); +void fu_common_dump_raw (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len); +void fu_common_dump_full (const gchar *log_domain, + const gchar *title, + const guint8 *data, + gsize len, + guint columns, + FuDumpFlags flags); +void fu_common_dump_bytes (const gchar *log_domain, + const gchar *title, + GBytes *bytes); +GBytes *fu_common_bytes_align (GBytes *bytes, + gsize blksz, + gchar padval); +gboolean fu_common_bytes_is_empty (GBytes *bytes); +gboolean fu_common_bytes_compare (GBytes *bytes1, + GBytes *bytes2, + GError **error); typedef guint FuEndianType; @@ -68,4 +147,8 @@ guint32 fu_common_read_uint32 (const guint8 *buf, FuEndianType endian); -#endif /* __FU_COMMON_H__ */ +guint fu_common_string_replace (GString *string, + const gchar *search, + const gchar *replace); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-common-version.c fwupd-1.2.10/src/fu-common-version.c --- fwupd-1.0.6/src/fu-common-version.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-common-version.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include + +#include "fwupd-enums.h" +#include "fwupd-error.h" + +#include "fu-common-version.h" + +#define FU_COMMON_VERSION_DECODE_BCD(val) ((((val) >> 4) & 0x0f) * 10 + ((val) & 0x0f)) + +/** + * fu_common_version_from_uint32: + * @val: A uint32le version number + * @kind: version kind used for formatting, e.g. %FWUPD_VERSION_FORMAT_TRIPLET + * + * Returns a dotted decimal version string from a 32 bit number. + * + * Returns: A version number, e.g. "1.0.3", or %NULL if not supported + * + * Since: 1.2.0 + **/ +gchar * +fu_common_version_from_uint32 (guint32 val, FwupdVersionFormat kind) +{ + if (kind == FWUPD_VERSION_FORMAT_QUAD) { + /* AA.BB.CC.DD */ + return g_strdup_printf ("%u.%u.%u.%u", + (val >> 24) & 0xff, + (val >> 16) & 0xff, + (val >> 8) & 0xff, + val & 0xff); + } + if (kind == FWUPD_VERSION_FORMAT_TRIPLET) { + /* AA.BB.CCDD */ + return g_strdup_printf ("%u.%u.%u", + (val >> 24) & 0xff, + (val >> 16) & 0xff, + val & 0xffff); + } + if (kind == FWUPD_VERSION_FORMAT_PAIR) { + /* AABB.CCDD */ + return g_strdup_printf ("%u.%u", + (val >> 16) & 0xffff, + val & 0xffff); + } + if (kind == FWUPD_VERSION_FORMAT_NUMBER) { + /* AABBCCDD */ + return g_strdup_printf ("%" G_GUINT32_FORMAT, val); + } + if (kind == FWUPD_VERSION_FORMAT_BCD) { + /* AA.BB.CC.DD, but BCD */ + return g_strdup_printf ("%u.%u.%u.%u", + FU_COMMON_VERSION_DECODE_BCD(val >> 24), + FU_COMMON_VERSION_DECODE_BCD(val >> 16), + FU_COMMON_VERSION_DECODE_BCD(val >> 8), + FU_COMMON_VERSION_DECODE_BCD(val)); + } + if (kind == FWUPD_VERSION_FORMAT_INTEL_ME) { + /* aaa+11.bbbbb.cccccccc.dddddddddddddddd */ + return g_strdup_printf ("%u.%u.%u.%u", + ((val >> 29) & 0x07) + 0x0b, + (val >> 24) & 0x1f, + (val >> 16) & 0xff, + val & 0xffff); + } + if (kind == FWUPD_VERSION_FORMAT_INTEL_ME2) { + /* A.B.CC.DDDD */ + return g_strdup_printf ("%u.%u.%u.%u", + (val >> 28) & 0x0f, + (val >> 24) & 0x0f, + (val >> 16) & 0xff, + val & 0xffff); + } + g_critical ("failed to convert version format %s: %u", + fwupd_version_format_to_string (kind), val); + return NULL; +} + +/** + * fu_common_version_from_uint16: + * @val: A uint16le version number + * @kind: version kind used for formatting, e.g. %FWUPD_VERSION_FORMAT_TRIPLET + * + * Returns a dotted decimal version string from a 16 bit number. + * + * Returns: A version number, e.g. "1.3", or %NULL if not supported + * + * Since: 1.2.0 + **/ +gchar * +fu_common_version_from_uint16 (guint16 val, FwupdVersionFormat kind) +{ + if (kind == FWUPD_VERSION_FORMAT_BCD) { + return g_strdup_printf ("%i.%i", + FU_COMMON_VERSION_DECODE_BCD(val >> 8), + FU_COMMON_VERSION_DECODE_BCD(val)); + } + if (kind == FWUPD_VERSION_FORMAT_PAIR) { + return g_strdup_printf ("%u.%u", + (guint) (val >> 8) & 0xff, + (guint) val & 0xff); + } + if (kind == FWUPD_VERSION_FORMAT_NUMBER) { + return g_strdup_printf ("%" G_GUINT16_FORMAT, val); + } + g_critical ("failed to convert version format %s: %u", + fwupd_version_format_to_string (kind), val); + return NULL; +} + +static gint +fu_common_vercmp_char (gchar chr1, gchar chr2) +{ + if (chr1 == chr2) + return 0; + if (chr1 == '~') + return -1; + if (chr2 == '~') + return 1; + return chr1 < chr2 ? -1 : 1; +} + +static gint +fu_common_vercmp_chunk (const gchar *str1, const gchar *str2) +{ + guint i; + + /* trivial */ + if (g_strcmp0 (str1, str2) == 0) + return 0; + if (str1 == NULL) + return 1; + if (str2 == NULL) + return -1; + + /* check each char of the chunk */ + for (i = 0; str1[i] != '\0' && str2[i] != '\0'; i++) { + gint rc = fu_common_vercmp_char (str1[i], str2[i]); + if (rc != 0) + return rc; + } + return fu_common_vercmp_char (str1[i], str2[i]); +} + +static gboolean +_g_ascii_is_digits (const gchar *str) +{ + g_return_val_if_fail (str != NULL, FALSE); + for (gsize i = 0; str[i] != '\0'; i++) { + if (!g_ascii_isdigit (str[i])) + return FALSE; + } + return TRUE; +} + +static gboolean +fu_common_version_is_valid_semver_char (gchar c) +{ + if (g_ascii_isdigit (c)) + return TRUE; + if (c == '.') + return TRUE; + return FALSE; +} + +/** + * fu_common_version_ensure_semver: + * @version: A version number, e.g. ` V1.2.3 ` + * + * Builds a semver from the possibly crazy version number. + * + * Returns: A version number, e.g. "1.2.3" + * + * Since: 1.2.9 + */ +gchar * +fu_common_version_ensure_semver (const gchar *version) +{ + GString *version_safe = g_string_new (NULL); + for (guint i = 0; version[i] != '\0'; i++) { + if (fu_common_version_is_valid_semver_char (version[i])) + g_string_append_c (version_safe, version[i]); + } + return g_string_free (version_safe, FALSE); +} + +/** + * fu_common_version_parse: + * @version: A version number + * + * Returns a dotted decimal version string from a version string. The supported + * formats are: + * + * - Dotted decimal, e.g. "1.2.3" + * - Base 16, a hex number *with* a 0x prefix, e.g. "0x10203" + * - Base 10, a string containing just [0-9], e.g. "66051" + * - Date in YYYYMMDD format, e.g. 20150915 + * + * Anything with a '.' or that doesn't match [0-9] or 0x[a-f,0-9] is considered + * a string and returned without modification. + * + * Returns: A version number, e.g. "1.0.3" + * + * Since: 1.2.0 + */ +gchar * +fu_common_version_parse (const gchar *version) +{ + const gchar *version_noprefix = version; + gchar *endptr = NULL; + guint64 tmp; + guint base; + + /* already dotted decimal */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* is a date */ + if (g_str_has_prefix (version, "20") && + strlen (version) == 8) + return g_strdup (version); + + /* convert 0x prefixed strings to dotted decimal */ + if (g_str_has_prefix (version, "0x")) { + version_noprefix += 2; + base = 16; + } else { + /* for non-numeric content, just return the string */ + if (!_g_ascii_is_digits (version)) + return g_strdup (version); + base = 10; + } + + /* convert */ + tmp = g_ascii_strtoull (version_noprefix, &endptr, base); + if (endptr != NULL && endptr[0] != '\0') + return g_strdup (version); + if (tmp == 0) + return g_strdup (version); + return fu_common_version_from_uint32 ((guint32) tmp, FWUPD_VERSION_FORMAT_TRIPLET); +} + +/** + * fu_common_version_guess_format: + * @version: A version number, e.g. "1.2.3" + * + * Guesses the version format from the version number. This is only a heuristic + * and plugins and components should explicitly set the version format whenever + * possible. + * + * If the version format cannot be guessed with any degree of accuracy, the + * %FWUPD_VERSION_FORMAT_UNKNOWN constant is returned. + * + * Returns: A #FwupdVersionFormat, e.g. %FWUPD_VERSION_FORMAT_QUAD + * + * Since: 1.2.0 + */ +FwupdVersionFormat +fu_common_version_guess_format (const gchar *version) +{ + guint sz; + g_auto(GStrv) split = NULL; + + /* nothing to use */ + if (version == NULL || version[0] == '\0') + return FWUPD_VERSION_FORMAT_UNKNOWN; + + /* no dots, assume just text */ + split = g_strsplit (version, ".", -1); + sz = g_strv_length (split); + if (sz == 1) { + if (g_str_has_prefix (version, "0x")) + version += 2; + if (_g_ascii_is_digits (version)) + return FWUPD_VERSION_FORMAT_NUMBER; + return FWUPD_VERSION_FORMAT_PLAIN; + } + + /* check for only-digit semver version */ + for (guint i = 0; split[i] != NULL; i++) { + /* check sections are plain numbers */ + if (!_g_ascii_is_digits (split[i])) + return FWUPD_VERSION_FORMAT_PLAIN; + } + + /* the most common formats */ + if (sz == 2) + return FWUPD_VERSION_FORMAT_PAIR; + if (sz == 3) + return FWUPD_VERSION_FORMAT_TRIPLET; + if (sz == 4) + return FWUPD_VERSION_FORMAT_QUAD; + + /* unknown! */ + return FWUPD_VERSION_FORMAT_UNKNOWN; +} + +static FwupdVersionFormat +fu_common_version_convert_base (FwupdVersionFormat fmt) +{ + if (fmt == FWUPD_VERSION_FORMAT_INTEL_ME || + fmt == FWUPD_VERSION_FORMAT_INTEL_ME2) + return FWUPD_VERSION_FORMAT_QUAD; + if (fmt == FWUPD_VERSION_FORMAT_BCD) + return FWUPD_VERSION_FORMAT_PAIR; + return fmt; +} + +gboolean +fu_common_version_verify_format (const gchar *version, + FwupdVersionFormat fmt, + GError **error) +{ + FwupdVersionFormat fmt_base = fu_common_version_convert_base (fmt); + + /* don't touch */ + if (fmt == FWUPD_VERSION_FORMAT_PLAIN) + return TRUE; + + /* nothing we can check for */ + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) { + g_debug ("not checking %s as no version format set", version); + return TRUE; + } + + /* check the base format */ + if (fu_common_version_guess_format (version) != fmt_base) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "%s is not a valid %s", + version, + fwupd_version_format_to_string (fmt)); + return FALSE; + } + return TRUE; +} + +/** + * fu_common_vercmp: + * @version_a: the release version, e.g. 1.2.3 + * @version_b: the release version, e.g. 1.2.3.1 + * + * Compares version numbers for sorting. + * + * Returns: -1 if a < b, +1 if a > b, 0 if they are equal, and %G_MAXINT on error + * + * Since: 0.3.5 + */ +gint +fu_common_vercmp (const gchar *version_a, const gchar *version_b) +{ + guint longest_split; + g_autofree gchar *str_a = NULL; + g_autofree gchar *str_b = NULL; + g_auto(GStrv) split_a = NULL; + g_auto(GStrv) split_b = NULL; + + /* sanity check */ + if (version_a == NULL || version_b == NULL) + return G_MAXINT; + + /* optimisation */ + if (g_strcmp0 (version_a, version_b) == 0) + return 0; + + /* split into sections, and try to parse */ + str_a = fu_common_version_parse (version_a); + str_b = fu_common_version_parse (version_b); + split_a = g_strsplit (str_a, ".", -1); + split_b = g_strsplit (str_b, ".", -1); + longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b)); + for (guint i = 0; i < longest_split; i++) { + gchar *endptr_a = NULL; + gchar *endptr_b = NULL; + gint64 ver_a; + gint64 ver_b; + + /* we lost or gained a dot */ + if (split_a[i] == NULL) + return -1; + if (split_b[i] == NULL) + return 1; + + /* compare integers */ + ver_a = g_ascii_strtoll (split_a[i], &endptr_a, 10); + ver_b = g_ascii_strtoll (split_b[i], &endptr_b, 10); + if (ver_a < ver_b) + return -1; + if (ver_a > ver_b) + return 1; + + /* compare strings */ + if ((endptr_a != NULL && endptr_a[0] != '\0') || + (endptr_b != NULL && endptr_b[0] != '\0')) { + gint rc = fu_common_vercmp_chunk (endptr_a, endptr_b); + if (rc < 0) + return -1; + if (rc > 0) + return 1; + } + } + + /* we really shouldn't get here */ + return 0; +} diff -Nru fwupd-1.0.6/src/fu-common-version.h fwupd-1.2.10/src/fu-common-version.h --- fwupd-1.0.6/src/fu-common-version.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-common-version.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +gint fu_common_vercmp (const gchar *version_a, + const gchar *version_b); +gchar *fu_common_version_from_uint32 (guint32 val, + FwupdVersionFormat kind); +gchar *fu_common_version_from_uint16 (guint16 val, + FwupdVersionFormat kind); +gchar *fu_common_version_parse (const gchar *version); +gchar *fu_common_version_ensure_semver (const gchar *version); +FwupdVersionFormat fu_common_version_guess_format (const gchar *version); +gboolean fu_common_version_verify_format (const gchar *version, + FwupdVersionFormat fmt, + GError **error); +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-config.c fwupd-1.2.10/src/fu-config.c --- fwupd-1.0.6/src/fu-config.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-config.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,31 +1,22 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuConfig" + #include "config.h" +#include #include #include +#include +#include "fu-common.h" #include "fu-config.h" +#include "fwupd-common.h" #include "fwupd-error.h" #include "fwupd-remote-private.h" @@ -39,7 +30,12 @@ GPtrArray *monitors; GPtrArray *blacklist_devices; GPtrArray *blacklist_plugins; + GPtrArray *approved_firmware; guint64 archive_size_max; + guint idle_timeout; + XbSilo *silo; + GHashTable *os_release; + gchar *config_file; }; G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT) @@ -50,7 +46,7 @@ GPtrArray *paths = g_ptr_array_new_with_free_func (g_free); const gchar *remotes_dir; const gchar *system_prefixlibdir = "/usr/lib/fwupd"; - g_autofree gchar *sysconfdir = NULL; + g_autofree gchar *configdir = NULL; /* only set by the self test program */ remotes_dir = g_getenv ("FU_SELF_TEST_REMOTES_DIR"); @@ -60,9 +56,9 @@ } /* use sysconfig, and then fall back to /etc */ - sysconfdir = g_build_filename (FWUPDCONFIGDIR, NULL); - if (g_file_test (sysconfdir, G_FILE_TEST_EXISTS)) - g_ptr_array_add (paths, g_steal_pointer (&sysconfdir)); + configdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG); + if (g_file_test (configdir, G_FILE_TEST_EXISTS)) + g_ptr_array_add (paths, g_steal_pointer (&configdir)); /* add in system-wide locations */ if (g_file_test (system_prefixlibdir, G_FILE_TEST_EXISTS)) @@ -82,7 +78,7 @@ g_autoptr(GError) error = NULL; g_autofree gchar *filename = g_file_get_path (file); g_debug ("%s changed, reloading all configs", filename); - if (!fu_config_load (self, &error)) + if (!fu_config_load (self, FU_CONFIG_LOAD_FLAG_NONE, &error)) g_warning ("failed to rescan config: %s", error->message); } @@ -120,6 +116,54 @@ return TRUE; } +static GString * +fu_config_get_remote_agreement_default (FwupdRemote *self, GError **error) +{ + GString *str = g_string_new (NULL); + + /* this is designed as a fallback; the actual warning should ideally + * come from the LVFS instance that is serving the remote */ + g_string_append_printf (str, "%s\n", + /* TRANSLATORS: show the user a warning */ + _("Your distributor may not have verified any of " + "the firmware updates for compatibility with your " + "system or connected devices.")); + g_string_append_printf (str, "%s\n", + /* TRANSLATORS: show the user a warning */ + _("Enabling this remote is done at your own risk.")); + return str; +} + +static GString * +fu_config_get_remote_agreement_for_app (FwupdRemote *self, XbNode *component, GError **error) +{ + XbNode *n; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error_local = NULL; + + /* manually find the first agreement section */ + n = xb_node_query_first (component, "agreement/agreement_section/description/*", &error_local); + if (n == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No agreement description found: %s", + error_local->message); + return NULL; + } + tmp = xb_node_export (n, XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS, error); + if (tmp == NULL) + return NULL; + return g_string_new (tmp); +} + +static gchar * +fu_config_build_remote_component_id (FwupdRemote *remote) +{ + return g_strdup_printf ("org.freedesktop.fwupd.remotes.%s", + fwupd_remote_get_id (remote)); +} + static gboolean fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **error) { @@ -128,8 +172,10 @@ g_autoptr(GDir) dir = NULL; path_remotes = g_build_filename (path, "remotes.d", NULL); - if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS)) + if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS)) { + g_debug ("path %s does not exist", path_remotes); return TRUE; + } if (!fu_config_add_inotify (self, path_remotes, error)) return FALSE; dir = g_dir_open (path_remotes, 0, error); @@ -159,6 +205,35 @@ if (!fu_config_add_inotify (self, fwupd_remote_get_filename_cache (remote), error)) return FALSE; + /* try to find a custom agreement, falling back to a generic warning */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DOWNLOAD) { + g_autoptr(GString) agreement_markup = NULL; + g_autofree gchar *component_id = fu_config_build_remote_component_id (remote); + g_autoptr(XbNode) component = NULL; + g_autofree gchar *xpath = NULL; + + xpath = g_strdup_printf ("component/id[text()='%s']/..", component_id); + component = xb_silo_query_first (self->silo, xpath, NULL); + if (component != NULL) { + agreement_markup = fu_config_get_remote_agreement_for_app (remote, component, error); + } else { + agreement_markup = fu_config_get_remote_agreement_default (remote, error); + } + if (agreement_markup == NULL) + return FALSE; + + /* replace any dynamic values from os-release */ + tmp = g_hash_table_lookup (self->os_release, "NAME"); + if (tmp == NULL) + tmp = "this distribution"; + fu_common_string_replace (agreement_markup, "$OS_RELEASE:NAME$", tmp); + tmp = g_hash_table_lookup (self->os_release, "BUG_REPORT_URL"); + if (tmp == NULL) + tmp = "https://github.com/hughsie/fwupd/issues"; + fu_common_string_replace (agreement_markup, "$OS_RELEASE:BUG_REPORT_URL$", tmp); + fwupd_remote_set_agreement (remote, agreement_markup->str); + } + /* set mtime */ fwupd_remote_set_mtime (remote, fu_config_get_remote_mtime (self, remote)); g_ptr_array_add (self->remotes, g_steal_pointer (&remote)); @@ -278,28 +353,35 @@ } gboolean -fu_config_load (FuConfig *self, GError **error) +fu_config_modify_and_save (FuConfig *self, const gchar *key, const gchar *value, GError **error) +{ + g_key_file_set_string (self->keyfile, "fwupd", key, value); + return g_key_file_save_to_file (self->keyfile, self->config_file, error); +} + +static gboolean +fu_config_load_from_file (FuConfig *self, const gchar *config_file, + GError **error) { GFileMonitor *monitor; guint64 archive_size_max; - g_autofree gchar *config_file = NULL; + guint idle_timeout; + g_auto(GStrv) approved_firmware = NULL; g_auto(GStrv) devices = NULL; g_auto(GStrv) plugins = NULL; g_autoptr(GFile) file = NULL; - - g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); + g_autofree gchar *domains = NULL; /* ensure empty in case we're called from a monitor change */ g_ptr_array_set_size (self->blacklist_devices, 0); g_ptr_array_set_size (self->blacklist_plugins, 0); + g_ptr_array_set_size (self->approved_firmware, 0); g_ptr_array_set_size (self->monitors, 0); g_ptr_array_set_size (self->remotes, 0); - /* load the main daemon config file */ - config_file = g_build_filename (FWUPDCONFIGDIR, "daemon.conf", NULL); g_debug ("loading config values from %s", config_file); if (!g_key_file_load_from_file (self->keyfile, config_file, - G_KEY_FILE_NONE, error)) + G_KEY_FILE_KEEP_COMMENTS, error)) return FALSE; /* set up a notify watch */ @@ -337,6 +419,19 @@ } } + /* get approved firmware */ + approved_firmware = g_key_file_get_string_list (self->keyfile, + "fwupd", + "ApprovedFirmware", + NULL, /* length */ + NULL); + if (approved_firmware != NULL) { + for (guint i = 0; approved_firmware[i] != NULL; i++) { + g_ptr_array_add (self->approved_firmware, + g_strdup (approved_firmware[i])); + } + } + /* get maximum archive size, defaulting to something sane */ archive_size_max = g_key_file_get_uint64 (self->keyfile, "fwupd", @@ -345,6 +440,107 @@ if (archive_size_max > 0) self->archive_size_max = archive_size_max *= 0x100000; + /* get idle timeout */ + idle_timeout = g_key_file_get_uint64 (self->keyfile, + "fwupd", + "IdleTimeout", + NULL); + if (idle_timeout > 0) + self->idle_timeout = idle_timeout; + + /* get the domains to run in verbose */ + domains = g_key_file_get_string (self->keyfile, + "fwupd", + "VerboseDomains", + NULL); + if (domains != NULL && domains[0] != '\0') + g_setenv ("FWUPD_VERBOSE", domains, TRUE); + + return TRUE; +} + +static gboolean +fu_config_load_metainfos (XbBuilder *builder, GError **error) +{ + const gchar *fn; + g_autofree gchar *datadir = NULL; + g_autofree gchar *metainfo_path = NULL; + g_autoptr(GDir) dir = NULL; + + /* pkg metainfo dir */ + datadir = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); + metainfo_path = g_build_filename (datadir, "metainfo", NULL); + if (!g_file_test (metainfo_path, G_FILE_TEST_EXISTS)) + return TRUE; + + g_debug ("loading %s", metainfo_path); + dir = g_dir_open (metainfo_path, 0, error); + if (dir == NULL) + return FALSE; + while ((fn = g_dir_read_name (dir)) != NULL) { + if (g_str_has_suffix (fn, ".metainfo.xml")) { + g_autofree gchar *filename = g_build_filename (metainfo_path, fn, NULL); + g_autoptr(GFile) file = g_file_new_for_path (filename); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return FALSE; + xb_builder_import_source (builder, source); + } + } + return TRUE; +} + +gboolean +fu_config_load (FuConfig *self, FuConfigLoadFlags flags, GError **error) +{ + const gchar *const *locales = g_get_language_names (); + g_autofree gchar *configdir = NULL; + g_autofree gchar *cachedirpkg = NULL; + g_autofree gchar *xmlbfn = NULL; + g_autoptr(GFile) xmlb = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + XbBuilderCompileFlags compile_flags = XB_BUILDER_COMPILE_FLAG_SINGLE_LANG | + XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID; + + g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); + + /* load the main daemon config file */ + configdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG); + self->config_file = g_build_filename (configdir, "daemon.conf", NULL); + if (g_file_test (self->config_file, G_FILE_TEST_EXISTS)) { + if (!fu_config_load_from_file (self, self->config_file, error)) + return FALSE; + } else { + g_warning ("Daemon configuration %s not found", self->config_file); + } + + /* load AppStream about the remotes */ + self->os_release = fwupd_get_os_release (error); + if (self->os_release == NULL) + return FALSE; + if (!fu_config_load_metainfos (builder, error)) + return FALSE; + + /* add the locales, which is really only going to be 'C' or 'en' */ + for (guint i = 0; locales[i] != NULL; i++) + xb_builder_add_locale (builder, locales[i]); + +#if LIBXMLB_CHECK_VERSION(0,1,7) + /* on a read-only filesystem don't care about the cache GUID */ + if (flags & FU_CONFIG_LOAD_FLAG_READONLY_FS) + compile_flags |= XB_BUILDER_COMPILE_FLAG_IGNORE_GUID; +#endif + + /* build the metainfo silo */ + cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + xmlbfn = g_build_filename (cachedirpkg, "metainfo.xmlb", NULL); + xmlb = g_file_new_for_path (xmlbfn); + self->silo = xb_builder_ensure (builder, xmlb, compile_flags, NULL, error); + if (self->silo == NULL) + return FALSE; + /* load remotes */ if (!fu_config_load_remotes (self, error)) return FALSE; @@ -360,6 +556,13 @@ return self->remotes; } +guint +fu_config_get_idle_timeout (FuConfig *self) +{ + g_return_val_if_fail (FU_IS_CONFIG (self), 0); + return self->idle_timeout; +} + FwupdRemote * fu_config_get_remote_by_id (FuConfig *self, const gchar *remote_id) { @@ -388,6 +591,13 @@ return self->blacklist_plugins; } +GPtrArray * +fu_config_get_approved_firmware (FuConfig *self) +{ + g_return_val_if_fail (FU_IS_CONFIG (self), NULL); + return self->approved_firmware; +} + static void fu_config_class_init (FuConfigClass *klass) { @@ -402,6 +612,7 @@ self->keyfile = g_key_file_new (); self->blacklist_devices = g_ptr_array_new_with_free_func (g_free); self->blacklist_plugins = g_ptr_array_new_with_free_func (g_free); + self->approved_firmware = g_ptr_array_new_with_free_func (g_free); self->remotes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); } @@ -411,11 +622,17 @@ { FuConfig *self = FU_CONFIG (obj); + if (self->os_release != NULL) + g_hash_table_unref (self->os_release); + if (self->silo != NULL) + g_object_unref (self->silo); g_key_file_unref (self->keyfile); g_ptr_array_unref (self->blacklist_devices); g_ptr_array_unref (self->blacklist_plugins); + g_ptr_array_unref (self->approved_firmware); g_ptr_array_unref (self->remotes); g_ptr_array_unref (self->monitors); + g_free (self->config_file); G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj); } diff -Nru fwupd-1.0.6/src/fu-config.h fwupd-1.2.10/src/fu-config.h --- fwupd-1.0.6/src/fu-config.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-config.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,48 +1,50 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_CONFIG_H -#define __FU_CONFIG_H - -G_BEGIN_DECLS +#pragma once #include #include "fwupd-remote.h" +G_BEGIN_DECLS + #define FU_TYPE_CONFIG (fu_config_get_type ()) G_DECLARE_FINAL_TYPE (FuConfig, fu_config, FU, CONFIG, GObject) +/** + * FuConfigLoadFlags: + * @FU_CONFIG_LOAD_FLAG_NONE: No flags set + * @FU_CONFIG_LOAD_FLAG_READONLY_FS: Ignore readonly filesystem errors + * + * The flags to use when loading a configuration file. + **/ +typedef enum { + FU_CONFIG_LOAD_FLAG_NONE = 0, + FU_CONFIG_LOAD_FLAG_READONLY_FS = 1 << 0, + /*< private >*/ + FU_CONFIG_LOAD_FLAG_LAST +} FuConfigLoadFlags; + FuConfig *fu_config_new (void); gboolean fu_config_load (FuConfig *self, + FuConfigLoadFlags flags, + GError **error); +gboolean fu_config_modify_and_save (FuConfig *self, + const gchar *key, + const gchar *value, GError **error); guint64 fu_config_get_archive_size_max (FuConfig *self); +guint fu_config_get_idle_timeout (FuConfig *self); GPtrArray *fu_config_get_blacklist_devices (FuConfig *self); GPtrArray *fu_config_get_blacklist_plugins (FuConfig *self); +GPtrArray *fu_config_get_approved_firmware (FuConfig *self); GPtrArray *fu_config_get_remotes (FuConfig *self); FwupdRemote *fu_config_get_remote_by_id (FuConfig *self, const gchar *remote_id); G_END_DECLS - -#endif /* __FU_CONFIG_H */ - diff -Nru fwupd-1.0.6/src/fu-debug.c fwupd-1.2.10/src/fu-debug.c --- fwupd-1.0.6/src/fu-debug.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-debug.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2010-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuDebug" + #include #include #include @@ -27,35 +14,47 @@ #include typedef struct { + GOptionGroup *group; gboolean verbose; gboolean console; gchar **plugin_verbose; + gchar **daemon_verbose; } FuDebug; static void fu_debug_free (FuDebug *self) { + g_option_group_set_parse_hooks (self->group, NULL, NULL); + g_option_group_unref (self->group); g_strfreev (self->plugin_verbose); + g_strfreev (self->daemon_verbose); g_free (self); } -static void -fu_debug_ignore_cb (const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data) +static gboolean +fu_debug_filter_cb (FuDebug *self, const gchar *log_domain, GLogLevelFlags log_level) { - /* syslog */ - switch (log_level) { - case G_LOG_LEVEL_INFO: - case G_LOG_LEVEL_CRITICAL: - case G_LOG_LEVEL_ERROR: - case G_LOG_LEVEL_WARNING: - g_print ("%s\n", message); - break; - default: - break; + const gchar *domains = g_getenv ("FWUPD_VERBOSE"); + g_auto(GStrv) domains_str = NULL; + + /* include important things by default only */ + if (domains == NULL) { + if (log_level == G_LOG_LEVEL_INFO || + log_level == G_LOG_LEVEL_CRITICAL || + log_level == G_LOG_LEVEL_WARNING || + log_level == G_LOG_LEVEL_ERROR) { + return TRUE; + } + return FALSE; } + + /* everything */ + if (g_strcmp0 (domains, "*") == 0) + return TRUE; + + /* filter on domain */ + domains_str = g_strsplit (domains, ",", -1); + return g_strv_contains ((const gchar * const *) domains_str, log_domain); } static void @@ -69,6 +68,10 @@ g_autoptr(GDateTime) dt = g_date_time_new_now_utc (); g_autoptr(GString) domain = NULL; + /* should ignore */ + if (!fu_debug_filter_cb (self, log_domain, log_level)) + return; + /* time header */ tmp = g_strdup_printf ("%02i:%02i:%02i:%04i", g_date_time_get_hour (dt), @@ -76,21 +79,21 @@ g_date_time_get_second (dt), g_date_time_get_microsecond (dt) / 1000); - /* make these shorter */ - if (g_str_has_prefix (log_domain, "FuPlugin")) - log_domain += 8; + /* each file should have set this */ + if (log_domain == NULL) + log_domain = "FIXME"; /* pad out domain */ domain = g_string_new (log_domain); - for (gsize i = domain->len; i < 3; i++) + for (gsize i = domain->len; i < 20; i++) g_string_append (domain, " "); /* to file */ if (!self->console) { if (tmp != NULL) - g_print ("%s ", tmp); - g_print ("%s ", domain->str); - g_print ("%s\n", message); + g_printerr ("%s ", tmp); + g_printerr ("%s ", domain->str); + g_printerr ("%s\n", message); return; } @@ -101,16 +104,16 @@ case G_LOG_LEVEL_WARNING: /* critical in red */ if (tmp != NULL) - g_print ("%c[%dm%s ", 0x1B, 32, tmp); - g_print ("%s ", domain->str); - g_print ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0); + g_printerr ("%c[%dm%s ", 0x1B, 32, tmp); + g_printerr ("%s ", domain->str); + g_printerr ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0); break; default: /* debug in blue */ if (tmp != NULL) - g_print ("%c[%dm%s ", 0x1B, 32, tmp); - g_print ("%s ", domain->str); - g_print ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0); + g_printerr ("%c[%dm%s ", 0x1B, 32, tmp); + g_printerr ("%s ", domain->str); + g_printerr ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0); break; } } @@ -125,10 +128,13 @@ const GOptionEntry main_entries[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &self->verbose, /* TRANSLATORS: turn on all debugging */ - N_("Show debugging information for all files"), NULL }, + N_("Show debugging information for all domains"), NULL }, { "plugin-verbose", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &self->plugin_verbose, /* TRANSLATORS: this is for plugin development */ N_("Show plugin verbose information"), "PLUGIN-NAME" }, + { "daemon-verbose", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &self->daemon_verbose, + /* TRANSLATORS: this is for daemon development */ + N_("Show daemon verbose information for a particular domain"), "DOMAIN" }, { NULL} }; @@ -147,18 +153,18 @@ /* verbose? */ if (self->verbose) { - g_setenv ("FWUPD_VERBOSE", "1", TRUE); - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | - G_LOG_LEVEL_CRITICAL); - g_log_set_default_handler (fu_debug_handler_cb, self); - } else { - /* hide all debugging */ - g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - fu_debug_ignore_cb, self); + g_setenv ("FWUPD_VERBOSE", "*", TRUE); + } else if (self->daemon_verbose != NULL) { + g_autofree gchar *str = g_strjoinv (",", self->daemon_verbose); + g_setenv ("FWUPD_VERBOSE", str, TRUE); } + /* redirect all domains to be able to change FWUPD_VERBOSE at runtime */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_MASK); + g_log_set_default_handler (fu_debug_handler_cb, self); + /* are we on an actual TTY? */ - self->console = (isatty (fileno (stdout)) == 1); + self->console = (isatty (fileno (stderr)) == 1); g_debug ("Verbose debugging %s (on console %i)", self->verbose ? "enabled" : "disabled", self->console); @@ -176,19 +182,19 @@ return TRUE; } +/*(transfer): full */ GOptionGroup * fu_debug_get_option_group (void) { - GOptionGroup *group; FuDebug *self = g_new0 (FuDebug, 1); - group = g_option_group_new ("debug", - /* TRANSLATORS: for the --verbose arg */ - _("Debugging Options"), - /* TRANSLATORS: for the --verbose arg */ - _("Show debugging options"), - self, (GDestroyNotify) fu_debug_free); - g_option_group_set_parse_hooks (group, + self->group = g_option_group_new ("debug", + /* TRANSLATORS: for the --verbose arg */ + _("Debugging Options"), + /* TRANSLATORS: for the --verbose arg */ + _("Show debugging options"), + self, (GDestroyNotify) fu_debug_free); + g_option_group_set_parse_hooks (self->group, fu_debug_pre_parse_hook, fu_debug_post_parse_hook); - return group; + return g_option_group_ref (self->group); } diff -Nru fwupd-1.0.6/src/fu-debug.h fwupd-1.2.10/src/fu-debug.h --- fwupd-1.0.6/src/fu-debug.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-debug.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2010-2011 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEBUG_H__ -#define __FU_DEBUG_H__ +#pragma once #include +G_BEGIN_DECLS + GOptionGroup *fu_debug_get_option_group (void); -#endif /* __FU_DEBUG_H__ */ +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-device.c fwupd-1.2.10/src/fu-device.c --- fwupd-1.0.6/src/fu-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,32 +1,24 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2015-2018 Richard Hughes * - * Copyright (C) 2015 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuDevice" + #include "config.h" #include -#include #include #include +#include "fu-common.h" +#include "fu-common-version.h" #include "fu-device-private.h" +#include "fu-mutex.h" + +#include "fwupd-common.h" +#include "fwupd-device-private.h" /** * SECTION:fu-device @@ -40,20 +32,35 @@ static void fu_device_finalize (GObject *object); typedef struct { + gchar *alternate_id; gchar *equivalent_id; FuDevice *alternate; + FuDevice *parent; /* noref */ FuQuirks *quirks; GHashTable *metadata; + GRWLock metadata_mutex; + GPtrArray *parent_guids; + GRWLock parent_guids_mutex; + GPtrArray *children; guint remove_delay; /* ms */ FwupdStatus status; guint progress; + guint order; + guint priority; + guint poll_id; + gboolean done_probe; + gboolean done_setup; + guint64 size_min; + guint64 size_max; + gint open_refcount; /* atomic */ } FuDevicePrivate; enum { PROP_0, PROP_STATUS, PROP_PROGRESS, - PROP_PLATFORM_ID, + PROP_PHYSICAL_ID, + PROP_LOGICAL_ID, PROP_QUIRKS, PROP_LAST }; @@ -65,8 +72,8 @@ fu_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - FuDevice *device = FU_DEVICE (object); - FuDevicePrivate *priv = GET_PRIVATE (device); + FuDevice *self = FU_DEVICE (object); + FuDevicePrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_STATUS: g_value_set_uint (value, priv->status); @@ -74,8 +81,11 @@ case PROP_PROGRESS: g_value_set_uint (value, priv->progress); break; - case PROP_PLATFORM_ID: - g_value_set_string (value, fu_device_get_platform_id (device)); + case PROP_PHYSICAL_ID: + g_value_set_string (value, fu_device_get_physical_id (self)); + break; + case PROP_LOGICAL_ID: + g_value_set_string (value, fu_device_get_logical_id (self)); break; case PROP_QUIRKS: g_value_set_object (value, priv->quirks); @@ -90,19 +100,22 @@ fu_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - FuDevice *device = FU_DEVICE (object); + FuDevice *self = FU_DEVICE (object); switch (prop_id) { case PROP_STATUS: - fu_device_set_status (device, g_value_get_uint (value)); + fu_device_set_status (self, g_value_get_uint (value)); break; case PROP_PROGRESS: - fu_device_set_progress (device, g_value_get_uint (value)); + fu_device_set_progress (self, g_value_get_uint (value)); + break; + case PROP_PHYSICAL_ID: + fu_device_set_physical_id (self, g_value_get_string (value)); break; - case PROP_PLATFORM_ID: - fu_device_set_platform_id (device, g_value_get_string (value)); + case PROP_LOGICAL_ID: + fu_device_set_logical_id (self, g_value_get_string (value)); break; case PROP_QUIRKS: - fu_device_set_quirks (device, g_value_get_object (value)); + fu_device_set_quirks (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -110,88 +123,878 @@ } } +/** + * fu_device_poll: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Polls a device, typically querying the hardware for status. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_poll (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* subclassed */ + if (klass->poll != NULL) { + if (!klass->poll (self, error)) + return FALSE; + } + return TRUE; +} + +static gboolean +fu_device_poll_cb (gpointer user_data) +{ + FuDevice *self = FU_DEVICE (user_data); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GError) error_local = NULL; + if (!fu_device_poll (self, &error_local)) { + g_warning ("disabling polling: %s", error_local->message); + priv->poll_id = 0; + return G_SOURCE_REMOVE; + } + return G_SOURCE_CONTINUE; +} + +/** + * fu_device_set_poll_interval: + * @self: a #FuPlugin + * @interval: duration in ms, or 0 to disable + * + * Polls the hardware every interval period. If the subclassed `->poll()` method + * returns %FALSE then a warning is printed to the console and the poll is + * disabled until the next call to fu_device_set_poll_interval(). + * + * Since: 1.1.2 + **/ +void +fu_device_set_poll_interval (FuDevice *self, guint interval) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FU_IS_DEVICE (self)); + + if (priv->poll_id != 0) { + g_source_remove (priv->poll_id); + priv->poll_id = 0; + } + if (interval == 0) + return; + if (interval % 1000 == 0) { + priv->poll_id = g_timeout_add_seconds (interval / 1000, + fu_device_poll_cb, + self); + } else { + priv->poll_id = g_timeout_add (interval, fu_device_poll_cb, self); + } +} + +/** + * fu_device_get_order: + * @self: a #FuPlugin + * + * Gets the device order, where higher numbers are installed after lower + * numbers. + * + * Returns: the integer value + * + * Since: 1.0.8 + **/ +guint +fu_device_get_order (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->order; +} + +/** + * fu_device_set_order: + * @self: a #FuDevice + * @order: a integer value + * + * Sets the device order, where higher numbers are installed after lower + * numbers. + * + * Since: 1.0.8 + **/ +void +fu_device_set_order (FuDevice *self, guint order) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->order = order; +} + +/** + * fu_device_get_priority: + * @self: a #FuPlugin + * + * Gets the device priority, where higher numbers are better. + * + * Returns: the integer value + * + * Since: 1.1.1 + **/ +guint +fu_device_get_priority (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->priority; +} + +/** + * fu_device_set_priority: + * @self: a #FuDevice + * @priority: a integer value + * + * Sets the device priority, where higher numbers are better. + * + * Since: 1.1.1 + **/ +void +fu_device_set_priority (FuDevice *self, guint priority) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->priority = priority; +} + const gchar * -fu_device_get_equivalent_id (FuDevice *device) +fu_device_get_equivalent_id (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); return priv->equivalent_id; } void -fu_device_set_equivalent_id (FuDevice *device, const gchar *equivalent_id) +fu_device_set_equivalent_id (FuDevice *self, const gchar *equivalent_id) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); g_free (priv->equivalent_id); priv->equivalent_id = g_strdup (equivalent_id); } /** * fu_device_get_alternate: - * @device: A #FuDevice + * @self: A #FuDevice + * + * Gets any alternate device ID. An alternate device may be linked to the primary + * device in some way. + * + * Returns: (transfer none): a #FuDevice or %NULL + * + * Since: 1.1.0 + **/ +const gchar * +fu_device_get_alternate_id (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return priv->alternate_id; +} + +/** + * fu_device_set_alternate: + * @self: A #FuDevice + * @alternate: Another #FuDevice + * + * Sets any alternate device ID. An alternate device may be linked to the primary + * device in some way. + * + * Since: 1.1.0 + **/ +void +fu_device_set_alternate_id (FuDevice *self, const gchar *alternate_id) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + g_free (priv->alternate_id); + priv->alternate_id = g_strdup (alternate_id); +} + +/** + * fu_device_get_alternate: + * @self: A #FuDevice * * Gets any alternate device. An alternate device may be linked to the primary * device in some way. * + * The alternate object will be matched from the ID set in fu_device_set_alternate_id() + * and will be assigned by the daemon. This means if the ID is not found as an + * added device, then this function will return %NULL. + * * Returns: (transfer none): a #FuDevice or %NULL * * Since: 0.7.2 **/ FuDevice * -fu_device_get_alternate (FuDevice *device) +fu_device_get_alternate (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); return priv->alternate; } /** * fu_device_set_alternate: - * @device: A #FuDevice + * @self: A #FuDevice * @alternate: Another #FuDevice * * Sets any alternate device. An alternate device may be linked to the primary * device in some way. * + * This function is only usable by the daemon, not directly from plugins. + * * Since: 0.7.2 **/ void -fu_device_set_alternate (FuDevice *device, FuDevice *alternate) +fu_device_set_alternate (FuDevice *self, FuDevice *alternate) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); g_set_object (&priv->alternate, alternate); } /** + * fu_device_get_parent: + * @self: A #FuDevice + * + * Gets any parent device. An parent device is logically "above" the current + * device and this may be reflected in client tools. + * + * This information also allows the plugin to optionally verify the parent + * device, for instance checking the parent device firmware version. + * + * The parent object is not refcounted and if destroyed this function will then + * return %NULL. + * + * Returns: (transfer none): a #FuDevice or %NULL + * + * Since: 1.0.8 + **/ +FuDevice * +fu_device_get_parent (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return priv->parent; +} + +void +fu_device_set_parent (FuDevice *self, FuDevice *parent) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FU_IS_DEVICE (self)); + + g_object_add_weak_pointer (G_OBJECT (parent), (gpointer *) &priv->parent); + priv->parent = parent; + + /* this is what goes over D-Bus */ + fwupd_device_set_parent_id (FWUPD_DEVICE (self), + parent != NULL ? fu_device_get_id (parent) : NULL); +} + +/** + * fu_device_get_children: + * @self: A #FuDevice + * + * Gets any child devices. A child device is logically "below" the current + * device and this may be reflected in client tools. + * + * Returns: (transfer none) (element-type FuDevice): child devices + * + * Since: 1.0.8 + **/ +GPtrArray * +fu_device_get_children (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return priv->children; +} + +/** + * fu_device_add_child: + * @self: A #FuDevice + * @child: Another #FuDevice + * + * Sets any child device. An child device is logically linked to the primary + * device in some way. + * + * Since: 1.0.8 + **/ +void +fu_device_add_child (FuDevice *self, FuDevice *child) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (FU_IS_DEVICE (child)); + + /* add if the child does not already exist */ + for (guint i = 0; i < priv->children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (priv->children, i); + if (devtmp == child) + return; + } + g_ptr_array_add (priv->children, g_object_ref (child)); + + /* copy from main device if unset */ + if (fu_device_get_physical_id (child) == NULL && + fu_device_get_physical_id (self) != NULL) + fu_device_set_physical_id (child, fu_device_get_physical_id (self)); + if (fu_device_get_vendor (child) == NULL) + fu_device_set_vendor (child, fu_device_get_vendor (self)); + if (fu_device_get_vendor_id (child) == NULL) + fu_device_set_vendor_id (child, fu_device_get_vendor_id (self)); + if (fu_device_get_icons(child)->len == 0) { + GPtrArray *icons = fu_device_get_icons (self); + for (guint i = 0; i < icons->len; i++) { + const gchar *icon_name = g_ptr_array_index (icons, i); + fu_device_add_icon (child, icon_name); + } + } + + /* ensure the parent is also set on the child */ + fu_device_set_parent (child, self); + + /* order devices so they are updated in the correct sequence */ + if (fu_device_has_flag (child, FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST)) { + if (priv->order >= fu_device_get_order (child)) + fu_device_set_order (child, priv->order + 1); + } else { + if (priv->order <= fu_device_get_order (child)) + priv->order = fu_device_get_order (child) + 1; + } +} + +/** + * fu_device_get_parent_guids: + * @self: A #FuDevice + * + * Gets any parent device GUIDs. If a device is added to the daemon that matches + * any GUIDs added from fu_device_add_parent_guid() then this device is marked the parent of @self. + * + * Returns: (transfer none) (element-type utf8): a list of GUIDs + * + * Since: 1.0.8 + **/ +GPtrArray * +fu_device_get_parent_guids (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->parent_guids_mutex); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + g_return_val_if_fail (locker != NULL, NULL); + return priv->parent_guids; +} + +/** + * fu_device_has_parent_guid: + * @self: A #FuDevice + * @guid: a GUID + * + * Searches the list of parent GUIDs for a string match. + * + * Returns: %TRUE if the parent GUID exists + * + * Since: 1.0.8 + **/ +gboolean +fu_device_has_parent_guid (FuDevice *self, const gchar *guid) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->parent_guids_mutex); + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (locker != NULL, FALSE); + for (guint i = 0; i < priv->parent_guids->len; i++) { + const gchar *guid_tmp = g_ptr_array_index (priv->parent_guids, i); + if (g_strcmp0 (guid_tmp, guid) == 0) + return TRUE; + } + return FALSE; +} + +/** + * fu_device_add_parent_guid: + * @self: A #FuDevice + * @guid: a GUID + * + * Sets any parent device using a GUID. An parent device is logically linked to + * the primary device in some way and can be added before or after @self. + * + * The GUIDs are searched in order, and so the order of adding GUIDs may be + * important if more than one parent device might match. + * + * If the parent device is removed, any children logically linked to it will + * also be removed. + * + * Since: 1.0.8 + **/ +void +fu_device_add_parent_guid (FuDevice *self, const gchar *guid) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = NULL; + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (guid != NULL); + + /* make valid */ + if (!fwupd_guid_is_valid (guid)) { + g_autofree gchar *tmp = fwupd_guid_hash_string (guid); + if (fu_device_has_parent_guid (self, tmp)) + return; + g_debug ("using %s for %s", tmp, guid); + g_ptr_array_add (priv->parent_guids, g_steal_pointer (&tmp)); + return; + } + + /* already valid */ + if (fu_device_has_parent_guid (self, guid)) + return; + locker = g_rw_lock_writer_locker_new (&priv->parent_guids_mutex); + g_return_if_fail (locker != NULL); + g_ptr_array_add (priv->parent_guids, g_strdup (guid)); +} + +static gboolean +fu_device_add_child_by_type_guid (FuDevice *self, + GType type, + const gchar *guid, + GError **error) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(FuDevice) child = NULL; + child = g_object_new (type, + "quirks", priv->quirks, + "logical-id", guid, + NULL); + fu_device_add_guid (child, guid); + if (fu_device_get_physical_id (self) != NULL) + fu_device_set_physical_id (child, fu_device_get_physical_id (self)); + if (!fu_device_ensure_id (self, error)) + return FALSE; + if (!fu_device_probe (child, error)) + return FALSE; + fu_device_convert_instance_ids (child); + fu_device_add_child (self, child); + return TRUE; +} + +static gboolean +fu_device_add_child_by_kv (FuDevice *self, const gchar *str, GError **error) +{ + g_auto(GStrv) split = g_strsplit (str, "|", -1); + + /* type same as parent */ + if (g_strv_length (split) == 1) { + return fu_device_add_child_by_type_guid (self, + G_OBJECT_TYPE (self), + split[1], + error); + } + + /* type specified */ + if (g_strv_length (split) == 2) { + GType devtype = g_type_from_name (split[0]); + if (devtype == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no GType registered"); + return FALSE; + } + return fu_device_add_child_by_type_guid (self, + devtype, + split[1], + error); + } + + /* more than one '|' */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "unable to add parse child section"); + return FALSE; +} + +static gboolean +fu_device_set_quirk_kv (FuDevice *self, + const gchar *key, + const gchar *value, + GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + if (g_strcmp0 (key, FU_QUIRKS_PLUGIN) == 0) { + fu_device_set_plugin (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_FLAGS) == 0) { + fu_device_set_custom_flags (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_NAME) == 0) { + fu_device_set_name (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_SUMMARY) == 0) { + fu_device_set_summary (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_VENDOR) == 0) { + fu_device_set_vendor (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_VENDOR_ID) == 0) { + fu_device_set_vendor_id (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_VERSION) == 0) { + fu_device_set_version (self, value, fu_device_get_version_format (self)); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_ICON) == 0) { + fu_device_add_icon (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_GUID) == 0) { + fu_device_add_guid (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_COUNTERPART_GUID) == 0) { + fu_device_add_counterpart_guid (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_PARENT_GUID) == 0) { + fu_device_add_parent_guid (self, value); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_FIRMWARE_SIZE_MIN) == 0) { + fu_device_set_firmware_size_min (self, fu_common_strtoull (value)); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_FIRMWARE_SIZE_MAX) == 0) { + fu_device_set_firmware_size_max (self, fu_common_strtoull (value)); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_FIRMWARE_SIZE) == 0) { + fu_device_set_firmware_size (self, fu_common_strtoull (value)); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_INSTALL_DURATION) == 0) { + fu_device_set_install_duration (self, fu_common_strtoull (value)); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_VERSION_FORMAT) == 0) { + fu_device_set_version_format (self, fwupd_version_format_from_string (value)); + return TRUE; + } + if (g_strcmp0 (key, FU_QUIRKS_CHILDREN) == 0) { + g_auto(GStrv) sections = g_strsplit (value, ",", -1); + for (guint i = 0; sections[i] != NULL; i++) { + if (!fu_device_add_child_by_kv (self, sections[i], error)) + return FALSE; + } + return TRUE; + } + + /* optional device-specific method */ + if (klass->set_quirk_kv != NULL) + return klass->set_quirk_kv (self, key, value, error); + + /* failed */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "quirk key not supported"); + return FALSE; +} + +static void +fu_device_add_guid_quirks (FuDevice *self, const gchar *guid) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + const gchar *key; + const gchar *value; + GHashTableIter iter; + + /* not set */ + if (priv->quirks == NULL) + return; + if (!fu_quirks_get_kvs_for_guid (priv->quirks, guid, &iter)) + return; + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) { + g_autoptr(GError) error = NULL; + if (!fu_device_set_quirk_kv (self, key, value, &error)) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { + g_warning ("failed to set quirk key %s=%s: %s", + key, value, error->message); + } + } + } +} + +/** + * fu_device_set_firmware_size: + * @self: A #FuDevice + * @size: Size in bytes + * + * Sets the exact allowed size of the firmware blob. + * + * Since: 1.2.6 + **/ +void +fu_device_set_firmware_size (FuDevice *self, guint64 size) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->size_min = size; + priv->size_max = size; +} + +/** + * fu_device_set_firmware_size_min: + * @self: A #FuDevice + * @size_min: Size in bytes + * + * Sets the minimum allowed size of the firmware blob. + * + * Since: 1.1.2 + **/ +void +fu_device_set_firmware_size_min (FuDevice *self, guint64 size_min) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->size_min = size_min; +} + +/** + * fu_device_set_firmware_size_max: + * @self: A #FuDevice + * @size_max: Size in bytes + * + * Sets the maximum allowed size of the firmware blob. + * + * Since: 1.1.2 + **/ +void +fu_device_set_firmware_size_max (FuDevice *self, guint64 size_max) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->size_max = size_max; +} + +/** + * fu_device_get_firmware_size_min: + * @self: A #FuDevice + * + * Gets the minimum size of the firmware blob. + * + * Returns: Size in bytes, or 0 if unset + * + * Since: 1.2.6 + **/ +guint64 +fu_device_get_firmware_size_min (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->size_min; +} + +/** + * fu_device_get_firmware_size_max: + * @self: A #FuDevice + * + * Gets the maximum size of the firmware blob. + * + * Returns: Size in bytes, or 0 if unset + * + * Since: 1.2.6 + **/ +guint64 +fu_device_get_firmware_size_max (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); + return priv->size_max; +} + +static void +fu_device_add_guid_safe (FuDevice *self, const gchar *guid) +{ + /* add the device GUID before adding additional GUIDs from quirks + * to ensure the bootloader GUID is listed after the runtime GUID */ + fwupd_device_add_guid (FWUPD_DEVICE (self), guid); + fu_device_add_guid_quirks (self, guid); +} + +/** + * fu_device_has_guid: + * @self: A #FuDevice + * @guid: A GUID, e.g. `WacomAES` + * + * Finds out if the device has a specific GUID. + * + * Returns: %TRUE if the GUID is found + * + * Since: 1.2.2 + **/ +gboolean +fu_device_has_guid (FuDevice *self, const gchar *guid) +{ + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (guid != NULL, FALSE); + + /* make valid */ + if (!fwupd_guid_is_valid (guid)) { + g_autofree gchar *tmp = fwupd_guid_hash_string (guid); + return fwupd_device_has_guid (FWUPD_DEVICE (self), tmp); + } + + /* already valid */ + return fwupd_device_has_guid (FWUPD_DEVICE (self), guid); +} + +/* private */ +void +fu_device_add_instance_id_full (FuDevice *self, + const gchar *instance_id, + FuDeviceInstanceFlags flags) +{ + g_autofree gchar *guid = NULL; + if (fwupd_guid_is_valid (instance_id)) { + g_warning ("use fu_device_add_guid(\"%s\") instead!", instance_id); + fu_device_add_guid_safe (self, instance_id); + return; + } + + /* it seems odd adding the instance ID and the GUID quirks and not just + * calling fu_device_add_guid_safe() -- but we want the quirks to match + * so the plugin is set, but not the LVFS metadata to match firmware + * until we're sure the device isn't using _NO_AUTO_INSTANCE_IDS */ + guid = fwupd_guid_hash_string (instance_id); + fu_device_add_guid_quirks (self, guid); + if ((flags & FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS) == 0) + fwupd_device_add_instance_id (FWUPD_DEVICE (self), instance_id); +} + +/** + * fu_device_add_instance_id: + * @self: A #FuDevice + * @instance_id: the InstanceID, e.g. `PCI\VEN_10EC&DEV_525A` + * + * Adds an instance ID to the device. If the @instance_id argument is already a + * valid GUID then fu_device_add_guid() should be used instead. + * + * Since: 1.2.5 + **/ +void +fu_device_add_instance_id (FuDevice *self, const gchar *instance_id) +{ + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (instance_id != NULL); + fu_device_add_instance_id_full (self, instance_id, FU_DEVICE_INSTANCE_FLAG_NONE); +} + +/** * fu_device_add_guid: - * @device: A #FuDevice + * @self: A #FuDevice * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fwupd_guid_hash_string(). * * Since: 0.7.2 **/ void -fu_device_add_guid (FuDevice *device, const gchar *guid) +fu_device_add_guid (FuDevice *self, const gchar *guid) { + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (guid != NULL); + if (!fwupd_guid_is_valid (guid)) { + fu_device_add_instance_id (self, guid); + return; + } + fu_device_add_guid_safe (self, guid); +} + +/** + * fu_device_add_counterpart_guid: + * @self: A #FuDevice + * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` + * + * Adds a GUID to the device. If the @guid argument is not a valid GUID then it + * is converted to a GUID using fwupd_guid_hash_string(). + * + * A counterpart GUID is typically the GUID of the same device in bootloader + * or runtime mode, if they have a different device PCI or USB ID. Adding this + * type of GUID does not cause a "cascade" by matching using the quirk database. + * + * Since: 1.1.2 + **/ +void +fu_device_add_counterpart_guid (FuDevice *self, const gchar *guid) +{ + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (guid != NULL); + /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); - g_debug ("using %s for %s", tmp, guid); - fwupd_device_add_guid (FWUPD_DEVICE (device), tmp); + if (!fwupd_guid_is_valid (guid)) { + g_autofree gchar *tmp = fwupd_guid_hash_string (guid); + fwupd_device_add_guid (FWUPD_DEVICE (self), tmp); return; } /* already valid */ - fwupd_device_add_guid (FWUPD_DEVICE (device), guid); + fwupd_device_add_guid (FWUPD_DEVICE (self), guid); +} + +/** + * fu_device_get_guids_as_str: + * @self: A #FuDevice + * + * Gets the device GUIDs as a joined string, which may be useful for error + * messages. + * + * Returns: a string, which may be empty length but not %NULL + * + * Since: 1.0.8 + **/ +gchar * +fu_device_get_guids_as_str (FuDevice *self) +{ + GPtrArray *guids; + g_autofree gchar **tmp = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + + guids = fu_device_get_guids (self); + tmp = g_new0 (gchar *, guids->len + 1); + for (guint i = 0; i < guids->len; i++) + tmp[i] = g_ptr_array_index (guids, i); + return g_strjoinv (",", tmp); } /** * fu_device_get_metadata: - * @device: A #FuDevice + * @self: A #FuDevice * @key: the key * * Gets an item of metadata from the device. @@ -201,17 +1004,19 @@ * Since: 0.1.0 **/ const gchar * -fu_device_get_metadata (FuDevice *device, const gchar *key) +fu_device_get_metadata (FuDevice *self, const gchar *key) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->metadata_mutex); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (locker != NULL, NULL); return g_hash_table_lookup (priv->metadata, key); } /** * fu_device_get_metadata_boolean: - * @device: A #FuDevice + * @self: A #FuDevice * @key: the key * * Gets an item of metadata from the device. @@ -221,12 +1026,16 @@ * Since: 0.9.7 **/ gboolean -fu_device_get_metadata_boolean (FuDevice *device, const gchar *key) +fu_device_get_metadata_boolean (FuDevice *self, const gchar *key) { - FuDevicePrivate *priv = GET_PRIVATE (device); + FuDevicePrivate *priv = GET_PRIVATE (self); const gchar *tmp; - g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->metadata_mutex); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (locker != NULL, FALSE); + tmp = g_hash_table_lookup (priv->metadata, key); if (tmp == NULL) return FALSE; @@ -235,7 +1044,7 @@ /** * fu_device_get_metadata_integer: - * @device: A #FuDevice + * @self: A #FuDevice * @key: the key * * Gets an item of metadata from the device. @@ -245,15 +1054,17 @@ * Since: 0.9.7 **/ guint -fu_device_get_metadata_integer (FuDevice *device, const gchar *key) +fu_device_get_metadata_integer (FuDevice *self, const gchar *key) { - FuDevicePrivate *priv = GET_PRIVATE (device); + FuDevicePrivate *priv = GET_PRIVATE (self); const gchar *tmp; gchar *endptr = NULL; guint64 val; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->metadata_mutex); - g_return_val_if_fail (FU_IS_DEVICE (device), G_MAXUINT); + g_return_val_if_fail (FU_IS_DEVICE (self), G_MAXUINT); g_return_val_if_fail (key != NULL, G_MAXUINT); + g_return_val_if_fail (locker != NULL, G_MAXUINT); tmp = g_hash_table_lookup (priv->metadata, key); if (tmp == NULL) @@ -268,7 +1079,7 @@ /** * fu_device_set_metadata: - * @device: A #FuDevice + * @self: A #FuDevice * @key: the key * @value: the string value * @@ -277,18 +1088,20 @@ * Since: 0.1.0 **/ void -fu_device_set_metadata (FuDevice *device, const gchar *key, const gchar *value) +fu_device_set_metadata (FuDevice *self, const gchar *key, const gchar *value) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->metadata_mutex); + g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); + g_return_if_fail (locker != NULL); g_hash_table_insert (priv->metadata, g_strdup (key), g_strdup (value)); } /** * fu_device_set_metadata_boolean: - * @device: A #FuDevice + * @self: A #FuDevice * @key: the key * @value: the boolean value * @@ -298,14 +1111,17 @@ * Since: 0.9.7 **/ void -fu_device_set_metadata_boolean (FuDevice *device, const gchar *key, gboolean value) +fu_device_set_metadata_boolean (FuDevice *self, const gchar *key, gboolean value) { - fu_device_set_metadata (device, key, value ? "true" : "false"); + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (key != NULL); + + fu_device_set_metadata (self, key, value ? "true" : "false"); } /** * fu_device_set_metadata_integer: - * @device: A #FuDevice + * @self: A #FuDevice * @key: the key * @value: the unsigned integer value * @@ -315,15 +1131,19 @@ * Since: 0.9.7 **/ void -fu_device_set_metadata_integer (FuDevice *device, const gchar *key, guint value) +fu_device_set_metadata_integer (FuDevice *self, const gchar *key, guint value) { g_autofree gchar *tmp = g_strdup_printf ("%u", value); - fu_device_set_metadata (device, key, tmp); + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (key != NULL); + + fu_device_set_metadata (self, key, tmp); } /** * fu_device_set_name: - * @device: A #FuDevice + * @self: A #FuDevice * @value: a device name * * Sets the name on the device. Any invalid parts will be converted or removed. @@ -331,33 +1151,38 @@ * Since: 0.7.1 **/ void -fu_device_set_name (FuDevice *device, const gchar *value) +fu_device_set_name (FuDevice *self, const gchar *value) { g_autoptr(GString) new = g_string_new (value); + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (value != NULL); + /* overwriting? */ - if (g_strcmp0 (value, fu_device_get_name (device)) == 0) { - g_warning ("device %s overwriting same name value: %s", - fu_device_get_id (device), value); + if (g_strcmp0 (value, fu_device_get_name (self)) == 0) { + const gchar *id = fu_device_get_id (self); + g_debug ("%s device overwriting same name value: %s", + id != NULL ? id : "unknown", value); return; } /* changing */ - if (fu_device_get_name (device) != NULL) { - g_debug ("device %s overwriting name value: %s->%s", - fu_device_get_id (device), - fu_device_get_name (device), + if (fu_device_get_name (self) != NULL) { + const gchar *id = fu_device_get_id (self); + g_debug ("%s device overwriting name value: %s->%s", + id != NULL ? id : "unknown", + fu_device_get_name (self), value); } g_strdelimit (new->str, "_", ' '); - as_utils_string_replace (new, "(TM)", "™"); - fwupd_device_set_name (FWUPD_DEVICE (device), new->str); + fu_common_string_replace (new, "(TM)", "™"); + fwupd_device_set_name (FWUPD_DEVICE (self), new->str); } /** * fu_device_set_id: - * @device: A #FuDevice + * @self: A #FuDevice * @id: a string, e.g. `tbt-port1` * * Sets the ID on the device. The ID should represent the *connection* of the @@ -371,127 +1196,281 @@ * Since: 0.7.1 **/ void -fu_device_set_id (FuDevice *device, const gchar *id) +fu_device_set_id (FuDevice *self, const gchar *id) { + FuDevicePrivate *priv = GET_PRIVATE (self); g_autofree gchar *id_hash = NULL; - g_return_if_fail (FU_IS_DEVICE (device)); + + g_return_if_fail (FU_IS_DEVICE (self)); g_return_if_fail (id != NULL); + id_hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, id, -1); g_debug ("using %s for %s", id_hash, id); - fwupd_device_set_id (FWUPD_DEVICE (device), id_hash); + fwupd_device_set_id (FWUPD_DEVICE (self), id_hash); + + /* ensure the parent ID is set */ + for (guint i = 0; i < priv->children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (priv->children, i); + fwupd_device_set_parent_id (FWUPD_DEVICE (devtmp), id_hash); + } } /** - * fu_device_set_serial: - * @device: A #FuDevice - * @serial: a serial number string, e.g. `0000123` + * fu_device_set_version: + * @self: A #FuDevice + * @version: a string, e.g. `1.2.3` + * @fmt: a #FwupdVersionFormat, e.g. %FWUPD_VERSION_FORMAT_TRIPLET * - * Sets the serial number for the device. + * Sets the device version, sanitizing the string if required. * - * Since: 1.0.3 + * Since: 1.2.9 **/ void -fu_device_set_serial (FuDevice *device, const gchar *serial) +fu_device_set_version (FuDevice *self, const gchar *version, FwupdVersionFormat fmt) { - g_return_if_fail (FU_IS_DEVICE (device)); - g_return_if_fail (serial != NULL); - fu_device_set_metadata (device, "serial", serial); + g_autofree gchar *version_safe = NULL; + g_autoptr(GError) error = NULL; + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (version != NULL); + + /* sanitize if required */ + if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_ENSURE_SEMVER)) { + version_safe = fu_common_version_ensure_semver (version); + if (g_strcmp0 (version, version_safe) != 0) + g_debug ("converted '%s' to '%s'", version, version_safe); + } else { + version_safe = g_strdup (version); + } + + /* print a console warning for an invalid version, if semver */ + if (!fu_common_version_verify_format (version_safe, fmt, &error)) + g_warning ("%s", error->message); + + fu_device_set_version_format (self, fmt); + fwupd_device_set_version (FWUPD_DEVICE (self), version_safe); } /** - * fu_device_get_serial: - * @device: A #FuDevice + * fu_device_ensure_id: + * @self: A #FuDevice + * @error: A #GError * - * Gets the serial number for the device. + * If not already set, generates a device ID with the optional physical and + * logical IDs. + * + * Returns: %TRUE on success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_ensure_id (FuDevice *self, GError **error) +{ + g_autofree gchar *device_id = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already set */ + if (fu_device_get_id (self) != NULL) + return TRUE; + + /* nothing we can do! */ + if (fu_device_get_physical_id (self) == NULL) { + g_autofree gchar *tmp = fu_device_to_string (self); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "cannot ensure ID: %s", tmp); + return FALSE; + } + + /* logical may be NULL */ + device_id = g_strjoin (":", + fu_device_get_physical_id (self), + fu_device_get_logical_id (self), + NULL); + fu_device_set_id (self, device_id); + return TRUE; +} + +/** + * fu_device_get_logical_id: + * @self: A #FuDevice + * + * Gets the logical ID set for the device, which disambiguates devices with the + * same physical ID. + * + * Returns: a string value, or %NULL if never set. + * + * Since: 1.1.2 + **/ +const gchar * +fu_device_get_logical_id (FuDevice *self) +{ + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return fu_device_get_metadata (self, "logical-id"); +} + +/** + * fu_device_set_logical_id: + * @self: A #FuDevice + * @logical_id: a string, e.g. `dev2` * - * Returns: a string value, or %NULL if never set. + * Sets the logical ID on the device. This is designed to disambiguate devices + * with the same physical ID. * - * Since: 1.0.3 + * Since: 1.1.2 **/ -const gchar * -fu_device_get_serial (FuDevice *device) +void +fu_device_set_logical_id (FuDevice *self, const gchar *logical_id) { - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); - return fu_device_get_metadata (device, "serial"); + g_return_if_fail (FU_IS_DEVICE (self)); + fu_device_set_metadata (self, "logical-id", logical_id); } /** - * fu_device_set_plugin_hints: - * @device: A #FuDevice - * @plugin_hints: a string + * fu_device_set_physical_id: + * @self: A #FuDevice + * @physical_id: a string that identifies the physical device connection * - * Sets the hint the the plugin from the quirk system that can be used to - * do affect device matching. The actual string format is defined by the plugin. + * Sets the physical ID on the device which represents the electrical connection + * of the device to the system. Multiple #FuDevices can share a physical ID. * - * Since: 1.0.3 + * The physical ID is used to remove logical devices when a physical device has + * been removed from the system. + * + * A sysfs or devpath is not a physical ID, but could be something like + * `PCI_SLOT_NAME=0000:3e:00.0`. + * + * Since: 1.1.2 **/ void -fu_device_set_plugin_hints (FuDevice *device, const gchar *plugin_hints) +fu_device_set_physical_id (FuDevice *self, const gchar *physical_id) { - g_return_if_fail (FU_IS_DEVICE (device)); - g_return_if_fail (plugin_hints != NULL); - fu_device_set_metadata (device, "PluginHints", plugin_hints); + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (physical_id != NULL); + fu_device_set_metadata (self, "physical-id", physical_id); } /** - * fu_device_get_plugin_hints: - * @device: A #FuDevice + * fu_device_get_physical_id: + * @self: A #FuDevice * - * Gets the plugin hint for the device from the quirk system. + * Gets the physical ID set for the device, which represents the electrical + * connection used to compare devices. + * + * Multiple #FuDevices can share a single physical ID. * * Returns: a string value, or %NULL if never set. * - * Since: 1.0.3 + * Since: 1.1.2 **/ const gchar * -fu_device_get_plugin_hints (FuDevice *device) +fu_device_get_physical_id (FuDevice *self) +{ + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return fu_device_get_metadata (self, "physical-id"); +} + +static void +fu_device_set_custom_flag (FuDevice *self, const gchar *hint) { - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); - return fu_device_get_metadata (device, "PluginHints"); + FwupdDeviceFlags flag; + + /* is this a known device flag */ + flag = fwupd_device_flag_from_string (hint); + if (flag == FWUPD_DEVICE_FLAG_UNKNOWN) + return; + + /* being both a bootloader and requiring a bootloader is invalid */ + if (flag == FWUPD_DEVICE_FLAG_NONE || + flag == FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER) { + fu_device_remove_flag (self, FWUPD_DEVICE_FLAG_IS_BOOTLOADER); + } + if (flag == FWUPD_DEVICE_FLAG_NONE || + flag == FWUPD_DEVICE_FLAG_IS_BOOTLOADER) { + fu_device_remove_flag (self, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER); + } + + /* none is not used as an "exported" flag */ + if (flag != FWUPD_DEVICE_FLAG_NONE) + fu_device_add_flag (self, flag); } /** - * fu_device_set_platform_id: - * @device: A #FuDevice - * @platform_id: a platform string, e.g. `/sys/devices/usb1/1-1/1-1.2` + * fu_device_set_custom_flags: + * @self: A #FuDevice + * @custom_flags: a string * - * Sets the Platform ID on the device. If unset, the ID will automatically - * be set using a hash of the @platform_id value. + * Sets the custom flags from the quirk system that can be used to + * affect device matching. The actual string format is defined by the plugin. * - * Since: 1.0.2 + * Since: 1.1.0 **/ void -fu_device_set_platform_id (FuDevice *device, const gchar *platform_id) +fu_device_set_custom_flags (FuDevice *self, const gchar *custom_flags) { - g_return_if_fail (FU_IS_DEVICE (device)); - g_return_if_fail (platform_id != NULL); + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (custom_flags != NULL); - /* automatically use this */ - if (fu_device_get_id (device) == NULL) { - g_autofree gchar *id_guid = NULL; - id_guid = g_strdup_printf ("%s:%s", platform_id, - fu_device_get_guid_default (device)); - fu_device_set_id (device, id_guid); + /* display what was set when converting to a string */ + fu_device_set_metadata (self, "CustomFlags", custom_flags); + + /* look for any standard FwupdDeviceFlags */ + if (custom_flags != NULL) { + g_auto(GStrv) hints = g_strsplit (custom_flags, ",", -1); + for (guint i = 0; hints[i] != NULL; i++) + fu_device_set_custom_flag (self, hints[i]); } - fu_device_set_metadata (device, "platform-id", platform_id); } /** - * fu_device_get_platform_id: - * @device: A #FuDevice + * fu_device_get_custom_flags: + * @self: A #FuDevice * - * Gets the Platform ID set for the device, which represents the connection - * string used to compare devices. + * Gets the custom flags for the device from the quirk system. * * Returns: a string value, or %NULL if never set. * - * Since: 1.0.2 + * Since: 1.1.0 **/ const gchar * -fu_device_get_platform_id (FuDevice *device) +fu_device_get_custom_flags (FuDevice *self) +{ + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + return fu_device_get_metadata (self, "CustomFlags"); +} + +/** + * fu_device_has_custom_flag: + * @self: A #FuDevice + * @hint: A string, e.g. "bootloader" + * + * Checks if the custom flag exists for the device from the quirk system. + * + * It may be more efficient to call fu_device_get_custom_flags() and split the + * string locally if checking for lots of different flags. + * + * Returns: %TRUE if the hint exists + * + * Since: 1.1.0 + **/ +gboolean +fu_device_has_custom_flag (FuDevice *self, const gchar *hint) { - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); - return fu_device_get_metadata (device, "platform-id"); + const gchar *hint_str; + g_auto(GStrv) hints = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (hint != NULL, FALSE); + + /* no hint is perfectly valid */ + hint_str = fu_device_get_custom_flags (self); + if (hint_str == NULL) + return FALSE; + hints = g_strsplit (hint_str, ",", -1); + return g_strv_contains ((const gchar * const *) hints, hint); } static void @@ -508,7 +1487,7 @@ /** * fu_device_get_remove_delay: - * @device: A #FuDevice + * @self: A #FuDevice * * Returns the maximum delay expected when replugging the device going into * bootloader mode. @@ -518,16 +1497,16 @@ * Since: 1.0.2 **/ guint -fu_device_get_remove_delay (FuDevice *device) +fu_device_get_remove_delay (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), 0); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); return priv->remove_delay; } /** * fu_device_set_remove_delay: - * @device: A #FuDevice + * @self: A #FuDevice * @remove_delay: the remove_delay value * * Sets the amount of time a device is allowed to return in bootloader mode. @@ -540,16 +1519,16 @@ * Since: 1.0.2 **/ void -fu_device_set_remove_delay (FuDevice *device, guint remove_delay) +fu_device_set_remove_delay (FuDevice *self, guint remove_delay) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); priv->remove_delay = remove_delay; } /** * fu_device_get_status: - * @device: A #FuDevice + * @self: A #FuDevice * * Returns what the device is currently doing. * @@ -558,16 +1537,16 @@ * Since: 1.0.3 **/ FwupdStatus -fu_device_get_status (FuDevice *device) +fu_device_get_status (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), 0); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); return priv->status; } /** * fu_device_set_status: - * @device: A #FuDevice + * @self: A #FuDevice * @status: the status value, e.g. %FWUPD_STATUS_DEVICE_WRITE * * Sets what the device is currently doing. @@ -575,19 +1554,19 @@ * Since: 1.0.3 **/ void -fu_device_set_status (FuDevice *device, FwupdStatus status) +fu_device_set_status (FuDevice *self, FwupdStatus status) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); if (priv->status == status) return; priv->status = status; - g_object_notify (G_OBJECT (device), "status"); + g_object_notify (G_OBJECT (self), "status"); } /** * fu_device_get_progress: - * @device: A #FuDevice + * @self: A #FuDevice * * Returns the progress completion. * @@ -596,16 +1575,16 @@ * Since: 1.0.3 **/ guint -fu_device_get_progress (FuDevice *device) +fu_device_get_progress (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), 0); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), 0); return priv->progress; } /** * fu_device_set_progress: - * @device: A #FuDevice + * @self: A #FuDevice * @progress: the progress percentage value * * Sets the progress completion. @@ -613,19 +1592,19 @@ * Since: 1.0.3 **/ void -fu_device_set_progress (FuDevice *device, guint progress) +fu_device_set_progress (FuDevice *self, guint progress) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); if (priv->progress == progress) return; priv->progress = progress; - g_object_notify (G_OBJECT (device), "progress"); + g_object_notify (G_OBJECT (self), "progress"); } /** * fu_device_set_progress_full: - * @device: A #FuDevice + * @self: A #FuDevice * @progress_done: the bytes already done * @progress_total: the total number of bytes * @@ -634,17 +1613,18 @@ * Since: 1.0.3 **/ void -fu_device_set_progress_full (FuDevice *device, gsize progress_done, gsize progress_total) +fu_device_set_progress_full (FuDevice *self, gsize progress_done, gsize progress_total) { gdouble percentage = 0.f; + g_return_if_fail (FU_IS_DEVICE (self)); if (progress_total > 0) percentage = (100.f * (gdouble) progress_done) / (gdouble) progress_total; - fu_device_set_progress (device, (guint) percentage); + fu_device_set_progress (self, (guint) percentage); } /** * fu_device_to_string: - * @device: A #FuDevice + * @self: A #FuDevice * * This allows us to easily print the FwupdDevice, the FwupdRelease and the * daemon-specific metadata. @@ -654,21 +1634,33 @@ * Since: 0.9.8 **/ gchar * -fu_device_to_string (FuDevice *device) +fu_device_to_string (FuDevice *self) { - FuDeviceClass *klass = FU_DEVICE_GET_CLASS (device); - FuDevicePrivate *priv = GET_PRIVATE (device); + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + FuDevicePrivate *priv = GET_PRIVATE (self); GString *str = g_string_new (""); g_autofree gchar *tmp = NULL; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->metadata_mutex); g_autoptr(GList) keys = NULL; - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + g_return_val_if_fail (locker != NULL, NULL); - tmp = fwupd_device_to_string (FWUPD_DEVICE (device)); + tmp = fwupd_device_to_string (FWUPD_DEVICE (self)); if (tmp != NULL && tmp[0] != '\0') g_string_append (str, tmp); + if (priv->alternate_id != NULL) + fwupd_pad_kv_str (str, "AlternateId", priv->alternate_id); if (priv->equivalent_id != NULL) fwupd_pad_kv_str (str, "EquivalentId", priv->equivalent_id); + if (priv->size_min > 0) { + g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_min); + fwupd_pad_kv_str (str, "FirmwareSizeMin", sz); + } + if (priv->size_max > 0) { + g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_max); + fwupd_pad_kv_str (str, "FirmwareSizeMax", sz); + } keys = g_hash_table_get_keys (priv->metadata); for (GList *l = keys; l != NULL; l = l->next) { const gchar *key = l->data; @@ -678,14 +1670,14 @@ /* subclassed */ if (klass->to_string != NULL) - klass->to_string (device, str); + klass->to_string (self, str); return g_string_free (str, FALSE); } /** * fu_device_set_quirks: - * @device: A #FuDevice + * @self: A #FuDevice * @quirks: A #FuQuirks, or %NULL * * Sets the optional quirk information which may be useful to this device. @@ -695,17 +1687,17 @@ * Since: 1.0.3 **/ void -fu_device_set_quirks (FuDevice *device, FuQuirks *quirks) +fu_device_set_quirks (FuDevice *self, FuQuirks *quirks) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_if_fail (FU_IS_DEVICE (device)); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); if (g_set_object (&priv->quirks, quirks)) - g_object_notify (G_OBJECT (device), "quirks"); + g_object_notify (G_OBJECT (self), "quirks"); } /** * fu_device_get_quirks: - * @device: A #FuDevice + * @self: A #FuDevice * * Gets the quirk information which may be useful to this device. * @@ -714,16 +1706,16 @@ * Since: 1.0.3 **/ FuQuirks * -fu_device_get_quirks (FuDevice *device) +fu_device_get_quirks (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); - g_return_val_if_fail (FU_IS_DEVICE (device), NULL); + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); return priv->quirks; } /** * fu_device_get_release_default: - * @device: A #FuDevice + * @self: A #FuDevice * * Gets the default release for the device, creating one if not found. * @@ -732,16 +1724,562 @@ * Since: 1.0.5 **/ FwupdRelease * -fu_device_get_release_default (FuDevice *device) +fu_device_get_release_default (FuDevice *self) { g_autoptr(FwupdRelease) rel = NULL; - if (fwupd_device_get_release_default (FWUPD_DEVICE (device)) != NULL) - return fwupd_device_get_release_default (FWUPD_DEVICE (device)); + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + if (fwupd_device_get_release_default (FWUPD_DEVICE (self)) != NULL) + return fwupd_device_get_release_default (FWUPD_DEVICE (self)); rel = fwupd_release_new (); - fwupd_device_add_release (FWUPD_DEVICE (device), rel); + fwupd_device_add_release (FWUPD_DEVICE (self), rel); return rel; } +/** + * fu_device_write_firmware: + * @self: A #FuDevice + * @fw: A #GBytes + * @flags: #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE + * @error: A #GError + * + * Writes firmware to the device by calling a plugin-specific vfunc. + * + * Returns: %TRUE on success + * + * Since: 1.0.8 + **/ +gboolean +fu_device_write_firmware (FuDevice *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + g_autoptr(GBytes) fw_new = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no plugin-specific method */ + if (klass->write_firmware == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* prepare (e.g. decompress) firmware */ + fw_new = fu_device_prepare_firmware (self, fw, flags, error); + if (fw_new == NULL) + return FALSE; + + /* call vfunc */ + return klass->write_firmware (self, fw_new, flags, error); +} + +/** + * fu_device_prepare_firmware: + * @self: A #FuDevice + * @fw: A #GBytes + * @flags: #FwupdInstallFlags, e.g. %FWUPD_INSTALL_FLAG_FORCE + * @error: A #GError + * + * Prepares the firmware by calling an optional device-specific vfunc for the + * device, which can do things like decompressing or parsing of the firmware + * data. + * + * For all firmware, this checks the size of the firmware if limits have been + * set using fu_device_set_firmware_size_min(), fu_device_set_firmware_size_max() + * or using a quirk entry. + * + * Returns: (transfer full): A new #GBytes, or %NULL for error + * + * Since: 1.1.2 + **/ +GBytes * +fu_device_prepare_firmware (FuDevice *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + FuDevicePrivate *priv = GET_PRIVATE (self); + guint64 fw_sz; + g_autoptr(GBytes) fw_new = NULL; + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + g_return_val_if_fail (fw != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* optionally subclassed */ + if (klass->prepare_firmware != NULL) { + fw_new = klass->prepare_firmware (self, fw, flags, error); + if (fw_new == NULL) + return NULL; + } else { + fw_new = g_bytes_ref (fw); + } + + /* check size */ + fw_sz = (guint64) g_bytes_get_size (fw_new); + if (priv->size_max > 0 && fw_sz > priv->size_max) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware is %04x bytes larger than the allowed " + "maximum size of %04x bytes", + (guint) (fw_sz - priv->size_max), + (guint) priv->size_max); + return NULL; + } + if (priv->size_min > 0 && fw_sz < priv->size_min) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "firmware is %04x bytes smaller than the allowed " + "minimum size of %04x bytes", + (guint) (priv->size_min - fw_sz), + (guint) priv->size_max); + return NULL; + } + + return g_steal_pointer (&fw_new); +} + +/** + * fu_device_read_firmware: + * @self: A #FuDevice + * @error: A #GError + * + * Reads firmware from the device by calling a plugin-specific vfunc. + * + * Returns: (transfer full): A #GBytes, or %NULL for error + * + * Since: 1.0.8 + **/ +GBytes * +fu_device_read_firmware (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* no plugin-specific method */ + if (klass->read_firmware == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return NULL; + } + + /* call vfunc */ + return klass->read_firmware (self, error); +} + +/** + * fu_device_detach: + * @self: A #FuDevice + * @error: A #GError + * + * Detaches a device from the application into bootloader mode. + * + * Returns: %TRUE on success + * + * Since: 1.0.8 + **/ +gboolean +fu_device_detach (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no plugin-specific method */ + if (klass->detach == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* call vfunc */ + return klass->detach (self, error); +} + +/** + * fu_device_attach: + * @self: A #FuDevice + * @error: A #GError + * + * Attaches a device from the bootloader into application mode. + * + * Returns: %TRUE on success + * + * Since: 1.0.8 + **/ +gboolean +fu_device_attach (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* no plugin-specific method */ + if (klass->attach == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "not supported"); + return FALSE; + } + + /* call vfunc */ + return klass->attach (self, error); +} + +/** + * fu_device_open: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Opens a device, optionally running a object-specific vfunc. + * + * Plugins can call fu_device_open() multiple times without calling + * fu_device_close(), but only the first call will actually invoke the vfunc. + * + * It is expected that plugins issue the same number of fu_device_open() and + * fu_device_close() methods when using a specific @self. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_open (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already open */ + g_atomic_int_inc (&priv->open_refcount); + if (priv->open_refcount > 1) + return TRUE; + + /* probe */ + if (!fu_device_probe (self, error)) + return FALSE; + + /* ensure the device ID is already setup */ + if (!fu_device_ensure_id (self, error)) + return FALSE; + + /* subclassed */ + if (klass->open != NULL) { + if (!klass->open (self, error)) + return FALSE; + } + + /* setup */ + if (!fu_device_setup (self, error)) + return FALSE; + + /* success */ + return TRUE; +} + +/** + * fu_device_close: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Closes a device, optionally running a object-specific vfunc. + * + * Plugins can call fu_device_close() multiple times without calling + * fu_device_open(), but only the last call will actually invoke the vfunc. + * + * It is expected that plugins issue the same number of fu_device_open() and + * fu_device_close() methods when using a specific @self. + * + * An error is returned if this method is called without having used the + * fu_device_open() method beforehand. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_close (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + FuDevicePrivate *priv = GET_PRIVATE (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not yet open */ + if (priv->open_refcount == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "cannot close device, refcount already zero"); + return FALSE; + } + if (!g_atomic_int_dec_and_test (&priv->open_refcount)) + return TRUE; + + /* subclassed */ + if (klass->close != NULL) { + if (!klass->close (self, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +/** + * fu_device_probe: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Probes a device, setting parameters on the object that does not need + * the device open or the interface claimed. + * If the device is not compatible then an error should be returned. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_probe (FuDevice *self, GError **error) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already done */ + if (priv->done_probe) + return TRUE; + + /* subclassed */ + if (klass->probe != NULL) { + if (!klass->probe (self, error)) + return FALSE; + } + priv->done_probe = TRUE; + return TRUE; +} + +/** + * fu_device_convert_instance_ids: + * @self: A #FuDevice + * + * Converts all the Device Instance IDs added using fu_device_add_instance_id() + * into actual GUIDs, **unless** %FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS has + * been set. + * + * Plugins will only need to need to call this manually when adding child + * devices, as fu_device_setup() automatically calls this after the + * fu_device_probe() and fu_device_setup() virtual functions have been run. + * + * Since: 1.2.5 + **/ +void +fu_device_convert_instance_ids (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + GPtrArray *instance_ids = fwupd_device_get_instance_ids (FWUPD_DEVICE (self)); + + /* OEM specific hardware */ + if (fu_device_has_flag (self, FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS)) + return; + for (guint i = 0; i < instance_ids->len; i++) { + const gchar *instance_id = g_ptr_array_index (instance_ids, i); + g_autofree gchar *guid = fwupd_guid_hash_string (instance_id); + fwupd_device_add_guid (FWUPD_DEVICE (self), guid); + } + + /* convert all children too */ + for (guint i = 0; i < priv->children->len; i++) { + FuDevice *devtmp = g_ptr_array_index (priv->children, i); + fu_device_convert_instance_ids (devtmp); + } +} + +/** + * fu_device_setup: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Sets up a device, setting parameters on the object that requires + * the device to be open and have the interface claimed. + * If the device is not compatible then an error should be returned. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_setup (FuDevice *self, GError **error) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* already done */ + if (priv->done_setup) + return TRUE; + + /* subclassed */ + if (klass->setup != NULL) { + if (!klass->setup (self, error)) + return FALSE; + } + + /* convert the instance IDs to GUIDs */ + fu_device_convert_instance_ids (self); + + priv->done_setup = TRUE; + return TRUE; +} + +/** + * fu_device_activate: + * @self: A #FuDevice + * @error: A #GError, or %NULL + * + * Activates up a device, which normally means the device switches to a new + * firmware version. This should only be called when data loss cannot occur. + * + * Returns: %TRUE for success + * + * Since: 1.2.6 + **/ +gboolean +fu_device_activate (FuDevice *self, GError **error) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + + g_return_val_if_fail (FU_IS_DEVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* subclassed */ + if (klass->activate != NULL) { + if (!klass->activate (self, error)) + return FALSE; + } + + return TRUE; +} + +/** + * fu_device_probe_invalidate: + * @self: A #FuDevice + * + * Normally when calling fu_device_probe() multiple times it is only done once. + * Calling this method causes the next requests to fu_device_probe() and + * fu_device_setup() actually probe the hardware. + * + * This should be done in case the backing device has changed, for instance if + * a USB device has been replugged. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +void +fu_device_probe_invalidate (FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_DEVICE (self)); + priv->done_probe = FALSE; + priv->done_setup = FALSE; +} + +/** + * fu_device_incorporate: + * @self: A #FuDevice + * @donor: Another #FuDevice + * + * Copy all properties from the donor object if they have not already been set. + * + * Since: 1.1.0 + **/ +void +fu_device_incorporate (FuDevice *self, FuDevice *donor) +{ + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (self); + FuDevicePrivate *priv = GET_PRIVATE (self); + FuDevicePrivate *priv_donor = GET_PRIVATE (donor); + GPtrArray *parent_guids = fu_device_get_parent_guids (donor); + g_autoptr(GList) metadata_keys = NULL; + + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (FU_IS_DEVICE (donor)); + + /* copy from donor FuDevice if has not already been set */ + if (priv->alternate_id == NULL) + fu_device_set_alternate_id (self, fu_device_get_alternate_id (donor)); + if (priv->equivalent_id == NULL) + fu_device_set_equivalent_id (self, fu_device_get_equivalent_id (donor)); + if (priv->quirks == NULL) + fu_device_set_quirks (self, fu_device_get_quirks (donor)); + g_rw_lock_reader_lock (&priv_donor->parent_guids_mutex); + for (guint i = 0; i < parent_guids->len; i++) + fu_device_add_parent_guid (self, g_ptr_array_index (parent_guids, i)); + g_rw_lock_reader_unlock (&priv_donor->parent_guids_mutex); + g_rw_lock_reader_lock (&priv_donor->metadata_mutex); + metadata_keys = g_hash_table_get_keys (priv_donor->metadata); + for (GList *l = metadata_keys; l != NULL; l = l->next) { + const gchar *key = l->data; + if (g_hash_table_lookup (priv->metadata, key) == NULL) { + const gchar *value = g_hash_table_lookup (priv_donor->metadata, key); + fu_device_set_metadata (self, key, value); + } + } + g_rw_lock_reader_unlock (&priv_donor->metadata_mutex); + + /* now the base class, where all the interesting bits are */ + fwupd_device_incorporate (FWUPD_DEVICE (self), FWUPD_DEVICE (donor)); + + /* optional subclass */ + if (klass->incorporate != NULL) + klass->incorporate (self, donor); +} + +/** + * fu_device_incorporate_from_component: + * @device: A #FuDevice + * @component: A #XbNode + * + * Copy all properties from the donor AppStream component. + * + * Since: 1.2.4 + **/ +void +fu_device_incorporate_from_component (FuDevice *self, XbNode *component) +{ + const gchar *tmp; + g_return_if_fail (FU_IS_DEVICE (self)); + g_return_if_fail (XB_IS_NODE (component)); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); + if (tmp != NULL) + fwupd_device_set_update_message (FWUPD_DEVICE (self), tmp); +} + static void fu_device_class_init (FuDeviceClass *klass) { @@ -759,17 +2297,22 @@ G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_STATUS, pspec); + pspec = g_param_spec_string ("physical-id", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_PHYSICAL_ID, pspec); + + pspec = g_param_spec_string ("logical-id", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_LOGICAL_ID, pspec); + pspec = g_param_spec_uint ("progress", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_PROGRESS, pspec); - pspec = g_param_spec_string ("platform-id", NULL, NULL, NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_PLATFORM_ID, pspec); - pspec = g_param_spec_object ("quirks", NULL, NULL, FU_TYPE_QUIRKS, G_PARAM_READWRITE | @@ -778,25 +2321,38 @@ } static void -fu_device_init (FuDevice *device) +fu_device_init (FuDevice *self) { - FuDevicePrivate *priv = GET_PRIVATE (device); + FuDevicePrivate *priv = GET_PRIVATE (self); priv->status = FWUPD_STATUS_IDLE; + priv->children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->parent_guids = g_ptr_array_new_with_free_func (g_free); + g_rw_lock_init (&priv->parent_guids_mutex); priv->metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_rw_lock_init (&priv->metadata_mutex); } static void fu_device_finalize (GObject *object) { - FuDevice *device = FU_DEVICE (object); - FuDevicePrivate *priv = GET_PRIVATE (device); + FuDevice *self = FU_DEVICE (object); + FuDevicePrivate *priv = GET_PRIVATE (self); if (priv->alternate != NULL) g_object_unref (priv->alternate); + if (priv->parent != NULL) + g_object_remove_weak_pointer (G_OBJECT (priv->parent), (gpointer *) &priv->parent); if (priv->quirks != NULL) g_object_unref (priv->quirks); + if (priv->poll_id != 0) + g_source_remove (priv->poll_id); + g_rw_lock_clear (&priv->metadata_mutex); + g_rw_lock_clear (&priv->parent_guids_mutex); g_hash_table_unref (priv->metadata); + g_ptr_array_unref (priv->children); + g_ptr_array_unref (priv->parent_guids); + g_free (priv->alternate_id); g_free (priv->equivalent_id); G_OBJECT_CLASS (fu_device_parent_class)->finalize (object); @@ -805,7 +2361,6 @@ FuDevice * fu_device_new (void) { - FuDevice *device; - device = g_object_new (FU_TYPE_DEVICE, NULL); - return FU_DEVICE (device); + FuDevice *self = g_object_new (FU_TYPE_DEVICE, NULL); + return FU_DEVICE (self); } diff -Nru fwupd-1.0.6/src/fu-device.h fwupd-1.2.10/src/fu-device.h --- fwupd-1.0.6/src/fu-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,31 +1,16 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2015-2018 Richard Hughes * - * Copyright (C) 2015-2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_H -#define __FU_DEVICE_H +#pragma once #include #include #include "fu-quirks.h" +#include "fu-common-version.h" G_BEGIN_DECLS @@ -35,8 +20,42 @@ struct _FuDeviceClass { FwupdDeviceClass parent_class; - void (*to_string) (FuDevice *device, + void (*to_string) (FuDevice *self, GString *str); + gboolean (*write_firmware) (FuDevice *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); + GBytes *(*read_firmware) (FuDevice *self, + GError **error); + gboolean (*detach) (FuDevice *self, + GError **error); + gboolean (*attach) (FuDevice *self, + GError **error); + gboolean (*open) (FuDevice *self, + GError **error); + gboolean (*close) (FuDevice *self, + GError **error); + gboolean (*probe) (FuDevice *self, + GError **error); + GBytes *(*prepare_firmware) (FuDevice *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); + gboolean (*set_quirk_kv) (FuDevice *self, + const gchar *key, + const gchar *value, + GError **error); + gboolean (*setup) (FuDevice *self, + GError **error); + void (*incorporate) (FuDevice *self, + FuDevice *donor); + gboolean (*poll) (FuDevice *self, + GError **error); + gboolean (*activate) (FuDevice *self, + GError **error); + /*< private >*/ + gpointer padding[19]; }; /** @@ -46,7 +65,7 @@ * chain of slow USB hubs. This should be used when the device is able to * reset itself between bootloader->runtime->bootloader. */ -#define FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE 5000 +#define FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE 10000 /** * FU_DEVICE_REMOVE_DELAY_USER_REPLUG: @@ -55,7 +74,7 @@ * being slow and clumsy. This should be used when the user has to do something, * e.g. unplug, press a magic button and then replug. */ -#define FU_DEVICE_REMOVE_DELAY_USER_REPLUG 20000 +#define FU_DEVICE_REMOVE_DELAY_USER_REPLUG 40000 FuDevice *fu_device_new (void); @@ -63,23 +82,26 @@ #define fu_device_add_flag(d,v) fwupd_device_add_flag(FWUPD_DEVICE(d),v) #define fu_device_remove_flag(d,v) fwupd_device_remove_flag(FWUPD_DEVICE(d),v) #define fu_device_has_flag(d,v) fwupd_device_has_flag(FWUPD_DEVICE(d),v) +#define fu_device_has_instance_id(d,v) fwupd_device_has_instance_id(FWUPD_DEVICE(d),v) #define fu_device_add_checksum(d,v) fwupd_device_add_checksum(FWUPD_DEVICE(d),v) +#define fu_device_add_release(d,v) fwupd_device_add_release(FWUPD_DEVICE(d),v) #define fu_device_add_icon(d,v) fwupd_device_add_icon(FWUPD_DEVICE(d),v) #define fu_device_set_created(d,v) fwupd_device_set_created(FWUPD_DEVICE(d),v) #define fu_device_set_description(d,v) fwupd_device_set_description(FWUPD_DEVICE(d),v) #define fu_device_set_flags(d,v) fwupd_device_set_flags(FWUPD_DEVICE(d),v) -#define fu_device_has_guid(d,v) fwupd_device_has_guid(FWUPD_DEVICE(d),v) #define fu_device_set_modified(d,v) fwupd_device_set_modified(FWUPD_DEVICE(d),v) #define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v) +#define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v) #define fu_device_set_summary(d,v) fwupd_device_set_summary(FWUPD_DEVICE(d),v) #define fu_device_set_update_error(d,v) fwupd_device_set_update_error(FWUPD_DEVICE(d),v) #define fu_device_set_update_state(d,v) fwupd_device_set_update_state(FWUPD_DEVICE(d),v) #define fu_device_set_vendor(d,v) fwupd_device_set_vendor(FWUPD_DEVICE(d),v) #define fu_device_set_vendor_id(d,v) fwupd_device_set_vendor_id(FWUPD_DEVICE(d),v) -#define fu_device_set_version(d,v) fwupd_device_set_version(FWUPD_DEVICE(d),v) #define fu_device_set_version_lowest(d,v) fwupd_device_set_version_lowest(FWUPD_DEVICE(d),v) #define fu_device_set_version_bootloader(d,v) fwupd_device_set_version_bootloader(FWUPD_DEVICE(d),v) +#define fu_device_set_version_format(d,v) fwupd_device_set_version_format(FWUPD_DEVICE(d),v) #define fu_device_set_flashes_left(d,v) fwupd_device_set_flashes_left(FWUPD_DEVICE(d),v) +#define fu_device_set_install_duration(d,v) fwupd_device_set_install_duration(FWUPD_DEVICE(d),v) #define fu_device_get_checksums(d) fwupd_device_get_checksums(FWUPD_DEVICE(d)) #define fu_device_get_flags(d) fwupd_device_get_flags(FWUPD_DEVICE(d)) #define fu_device_get_created(d) fwupd_device_get_created(FWUPD_DEVICE(d)) @@ -88,6 +110,8 @@ #define fu_device_get_guid_default(d) fwupd_device_get_guid_default(FWUPD_DEVICE(d)) #define fu_device_get_icons(d) fwupd_device_get_icons(FWUPD_DEVICE(d)) #define fu_device_get_name(d) fwupd_device_get_name(FWUPD_DEVICE(d)) +#define fu_device_get_serial(d) fwupd_device_get_serial(FWUPD_DEVICE(d)) +#define fu_device_get_summary(d) fwupd_device_get_summary(FWUPD_DEVICE(d)) #define fu_device_get_id(d) fwupd_device_get_id(FWUPD_DEVICE(d)) #define fu_device_get_plugin(d) fwupd_device_get_plugin(FWUPD_DEVICE(d)) #define fu_device_get_update_error(d) fwupd_device_get_update_error(FWUPD_DEVICE(d)) @@ -96,65 +120,122 @@ #define fu_device_get_version(d) fwupd_device_get_version(FWUPD_DEVICE(d)) #define fu_device_get_version_lowest(d) fwupd_device_get_version_lowest(FWUPD_DEVICE(d)) #define fu_device_get_version_bootloader(d) fwupd_device_get_version_bootloader(FWUPD_DEVICE(d)) +#define fu_device_get_version_format(d) fwupd_device_get_version_format(FWUPD_DEVICE(d)) #define fu_device_get_vendor_id(d) fwupd_device_get_vendor_id(FWUPD_DEVICE(d)) #define fu_device_get_flashes_left(d) fwupd_device_get_flashes_left(FWUPD_DEVICE(d)) +#define fu_device_get_install_duration(d) fwupd_device_get_install_duration(FWUPD_DEVICE(d)) /* accessors */ -gchar *fu_device_to_string (FuDevice *device); -const gchar *fu_device_get_equivalent_id (FuDevice *device); -void fu_device_set_equivalent_id (FuDevice *device, +gchar *fu_device_to_string (FuDevice *self); +const gchar *fu_device_get_alternate_id (FuDevice *self); +void fu_device_set_alternate_id (FuDevice *self, + const gchar *alternate_id); +const gchar *fu_device_get_equivalent_id (FuDevice *self); +void fu_device_set_equivalent_id (FuDevice *self, const gchar *equivalent_id); -void fu_device_add_guid (FuDevice *device, +void fu_device_add_guid (FuDevice *self, const gchar *guid); -FuDevice *fu_device_get_alternate (FuDevice *device); -void fu_device_set_alternate (FuDevice *device, - FuDevice *alternate); -const gchar *fu_device_get_metadata (FuDevice *device, +gboolean fu_device_has_guid (FuDevice *self, + const gchar *guid); +void fu_device_add_instance_id (FuDevice *self, + const gchar *instance_id); +gchar *fu_device_get_guids_as_str (FuDevice *self); +FuDevice *fu_device_get_alternate (FuDevice *self); +FuDevice *fu_device_get_parent (FuDevice *self); +GPtrArray *fu_device_get_children (FuDevice *self); +void fu_device_add_child (FuDevice *self, + FuDevice *child); +void fu_device_add_parent_guid (FuDevice *self, + const gchar *guid); +void fu_device_add_counterpart_guid (FuDevice *self, + const gchar *guid); +const gchar *fu_device_get_metadata (FuDevice *self, const gchar *key); -gboolean fu_device_get_metadata_boolean (FuDevice *device, +gboolean fu_device_get_metadata_boolean (FuDevice *self, const gchar *key); -guint fu_device_get_metadata_integer (FuDevice *device, +guint fu_device_get_metadata_integer (FuDevice *self, const gchar *key); -void fu_device_set_metadata (FuDevice *device, +void fu_device_set_metadata (FuDevice *self, const gchar *key, const gchar *value); -void fu_device_set_metadata_boolean (FuDevice *device, +void fu_device_set_metadata_boolean (FuDevice *self, const gchar *key, gboolean value); -void fu_device_set_metadata_integer (FuDevice *device, +void fu_device_set_metadata_integer (FuDevice *self, const gchar *key, guint value); -void fu_device_set_id (FuDevice *device, +void fu_device_set_id (FuDevice *self, const gchar *id); -const gchar *fu_device_get_platform_id (FuDevice *device); -void fu_device_set_platform_id (FuDevice *device, - const gchar *platform_id); -const gchar *fu_device_get_serial (FuDevice *device); -void fu_device_set_serial (FuDevice *device, - const gchar *serial); -const gchar *fu_device_get_plugin_hints (FuDevice *device); -void fu_device_set_plugin_hints (FuDevice *device, - const gchar *plugin_hints); -void fu_device_set_name (FuDevice *device, +void fu_device_set_version (FuDevice *self, + const gchar *version, + FwupdVersionFormat fmt); +const gchar *fu_device_get_physical_id (FuDevice *self); +void fu_device_set_physical_id (FuDevice *self, + const gchar *physical_id); +const gchar *fu_device_get_logical_id (FuDevice *self); +void fu_device_set_logical_id (FuDevice *self, + const gchar *logical_id); +const gchar *fu_device_get_custom_flags (FuDevice *self); +gboolean fu_device_has_custom_flag (FuDevice *self, + const gchar *hint); +void fu_device_set_custom_flags (FuDevice *self, + const gchar *custom_flags); +void fu_device_set_name (FuDevice *self, const gchar *value); -guint fu_device_get_remove_delay (FuDevice *device); -void fu_device_set_remove_delay (FuDevice *device, +guint fu_device_get_remove_delay (FuDevice *self); +void fu_device_set_remove_delay (FuDevice *self, guint remove_delay); -FwupdStatus fu_device_get_status (FuDevice *device); -void fu_device_set_status (FuDevice *device, +FwupdStatus fu_device_get_status (FuDevice *self); +void fu_device_set_status (FuDevice *self, FwupdStatus status); -guint fu_device_get_progress (FuDevice *device); -void fu_device_set_progress (FuDevice *device, +void fu_device_set_firmware_size (FuDevice *self, + guint64 size); +void fu_device_set_firmware_size_min (FuDevice *self, + guint64 size_min); +void fu_device_set_firmware_size_max (FuDevice *self, + guint64 size_max); +guint64 fu_device_get_firmware_size_min (FuDevice *self); +guint64 fu_device_get_firmware_size_max (FuDevice *self); +guint fu_device_get_progress (FuDevice *self); +void fu_device_set_progress (FuDevice *self, guint progress); -void fu_device_set_progress_full (FuDevice *device, +void fu_device_set_progress_full (FuDevice *self, gsize progress_done, gsize progress_total); -void fu_device_set_quirks (FuDevice *device, +void fu_device_set_quirks (FuDevice *self, FuQuirks *quirks); -FuQuirks *fu_device_get_quirks (FuDevice *device); -FwupdRelease *fu_device_get_release_default (FuDevice *device); +FuQuirks *fu_device_get_quirks (FuDevice *self); +FwupdRelease *fu_device_get_release_default (FuDevice *self); +gboolean fu_device_write_firmware (FuDevice *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); +GBytes *fu_device_prepare_firmware (FuDevice *self, + GBytes *fw, + FwupdInstallFlags flags, + GError **error); +GBytes *fu_device_read_firmware (FuDevice *self, + GError **error); +gboolean fu_device_attach (FuDevice *self, + GError **error); +gboolean fu_device_detach (FuDevice *self, + GError **error); +void fu_device_incorporate (FuDevice *self, + FuDevice *donor); +gboolean fu_device_open (FuDevice *self, + GError **error); +gboolean fu_device_close (FuDevice *self, + GError **error); +gboolean fu_device_probe (FuDevice *self, + GError **error); +gboolean fu_device_setup (FuDevice *self, + GError **error); +gboolean fu_device_activate (FuDevice *self, + GError **error); +void fu_device_probe_invalidate (FuDevice *self); +gboolean fu_device_poll (FuDevice *self, + GError **error); +void fu_device_set_poll_interval (FuDevice *self, + guint interval); G_END_DECLS - -#endif /* __FU_DEVICE_H */ - diff -Nru fwupd-1.0.6/src/fu-device-list.c fwupd-1.2.10/src/fu-device-list.c --- fwupd-1.0.6/src/fu-device-list.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device-list.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,19 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuDeviceList" + #include "config.h" #include #include #include "fu-device-list.h" +#include "fu-device-private.h" +#include "fu-mutex.h" #include "fwupd-error.h" @@ -48,6 +37,7 @@ { GObject parent_instance; GPtrArray *devices; /* of FuDeviceItem */ + GRWLock devices_mutex; }; enum { @@ -63,6 +53,8 @@ FuDevice *device; FuDevice *device_old; FuDeviceList *self; /* no ref */ + GMainLoop *replug_loop; /* block waiting for replug */ + guint replug_id; /* timeout the loop */ guint remove_id; } FuDeviceItem; @@ -107,6 +99,8 @@ GPtrArray *devices; g_return_val_if_fail (FU_IS_DEVICE_LIST (self), NULL); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + g_rw_lock_reader_lock (&self->devices_mutex); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item = g_ptr_array_index (self->devices, i); g_ptr_array_add (devices, g_object_ref (item->device)); @@ -117,6 +111,7 @@ continue; g_ptr_array_add (devices, g_object_ref (item->device_old)); } + g_rw_lock_reader_unlock (&self->devices_mutex); return devices; } @@ -125,7 +120,7 @@ * @self: A #FuDeviceList * * Returns all the active devices that have been added to the device list. - * An active device is defined as a device that is currently conected and has + * An active device is defined as a device that is currently connected and has * is owned by a plugin. * * Returns: (transfer container) (element-type FuDevice): the devices @@ -138,16 +133,20 @@ GPtrArray *devices; g_return_val_if_fail (FU_IS_DEVICE_LIST (self), NULL); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_rw_lock_reader_lock (&self->devices_mutex); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item = g_ptr_array_index (self->devices, i); g_ptr_array_add (devices, g_object_ref (item->device)); } + g_rw_lock_reader_unlock (&self->devices_mutex); return devices; } static FuDeviceItem * fu_device_list_find_by_device (FuDeviceList *self, FuDevice *device) { + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->devices_mutex); + g_return_val_if_fail (locker != NULL, NULL); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item = g_ptr_array_index (self->devices, i); if (item->device == device) @@ -164,6 +163,8 @@ static FuDeviceItem * fu_device_list_find_by_guid (FuDeviceList *self, const gchar *guid) { + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->devices_mutex); + g_return_val_if_fail (locker != NULL, NULL); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item = g_ptr_array_index (self->devices, i); if (fu_device_has_guid (item->device, guid)) @@ -180,6 +181,35 @@ } static FuDeviceItem * +fu_device_list_find_by_connection (FuDeviceList *self, + const gchar *physical_id, + const gchar *logical_id) +{ + g_autoptr(GRWLockReaderLocker) locker = NULL; + if (physical_id == NULL) + return NULL; + locker = g_rw_lock_reader_locker_new (&self->devices_mutex); + g_return_val_if_fail (locker != NULL, NULL); + for (guint i = 0; i < self->devices->len; i++) { + FuDeviceItem *item_tmp = g_ptr_array_index (self->devices, i); + FuDevice *device = item_tmp->device; + if (device != NULL && + g_strcmp0 (fu_device_get_physical_id (device), physical_id) == 0 && + g_strcmp0 (fu_device_get_logical_id (device), logical_id) == 0) + return item_tmp; + } + for (guint i = 0; i < self->devices->len; i++) { + FuDeviceItem *item_tmp = g_ptr_array_index (self->devices, i); + FuDevice *device = item_tmp->device_old; + if (device != NULL && + g_strcmp0 (fu_device_get_physical_id (device), physical_id) == 0 && + g_strcmp0 (fu_device_get_logical_id (device), logical_id) == 0) + return item_tmp; + } + return NULL; +} + +static FuDeviceItem * fu_device_list_find_by_id (FuDeviceList *self, const gchar *device_id, gboolean *multiple_matches) @@ -187,8 +217,15 @@ FuDeviceItem *item = NULL; gsize device_id_len; + /* sanity check */ + if (device_id == NULL) { + g_critical ("device ID was NULL"); + return NULL; + } + /* support abbreviated hashes */ device_id_len = strlen (device_id); + g_rw_lock_reader_lock (&self->devices_mutex); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item_tmp = g_ptr_array_index (self->devices, i); const gchar *ids[] = { @@ -203,14 +240,19 @@ } } } + g_rw_lock_reader_unlock (&self->devices_mutex); + if (item != NULL) + return item; + + /* only search old devices if we didn't find the active device */ + g_rw_lock_reader_lock (&self->devices_mutex); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item_tmp = g_ptr_array_index (self->devices, i); - const gchar *ids[] = { - fu_device_get_id (item_tmp->device), - fu_device_get_equivalent_id (item_tmp->device), - NULL }; + const gchar *ids[3] = { NULL }; if (item_tmp->device_old == NULL) continue; + ids[0] = fu_device_get_id (item_tmp->device_old); + ids[1] = fu_device_get_equivalent_id (item_tmp->device_old); for (guint j = 0; ids[j] != NULL; j++) { if (strncmp (ids[j], device_id, device_id_len) == 0) { if (item != NULL && multiple_matches != NULL) @@ -219,6 +261,7 @@ } } } + g_rw_lock_reader_unlock (&self->devices_mutex); return item; } @@ -229,7 +272,7 @@ * * Returns the old device associated with the currently active device. * - * Returns: (transfer none): the device, or %NULL if not found + * Returns: (transfer full): the device, or %NULL if not found * * Since: 1.0.3 **/ @@ -239,12 +282,16 @@ FuDeviceItem *item = fu_device_list_find_by_device (self, device); if (item == NULL) return NULL; - return item->device_old; + if (item->device_old == NULL) + return NULL; + return g_object_ref (item->device_old); } static FuDeviceItem * fu_device_list_get_by_guids (FuDeviceList *self, GPtrArray *guids) { + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->devices_mutex); + g_return_val_if_fail (locker != NULL, NULL); for (guint i = 0; i < self->devices->len; i++) { FuDeviceItem *item = g_ptr_array_index (self->devices, i); for (guint j = 0; j < guids->len; j++) { @@ -278,10 +325,28 @@ /* just remove now */ g_debug ("doing delayed removal"); fu_device_list_emit_device_removed (self, item->device); + g_rw_lock_writer_lock (&self->devices_mutex); g_ptr_array_remove (self->devices, item); + g_rw_lock_writer_unlock (&self->devices_mutex); return G_SOURCE_REMOVE; } +static void +fu_device_list_remove_with_delay (FuDeviceItem *item) +{ + /* we can't do anything with an unconnected device */ + fu_device_remove_flag (item->device, FWUPD_DEVICE_FLAG_UPDATABLE); + + /* give the hardware time to re-enumerate or the user time to + * re-insert the device with a magic button pressed */ + g_debug ("waiting %ums for %s device removal", + fu_device_get_remove_delay (item->device), + fu_device_get_name (item->device)); + item->remove_id = g_timeout_add (fu_device_get_remove_delay (item->device), + fu_device_list_device_delayed_remove_cb, + item); +} + /** * fu_device_list_remove: * @self: A #FuDeviceList @@ -302,6 +367,7 @@ fu_device_list_remove (FuDeviceList *self, FuDevice *device) { FuDeviceItem *item; + GPtrArray *children; g_return_if_fail (FU_IS_DEVICE_LIST (self)); g_return_if_fail (FU_IS_DEVICE (device)); @@ -319,25 +385,38 @@ item->remove_id = 0; } + /* remove any children associated with device */ + children = fu_device_get_children (device); + for (guint j = 0; j < children->len; j++) { + FuDevice *child = g_ptr_array_index (children, j); + FuDeviceItem *child_item = fu_device_list_find_by_id (self, + fu_device_get_id (child), + NULL); + if (child_item == NULL) { + g_debug ("device %s not found", fu_device_get_id (child)); + continue; + } + if (fu_device_get_remove_delay (child_item->device) > 0) { + fu_device_list_remove_with_delay (child_item); + continue; + } + fu_device_list_emit_device_removed (self, child); + g_rw_lock_writer_lock (&self->devices_mutex); + g_ptr_array_remove (self->devices, child_item); + g_rw_lock_writer_unlock (&self->devices_mutex); + } + /* delay the removal and check for replug */ if (fu_device_get_remove_delay (item->device) > 0) { - - /* we can't do anything with an unconnected device */ - fu_device_remove_flag (item->device, FWUPD_DEVICE_FLAG_UPDATABLE); - - /* give the hardware time to re-enumerate or the user time to - * re-insert the device with a magic button pressed */ - g_debug ("waiting %ums for device removal", - fu_device_get_remove_delay (item->device)); - item->remove_id = g_timeout_add (fu_device_get_remove_delay (item->device), - fu_device_list_device_delayed_remove_cb, - item); + fu_device_list_remove_with_delay (item); return; } /* remove right now */ fu_device_list_emit_device_removed (self, item->device); + g_rw_lock_writer_lock (&self->devices_mutex); g_ptr_array_remove (self->devices, item); + g_rw_lock_writer_unlock (&self->devices_mutex); } static void @@ -348,16 +427,79 @@ const gchar *guid_tmp = g_ptr_array_index (guids_old, i); if (!fu_device_has_guid (device_new, guid_tmp)) { g_debug ("adding GUID %s to device", guid_tmp); - fu_device_add_guid (device_new, guid_tmp); + fu_device_add_counterpart_guid (device_new, guid_tmp); } } } +static void +fu_device_list_replace (FuDeviceList *self, FuDeviceItem *item, FuDevice *device) +{ + /* clear timeout if scheduled */ + if (item->remove_id != 0) { + g_source_remove (item->remove_id); + item->remove_id = 0; + } + + /* copy over any GUIDs that used to exist */ + fu_device_list_add_missing_guids (device, item->device); + + /* enforce the vendor ID if specified */ + if (fu_device_get_vendor_id (item->device) != NULL && + fu_device_get_vendor_id (device) == NULL) { + const gchar *vendor_id = fu_device_get_vendor_id (item->device); + g_debug ("copying old vendor ID %s to new device", vendor_id); + fu_device_set_vendor_id (device, vendor_id); + } + + /* copy over the version strings if not set */ + if (fu_device_get_version (item->device) != NULL && + fu_device_get_version (device) == NULL) { + const gchar *version = fu_device_get_version (item->device); + g_debug ("copying old version %s to new device", version); + fu_device_set_version (device, version, + fu_device_get_version_format (item->device)); + } + + /* always use the runtime version */ + if (fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION) && + fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { + const gchar *version = fu_device_get_version (item->device); + g_debug ("forcing runtime version %s to new device", version); + fu_device_set_version (device, version, + fu_device_get_version_format (item->device)); + } + + /* allow another plugin to handle the write too */ + if (fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)) { + g_debug ("copying another-write-required to new device"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + } + + /* copy the parent if not already set */ + if (fu_device_get_parent (item->device) != NULL && + fu_device_get_parent (device) == NULL) { + FuDevice *parent = fu_device_get_parent (item->device); + g_debug ("copying parent %s to new device", fu_device_get_id (parent)); + fu_device_set_parent (device, parent); + } + + /* assign the new device */ + g_set_object (&item->device_old, item->device); + g_set_object (&item->device, device); + fu_device_list_emit_device_changed (self, device); + + /* we were waiting for this... */ + if (g_main_loop_is_running (item->replug_loop)) { + g_debug ("quitting replug loop"); + g_main_loop_quit (item->replug_loop); + } +} + /** * fu_device_list_add: * @self: A #FuDeviceList * @device: A #FuDevice - * @error: A #GError, or %NULL * * Adds a specific device to the device list if not already present. * @@ -393,7 +535,7 @@ g_source_remove (item->remove_id); item->remove_id = 0; } - fu_device_list_emit_device_changed (self, device); + fu_device_list_replace (self, item, device); return; } @@ -406,56 +548,56 @@ /* verify a compatible device does not already exist */ item = fu_device_list_get_by_guids (self, fu_device_get_guids (device)); + if (item == NULL) { + item = fu_device_list_find_by_connection (self, + fu_device_get_physical_id (device), + fu_device_get_logical_id (device)); + } if (item != NULL && item->remove_id != 0) { g_debug ("found compatible device %s recently removed, reusing " "item from plugin %s for plugin %s", fu_device_get_id (item->device), fu_device_get_plugin (item->device), fu_device_get_plugin (device)); + fu_device_list_replace (self, item, device); + return; + } - /* do not remove this device */ - g_source_remove (item->remove_id); - item->remove_id = 0; - - /* copy over any GUIDs that used to exist */ - fu_device_list_add_missing_guids (device, item->device); - - /* enforce the vendor ID if specified */ - if (fu_device_get_vendor_id (item->device) != NULL && - fu_device_get_vendor_id (device) == NULL) { - const gchar *vendor_id = fu_device_get_vendor_id (item->device); - g_debug ("copying old vendor ID %s to new device", vendor_id); - fu_device_set_vendor_id (device, vendor_id); - } - - /* copy over the version strings if not set */ - if (fu_device_get_version (item->device) != NULL && - fu_device_get_version (device) == NULL) { - const gchar *version = fu_device_get_version (item->device); - g_debug ("copying old version %s to new device", version); - fu_device_set_version (device, version); + /* added the same device from a different plugin */ + if (item != NULL && g_strcmp0 (fu_device_get_plugin (item->device), + fu_device_get_plugin (device)) != 0) { + if (fu_device_get_priority (device) < fu_device_get_priority (item->device)) { + g_debug ("ignoring device %s [%s] as better device %s [%s] already exists", + fu_device_get_id (device), + fu_device_get_plugin (device), + fu_device_get_id (item->device), + fu_device_get_plugin (item->device)); + return; } - - /* always use the runtime version */ - if (fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION) && - fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { - const gchar *version = fu_device_get_version (item->device); - g_debug ("forcing runtime version %s to new device", version); - fu_device_set_version (device, version); + if (fu_device_get_priority (device) == fu_device_get_priority (item->device)) { + g_warning ("ignoring device %s [%s] existing device %s [%s] already exists", + fu_device_get_id (device), + fu_device_get_plugin (device), + fu_device_get_id (item->device), + fu_device_get_plugin (item->device)); + return; } - - /* assign the new device */ - g_set_object (&item->device_old, item->device); - g_set_object (&item->device, device); - fu_device_list_emit_device_changed (self, device); - return; + g_debug ("removing device %s [%s] as better device %s [%s] added", + fu_device_get_id (item->device), + fu_device_get_plugin (item->device), + fu_device_get_id (device), + fu_device_get_plugin (device)); + fu_device_list_remove (self, item->device); } /* add helper */ item = g_new0 (FuDeviceItem, 1); item->self = self; /* no ref */ item->device = g_object_ref (device); + item->replug_loop = g_main_loop_new (NULL, FALSE); + g_rw_lock_writer_lock (&self->devices_mutex); g_ptr_array_add (self->devices, item); + g_rw_lock_writer_unlock (&self->devices_mutex); fu_device_list_emit_device_added (self, device); } @@ -467,7 +609,7 @@ * * Finds a specific device that has the matching GUID. * - * Returns: (transfer none): a device, or %NULL if not found + * Returns: (transfer full): a device, or %NULL if not found * * Since: 1.0.2 **/ @@ -480,7 +622,7 @@ g_return_val_if_fail (error == NULL || *error == NULL, NULL); item = fu_device_list_find_by_guid (self, guid); if (item != NULL) - return item->device; + return g_object_ref (item->device); g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, @@ -489,6 +631,90 @@ return NULL; } +static gboolean +fu_device_list_replug_cb (gpointer user_data) +{ + FuDeviceItem *item = (FuDeviceItem *) user_data; + + /* no longer valid */ + item->replug_id = 0; + + /* quit loop */ + g_debug ("device did not replug"); + g_main_loop_quit (item->replug_loop); + return FALSE; +} + +/** + * fu_device_list_wait_for_replug: + * @self: A #FuDeviceList + * @device: A #FuDevice + * @error: A #GError, or %NULL + * + * Waits for a specific device to replug if %FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG + * is set. + * + * If the device does not exist this function returns without an error. + * + * Returns: %TRUE for success + * + * Since: 1.1.2 + **/ +gboolean +fu_device_list_wait_for_replug (FuDeviceList *self, FuDevice *device, GError **error) +{ + FuDeviceItem *item; + guint remove_delay; + + g_return_val_if_fail (FU_IS_DEVICE_LIST (self), FALSE); + g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not found */ + item = fu_device_list_find_by_device (self, device); + if (item == NULL) + return TRUE; + + /* not required, or possibly literally just happened */ + if (!fu_device_has_flag (item->device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) { + g_debug ("no replug or re-enumerate required"); + return TRUE; + } + + /* plugin did not specify */ + remove_delay = fu_device_get_remove_delay (device); + if (remove_delay == 0) { + remove_delay = FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE; + g_warning ("plugin %s did not specify a remove delay for %s, " + "so guessing we should wait %ums for replug", + fu_device_get_plugin (device), + fu_device_get_id (device), + remove_delay); + } else { + g_debug ("waiting %ums for replug", remove_delay); + } + + /* time to unplug and then re-plug */ + item->replug_id = g_timeout_add (remove_delay, fu_device_list_replug_cb, item); + g_main_loop_run (item->replug_loop); + + /* the loop was quit without the timer */ + if (item->replug_id != 0) { + g_debug ("waited for replug"); + g_source_remove (item->replug_id); + item->replug_id = 0; + return TRUE; + } + + /* device was not added back to the device list */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "device %s did not come back", + fu_device_get_id (device)); + return FALSE; +} + /** * fu_device_list_get_by_id: * @self: A #FuDeviceList @@ -498,7 +724,7 @@ * Finds a specific device using the ID string. This function also supports * using abbreviated hashes. * - * Returns: (transfer none): a device, or %NULL if not found + * Returns: (transfer full): a device, or %NULL if not found * * Since: 1.0.2 **/ @@ -534,7 +760,7 @@ } /* something found */ - return item->device; + return g_object_ref (item->device); } static void @@ -542,8 +768,11 @@ { if (item->remove_id != 0) g_source_remove (item->remove_id); + if (item->replug_id != 0) + g_source_remove (item->replug_id); if (item->device_old != NULL) g_object_unref (item->device_old); + g_main_loop_unref (item->replug_loop); g_object_unref (item->device); g_free (item); } @@ -575,6 +804,7 @@ fu_device_list_init (FuDeviceList *self) { self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_device_list_item_free); + g_rw_lock_init (&self->devices_mutex); } static void @@ -583,6 +813,7 @@ FuDeviceList *self = FU_DEVICE_LIST (obj); g_ptr_array_unref (self->devices); + g_rw_lock_clear (&self->devices_mutex); G_OBJECT_CLASS (fu_device_list_parent_class)->finalize (obj); } diff -Nru fwupd-1.0.6/src/fu-device-list.h fwupd-1.2.10/src/fu-device-list.h --- fwupd-1.0.6/src/fu-device-list.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device-list.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,33 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_LIST_H -#define __FU_DEVICE_LIST_H - -G_BEGIN_DECLS +#pragma once #include #include "fu-device.h" +G_BEGIN_DECLS + #define FU_TYPE_DEVICE_LIST (fu_device_list_get_type ()) G_DECLARE_FINAL_TYPE (FuDeviceList, fu_device_list, FU, DEVICE_LIST, GObject) @@ -46,8 +30,8 @@ FuDevice *fu_device_list_get_by_guid (FuDeviceList *self, const gchar *guid, GError **error); +gboolean fu_device_list_wait_for_replug (FuDeviceList *self, + FuDevice *device, + GError **error); G_END_DECLS - -#endif /* __FU_DEVICE_LIST_H */ - diff -Nru fwupd-1.0.6/src/fu-device-locker.c fwupd-1.2.10/src/fu-device-locker.c --- fwupd-1.0.6/src/fu-device-locker.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device-locker.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuDeviceLocker" + #include "config.h" #include @@ -87,8 +74,8 @@ * manually closed using g_clear_object(). * * The functions used for opening and closing the device are set automatically. - * If the @device is not a type or supertype of #GUsbDevice or #FuUsbDevice - * then this function will not work. + * If the @device is not a type or supertype of #GUsbDevice or #FuDevice then + * this function will not work. * * For custom objects please use fu_device_locker_new_full(). * @@ -112,11 +99,11 @@ error); } - /* FuUsbDevice */ - if (FU_IS_USB_DEVICE (device)) { + /* FuDevice */ + if (FU_IS_DEVICE (device)) { return fu_device_locker_new_full (device, - (FuDeviceLockerFunc) fu_usb_device_open, - (FuDeviceLockerFunc) fu_usb_device_close, + (FuDeviceLockerFunc) fu_device_open, + (FuDeviceLockerFunc) fu_device_close, error); } g_set_error_literal (error, diff -Nru fwupd-1.0.6/src/fu-device-locker.h fwupd-1.2.10/src/fu-device-locker.h --- fwupd-1.0.6/src/fu-device-locker.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device-locker.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_LOCKER_H -#define __FU_DEVICE_LOCKER_H +#pragma once #include @@ -41,5 +25,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_DEVICE_LOCKER_H */ diff -Nru fwupd-1.0.6/src/fu-device-metadata.h fwupd-1.2.10/src/fu-device-metadata.h --- fwupd-1.0.6/src/fu-device-metadata.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device-metadata.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,14 @@ -/* -*- mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Mario Limonciello * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_METADATA_H__ -#define __FU_DEVICE_METADATA_H__ +#pragma once + +#include + +G_BEGIN_DECLS /** * SECTION:fu-device-metadata @@ -49,12 +37,31 @@ #define FU_DEVICE_METADATA_TBT_IS_SAFE_MODE "Thunderbolt::IsSafeMode" /** - * FU_DEVICE_METADATA_DELL_DOCK_TYPE: + * FU_DEVICE_METADATA_UEFI_DEVICE_KIND: + * + * The type of UEFI device, e.g. "system-firmware" or "device-firmware" + * Consumed by the uefi plugin when other devices register fake devices that + * need to be handled as a capsule update. + */ +#define FU_DEVICE_METADATA_UEFI_DEVICE_KIND "UefiDeviceKind" + +/** + * FU_DEVICE_METADATA_UEFI_FW_VERSION: + * + * The firmware version of the UEFI device specified as a 32 bit unsigned + * integer. + * Consumed by the uefi plugin when other devices register fake devices that + * need to be handled as a capsule update. + */ +#define FU_DEVICE_METADATA_UEFI_FW_VERSION "UefiFwVersion" + +/** + * FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS: * - * The type of dock plugged into the system - * (if any) - * Consumed by the synaptics plugin. + * The capsule flags for the UEFI device, e.g. %EFI_CAPSULE_HEADER_FLAGS_PERSIST_ACROSS_RESET + * Consumed by the uefi plugin when other devices register fake devices that + * need to be handled as a capsule update. */ -#define FU_DEVICE_METADATA_DELL_DOCK_TYPE "Dell::DockType" +#define FU_DEVICE_METADATA_UEFI_CAPSULE_FLAGS "UefiCapsuleFlags" -#endif /* __FU_DEVICE_METADATA_H__ */ +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-device-private.h fwupd-1.2.10/src/fu-device-private.h --- fwupd-1.0.6/src/fu-device-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-device-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,32 +1,50 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_DEVICE_PRIVATE_H -#define __FU_DEVICE_PRIVATE_H +#pragma once #include +#include G_BEGIN_DECLS -G_END_DECLS - -#endif /* __FU_DEVICE_PRIVATE_H */ +/** + * FuDeviceInstanceFlags: + * @FU_DEVICE_INSTANCE_FLAG_NONE: No flags set + * @FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS: Only use instance ID for quirk matching + * + * The flags to use when interacting with a device instance + **/ +typedef enum { + FU_DEVICE_INSTANCE_FLAG_NONE = 0, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS = 1 << 0, + /*< private >*/ + FU_DEVICE_INSTANCE_FLAG_LAST +} FuDeviceInstanceFlags; + +GPtrArray *fu_device_get_parent_guids (FuDevice *self); +gboolean fu_device_has_parent_guid (FuDevice *self, + const gchar *guid); +void fu_device_set_parent (FuDevice *self, + FuDevice *parent); +guint fu_device_get_order (FuDevice *self); +void fu_device_set_order (FuDevice *self, + guint order); +guint fu_device_get_priority (FuDevice *self); +void fu_device_set_priority (FuDevice *self, + guint priority); +void fu_device_set_alternate (FuDevice *self, + FuDevice *alternate); +gboolean fu_device_ensure_id (FuDevice *self, + GError **error); +void fu_device_incorporate_from_component (FuDevice *device, + XbNode *component); +void fu_device_convert_instance_ids (FuDevice *self); +void fu_device_add_instance_id_full (FuDevice *self, + const gchar *instance_id, + FuDeviceInstanceFlags flags); +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-engine.c fwupd-1.2.10/src/fu-engine.c --- fwupd-1.0.6/src/fu-engine.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-engine.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,18 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuEngine" + #include "config.h" -#include #include #include #include +#include +#include #include #include @@ -43,19 +31,21 @@ #include "fu-device-private.h" #include "fu-engine.h" #include "fu-hwids.h" -#include "fu-keyring.h" +#include "fu-idle.h" +#include "fu-keyring-utils.h" +#include "fu-hash.h" #include "fu-history.h" +#include "fu-mutex.h" #include "fu-plugin.h" #include "fu-plugin-list.h" #include "fu-plugin-private.h" #include "fu-quirks.h" #include "fu-smbios.h" +#include "fu-udev-device-private.h" +#include "fu-usb-device-private.h" -#ifdef ENABLE_GPG -#include "fu-keyring-gpg.h" -#endif -#ifdef ENABLE_PKCS7 -#include "fu-keyring-pkcs7.h" +#ifdef HAVE_SYSTEMD +#include "fu-systemd.h" #endif static void fu_engine_finalize (GObject *obj); @@ -63,22 +53,30 @@ struct _FuEngine { GObject parent_instance; + FuAppFlags app_flags; GUsbContext *usb_ctx; + GUdevClient *gudev_client; FuConfig *config; FuDeviceList *device_list; FwupdStatus status; + gboolean tainted; guint percentage; FuHistory *history; - AsProfile *profile; - AsStore *store; + FuIdle *idle; + XbSilo *silo; gboolean coldplug_running; guint coldplug_id; guint coldplug_delay; FuPluginList *plugin_list; - GPtrArray *supported_guids; + GPtrArray *plugin_filter; + GPtrArray *udev_subsystems; FuSmbios *smbios; FuHwids *hwids; FuQuirks *quirks; + GHashTable *runtime_versions; + GHashTable *compile_versions; + GHashTable *approved_firmware; + gboolean loaded; }; enum { @@ -95,15 +93,11 @@ G_DEFINE_TYPE (FuEngine, fu_engine, G_TYPE_OBJECT) -#define FU_ENGINE_REQUIREMENT_FIRMWARE_RUNTIME NULL /* yes, NULL */ -#define FU_ENGINE_REQUIREMENT_FIRMWARE_BOOTLOADER "bootloader" -#define FU_ENGINE_REQUIREMENT_FIRMWARE_VENDOR "vendor-id" -#define FU_ENGINE_REQUIREMENT_ID_FWUPD "org.freedesktop.fwupd" - static void fu_engine_emit_changed (FuEngine *self) { g_signal_emit (self, signals[SIGNAL_CHANGED], 0); + fu_engine_idle_reset (self); } static void @@ -127,20 +121,6 @@ return self->status; } -/** - * fu_engine_profile_dump: - * @self: A #FuEngine - * - * Dumps the engine profiling state to the console. - **/ -void -fu_engine_profile_dump (FuEngine *self) -{ - g_return_if_fail (FU_IS_ENGINE (self)); - as_profile_set_duration_min (self->profile, 1); - as_profile_dump (self->profile); -} - static void fu_engine_set_status (FuEngine *self, FwupdStatus status) { @@ -168,19 +148,23 @@ static void fu_engine_progress_notify_cb (FuDevice *device, GParamSpec *pspec, FuEngine *self) { + if (fu_device_get_status (device) == FWUPD_STATUS_UNKNOWN) + return; fu_engine_set_percentage (self, fu_device_get_progress (device)); + fu_engine_emit_device_changed (self, device); } static void fu_engine_status_notify_cb (FuDevice *device, GParamSpec *pspec, FuEngine *self) { fu_engine_set_status (self, fu_device_get_status (device)); + fu_engine_emit_device_changed (self, device); } static void fu_engine_watch_device (FuEngine *self, FuDevice *device) { - FuDevice *device_old = fu_device_list_get_old (self->device_list, device); + g_autoptr(FuDevice) device_old = fu_device_list_get_old (self->device_list, device); if (device_old != NULL) { g_signal_handlers_disconnect_by_func (device_old, fu_engine_progress_notify_cb, @@ -203,8 +187,19 @@ } static void +fu_engine_device_runner_device_removed (FuEngine *self, FuDevice *device) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + fu_plugin_runner_device_removed (plugin_tmp, device); + } +} + +static void fu_engine_device_removed_cb (FuDeviceList *device_list, FuDevice *device, FuEngine *self) { + fu_engine_device_runner_device_removed (self, device); g_signal_handlers_disconnect_by_data (device, self); g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device); } @@ -216,53 +211,165 @@ fu_engine_emit_device_changed (self, device); } -static const gchar * -_as_release_get_metadata_item (AsRelease *release, const gchar *key) +static gboolean +fu_engine_set_device_version_format (FuEngine *self, FuDevice *device, XbNode *component, GError **error) { - GBytes *blob = as_release_get_blob (release, key); - if (blob == NULL) + FwupdVersionFormat fmt; + const gchar *developer_name; + const gchar *version_format; + + /* specified in metadata */ + version_format = xb_node_query_text (component, + "custom/value[@key='LVFS::VersionFormat']", + NULL); + if (version_format != NULL) { + fmt = fwupd_version_format_from_string (version_format); + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "version format from metadata %s unsupported", + version_format); + return FALSE; + } + g_debug ("using VersionFormat %s from metadata", version_format); + fu_device_set_version_format (device, fmt); + return TRUE; + } + + /* fall back to the SmbiosManufacturer quirk */ + developer_name = xb_node_query_text (component, "developer_name", NULL); + if (developer_name != NULL && + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) { + g_autofree gchar *group = NULL; + group = g_strdup_printf ("SmbiosManufacturer=%s", developer_name); + version_format = fu_quirks_lookup_by_id (self->quirks, group, + FU_QUIRKS_UEFI_VERSION_FORMAT); + if (version_format != NULL) { + fmt = fwupd_version_format_from_string (version_format); + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "version format %s from quirk %s unsupported", + version_format, developer_name); + return FALSE; + } + g_debug ("using VersionFormat %s from SmbiosManufacturer %s", + version_format, developer_name); + fu_device_set_version_format (device, fmt); + return TRUE; + } + } + + /* nothing found, which is probably fine */ + return TRUE; +} + +/* convert hex and decimal versions to dotted style */ +static gchar * +fu_engine_get_release_version (FuEngine *self, FuDevice *dev, XbNode *rel, GError **error) +{ + FwupdVersionFormat fmt = FWUPD_VERSION_FORMAT_TRIPLET; + const gchar *version; + guint64 ver_uint32; + + /* get version */ + version = xb_node_get_attr (rel, "version"); + if (version == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "version unset"); + return NULL; + } + + /* already dotted notation */ + if (g_strstr_len (version, -1, ".") != NULL) + return g_strdup (version); + + /* specified in metadata or from a quirk */ + fmt = fu_device_get_version_format (dev); + if (fmt == FWUPD_VERSION_FORMAT_UNKNOWN) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "version format unset and version %s ambiguous", + version); return NULL; - return (const gchar *) g_bytes_get_data (blob, NULL); + } + + /* don't touch my version! */ + if (fmt == FWUPD_VERSION_FORMAT_PLAIN) + return g_strdup (version); + + /* parse as integer */ + ver_uint32 = fu_common_strtoull (version); + if (ver_uint32 == 0 || ver_uint32 > G_MAXUINT32) + return g_strdup (version); + + /* convert to dotted decimal */ + return fu_common_version_from_uint32 ((guint32) ver_uint32, fmt); } -static void +static gboolean fu_engine_set_release_from_appstream (FuEngine *self, + FuDevice *dev, FwupdRelease *rel, - AsApp *app, - AsRelease *release) + XbNode *component, + XbNode *release, + GError **error) { - AsChecksum *csum; FwupdRemote *remote = NULL; const gchar *tmp; const gchar *remote_id; + guint64 tmp64; + g_autofree gchar *version_rel = NULL; + g_autoptr(GPtrArray) cats = NULL; + g_autoptr(XbNode) description = NULL; + + /* set from the component */ + tmp = xb_node_query_text (component, "id", NULL); + if (tmp != NULL) + fwupd_release_set_appstream_id (rel, tmp); + tmp = xb_node_query_text (component, "url[@type='homepage']", NULL); + if (tmp != NULL) + fwupd_release_set_homepage (rel, tmp); + tmp = xb_node_query_text (component, "project_license", NULL); + if (tmp != NULL) + fwupd_release_set_license (rel, tmp); + tmp = xb_node_query_text (component, "name", NULL); + if (tmp != NULL) + fwupd_release_set_name (rel, tmp); + tmp = xb_node_query_text (component, "summary", NULL); + if (tmp != NULL) + fwupd_release_set_summary (rel, tmp); + tmp = xb_node_query_text (component, "developer_name", NULL); + if (tmp != NULL) + fwupd_release_set_vendor (rel, tmp); - /* set from the AsApp */ - fwupd_release_set_appstream_id (rel, as_app_get_id (app)); - fwupd_release_set_homepage (rel, as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE)); - fwupd_release_set_license (rel, as_app_get_project_license (app)); - fwupd_release_set_name (rel, as_app_get_name (app, NULL)); - fwupd_release_set_summary (rel, as_app_get_comment (app, NULL)); - fwupd_release_set_vendor (rel, as_app_get_developer_name (app, NULL)); - fwupd_release_set_appstream_id (rel, as_app_get_id (app)); + /* the version is fixed up at runtime */ + version_rel = fu_engine_get_release_version (self, dev, release, error); + if (version_rel == NULL) + return FALSE; + fwupd_release_set_version (rel, version_rel); /* find the remote */ - remote_id = _as_release_get_metadata_item (release, "fwupd::RemoteId"); + remote_id = xb_node_query_text (component, "../custom/value[@key='fwupd::RemoteId']", NULL); if (remote_id != NULL) { fwupd_release_set_remote_id (rel, remote_id); remote = fu_config_get_remote_by_id (self->config, remote_id); - if (remote == NULL) { - g_warning ("no remote found for release %s", - as_release_get_version (release)); - } + if (remote == NULL) + g_warning ("no remote found for release %s", version_rel); } - - tmp = as_release_get_version (release); - if (tmp != NULL) - fwupd_release_set_version (rel, tmp); - tmp = as_release_get_description (release, NULL); - if (tmp != NULL) - fwupd_release_set_description (rel, tmp); - tmp = as_release_get_location_default (release); + description = xb_node_query_first (release, "description", NULL); + if (description != NULL) { + g_autofree gchar *xml = NULL; + xml = xb_node_export (description, XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, NULL); + if (xml != NULL) + fwupd_release_set_description (rel, xml); + } + tmp = xb_node_query_text (release, "location", NULL); if (tmp != NULL) { g_autofree gchar *uri = NULL; if (remote != NULL) @@ -270,173 +377,70 @@ if (uri == NULL) uri = g_strdup (tmp); fwupd_release_set_uri (rel, uri); + } else if (remote != NULL && + fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + g_autofree gchar *uri = NULL; + tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::FilenameCache']", NULL); + if (tmp != NULL) { + uri = g_strdup_printf ("file://%s", tmp); + fwupd_release_set_uri (rel, uri); + } } - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum != NULL) { - tmp = as_checksum_get_filename (csum); - if (tmp != NULL) - fwupd_release_set_filename (rel, tmp); - } - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTAINER); - if (csum != NULL) { - tmp = as_checksum_get_value (csum); - if (tmp != NULL) - fwupd_release_add_checksum (rel, tmp); - } - fwupd_release_set_size (rel, as_release_get_size (release, AS_SIZE_KIND_INSTALLED)); -} - -static FuKeyring * -fu_engine_get_keyring_for_kind (FwupdKeyringKind kind, GError **error) -{ - if (kind == FWUPD_KEYRING_KIND_GPG) { -#ifdef ENABLE_GPG - return fu_keyring_gpg_new (); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not compiled with GPG support"); - return NULL; -#endif - } - if (kind == FWUPD_KEYRING_KIND_PKCS7) { -#ifdef ENABLE_PKCS7 - return fu_keyring_pkcs7_new (); -#else - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Not compiled with PKCS7 support"); - return NULL; -#endif + tmp = xb_node_query_text (release, "checksum[@target='content']", NULL); + if (tmp != NULL) + fwupd_release_set_filename (rel, tmp); + tmp = xb_node_query_text (release, "url[@type='details']", NULL); + if (tmp != NULL) + fwupd_release_set_details_url (rel, tmp); + tmp = xb_node_query_text (release, "url[@type='source']", NULL); + if (tmp != NULL) + fwupd_release_set_source_url (rel, tmp); + tmp = xb_node_query_text (release, "checksum[@target='container']", NULL); + if (tmp != NULL) + fwupd_release_add_checksum (rel, tmp); + tmp64 = xb_node_query_text_as_uint (release, "size[@type='installed']", NULL); + if (tmp64 != G_MAXUINT64) { + fwupd_release_set_size (rel, tmp64); + } else { + GBytes *sz = xb_node_get_data (release, "fwupd::ReleaseSize"); + if (sz != NULL) { + const guint64 *sizeptr = g_bytes_get_data (sz, NULL); + fwupd_release_set_size (rel, *sizeptr); + } + } + tmp64 = xb_node_get_attr_as_uint (release, "install_duration"); + if (tmp64 != G_MAXUINT64) + fwupd_release_set_install_duration (rel, tmp64); + cats = xb_node_query (component, "categories/category", 0, NULL); + if (cats != NULL) { + for (guint i = 0; i < cats->len; i++) { + XbNode *n = g_ptr_array_index (cats, i); + fwupd_release_add_category (rel, xb_node_get_text (n)); + } } - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Keyring kind %s not supported", - fwupd_keyring_kind_to_string (kind)); - return NULL; + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateProtocol']", NULL); + if (tmp != NULL) + fwupd_release_set_protocol (rel, tmp); + tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateMessage']", NULL); + if (tmp != NULL) + fwupd_release_set_update_message (rel, tmp); + return TRUE; } -/* finds the remote-id for the first firmware in the store that matches this +/* finds the remote-id for the first firmware in the silo that matches this * container checksum */ static const gchar * fu_engine_get_remote_id_for_checksum (FuEngine *self, const gchar *csum) { - GPtrArray *array = as_store_get_apps (self->store); - for (guint i = 0; i < array->len; i++) { - AsApp *app = g_ptr_array_index (array, i); - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - AsChecksum *checksum; - checksum = as_release_get_checksum_by_target (release, - AS_CHECKSUM_TARGET_CONTAINER); - if (checksum == NULL) - continue; - if (g_strcmp0 (csum, as_checksum_get_value (checksum)) == 0) - return _as_release_get_metadata_item (release, "fwupd::RemoteId"); - } - } - return NULL; -} - -static gboolean -fu_engine_get_release_trust_flags (AsRelease *release, - FwupdTrustFlags *trust_flags, - GError **error) -{ - AsChecksum *csum_tmp; - FwupdKeyringKind keyring_kind = FWUPD_KEYRING_KIND_UNKNOWN; - GBytes *blob_payload; - GBytes *blob_signature; - const gchar *fn; - g_autofree gchar *pki_dir = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(FuKeyring) kr = NULL; - g_autoptr(FuKeyringResult) kr_result = NULL; - struct { - FwupdKeyringKind kind; - const gchar *ext; - } keyrings[] = { - { FWUPD_KEYRING_KIND_GPG, "asc" }, - { FWUPD_KEYRING_KIND_PKCS7, "p7b" }, - { FWUPD_KEYRING_KIND_PKCS7, "p7c" }, - { FWUPD_KEYRING_KIND_NONE, NULL } - }; - - /* no filename? */ - csum_tmp = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - fn = as_checksum_get_filename (csum_tmp); - if (fn == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no filename"); - return FALSE; - } - - /* no signature == no trust */ - for (guint i = 0; keyrings[i].ext != NULL; i++) { - g_autofree gchar *fn_tmp = g_strdup_printf ("%s.%s", fn, keyrings[i].ext); - blob_signature = as_release_get_blob (release, fn_tmp); - if (blob_signature != NULL) { - keyring_kind = keyrings[i].kind; - break; - } - } - if (keyring_kind == FWUPD_KEYRING_KIND_UNKNOWN) { - g_debug ("firmware archive contained no signature"); - return TRUE; - } - - /* get payload */ - blob_payload = as_release_get_blob (release, fn); - if (blob_payload == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no payload"); - return FALSE; - } - - /* check we were installed correctly */ - pki_dir = g_build_filename (SYSCONFDIR, "pki", "fwupd", NULL); - if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "PKI directory %s not found", pki_dir); - return FALSE; - } - - /* verify against the system trusted keys */ - kr = fu_engine_get_keyring_for_kind (keyring_kind, error); - if (kr == NULL) - return FALSE; - if (!fu_keyring_setup (kr, error)) { - g_prefix_error (error, "failed to set up %s keyring: ", - fu_keyring_get_name (kr)); - return FALSE; - } - if (!fu_keyring_add_public_keys (kr, pki_dir, error)) { - g_prefix_error (error, "failed to add public keys to %s keyring: ", - fu_keyring_get_name (kr)); - return FALSE; - } - kr_result = fu_keyring_verify_data (kr, blob_payload, blob_signature, &error_local); - if (kr_result == NULL) { - g_warning ("untrusted as failed to verify from %s keyring: %s", - fu_keyring_get_name (kr), - error_local->message); - return TRUE; - } - - /* awesome! */ - g_debug ("marking payload as trusted"); - *trust_flags |= FWUPD_TRUST_FLAG_PAYLOAD; - return TRUE; + g_autofree gchar *xpath = NULL; + g_autoptr(XbNode) key = NULL; + xpath = g_strdup_printf ("components/component/releases/release/" + "checksum[@target='container'][text()='%s']/../../" + "../../custom/value[@key='fwupd::RemoteId']", csum); + key = xb_silo_query_first (self->silo, xpath, NULL); + if (key == NULL) + return NULL; + return xb_node_get_text (key); } /** @@ -452,8 +456,8 @@ gboolean fu_engine_unlock (FuEngine *self, const gchar *device_id, GError **error) { - FuDevice *device; FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -481,61 +485,33 @@ return TRUE; } -static AsApp * -fu_engine_verify_update_device_to_app (FuDevice *device) +gboolean +fu_engine_modify_config (FuEngine *self, const gchar *key, const gchar *value, GError **error) { - AsApp *app = NULL; - GPtrArray *checksums; - g_autofree gchar *id = NULL; - g_autoptr(AsFormat) format = NULL; - g_autoptr(AsProvide) prov = NULL; - g_autoptr(AsRelease) rel = NULL; - - /* make a plausible ID */ - id = g_strdup_printf ("%s.firmware", fu_device_get_guid_default (device)); - - /* add app to store */ - app = as_app_new (); - as_app_set_id (app, id); - as_app_set_kind (app, AS_APP_KIND_FIRMWARE); - rel = as_release_new (); - as_release_set_version (rel, fu_device_get_version (device)); - checksums = fu_device_get_checksums (device); - for (guint j = 0; j < checksums->len; j++) { - const gchar *checksum = g_ptr_array_index (checksums, j); - g_autoptr(AsChecksum) csum = as_checksum_new (); - as_checksum_set_kind (csum, fwupd_checksum_guess_kind (checksum)); - as_checksum_set_value (csum, checksum); - as_checksum_set_target (csum, AS_CHECKSUM_TARGET_CONTENT); - as_release_add_checksum (rel, csum); - } - as_app_add_release (app, rel); - prov = as_provide_new (); - as_provide_set_kind (prov, AS_PROVIDE_KIND_FIRMWARE_FLASHED); - as_provide_set_value (prov, fu_device_get_guid_default (device)); - as_app_add_provide (app, prov); - format = as_format_new (); - as_format_set_kind (format, AS_FORMAT_KIND_UNKNOWN); - as_app_add_format (app, format); - return app; -} + const gchar *keys[] = { + "ArchiveSizeMax", + "BlacklistDevices", + "BlacklistPlugins", + "IdleTimeout", + "VerboseDomains", + NULL }; -static AsStore * -fu_engine_load_verify_store (GError **error) -{ - const gchar *fn = "/var/lib/fwupd/verify.xml"; - g_autoptr(AsStore) store = NULL; - g_autoptr(GFile) file = NULL; + g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - /* load existing store */ - store = as_store_new (); - as_store_set_api_version (store, 0.9); - file = g_file_new_for_path (fn); - if (g_file_query_exists (file, NULL)) { - if (!as_store_from_file (store, file, NULL, NULL, error)) - return NULL; + /* check keys are valid */ + if (!g_strv_contains (keys, key)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "key %s not supported", key); + return FALSE; } - return g_steal_pointer (&store); + + /* modify, effective next reboot */ + return fu_config_modify_and_save (self->config, key, value, error); } /** @@ -546,7 +522,7 @@ * @value: the key, e.g. `true` * @error: A #GError, or %NULL * - * Updates the verification store entry for a specific device. + * Updates the verification silo entry for a specific device. * * Returns: %TRUE for success **/ @@ -653,26 +629,44 @@ return FALSE; } +static const gchar * +fu_engine_checksum_type_to_string (GChecksumType checksum_type) +{ + if (checksum_type == G_CHECKSUM_SHA1) + return "sha1"; + if (checksum_type == G_CHECKSUM_SHA256) + return "sha256"; + if (checksum_type == G_CHECKSUM_SHA512) + return "sha512"; + return "sha1"; +} + /** * fu_engine_verify_update: * @self: A #FuEngine * @device_id: A device ID * @error: A #GError, or %NULL * - * Updates the verification store entry for a specific device. + * Updates the verification silo entry for a specific device. * * Returns: %TRUE for success **/ gboolean fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error) { - FuDevice *device; FuPlugin *plugin; GPtrArray *checksums; - const gchar *fn = "/var/lib/fwupd/verify.xml"; - g_autoptr(AsApp) app = NULL; - g_autoptr(AsStore) store = NULL; + GPtrArray *guids; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + g_autoptr(FuDevice) device = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderNode) component = NULL; + g_autoptr(XbBuilderNode) provides = NULL; + g_autoptr(XbBuilderNode) release = NULL; + g_autoptr(XbBuilderNode) releases = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -709,38 +703,70 @@ return FALSE; } - /* load existing store */ - store = fu_engine_load_verify_store (error); - if (store == NULL) + /* build XML */ + component = xb_builder_node_insert (NULL, "component", + "type", "firmware", + NULL); + provides = xb_builder_node_insert (component, "provides", NULL); + guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autoptr(XbBuilderNode) provide = NULL; + provide = xb_builder_node_insert (provides, "firmware", + "type", "flashed", + NULL); + xb_builder_node_set_text (provide, guid, -1); + } + releases = xb_builder_node_insert (component, "releases", NULL); + release = xb_builder_node_insert (releases, "release", + "version", fu_device_get_version (device), + NULL); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + GChecksumType kind = fwupd_checksum_guess_kind (checksum); + g_autoptr(XbBuilderNode) csum = NULL; + csum = xb_builder_node_insert (release, "checksum", + "type", fu_engine_checksum_type_to_string (kind), + "target", "content", + NULL); + xb_builder_node_set_text (csum, checksum, -1); + } + xb_builder_import_node (builder, component); + + /* save silo */ + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); + if (!fu_common_mkdir_parent (fn, error)) return FALSE; - - /* add to store */ - app = fu_engine_verify_update_device_to_app (device); - as_store_remove_app_by_id (store, as_app_get_id (app)); - as_store_add_app (store, app); - - /* write */ - g_debug ("writing %s", fn); file = g_file_new_for_path (fn); - return as_store_to_file (store, file, - AS_NODE_TO_XML_FLAG_ADD_HEADER | - AS_NODE_TO_XML_FLAG_FORMAT_INDENT | - AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, - NULL, error); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, error); + if (silo == NULL) + return FALSE; + if (!xb_silo_export_file (silo, file, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE, + NULL, error)) + return FALSE; + + /* success */ + return TRUE; } -static AsApp * -fu_engine_store_get_app_by_guids (AsStore *store, FuDevice *device) +XbNode * +fu_engine_get_component_by_guids (FuEngine *self, FuDevice *device) { GPtrArray *guids = fu_device_get_guids (device); + g_autoptr(GString) xpath = g_string_new (NULL); + g_autoptr(XbNode) component = NULL; for (guint i = 0; i < guids->len; i++) { - AsApp *app = NULL; - app = as_store_get_app_by_provide (store, - AS_PROVIDE_KIND_FIRMWARE_FLASHED, - g_ptr_array_index (guids, i)); - if (app != NULL) - return app; - } + const gchar *guid = g_ptr_array_index (guids, i); + xb_string_append_union (xpath, + "components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../..", guid); + } + component = xb_silo_query_first (self->silo, xpath->str, NULL); + if (component != NULL) + return g_steal_pointer (&component); return NULL; } @@ -750,22 +776,24 @@ * @device_id: A device ID * @error: A #GError, or %NULL * - * Verifies a device firmware checksum using the verification store entry. + * Verifies a device firmware checksum using the verification silo entry. * * Returns: %TRUE for success **/ gboolean fu_engine_verify (FuEngine *self, const gchar *device_id, GError **error) { - AsApp *app; - AsChecksum *csum; - AsRelease *release; - FuDevice *device = NULL; FuPlugin *plugin; GPtrArray *checksums; - const gchar *hash = NULL; - const gchar *version = NULL; - g_autoptr(AsStore) store = NULL; + const gchar *version; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + g_autoptr(FuDevice) device = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GString) xpath_csum = g_string_new (NULL); + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) release = NULL; + g_autoptr(XbSilo) silo = xb_silo_new (); g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (device_id != NULL, FALSE); @@ -789,32 +817,42 @@ return FALSE; /* find component in metadata */ - store = fu_engine_load_verify_store (error); - if (store == NULL) - return FALSE; - app = fu_engine_store_get_app_by_guids (store, device); - if (app == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No metadata"); - return FALSE; + version = fu_device_get_version (device); + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_strdup_printf ("%s/verify/%s.xml", localstatedir, device_id); + file = g_file_new_for_path (fn); + if (g_file_query_exists (file, NULL)) { + g_autofree gchar *xpath = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, error)) + return FALSE; + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, + XB_BUILDER_COMPILE_FLAG_NONE, + NULL, error); + if (silo == NULL) + return FALSE; + xpath = g_strdup_printf ("component/releases/release[@version='%s']", version); + release = xb_silo_query_first (silo, xpath, NULL); } - /* find version in metadata */ - version = fu_device_get_version (device); - release = as_app_get_release (app, version); + /* try again with the system metadata */ if (release == NULL) { - /* try again with the system metadata */ - app = fu_engine_store_get_app_by_guids (self->store, device); - if (app == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No system metadata"); - return FALSE; + GPtrArray *guids = fu_device_get_guids (device); + for (guint i = 0; i < guids->len; i++) { + const gchar *guid = g_ptr_array_index (guids, i); + g_autofree gchar *xpath2 = NULL; + xpath2 = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']/" + "../../releases/release[@version='%s']", + guid, version); + release = xb_silo_query_first (self->silo, xpath2, NULL); + if (release != NULL) + break; } - release = as_app_get_release (app, version); } if (release == NULL) { g_set_error (error, @@ -824,16 +862,6 @@ return FALSE; } - /* find checksum */ - csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); - if (csum == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No content checksum for %s", version); - return FALSE; - } - /* get the matching checksum */ checksums = fu_device_get_checksums (device); if (checksums->len == 0) { @@ -843,29 +871,52 @@ "No device checksums for %s", version); return FALSE; } + + /* do any of the checksums in the release match any in the device */ for (guint j = 0; j < checksums->len; j++) { const gchar *hash_tmp = g_ptr_array_index (checksums, j); - GChecksumType hash_kind = fwupd_checksum_guess_kind (hash_tmp); - if (as_checksum_get_kind (csum) == hash_kind) { - hash = hash_tmp; - break; - } - } - if (hash == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "No matching hash kind for %s", version); - return FALSE; + xb_string_append_union (xpath_csum, + "checksum[@target='device'][text()='%s']", + hash_tmp); + xb_string_append_union (xpath_csum, + "checksum[@target='content'][text()='%s']", + hash_tmp); } - if (g_strcmp0 (as_checksum_get_value (csum), hash) != 0) { + csum = xb_node_query_first (release, xpath_csum->str, NULL); + if (csum == NULL) { + g_autoptr(GString) checksums_device = g_string_new (NULL); + g_autoptr(GString) checksums_metadata = g_string_new (NULL); + g_autoptr(GPtrArray) csums = NULL; + g_autoptr(GString) xpath = g_string_new (NULL); + + /* get all checksums to display a useful error */ + xb_string_append_union (xpath, "checksum[@target='device']"); + xb_string_append_union (xpath, "checksum[@target='content']"); + csums = xb_node_query (release, xpath->str, 0, NULL); + if (csums == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No device or content checksum for %s", + version); + return FALSE; + } + for (guint i = 0; i < csums->len; i++) { + XbNode *csum_tmp = g_ptr_array_index (csums, i); + xb_string_append_union (checksums_metadata, + "%s", xb_node_get_text (csum_tmp)); + } + for (guint i = 0; i < checksums->len; i++) { + const gchar *hash_tmp = g_ptr_array_index (checksums, i); + xb_string_append_union (checksums_device, "%s", hash_tmp); + } g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "For v%s expected %s, got %s", version, - as_checksum_get_value (csum), - hash); + checksums_metadata->str, + checksums_device->str); return FALSE; } @@ -873,79 +924,105 @@ return TRUE; } -static AsScreenshot * -_as_app_get_screenshot_default (AsApp *app) +static gboolean +fu_engine_require_vercmp (XbNode *req, const gchar *version, GError **error) { -#if AS_CHECK_VERSION(0,7,3) - return as_app_get_screenshot_default (app); -#else - GPtrArray *array = as_app_get_screenshots (app); - if (array->len == 0) - return NULL; - return g_ptr_array_index (array, 0); -#endif + gboolean ret = FALSE; + gint rc = 0; + const gchar *tmp = xb_node_get_attr (req, "compare"); + const gchar *version_req = xb_node_get_attr (req, "version"); + + if (g_strcmp0 (tmp, "eq") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc == 0; + } else if (g_strcmp0 (tmp, "ne") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc != 0; + } else if (g_strcmp0 (tmp, "lt") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc < 0; + } else if (g_strcmp0 (tmp, "gt") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc > 0; + } else if (g_strcmp0 (tmp, "le") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc <= 0; + } else if (g_strcmp0 (tmp, "ge") == 0) { + rc = fu_common_vercmp (version, version_req); + ret = rc >= 0; + } else if (g_strcmp0 (tmp, "glob") == 0) { + ret = fnmatch (version_req, version, 0) == 0; + } else if (g_strcmp0 (tmp, "regex") == 0) { + ret = g_regex_match_simple (version_req, version, 0, 0); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "failed to compare [%s] and [%s]", + version_req, + version); + return FALSE; + } + + /* set error */ + if (!ret) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed predicate [%s %s %s]", + version_req, tmp, version); + } + return ret; } -static GPtrArray * -_as_store_get_apps_by_provide (AsStore *store, AsProvideKind kind, const gchar *value) +static gboolean +fu_engine_check_requirement_not_child (FuEngine *self, XbNode *req, + FuDevice *device, GError **error) { -#if AS_CHECK_VERSION(0,7,5) - return as_store_get_apps_by_provide (store, kind, value); -#else - GPtrArray *apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - GPtrArray *array = as_store_get_apps (store); - for (guint i = 0; i < array->len; i++) { - AsApp *app = g_ptr_array_index (array, i); - GPtrArray *provides = as_app_get_provides (app); - for (guint j = 0; j < provides->len; j++) { - AsProvide *tmp = g_ptr_array_index (provides, j); - if (kind != as_provide_get_kind (tmp)) - continue; - if (g_strcmp0 (as_provide_get_value (tmp), value) != 0) - continue; - g_ptr_array_add (apps, g_object_ref (app)); + GPtrArray *children = fu_device_get_children (device); + + /* only supported */ + if (g_strcmp0 (xb_node_get_element (req), "firmware") != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot handle not-child %s requirement", + xb_node_get_element (req)); + return FALSE; + } + + /* check each child */ + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + const gchar *version = fu_device_get_version (child); + if (fu_engine_require_vercmp (req, version, NULL)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not compatible with child device version %s", + version); + return FALSE; } } - return apps; -#endif + return TRUE; } static gboolean -fu_engine_check_version_requirement (AsApp *app, - AsRequireKind kind, - const gchar *id, - const gchar *version, - GError **error) +fu_engine_check_requirement_firmware (FuEngine *self, XbNode *req, + FuDevice *device, GError **error) { - AsRequire *req; g_autoptr(GError) error_local = NULL; - /* check args */ - if (version == NULL) { - g_debug ("no parameter given for %s{%s}", - as_require_kind_to_string (kind), id); - return TRUE; - } - - /* does requirement exist */ - req = as_app_get_require_by_value (app, kind, id); - if (req == NULL) { - g_debug ("no requirement on %s{%s}", - as_require_kind_to_string (kind), id); - return TRUE; - } - - /* check version */ - if (!as_require_version_compare (req, version, &error_local)) { - - /* firmware */ - if (g_strcmp0 (id, FU_ENGINE_REQUIREMENT_FIRMWARE_RUNTIME) == 0) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + /* old firmware version */ + if (xb_node_get_text (req) == NULL) { + const gchar *version = fu_device_get_version (device); + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Not compatible with firmware version %s, requires >= %s", - version, as_require_get_version (req)); + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, @@ -955,268 +1032,228 @@ } return FALSE; } + return TRUE; + } - /* fwupd */ - if (g_strcmp0 (id, FU_ENGINE_REQUIREMENT_ID_FWUPD) == 0) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + /* bootloader version */ + if (g_strcmp0 (xb_node_get_text (req), "bootloader") == 0) { + const gchar *version = fu_device_get_version_bootloader (device); + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Not compatible with fwupd version %s, requires >= %s", - version, as_require_get_version (req)); + "Not compatible with bootloader version %s, requires >= %s", + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Not compatible with fwupd version: %s", + "Not compatible with bootloader version: %s", error_local->message); } return FALSE; } + return TRUE; + } - /* bootloader */ - if (g_strcmp0 (id, FU_ENGINE_REQUIREMENT_FIRMWARE_BOOTLOADER) == 0) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + /* vendor ID */ + if (g_strcmp0 (xb_node_get_text (req), "vendor-id") == 0) { + const gchar *version = fu_device_get_vendor_id (device); + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Not compatible with bootloader version %s, requires >= %s", - version, as_require_get_version (req)); + "Not compatible with vendor %s, requires >= %s", + version, xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Not compatible with bootloader version: %s", + "Not compatible with vendor: %s", error_local->message); } return FALSE; } + return TRUE; + } + + /* child version */ + if (g_strcmp0 (xb_node_get_text (req), "not-child") == 0) + return fu_engine_check_requirement_not_child (self, req, device, error); + + /* another device */ + if (fwupd_guid_is_valid (xb_node_get_text (req))) { + const gchar *guid = xb_node_get_text (req); + const gchar *version; + g_autoptr(FuDevice) device2 = NULL; + + /* find if the other device exists */ + device2 = fu_device_list_get_by_guid (self->device_list, guid, error); + if (device2 == NULL) + return FALSE; - /* vendor */ - if (g_strcmp0 (id, FU_ENGINE_REQUIREMENT_FIRMWARE_VENDOR) == 0) { - if (as_require_get_compare (req) == AS_REQUIRE_COMPARE_GE) { + /* get the version of the other device */ + version = fu_device_get_version (device2); + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Not compatible with vendor %s, requires >= %s", - version, as_require_get_version (req)); + "Not compatible with %s version %s, requires >= %s", + fu_device_get_name (device2), + version, + xb_node_get_attr (req, "version")); } else { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "Not compatible with vendor: %s", + "Not compatible with %s: %s", + fu_device_get_name (device2), error_local->message); } return FALSE; } + return TRUE; - /* anything else */ - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Not compatible with %s: %s", - id, error_local->message); - return FALSE; } - /* success */ - g_debug ("requirement %s %s %s on %s passed", - as_require_get_version (req), - as_require_compare_to_string (as_require_get_compare (req)), - version, id); - return TRUE; + /* not supported */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot handle firmware requirement '%s'", + xb_node_get_text (req)); + return FALSE; } -#if AS_CHECK_VERSION(0,7,4) static gboolean -fu_engine_check_hardware_requirement (FuEngine *self, AsApp *app, GError **error) +fu_engine_check_requirement_id (FuEngine *self, XbNode *req, GError **error) { - GPtrArray *requires = as_app_get_requires (app); - - /* check each HWID requirement */ - for (guint i = 0; i < requires->len; i++) { - AsRequire *req = g_ptr_array_index (requires, i); - if (as_require_get_kind (req) != AS_REQUIRE_KIND_HARDWARE) - continue; - if (!fu_hwids_has_guid (self->hwids, as_require_get_value (req))) { + g_autoptr(GError) error_local = NULL; + const gchar *version = g_hash_table_lookup (self->runtime_versions, + xb_node_get_text (req)); + if (version == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no version available for %s", + xb_node_get_text (req)); + return FALSE; + } + if (!fu_engine_require_vercmp (req, version, &error_local)) { + if (g_strcmp0 (xb_node_get_attr (req, "compare"), "ge") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, - "no HWIDs matched %s", - as_require_get_value (req)); - return FALSE; + "Not compatible with %s version %s, requires >= %s", + xb_node_get_text (req), version, + xb_node_get_attr (req, "version")); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Not compatible with %s version: %s", + xb_node_get_text (req), error_local->message); } - g_debug ("HWID provided %s", as_require_get_value (req)); + return FALSE; } - /* success */ + g_debug ("requirement %s %s %s on %s passed", + xb_node_get_attr (req, "version"), + xb_node_get_attr (req, "compare"), + version, xb_node_get_text (req)); return TRUE; } -#endif static gboolean -fu_engine_check_requirements (FuEngine *self, AsApp *app, FuDevice *device, GError **error) +fu_engine_check_requirement_hardware (FuEngine *self, XbNode *req, GError **error) { - /* make sure requirements are satisfied */ - if (!fu_engine_check_version_requirement (app, - AS_REQUIRE_KIND_ID, - FU_ENGINE_REQUIREMENT_ID_FWUPD, - VERSION, - error)) { - return FALSE; - } -#if AS_CHECK_VERSION(0,7,4) - if (!fu_engine_check_hardware_requirement (self, app, error)) - return FALSE; -#endif + g_auto(GStrv) hwid_split = NULL; - if (device != NULL) { - if (!fu_engine_check_version_requirement (app, - AS_REQUIRE_KIND_FIRMWARE, - FU_ENGINE_REQUIREMENT_FIRMWARE_RUNTIME, - fu_device_get_version (device), - error)) { - return FALSE; - } - if (!fu_engine_check_version_requirement (app, - AS_REQUIRE_KIND_FIRMWARE, - FU_ENGINE_REQUIREMENT_FIRMWARE_BOOTLOADER, - fu_device_get_version_bootloader (device), - error)) { - return FALSE; - } - if (!fu_engine_check_version_requirement (app, - AS_REQUIRE_KIND_FIRMWARE, - FU_ENGINE_REQUIREMENT_FIRMWARE_VENDOR, - fu_device_get_vendor_id (device), - error)) { - return FALSE; + /* split and treat as OR */ + hwid_split = g_strsplit (xb_node_get_text (req), "|", -1); + for (guint i = 0; hwid_split[i] != NULL; i++) { + if (fu_hwids_has_guid (self->hwids, hwid_split[i])) { + g_debug ("HWID provided %s", hwid_split[i]); + return TRUE; } } - /* success */ - return TRUE; + /* nothing matched */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no HWIDs matched %s", + xb_node_get_text (req)); + return FALSE; } -static void -fu_engine_vendor_fixup_provide_value (AsApp *app) +static gboolean +fu_engine_check_requirement (FuEngine *self, XbNode *req, FuDevice *device, GError **error) { - GPtrArray *provides; - - /* no quirk required */ - if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) - return; + /* ensure component requirement */ + if (g_strcmp0 (xb_node_get_element (req), "id") == 0) + return fu_engine_check_requirement_id (self, req, error); - /* fix each provide to be a GUID */ - provides = as_app_get_provides (app); - for (guint i = 0; i < provides->len; i++) { - AsProvide *prov = g_ptr_array_index (provides, i); - const gchar *value = as_provide_get_value (prov); - g_autofree gchar *guid = NULL; - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - if (as_utils_guid_is_valid (value)) - continue; - guid = as_utils_guid_from_string (value); - as_provide_set_value (prov, guid); + /* ensure firmware requirement */ + if (g_strcmp0 (xb_node_get_element (req), "firmware") == 0) { + if (device == NULL) + return TRUE; + return fu_engine_check_requirement_firmware (self, req, device, error); } -} - -static void -fu_engine_vendor_quirk_release_version (FuEngine *self, AsApp *app) -{ - AsVersionParseFlag flags = AS_VERSION_PARSE_FLAG_USE_TRIPLET; - GPtrArray *releases; - const gchar *quirk; - /* no quirk required */ - if (as_app_get_kind (app) != AS_APP_KIND_FIRMWARE) - return; - - /* any quirks match */ - quirk = fu_quirks_lookup_by_glob (self->quirks, - FU_QUIRKS_DAEMON_VERSION_FORMAT, - as_app_get_id (app)); - if (g_strcmp0 (quirk, "none") == 0) - flags = AS_VERSION_PARSE_FLAG_NONE; - - /* fix each release */ - releases = as_app_get_releases (app); - for (guint i = 0; i < releases->len; i++) { - AsRelease *rel; - const gchar *version; - guint64 ver_uint32; - g_autofree gchar *version_new = NULL; + /* ensure hardware requirement */ + if (g_strcmp0 (xb_node_get_element (req), "hardware") == 0) + return fu_engine_check_requirement_hardware (self, req, error); - rel = g_ptr_array_index (releases, i); - version = as_release_get_version (rel); - if (version == NULL) - continue; - if (g_strstr_len (version, -1, ".") != NULL) - continue; + /* not supported */ + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot handle requirement type %s", + xb_node_get_element (req)); + return FALSE; +} - /* metainfo files use hex and the LVFS uses decimal */ - if (g_str_has_prefix (version, "0x")) { - ver_uint32 = g_ascii_strtoull (version + 2, NULL, 16); - } else { - ver_uint32 = g_ascii_strtoull (version, NULL, 10); - } - if (ver_uint32 == 0) - continue; +gboolean +fu_engine_check_requirements (FuEngine *self, FuInstallTask *task, + FwupdInstallFlags flags, GError **error) +{ + FuDevice *device = fu_install_task_get_device (task); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) reqs = NULL; - /* convert to dotted decimal */ - version_new = as_utils_version_from_uint32 ((guint32) ver_uint32, flags); - as_release_set_version (rel, version_new); + /* all install task checks require a device */ + if (device != NULL) { + if (!fu_install_task_check_requirements (task, flags, error)) + return FALSE; } -} -static gchar * -fu_engine_get_guids_from_store (AsStore *store) -{ - AsProvide *prov; - GPtrArray *provides; - GPtrArray *apps; - GString *str = g_string_new (""); - - /* return a string with all the firmware apps in the store */ - apps = as_store_get_apps (store); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = AS_APP (g_ptr_array_index (apps, i)); - provides = as_app_get_provides (app); - for (guint j = 0; j < provides->len; j++) { - prov = AS_PROVIDE (g_ptr_array_index (provides, j)); - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; - g_string_append_printf (str, "%s,", as_provide_get_value (prov)); - } + /* do engine checks */ + reqs = xb_node_query (fu_install_task_get_component (task), + "requires/*", 0, &error_local); + if (reqs == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return TRUE; + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; } - if (str->len == 0) { - g_string_free (str, TRUE); - return NULL; + for (guint i = 0; i < reqs->len; i++) { + XbNode *req = g_ptr_array_index (reqs, i); + if (!fu_engine_check_requirement (self, req, device, error)) + return FALSE; } - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); + return TRUE; } -static FuDevice * -fu_engine_get_item_by_wildcard (FuEngine *self, AsStore *store, GError **error) +void +fu_engine_idle_reset (FuEngine *self) { - g_autofree gchar *guids = NULL; - g_autoptr(GPtrArray) devices = NULL; - - devices = fu_device_list_get_all (self->device_list); - for (guint i = 0; i < devices->len; i++) { - FuDevice *device_tmp = g_ptr_array_index (devices, i); - if (fu_engine_store_get_app_by_guids (store, device_tmp) != NULL) - return device_tmp; - } - guids = fu_engine_get_guids_from_store (store); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Firmware is not for any attached hardware: got %s", - guids); - return NULL; + fu_idle_reset (self->idle); } static gchar * @@ -1239,27 +1276,29 @@ { GHashTable *hash; gchar *btime; - struct utsname name_tmp = { 0 }; + struct utsname name_tmp; + g_autoptr(GList) compile_keys = g_hash_table_get_keys (self->compile_versions); + g_autoptr(GList) runtime_keys = g_hash_table_get_keys (self->runtime_versions); - /* used by pretty much every plugin and are hard deps of fwupd */ + /* convert all the runtime and compile-time versions */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert (hash, - g_strdup ("FwupdVersion"), - g_strdup (VERSION)); - g_hash_table_insert (hash, - g_strdup ("AppstreamGlibVersion"), - g_strdup_printf ("%i.%i.%i", - AS_MAJOR_VERSION, - AS_MINOR_VERSION, - AS_MICRO_VERSION)); - g_hash_table_insert (hash, - g_strdup ("GUsbVersion"), - g_strdup_printf ("%i.%i.%i", - G_USB_MAJOR_VERSION, - G_USB_MINOR_VERSION, - G_USB_MICRO_VERSION)); + for (GList *l = compile_keys; l != NULL; l = l->next) { + const gchar *id = l->data; + const gchar *version = g_hash_table_lookup (self->compile_versions, id); + g_hash_table_insert (hash, + g_strdup_printf ("CompileVersion(%s)", id), + g_strdup (version)); + } + for (GList *l = runtime_keys; l != NULL; l = l->next) { + const gchar *id = l->data; + const gchar *version = g_hash_table_lookup (self->runtime_versions, id); + g_hash_table_insert (hash, + g_strdup_printf ("RuntimeVersion(%s)", id), + g_strdup (version)); + } /* kernel version is often important for debugging failures */ + memset (&name_tmp, 0, sizeof (struct utsname)); if (uname (&name_tmp) >= 0) { g_hash_table_insert (hash, g_strdup ("CpuArchitecture"), @@ -1278,174 +1317,284 @@ } /** - * fu_engine_install: + * fu_engine_composite_prepare: * @self: A #FuEngine - * @device_id: A device ID - * @store: The #AsStore with the firmware metadata - * @blob_cab: The #GBytes of the .cab file - * @flags: The #FwupdInstallFlags, e.g. %FWUPD_DEVICE_FLAG_UPDATABLE + * @devices: (element-type #FuDevice): devices that will be updated * @error: A #GError, or %NULL * - * Installs a specfic firmware file on a device. + * Calls into the plugin loader, informing each plugin of the pending upgrade(s). + * + * Any failure in any plugin will abort all of the actions before they are started. * * Returns: %TRUE for success **/ gboolean -fu_engine_install (FuEngine *self, - const gchar *device_id, - AsStore *store, - GBytes *blob_cab, - FwupdInstallFlags flags, - GError **error) +fu_engine_composite_prepare (FuEngine *self, GPtrArray *devices, GError **error) { - AsApp *app; - AsChecksum *csum_tmp; - AsRelease *rel; - FuDevice *device; - FuPlugin *plugin; - GBytes *blob_fw; - GPtrArray *plugins; - const gchar *tmp; - const gchar *version; - gboolean is_downgrade; - gint vercmp; - g_autofree gchar *checksum = NULL; - g_autofree gchar *device_id_orig = NULL; - g_autofree gchar *version_orig = NULL; - g_autoptr(FwupdRelease) release_history = fwupd_release_new (); - g_autoptr(GBytes) blob_fw2 = NULL; - g_autoptr(GError) error_local = NULL; - g_autoptr(GHashTable) metadata_hash = NULL; - - g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); - g_return_val_if_fail (device_id != NULL, FALSE); - g_return_val_if_fail (AS_IS_STORE (store), FALSE); - g_return_val_if_fail (blob_cab != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - /* wildcard */ - if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0) { - device = fu_engine_get_item_by_wildcard (self, store, error); - if (device == NULL) - return FALSE; - } else { - /* find the specific device */ - device = fu_device_list_get_by_id (self->device_list, device_id, error); - if (device == NULL) + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + if (!fu_plugin_runner_composite_prepare (plugin_tmp, devices, error)) return FALSE; } + return TRUE; +} - /* check the device is not locked */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Device %s is locked", - device_id); - return FALSE; +/** + * fu_engine_composite_cleanup: + * @self: A #FuEngine + * @devices: (element-type #FuDevice): devices that will be updated + * @error: A #GError, or %NULL + * + * Calls into the plugin loader, informing each plugin of the pending upgrade(s). + * + * Returns: %TRUE for success + **/ +gboolean +fu_engine_composite_cleanup (FuEngine *self, GPtrArray *devices, GError **error) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + if (!fu_plugin_runner_composite_cleanup (plugin_tmp, devices, error)) + return FALSE; } + return TRUE; +} - /* no update abilities */ - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Device %s does not currently allow updates", - fu_device_get_id (device)); +/** + * fu_engine_install_tasks: + * @self: A #FuEngine + * @install_tasks: (element-type FuInstallTask): A #FuDevice + * @blob_cab: The #GBytes of the .cab file + * @flags: The #FwupdInstallFlags, e.g. %FWUPD_DEVICE_FLAG_UPDATABLE + * @error: A #GError, or %NULL + * + * Installs a specific firmware file on one or more install tasks. + * + * By this point all the requirements and tests should have been done in + * fu_engine_check_requirements() so this should not fail before running + * the plugin loader. + * + * Returns: %TRUE for success + **/ +gboolean +fu_engine_install_tasks (FuEngine *self, + GPtrArray *install_tasks, + GBytes *blob_cab, + FwupdInstallFlags flags, + GError **error) +{ + g_autoptr(FuIdleLocker) locker = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) devices_new = NULL; + + /* do not allow auto-shutdown during this time */ + locker = fu_idle_locker_new (self->idle, "performing update"); + g_assert (locker != NULL); + + /* notify the plugins about the composite action */ + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < install_tasks->len; i++) { + FuInstallTask *task = g_ptr_array_index (install_tasks, i); + g_ptr_array_add (devices, g_object_ref (fu_install_task_get_device (task))); + } + if (!fu_engine_composite_prepare (self, devices, error)) { + g_prefix_error (error, "failed to prepare composite action: "); return FALSE; } - /* called with online update, test if device is supposed to allow this */ - if ((flags & FWUPD_INSTALL_FLAG_OFFLINE) == 0 && - fu_device_has_flag (device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) { - g_set_error(error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "Device %s only allows offline updates", - device_id); - return FALSE; + /* all authenticated, so install all the things */ + for (guint i = 0; i < install_tasks->len; i++) { + FuInstallTask *task = g_ptr_array_index (install_tasks, i); + if (!fu_engine_install (self, task, blob_cab, flags, error)) { + g_autoptr(GError) error_local = NULL; + if (!fu_engine_composite_cleanup (self, devices, &error_local)) { + g_warning ("failed to cleanup failed composite action: %s", + error_local->message); + } + return FALSE; + } } - /* find from guid */ - app = fu_engine_store_get_app_by_guids (store, device); - if (app == NULL) { - g_autofree gchar *guid = NULL; - guid = fu_engine_get_guids_from_store (store); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Firmware is not for this hw: required %s got %s", - fu_device_get_guid_default (device), guid); - return FALSE; + /* set all the device statuses back to unknown */ + for (guint i = 0; i < install_tasks->len; i++) { + FuInstallTask *task = g_ptr_array_index (install_tasks, i); + FuDevice *device = fu_install_task_get_device (task); + fu_device_set_status (device, FWUPD_STATUS_UNKNOWN); } - /* not in bootloader mode */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { - const gchar *caption = NULL; - AsScreenshot *ss = _as_app_get_screenshot_default (app); - if (ss != NULL) - caption = as_screenshot_get_caption (ss, NULL); - if (caption != NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Device %s needs to manually be put in update mode: %s", - fu_device_get_name (device), caption); - } else { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Device %s needs to manually be put in update mode", - fu_device_get_name (device)); + /* get a new list of devices in case they replugged */ + devices_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device; + g_autoptr(FuDevice) device_new = NULL; + g_autoptr(GError) error_local = NULL; + device = g_ptr_array_index (devices, i); + device_new = fu_device_list_get_by_id (self->device_list, + fu_device_get_id (device), + &error_local); + if (device_new == NULL) { + g_debug ("failed to find new device: %s", + error_local->message); + continue; } + g_ptr_array_add (devices_new, g_steal_pointer (&device_new)); + } + + /* notify the plugins about the composite action */ + if (!fu_engine_composite_cleanup (self, devices_new, error)) { + g_prefix_error (error, "failed to cleanup composite action: "); return FALSE; } - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); + /* success */ + return TRUE; +} - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); +static FwupdRelease * +fu_engine_create_release_metadata (FuEngine *self, FuPlugin *plugin, GError **error) +{ + const gchar *tmp; + g_autoptr(FwupdRelease) release = fwupd_release_new (); + g_autoptr(GHashTable) metadata_hash = NULL; + g_autoptr(GHashTable) os_release = NULL; - /* check we can install it */ - if (!fu_engine_check_requirements (self, app, device, error)) + /* add release data from os-release */ + os_release = fwupd_get_os_release (error); + if (os_release == NULL) + return NULL; + + /* build the version metadata */ + metadata_hash = fu_engine_get_report_metadata (self); + fwupd_release_add_metadata (release, metadata_hash); + fwupd_release_add_metadata (release, fu_plugin_get_report_metadata (plugin)); + + /* add details from os-release as metadata */ + tmp = g_hash_table_lookup (os_release, "ID"); + if (tmp != NULL) + fwupd_release_add_metadata_item (release, "DistroId", tmp); + tmp = g_hash_table_lookup (os_release, "VERSION_ID"); + if (tmp != NULL) + fwupd_release_add_metadata_item (release, "DistroVersion", tmp); + tmp = g_hash_table_lookup (os_release, "VARIANT_ID"); + if (tmp != NULL) + fwupd_release_add_metadata_item (release, "DistroVariant", tmp); + return g_steal_pointer (&release); +} + +static gboolean +fu_engine_is_running_offline (FuEngine *self) +{ +#ifdef HAVE_SYSTEMD + g_autofree gchar *default_target = NULL; + g_autoptr(GError) error = NULL; + default_target = fu_systemd_get_default_target (&error); + if (default_target == NULL) { + g_warning ("failed to get default.target: %s", error->message); return FALSE; + } + return g_strcmp0 (default_target, "system-update.target") == 0; +#else + return FALSE; +#endif +} - /* parse the DriverVer */ - rel = as_app_get_release_default (app); - if (rel == NULL) { - g_set_error_literal (error, +/** + * fu_engine_install: + * @self: A #FuEngine + * @task: A #FuInstallTask + * @blob_cab: The #GBytes of the .cab file + * @flags: The #FwupdInstallFlags, e.g. %FWUPD_DEVICE_FLAG_UPDATABLE + * @error: A #GError, or %NULL + * + * Installs a specific firmware file on a device. + * + * By this point all the requirements and tests should have been done in + * fu_engine_check_requirements() so this should not fail before running + * the plugin loader. + * + * Returns: %TRUE for success + **/ +gboolean +fu_engine_install (FuEngine *self, + FuInstallTask *task, + GBytes *blob_cab, + FwupdInstallFlags flags, + GError **error) +{ + XbNode *component = fu_install_task_get_component (task); + FuPlugin *plugin; + GBytes *blob_fw; + const gchar *tmp = NULL; + g_autofree gchar *release_key = NULL; + g_autofree gchar *version_orig = NULL; + g_autofree gchar *version_rel = NULL; + g_autoptr(FuDevice) device = NULL; + g_autoptr(FuDevice) device_tmp = NULL; + g_autoptr(GBytes) blob_fw2 = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(XbNode) rel = NULL; + + g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); + g_return_val_if_fail (XB_IS_NODE (component), FALSE); + g_return_val_if_fail (blob_cab != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* not in bootloader mode */ + device = g_object_ref (fu_install_task_get_device (task)); + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)) { + const gchar *caption = NULL; + caption = xb_node_query_text (component, + "screenshots/screenshot/caption", + NULL); + if (caption != NULL) { + g_set_error (error, FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No releases in the firmware component"); + FWUPD_ERROR_INTERNAL, + "Device %s needs to manually be put in update mode: %s", + fu_device_get_name (device), caption); + } else { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Device %s needs to manually be put in update mode", + fu_device_get_name (device)); + } return FALSE; } - /* get the blob */ - csum_tmp = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - tmp = as_checksum_get_filename (csum_tmp); - if (tmp == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "No checksum filename"); + /* parse the DriverVer */ + rel = xb_node_query_first (component, "releases/release", &error_local); + if (rel == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "No releases in the firmware component: %s", + error_local->message); return FALSE; } + /* get the blob */ + tmp = xb_node_query_attr (rel, "checksum[@target='content']", "filename", NULL); + if (tmp == NULL) + tmp = "firmware.bin"; + /* not all devices have to use the same blob */ - blob_fw = as_release_get_blob (rel, tmp); + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", tmp); + blob_fw = xb_node_get_data (rel, release_key); if (blob_fw == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "Failed to get firmware blob"); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "Failed to get firmware blob using %s", tmp); return FALSE; } /* use a bubblewrap helper script to build the firmware */ - tmp = as_app_get_metadata_item (app, "fwupd::BuilderScript"); + tmp = g_object_get_data (G_OBJECT (component), "fwupd::BuilderScript"); if (tmp != NULL) { - const gchar *tmp2 = as_app_get_metadata_item (app, "fwupd::BuilderOutput"); + const gchar *tmp2 = g_object_get_data (G_OBJECT (component), "fwupd::BuilderOutput"); if (tmp2 == NULL) tmp2 = "firmware.bin"; blob_fw2 = fu_common_firmware_builder (blob_fw, tmp, tmp2, error); @@ -1455,28 +1604,6 @@ blob_fw2 = g_bytes_ref (blob_fw); } - /* test the firmware is not an empty blob */ - if (g_bytes_get_size (blob_fw2) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Firmware is invalid as has zero size"); - return FALSE; - } - - version = as_release_get_version (rel); - - /* compare to the lowest supported version, if it exists */ - tmp = fu_device_get_version_lowest (device); - if (tmp != NULL && as_utils_vercmp (tmp, version) > 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_VERSION_NEWER, - "Specified firmware is older than the minimum " - "required version '%s < %s'", tmp, version); - return FALSE; - } - /* get the plugin */ plugin = fu_plugin_list_find_by_name (self->plugin_list, fu_device_get_plugin (device), @@ -1484,181 +1611,436 @@ if (plugin == NULL) return FALSE; - /* compare the versions of what we have installed */ + /* schedule this for the next reboot if not in system-update.target, + * but first check if allowed on battery power */ + version_rel = fu_engine_get_release_version (self, device, rel, error); + if (version_rel == NULL) { + g_prefix_error (error, "failed to get release version: "); + return FALSE; + } + if ((flags & FWUPD_INSTALL_FLAG_OFFLINE) > 0 && + !fu_engine_is_running_offline (self)) { + g_autoptr(FwupdRelease) release_tmp = NULL; + plugin = fu_plugin_list_find_by_name (self->plugin_list, "upower", NULL); + if (plugin != NULL) { + if (!fu_plugin_runner_update_prepare (plugin, flags, device, error)) + return FALSE; + } + release_tmp = fu_engine_create_release_metadata (self, plugin, error); + if (release_tmp == NULL) + return FALSE; + fwupd_release_set_version (release_tmp, version_rel); + return fu_plugin_runner_schedule_update (plugin, device, release_tmp, + blob_cab, flags, error); + } + + /* add device to database */ + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0) { + g_autoptr(FwupdRelease) release_tmp = NULL; + release_tmp = fu_engine_create_release_metadata (self, plugin, error); + if (release_tmp == NULL) + return FALSE; + tmp = xb_node_query_text (component, + "releases/release/checksum[@target='container']", + NULL); + if (tmp != NULL) + fwupd_release_add_checksum (release_tmp, tmp); + fwupd_release_set_version (release_tmp, version_rel); + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + if (!fu_history_add_device (self->history, device, release_tmp, error)) + return FALSE; + } + + /* install firmware blob */ version_orig = g_strdup (fu_device_get_version (device)); - if (version_orig == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Device %s does not yet have a current version", - device_id); + if (!fu_engine_install_blob (self, device, blob_fw2, flags, &error_local)) { + fu_device_set_status (device, FWUPD_STATUS_IDLE); + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_AC_POWER_REQUIRED) || + g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW) || + g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_BROKEN_SYSTEM)) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED_TRANSIENT); + } else { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + } + fu_device_set_update_error (device, error_local->message); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_OLD_VERSION | + FU_HISTORY_FLAGS_MATCH_NEW_VERSION, + error)) { + return FALSE; + } + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } - vercmp = as_utils_vercmp (version_orig, version); - if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_VERSION_SAME, - "Specified firmware is already installed '%s'", - version_orig); + + /* the device may have changed */ + device_tmp = fu_device_list_get_by_id (self->device_list, + fu_device_get_id (device), + error); + if (device_tmp == NULL) { + g_prefix_error (error, "failed to get device after install: "); return FALSE; } - is_downgrade = vercmp > 0; - if (is_downgrade && (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_VERSION_NEWER, - "Specified firmware is older than installed '%s < %s'", - version_orig, version); + g_set_object (&device, device_tmp); + + /* update database */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) || + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) { + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_NEEDS_REBOOT); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_OLD_VERSION | + FU_HISTORY_FLAGS_MATCH_NEW_VERSION, + error)) + return FALSE; + /* success */ + return TRUE; + } + + /* for online updates, verify the version changed if not a re-install */ + if (version_rel != NULL && + g_strcmp0 (version_orig, version_rel) != 0 && + g_strcmp0 (version_orig, fu_device_get_version (device)) == 0) { + g_autofree gchar *str = NULL; + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); + str = g_strdup_printf ("device version not updated on success, %s != %s", + version_rel, fu_device_get_version (device)); + fu_device_set_update_error (device, str); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_OLD_VERSION, + error)) + return FALSE; + /* success */ + return TRUE; + } + + /* ensure the new version matched what we expected */ + if (version_rel != NULL && + g_strcmp0 (fu_device_get_version (device), version_rel) != 0) { + g_warning ("new device version '%s' was is not '%s', fixing up", + fu_device_get_version (device), version_rel); + fu_device_set_version (device, version_rel, + fu_device_get_version_format (device)); + } + + /* success */ + fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); + if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && + !fu_history_modify_device (self->history, device, + FU_HISTORY_FLAGS_MATCH_NEW_VERSION, + error)) return FALSE; + return TRUE; +} + +/** + * fu_engine_get_plugins: + * @self: A #FuPluginList + * + * Gets all the plugins that have been added. + * + * Returns: (transfer none) (element-type FuPlugin): the plugins + * + * Since: 1.0.8 + **/ +GPtrArray * +fu_engine_get_plugins (FuEngine *self) +{ + g_return_val_if_fail (FU_IS_ENGINE (self), NULL); + return fu_plugin_list_get_all (self->plugin_list); +} + +static FuDevice * +fu_engine_get_device_by_id (FuEngine *self, const gchar *device_id, GError **error) +{ + g_autoptr(FuDevice) device1 = NULL; + g_autoptr(FuDevice) device2 = NULL; + + /* find device */ + device1 = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device1 == NULL) + return NULL; + + /* no replug required */ + if (!fu_device_has_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG)) + return g_steal_pointer (&device1); + + /* wait for device to disconnect and reconnect */ + if (!fu_device_list_wait_for_replug (self->device_list, device1, error)) { + g_prefix_error (error, "failed to wait for detach replug: "); + return NULL; } - /* signal to all the plugins the update is about to happen */ - plugins = fu_plugin_list_get_all (self->plugin_list); + /* get the new device */ + device2 = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device2 == NULL) { + g_prefix_error (error, "failed to get device after replug: "); + return NULL; + } + + /* success */ + return g_steal_pointer (&device2); +} + +static gboolean +fu_engine_update_prepare (FuEngine *self, + FwupdInstallFlags flags, + const gchar *device_id, + GError **error) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + g_autoptr(FuDevice) device = NULL; + + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) + return FALSE; for (guint j = 0; j < plugins->len; j++) { FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - if (!fu_plugin_runner_update_prepare (plugin_tmp, device, error)) + if (!fu_plugin_runner_update_prepare (plugin_tmp, flags, device, error)) return FALSE; } + return TRUE; +} - /* save the chosen device ID in case the device goes away */ - device_id_orig = g_strdup (fu_device_get_id (device)); +static gboolean +fu_engine_update_cleanup (FuEngine *self, + FwupdInstallFlags flags, + const gchar *device_id, + GError **error) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + g_autoptr(FuDevice) device = NULL; - /* mark this as modified even if we actually fail to do the update */ - fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) + return FALSE; + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + if (!fu_plugin_runner_update_cleanup (plugin_tmp, flags, device, error)) + return FALSE; + } + return TRUE; +} - /* build the version metadata */ - metadata_hash = fu_engine_get_report_metadata (self); - fwupd_release_add_metadata (release_history, metadata_hash); - fwupd_release_add_metadata (release_history, - fu_plugin_get_report_metadata (plugin)); +static gboolean +fu_engine_update_detach (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; - /* add device to database */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob_cab); - fwupd_release_set_version (release_history, version); - fwupd_release_add_checksum (release_history, checksum); - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); - if (!fu_history_add_device (self->history, device, release_history, error)) + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) return FALSE; + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update_detach (plugin, device, error)) + return FALSE; + return TRUE; +} - /* do the update */ - if (!fu_plugin_runner_update_detach (plugin, device, &error_local)) { - fu_device_set_update_error (device, error_local->message); - if (!fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error)) { - return FALSE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); +static gboolean +fu_engine_update_attach (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; + + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) { + g_prefix_error (error, "failed to get device after update: "); return FALSE; } - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update_attach (plugin, device, error)) + return FALSE; + return TRUE; +} + +gboolean +fu_engine_activate (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; + + g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); + g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* check the device exists */ + device = fu_device_list_get_by_id (self->device_list, device_id, error); if (device == NULL) return FALSE; - if (!fu_plugin_runner_update (plugin, - device, - blob_cab, - blob_fw2, - flags, - &error_local)) { - g_autoptr(GError) error_attach = NULL; - /* save to database */ - fu_device_set_update_error (device, error_local->message); - if (!fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error)) { - return FALSE; - } - g_propagate_error (error, g_steal_pointer (&error_local)); + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + g_debug ("Activating %s", fu_device_get_name (device)); + + if (!fu_plugin_runner_activate (plugin, device, error)) + return FALSE; + + fu_engine_emit_device_changed (self, device); + fu_engine_emit_changed (self); + + return TRUE; +} + +static gboolean +fu_engine_update_reload (FuEngine *self, const gchar *device_id, GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; - /* attack back into runtime */ + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) { + g_prefix_error (error, "failed to get device after update: "); + return FALSE; + } + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update_reload (plugin, device, error)) { + g_prefix_error (error, "failed to reload device: "); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_engine_update (FuEngine *self, + const gchar *device_id, + GBytes *blob_fw2, + FwupdInstallFlags flags, + GError **error) +{ + FuPlugin *plugin; + g_autoptr(FuDevice) device = NULL; + + /* the device and plugin both may have changed */ + device = fu_engine_get_device_by_id (self, device_id, error); + if (device == NULL) { + g_prefix_error (error, "failed to get device after detach: "); + return FALSE; + } + plugin = fu_plugin_list_find_by_name (self->plugin_list, + fu_device_get_plugin (device), + error); + if (plugin == NULL) + return FALSE; + if (!fu_plugin_runner_update (plugin, device, blob_fw2, flags, error)) { + g_autoptr(GError) error_attach = NULL; + g_autoptr(GError) error_cleanup = NULL; + + /* attack back into runtime then cleanup */ if (!fu_plugin_runner_update_attach (plugin, device, &error_attach)) { g_warning ("failed to attach device after failed update: %s", error_attach->message); } - for (guint j = 0; j < plugins->len; j++) { - FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - g_autoptr(GError) error_cleanup = NULL; - if (!fu_plugin_runner_update_cleanup (plugin_tmp, - device, - &error_cleanup)) { - g_warning ("failed to update-cleanup " - "after failed update: %s", - error_cleanup->message); - } + if (!fu_engine_update_cleanup (self, flags, device_id, &error_cleanup)) { + g_warning ("failed to update-cleanup after failed update: %s", + error_cleanup->message); } - fu_device_set_status (device, FWUPD_STATUS_IDLE); return FALSE; } - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) + return TRUE; +} + +gboolean +fu_engine_install_blob (FuEngine *self, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error) +{ + guint retries = 0; + g_autofree gchar *device_id = NULL; + g_autoptr(GTimer) timer = g_timer_new (); + + /* test the firmware is not an empty blob */ + if (g_bytes_get_size (blob_fw) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Firmware is invalid as has zero size"); return FALSE; - if (!fu_plugin_runner_update_attach (plugin, device, &error_local)) { - fu_device_set_update_error (device, error_local->message); - if (!fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION | - FU_HISTORY_FLAGS_MATCH_NEW_VERSION, - error)) { + } + + /* mark this as modified even if we actually fail to do the update */ + fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); + + /* plugins can set FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED to run again, but they + * must return TRUE rather than an error */ + device_id = g_strdup (fu_device_get_id (device)); + do { + /* check for a loop */ + if (++retries > 5) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "aborting device write loop, limit 5"); return FALSE; } - g_propagate_error (error, g_steal_pointer (&error_local)); - return FALSE; - } + + /* don't rely on a plugin clearing this */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED); + + /* signal to all the plugins the update is about to happen */ + if (!fu_engine_update_prepare (self, flags, device_id, error)) + return FALSE; + + /* detach to bootloader mode */ + if (!fu_engine_update_detach (self, device_id, error)) + return FALSE; + + /* install */ + if (!fu_engine_update (self, device_id, blob_fw, flags, error)) + return FALSE; + + /* attach into runtime mode */ + if (!fu_engine_update_attach (self, device_id, error)) + return FALSE; + + } while (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED)); /* get the new version number */ - device = fu_device_list_get_by_id (self->device_list, device_id_orig, error); - if (device == NULL) - return FALSE; - if (!fu_plugin_runner_update_reload (plugin, device, error)) + if (!fu_engine_update_reload (self, device_id, error)) return FALSE; /* signal to all the plugins the update has happened */ - for (guint j = 0; j < plugins->len; j++) { - FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); - g_autoptr(GError) error_cleanup = NULL; - if (!fu_plugin_runner_update_cleanup (plugin_tmp, device, &error_cleanup)) { - g_warning ("failed to update-cleanup: %s", - error_cleanup->message); - } - } + if (!fu_engine_update_cleanup (self, flags, device_id, error)) + return FALSE; /* make the UI update */ - fu_device_set_status (device, FWUPD_STATUS_IDLE); - fu_engine_emit_device_changed (self, device); + fu_engine_set_status (self, FWUPD_STATUS_IDLE); fu_engine_emit_changed (self); - - /* update database */ - if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) { - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_NEEDS_REBOOT); - return fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error); - } - - /* for online updates, verify the version changed if not a re-install */ - if (g_strcmp0 (version_orig, version) != 0 && - g_strcmp0 (version_orig, fu_device_get_version (device)) == 0) { - fu_device_set_update_error (device, "device version not updated on success"); - return fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_OLD_VERSION, - error); - } - - /* ensure the new version matched what we expected */ - if (g_strcmp0 (fu_device_get_version (device), version) != 0) { - g_warning ("new device version '%s' was is not '%s', fixing up", - fu_device_get_version (device), version); - fu_device_set_version (device, version); - } - - /* success */ - fu_device_set_update_state (device, FWUPD_UPDATE_STATE_SUCCESS); - return fu_history_modify_device (self->history, device, - FU_HISTORY_FLAGS_MATCH_NEW_VERSION, - error); + g_debug ("Updating %s took %f seconds", fu_device_get_name (device), + g_timer_elapsed (timer, NULL)); + return TRUE; } static FuDevice * @@ -1684,6 +2066,7 @@ /* only useful */ if (fu_device_get_update_state (dev) == FWUPD_UPDATE_STATE_SUCCESS || + fu_device_get_update_state (dev) == FWUPD_UPDATE_STATE_FAILED_TRANSIENT || fu_device_get_update_state (dev) == FWUPD_UPDATE_STATE_FAILED) { return g_steal_pointer (&dev); } @@ -1704,6 +2087,7 @@ for (guint i = 0; i < devices->len; i++) { FuDevice *dev = g_ptr_array_index (devices, i); if (fu_device_get_update_state (dev) == FWUPD_UPDATE_STATE_SUCCESS || + fu_device_get_update_state (dev) == FWUPD_UPDATE_STATE_FAILED_TRANSIENT || fu_device_get_update_state (dev) == FWUPD_UPDATE_STATE_FAILED) return g_object_ref (dev); } @@ -1714,272 +2098,160 @@ return NULL; } -/** - * fu_engine_get_action_id_for_device: - * @self: A #FuEngine - * @device_id: A device ID - * @store: The #AsStore with the firmware metadata - * @flags: The #FwupdInstallFlags, e.g. %FWUPD_DEVICE_FLAG_UPDATABLE - * @error: A #GError, or %NULL - * - * Gets the PolicyKit action ID to use for the install operation. - * - * Returns: string, e.g. `org.freedesktop.fwupd.update-internal-trusted` - **/ -const gchar * -fu_engine_get_action_id_for_device (FuEngine *self, - const gchar *device_id, - AsStore *store, - FwupdInstallFlags flags, - GError **error) +/* for the self tests */ +void +fu_engine_set_silo (FuEngine *self, XbSilo *silo) { - AsApp *app; - AsRelease *release; - FuDevice *device; - FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE; - const gchar *version; - const gchar *version_release; - gboolean is_downgrade; - gboolean is_trusted; - gint vercmp; + g_return_if_fail (FU_IS_ENGINE (self)); + g_return_if_fail (XB_IS_SILO (silo)); + g_set_object (&self->silo, silo); +} - g_return_val_if_fail (FU_IS_ENGINE (self), NULL); - g_return_val_if_fail (AS_IS_STORE (store), NULL); - g_return_val_if_fail (device_id != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); +static gboolean +fu_engine_is_device_supported (FuEngine *self, FuDevice *device) +{ + g_autoptr(XbNode) component = NULL; - /* wildcard */ - if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0) { - device = fu_engine_get_item_by_wildcard (self, store, error); - if (device == NULL) - return NULL; - } else { - /* find the specific device */ - device = fu_device_list_get_by_id (self->device_list, device_id, error); - if (device == NULL) - return NULL; + /* sanity check */ + if (self->silo == NULL) { + g_critical ("FuEngine silo not set up"); + return FALSE; } - /* get device */ - version = fu_device_get_version (device); - if (version == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Device with ID %s has no firmware version", - device_id); - return NULL; - } + /* no device version */ + if (fu_device_get_version (device) == NULL) + return FALSE; /* match the GUIDs in the XML */ - app = fu_engine_store_get_app_by_guids (store, device); - if (app == NULL) { - g_autofree gchar *guid = NULL; - guid = fu_engine_get_guids_from_store (store); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "firmware is not for this hw: required %s got %s", - fu_device_get_guid_default (device), guid); - return NULL; - } - - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); - - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); - - /* get latest release */ - release = as_app_get_release_default (app); - if (release == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "%s [%s] has no firmware update metadata", - fu_device_get_id (device), - fu_device_get_name (device)); - return NULL; - } - - /* is this a downgrade or re-install */ - version_release = as_release_get_version (release); - if (version_release == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "Release has no firmware version"); - return NULL; - } - vercmp = as_utils_vercmp (version, version_release); - if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_VERSION_SAME, - "Specified firmware is already installed '%s'", - version_release); - return NULL; - } - is_downgrade = vercmp > 0; - if (is_downgrade && (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_VERSION_NEWER, - "Specified firmware is older than installed '%s < %s'", - version_release, version); - return NULL; - } - - /* verify */ - if (!fu_engine_get_release_trust_flags (release, &trust_flags, error)) - return NULL; - is_trusted = (trust_flags & FWUPD_TRUST_FLAG_PAYLOAD) > 0; - - /* relax authentication checks for removable devices */ - if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_INTERNAL)) { - if (is_downgrade) - return "org.freedesktop.fwupd.downgrade-hotplug"; - if (is_trusted) - return "org.freedesktop.fwupd.update-hotplug-trusted"; - return "org.freedesktop.fwupd.update-hotplug"; - } + component = fu_engine_get_component_by_guids (self, device); + if (component == NULL) + return FALSE; - /* internal device */ - if (is_downgrade) - return "org.freedesktop.fwupd.downgrade-internal"; - if (is_trusted) - return "org.freedesktop.fwupd.update-internal-trusted"; - return "org.freedesktop.fwupd.update-internal"; + /* success */ + return TRUE; } -static AsRelease * -_as_app_get_release_by_version (AsApp *app, const gchar *version) +static gboolean +fu_engine_appstream_upgrade_cb (XbBuilderFixup *self, + XbBuilderNode *bn, + gpointer user_data, + GError **error) { -#if AS_CHECK_VERSION(0,7,3) - return as_app_get_release_by_version (app, version); -#else - GPtrArray *releases = as_app_get_releases (app); - for (guint i = 0; i < releases->len; i++) { - AsRelease *release = g_ptr_array_index (releases, i); - if (g_strcmp0 (version, as_release_get_version (release)) == 0) - return release; - } - return NULL; -#endif + if (g_strcmp0 (xb_builder_node_get_element (bn), "metadata") == 0) + xb_builder_node_set_element (bn, "custom"); + return TRUE; } -static void -fu_engine_add_component_to_store (FuEngine *self, AsApp *app) +static XbBuilderSource * +fu_engine_create_metadata_builder_source (FuEngine *self, + const gchar *fn, + GError **error) { - AsApp *app_old = as_store_get_app_by_id (self->store, as_app_get_id (app)); - GPtrArray *releases = as_app_get_releases (app); - - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); - - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); + g_autoptr(GBytes) blob = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autofree gchar *xml = NULL; - /* the app does not already exist */ - if (app_old == NULL) { - as_store_add_app (self->store, app); - return; - } + g_debug ("building metadata for %s", fn); + blob = fu_common_get_contents_bytes (fn, error); + if (blob == NULL) + return NULL; - /* add releases that do not exist from a higher priority remote */ - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - AsRelease *release_old; - const gchar *version = as_release_get_version (release); - release_old = _as_app_get_release_by_version (app_old, version); - if (release_old != NULL) { - g_debug ("skipping release %s that already exists for %s", - version, as_app_get_id (app_old)); - continue; - } - g_debug ("adding release %s to existing %s", - version, as_app_get_id (app_old)); - as_app_add_release (app_old, release); - } + /* convert the silo for the CAB into a XbBuilderSource */ + silo = fu_engine_get_silo_from_blob (self, blob, error); + if (silo == NULL) + return NULL; + xml = xb_silo_export (silo, XB_NODE_EXPORT_FLAG_NONE, error); + if (xml == NULL) + return NULL; + if (!xb_builder_source_load_xml (source, xml, + XB_BUILDER_SOURCE_FLAG_NONE, + error)) + return NULL; + return g_steal_pointer (&source); } static gboolean -fu_engine_load_metadata_from_file (FuEngine *self, - const gchar *path, - const gchar *remote_id, - GError **error) +fu_engine_create_metadata (FuEngine *self, XbBuilder *builder, + FwupdRemote *remote, GError **error) { - GPtrArray *apps; - g_autoptr(AsStore) store = NULL; - g_autoptr(GFile) file = NULL; - g_autoptr(GBytes) remote_blob = NULL; - - /* load the store locally until we know it is valid */ - store = as_store_new (); - file = g_file_new_for_path (path); - if (!as_store_from_file (store, file, NULL, NULL, error)) - return FALSE; + g_autoptr(GPtrArray) files = NULL; + const gchar *path; - /* save the remote to the release */ - if (remote_id != NULL && remote_id[0] != '\0') - remote_blob = g_bytes_new (remote_id, strlen (remote_id) + 1); + /* find all files in directory */ + path = fwupd_remote_get_filename_cache (remote); + files = fu_common_get_files_recursive (path, error); + if (files == NULL) + return FALSE; + + /* add each source */ + for (guint i = 0; i < files->len; i++) { + g_autoptr(XbBuilderNode) custom = NULL; + g_autoptr(XbBuilderSource) source = NULL; + g_autoptr(GError) error_local = NULL; + const gchar *fn = g_ptr_array_index (files, i); - /* add the new application from the store */ - apps = as_store_get_apps (store); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); + /* check is cab file */ + if (!g_str_has_suffix (fn, ".cab")) { + g_debug ("ignoring: %s", fn); + continue; + } - /* save the remote-id to all the releases for this component */ - if (remote_blob != NULL) { - GPtrArray *releases = as_app_get_releases (app); - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - as_release_set_blob (release, - "fwupd::RemoteId", - remote_blob); - } + /* build source for file */ + source = fu_engine_create_metadata_builder_source (self, fn, &error_local); + if (source == NULL) { + g_warning ("%s", error_local->message); + continue; } - /* either add component, or merge in new releases */ - fu_engine_add_component_to_store (self, app); + /* add metadata */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "value", fn, + "key", "fwupd::FilenameCache", + NULL); + xb_builder_node_insert_text (custom, + "value", fwupd_remote_get_id (remote), + "key", "fwupd::RemoteId", + NULL); + xb_builder_source_set_info (source, custom); + xb_builder_import_source (builder, source); } return TRUE; } static gboolean -fu_engine_is_device_supported (FuEngine *self, FuDevice *device) +fu_engine_load_metadata_store (FuEngine *self, FuEngineLoadFlags flags, GError **error) { - AsApp *app; - - /* no device version */ - if (fu_device_get_version (device) == NULL) - return FALSE; - - /* match the GUIDs in the XML */ - app = fu_engine_store_get_app_by_guids (self->store, device); - if (app == NULL) - return FALSE; - - /* success */ - return TRUE; -} - -static gboolean -fu_engine_load_metadata_store (FuEngine *self, GError **error) -{ - GPtrArray *apps; GPtrArray *remotes; - g_autofree gchar *guids_str = NULL; + XbBuilderCompileFlags compile_flags = XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID; + g_autofree gchar *cachedirpkg = NULL; + g_autofree gchar *xmlbfn = NULL; + g_autoptr(GFile) xmlb = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + + /* clear existing silo */ + g_clear_object (&self->silo); - /* clear existing store */ - as_store_remove_all (self->store); + /* verbose profiling */ + if (g_getenv ("FWUPD_VERBOSE") != NULL) { + xb_builder_set_profile_flags (builder, + XB_SILO_PROFILE_FLAG_XPATH | + XB_SILO_PROFILE_FLAG_DEBUG); + } /* load each enabled metadata file */ remotes = fu_config_get_remotes (self->config); for (guint i = 0; i < remotes->len; i++) { const gchar *path = NULL; g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilderFixup) fixup = NULL; + g_autoptr(XbBuilderNode) custom = NULL; + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + FwupdRemote *remote = g_ptr_array_index (remotes, i); if (!fwupd_remote_get_enabled (remote)) { g_debug ("remote %s not enabled, so skipping", @@ -1991,55 +2263,81 @@ g_debug ("no %s, so skipping", path); continue; } - if (!fu_engine_load_metadata_from_file (self, path, - fwupd_remote_get_id (remote), - &error_local)) { + + /* generate all metadata on demand */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + g_debug ("building metadata for remote '%s'", + fwupd_remote_get_id (remote)); + if (!fu_engine_create_metadata (self, builder, remote, &error_local)) { + g_warning ("failed to generate remote %s: %s", + fwupd_remote_get_id (remote), + error_local->message); + } + continue; + } + + /* save the remote-id in the custom metadata space */ + file = g_file_new_for_path (path); + if (!xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, &error_local)) { g_warning ("failed to load remote %s: %s", fwupd_remote_get_id (remote), error_local->message); continue; } - } - /* print what we've got */ - apps = as_store_get_apps (self->store); - if (apps->len == 0) { - g_debug ("no devices in store"); - } else { - g_debug ("devices now in store:"); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); - GPtrArray *releases = as_app_get_releases (app); - g_autoptr(GString) releases_str = g_string_new (NULL); - - for (guint j = 0; j < releases->len; j++) { - AsRelease *release = g_ptr_array_index (releases, j); - g_string_append_printf (releases_str, "%s,", - as_release_get_version (release)); - if (j >= 2) { - g_string_append (releases_str, "…,"); - break; - } - } - if (releases_str->len > 1) - g_string_truncate (releases_str, releases_str->len - 1); - g_debug ("%u\t%s\t%s [%s]", i + 1, - as_app_get_id (app), - as_app_get_name (app, NULL), - releases_str->str); - } - } + /* fix up any legacy installed files */ + fixup = xb_builder_fixup_new ("AppStreamUpgrade", + fu_engine_appstream_upgrade_cb, + self, NULL); + xb_builder_fixup_set_max_depth (fixup, 3); + xb_builder_source_add_fixup (source, fixup); + + /* add metadata */ + custom = xb_builder_node_new ("custom"); + xb_builder_node_insert_text (custom, + "value", path, + "key", "fwupd::FilenameCache", + NULL); + xb_builder_node_insert_text (custom, + "value", fwupd_remote_get_id (remote), + "key", "fwupd::RemoteId", + NULL); + xb_builder_source_set_info (source, custom); + + /* we need to watch for changes? */ + xb_builder_import_source (builder, source); + } + +#if LIBXMLB_CHECK_VERSION(0,1,7) + /* on a read-only filesystem don't care about the cache GUID */ + if (flags & FU_ENGINE_LOAD_FLAG_READONLY_FS) + compile_flags |= XB_BUILDER_COMPILE_FLAG_IGNORE_GUID; +#endif - /* update the list of supported GUIDs */ - g_ptr_array_set_size (self->supported_guids, 0); - guids_str = fu_engine_get_guids_from_store (self->store); - if (guids_str != NULL) { - g_auto(GStrv) guids = g_strsplit (guids_str, ",", -1); - for (guint i = 0; guids[i] != NULL; i++) { - g_ptr_array_add (self->supported_guids, - g_steal_pointer (&guids[i])); - } - } + /* ensure silo is up to date */ + cachedirpkg = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + xmlbfn = g_build_filename (cachedirpkg, "metadata.xmlb", NULL); + xmlb = g_file_new_for_path (xmlbfn); + self->silo = xb_builder_ensure (builder, xmlb, compile_flags, NULL, error); + if (self->silo == NULL) + return FALSE; + + /* print what we've got */ + components = xb_silo_query (self->silo, "components/component", 0, NULL); + if (components != NULL) + g_debug ("%u components now in silo", components->len); + + /* build the index */ + if (!xb_silo_query_build_index (self->silo, + "components/component/provides/firmware", + "type", error)) + return FALSE; + if (!xb_silo_query_build_index (self->silo, + "components/component/provides/firmware", + NULL, error)) + return FALSE; /* did any devices SUPPORTED state change? */ devices = fu_device_list_get_all (self->device_list); @@ -2077,7 +2375,8 @@ blob_sig = fu_common_get_contents_bytes (fwupd_remote_get_filename_cache_sig (remote), error); if (blob_sig == NULL) return NULL; - return fu_keyring_verify_data (kr, blob, blob_sig, error); + return fu_keyring_verify_data (kr, blob, blob_sig, + FU_KEYRING_VERIFY_FLAG_NONE, error); } /** @@ -2104,6 +2403,8 @@ g_autoptr(GBytes) bytes_sig = NULL; g_autoptr(GInputStream) stream_fd = NULL; g_autoptr(GInputStream) stream_sig = NULL; + g_autofree gchar *pki_dir = NULL; + g_autofree gchar *sysconfdir = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (remote_id != NULL, FALSE); @@ -2149,14 +2450,18 @@ g_autoptr(FuKeyringResult) kr_result = NULL; g_autoptr(FuKeyringResult) kr_result_old = NULL; g_autoptr(GError) error_local = NULL; - kr = fu_engine_get_keyring_for_kind (keyring_kind, error); + kr = fu_keyring_create_for_kind (keyring_kind, error); if (kr == NULL) return FALSE; if (!fu_keyring_setup (kr, error)) return FALSE; - if (!fu_keyring_add_public_keys (kr, "/etc/pki/fwupd-metadata", error)) + sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); + pki_dir = g_build_filename (sysconfdir, "pki", "fwupd-metadata", NULL); + if (!fu_keyring_add_public_keys (kr, pki_dir, error)) return FALSE; - kr_result = fu_keyring_verify_data (kr, bytes_raw, bytes_sig, error); + kr_result = fu_keyring_verify_data (kr, bytes_raw, bytes_sig, + FU_KEYRING_VERIFY_FLAG_NONE, + error); if (kr_result == NULL) return FALSE; @@ -2205,24 +2510,23 @@ bytes_sig, error)) return FALSE; } - return fu_engine_load_metadata_store (self, error); + return fu_engine_load_metadata_store (self, FU_ENGINE_LOAD_FLAG_NONE, error); } /** - * fu_engine_get_store_from_blob: + * fu_engine_get_silo_from_blob: * @self: A #FuEngine * @blob_cab: A #GBytes * @error: A #GError, or %NULL * - * Creates an AppStream store from a .cab file blob. + * Creates a silo from a .cab file blob. * - * Returns: (transfer container): a #AsStore, or %NULL + * Returns: (transfer container): a #XbSilo, or %NULL **/ -AsStore * -fu_engine_get_store_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) +XbSilo * +fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error) { - g_autofree gchar *checksum = NULL; - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); g_return_val_if_fail (blob_cab != NULL, NULL); @@ -2230,55 +2534,60 @@ /* load file */ fu_engine_set_status (self, FWUPD_STATUS_DECOMPRESSING); - store = fu_common_store_from_cab_bytes (blob_cab, - fu_engine_get_archive_size_max (self), - error); - if (store == NULL) + silo = fu_common_cab_build_silo (blob_cab, + fu_engine_get_archive_size_max (self), + error); + if (silo == NULL) return NULL; - /* get a checksum of the file and use it as the origin */ - checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, blob_cab); - as_store_set_origin (store, checksum); - fu_engine_set_status (self, FWUPD_STATUS_IDLE); - return g_steal_pointer (&store); + return g_steal_pointer (&silo); } -static FwupdDevice * -fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) +static FuDevice * +fu_engine_get_result_from_component (FuEngine *self, XbNode *component, GError **error) { - FwupdTrustFlags trust_flags = FWUPD_TRUST_FLAG_NONE; - AsRelease *release; - GPtrArray *provides; - g_autoptr(FwupdDevice) dev = NULL; + FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE; + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(FuDevice) dev = NULL; g_autoptr(FwupdRelease) rel = NULL; - - dev = fwupd_device_new (); - provides = as_app_get_provides (app); + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) description = NULL; + g_autoptr(XbNode) release = NULL; + + dev = fu_device_new (); + provides = xb_node_query (component, + "provides/firmware[@type=$'flashed']", + 0, &error_local); + if (provides == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to get release: %s", + error_local->message); + return NULL; + } for (guint i = 0; i < provides->len; i++) { - AsProvide *prov = AS_PROVIDE (g_ptr_array_index (provides, i)); - FuDevice *device; + XbNode *prov = XB_NODE (g_ptr_array_index (provides, i)); const gchar *guid; - - /* not firmware */ - if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) - continue; + g_autoptr(FuDevice) device = NULL; /* is a online or offline update appropriate */ - guid = as_provide_get_value (prov); + guid = xb_node_get_text (prov); if (guid == NULL) continue; device = fu_device_list_get_by_guid (self->device_list, guid, NULL); if (device != NULL) { - fwupd_device_set_name (dev, fu_device_get_name (device)); - fwupd_device_set_flags (dev, fu_device_get_flags (device)); - fwupd_device_set_id (dev, fu_device_get_id (device)); + fu_device_set_name (dev, fu_device_get_name (device)); + fu_device_set_flags (dev, fu_device_get_flags (device)); + fu_device_set_id (dev, fu_device_get_id (device)); } /* add GUID */ - fwupd_device_add_guid (dev, guid); + fu_device_add_guid (dev, guid); } - if (fwupd_device_get_guids(dev)->len == 0) { + if (fu_device_get_guids(dev)->len == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, @@ -2286,27 +2595,58 @@ return NULL; } + /* get (or guess) the component version format */ + if (!fu_engine_set_device_version_format (self, dev, component, error)) + return NULL; + /* check we can install it */ - if (!fu_engine_check_requirements (self, app, NULL, error)) + task = fu_install_task_new (NULL, component); + if (!fu_engine_check_requirements (self, task, + FWUPD_INSTALL_FLAG_NONE, + error)) return NULL; /* verify trust */ - release = as_app_get_release_default (app); - if (!fu_engine_get_release_trust_flags (release, &trust_flags, error)) + release = xb_node_query_first (component, + "releases/release", + &error_local); + if (release == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to get release: %s", + error_local->message); return NULL; - - /* possibly convert the version from 0x to dotted */ - fu_engine_vendor_quirk_release_version (self, app); - - /* possibly convert the flashed provide to a GUID */ - fu_engine_vendor_fixup_provide_value (app); + } + if (!fu_keyring_get_release_flags (release, + &release_flags, + &error_local)) { + if (g_error_matches (error_local, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED)) { + g_warning ("Ignoring verification: %s", + error_local->message); + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return NULL; + } + } /* create a result with all the metadata in */ - fwupd_device_set_description (dev, as_app_get_description (app, NULL)); + description = xb_node_query_first (component, "description", NULL); + if (description != NULL) { + g_autofree gchar *xml = NULL; + xml = xb_node_export (description, + XB_NODE_EXPORT_FLAG_ONLY_CHILDREN, + NULL); + if (xml != NULL) + fu_device_set_description (dev, xml); + } rel = fwupd_release_new (); - fwupd_release_set_trust_flags (rel, trust_flags); - fu_engine_set_release_from_appstream (self, rel, app, release); - fwupd_device_add_release (dev, rel); + fwupd_release_set_flags (rel, release_flags); + if (!fu_engine_set_release_from_appstream (self, dev, rel, component, release, error)) + return NULL; + fu_device_add_release (dev, rel); return g_steal_pointer (&dev); } @@ -2320,60 +2660,64 @@ * * Note: this will close the fd when done * - * Returns: (transfer container) (element-type FwupdDevice): results + * Returns: (transfer container) (element-type FuDevice): results **/ GPtrArray * fu_engine_get_details (FuEngine *self, gint fd, GError **error) { - GPtrArray *apps; const gchar *remote_id; g_autofree gchar *csum = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) components = NULL; g_autoptr(GPtrArray) details = NULL; + g_autoptr(XbSilo) silo = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); g_return_val_if_fail (fd > 0, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - /* get all apps */ + /* get all components */ blob = fu_common_get_contents_fd (fd, fu_engine_get_archive_size_max (self), error); if (blob == NULL) return NULL; - store = fu_engine_get_store_from_blob (self, blob, error); - if (store == NULL) + silo = fu_engine_get_silo_from_blob (self, blob, error); + if (silo == NULL) return NULL; - apps = as_store_get_apps (store); - if (apps->len == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no components"); + components = xb_silo_query (silo, "components/component", 0, &error_local); + if (components == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no components: %s", + error_local->message); return NULL; } + /* build the index */ + if (!xb_silo_query_build_index (silo, "components/component/provides/firmware", + "type", error)) + return NULL; + if (!xb_silo_query_build_index (silo, "components/component/provides/firmware", + NULL, error)) + return NULL; + /* does this exist in any enabled remote */ csum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); remote_id = fu_engine_get_remote_id_for_checksum (self, csum); /* create results with all the metadata in */ details = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (guint i = 0; i < apps->len; i++) { - AsApp *app = g_ptr_array_index (apps, i); - FwupdDevice *dev; - - /* check we can install it */ - if (!fu_engine_check_requirements (self, app, NULL, error)) - return NULL; - - as_app_set_origin (app, as_store_get_origin (store)); - dev = fu_engine_get_result_from_app (self, app, error); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + FuDevice *dev; + dev = fu_engine_get_result_from_component (self, component, error); if (dev == NULL) return NULL; if (remote_id != NULL) { - FwupdRelease *rel = fwupd_device_get_release_default (dev); + FwupdRelease *rel = fu_device_get_release_default (dev); fwupd_release_set_remote_id (rel, remote_id); fu_device_add_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED); } @@ -2382,6 +2726,21 @@ return g_steal_pointer (&details); } +static gint +fu_engine_sort_devices_by_priority (gconstpointer a, gconstpointer b) +{ + FuDevice *dev_a = *((FuDevice **) a); + FuDevice *dev_b = *((FuDevice **) b); + gint prio_a = fu_device_get_priority (dev_a); + gint prio_b = fu_device_get_priority (dev_b); + + if (prio_a > prio_b) + return -1; + if (prio_a < prio_b) + return 1; + return 0; +} + /** * fu_engine_get_devices: * @self: A #FuEngine @@ -2407,10 +2766,32 @@ "No detected devices"); return NULL; } + g_ptr_array_sort (devices, fu_engine_sort_devices_by_priority); return g_steal_pointer (&devices); } /** + * fu_engine_get_device: + * @self: A #FuEngine + * @device_id: A device ID + * @error: A #GError, or %NULL + * + * Gets a specific device. + * + * Returns: (transfer full): a device, or %NULL if not found + **/ +FuDevice * +fu_engine_get_device (FuEngine *self, const gchar *device_id, GError **error) +{ + FuDevice *device; + + device = fu_device_list_get_by_id (self->device_list, device_id, error); + if (device == NULL) + return NULL; + return device; +} + +/** * fu_engine_get_history: * @self: A #FuEngine * @error: A #GError, or %NULL @@ -2493,40 +2874,158 @@ return g_ptr_array_ref (remotes); } +/** + * fu_engine_get_remote_by_id: + * @self: A #FuEngine + * @remote_id: A string representation of a remote + * @error: A #GError, or %NULL + * + * Gets the FwupdRemote object. + * + * Returns: FwupdRemote + **/ +FwupdRemote * +fu_engine_get_remote_by_id (FuEngine *self, const gchar *remote_id, GError **error) +{ + g_autoptr(GPtrArray) remotes = NULL; + + remotes = fu_engine_get_remotes (self, error); + if (remotes == NULL) + return NULL; + + for (guint i = 0; i < remotes->len; i++) { + FwupdRemote *remote = g_ptr_array_index (remotes, i); + if (g_strcmp0 (remote_id, fwupd_remote_get_id (remote)) == 0) + return remote; + } + + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Couldn't find remote %s", remote_id); + + return NULL; +} + + static gint fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b) { FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a)); FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b)); - return as_utils_vercmp (fwupd_release_get_version (rel_b), + return fu_common_vercmp (fwupd_release_get_version (rel_b), fwupd_release_get_version (rel_a)); } -static AsApp * -fu_engine_filter_apps_by_requirements (FuEngine *self, GPtrArray *apps, - FuDevice *device, GError **error) +static gboolean +fu_engine_check_release_is_approved (FuEngine *self, FwupdRelease *rel) { - g_autoptr(GError) error_all = NULL; + GPtrArray *csums = fwupd_release_get_checksums (rel); + for (guint i = 0; i < csums->len; i++) { + const gchar *csum = g_ptr_array_index (csums, i); + g_debug ("checking %s against approved list", csum); + if (g_hash_table_lookup (self->approved_firmware, csum) != NULL) + return TRUE; + } + return FALSE; +} - /* find the first component that passes all the requirements */ - for (guint i = 0; i < apps->len; i++) { - g_autoptr(GError) error_local = NULL; - AsApp *app_tmp = AS_APP (g_ptr_array_index (apps, i)); - if (!fu_engine_check_requirements (self, app_tmp, device, &error_local)) { - if (error_all == NULL) { - error_all = g_steal_pointer (&error_local); - continue; - } - /* assume the domain and code is the same */ - g_prefix_error (&error_all, "%s, ", error_local->message); +static gboolean +fu_engine_add_releases_for_device_component (FuEngine *self, + FuDevice *device, + XbNode *component, + GPtrArray *releases, + GError **error) +{ + g_autoptr(GError) error_local = NULL; + g_autoptr(FuInstallTask) task = fu_install_task_new (device, component); + g_autoptr(GPtrArray) releases_tmp = NULL; + + if (!fu_engine_check_requirements (self, task, + FWUPD_INSTALL_FLAG_OFFLINE | + FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | + FWUPD_INSTALL_FLAG_ALLOW_OLDER, + error)) + return FALSE; + + /* get all releases */ + releases_tmp = xb_node_query (component, "releases/release", 0, &error_local); + if (releases_tmp == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return TRUE; + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + return TRUE; + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + for (guint i = 0; i < releases_tmp->len; i++) { + XbNode *release = g_ptr_array_index (releases_tmp, i); + const gchar *remote_id; + const gchar *update_message; + gint vercmp; + GPtrArray *checksums; + g_autoptr(FwupdRelease) rel = fwupd_release_new (); + g_autoptr(GError) error_loop = NULL; + + /* create new FwupdRelease for the XbNode */ + if (!fu_engine_set_release_from_appstream (self, + device, + rel, + component, + release, + &error_loop)) { + g_warning ("failed to set release for component: %s", + error_loop->message); continue; } - return g_object_ref (app_tmp); + + /* fall back to quirk-provided value */ + if (fwupd_release_get_install_duration (rel) == 0) + fwupd_release_set_install_duration (rel, fu_device_get_install_duration (device)); + + /* invalid */ + if (fwupd_release_get_uri (rel) == NULL) + continue; + checksums = fwupd_release_get_checksums (rel); + if (checksums->len == 0) + continue; + + /* test for upgrade or downgrade */ + vercmp = fu_common_vercmp (fwupd_release_get_version (rel), + fu_device_get_version (device)); + if (vercmp > 0) + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_IS_UPGRADE); + else if (vercmp < 0) + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_IS_DOWNGRADE); + + /* lower than allowed to downgrade to */ + if (fu_device_get_version_lowest (device) != NULL && + fu_common_vercmp (fwupd_release_get_version (rel), + fu_device_get_version_lowest (device)) < 0) { + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_BLOCKED_VERSION); + } + + /* check if remote is whitelisting firmware */ + remote_id = fwupd_release_get_remote_id (rel); + if (remote_id != NULL) { + FwupdRemote *remote = fu_engine_get_remote_by_id (self, remote_id, NULL); + if (remote != NULL && + fwupd_remote_get_approval_required (remote) && + !fu_engine_check_release_is_approved (self, rel)) { + fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL); + } + } + + /* add update message if exists but device doesn't already have one */ + update_message = fwupd_release_get_update_message (rel); + if (fwupd_device_get_update_message (FWUPD_DEVICE (device)) == NULL && + update_message != NULL) { + fwupd_device_set_update_message (FWUPD_DEVICE (device), update_message); + } + /* success */ + g_ptr_array_add (releases, g_steal_pointer (&rel)); } - /* return the compound error */ - g_propagate_error (error, g_steal_pointer (&error_all)); - return NULL; + /* success */ + return TRUE; } static GPtrArray * @@ -2535,6 +3034,10 @@ GPtrArray *device_guids; GPtrArray *releases; const gchar *version; + g_autoptr(GError) error_all = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GString) xpath = g_string_new (NULL); /* get device version */ version = fu_device_get_version (device); @@ -2552,51 +3055,67 @@ FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "ignoring %s [%s] as not updatable", - fu_device_get_id (device), - fu_device_get_name (device)); + fu_device_get_name (device), + fu_device_get_id (device)); return NULL; } - releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + /* get all the components that provide any of these GUIDs */ device_guids = fu_device_get_guids (device); for (guint i = 0; i < device_guids->len; i++) { - GPtrArray *releases_tmp; - g_autoptr(AsApp) app = NULL; - g_autoptr(GPtrArray) apps = NULL; const gchar *guid = g_ptr_array_index (device_guids, i); - - /* get all the components that provide this GUID */ - apps = _as_store_get_apps_by_provide (self->store, - AS_PROVIDE_KIND_FIRMWARE_FLASHED, - guid); - if (apps->len == 0) - continue; - - /* filter by requirements */ - app = fu_engine_filter_apps_by_requirements (self, apps, device, error); - if (app == NULL) + xb_string_append_union (xpath, + "components/component/" + "provides/firmware[@type=$'flashed'][text()=$'%s']/" + "../..", guid); + } + components = xb_silo_query (self->silo, xpath->str, 0, &error_local); + if (components == NULL) { + if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No releases for %s", + fu_device_get_name (device)); return NULL; + } + g_propagate_error (error, g_steal_pointer (&error_local)); + return NULL; + } - /* get all releases */ - releases_tmp = as_app_get_releases (app); - for (guint j = 0; j < releases_tmp->len; j++) { - AsRelease *release = g_ptr_array_index (releases_tmp, j); - GPtrArray *checksums; - g_autoptr(FwupdRelease) rel = fwupd_release_new (); - - /* create new FwupdRelease for the AsRelease */ - fu_engine_set_release_from_appstream (self, rel, app, release); - - /* invalid */ - if (fwupd_release_get_uri (rel) == NULL) - continue; - checksums = fwupd_release_get_checksums (rel); - if (checksums->len == 0) + /* find all the releases that pass all the requirements */ + releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < components->len; i++) { + XbNode *component = XB_NODE (g_ptr_array_index (components, i)); + g_autoptr(GError) error_tmp = NULL; + if (!fu_engine_add_releases_for_device_component (self, + device, + component, + releases, + &error_tmp)) { + if (error_all == NULL) { + error_all = g_steal_pointer (&error_tmp); continue; + } + + /* assume the domain and code is the same */ + g_prefix_error (&error_all, "%s, ", error_tmp->message); + } + } - /* success */ - g_ptr_array_add (releases, g_steal_pointer (&rel)); + /* return the compound error */ + if (releases->len == 0) { + if (error_all != NULL) { + g_propagate_prefixed_error (error, g_steal_pointer (&error_all), + "No releases found for device: "); + return NULL; } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No releases found for device"); + return NULL; } return releases; } @@ -2614,7 +3133,7 @@ GPtrArray * fu_engine_get_releases (FuEngine *self, const gchar *device_id, GError **error) { - FuDevice *device; + g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), NULL); @@ -2654,7 +3173,7 @@ GPtrArray * fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error) { - FuDevice *device; + g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; g_autoptr(GPtrArray) releases_tmp = NULL; g_autoptr(GString) error_str = g_string_new (NULL); @@ -2675,12 +3194,10 @@ releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < releases_tmp->len; i++) { FwupdRelease *rel_tmp = g_ptr_array_index (releases_tmp, i); - gint vercmp; - /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), - fu_device_get_version (device)); - if (vercmp == 0) { + /* same as installed */ + if (!fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_UPGRADE) && + !fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_DOWNGRADE)) { g_string_append_printf (error_str, "%s=same, ", fwupd_release_get_version (rel_tmp)); g_debug ("ignoring %s as the same as %s", @@ -2688,7 +3205,9 @@ fu_device_get_version (device)); continue; } - if (vercmp > 0) { + + /* newer than current */ + if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_UPGRADE)) { g_string_append_printf (error_str, "%s=newer, ", fwupd_release_get_version (rel_tmp)); g_debug ("ignoring %s as newer than %s", @@ -2697,17 +3216,14 @@ continue; } - /* don't show releases we are not allowed to dowgrade to */ - if (fu_device_get_version_lowest (device) != NULL) { - if (as_utils_vercmp (fwupd_release_get_version (rel_tmp), - fu_device_get_version_lowest (device)) <= 0) { - g_string_append_printf (error_str, "%s=lowest, ", - fwupd_release_get_version (rel_tmp)); - g_debug ("ignoring %s as older than lowest %s", - fwupd_release_get_version (rel_tmp), - fu_device_get_version_lowest (device)); - continue; - } + /* don't show releases we are not allowed to downgrade to */ + if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_BLOCKED_VERSION)) { + g_string_append_printf (error_str, "%s=lowest, ", + fwupd_release_get_version (rel_tmp)); + g_debug ("ignoring %s as older than lowest %s", + fwupd_release_get_version (rel_tmp), + fu_device_get_version_lowest (device)); + continue; } g_ptr_array_add (releases, g_object_ref (rel_tmp)); } @@ -2734,6 +3250,54 @@ return g_steal_pointer (&releases); } +GPtrArray * +fu_engine_get_approved_firmware (FuEngine *self) +{ + GPtrArray *checksums = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GList) keys = g_hash_table_get_keys (self->approved_firmware); + for (GList *l = keys; l != NULL; l = l->next) { + const gchar *csum = l->data; + g_ptr_array_add (checksums, g_strdup (csum)); + } + return checksums; +} + +void +fu_engine_add_approved_firmware (FuEngine *self, const gchar *checksum) +{ + g_hash_table_add (self->approved_firmware, g_strdup (checksum)); +} + +gchar * +fu_engine_self_sign (FuEngine *self, + const gchar *value, + FuKeyringSignFlags flags, + GError **error) +{ + g_autoptr(FuKeyring) kr = NULL; + g_autoptr(FuKeyringResult) kr_result = NULL; + g_autoptr(GBytes) payload = NULL; + g_autoptr(GBytes) signature = NULL; + + /* create detached signature and verify */ + kr = fu_keyring_create_for_kind (FWUPD_KEYRING_KIND_PKCS7, error); + if (kr == NULL) + return NULL; + if (!fu_keyring_setup (kr, error)) + return NULL; + payload = g_bytes_new (value, strlen (value)); + signature = fu_keyring_sign_data (kr, payload, flags, error); + if (signature == NULL) + return NULL; + kr_result = fu_keyring_verify_data (kr, payload, signature, + FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT, + error); + if (kr_result == NULL) + return NULL; + return g_strndup (g_bytes_get_data (signature, NULL), + g_bytes_get_size (signature)); +} + /** * fu_engine_get_upgrades: * @self: A #FuEngine @@ -2747,7 +3311,7 @@ GPtrArray * fu_engine_get_upgrades (FuEngine *self, const gchar *device_id, GError **error) { - FuDevice *device; + g_autoptr(FuDevice) device = NULL; g_autoptr(GPtrArray) releases = NULL; g_autoptr(GPtrArray) releases_tmp = NULL; g_autoptr(GString) error_str = g_string_new (NULL); @@ -2761,6 +3325,16 @@ if (device == NULL) return NULL; + /* don't show upgrades again until we reboot */ + if (fu_device_get_update_state (device) == FWUPD_UPDATE_STATE_NEEDS_REBOOT) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No upgrades for %s: A reboot is pending", + fu_device_get_name (device)); + return NULL; + } + /* get all the releases for the device */ releases_tmp = fu_engine_get_releases_for_device (self, device, error); if (releases_tmp == NULL) @@ -2768,12 +3342,10 @@ releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (guint i = 0; i < releases_tmp->len; i++) { FwupdRelease *rel_tmp = g_ptr_array_index (releases_tmp, i); - gint vercmp; - /* only include older firmware */ - vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp), - fu_device_get_version (device)); - if (vercmp == 0) { + /* same as installed */ + if (!fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_UPGRADE) && + !fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_DOWNGRADE)) { g_string_append_printf (error_str, "%s=same, ", fwupd_release_get_version (rel_tmp)); g_debug ("ignoring %s as the same as %s", @@ -2781,7 +3353,9 @@ fu_device_get_version (device)); continue; } - if (vercmp < 0) { + + /* older than current */ + if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_DOWNGRADE)) { g_string_append_printf (error_str, "%s=older, ", fwupd_release_get_version (rel_tmp)); g_debug ("ignoring %s as older than %s", @@ -2789,6 +3363,17 @@ fu_device_get_version (device)); continue; } + + /* not approved */ + if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL)) { + g_string_append_printf (error_str, "%s=not-approved, ", + fwupd_release_get_version (rel_tmp)); + g_debug ("ignoring %s as not approved as required by %s", + fwupd_release_get_version (rel_tmp), + fwupd_release_get_remote_id (rel_tmp)); + continue; + } + g_ptr_array_add (releases, g_object_ref (rel_tmp)); } if (error_str->len > 2) @@ -2889,14 +3474,15 @@ /* find the device */ device = fu_engine_get_item_by_id_fallback_history (self, device_id, error); if (device == NULL) - return FALSE; + return NULL; /* the notification has already been shown to the user */ if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NOTIFIED)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, - "User has already been notified about %s", + "User has already been notified about %s [%s]", + fu_device_get_name (device), fu_device_get_id (device)); return NULL; } @@ -2908,20 +3494,10 @@ static void fu_engine_plugins_setup (FuEngine *self) { - GPtrArray *plugins; - g_autoptr(AsProfileTask) ptask = NULL; - - ptask = as_profile_start_literal (self->profile, "FuEngine:setup"); - g_assert (ptask != NULL); - plugins = fu_plugin_list_get_all (self->plugin_list); + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); for (guint i = 0; i < plugins->len; i++) { g_autoptr(GError) error = NULL; - g_autoptr(AsProfileTask) ptask2 = NULL; FuPlugin *plugin = g_ptr_array_index (plugins, i); - ptask2 = as_profile_start (self->profile, - "FuEngine:setup{%s}", - fu_plugin_get_name (plugin)); - g_assert (ptask2 != NULL); if (!fu_plugin_runner_startup (plugin, &error)) { fu_plugin_set_enabled (plugin, FALSE); g_message ("disabling plugin because: %s", error->message); @@ -2933,7 +3509,6 @@ fu_engine_plugins_coldplug (FuEngine *self, gboolean is_recoldplug) { GPtrArray *plugins; - g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(GString) str = g_string_new (NULL); /* don't allow coldplug to be scheduled when in coldplug */ @@ -2955,16 +3530,9 @@ } /* exec */ - ptask = as_profile_start_literal (self->profile, "FuEngine:coldplug"); - g_assert (ptask != NULL); for (guint i = 0; i < plugins->len; i++) { g_autoptr(GError) error = NULL; - g_autoptr(AsProfileTask) ptask2 = NULL; FuPlugin *plugin = g_ptr_array_index (plugins, i); - ptask2 = as_profile_start (self->profile, - "FuEngine:coldplug{%s}", - fu_plugin_get_name (plugin)); - g_assert (ptask2 != NULL); if (is_recoldplug) { if (!fu_plugin_runner_recoldplug (plugin, &error)) g_message ("failed recoldplug: %s", error->message); @@ -2994,7 +3562,7 @@ } if (str->len > 2) { g_string_truncate (str, str->len - 2); - g_message ("using plugins: %s", str->str); + g_debug ("using plugins: %s", str->str); } /* we can recoldplug from this point on */ @@ -3015,25 +3583,109 @@ FuPlugin *plugin = g_ptr_array_index (plugins, i); fu_plugin_runner_device_register (plugin, device); } - fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REGISTERED); -} + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_REGISTERED); +} + +static void +fu_engine_plugin_device_register_cb (FuPlugin *plugin, + FuDevice *device, + gpointer user_data) +{ + FuEngine *self = FU_ENGINE (user_data); + fu_engine_plugin_device_register (self, device); +} + +static void +fu_engine_plugin_device_added_cb (FuPlugin *plugin, + FuDevice *device, + gpointer user_data) +{ + FuEngine *self = (FuEngine *) user_data; + gint priority = fu_plugin_get_priority (plugin); + GPtrArray *children = fu_device_get_children (device); + /* set the priority to 1 greater than biggest child */ + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + gint child_priority = fu_device_get_priority (child); + if (child_priority >= priority) + priority = child_priority + 1; + } + fu_device_set_priority (device, priority); + fu_engine_add_device (self, device); +} + +static void +fu_engine_adopt_children (FuEngine *self, FuDevice *device) +{ + GPtrArray *guids; + g_autoptr(GPtrArray) devices = fu_device_list_get_active (self->device_list); + + /* find the parent GUID in any existing device */ + guids = fu_device_get_parent_guids (device); + for (guint j = 0; j < guids->len; j++) { + const gchar *guid = g_ptr_array_index (guids, j); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device_tmp = g_ptr_array_index (devices, i); + if (fu_device_get_parent (device) != NULL) + continue; + if (fu_device_has_guid (device_tmp, guid)) { + g_debug ("setting parent of %s [%s] to be %s [%s]", + fu_device_get_name (device), + fu_device_get_id (device), + fu_device_get_name (device_tmp), + fu_device_get_id (device_tmp)); + fu_device_add_child (device_tmp, device); + break; + } + } + } -static void -fu_engine_plugin_device_register_cb (FuPlugin *plugin, - FuDevice *device, - gpointer user_data) -{ - FuEngine *self = FU_ENGINE (user_data); - fu_engine_plugin_device_register (self, device); + /* the new device is the parent to an existing child */ + guids = fu_device_get_guids (device); + for (guint j = 0; j < guids->len; j++) { + const gchar *guid = g_ptr_array_index (guids, j); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device_tmp = g_ptr_array_index (devices, i); + if (fu_device_get_parent (device_tmp) != NULL) + continue; + if (fu_device_has_parent_guid (device_tmp, guid)) { + g_debug ("setting parent of %s [%s] to be %s [%s]", + fu_device_get_name (device_tmp), + fu_device_get_id (device_tmp), + fu_device_get_name (device), + fu_device_get_id (device)); + fu_device_add_child (device, device_tmp); + } + } + } } static void -fu_engine_plugin_device_added_cb (FuPlugin *plugin, - FuDevice *device, - gpointer user_data) +fu_engine_device_inherit_history (FuEngine *self, FuDevice *device) { - FuEngine *self = (FuEngine *) user_data; - fu_engine_add_device (self, device); + g_autoptr(FuDevice) device_history = NULL; + + /* any success or failed update? */ + device_history = fu_history_get_device_by_id (self->history, + fu_device_get_id (device), + NULL); + if (device_history == NULL) + return; + + /* the device is still running the old firmware version and so if it + * required activation before, it still requires it now -- note: + * we can't just check for version_new=version to allow for re-installs */ + if (fu_device_has_flag (device_history, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { + FwupdRelease *release = fu_device_get_release_default (device_history); + if (fu_common_vercmp (fu_device_get_version (device), + fwupd_release_get_version (release)) != 0) { + g_debug ("inheriting needs-activation for %s as version %s != %s", + fu_device_get_name (device), + fu_device_get_version (device), + fwupd_release_get_version (release)); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + } + } } void @@ -3046,8 +3698,8 @@ device_guids = fu_device_get_guids (device); if (device_guids->len == 0) { g_warning ("no GUIDs for device %s [%s]", - fu_device_get_id (device), - fu_device_get_name (device)); + fu_device_get_name (device), + fu_device_get_id (device)); return; } @@ -3058,25 +3710,86 @@ for (guint j = 0; j < device_guids->len; j++) { const gchar *device_guid = g_ptr_array_index (device_guids, j); if (g_strcmp0 (blacklisted_guid, device_guid) == 0) { - g_debug ("%s is blacklisted [%s], ignoring from %s", - fu_device_get_id (device), device_guid, + g_debug ("%s [%s] is blacklisted [%s], ignoring from %s", + fu_device_get_name (device), + fu_device_get_id (device), + device_guid, fu_device_get_plugin (device)); return; } } } + /* if this device is locked get some metadata from AppStream */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_LOCKED)) { + g_autoptr(XbNode) component = fu_engine_get_component_by_guids (self, device); + if (component != NULL) { + g_autoptr(XbNode) release = NULL; + release = xb_node_query_first (component, + "releases/release", + NULL); + if (release != NULL) { + g_autoptr(FwupdRelease) rel = fwupd_release_new (); + g_autoptr(GError) error_local = NULL; + if (!fu_engine_set_release_from_appstream (self, + device, + rel, + component, + release, + &error_local)) { + g_warning ("failed to set AppStream release: %s", + error_local->message); + } else { + fu_device_add_release (device, rel); + } + } + } + } + + /* adopt any required children, which may or may not already exist */ + fu_engine_adopt_children (self, device); + + /* set any alternate objects on the device from the ID */ + if (fu_device_get_alternate_id (device) != NULL) { + g_autoptr(FuDevice) device_alt = NULL; + device_alt = fu_device_list_get_by_id (self->device_list, + fu_device_get_alternate_id (device), + NULL); + if (device_alt != NULL) + fu_device_set_alternate (device, device_alt); + } + + if (fu_device_get_version_format (device) == FWUPD_VERSION_FORMAT_UNKNOWN && + fu_common_version_guess_format (fu_device_get_version (device)) == FWUPD_VERSION_FORMAT_NUMBER) { + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_update_error (device, "VersionFormat is ambiguous for this device"); + } + /* notify all plugins about this new device */ if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)) fu_engine_plugin_device_register (self, device); + /* create new device */ + fu_device_list_add (self->device_list, device); + /* match the metadata at this point so clients can tell if the * device is worthy */ if (fu_engine_is_device_supported (self, device)) fu_device_add_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED); - /* create new device */ - fu_device_list_add (self->device_list, device); + /* sometimes inherit flags from recent history */ + fu_engine_device_inherit_history (self, device); +} + +static void +fu_engine_plugin_rules_changed_cb (FuPlugin *plugin, gpointer user_data) +{ + FuEngine *self = FU_ENGINE (user_data); + GPtrArray *rules = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_INHIBITS_IDLE); + for (guint j = 0; j < rules->len; j++) { + const gchar *tmp = g_ptr_array_index (rules, j); + fu_idle_inhibit (self->idle, tmp); + } } static void @@ -3085,8 +3798,8 @@ gpointer user_data) { FuEngine *self = (FuEngine *) user_data; - FuDevice *device_tmp; FuPlugin *plugin_old; + g_autoptr(FuDevice) device_tmp = NULL; g_autoptr(GError) error = NULL; device_tmp = fu_device_list_get_by_id (self->device_list, @@ -3130,12 +3843,140 @@ } static void +fu_engine_udev_device_add (FuEngine *self, GUdevDevice *udev_device) +{ + GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + const gchar *plugin_name; + g_autoptr(FuUdevDevice) device = fu_udev_device_new (udev_device); + g_autoptr(GError) error_local = NULL; + + /* add any extra quirks */ + fu_device_set_quirks (FU_DEVICE (device), self->quirks); + if (!fu_device_probe (FU_DEVICE (device), &error_local)) { + g_warning ("failed to probe device %s: %s", + g_udev_device_get_sysfs_path (udev_device), + error_local->message); + return; + } + + /* can be specified using a quirk */ + plugin_name = fu_device_get_plugin (FU_DEVICE (device)); + if (plugin_name != NULL) { + g_autoptr(GError) error = NULL; + FuPlugin *plugin = fu_plugin_list_find_by_name (self->plugin_list, + plugin_name, &error); + if (plugin == NULL) { + g_warning ("failed to find specified plugin %s: %s", + plugin_name, error->message); + return; + } + if (!fu_plugin_runner_udev_device_added (plugin, device, &error)) { + g_warning ("failed to add udev device %s: %s", + g_udev_device_get_sysfs_path (udev_device), + error->message); + } + return; + } + + /* call into each plugin */ + g_debug ("no plugin specified for udev device %s", + g_udev_device_get_sysfs_path (udev_device)); + for (guint j = 0; j < plugins->len; j++) { + FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); + g_autoptr(GError) error = NULL; + + /* skipping plugin as requires quirk */ + if (fu_plugin_has_rule (plugin_tmp, + FU_PLUGIN_RULE_REQUIRES_QUIRK, + FU_QUIRKS_PLUGIN)) { + continue; + } + + /* run all plugins */ + if (!fu_plugin_runner_udev_device_added (plugin_tmp, device, &error)) { + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_debug ("%s ignoring: %s", + fu_plugin_get_name (plugin_tmp), + error->message); + continue; + } + g_warning ("%s failed to add udev device %s: %s", + fu_plugin_get_name (plugin_tmp), + g_udev_device_get_sysfs_path (udev_device), + error->message); + } + } +} + +static void +fu_engine_udev_device_remove (FuEngine *self, GUdevDevice *udev_device) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* go through each device and remove any that match */ + devices = fu_device_list_get_all (self->device_list); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + if (!FU_IS_UDEV_DEVICE (device)) + continue; + if (g_strcmp0 (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device)), + g_udev_device_get_sysfs_path (udev_device)) == 0) { + g_debug ("auto-removing GUdevDevice"); + fu_device_list_remove (self->device_list, device); + } + } +} + +static void +fu_engine_udev_device_changed (FuEngine *self, GUdevDevice *udev_device) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* emit changed on any that match */ + devices = fu_device_list_get_all (self->device_list); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + if (!FU_IS_UDEV_DEVICE (device)) + continue; + if (g_strcmp0 (fu_udev_device_get_sysfs_path (FU_UDEV_DEVICE (device)), + g_udev_device_get_sysfs_path (udev_device)) == 0) { + fu_udev_device_emit_changed (FU_UDEV_DEVICE (device)); + } + } +} + +static void +fu_engine_enumerate_udev (FuEngine *self) +{ + /* get all devices of class */ + for (guint i = 0; i < self->udev_subsystems->len; i++) { + const gchar *subsystem = g_ptr_array_index (self->udev_subsystems, i); + GList *devices = g_udev_client_query_by_subsystem (self->gudev_client, + subsystem); + g_debug ("%u devices with subsystem %s", + g_list_length (devices), subsystem); + for (GList *l = devices; l != NULL; l = l->next) { + GUdevDevice *udev_device = l->data; + fu_engine_udev_device_add (self, udev_device); + } + g_list_foreach (devices, (GFunc) g_object_unref, NULL); + g_list_free (devices); + } +} + +static void fu_engine_plugin_recoldplug_cb (FuPlugin *plugin, FuEngine *self) { if (self->coldplug_running) { g_warning ("coldplug already running, cannot recoldplug"); return; } + if (self->app_flags & FU_APP_FLAGS_NO_IDLE_SOURCES) { + g_debug ("doing direct recoldplug"); + fu_engine_plugins_coldplug (self, TRUE); + fu_engine_enumerate_udev (self); + return; + } g_debug ("scheduling a recoldplug"); if (self->coldplug_id != 0) g_source_remove (self->coldplug_id); @@ -3150,31 +3991,91 @@ duration, self->coldplug_delay); } -/* for the self tests to use */ +/* this is called by the self tests as well */ void fu_engine_add_plugin (FuEngine *self, FuPlugin *plugin) { + /* plugin does not match built version */ + if (fu_plugin_get_build_hash (plugin) == NULL) { + const gchar *name = fu_plugin_get_name (plugin); + g_warning ("%s should call fu_plugin_set_build_hash()", name); + self->tainted = TRUE; + } else if (g_strcmp0 (fu_plugin_get_build_hash (plugin), FU_BUILD_HASH) != 0) { + const gchar *name = fu_plugin_get_name (plugin); + g_warning ("%s has incorrect built version %s", + name, fu_plugin_get_build_hash (plugin)); + self->tainted = TRUE; + } + fu_plugin_list_add (self->plugin_list, plugin); } static gboolean +fu_engine_is_plugin_name_blacklisted (FuEngine *self, const gchar *name) +{ + GPtrArray *blacklist = fu_config_get_blacklist_plugins (self->config); + for (guint i = 0; i < blacklist->len; i++) { + const gchar *name_tmp = g_ptr_array_index (blacklist, i); + if (g_strcmp0 (name_tmp, name) == 0) + return TRUE; + } + return FALSE; +} + +static gboolean +fu_engine_is_plugin_name_whitelisted (FuEngine *self, const gchar *name) +{ + if (self->plugin_filter->len == 0) + return TRUE; + for (guint i = 0; i < self->plugin_filter->len; i++) { + const gchar *name_tmp = g_ptr_array_index (self->plugin_filter, i); + if (fnmatch (name_tmp, name, 0) == 0) + return TRUE; + } + return FALSE; +} + +void +fu_engine_add_plugin_filter (FuEngine *self, const gchar *plugin_glob) +{ + g_return_if_fail (FU_IS_ENGINE (self)); + g_return_if_fail (plugin_glob != NULL); + g_ptr_array_add (self->plugin_filter, g_strdup (plugin_glob)); +} + +static gboolean +fu_engine_plugin_check_supported_cb (FuPlugin *plugin, const gchar *guid, FuEngine *self) +{ + g_autoptr(XbNode) n = NULL; + g_autofree gchar *xpath = NULL; + xpath = g_strdup_printf ("components/component/" + "provides/firmware[@type='flashed'][text()='%s']", + guid); + n = xb_silo_query_first (self->silo, xpath, NULL); + return n != NULL; +} + +gboolean +fu_engine_get_tainted (FuEngine *self) +{ + return self->tainted; +} + +gboolean fu_engine_load_plugins (FuEngine *self, GError **error) { const gchar *fn; g_autoptr(GDir) dir = NULL; - g_autoptr(AsProfileTask) ptask = NULL; - - /* profile */ - ptask = as_profile_start_literal (self->profile, "FuEngine:load-plugins"); - g_assert (ptask != NULL); + g_autofree gchar *plugin_path = NULL; /* search */ - dir = g_dir_open (PLUGINDIR, 0, error); + plugin_path = fu_common_get_path (FU_PATH_KIND_PLUGINDIR_PKG); + dir = g_dir_open (plugin_path, 0, error); if (dir == NULL) return FALSE; while ((fn = g_dir_read_name (dir)) != NULL) { - GPtrArray *blacklist; g_autofree gchar *filename = NULL; + g_autofree gchar *name = NULL; g_autoptr(FuPlugin) plugin = NULL; g_autoptr(GError) error_local = NULL; @@ -3182,32 +4083,44 @@ if (!g_str_has_suffix (fn, ".so")) continue; + /* is blacklisted */ + name = fu_plugin_guess_name_from_fn (fn); + if (name == NULL) + continue; + if (fu_engine_is_plugin_name_blacklisted (self, name)) { + g_debug ("plugin %s is blacklisted", name); + continue; + } + if (!fu_engine_is_plugin_name_whitelisted (self, name)) { + g_debug ("plugin %s is not whitelisted", name); + continue; + } + /* open module */ - filename = g_build_filename (PLUGINDIR, fn, NULL); + filename = g_build_filename (plugin_path, fn, NULL); plugin = fu_plugin_new (); + fu_plugin_set_name (plugin, name); fu_plugin_set_usb_context (plugin, self->usb_ctx); fu_plugin_set_hwids (plugin, self->hwids); fu_plugin_set_smbios (plugin, self->smbios); - fu_plugin_set_supported (plugin, self->supported_guids); + fu_plugin_set_udev_subsystems (plugin, self->udev_subsystems); fu_plugin_set_quirks (plugin, self->quirks); + fu_plugin_set_runtime_versions (plugin, self->runtime_versions); + fu_plugin_set_compile_versions (plugin, self->compile_versions); g_debug ("adding plugin %s", filename); - if (!fu_plugin_open (plugin, filename, &error_local)) { - g_warning ("failed to open plugin %s: %s", - filename, error_local->message); - continue; - } - /* is blacklisted */ - blacklist = fu_config_get_blacklist_plugins (self->config); - for (guint i = 0; i < blacklist->len; i++) { - const gchar *name = g_ptr_array_index (blacklist, i); - if (g_strcmp0 (name, fu_plugin_get_name (plugin)) == 0) { - fu_plugin_set_enabled (plugin, FALSE); - break; + /* if loaded from fu_engine_load() open the plugin */ + if (self->usb_ctx != NULL) { + if (!fu_plugin_open (plugin, filename, &error_local)) { + g_warning ("failed to open plugin %s: %s", + filename, error_local->message); + continue; } } + + /* self disabled */ if (!fu_plugin_get_enabled (plugin)) { - g_debug ("%s blacklisted by config", + g_debug ("%s self disabled", fu_plugin_get_name (plugin)); continue; } @@ -3228,9 +4141,15 @@ g_signal_connect (plugin, "set-coldplug-delay", G_CALLBACK (fu_engine_plugin_set_coldplug_delay_cb), self); + g_signal_connect (plugin, "check-supported", + G_CALLBACK (fu_engine_plugin_check_supported_cb), + self); + g_signal_connect (plugin, "rules-changed", + G_CALLBACK (fu_engine_plugin_rules_changed_cb), + self); /* add */ - fu_plugin_list_add (self->plugin_list, plugin); + fu_engine_add_plugin (self, plugin); } /* depsolve into the correct order */ @@ -3241,38 +4160,6 @@ return TRUE; } -/** - * fu_engine_check_plugins_pending: - * @self: A #FuEngine - * @error: A #GError, or %NULL - * - * Checks if any plugins have pending devices to be added. - * - * Returns: %FALSE if any plugins have pending devices. - **/ -gboolean -fu_engine_check_plugins_pending (FuEngine *self, GError **error) -{ - GPtrArray *plugins; - - g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - plugins = fu_plugin_list_get_all (self->plugin_list); - for (guint i = 0; i < plugins->len; i++) { - FuPlugin *plugin = g_ptr_array_index (plugins, i); - if (fu_plugin_has_device_delay (plugin)) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "%s pending", - fu_plugin_get_name (plugin)); - return FALSE; - } - } - return TRUE; -} - static gboolean fu_engine_cleanup_state (GError **error) { @@ -3309,9 +4196,9 @@ FuDevice *device = g_ptr_array_index (devices, i); if (!FU_IS_USB_DEVICE (device)) continue; - if (g_strcmp0 (fu_device_get_platform_id (device), + if (g_strcmp0 (fu_usb_device_get_platform_id (FU_USB_DEVICE (device)), g_usb_device_get_platform_id (usb_device)) == 0) { - g_debug ("auto-removing FuUsbDevice"); + g_debug ("auto-removing GUsbDevice"); fu_device_list_remove (self->device_list, device); } } @@ -3323,17 +4210,67 @@ FuEngine *self) { GPtrArray *plugins = fu_plugin_list_get_all (self->plugin_list); + const gchar *plugin_name; + g_autoptr(FuUsbDevice) device = fu_usb_device_new (usb_device); + g_autoptr(GError) error_local = NULL; + + /* add any extra quirks */ + fu_device_set_quirks (FU_DEVICE (device), self->quirks); + if (!fu_device_probe (FU_DEVICE (device), &error_local)) { + g_warning ("failed to probe device %s: %s", + fu_device_get_physical_id (FU_DEVICE (device)), + error_local->message); + return; + } + + /* can be specified using a quirk */ + plugin_name = fu_device_get_plugin (device); + if (plugin_name != NULL) { + g_autoptr(GError) error = NULL; + FuPlugin *plugin = fu_plugin_list_find_by_name (self->plugin_list, + plugin_name, &error); + if (plugin == NULL) { + g_warning ("failed to find specified plugin %s: %s", + plugin_name, error->message); + return; + } + if (!fu_plugin_runner_usb_device_added (plugin, device, &error)) { + g_warning ("failed to add USB device %04x:%04x: %s", + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device), + error->message); + } + return; + } /* call into each plugin */ + g_debug ("no plugin specified for USB device %04x:%04x", + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device)); for (guint j = 0; j < plugins->len; j++) { FuPlugin *plugin_tmp = g_ptr_array_index (plugins, j); g_autoptr(GError) error = NULL; - if (!fu_plugin_runner_usb_device_added (plugin_tmp, usb_device, &error)) { + + /* skipping plugin as requires quirk */ + if (fu_plugin_has_rule (plugin_tmp, + FU_PLUGIN_RULE_REQUIRES_QUIRK, + FU_QUIRKS_PLUGIN)) { + continue; + } + + /* create a device, then probe */ + if (!fu_plugin_runner_usb_device_added (plugin_tmp, device, &error)) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { - g_debug ("ignoring: %s", error->message); + g_debug ("%s ignoring: %s", + fu_plugin_get_name (plugin_tmp), + error->message); continue; } - g_warning ("failed to add USB device: %s", error->message); + g_warning ("%s failed to add USB device %04x:%04x: %s", + fu_plugin_get_name (plugin_tmp), + g_usb_device_get_vid (usb_device), + g_usb_device_get_pid (usb_device), + error->message); } } } @@ -3342,12 +4279,7 @@ static void fu_engine_load_quirks (FuEngine *self) { - g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(GError) error = NULL; - - /* profile */ - ptask = as_profile_start_literal (self->profile, "FuEngine:load-quirks"); - g_assert (ptask != NULL); if (!fu_quirks_load (self->quirks, &error)) g_warning ("Failed to load quirks: %s", error->message); } @@ -3355,12 +4287,7 @@ static void fu_engine_load_smbios (FuEngine *self) { - g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(GError) error = NULL; - - /* profile */ - ptask = as_profile_start_literal (self->profile, "FuEngine:load-smbios"); - g_assert (ptask != NULL); if (!fu_smbios_setup (self->smbios, &error)) g_warning ("Failed to load SMBIOS: %s", error->message); } @@ -3368,12 +4295,7 @@ static void fu_engine_load_hwids (FuEngine *self) { - g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(GError) error = NULL; - - /* profile */ - ptask = as_profile_start_literal (self->profile, "FuEngine:load-hwids"); - g_assert (ptask != NULL); if (!fu_hwids_setup (self->hwids, self->smbios, &error)) g_warning ("Failed to load HWIDs: %s", error->message); } @@ -3381,10 +4303,10 @@ static gboolean fu_engine_update_history_device (FuEngine *self, FuDevice *dev_history, GError **error) { - FuDevice *dev; FuPlugin *plugin; FwupdRelease *rel_history; g_autofree gchar *btime = NULL; + g_autoptr(FuDevice) dev = NULL; /* is in the device list */ dev = fu_device_list_get_by_id (self->device_list, @@ -3414,11 +4336,22 @@ } /* the system is running with the new firmware version */ - if (g_strcmp0 (fu_device_get_version (dev), - fwupd_release_get_version (rel_history)) == 0) { + if (fu_common_vercmp (fu_device_get_version (dev), + fwupd_release_get_version (rel_history)) == 0) { + GPtrArray *checksums; g_debug ("installed version %s matching history %s", fu_device_get_version (dev), fwupd_release_get_version (rel_history)); + + /* copy over runtime checksums if set from probe() */ + checksums = fu_device_get_checksums (dev); + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + fu_device_add_checksum (dev_history, csum); + } + fu_device_set_version (dev_history, fu_device_get_version (dev), + fu_device_get_version_format (dev)); + fu_device_remove_flag (dev_history, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); fu_device_set_update_state (dev_history, FWUPD_UPDATE_STATE_SUCCESS); return fu_history_modify_device (self->history, dev_history, FU_HISTORY_FLAGS_MATCH_NEW_VERSION, @@ -3435,7 +4368,8 @@ return FALSE; /* the plugin either can't tell us the error, or doesn't know itself */ - if (fu_device_get_update_state (dev) != FWUPD_UPDATE_STATE_FAILED) { + if (fu_device_get_update_state (dev) != FWUPD_UPDATE_STATE_FAILED && + fu_device_get_update_state (dev) != FWUPD_UPDATE_STATE_FAILED_TRANSIENT) { g_debug ("falling back to generic failure"); fu_device_set_update_error (dev_history, "failed to run update on reboot"); } @@ -3471,9 +4405,56 @@ return TRUE; } +static void +fu_engine_udev_uevent_cb (GUdevClient *gudev_client, + const gchar *action, + GUdevDevice *udev_device, + FuEngine *self) +{ + if (g_strcmp0 (action, "add") == 0) { + fu_engine_udev_device_add (self, udev_device); + return; + } + if (g_strcmp0 (action, "remove") == 0) { + fu_engine_udev_device_remove (self, udev_device); + return; + } + if (g_strcmp0 (action, "change") == 0) { + fu_engine_udev_device_changed (self, udev_device); + return; + } +} + +static void +fu_engine_ensure_client_certificate (FuEngine *self) +{ + g_autoptr(FuKeyring) kr = NULL; + g_autoptr(GBytes) blob = g_bytes_new_static ("test\0", 5); + g_autoptr(GBytes) sig = NULL; + g_autoptr(GError) error = NULL; + + /* create keyring and sign dummy data to ensure certificate exists */ + kr = fu_keyring_create_for_kind (FWUPD_KEYRING_KIND_PKCS7, &error); + if (kr == NULL) { + g_message ("failed to create keyring: %s", error->message); + return; + } + if (!fu_keyring_setup (kr, &error)) { + g_message ("failed to setup keyring: %s", error->message); + return; + } + sig = fu_keyring_sign_data (kr, blob, FU_KEYRING_SIGN_FLAG_NONE, &error); + if (sig == NULL) { + g_message ("failed to sign using keyring: %s", error->message); + return; + } + g_debug ("client certificate exists and working"); +} + /** * fu_engine_load: * @self: A #FuEngine + * @flags: #FuEngineLoadFlags, e.g. %FU_ENGINE_LOAD_FLAG_READONLY_FS * @error: A #GError, or %NULL * * Load the firmware update engine so it is ready for use. @@ -3481,31 +4462,56 @@ * Returns: %TRUE for success **/ gboolean -fu_engine_load (FuEngine *self, GError **error) +fu_engine_load (FuEngine *self, FuEngineLoadFlags flags, GError **error) { - g_autoptr(AsProfileTask) ptask = NULL; - - /* profile */ - ptask = as_profile_start_literal (self->profile, "FuEngine:load"); - g_assert (ptask != NULL); + FuConfigLoadFlags config_flags = FU_CONFIG_LOAD_FLAG_NONE; + g_autoptr(GPtrArray) checksums = NULL; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* avoid re-loading a second time if fu-tool or fu-util request to */ + if (self->loaded) + return TRUE; + /* read config file */ - if (!fu_config_load (self->config, error)) { + if (flags & FU_ENGINE_LOAD_FLAG_READONLY_FS) + config_flags |= FU_CONFIG_LOAD_FLAG_READONLY_FS; + if (!fu_config_load (self->config, config_flags, error)) { g_prefix_error (error, "Failed to load config: "); return FALSE; } + /* create client certificate */ + fu_engine_ensure_client_certificate (self); + + /* get hardcoded approved firmware */ + checksums = fu_config_get_approved_firmware (self->config); + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + fu_engine_add_approved_firmware (self, csum); + } + + /* get extra firmware saved to the database */ + checksums = fu_history_get_approved_firmware (self->history, error); + if (checksums == NULL) + return FALSE; + for (guint i = 0; i < checksums->len; i++) { + const gchar *csum = g_ptr_array_index (checksums, i); + fu_engine_add_approved_firmware (self, csum); + } + + /* set up idle exit */ + if ((self->app_flags & FU_APP_FLAGS_NO_IDLE_SOURCES) == 0) + fu_idle_set_timeout (self->idle, fu_config_get_idle_timeout (self->config)); + /* load quirks, SMBIOS and the hwids */ fu_engine_load_smbios (self); fu_engine_load_hwids (self); fu_engine_load_quirks (self); /* load AppStream metadata */ - as_store_add_filter (self->store, AS_APP_KIND_FIRMWARE); - if (!fu_engine_load_metadata_store (self, error)) { + if (!fu_engine_load_metadata_store (self, flags, error)) { g_prefix_error (error, "Failed to load AppStream data: "); return FALSE; } @@ -3540,6 +4546,20 @@ G_CALLBACK (fu_engine_device_changed_cb), self); + /* udev watches can only be set up in _init() so set up client now */ + if (self->udev_subsystems->len > 0) { + g_auto(GStrv) udev_subsystems = g_new0 (gchar *, self->udev_subsystems->len + 1); + for (guint i = 0; i < self->udev_subsystems->len; i++) { + const gchar *subsystem = g_ptr_array_index (self->udev_subsystems, i); + udev_subsystems[i] = g_strdup (subsystem); + } + self->gudev_client = g_udev_client_new ((const gchar * const *) udev_subsystems); + g_signal_connect (self->gudev_client, "uevent", + G_CALLBACK (fu_engine_udev_uevent_cb), self); + } + + fu_engine_set_status (self, FWUPD_STATUS_LOADING); + /* add devices */ fu_engine_plugins_setup (self); fu_engine_plugins_coldplug (self, FALSE); @@ -3553,10 +4573,16 @@ self); g_usb_context_enumerate (self->usb_ctx); + /* coldplug udev devices */ + fu_engine_enumerate_udev (self); + /* update the db for devices that were updated during the reboot */ if (!fu_engine_update_history_database (self, error)) return FALSE; + fu_engine_set_status (self, FWUPD_STATUS_IDLE); + self->loaded = TRUE; + /* success */ return TRUE; } @@ -3599,6 +4625,31 @@ G_TYPE_NONE, 1, G_TYPE_UINT); } +void +fu_engine_add_runtime_version (FuEngine *self, + const gchar *component_id, + const gchar *version) +{ + g_hash_table_insert (self->runtime_versions, + g_strdup (component_id), + g_strdup (version)); +} + +void +fu_engine_add_app_flag (FuEngine *self, FuAppFlags app_flags) +{ + g_return_if_fail (FU_IS_ENGINE (self)); + self->app_flags |= app_flags; +} + +static void +fu_engine_idle_status_notify_cb (FuIdle *idle, GParamSpec *pspec, FuEngine *self) +{ + FwupdStatus status = fu_idle_get_status (idle); + if (status == FWUPD_STATUS_SHUTDOWN) + fu_engine_set_status (self, status); +} + static void fu_engine_init (FuEngine *self) { @@ -3608,12 +4659,40 @@ self->device_list = fu_device_list_new (); self->smbios = fu_smbios_new (); self->hwids = fu_hwids_new (); + self->idle = fu_idle_new (); self->quirks = fu_quirks_new (); self->history = fu_history_new (); self->plugin_list = fu_plugin_list_new (); - self->profile = as_profile_new (); - self->store = as_store_new (); - self->supported_guids = g_ptr_array_new_with_free_func (g_free); + self->plugin_filter = g_ptr_array_new_with_free_func (g_free); + self->udev_subsystems = g_ptr_array_new_with_free_func (g_free); + self->runtime_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + self->compile_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + self->approved_firmware = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + g_signal_connect (self->idle, "notify::status", + G_CALLBACK (fu_engine_idle_status_notify_cb), self); + + /* add some runtime versions of things the daemon depends on */ + fu_engine_add_runtime_version (self, "org.freedesktop.fwupd", VERSION); + fu_engine_add_runtime_version (self, "com.redhat.fwupdate", "12"); + fu_engine_add_runtime_version (self, "org.freedesktop.appstream-glib", "0.7.14"); +#if G_USB_CHECK_VERSION(0,3,1) + fu_engine_add_runtime_version (self, "org.freedesktop.gusb", g_usb_version_string ()); +#endif + + g_hash_table_insert (self->compile_versions, + g_strdup ("com.redhat.fwupdate"), + g_strdup ("12")); + g_hash_table_insert (self->compile_versions, + g_strdup ("org.freedesktop.fwupd"), + g_strdup (VERSION)); + g_hash_table_insert (self->compile_versions, + g_strdup ("org.freedesktop.gusb"), + g_strdup_printf ("%i.%i.%i", + G_USB_MAJOR_VERSION, + G_USB_MINOR_VERSION, + G_USB_MICRO_VERSION)); + } static void @@ -3623,27 +4702,35 @@ if (self->usb_ctx != NULL) g_object_unref (self->usb_ctx); + if (self->silo != NULL) + g_object_unref (self->silo); + if (self->gudev_client != NULL) + g_object_unref (self->gudev_client); if (self->coldplug_id != 0) g_source_remove (self->coldplug_id); + g_object_unref (self->idle); g_object_unref (self->config); g_object_unref (self->smbios); g_object_unref (self->quirks); g_object_unref (self->hwids); g_object_unref (self->history); - g_object_unref (self->plugin_list); - g_object_unref (self->profile); - g_object_unref (self->store); g_object_unref (self->device_list); - g_ptr_array_unref (self->supported_guids); + g_ptr_array_unref (self->plugin_filter); + g_ptr_array_unref (self->udev_subsystems); + g_hash_table_unref (self->runtime_versions); + g_hash_table_unref (self->compile_versions); + g_hash_table_unref (self->approved_firmware); + g_object_unref (self->plugin_list); G_OBJECT_CLASS (fu_engine_parent_class)->finalize (obj); } FuEngine * -fu_engine_new (void) +fu_engine_new (FuAppFlags app_flags) { FuEngine *self; self = g_object_new (FU_TYPE_ENGINE, NULL); + self->app_flags = app_flags; return FU_ENGINE (self); } diff -Nru fwupd-1.0.6/src/fu-engine.h fwupd-1.2.10/src/fu-engine.h --- fwupd-1.0.6/src/fu-engine.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-engine.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,60 +1,69 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_ENGINE_H -#define __FU_ENGINE_H - -G_BEGIN_DECLS +#pragma once -#include +#include #include #include "fwupd-device.h" #include "fwupd-enums.h" +#include "fu-common.h" +#include "fu-keyring.h" +#include "fu-install-task.h" #include "fu-plugin.h" +G_BEGIN_DECLS + #define FU_TYPE_ENGINE (fu_engine_get_type ()) G_DECLARE_FINAL_TYPE (FuEngine, fu_engine, FU, ENGINE, GObject) -FuEngine *fu_engine_new (void); +/** + * FuEngineLoadFlags: + * @FU_ENGINE_LOAD_FLAG_NONE: No flags set + * @FU_ENGINE_LOAD_FLAG_READONLY_FS: Ignore readonly filesystem errors + * + * The flags to use when loading the engine. + **/ +typedef enum { + FU_ENGINE_LOAD_FLAG_NONE = 0, + FU_ENGINE_LOAD_FLAG_READONLY_FS = 1 << 0, + /*< private >*/ + FU_ENGINE_LOAD_FLAG_LAST +} FuEngineLoadFlags; + +FuEngine *fu_engine_new (FuAppFlags app_flags); +void fu_engine_add_app_flag (FuEngine *self, + FuAppFlags app_flags); +void fu_engine_add_plugin_filter (FuEngine *self, + const gchar *plugin_glob); +void fu_engine_idle_reset (FuEngine *self); gboolean fu_engine_load (FuEngine *self, + FuEngineLoadFlags flags, GError **error); -FwupdStatus fu_engine_get_status (FuEngine *self); -void fu_engine_profile_dump (FuEngine *self); -gboolean fu_engine_check_plugins_pending (FuEngine *self, +gboolean fu_engine_load_plugins (FuEngine *self, GError **error); -AsStore *fu_engine_get_store_from_blob (FuEngine *self, +gboolean fu_engine_get_tainted (FuEngine *self); +FwupdStatus fu_engine_get_status (FuEngine *self); +XbSilo *fu_engine_get_silo_from_blob (FuEngine *self, GBytes *blob_cab, GError **error); -const gchar *fu_engine_get_action_id_for_device (FuEngine *self, - const gchar *device_id, - AsStore *store, - FwupdInstallFlags flags, - GError **error); guint64 fu_engine_get_archive_size_max (FuEngine *self); +GPtrArray *fu_engine_get_plugins (FuEngine *self); GPtrArray *fu_engine_get_devices (FuEngine *self, GError **error); +FuDevice *fu_engine_get_device (FuEngine *self, + const gchar *device_id, + GError **error); GPtrArray *fu_engine_get_history (FuEngine *self, GError **error); +FwupdRemote *fu_engine_get_remote_by_id (FuEngine *self, + const gchar *remote_id, + GError **error); GPtrArray *fu_engine_get_remotes (FuEngine *self, GError **error); GPtrArray *fu_engine_get_releases (FuEngine *self, @@ -96,23 +105,60 @@ const gchar *key, const gchar *value, GError **error); +gboolean fu_engine_composite_prepare (FuEngine *self, + GPtrArray *devices, + GError **error); +gboolean fu_engine_composite_cleanup (FuEngine *self, + GPtrArray *devices, + GError **error); gboolean fu_engine_install (FuEngine *self, - const gchar *device_id, - AsStore *store, + FuInstallTask *task, + GBytes *blob_cab, + FwupdInstallFlags flags, + GError **error); +gboolean fu_engine_install_blob (FuEngine *self, + FuDevice *device, + GBytes *blob_fw, + FwupdInstallFlags flags, + GError **error); +gboolean fu_engine_install_tasks (FuEngine *self, + GPtrArray *install_tasks, GBytes *blob_cab, FwupdInstallFlags flags, GError **error); GPtrArray *fu_engine_get_details (FuEngine *self, gint fd, GError **error); +gboolean fu_engine_activate (FuEngine *self, + const gchar *device_id, + GError **error); +GPtrArray *fu_engine_get_approved_firmware (FuEngine *self); +void fu_engine_add_approved_firmware (FuEngine *self, + const gchar *checksum); +gchar *fu_engine_self_sign (FuEngine *self, + const gchar *value, + FuKeyringSignFlags flags, + GError **error); +gboolean fu_engine_modify_config (FuEngine *self, + const gchar *key, + const gchar *value, + GError **error); /* for the self tests */ void fu_engine_add_device (FuEngine *self, FuDevice *device); void fu_engine_add_plugin (FuEngine *self, FuPlugin *plugin); +void fu_engine_add_runtime_version (FuEngine *self, + const gchar *component_id, + const gchar *version); +gboolean fu_engine_check_requirements (FuEngine *self, + FuInstallTask *task, + FwupdInstallFlags flags, + GError **error); +void fu_engine_set_silo (FuEngine *self, + XbSilo *silo); +XbNode *fu_engine_get_component_by_guids (FuEngine *self, + FuDevice *device); G_END_DECLS - -#endif /* __FU_ENGINE_H */ - diff -Nru fwupd-1.0.6/src/fu-hash.py fwupd-1.2.10/src/fu-hash.py --- fwupd-1.0.6/src/fu-hash.py 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-hash.py 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +""" Builds a header for the plugins to include """ + +# pylint: disable=invalid-name,wrong-import-position,pointless-string-statement + +""" +SPDX-License-Identifier: LGPL-2.1+ +""" + +import sys +import hashlib + +def usage(return_code): + """ print usage and exit with the supplied return code """ + if return_code == 0: + out = sys.stdout + else: + out = sys.stderr + out.write("usage: fu-hash.py
") + sys.exit(return_code) + +if __name__ == '__main__': + if {'-?', '--help', '--usage'}.intersection(set(sys.argv)): + usage(0) + if len(sys.argv) != 3: + usage(1) + with open(sys.argv[1], 'rb') as f: + buf = f.read() + csum = hashlib.sha256(buf).hexdigest() + with open(sys.argv[2], 'w') as f2: + f2.write('#pragma once\n') + f2.write('#define FU_BUILD_HASH "%s"\n' % csum) diff -Nru fwupd-1.0.6/src/fu-history.c fwupd-1.2.10/src/fu-history.c --- fwupd-1.0.6/src/fu-history.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-history.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,34 +1,26 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuHistory" + #include "config.h" #include #include +#include #include #include #include +#include "fu-common.h" #include "fu-device-private.h" #include "fu-history.h" +#include "fu-mutex.h" + +#define FU_HISTORY_CURRENT_SCHEMA_VERSION 5 static void fu_history_finalize (GObject *object); @@ -36,11 +28,15 @@ { GObject parent_instance; sqlite3 *db; + GRWLock db_mutex; }; G_DEFINE_TYPE (FuHistory, fu_history, G_TYPE_OBJECT) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(sqlite3_stmt, sqlite3_finalize); +#pragma clang diagnostic pop static FuDevice * fu_history_device_from_stmt (sqlite3_stmt *stmt) @@ -55,7 +51,6 @@ /* device_id */ tmp = (const gchar *) sqlite3_column_text (stmt, 0); - g_debug ("FuHistory: got sql result %s", tmp); if (tmp != NULL) fwupd_device_set_id (FWUPD_DEVICE (device), tmp); @@ -120,7 +115,17 @@ /* version_old */ tmp = (const gchar *) sqlite3_column_text (stmt, 13); if (tmp != NULL) - fu_device_set_version (device, tmp); + fu_device_set_version (device, tmp, FWUPD_VERSION_FORMAT_UNKNOWN); + + /* checksum_device */ + tmp = (const gchar *) sqlite3_column_text (stmt, 14); + if (tmp != NULL) + fu_device_add_checksum (device, tmp); + + /* protocol */ + tmp = (const gchar *) sqlite3_column_text (stmt, 15); + if (tmp != NULL) + fwupd_release_set_protocol (release, tmp); return device; } @@ -155,7 +160,7 @@ "CREATE TABLE schema (" "created timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP," "version INTEGER DEFAULT 0);" - "INSERT INTO schema (version) VALUES (2);" + "INSERT INTO schema (version) VALUES (0);" "CREATE TABLE history (" "device_id TEXT," "update_state INTEGER DEFAULT 0," @@ -170,11 +175,15 @@ "metadata TEXT DEFAULT NULL," "guid_default TEXT DEFAULT NULL," "version_old TEXT," - "version_new TEXT);" + "version_new TEXT," + "checksum_device TEXT DEFAULT NULL," + "protocol TEXT DEFAULT NULL);" + "CREATE TABLE approved_firmware (" + "checksum TEXT);" "COMMIT;", NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to create database: %s", + "Failed to prepare SQL for creating tables: %s", sqlite3_errmsg (self->db)); return FALSE; } @@ -191,7 +200,7 @@ "ALTER TABLE history RENAME TO history_old;", NULL, NULL, NULL); if (rc != SQLITE_OK) { - g_debug ("FuHistory: cannot rename v0 table: %s", sqlite3_errmsg (self->db)); + g_debug ("cannot rename v0 table: %s", sqlite3_errmsg (self->db)); return TRUE; } @@ -201,16 +210,64 @@ /* migrate the old entries to the new table */ rc = sqlite3_exec (self->db, - "INSERT INTO history SELECT * FROM history_old;" + "INSERT INTO history SELECT " + "device_id, update_state, update_error, filename, " + "display_name, plugin, device_created, device_modified, " + "checksum, flags, metadata, guid_default, version_old, " + "version_new, NULL, NULL FROM history_old;" "DROP TABLE history_old;", NULL, NULL, NULL); if (rc != SQLITE_OK) { - g_debug ("FuHistory: no history to migrate: %s", sqlite3_errmsg (self->db)); + g_debug ("no history to migrate: %s", sqlite3_errmsg (self->db)); return TRUE; } return TRUE; } +static gboolean +fu_history_migrate_database_v2 (FuHistory *self, GError **error) +{ + gint rc; + rc = sqlite3_exec (self->db, + "ALTER TABLE history ADD COLUMN checksum_device TEXT DEFAULT NULL;", + NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to alter database: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_history_migrate_database_v3 (FuHistory *self, GError **error) +{ + gint rc; + rc = sqlite3_exec (self->db, + "ALTER TABLE history ADD COLUMN protocol TEXT DEFAULT NULL;", + NULL, NULL, NULL); + if (rc != SQLITE_OK) + g_debug ("ignoring database error: %s", sqlite3_errmsg (self->db)); + return TRUE; +} + +static gboolean +fu_history_migrate_database_v4 (FuHistory *self, GError **error) +{ + gint rc; + rc = sqlite3_exec (self->db, + "CREATE TABLE approved_firmware (checksum TEXT);", + NULL, NULL, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to create table: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + /* returns 0 if database is not initialised */ static guint fu_history_get_schema_version (FuHistory *self) @@ -219,14 +276,15 @@ g_autoptr(sqlite3_stmt) stmt = NULL; rc = sqlite3_prepare_v2 (self->db, - "SELECT version FROM schema LIMIT 1;", -1, &stmt, NULL); + "SELECT version FROM schema LIMIT 1;", + -1, &stmt, NULL); if (rc != SQLITE_OK) { g_debug ("no schema version: %s", sqlite3_errmsg (self->db)); return 0; } rc = sqlite3_step (stmt); if (rc != SQLITE_ROW) { - g_warning ("failed to execute prepared statement: %s", + g_warning ("failed prepare to get schema version: %s", sqlite3_errmsg (self->db)); return 0; } @@ -234,6 +292,77 @@ } static gboolean +fu_history_create_or_migrate (FuHistory *self, guint schema_ver, GError **error) +{ + gint rc; + g_autoptr(sqlite3_stmt) stmt = NULL; + + /* create initial up-to-date database or migrate */ + if (schema_ver == 0) { + g_debug ("building initial database"); + if (!fu_history_create_database (self, error)) + return FALSE; + } else if (schema_ver == 1) { + g_debug ("migrating v%u database by recreating table", schema_ver); + if (!fu_history_migrate_database_v1 (self, error)) + return FALSE; + } else if (schema_ver == 2) { + g_debug ("migrating v%u database by altering", schema_ver); + if (!fu_history_migrate_database_v2 (self, error)) + return FALSE; + if (!fu_history_migrate_database_v3 (self, error)) + return FALSE; + if (!fu_history_migrate_database_v4 (self, error)) + return FALSE; + } else if (schema_ver == 3) { + g_debug ("migrating v%u database by altering", schema_ver); + if (!fu_history_migrate_database_v3 (self, error)) + return FALSE; + if (!fu_history_migrate_database_v4 (self, error)) + return FALSE; + } else if (schema_ver == 4) { + g_debug ("migrating v%u database by altering", schema_ver); + if (!fu_history_migrate_database_v4 (self, error)) + return FALSE; + } else { + /* this is probably okay, but return an error if we ever delete + * or rename columns */ + g_warning ("schema version %u is unknown", schema_ver); + return TRUE; + } + + /* set new schema version */ + rc = sqlite3_prepare_v2 (self->db, + "UPDATE schema SET version=?1;", + -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL for updating schema: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + sqlite3_bind_int (stmt, 1, FU_HISTORY_CURRENT_SCHEMA_VERSION); + return fu_history_stmt_exec (self, stmt, NULL, error); +} + +static gboolean +fu_history_open (FuHistory *self, const gchar *filename, GError **error) +{ + gint rc; + g_debug ("trying to open database '%s'", filename); + rc = sqlite3_open (filename, &self->db); + if (rc != SQLITE_OK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "Can't open %s: %s", + filename, sqlite3_errmsg (self->db)); + return FALSE; + } + return TRUE; +} + +static gboolean fu_history_load (FuHistory *self, GError **error) { gint rc; @@ -241,6 +370,7 @@ g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; g_autoptr(GFile) file = NULL; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&self->db_mutex); /* already done */ if (self->db != NULL) @@ -248,9 +378,10 @@ g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); g_return_val_if_fail (self->db == NULL, FALSE); + g_return_val_if_fail (locker != NULL, FALSE); /* create directory */ - dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); + dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); file = g_file_new_for_path (dirname); if (!g_file_query_exists (file, NULL)) { if (!g_file_make_directory_with_parents (file, NULL, error)) @@ -259,41 +390,44 @@ /* open */ filename = g_build_filename (dirname, "pending.db", NULL); - g_debug ("FuHistory: trying to open database '%s'", filename); - rc = sqlite3_open (filename, &self->db); - if (rc != SQLITE_OK) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_READ, - "Can't open %s: %s", - filename, sqlite3_errmsg (self->db)); - sqlite3_close (self->db); + if (!fu_history_open (self, filename, error)) return FALSE; - } /* check database */ schema_ver = fu_history_get_schema_version (self); if (schema_ver == 0) { - g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(sqlite3_stmt) stmt_tmp = NULL; rc = sqlite3_prepare_v2 (self->db, "SELECT * FROM history LIMIT 0;", - -1, &stmt, NULL); + -1, &stmt_tmp, NULL); if (rc == SQLITE_OK) schema_ver = 1; } - g_debug ("FuHistory: got schema version of %u", schema_ver); - /* migrate schema */ - if (schema_ver == 0) { - g_debug ("FuHistory: building initial database"); - if (!fu_history_create_database (self, error)) - return FALSE; - } else if (schema_ver == 1) { - g_debug ("FuHistory: migrating v%u database", schema_ver); - if (!fu_history_migrate_database_v1 (self, error)) - return FALSE; + /* create initial up-to-date database, or migrate */ + g_debug ("got schema version of %u", schema_ver); + if (schema_ver != FU_HISTORY_CURRENT_SCHEMA_VERSION) { + g_autoptr(GError) error_migrate = NULL; + if (!fu_history_create_or_migrate (self, schema_ver, &error_migrate)) { + /* this is fatal to the daemon, so delete the database + * and try again with something empty */ + g_warning ("failed to migrate %s database: %s", + filename, error_migrate->message); + sqlite3_close (self->db); + if (g_unlink (filename) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Can't delete %s", filename); + return FALSE; + } + if (!fu_history_open (self, filename, error)) + return FALSE; + return fu_history_create_database (self, error); + } } + /* success */ return TRUE; } @@ -329,6 +463,7 @@ { gint rc; g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); @@ -338,34 +473,44 @@ return FALSE; /* overwrite entry if it exists */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); if ((flags & FU_HISTORY_FLAGS_MATCH_OLD_VERSION) && (flags & FU_HISTORY_FLAGS_MATCH_NEW_VERSION)) { - g_debug ("FuHistory: modifying device %s, version not important", + g_debug ("modifying device %s [%s], version not important", + fu_device_get_name (device), fu_device_get_id (device)); rc = sqlite3_prepare_v2 (self->db, "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4;", -1, &stmt, NULL); } else if (flags & FU_HISTORY_FLAGS_MATCH_OLD_VERSION) { - g_debug ("FuHistory: modifying device %s, only version old %s", - fu_device_get_id (device), fu_device_get_version (device)); + g_debug ("modifying device %s [%s], only version old %s", + fu_device_get_name (device), + fu_device_get_id (device), + fu_device_get_version (device)); rc = sqlite3_prepare_v2 (self->db, "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4 AND version_old = ?5;", -1, &stmt, NULL); } else if (flags & FU_HISTORY_FLAGS_MATCH_NEW_VERSION) { - g_debug ("FuHistory: modifying device %s, only version new %s", - fu_device_get_id (device), fu_device_get_version (device)); + g_debug ("modifying device %s [%s], only version new %s", + fu_device_get_name (device), + fu_device_get_id (device), + fu_device_get_version (device)); rc = sqlite3_prepare_v2 (self->db, "UPDATE history SET " "update_state = ?1, " "update_error = ?2, " + "checksum_device = ?6, " "flags = ?3 " "WHERE device_id = ?4 AND version_new = ?5;", -1, &stmt, NULL); @@ -374,25 +519,30 @@ } if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to update history: %s", sqlite3_errmsg (self->db)); return FALSE; } + sqlite3_bind_int (stmt, 1, fu_device_get_update_state (device)); sqlite3_bind_text (stmt, 2, fu_device_get_update_error (device), -1, SQLITE_STATIC); sqlite3_bind_int64 (stmt, 3, fu_history_get_device_flags_filtered (device)); sqlite3_bind_text (stmt, 4, fu_device_get_id (device), -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 5, fu_device_get_version (device), -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 6, fwupd_checksum_get_by_kind (fu_device_get_checksums (device), + G_CHECKSUM_SHA1), -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } gboolean fu_history_add_device (FuHistory *self, FuDevice *device, FwupdRelease *release, GError **error) { + const gchar *checksum_device; const gchar *checksum = NULL; gint rc; g_autofree gchar *metadata = NULL; g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); @@ -406,16 +556,22 @@ if (!fu_history_remove_device (self, device, release, error)) return FALSE; - g_debug ("FuHistory: add device %s", fu_device_get_id (device)); + g_debug ("add device %s [%s]", + fu_device_get_name (device), + fu_device_get_id (device)); if (release != NULL) { GPtrArray *checksums = fwupd_release_get_checksums (release); checksum = fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1); } + checksum_device = fwupd_checksum_get_by_kind (fu_device_get_checksums (device), + G_CHECKSUM_SHA1); /* metadata is stored as a simple string */ metadata = _convert_hash_to_string (fwupd_release_get_metadata (release)); /* add */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); rc = sqlite3_prepare_v2 (self->db, "INSERT INTO history (device_id," "update_state," @@ -430,12 +586,14 @@ "device_created," "device_modified," "version_old," - "version_new) " + "version_new," + "checksum_device," + "protocol) " "VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10," - "?11,?12,?13,?14)", -1, &stmt, NULL); + "?11,?12,?13,?14,?15,?16)", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to insert history: %s", sqlite3_errmsg (self->db)); return FALSE; } @@ -453,6 +611,8 @@ sqlite3_bind_int64 (stmt, 12, fu_device_get_modified (device)); sqlite3_bind_text (stmt, 13, fu_device_get_version (device), -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 14, fwupd_release_get_version (release), -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 15, checksum_device, -1, SQLITE_STATIC); + sqlite3_bind_text (stmt, 16, fwupd_release_get_protocol (release), -1, SQLITE_STATIC); return fu_history_stmt_exec (self, stmt, NULL, error); } @@ -463,6 +623,7 @@ { gint rc; g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); @@ -471,14 +632,16 @@ return FALSE; /* remove entries */ - g_debug ("FuHistory: removing all devices with update_state %s", + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + g_debug ("removing all devices with update_state %s", fwupd_update_state_to_string (update_state)); rc = sqlite3_prepare_v2 (self->db, - "DELETE FROM history WHERE update_state = ?1)", + "DELETE FROM history WHERE update_state = ?1", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to delete history: %s", sqlite3_errmsg (self->db)); return FALSE; } @@ -491,6 +654,7 @@ { gint rc; g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); @@ -499,11 +663,13 @@ return FALSE; /* remove entries */ - g_debug ("FuHistory: removing all devices"); + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + g_debug ("removing all devices"); rc = sqlite3_prepare_v2 (self->db, "DELETE FROM history;", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to delete history: %s", sqlite3_errmsg (self->db)); return FALSE; } @@ -516,6 +682,7 @@ { gint rc; g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); g_return_val_if_fail (FU_IS_DEVICE (device), FALSE); @@ -525,7 +692,11 @@ if (!fu_history_load (self, error)) return FALSE; - g_debug ("FuHistory: remove device %s", fu_device_get_id (device)); + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + g_debug ("remove device %s [%s]", + fu_device_get_name (device), + fu_device_get_id (device)); rc = sqlite3_prepare_v2 (self->db, "DELETE FROM history WHERE device_id = ?1 " "AND version_old = ?2 " @@ -533,7 +704,7 @@ -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to delete history: %s", sqlite3_errmsg (self->db)); return FALSE; } @@ -549,16 +720,19 @@ gint rc; g_autoptr(GPtrArray) array_tmp = NULL; g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), NULL); - g_return_val_if_fail (device_id != NULL, FALSE); + g_return_val_if_fail (device_id != NULL, NULL); /* lazy load */ if (!fu_history_load (self, error)) return NULL; /* get all the devices */ - g_debug ("FuHistory: get device"); + locker = g_rw_lock_reader_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, NULL); + g_debug ("get device"); rc = sqlite3_prepare_v2 (self->db, "SELECT device_id, " "checksum, " @@ -573,18 +747,21 @@ "update_state, " "update_error, " "version_new, " - "version_old FROM history WHERE " - "device_id = ?1 LIMIT 1", -1, &stmt, NULL); + "version_old, " + "checksum_device, " + "protocol FROM history WHERE " + "device_id = ?1 ORDER BY device_created DESC " + "LIMIT 1", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to get history: %s", sqlite3_errmsg (self->db)); - return FALSE; + return NULL; } sqlite3_bind_text (stmt, 1, device_id, -1, SQLITE_STATIC); array_tmp = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); if (!fu_history_stmt_exec (self, stmt, array_tmp, error)) - return FALSE; + return NULL; if (array_tmp->len == 0) { g_set_error_literal (error, FWUPD_ERROR, @@ -602,6 +779,7 @@ g_autoptr(sqlite3_stmt) stmt = NULL; gint rc; g_autoptr(GPtrArray) array_tmp = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; g_return_val_if_fail (FU_IS_HISTORY (self), NULL); @@ -612,7 +790,8 @@ } /* get all the devices */ - g_debug ("FuHistory: get devices"); + locker = g_rw_lock_reader_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, NULL); rc = sqlite3_prepare_v2 (self->db, "SELECT device_id, " "checksum, " @@ -627,22 +806,126 @@ "update_state, " "update_error, " "version_new, " - "version_old FROM history " + "version_old, " + "checksum_device, " + "protocol FROM history " "ORDER BY device_modified ASC;", -1, &stmt, NULL); if (rc != SQLITE_OK) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, - "Failed to prepare SQL: %s", + "Failed to prepare SQL to get history: %s", sqlite3_errmsg (self->db)); - return FALSE; + return NULL; } array_tmp = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); if (!fu_history_stmt_exec (self, stmt, array_tmp, error)) - return FALSE; + return NULL; array = g_ptr_array_ref (array_tmp); return array; } +GPtrArray * +fu_history_get_approved_firmware (FuHistory *self, GError **error) +{ + gint rc; + g_autoptr(GRWLockReaderLocker) locker = NULL; + g_autoptr(GPtrArray) array = NULL; + g_autoptr(sqlite3_stmt) stmt = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), NULL); + + /* lazy load */ + if (self->db == NULL) { + if (!fu_history_load (self, error)) + return NULL; + } + + /* get all the approved firmware */ + locker = g_rw_lock_reader_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, NULL); + rc = sqlite3_prepare_v2 (self->db, + "SELECT checksum FROM approved_firmware;", + -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL to get checksum: %s", + sqlite3_errmsg (self->db)); + return NULL; + } + array = g_ptr_array_new_with_free_func (g_free); + while ((rc = sqlite3_step (stmt)) == SQLITE_ROW) { + const gchar *tmp = (const gchar *) sqlite3_column_text (stmt, 0); + g_ptr_array_add (array, g_strdup (tmp)); + } + if (rc != SQLITE_DONE) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, + "failed to execute prepared statement: %s", + sqlite3_errmsg (self->db)); + return NULL; + } + return g_steal_pointer (&array); +} + +gboolean +fu_history_clear_approved_firmware (FuHistory *self, GError **error) +{ + gint rc; + g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); + + /* lazy load */ + if (!fu_history_load (self, error)) + return FALSE; + + /* remove entries */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + rc = sqlite3_prepare_v2 (self->db, + "DELETE FROM approved_firmware;", + -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL to delete approved firmware: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + return fu_history_stmt_exec (self, stmt, NULL, error); +} + +gboolean +fu_history_add_approved_firmware (FuHistory *self, + const gchar *checksum, + GError **error) +{ + gint rc; + g_autoptr(sqlite3_stmt) stmt = NULL; + g_autoptr(GRWLockReaderLocker) locker = NULL; + + g_return_val_if_fail (FU_IS_HISTORY (self), FALSE); + g_return_val_if_fail (checksum != NULL, FALSE); + + /* lazy load */ + if (!fu_history_load (self, error)) + return FALSE; + + /* add */ + locker = g_rw_lock_writer_locker_new (&self->db_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + rc = sqlite3_prepare_v2 (self->db, + "INSERT INTO approved_firmware (checksum) " + "VALUES (?1)", -1, &stmt, NULL); + if (rc != SQLITE_OK) { + g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, + "Failed to prepare SQL to insert checksum: %s", + sqlite3_errmsg (self->db)); + return FALSE; + } + sqlite3_bind_text (stmt, 1, checksum, -1, SQLITE_STATIC); + return fu_history_stmt_exec (self, stmt, NULL, error); +} + static void fu_history_class_init (FuHistoryClass *klass) { @@ -653,6 +936,7 @@ static void fu_history_init (FuHistory *self) { + g_rw_lock_init (&self->db_mutex); } static void @@ -662,6 +946,7 @@ if (self->db != NULL) sqlite3_close (self->db); + g_rw_lock_clear (&self->db_mutex); G_OBJECT_CLASS (fu_history_parent_class)->finalize (object); } diff -Nru fwupd-1.0.6/src/fu-history.h fwupd-1.2.10/src/fu-history.h --- fwupd-1.0.6/src/fu-history.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-history.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_HISTORY_H -#define __FU_HISTORY_H +#pragma once #include @@ -31,10 +15,19 @@ #define FU_TYPE_PENDING (fu_history_get_type ()) G_DECLARE_FINAL_TYPE (FuHistory, fu_history, FU, HISTORY, GObject) +/** + * FuHistoryFlags: + * @FU_HISTORY_FLAGS_NONE: No flags set + * @FU_HISTORY_FLAGS_MATCH_OLD_VERSION: Match previous firmware version + * @FU_HISTORY_FLAGS_MATCH_NEW_VERSION: Match new firmware version + * + * The flags to use when matching devices against the history database. + **/ typedef enum { FU_HISTORY_FLAGS_NONE = 0, FU_HISTORY_FLAGS_MATCH_OLD_VERSION = 1 << 0, FU_HISTORY_FLAGS_MATCH_NEW_VERSION = 1 << 1, + /*< private >*/ FU_HISTORY_FLAGS_LAST } FuHistoryFlags; @@ -63,7 +56,12 @@ GPtrArray *fu_history_get_devices (FuHistory *self, GError **error); -G_END_DECLS - -#endif /* __FU_HISTORY_H */ +gboolean fu_history_clear_approved_firmware (FuHistory *self, + GError **error); +gboolean fu_history_add_approved_firmware (FuHistory *self, + const gchar *checksum, + GError **error); +GPtrArray *fu_history_get_approved_firmware (FuHistory *self, + GError **error); +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-hwids.c fwupd-1.2.10/src/fu-hwids.c --- fwupd-1.0.6/src/fu-hwids.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-hwids.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,32 +1,20 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuHwids" + #include "config.h" #include #include #include -#include +#include "fu-common.h" #include "fu-hwids.h" +#include "fwupd-common.h" #include "fwupd-error.h" struct _FuHwids { @@ -34,6 +22,7 @@ GHashTable *hash_dmi_hw; /* BiosVersion->"1.2.3 " */ GHashTable *hash_dmi_display; /* BiosVersion->"1.2.3" */ GHashTable *hash_guid; /* a-c-b-d->1 */ + GPtrArray *array_guids; /* a-c-b-d */ }; G_DEFINE_TYPE (FuHwids, fu_hwids, G_TYPE_OBJECT) @@ -69,10 +58,23 @@ return g_hash_table_lookup (self->hash_guid, guid) != NULL; } +/** + * fu_hwids_get_guids: + * @self: A #FuHwids + * + * Returns all the defined HWIDs + * + * Returns: (transfer none) (element-type utf-8): An array of GUIDs + **/ +GPtrArray * +fu_hwids_get_guids (FuHwids *self) +{ + return self->array_guids; +} + static gchar * fu_hwids_get_guid_for_str (const gchar *str, GError **error) { - const gchar *namespace_id = "70ffd812-4c7f-4c7d-0000-000000000000"; glong items_written = 0; g_autofree gunichar2 *data = NULL; @@ -81,15 +83,21 @@ if (data == NULL) return NULL; + if (items_written == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no GUIDs in data"); + return NULL; + } + /* ensure the data is in little endian format */ for (glong i = 0; i < items_written; i++) data[i] = GUINT16_TO_LE(data[i]); /* convert to a GUID */ - return as_utils_guid_from_data (namespace_id, - (guint8*) data, - items_written * 2, - error); + return fwupd_guid_hash_data ((guint8*) data, items_written * 2, + FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT); } /** @@ -251,11 +259,12 @@ tmp = fu_smbios_get_string (smbios, type, offset, error); if (tmp == NULL) return NULL; - return g_strdup (tmp); + /* ComputerHardwareIds.exe seems to strip spaces */ + return fu_common_strstrip (tmp); } static gchar * -fu_hwids_convert_base10_integer_cb (FuSmbios *smbios, +fu_hwids_convert_padded_integer_cb (FuSmbios *smbios, guint8 type, guint8 offset, GError **error) { @@ -273,7 +282,29 @@ "offset bigger than data"); return NULL; } - return g_strdup_printf ("%u", data_raw[offset]); + return g_strdup_printf ("%02x", data_raw[offset]); +} + +static gchar * +fu_hwids_convert_integer_cb (FuSmbios *smbios, + guint8 type, guint8 offset, + GError **error) +{ + GBytes *data; + const guint8 *data_raw; + gsize data_sz = 0; + data = fu_smbios_get_data (smbios, type, error); + if (data == NULL) + return NULL; + data_raw = g_bytes_get_data (data, &data_sz); + if (offset >= data_sz) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "offset bigger than data"); + return NULL; + } + return g_strdup_printf ("%x", data_raw[offset]); } /** @@ -298,7 +329,7 @@ { FU_HWIDS_KEY_MANUFACTURER, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x04, fu_hwids_convert_string_table_cb }, { FU_HWIDS_KEY_ENCLOSURE_KIND, FU_SMBIOS_STRUCTURE_TYPE_CHASSIS, 0x05, - fu_hwids_convert_base10_integer_cb }, + fu_hwids_convert_integer_cb }, { FU_HWIDS_KEY_FAMILY, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x1a, fu_hwids_convert_string_table_cb }, { FU_HWIDS_KEY_PRODUCT_NAME, FU_SMBIOS_STRUCTURE_TYPE_SYSTEM, 0x05, @@ -310,9 +341,9 @@ { FU_HWIDS_KEY_BIOS_VERSION, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x05, fu_hwids_convert_string_table_cb }, { FU_HWIDS_KEY_BIOS_MAJOR_RELEASE, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x14, - fu_hwids_convert_base10_integer_cb }, + fu_hwids_convert_padded_integer_cb }, { FU_HWIDS_KEY_BIOS_MINOR_RELEASE, FU_SMBIOS_STRUCTURE_TYPE_BIOS, 0x15, - fu_hwids_convert_base10_integer_cb }, + fu_hwids_convert_padded_integer_cb }, { FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x04, fu_hwids_convert_string_table_cb }, { FU_HWIDS_KEY_BASEBOARD_PRODUCT, FU_SMBIOS_STRUCTURE_TYPE_BASEBOARD, 0x05, @@ -340,7 +371,8 @@ /* weirdly, remove leading zeros */ contents_hdr = contents; - while (contents_hdr[0] == '0') + while (contents_hdr[0] == '0' && + map[i].func != fu_hwids_convert_padded_integer_cb) contents_hdr++; g_hash_table_insert (self->hash_dmi_hw, g_strdup (map[i].key), @@ -359,7 +391,6 @@ for (guint i = 0; i < 15; i++) { g_autofree gchar *guid = NULL; g_autofree gchar *key = NULL; - g_autofree gchar *values = NULL; g_autoptr(GError) error_local = NULL; /* get the GUID and add to hash */ @@ -372,10 +403,7 @@ g_hash_table_insert (self->hash_guid, g_strdup (guid), GUINT_TO_POINTER (1)); - - /* show what makes up the GUID */ - values = fu_hwids_get_replace_values (self, key, NULL); - g_debug ("{%s} <- %s", guid, values); + g_ptr_array_add (self->array_guids, g_steal_pointer (&guid)); } return TRUE; @@ -391,6 +419,8 @@ g_hash_table_unref (self->hash_dmi_hw); g_hash_table_unref (self->hash_dmi_display); g_hash_table_unref (self->hash_guid); + g_ptr_array_unref (self->array_guids); + G_OBJECT_CLASS (fu_hwids_parent_class)->finalize (object); } @@ -407,6 +437,7 @@ self->hash_dmi_hw = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->hash_dmi_display = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); self->hash_guid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + self->array_guids = g_ptr_array_new_with_free_func (g_free); } FuHwids * diff -Nru fwupd-1.0.6/src/fu-hwids.h fwupd-1.2.10/src/fu-hwids.h --- fwupd-1.0.6/src/fu-hwids.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-hwids.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_HWIDS_H -#define __FU_HWIDS_H +#pragma once #include @@ -56,6 +40,7 @@ gchar *fu_hwids_get_guid (FuHwids *self, const gchar *keys, GError **error); +GPtrArray *fu_hwids_get_guids (FuHwids *self); gboolean fu_hwids_has_guid (FuHwids *self, const gchar *guid); gboolean fu_hwids_setup (FuHwids *self, @@ -63,5 +48,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_HWIDS_H */ diff -Nru fwupd-1.0.6/src/fu-idle.c fwupd-1.2.10/src/fu-idle.c --- fwupd-1.0.6/src/fu-idle.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-idle.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuIdle" + +#include "config.h" + +#include + +#include "fu-idle.h" +#include "fu-mutex.h" + +static void fu_idle_finalize (GObject *obj); + +struct _FuIdle +{ + GObject parent_instance; + GPtrArray *items; /* of FuIdleItem */ + GRWLock items_mutex; + guint idle_id; + guint timeout; + FwupdStatus status; +}; + +enum { + PROP_0, + PROP_STATUS, + PROP_LAST +}; + +static void +fu_idle_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + FuIdle *self = FU_IDLE (object); + switch (prop_id) { + case PROP_STATUS: + g_value_set_uint (value, self->status); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_idle_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +typedef struct { + gchar *reason; + guint32 token; +} FuIdleItem; + +G_DEFINE_TYPE (FuIdle, fu_idle, G_TYPE_OBJECT) + +FwupdStatus +fu_idle_get_status (FuIdle *self) +{ + g_return_val_if_fail (FU_IS_IDLE (self), FWUPD_STATUS_UNKNOWN); + return self->status; +} + +static void +fu_idle_set_status (FuIdle *self, FwupdStatus status) +{ + if (self->status == status) + return; + self->status = status; + g_debug ("status now %s", fwupd_status_to_string (status)); + g_object_notify (G_OBJECT (self), "status"); +} + +static gboolean +fu_idle_check_cb (gpointer user_data) +{ + FuIdle *self = FU_IDLE (user_data); + fu_idle_set_status (self, FWUPD_STATUS_SHUTDOWN); + return G_SOURCE_CONTINUE; +} + +static void +fu_idle_start (FuIdle *self) +{ + if (self->idle_id != 0) + return; + if (self->timeout == 0) + return; + self->idle_id = g_timeout_add_seconds (self->timeout, fu_idle_check_cb, self); +} + +static void +fu_idle_stop (FuIdle *self) +{ + if (self->idle_id == 0) + return; + g_source_remove (self->idle_id); + self->idle_id = 0; +} + +void +fu_idle_reset (FuIdle *self) +{ + g_return_if_fail (FU_IS_IDLE (self)); + fu_idle_stop (self); + if (self->items->len == 0) + fu_idle_start (self); +} + +void +fu_idle_uninhibit (FuIdle *self, guint32 token) +{ + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&self->items_mutex); + + g_return_if_fail (FU_IS_IDLE (self)); + g_return_if_fail (token != 0); + g_return_if_fail (locker != NULL); + + for (guint i = 0; i < self->items->len; i++) { + FuIdleItem *item = g_ptr_array_index (self->items, i); + if (item->token == token) { + g_debug ("uninhibiting: %s", item->reason); + g_ptr_array_remove_index (self->items, i); + break; + } + } + fu_idle_reset (self); +} + +guint32 +fu_idle_inhibit (FuIdle *self, const gchar *reason) +{ + FuIdleItem *item; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&self->items_mutex); + + g_return_val_if_fail (FU_IS_IDLE (self), 0); + g_return_val_if_fail (reason != NULL, 0); + g_return_val_if_fail (locker != NULL, 0); + + g_debug ("inhibiting: %s", reason); + item = g_new0 (FuIdleItem, 1); + item->reason = g_strdup (reason); + item->token = g_random_int_range (1, G_MAXINT); + g_ptr_array_add (self->items, item); + fu_idle_reset (self); + return item->token; +} + +void +fu_idle_set_timeout (FuIdle *self, guint timeout) +{ + g_return_if_fail (FU_IS_IDLE (self)); + g_debug ("setting timeout to %us", timeout); + self->timeout = timeout; + fu_idle_reset (self); +} + +static void +fu_idle_item_free (FuIdleItem *item) +{ + g_free (item->reason); + g_free (item); +} + +FuIdleLocker * +fu_idle_locker_new (FuIdle *self, const gchar *reason) +{ + FuIdleLocker *locker = g_new0 (FuIdleLocker, 1); + locker->idle = g_object_ref (self); + locker->token = fu_idle_inhibit (self, reason); + return locker; +} + +void +fu_idle_locker_free (FuIdleLocker *locker) +{ + if (locker == NULL) + return; + fu_idle_uninhibit (locker->idle, locker->token); + g_object_unref (locker->idle); + g_free (locker); +} + +static void +fu_idle_class_init (FuIdleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fu_idle_finalize; + object_class->get_property = fu_idle_get_property; + object_class->set_property = fu_idle_set_property; + + pspec = g_param_spec_uint ("status", NULL, NULL, + FWUPD_STATUS_UNKNOWN, + FWUPD_STATUS_LAST, + FWUPD_STATUS_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_STATUS, pspec); +} + +static void +fu_idle_init (FuIdle *self) +{ + self->status = FWUPD_STATUS_IDLE; + self->items = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_idle_item_free); + g_rw_lock_init (&self->items_mutex); +} + +static void +fu_idle_finalize (GObject *obj) +{ + FuIdle *self = FU_IDLE (obj); + + fu_idle_stop (self); + g_ptr_array_unref (self->items); + g_rw_lock_clear (&self->items_mutex); + + G_OBJECT_CLASS (fu_idle_parent_class)->finalize (obj); +} + +FuIdle * +fu_idle_new (void) +{ + FuIdle *self; + self = g_object_new (FU_TYPE_IDLE, NULL); + return FU_IDLE (self); +} diff -Nru fwupd-1.0.6/src/fu-idle.h fwupd-1.2.10/src/fu-idle.h --- fwupd-1.0.6/src/fu-idle.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-idle.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_IDLE (fu_idle_get_type ()) +G_DECLARE_FINAL_TYPE (FuIdle, fu_idle, FU, IDLE, GObject) + +FuIdle *fu_idle_new (void); +guint32 fu_idle_inhibit (FuIdle *self, + const gchar *reason); +void fu_idle_uninhibit (FuIdle *self, + guint32 token); +void fu_idle_set_timeout (FuIdle *self, + guint timeout); +void fu_idle_reset (FuIdle *self); +FwupdStatus fu_idle_get_status (FuIdle *self); + +/** + * FuIdleLocker: + * @idle: A #FuIdle + * @token: A #guint32 number + * + * A locker to prevent daemon from shutting down on its own + **/ +typedef struct { + FuIdle *idle; + guint32 token; +} FuIdleLocker; + +FuIdleLocker *fu_idle_locker_new (FuIdle *self, + const gchar *reason); +void fu_idle_locker_free (FuIdleLocker *locker); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuIdleLocker, fu_idle_locker_free) + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-install-task.c fwupd-1.2.10/src/fu-install-task.c --- fwupd-1.0.6/src/fu-install-task.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-install-task.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuInstallTask" + +#include "config.h" + +#include + +#include "fu-common-version.h" +#include "fu-device-private.h" +#include "fu-install-task.h" +#include "fu-keyring-utils.h" + +struct _FuInstallTask +{ + GObject parent_instance; + FuDevice *device; + XbNode *component; + FwupdReleaseFlags trust_flags; + gboolean is_downgrade; +}; + +G_DEFINE_TYPE (FuInstallTask, fu_install_task, G_TYPE_OBJECT) + +/** + * fu_install_task_get_device: + * @self: A #FuInstallTask + * + * Gets the device for this task. + * + * Returns: (transfer none): the device + **/ +FuDevice * +fu_install_task_get_device (FuInstallTask *self) +{ + g_return_val_if_fail (FU_IS_INSTALL_TASK (self), NULL); + return self->device; +} + +/** + * fu_install_task_get_component: + * @self: A #FuInstallTask + * + * Gets the component for this task. + * + * Returns: (transfer none): the component + **/ +XbNode * +fu_install_task_get_component (FuInstallTask *self) +{ + g_return_val_if_fail (FU_IS_INSTALL_TASK (self), NULL); + return self->component; +} + +/** + * fu_install_task_get_trust_flags: + * @self: A #FuInstallTask + * + * Gets the trust flags for this task. + * + * NOTE: This is only set after fu_install_task_check_requirements() has been + * called successfully. + * + * Returns: the #FwupdReleaseFlags, e.g. #FWUPD_TRUST_FLAG_PAYLOAD + **/ +FwupdReleaseFlags +fu_install_task_get_trust_flags (FuInstallTask *self) +{ + g_return_val_if_fail (FU_IS_INSTALL_TASK (self), FALSE); + return self->trust_flags; +} + +/** + * fu_install_task_get_is_downgrade: + * @self: A #FuInstallTask + * + * Gets if this task is to downgrade firmware. + * + * NOTE: This is only set after fu_install_task_check_requirements() has been + * called successfully. + * + * Returns: %TRUE if versions numbers are going backwards + **/ +gboolean +fu_install_task_get_is_downgrade (FuInstallTask *self) +{ + g_return_val_if_fail (FU_IS_INSTALL_TASK (self), FALSE); + return self->is_downgrade; +} + +/** + * fu_install_task_check_requirements: + * @self: A #FuInstallTask + * @flags: A #FwupdInstallFlags, e.g. #FWUPD_INSTALL_FLAG_ALLOW_OLDER + * @error: A #GError, or %NULL + * + * Checks any requirements of this task. This will typically involve checking + * that the device can accept the component (the GUIDs match) and that the + * device can be upgraded with this firmware version. + * + * Returns: %TRUE if the requirements passed + **/ +gboolean +fu_install_task_check_requirements (FuInstallTask *self, + FwupdInstallFlags flags, + GError **error) +{ + const gchar *tmp; + const gchar *version; + const gchar *version_release; + const gchar *version_lowest; + gboolean matches_guid = FALSE; + gint vercmp; + g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) provides = NULL; + g_autoptr(XbNode) release = NULL; + + g_return_val_if_fail (FU_IS_INSTALL_TASK (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* does this component provide a GUID the device has */ + provides = xb_node_query (self->component, + "provides/firmware[@type='flashed']", + 0, &error_local); + if (provides == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No supported devices found: %s", + error_local->message); + return FALSE; + } + for (guint i = 0; i < provides->len; i++) { + XbNode *provide = g_ptr_array_index (provides, i); + if (fu_device_has_guid (self->device, xb_node_get_text (provide))) { + matches_guid = TRUE; + break; + } + } + if (!matches_guid) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "No supported devices found"); + return FALSE; + } + + /* check the device is not locked */ + if (fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_LOCKED)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s [%s] is locked", + fu_device_get_name (self->device), + fu_device_get_id (self->device)); + return FALSE; + } + + /* no update abilities */ + if (!fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_UPDATABLE)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s [%s] does not currently allow updates", + fu_device_get_name (self->device), + fu_device_get_id (self->device)); + return FALSE; + } + + /* called with online update, test if device is supposed to allow this */ + if ((flags & FWUPD_INSTALL_FLAG_OFFLINE) == 0 && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && + fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s [%s] only allows offline updates", + fu_device_get_name (self->device), + fu_device_get_id (self->device)); + return FALSE; + } + + /* get device */ + version = fu_device_get_version (self->device); + if (version == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "Device %s [%s] has no firmware version", + fu_device_get_name (self->device), + fu_device_get_id (self->device)); + return FALSE; + } + + /* get latest release */ + release = xb_node_query_first (self->component, "releases/release", NULL); + if (release == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "%s [%s] has no firmware update metadata", + fu_device_get_name (self->device), + fu_device_get_id (self->device)); + return FALSE; + } + + /* is this a downgrade or re-install */ + version_release = xb_node_get_attr (release, "version"); + if (version_release == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Release has no firmware version"); + return FALSE; + } + + /* check the version formats match if set in the release */ + tmp = xb_node_query_text (self->component, "custom/value[@key='LVFS::VersionFormat']", NULL); + if (tmp != NULL) { + FwupdVersionFormat fmt_dev = fu_device_get_version_format (self->device); + FwupdVersionFormat fmt_rel = fwupd_version_format_from_string (tmp); + if (fmt_rel == FWUPD_VERSION_FORMAT_UNKNOWN && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "release version format '%s' unsupported", + tmp); + return FALSE; + } + if (fmt_dev == FWUPD_VERSION_FORMAT_UNKNOWN && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "release version format '%s' but no device version format", + tmp); + return FALSE; + } + if (fmt_dev != fmt_rel) { + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Firmware version formats were different, " + "device was '%s' and release is '%s'", + fwupd_version_format_to_string (fmt_dev), + fwupd_version_format_to_string (fmt_rel)); + return FALSE; + } + g_warning ("ignoring version format difference %s:%s", + fwupd_version_format_to_string (fmt_dev), + fwupd_version_format_to_string (fmt_rel)); + } + } + + + /* compare to the lowest supported version, if it exists */ + version_lowest = fu_device_get_version_lowest (self->device); + if (version_lowest != NULL && + fu_common_vercmp (version_lowest, version) > 0 && + (flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_VERSION_NEWER, + "Specified firmware is older than the minimum " + "required version '%s < %s'", version, version_lowest); + return FALSE; + } + + /* check semver */ + vercmp = fu_common_vercmp (version, version_release); + if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_VERSION_SAME, + "Specified firmware is already installed '%s'", + version_release); + return FALSE; + } + self->is_downgrade = vercmp > 0; + if (self->is_downgrade && (flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_VERSION_NEWER, + "Specified firmware is older than installed '%s < %s'", + version_release, version); + return FALSE; + } + + /* verify */ + if (!fu_keyring_get_release_flags (release, &self->trust_flags, &error_local)) { + if (g_error_matches (error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_warning ("Ignoring verification for %s: %s", + fu_device_get_name (self->device), + error_local->message); + } else { + g_propagate_error (error, g_steal_pointer (&error_local)); + return FALSE; + } + } + return TRUE; +} + +/** + * fu_install_task_get_action_id: + * @self: A #FuEngine + * + * Gets the PolicyKit action ID to use for the install operation. + * + * Returns: string, e.g. `org.freedesktop.fwupd.update-internal-trusted` + **/ +const gchar * +fu_install_task_get_action_id (FuInstallTask *self) +{ + /* relax authentication checks for removable devices */ + if (!fu_device_has_flag (self->device, FWUPD_DEVICE_FLAG_INTERNAL)) { + if (self->is_downgrade) + return "org.freedesktop.fwupd.downgrade-hotplug"; + if (self->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD) + return "org.freedesktop.fwupd.update-hotplug-trusted"; + return "org.freedesktop.fwupd.update-hotplug"; + } + + /* internal device */ + if (self->is_downgrade) + return "org.freedesktop.fwupd.downgrade-internal"; + if (self->trust_flags & FWUPD_TRUST_FLAG_PAYLOAD) + return "org.freedesktop.fwupd.update-internal-trusted"; + return "org.freedesktop.fwupd.update-internal"; +} + +static void +fu_install_task_init (FuInstallTask *self) +{ + self->trust_flags = FWUPD_TRUST_FLAG_NONE; +} + +static void +fu_install_task_finalize (GObject *object) +{ + FuInstallTask *self = FU_INSTALL_TASK (object); + + g_object_unref (self->component); + if (self->device != NULL) + g_object_unref (self->device); + + G_OBJECT_CLASS (fu_install_task_parent_class)->finalize (object); +} + +static void +fu_install_task_class_init (FuInstallTaskClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_install_task_finalize; +} + +/** + * fu_install_task_compare: + * @task1: first #FuInstallTask to compare. + * @task2: second #FuInstallTask to compare. + * + * Compares two install tasks. + * + * Returns: 1, 0 or -1 if @task1 is greater, equal, or less than @task2, respectively. + **/ +gint +fu_install_task_compare (FuInstallTask *task1, FuInstallTask *task2) +{ + FuDevice *device1 = fu_install_task_get_device (task1); + FuDevice *device2 = fu_install_task_get_device (task2); + if (fu_device_get_order (device1) < fu_device_get_order (device2)) + return -1; + if (fu_device_get_order (device1) > fu_device_get_order (device2)) + return 1; + return 0; +} + +/** + * fu_install_task_new: + * @device: A #FuDevice + * @component: a #XbNode + * + * Creates a new install task that may or may not be valid. + * + * Returns: (transfer full): the #FuInstallTask + **/ +FuInstallTask * +fu_install_task_new (FuDevice *device, XbNode *component) +{ + FuInstallTask *self; + self = g_object_new (FU_TYPE_TASK, NULL); + self->component = g_object_ref (component); + if (device != NULL) + self->device = g_object_ref (device); + return FU_INSTALL_TASK (self); +} diff -Nru fwupd-1.0.6/src/fu-install-task.h fwupd-1.2.10/src/fu-install-task.h --- fwupd-1.0.6/src/fu-install-task.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-install-task.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-device.h" + +G_BEGIN_DECLS + +#define FU_TYPE_TASK (fu_install_task_get_type ()) +G_DECLARE_FINAL_TYPE (FuInstallTask, fu_install_task, FU, INSTALL_TASK, GObject) + +FuInstallTask *fu_install_task_new (FuDevice *device, + XbNode *component); +FuDevice *fu_install_task_get_device (FuInstallTask *self); +XbNode *fu_install_task_get_component (FuInstallTask *self); +FwupdReleaseFlags fu_install_task_get_trust_flags (FuInstallTask *self); +gboolean fu_install_task_get_is_downgrade (FuInstallTask *self); +gboolean fu_install_task_check_requirements (FuInstallTask *self, + FwupdInstallFlags flags, + GError **error); +const gchar *fu_install_task_get_action_id (FuInstallTask *self); +gint fu_install_task_compare (FuInstallTask *task1, + FuInstallTask *task2); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-io-channel.c fwupd-1.2.10/src/fu-io-channel.c --- fwupd-1.0.6/src/fu-io-channel.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-io-channel.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuIOChannel" + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "fwupd-error.h" +#include "fu-common.h" +#include "fu-io-channel.h" + +struct _FuIOChannel { + GObject parent_instance; + gint fd; +}; + +G_DEFINE_TYPE (FuIOChannel, fu_io_channel, G_TYPE_OBJECT) + +/** + * fu_io_channel_unix_get_fd: + * @self: a #FuIOChannel + * + * Gets the file descriptor for the device. + * + * Returns: fd, or -1 for not open. + * + * Since: 1.2.2 + **/ +gint +fu_io_channel_unix_get_fd (FuIOChannel *self) +{ + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), -1); + return self->fd; +} + +/** + * fu_io_channel_shutdown: + * @self: a #FuIOChannel + * @error: a #GError, or %NULL + * + * Closes the file descriptor for the device. + * + * Returns: %TRUE if all the FD was closed. + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_shutdown (FuIOChannel *self, GError **error) +{ + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + if (!g_close (self->fd, error)) + return FALSE; + self->fd = -1; + return TRUE; +} + +static gboolean +fu_io_channel_flush_input (FuIOChannel *self, GError **error) +{ + GPollFD poll = { + .fd = self->fd, + .events = G_IO_IN | G_IO_ERR, + }; + while (g_poll (&poll, 1, 0) > 0) { + gchar c; + gint r = read (self->fd, &c, 1); + if (r < 0 && errno != EINTR) + break; + } + return TRUE; +} + +/** + * fu_io_channel_write_bytes: + * @self: a #FuIOChannel + * @bytes: buffer to write + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Writes bytes to the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: %TRUE if all the bytes was written + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_write_bytes (FuIOChannel *self, + GBytes *bytes, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (bytes, &bufsz); + return fu_io_channel_write_raw (self, buf, bufsz, timeout_ms, flags, error); +} + +/** + * fu_io_channel_write_raw: + * @self: a #FuIOChannel + * @data: buffer to write + * @datasz: size of @data + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Writes bytes to the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: %TRUE if all the bytes was written + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_write_raw (FuIOChannel *self, + const guint8 *data, + gsize datasz, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + gsize idx = 0; + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + + /* flush pending reads */ + if (flags & FU_IO_CHANNEL_FLAG_FLUSH_INPUT) { + if (!fu_io_channel_flush_input (self, error)) + return FALSE; + } + + /* blocking IO */ + if (flags & FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO) { + gssize wrote = write (self->fd, data, datasz); + if (wrote != (gssize) datasz) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to write: " + "wrote %" G_GSSIZE_FORMAT " of %" G_GSIZE_FORMAT, + wrote, datasz); + return FALSE; + } + return TRUE; + } + + /* nonblocking IO */ + while (idx < datasz) { + gint rc; + GPollFD fds = { + .fd = self->fd, + .events = G_IO_OUT | G_IO_ERR, + }; + + /* wait for data to be allowed to write without blocking */ + rc = g_poll (&fds, 1, (gint) timeout_ms); + if (rc == 0) + break; + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to poll %i", + self->fd); + return FALSE; + } + + /* we can write data */ + if (fds.revents & G_IO_OUT) { + gssize len = write (self->fd, data + idx, datasz - idx); + if (len < 0) { + if (errno == EAGAIN) { + g_debug ("got EAGAIN, trying harder"); + continue; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_WRITE, + "failed to write %" G_GSIZE_FORMAT + " bytes to %i: %s" , + datasz, + self->fd, + strerror (errno)); + return FALSE; + } + if (flags & FU_IO_CHANNEL_FLAG_SINGLE_SHOT) + break; + idx += len; + } + } + + return TRUE; +} + +/** + * fu_io_channel_read_bytes: + * @self: a #FuIOChannel + * @max_size: maximum size of the returned blob, or -1 for no limit + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Reads bytes from the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: a #GBytes, or %NULL for error + * + * Since: 1.2.2 + **/ +GBytes * +fu_io_channel_read_bytes (FuIOChannel *self, + gssize max_size, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + GPollFD fds = { + .fd = self->fd, + .events = G_IO_IN | G_IO_PRI | G_IO_ERR, + }; + g_autoptr(GString) str = g_string_new (NULL); + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), NULL); + + /* blocking IO */ + if (flags & FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO) { + guint8 buf[1024]; + gssize len = read (self->fd, buf, sizeof (buf)); + if (len < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read %i: %s", self->fd, + strerror (errno)); + return NULL; + } + if (len > 0) + g_string_append_len (str, (gchar *) buf, len); + return g_bytes_new (str->str, str->len); + } + + /* nonblocking IO */ + while (TRUE) { + /* wait for data to appear */ + gint rc = g_poll (&fds, 1, (gint) timeout_ms); + if (rc == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timeout"); + return NULL; + } + if (rc < 0) { + if (errno == EINTR) + continue; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to poll %i", self->fd); + return NULL; + } + + /* we have data to read */ + if (fds.revents & G_IO_IN) { + guint8 buf[1024]; + gssize len = read (self->fd, buf, sizeof (buf)); + if (len < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + continue; + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "failed to read %i: %s", self->fd, + strerror (errno)); + return NULL; + } + if (len > 0) + g_string_append_len (str, (gchar *) buf, len); + + /* check maximum size */ + if (max_size > 0 && str->len >= (guint) max_size) + break; + if (flags & FU_IO_CHANNEL_FLAG_SINGLE_SHOT) + break; + continue; + } + if (fds.revents & G_IO_ERR) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "error condition"); + return NULL; + } + if (fds.revents & G_IO_HUP) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "connection hung up"); + return NULL; + } + if (fds.revents & G_IO_NVAL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "invalid request"); + return NULL; + } + } + + /* no data */ + if (str->len == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_READ, + "no data received from device in %ums", + timeout_ms); + return NULL; + } + + /* return blob */ + return g_bytes_new (str->str, str->len); +} + +/** + * fu_io_channel_read_raw: + * @self: a #FuIOChannel + * @buf: buffer, or %NULL + * @bufsz: size of @buf + * @bytes_read: (out): data written to @buf, or %NULL + * @timeout_ms: timeout in ms + * @flags: some #FuIOChannelFlags, e.g. %FU_IO_CHANNEL_FLAG_SINGLE_SHOT + * @error: a #GError, or %NULL + * + * Reads bytes from the TTY, that will fail if exceeding @timeout_ms. + * + * Returns: a #GBytes, or %NULL for error + * + * Since: 1.2.2 + **/ +gboolean +fu_io_channel_read_raw (FuIOChannel *self, + guint8 *buf, + gsize bufsz, + gsize *bytes_read, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error) +{ + const guint8 *tmpbuf = NULL; + gsize bytes_read_tmp; + g_autoptr(GBytes) tmp = NULL; + + g_return_val_if_fail (FU_IS_IO_CHANNEL (self), FALSE); + + tmp = fu_io_channel_read_bytes (self, bufsz, timeout_ms, flags, error); + if (tmp == NULL) + return FALSE; + tmpbuf = g_bytes_get_data (tmp, &bytes_read_tmp); + if (tmpbuf != NULL) + memcpy (buf, tmpbuf, bytes_read_tmp); + if (bytes_read != NULL) + *bytes_read = bytes_read_tmp; + return TRUE; +} + +static void +fu_io_channel_finalize (GObject *object) +{ + FuIOChannel *self = FU_IO_CHANNEL (object); + if (self->fd != -1) + g_close (self->fd, NULL); + G_OBJECT_CLASS (fu_io_channel_parent_class)->finalize (object); +} + +static void +fu_io_channel_class_init (FuIOChannelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_io_channel_finalize; +} + +static void +fu_io_channel_init (FuIOChannel *self) +{ + self->fd = -1; +} + +/** + * fu_io_channel_unix_new: + * @fd: file descriptor + * + * Creates a new object to write and read from. + * + * Returns: a #FuIOChannel + **/ +FuIOChannel * +fu_io_channel_unix_new (gint fd) +{ + FuIOChannel *self; + self = g_object_new (FU_TYPE_IO_CHANNEL, NULL); + self->fd = fd; + return FU_IO_CHANNEL (self); +} + +/** + * fu_io_channel_new_file: + * @filename: device file + * @error: a #GError, or %NULL + * + * Creates a new object to write and read from. + * + * Returns: a #FuIOChannel + **/ +FuIOChannel * +fu_io_channel_new_file (const gchar *filename, GError **error) +{ + gint fd = g_open (filename, O_RDWR | O_NONBLOCK, S_IRWXU); + if (fd < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to open %s", filename); + return NULL; + } + return fu_io_channel_unix_new (fd); +} diff -Nru fwupd-1.0.6/src/fu-io-channel.h fwupd-1.2.10/src/fu-io-channel.h --- fwupd-1.0.6/src/fu-io-channel.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-io-channel.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FU_TYPE_IO_CHANNEL (fu_io_channel_get_type ()) + +G_DECLARE_FINAL_TYPE (FuIOChannel, fu_io_channel, FU, IO_CHANNEL, GObject) + +/** + * FuIOChannelFlags: + * @FU_IO_CHANNEL_FLAG_NONE: No flags are set + * @FU_IO_CHANNEL_FLAG_SINGLE_SHOT: Only one read or write is expected + * @FU_IO_CHANNEL_FLAG_FLUSH_INPUT: Flush pending input before writing + * @FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO: Block waiting for the TTY + * + * The flags used when reading data from the TTY. + **/ +typedef enum { + FU_IO_CHANNEL_FLAG_NONE = 0, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_SINGLE_SHOT = 1 << 0, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_FLUSH_INPUT = 1 << 1, /* Since: 1.2.2 */ + FU_IO_CHANNEL_FLAG_USE_BLOCKING_IO = 1 << 2, /* Since: 1.2.2 */ + /*< private >*/ + FU_IO_CHANNEL_FLAG_LAST +} FuIOChannelFlags; + +FuIOChannel *fu_io_channel_unix_new (gint fd); +FuIOChannel *fu_io_channel_new_file (const gchar *filename, + GError **error); + +gint fu_io_channel_unix_get_fd (FuIOChannel *self); +gboolean fu_io_channel_shutdown (FuIOChannel *self, + GError **error); +gboolean fu_io_channel_write_raw (FuIOChannel *self, + const guint8 *data, + gsize datasz, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +gboolean fu_io_channel_read_raw (FuIOChannel *self, + guint8 *buf, + gsize bufsz, + gsize *bytes_read, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +gboolean fu_io_channel_write_bytes (FuIOChannel *self, + GBytes *bytes, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); +GBytes *fu_io_channel_read_bytes (FuIOChannel *self, + gssize max_size, + guint timeout_ms, + FuIOChannelFlags flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-keyring.c fwupd-1.2.10/src/fu-keyring.c --- fwupd-1.0.6/src/fu-keyring.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuKeyring" + #include "config.h" #include "fwupd-error.h" @@ -53,13 +40,33 @@ fu_keyring_verify_data (FuKeyring *keyring, GBytes *blob, GBytes *blob_signature, + FuKeyringVerifyFlags flags, GError **error) { FuKeyringClass *klass = FU_KEYRING_GET_CLASS (keyring); g_return_val_if_fail (FU_IS_KEYRING (keyring), NULL); g_return_val_if_fail (blob != NULL, NULL); g_return_val_if_fail (blob_signature != NULL, NULL); - return klass->verify_data (keyring, blob, blob_signature, error); + return klass->verify_data (keyring, blob, blob_signature, flags, error); +} + +GBytes * +fu_keyring_sign_data (FuKeyring *keyring, + GBytes *blob, + FuKeyringSignFlags flags, + GError **error) +{ + FuKeyringClass *klass = FU_KEYRING_GET_CLASS (keyring); + g_return_val_if_fail (FU_IS_KEYRING (keyring), NULL); + g_return_val_if_fail (blob != NULL, NULL); + if (klass->sign_data == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "signing data is not supported"); + return NULL; + } + return klass->sign_data (keyring, blob, flags, error); } const gchar * diff -Nru fwupd-1.0.6/src/fu-keyring-gpg.c fwupd-1.2.10/src/fu-keyring-gpg.c --- fwupd-1.0.6/src/fu-keyring-gpg.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-gpg.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,18 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuKeyring" + #include "config.h" #include #include "fwupd-error.h" +#include "fu-common.h" #include "fu-keyring-gpg.h" struct _FuKeyringGpg @@ -97,6 +85,7 @@ FuKeyringGpg *self = FU_KEYRING_GPG (keyring); gpgme_error_t rc; g_autofree gchar *gpg_home = NULL; + g_autofree gchar *localstatedir = NULL; if (self->ctx != NULL) return TRUE; @@ -135,11 +124,8 @@ } /* set a custom home directory */ - gpg_home = g_build_filename (LOCALSTATEDIR, - "lib", - PACKAGE_NAME, - "gnupg", - NULL); + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + gpg_home = g_build_filename (localstatedir, "gnupg", NULL); if (g_mkdir_with_parents (gpg_home, 0700) < 0) { g_set_error (error, FWUPD_ERROR, @@ -245,6 +231,7 @@ fu_keyring_gpg_verify_data (FuKeyring *keyring, GBytes *blob, GBytes *blob_signature, + FuKeyringVerifyFlags flags, GError **error) { FuKeyringGpg *self = FU_KEYRING_GPG (keyring); @@ -256,6 +243,15 @@ g_auto(gpgme_data_t) sig = NULL; g_autoptr(GString) authority_newest = g_string_new (NULL); + /* not supported */ + if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no GPG client certificate support"); + return NULL; + } + /* load file data */ rc = gpgme_data_new_from_mem (&data, g_bytes_get_data (blob, NULL), diff -Nru fwupd-1.0.6/src/fu-keyring-gpg.h fwupd-1.2.10/src/fu-keyring-gpg.h --- fwupd-1.0.6/src/fu-keyring-gpg.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-gpg.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_GPG_H -#define __FU_KEYRING_GPG_H +#pragma once #include "fu-keyring.h" @@ -33,5 +17,3 @@ FuKeyring *fu_keyring_gpg_new (void); G_END_DECLS - -#endif /* __FU_KEYRING_GPG_H */ diff -Nru fwupd-1.0.6/src/fu-keyring.h fwupd-1.2.10/src/fu-keyring.h --- fwupd-1.0.6/src/fu-keyring.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_H -#define __FU_KEYRING_H +#pragma once #include #include @@ -32,6 +16,36 @@ #define FU_TYPE_KEYRING (fu_keyring_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuKeyring, fu_keyring, FU, KEYRING, GObject) +/** + * FuKeyringVerifyFlags: + * @FU_KEYRING_VERIFY_FLAG_NONE: No flags set + * @FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT: Use client certificate to verify + * + * The flags to use when interacting with a keyring + **/ +typedef enum { + FU_KEYRING_VERIFY_FLAG_NONE = 0, + FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT = 1 << 1, + /*< private >*/ + FU_KEYRING_VERIFY_FLAG_LAST +} FuKeyringVerifyFlags; + +/** + * FuKeyringSignFlags: + * @FU_KEYRING_SIGN_FLAG_NONE: No flags set + * @FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP: Add a timestamp + * @FU_KEYRING_SIGN_FLAG_ADD_CERT: Add a certificate + * + * The flags to when signing a binary + **/ +typedef enum { + FU_KEYRING_SIGN_FLAG_NONE = 0, + FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP = 1 << 0, + FU_KEYRING_SIGN_FLAG_ADD_CERT = 1 << 1, + /*< private >*/ + FU_KEYRING_SIGN_FLAG_LAST +} FuKeyringSignFlags; + struct _FuKeyringClass { GObjectClass parent_class; @@ -43,6 +57,11 @@ FuKeyringResult *(*verify_data) (FuKeyring *keyring, GBytes *payload, GBytes *payload_signature, + FuKeyringVerifyFlags flags, + GError **error); + GBytes *(*sign_data) (FuKeyring *keyring, + GBytes *payload, + FuKeyringSignFlags flags, GError **error); }; @@ -54,11 +73,14 @@ FuKeyringResult *fu_keyring_verify_data (FuKeyring *keyring, GBytes *blob, GBytes *blob_signature, + FuKeyringVerifyFlags flags, + GError **error); +GBytes *fu_keyring_sign_data (FuKeyring *keyring, + GBytes *blob, + FuKeyringSignFlags flags, GError **error); const gchar *fu_keyring_get_name (FuKeyring *self); void fu_keyring_set_name (FuKeyring *self, const gchar *name); G_END_DECLS - -#endif /* __FU_KEYRING_H */ diff -Nru fwupd-1.0.6/src/fu-keyring-pkcs7.c fwupd-1.2.10/src/fu-keyring-pkcs7.c --- fwupd-1.0.6/src/fu-keyring-pkcs7.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-pkcs7.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,28 +1,18 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuKeyring" + #include "config.h" +#include +#include #include +#include "fu-common.h" #include "fu-keyring-pkcs7.h" #include "fwupd-error.h" @@ -35,9 +25,60 @@ G_DEFINE_TYPE (FuKeyringPkcs7, fu_keyring_pkcs7, FU_TYPE_KEYRING) +typedef guchar gnutls_data_t; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pkcs7_t, gnutls_pkcs7_deinit, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_privkey_t, gnutls_privkey_deinit, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pubkey_t, gnutls_pubkey_deinit, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_crt_t, gnutls_x509_crt_deinit, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_dn_t, gnutls_x509_dn_deinit, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_privkey_t, gnutls_x509_privkey_deinit, NULL) +#ifdef HAVE_GNUTLS_3_6_0 +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_spki_t, gnutls_x509_spki_deinit, NULL) +#endif +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_data_t, gnutls_free) +#pragma clang diagnostic pop + +static gnutls_x509_crt_t +fu_keyring_pkcs7_load_crt_from_filename (const gchar *filename, + gnutls_x509_crt_fmt_t format, + GError **error) +{ + gnutls_datum_t d = { 0 }; + gsize bufsz = 0; + int rc; + g_autofree gchar *buf = NULL; + g_auto(gnutls_x509_crt_t) crt = NULL; + + /* create certificate */ + rc = gnutls_x509_crt_init (&crt); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_init: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + + /* import the certificate */ + if (!g_file_get_contents (filename, &buf, &bufsz, error)) + return NULL; + d.size = bufsz; + d.data = (unsigned char *) buf; + rc = gnutls_x509_crt_import (crt, &d, GNUTLS_X509_FMT_PEM); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_import: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + return g_steal_pointer (&crt); +} static gboolean fu_keyring_pkcs7_add_public_key (FuKeyringPkcs7 *self, @@ -45,47 +86,34 @@ gnutls_x509_crt_fmt_t format, GError **error) { - gnutls_datum_t datum; - gsize sz; + guint key_usage = 0; int rc; - g_autofree gchar *pem_data = NULL; - g_auto(gnutls_x509_crt_t) cert = NULL; + g_auto(gnutls_x509_crt_t) crt = NULL; /* load file and add to the trust list */ - if (!g_file_get_contents (filename, &pem_data, &sz, error)) { - g_prefix_error (error, "failed to load %s: ", filename); + g_debug ("trying to load certificate from %s", filename); + crt = fu_keyring_pkcs7_load_crt_from_filename (filename, format, error); + if (crt == NULL) return FALSE; - } - datum.data = (guint8 *) pem_data; - datum.size = sz; - g_debug ("trying to load CA from %s", filename); - rc = gnutls_x509_crt_init (&cert); + rc = gnutls_x509_crt_get_key_usage (crt, &key_usage, NULL); if (rc < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, - "failed to initialize certificate: %s [%i]", + "failed to get key usage: %s [%i]", gnutls_strerror (rc), rc); return FALSE; } - rc = gnutls_x509_crt_import (cert, &datum, format); - if (rc < 0) { + if ((key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) == 0 && + (key_usage & GNUTLS_KEY_KEY_CERT_SIGN) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID, - "failed to import certificate: %s [%i]", - gnutls_strerror (rc), rc); + "certificate %s not suitable for use [0x%x]", + filename, key_usage); return FALSE; } - if (gnutls_x509_crt_check_key_purpose (cert, GNUTLS_KP_ANY, 0) != 0) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_SIGNATURE_INVALID, - "certificate %s not suitable for use", - filename); - return FALSE; - } - rc = gnutls_x509_trust_list_add_cas (self->tl, &cert, 1, 0); + rc = gnutls_x509_trust_list_add_cas (self->tl, &crt, 1, 0); if (rc < 0) { g_set_error (error, FWUPD_ERROR, @@ -94,10 +122,10 @@ gnutls_strerror (rc), rc); return FALSE; } - g_debug ("loaded %i CAs", rc); + g_debug ("loaded %i certificates", rc); /* confusingly the trust list does not copy the certificate */ - cert = NULL; + crt = NULL; return TRUE; } @@ -135,6 +163,362 @@ return TRUE; } +static gnutls_privkey_t +fu_keyring_pkcs7_load_privkey (FuKeyringPkcs7 *self, GError **error) +{ + int rc; + gnutls_datum_t d = { 0 }; + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + g_auto(gnutls_privkey_t) key = NULL; + + /* load the private key */ + rc = gnutls_privkey_init (&key); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "privkey_init: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_build_filename (localstatedir, "pki", "secret.key", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, error)) + return NULL; + d.size = bufsz; + d.data = (unsigned char *) buf; + rc = gnutls_privkey_import_x509_raw (key, &d, GNUTLS_X509_FMT_PEM, NULL, 0); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "privkey_import_x509_raw: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + return g_steal_pointer (&key); +} + +static gnutls_x509_crt_t +fu_keyring_pkcs7_load_client_certificate (FuKeyringPkcs7 *self, GError **error) +{ + g_autofree gchar *filename = NULL; + g_autofree gchar *localstatedir = NULL; + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + filename = g_build_filename (localstatedir, "pki", "client.pem", NULL); + return fu_keyring_pkcs7_load_crt_from_filename (filename, + GNUTLS_X509_FMT_PEM, + error); +} + +static gnutls_pubkey_t +fu_keyring_pkcs7_load_pubkey_from_privkey (gnutls_privkey_t privkey, GError **error) +{ + g_auto(gnutls_pubkey_t) pubkey = NULL; + int rc; + + /* get the public key part of the private key */ + rc = gnutls_pubkey_init (&pubkey); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "pubkey_init: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + rc = gnutls_pubkey_import_privkey (pubkey, privkey, 0, 0); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "pubkey_import_privkey: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + + /* success */ + return g_steal_pointer (&pubkey); +} + +/* generates a private key just like: + * `certtool --generate-privkey` */ +static gboolean +fu_keyring_pkcs7_ensure_private_key (FuKeyringPkcs7 *self, GError **error) +{ +#ifdef HAVE_GNUTLS_3_6_0 + gnutls_datum_t d = { 0 }; + int bits; + int key_type = GNUTLS_PK_RSA; + int rc; + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + g_auto(gnutls_x509_privkey_t) key = NULL; + g_auto(gnutls_x509_spki_t) spki = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(gnutls_data_t) d_payload = NULL; + + /* check exists */ + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_build_filename (localstatedir, "pki", "secret.key", NULL); + if (g_file_test (fn, G_FILE_TEST_EXISTS)) + return TRUE; + + /* initialize key and SPKI */ + rc = gnutls_x509_privkey_init (&key); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "privkey_init: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + rc = gnutls_x509_spki_init (&spki); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "spki_init: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* generate key */ + bits = gnutls_sec_param_to_pk_bits (key_type, GNUTLS_SEC_PARAM_HIGH); + g_debug ("generating a %d bit %s private key...", + bits, gnutls_pk_algorithm_get_name (key_type)); + rc = gnutls_x509_privkey_generate2(key, key_type, bits, 0, NULL, 0); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "privkey_generate2: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + rc = gnutls_x509_privkey_verify_params (key); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "privkey_verify_params: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* create parents if required */ + if (!fu_common_mkdir_parent (fn, error)) + return FALSE; + + /* save to file */ + rc = gnutls_x509_privkey_export2 (key, GNUTLS_X509_FMT_PEM, &d); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "privkey_export2: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + d_payload = d.data; + file = g_file_new_for_path (fn); + return g_file_replace_contents (file, (const char *) d_payload, d.size, + NULL, FALSE, G_FILE_CREATE_PRIVATE, NULL, + NULL, error); +#else + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "cannot build private key as GnuTLS version is too old"); + return FALSE; +#endif +} + +/* generates a self signed certificate just like: + * `certtool --generate-self-signed --load-privkey priv.pem` */ +static gboolean +fu_keyring_pkcs7_ensure_client_certificate (FuKeyringPkcs7 *self, GError **error) +{ + int rc; + gnutls_datum_t d = { 0 }; + guchar sha1buf[20]; + gsize sha1bufsz = sizeof(sha1buf); + g_autofree gchar *fn = NULL; + g_autofree gchar *localstatedir = NULL; + g_auto(gnutls_privkey_t) key = NULL; + g_auto(gnutls_pubkey_t) pubkey = NULL; + g_auto(gnutls_x509_crt_t) crt = NULL; + g_autoptr(gnutls_data_t) d_payload = NULL; + + /* check exists */ + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + fn = g_build_filename (localstatedir, "pki", "client.pem", NULL); + if (g_file_test (fn, G_FILE_TEST_EXISTS)) + return TRUE; + + /* ensure the private key exists */ + if (!fu_keyring_pkcs7_ensure_private_key (self, error)) { + g_prefix_error (error, "failed to generate private key: "); + return FALSE; + } + + /* load private key */ + key = fu_keyring_pkcs7_load_privkey (self, error); + if (key == NULL) + return FALSE; + + /* load the public key from the private key */ + pubkey = fu_keyring_pkcs7_load_pubkey_from_privkey (key, error); + if (pubkey == NULL) + return FALSE; + + /* create certificate */ + rc = gnutls_x509_crt_init (&crt); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_init: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set public key */ + rc = gnutls_x509_crt_set_pubkey (crt, pubkey); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_set_pubkey: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set positive random serial number */ + rc = gnutls_rnd (GNUTLS_RND_NONCE, sha1buf, sizeof(sha1buf)); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "gnutls_rnd: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + sha1buf[0] &= 0x7f; + rc = gnutls_x509_crt_set_serial(crt, sha1buf, sizeof(sha1buf)); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_set_serial: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set activation */ + rc = gnutls_x509_crt_set_activation_time (crt, time (NULL)); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "set_activation_time: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set expiration */ + rc = gnutls_x509_crt_set_expiration_time (crt, (time_t) -1); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "set_expiration_time: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set basic constraints */ + rc = gnutls_x509_crt_set_basic_constraints (crt, 0, -1); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "set_basic_constraints: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set usage */ + rc = gnutls_x509_crt_set_key_usage (crt, GNUTLS_KEY_DIGITAL_SIGNATURE); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "set_key_usage: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set subject key ID */ + rc = gnutls_x509_crt_get_key_id (crt, GNUTLS_KEYID_USE_SHA1, sha1buf, &sha1bufsz); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "get_key_id: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + rc = gnutls_x509_crt_set_subject_key_id (crt, sha1buf, sha1bufsz); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "set_subject_key_id: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* set version */ + rc = gnutls_x509_crt_set_version (crt, 3); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "error setting certificate version: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* self-sign certificate */ + rc = gnutls_x509_crt_privkey_sign (crt, crt, key, GNUTLS_DIG_SHA256, 0); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_privkey_sign: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + + /* export to file */ + rc = gnutls_x509_crt_export2 (crt, GNUTLS_X509_FMT_PEM, &d); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "crt_export2: %s [%i]", + gnutls_strerror (rc), rc); + return FALSE; + } + d_payload = d.data; + return g_file_set_contents (fn, (const gchar *) d_payload, d.size, error); +} + static gboolean fu_keyring_pkcs7_setup (FuKeyring *keyring, GError **error) { @@ -164,7 +548,10 @@ gnutls_free (d); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_datum_t, _gnutls_datum_deinit) +#pragma clang diagnostic pop static gchar * fu_keyring_pkcs7_datum_to_dn_str (const gnutls_datum_t *raw) @@ -179,24 +566,29 @@ if (rc < 0) return NULL; str = (gnutls_datum_t *) gnutls_malloc (sizeof (gnutls_datum_t)); + str->data = NULL; rc = gnutls_x509_dn_get_str2 (dn, str, 0); if (rc < 0) return NULL; return g_strndup ((const gchar *) str->data, str->size); } +/* verifies a detached signature just like: + * `certtool --p7-verify --load-certificate client.pem --infile=test.p7b` */ static FuKeyringResult * fu_keyring_pkcs7_verify_data (FuKeyring *keyring, GBytes *blob, GBytes *blob_signature, + FuKeyringVerifyFlags flags, GError **error) { FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring); - gnutls_datum_t datum; + gnutls_datum_t datum = { 0 }; gint64 timestamp_newest = 0; int count; int rc; g_auto(gnutls_pkcs7_t) pkcs7 = NULL; + g_auto(gnutls_x509_crt_t) crt = NULL; g_autoptr(GString) authority_newest = g_string_new (NULL); /* startup */ @@ -235,17 +627,33 @@ "no PKCS7 signatures found"); return NULL; } + + /* use client certificate */ + if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { + if (!fu_keyring_pkcs7_ensure_client_certificate (self, error)) { + g_prefix_error (error, "failed to generate client certificate: "); + return NULL; + } + crt = fu_keyring_pkcs7_load_client_certificate (self, error); + if (crt == NULL) + return NULL; + } + for (gint i = 0; i < count; i++) { gnutls_pkcs7_signature_info_st info; gint64 signing_time = 0; /* verify the data against the detached signature */ - rc = gnutls_pkcs7_verify (pkcs7, self->tl, - NULL, /* vdata */ - 0, /* vdata_size */ - i, /* index */ - &datum, /* data */ - 0); /* flags */ + if (flags & FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT) { + rc = gnutls_pkcs7_verify_direct (pkcs7, crt, i, &datum, 0); + } else { + rc = gnutls_pkcs7_verify (pkcs7, self->tl, + NULL, /* vdata */ + 0, /* vdata_size */ + i, /* index */ + &datum, /* data */ + 0); /* flags */ + } if (rc < 0) { g_set_error (error, FWUPD_ERROR, @@ -270,7 +678,8 @@ g_autofree gchar *dn = NULL; timestamp_newest = signing_time; dn = fu_keyring_pkcs7_datum_to_dn_str (&info.issuer_dn); - g_string_assign (authority_newest, dn); + if (dn != NULL) + g_string_assign (authority_newest, dn); } gnutls_pkcs7_signature_info_deinit (&info); } @@ -282,6 +691,107 @@ NULL)); } +/* creates a detached signature just like: + * `certtool --p7-detached-sign --load-certificate client.pem \ + * --load-privkey secret.pem --outfile=test.p7b` */ +static GBytes * +fu_keyring_pkcs7_sign_data (FuKeyring *keyring, + GBytes *blob, + FuKeyringSignFlags flags, + GError **error) +{ + FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring); + gnutls_datum_t d = { 0 }; + gnutls_digest_algorithm_t dig = GNUTLS_DIG_NULL; + guint gnutls_flags = 0; + int rc; + g_auto(gnutls_pkcs7_t) pkcs7 = NULL; + g_auto(gnutls_privkey_t) key = NULL; + g_auto(gnutls_pubkey_t) pubkey = NULL; + g_auto(gnutls_x509_crt_t) crt = NULL; + g_autoptr(gnutls_data_t) d_payload = NULL; + + /* ensure the client certificate exists */ + if (!fu_keyring_pkcs7_ensure_client_certificate (self, error)) { + g_prefix_error (error, "failed to generate client certificate: "); + return NULL; + } + + /* import the keys */ + crt = fu_keyring_pkcs7_load_client_certificate (self, error); + if (crt == NULL) + return NULL; + key = fu_keyring_pkcs7_load_privkey (self, error); + if (key == NULL) + return NULL; + + /* get the digest algorithm from the publix key */ + pubkey = fu_keyring_pkcs7_load_pubkey_from_privkey (key, error); + if (pubkey == NULL) + return NULL; + rc = gnutls_pubkey_get_preferred_hash_algorithm (pubkey, &dig, NULL); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "preferred_hash_algorithm: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + + /* create container */ + rc = gnutls_pkcs7_init (&pkcs7); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "pkcs7_init: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + + /* sign data */ + d.data = (unsigned char *) g_bytes_get_data (blob, NULL); + d.size = g_bytes_get_size (blob); + if (flags & FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP) + gnutls_flags |= GNUTLS_PKCS7_INCLUDE_TIME; + if (flags & FU_KEYRING_SIGN_FLAG_ADD_CERT) + gnutls_flags |= GNUTLS_PKCS7_INCLUDE_CERT; + rc = gnutls_pkcs7_sign (pkcs7, crt, key, &d, NULL, NULL, dig, gnutls_flags); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "pkcs7_sign: %s [%i]", + gnutls_strerror (rc), rc); + return NULL; + } + + /* set certificate */ + if (flags & FU_KEYRING_SIGN_FLAG_ADD_CERT) { + rc = gnutls_pkcs7_set_crt (pkcs7, crt); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "pkcs7_set_cr: %s", gnutls_strerror (rc)); + return NULL; + } + } + + /* export */ + rc = gnutls_pkcs7_export2 (pkcs7, GNUTLS_X509_FMT_PEM, &d); + if (rc < 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_SIGNATURE_INVALID, + "pkcs7_export: %s", gnutls_strerror (rc)); + return NULL; + } + d_payload = d.data; + return g_bytes_new (d_payload, d.size); +} + static void fu_keyring_pkcs7_finalize (GObject *object) { @@ -297,6 +807,7 @@ FuKeyringClass *klass_app = FU_KEYRING_CLASS (klass); klass_app->setup = fu_keyring_pkcs7_setup; klass_app->add_public_keys = fu_keyring_pkcs7_add_public_keys; + klass_app->sign_data = fu_keyring_pkcs7_sign_data; klass_app->verify_data = fu_keyring_pkcs7_verify_data; object_class->finalize = fu_keyring_pkcs7_finalize; } diff -Nru fwupd-1.0.6/src/fu-keyring-pkcs7.h fwupd-1.2.10/src/fu-keyring-pkcs7.h --- fwupd-1.0.6/src/fu-keyring-pkcs7.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-pkcs7.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_PKCS7_H -#define __FU_KEYRING_PKCS7_H +#pragma once #include "fu-keyring.h" @@ -33,5 +17,3 @@ FuKeyring *fu_keyring_pkcs7_new (void); G_END_DECLS - -#endif /* __FU_KEYRING_PKCS7_H */ diff -Nru fwupd-1.0.6/src/fu-keyring-result.c fwupd-1.2.10/src/fu-keyring-result.c --- fwupd-1.0.6/src/fu-keyring-result.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-result.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuKeyring" + #include "config.h" #include "fwupd-error.h" @@ -111,11 +98,15 @@ pspec = g_param_spec_int64 ("timestamp", NULL, NULL, 0, G_MAXINT64, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_TIMESTAMP, pspec); pspec = g_param_spec_string ("authority", NULL, NULL, NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_AUTHORITY, pspec); } diff -Nru fwupd-1.0.6/src/fu-keyring-result.h fwupd-1.2.10/src/fu-keyring-result.h --- fwupd-1.0.6/src/fu-keyring-result.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-result.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_KEYRING_RESULT_H -#define __FU_KEYRING_RESULT_H +#pragma once #include @@ -34,5 +18,3 @@ const gchar *fu_keyring_result_get_authority (FuKeyringResult *self); G_END_DECLS - -#endif /* __FU_KEYRING_RESULT_H */ diff -Nru fwupd-1.0.6/src/fu-keyring-utils.c fwupd-1.2.10/src/fu-keyring-utils.c --- fwupd-1.0.6/src/fu-keyring-utils.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-utils.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuKeyring" + +#include + +#include "fwupd-error.h" + +#include "fu-common.h" +#include "fu-keyring-utils.h" + +#ifdef ENABLE_GPG +#include "fu-keyring-gpg.h" +#endif +#ifdef ENABLE_PKCS7 +#include "fu-keyring-pkcs7.h" +#endif + +/** + * fu_keyring_create_for_kind: + * @kind: A #FwupdKeyringKind, e.g. %FWUPD_KEYRING_KIND_GPG + * @error: A #GError, or %NULL + * + * Creates a new keyring of the specified kind. + * + * If the keyring cannot be created (for example, if fwupd is compiled without + * GPG support) then an error is returned. + * + * Returns: (transfer full): a new #FuKeyring, or %NULL for error + **/ +FuKeyring * +fu_keyring_create_for_kind (FwupdKeyringKind kind, GError **error) +{ + if (kind == FWUPD_KEYRING_KIND_GPG) { +#ifdef ENABLE_GPG + return fu_keyring_gpg_new (); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not compiled with GPG support"); + return NULL; +#endif + } + if (kind == FWUPD_KEYRING_KIND_PKCS7) { +#ifdef ENABLE_PKCS7 + return fu_keyring_pkcs7_new (); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Not compiled with PKCS7 support"); + return NULL; +#endif + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Keyring kind %s not supported", + fwupd_keyring_kind_to_string (kind)); + return NULL; +} + +/** + * fu_keyring_get_release_flags: + * @release: A #XbNode, e.g. %FWUPD_KEYRING_KIND_GPG + * @flags: A #FwupdReleaseFlags, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD + * @error: A #GError, or %NULL + * + * Uses the correct keyring to get the trust flags for a given release. + * + * Returns: %TRUE if @flags has been set + **/ +gboolean +fu_keyring_get_release_flags (XbNode *release, + FwupdReleaseFlags *flags, + GError **error) +{ + FwupdKeyringKind keyring_kind = FWUPD_KEYRING_KIND_UNKNOWN; + GBytes *blob_payload; + GBytes *blob_signature; + const gchar *fn; + g_autofree gchar *pki_dir = NULL; + g_autofree gchar *release_key = NULL; + g_autofree gchar *sysconfdir = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(FuKeyring) kr = NULL; + g_autoptr(FuKeyringResult) kr_result = NULL; + struct { + FwupdKeyringKind kind; + const gchar *ext; + } keyrings[] = { + { FWUPD_KEYRING_KIND_GPG, "asc" }, + { FWUPD_KEYRING_KIND_PKCS7, "p7b" }, + { FWUPD_KEYRING_KIND_PKCS7, "p7c" }, + { FWUPD_KEYRING_KIND_NONE, NULL } + }; + + /* custom filename specified */ + fn = xb_node_query_attr (release, "checksum[@target='content']", "filename", NULL); + if (fn == NULL) + fn = "filename.bin"; + + /* no signature == no trust */ + for (guint i = 0; keyrings[i].ext != NULL; i++) { + g_autofree gchar *fn_tmp = NULL; + fn_tmp = g_strdup_printf ("fwupd::ReleaseBlob(%s.%s)", + fn, keyrings[i].ext); + blob_signature = g_object_get_data (G_OBJECT (release), fn_tmp); + if (blob_signature != NULL) { + keyring_kind = keyrings[i].kind; + break; + } + } + if (keyring_kind == FWUPD_KEYRING_KIND_UNKNOWN) { + g_debug ("firmware archive contained no signature"); + return TRUE; + } + + /* get payload */ + release_key = g_strdup_printf ("fwupd::ReleaseBlob(%s)", fn); + blob_payload = g_object_get_data (G_OBJECT (release), release_key); + if (blob_payload == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no payload"); + return FALSE; + } + + /* check we were installed correctly */ + sysconfdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR); + pki_dir = g_build_filename (sysconfdir, "pki", PACKAGE_NAME, NULL); +#if defined(ENABLE_PKCS7) || defined(ENABLE_PKCS7) + if (!g_file_test (pki_dir, G_FILE_TEST_EXISTS)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "PKI directory %s not found", pki_dir); + return FALSE; + } +#endif + + /* verify against the system trusted keys */ + kr = fu_keyring_create_for_kind (keyring_kind, error); + if (kr == NULL) + return FALSE; + if (!fu_keyring_setup (kr, error)) { + g_prefix_error (error, "failed to set up %s keyring: ", + fu_keyring_get_name (kr)); + return FALSE; + } + if (!fu_keyring_add_public_keys (kr, pki_dir, error)) { + g_prefix_error (error, "failed to add public keys to %s keyring: ", + fu_keyring_get_name (kr)); + return FALSE; + } + kr_result = fu_keyring_verify_data (kr, blob_payload, blob_signature, + FU_KEYRING_VERIFY_FLAG_NONE, + &error_local); + if (kr_result == NULL) { + g_warning ("untrusted as failed to verify from %s keyring: %s", + fu_keyring_get_name (kr), + error_local->message); + return TRUE; + } + + /* awesome! */ + g_debug ("marking payload as trusted"); + *flags |= FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD; + return TRUE; +} diff -Nru fwupd-1.0.6/src/fu-keyring-utils.h fwupd-1.2.10/src/fu-keyring-utils.h --- fwupd-1.0.6/src/fu-keyring-utils.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-keyring-utils.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-keyring.h" +#include "fwupd-enums.h" + +G_BEGIN_DECLS + +FuKeyring *fu_keyring_create_for_kind (FwupdKeyringKind kind, + GError **error); +gboolean fu_keyring_get_release_flags (XbNode *release, + FwupdReleaseFlags *flags, + GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-main.c fwupd-1.2.10/src/fu-main.c --- fwupd-1.0.6/src/fu-main.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-main.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,30 +1,18 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuMain" + #include "config.h" -#include +#include #include #include #include +#include #include #include #include @@ -38,10 +26,14 @@ #include "fu-debug.h" #include "fu-device-private.h" #include "fu-engine.h" +#include "fu-install-task.h" #ifndef HAVE_POLKIT_0_114 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref) +#pragma clang diagnostic pop #endif typedef struct { @@ -49,11 +41,27 @@ GDBusNodeInfo *introspection_daemon; GDBusProxy *proxy_uid; GMainLoop *loop; + GFileMonitor *argv0_monitor; PolkitAuthority *authority; guint owner_id; FuEngine *engine; + gboolean update_in_progress; + gboolean pending_sigterm; } FuMainPrivate; +static gboolean +fu_main_sigterm_cb (gpointer user_data) +{ + FuMainPrivate *priv = (FuMainPrivate *) user_data; + if (!priv->update_in_progress) { + g_main_loop_quit (priv->loop); + return G_SOURCE_REMOVE; + } + g_warning ("Received SIGTERM during a firmware update, ignoring"); + priv->pending_sigterm = TRUE; + return G_SOURCE_CONTINUE; +} + static void fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv) { @@ -134,12 +142,14 @@ GVariantBuilder invalidated_builder; /* not yet connected */ - if (priv->connection == NULL) + if (priv->connection == NULL) { + g_variant_unref (g_variant_ref_sink (property_value)); return; + } /* build the dict */ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); - g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", property_name, @@ -173,6 +183,10 @@ FuMainPrivate *priv) { fu_main_set_status (priv, status); + + /* engine has gone idle */ + if (status == FWUPD_STATUS_SHUTDOWN) + g_main_loop_quit (priv->loop); } static void @@ -185,15 +199,51 @@ g_variant_new_uint32 (percentage)); } +static gboolean +fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender, + FwupdDeviceFlags *flags, GError **error) +{ + uid_t calling_uid; + g_autoptr(GVariant) value = NULL; + + g_return_val_if_fail (sender != NULL, FALSE); + g_return_val_if_fail (flags != NULL, FALSE); + + value = g_dbus_proxy_call_sync (priv->proxy_uid, + "GetConnectionUnixUser", + g_variant_new ("(s)", sender), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + error); + if (value == NULL) { + g_prefix_error (error, "failed to read user id of caller: "); + return FALSE; + } + g_variant_get (value, "(u)", &calling_uid); + if (calling_uid == 0) + *flags |= FWUPD_DEVICE_FLAG_TRUSTED; + + return TRUE; +} + static GVariant * -fu_main_device_array_to_variant (GPtrArray *devices) +fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender, + GPtrArray *devices, GError **error) { GVariantBuilder builder; + FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE; + g_return_val_if_fail (devices->len > 0, NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + + if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error)) + return NULL; + for (guint i = 0; i < devices->len; i++) { FuDevice *device = g_ptr_array_index (devices, i); - GVariant *tmp = fwupd_device_to_variant (FWUPD_DEVICE (device)); + GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device), + flags); g_variant_builder_add_value (&builder, tmp); } return g_variant_new ("(aa{sv})", &builder); @@ -243,14 +293,18 @@ typedef struct { GDBusMethodInvocation *invocation; - AsStore *store; - FwupdInstallFlags flags; + PolkitSubject *subject; + GPtrArray *install_tasks; + GPtrArray *action_ids; + GPtrArray *checksums; + guint64 flags; GBytes *blob_cab; FuMainPrivate *priv; gchar *device_id; gchar *remote_id; gchar *key; gchar *value; + XbSilo *silo; } FuMainAuthHelper; static void @@ -258,8 +312,16 @@ { if (helper->blob_cab != NULL) g_bytes_unref (helper->blob_cab); - if (helper->store != NULL) - g_object_unref (helper->store); + if (helper->subject != NULL) + g_object_unref (helper->subject); + if (helper->silo != NULL) + g_object_unref (helper->silo); + if (helper->install_tasks != NULL) + g_ptr_array_unref (helper->install_tasks); + if (helper->action_ids != NULL) + g_ptr_array_unref (helper->action_ids); + if (helper->checksums != NULL) + g_ptr_array_unref (helper->checksums); g_free (helper->device_id); g_free (helper->remote_id); g_free (helper->key); @@ -268,7 +330,10 @@ g_free (helper); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free) +#pragma clang diagnostic pop /* error may or may not already have been set */ static gboolean @@ -326,6 +391,108 @@ } static void +fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) auth = NULL; + + /* get result */ + fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE); + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (!fu_main_authorization_is_valid (auth, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* success */ + for (guint i = 0; i < helper->checksums->len; i++) { + const gchar *csum = g_ptr_array_index (helper->checksums, i); + fu_engine_add_approved_firmware (helper->priv->engine, csum); + } + g_dbus_method_invocation_return_value (helper->invocation, NULL); +} + +static void +fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; + g_autofree gchar *sig = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) auth = NULL; + + /* get result */ + fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE); + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (!fu_main_authorization_is_valid (auth, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* authenticated */ + sig = fu_engine_self_sign (helper->priv->engine, helper->value, helper->flags, &error); + if (sig == NULL) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* success */ + g_dbus_method_invocation_return_value (helper->invocation, g_variant_new ("(s)", sig)); +} + +static void +fu_main_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) auth = NULL; + + /* get result */ + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (!fu_main_authorization_is_valid (auth, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + if (!fu_engine_modify_config (helper->priv->engine, helper->key, helper->value, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* success */ + g_dbus_method_invocation_return_value (helper->invocation, NULL); +} + +static void +fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) auth = NULL; + + /* get result */ + fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE); + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (!fu_main_authorization_is_valid (auth, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* authenticated */ + if (!fu_engine_activate (helper->priv->engine, helper->device_id, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* success */ + g_dbus_method_invocation_return_value (helper->invocation, NULL); +} + +static void fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data) { g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; @@ -381,6 +548,8 @@ g_dbus_method_invocation_return_value (helper->invocation, NULL); } +static void fu_main_authorize_install_queue (FuMainAuthHelper *helper); + static void fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data) { @@ -397,13 +566,43 @@ return; } - /* authenticated */ - if (!fu_engine_install (helper->priv->engine, - helper->device_id, - helper->store, - helper->blob_cab, - helper->flags, - &error)) { + /* do the next authentication action ID */ + fu_main_authorize_install_queue (g_steal_pointer (&helper)); +} + +static void +fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref) +{ + FuMainPrivate *priv = helper_ref->priv; + g_autoptr(FuMainAuthHelper) helper = helper_ref; + g_autoptr(GError) error = NULL; + gboolean ret; + + /* still more things to to authenticate */ + if (helper->action_ids->len > 0) { + g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0)); + g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject); + g_ptr_array_remove_index (helper->action_ids, 0); + polkit_authority_check_authorization (priv->authority, subject, + action_id, NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_authorize_install_cb, + g_steal_pointer (&helper)); + return; + } + + /* all authenticated, so install all the things */ + priv->update_in_progress = TRUE; + ret = fu_engine_install_tasks (helper->priv->engine, + helper->install_tasks, + helper->blob_cab, + helper->flags, + &error); + priv->update_in_progress = FALSE; + if (priv->pending_sigterm) + g_main_loop_quit (priv->loop); + if (!ret) { g_dbus_method_invocation_return_gerror (helper->invocation, error); return; } @@ -412,6 +611,157 @@ g_dbus_method_invocation_return_value (helper->invocation, NULL); } +#if !GLIB_CHECK_VERSION(2,54,0) +static gboolean +g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_) +{ + for (guint i = 0; i < haystack->len; i++) { + gconstpointer *tmp = g_ptr_array_index (haystack, i); + if (tmp == needle) { + if (index_ != NULL) { + *index_ = i; + return TRUE; + } + } + } + return FALSE; +} +#endif + +static gint +fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b) +{ + FuInstallTask *task_a = *((FuInstallTask **) a); + FuInstallTask *task_b = *((FuInstallTask **) b); + return fu_install_task_compare (task_a, task_b); +} + +static GPtrArray * +fu_main_get_device_family (FuMainAuthHelper *helper, GError **error) +{ + FuDevice *parent; + GPtrArray *children; + g_autoptr(FuDevice) device = NULL; + g_autoptr(GPtrArray) devices_possible = NULL; + + /* get the device */ + device = fu_engine_get_device (helper->priv->engine, helper->device_id, error); + if (device == NULL) + return NULL; + + /* device itself */ + devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices_possible, g_object_ref (device)); + + /* add device children */ + children = fu_device_get_children (device); + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + g_ptr_array_add (devices_possible, g_object_ref (child)); + } + + /* add parent and siblings, not including the device itself */ + parent = fu_device_get_parent (device); + if (parent != NULL) { + GPtrArray *siblings = fu_device_get_children (parent); + g_ptr_array_add (devices_possible, g_object_ref (parent)); + for (guint i = 0; i < siblings->len; i++) { + FuDevice *sibling = g_ptr_array_index (siblings, i); + if (sibling == device) + continue; + g_ptr_array_add (devices_possible, g_object_ref (sibling)); + } + } + + /* success */ + return g_steal_pointer (&devices_possible); +} + +static gboolean +fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error) +{ + FuMainPrivate *priv = helper_ref->priv; + g_autoptr(FuMainAuthHelper) helper = helper_ref; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GPtrArray) devices_possible = NULL; + g_autoptr(GPtrArray) errors = NULL; + + /* get a list of devices that in some way match the device_id */ + if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) { + devices_possible = fu_engine_get_devices (priv->engine, error); + if (devices_possible == NULL) + return FALSE; + } else { + devices_possible = fu_main_get_device_family (helper, error); + if (devices_possible == NULL) + return FALSE; + } + + /* parse silo */ + helper->silo = fu_engine_get_silo_from_blob (priv->engine, + helper->blob_cab, + error); + if (helper->silo == NULL) + return FALSE; + + /* for each component in the silo */ + components = xb_silo_query (helper->silo, "components/component", 0, error); + if (components == NULL) + return FALSE; + helper->action_ids = g_ptr_array_new_with_free_func (g_free); + helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + + /* do any devices pass the requirements */ + for (guint j = 0; j < devices_possible->len; j++) { + FuDevice *device = g_ptr_array_index (devices_possible, j); + const gchar *action_id; + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error_local = NULL; + + /* is this component valid for the device */ + task = fu_install_task_new (device, component); + if (!fu_engine_check_requirements (priv->engine, + task, + helper->flags, + &error_local)) { + g_debug ("requirement on %s:%s failed: %s", + fu_device_get_id (device), + xb_node_query_text (component, "id", NULL), + error_local->message); + g_ptr_array_add (errors, g_steal_pointer (&error_local)); + continue; + } + + /* if component should have an update message from CAB */ + fu_device_incorporate_from_component (device, component); + + /* get the action IDs for the valid device */ + action_id = fu_install_task_get_action_id (task); + if (!g_ptr_array_find (helper->action_ids, action_id, NULL)) + g_ptr_array_add (helper->action_ids, g_strdup (action_id)); + g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task)); + } + } + + /* order the install tasks by the device priority */ + g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb); + + /* nothing suitable */ + if (helper->install_tasks->len == 0) { + GError *error_tmp = fu_common_error_array_get_best (errors); + g_propagate_error (error, error_tmp); + return FALSE; + } + + /* authenticate all things in the action_ids */ + fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); + fu_main_authorize_install_queue (g_steal_pointer (&helper)); + return TRUE; +} + static gboolean fu_main_device_id_valid (const gchar *device_id, GError **error) { @@ -437,6 +787,9 @@ GVariant *val = NULL; g_autoptr(GError) error = NULL; + /* activity */ + fu_engine_idle_reset (priv->engine); + if (g_strcmp0 (method_name, "GetDevices") == 0) { g_autoptr(GPtrArray) devices = NULL; g_debug ("Called %s()", method_name); @@ -445,7 +798,11 @@ g_dbus_method_invocation_return_gerror (invocation, error); return; } - val = fu_main_device_array_to_variant (devices); + val = fu_main_device_array_to_variant (priv, sender, devices, &error); + if (val == NULL) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } g_dbus_method_invocation_return_value (invocation, val); return; } @@ -467,6 +824,86 @@ g_dbus_method_invocation_return_value (invocation, val); return; } + if (g_strcmp0 (method_name, "GetApprovedFirmware") == 0) { + GVariantBuilder builder; + GPtrArray *checksums = fu_engine_get_approved_firmware (priv->engine); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + g_variant_builder_add_value (&builder, g_variant_new_string (checksum)); + } + val = g_variant_builder_end (&builder); + g_dbus_method_invocation_return_value (invocation, + g_variant_new_tuple (&val, 1)); + return; + } + if (g_strcmp0 (method_name, "SetApprovedFirmware") == 0) { + g_autofree gchar *checksums_str = NULL; + g_auto(GStrv) checksums = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; + g_autoptr(PolkitSubject) subject = NULL; + + g_variant_get (parameters, "(^as)", &checksums); + checksums_str = g_strjoinv (",", checksums); + g_debug ("Called %s(%s)", method_name, checksums_str); + + /* authenticate */ + fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); + helper = g_new0 (FuMainAuthHelper, 1); + helper->priv = priv; + helper->invocation = g_object_ref (invocation); + helper->checksums = g_ptr_array_new_with_free_func (g_free); + for (guint i = 0; checksums[i] != NULL; i++) + g_ptr_array_add (helper->checksums, g_strdup (checksums[i])); + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (priv->authority, subject, + "org.freedesktop.fwupd.set-approved-firmware", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_authorize_set_approved_firmware_cb, + g_steal_pointer (&helper)); + return; + } + if (g_strcmp0 (method_name, "SelfSign") == 0) { + GVariant *prop_value; + gchar *prop_key; + g_autofree gchar *value = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; + g_autoptr(PolkitSubject) subject = NULL; + g_autoptr(GVariantIter) iter = NULL; + + g_variant_get (parameters, "(sa{sv})", &value, &iter); + g_debug ("Called %s(%s)", method_name, value); + + /* get flags */ + helper = g_new0 (FuMainAuthHelper, 1); + while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) { + g_debug ("got option %s", prop_key); + if (g_strcmp0 (prop_key, "add-timestamp") == 0 && + g_variant_get_boolean (prop_value) == TRUE) + helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP; + if (g_strcmp0 (prop_key, "add-cert") == 0 && + g_variant_get_boolean (prop_value) == TRUE) + helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_CERT; + g_variant_unref (prop_value); + } + + /* authenticate */ + fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); + helper->priv = priv; + helper->value = g_steal_pointer (&value); + helper->invocation = g_object_ref (invocation); + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (priv->authority, subject, + "org.freedesktop.fwupd.self-sign", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_authorize_self_sign_cb, + g_steal_pointer (&helper)); + return; + } if (g_strcmp0 (method_name, "GetDowngrades") == 0) { const gchar *device_id; g_autoptr(GPtrArray) releases = NULL; @@ -523,7 +960,11 @@ g_dbus_method_invocation_return_gerror (invocation, error); return; } - val = fu_main_device_array_to_variant (devices); + val = fu_main_device_array_to_variant (priv, sender, devices, &error); + if (val == NULL) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } g_dbus_method_invocation_return_value (invocation, val); return; } @@ -615,8 +1056,8 @@ return; } if (g_strcmp0 (method_name, "Unlock") == 0) { - FuMainAuthHelper *helper; const gchar *device_id = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; g_autoptr(PolkitSubject) subject = NULL; g_variant_get (parameters, "(&s)", &device_id); @@ -639,14 +1080,67 @@ POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, fu_main_authorize_unlock_cb, - helper); + g_steal_pointer (&helper)); + return; + } + if (g_strcmp0 (method_name, "Activate") == 0) { + const gchar *device_id = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; + g_autoptr(PolkitSubject) subject = NULL; + + g_variant_get (parameters, "(&s)", &device_id); + g_debug ("Called %s(%s)", method_name, device_id); + if (!fu_main_device_id_valid (device_id, &error)) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + + /* authenticate */ + fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); + helper = g_new0 (FuMainAuthHelper, 1); + helper->priv = priv; + helper->invocation = g_object_ref (invocation); + helper->device_id = g_strdup (device_id); + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (priv->authority, subject, + "org.freedesktop.fwupd.device-activate", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_authorize_activate_cb, + g_steal_pointer (&helper)); + return; + } + if (g_strcmp0 (method_name, "ModifyConfig") == 0) { + g_autofree gchar *key = NULL; + g_autofree gchar *value = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; + g_autoptr(PolkitSubject) subject = NULL; + + g_variant_get (parameters, "(ss)", &key, &value); + g_debug ("Called %s(%s=%s)", method_name, key, value); + + /* authenticate */ + helper = g_new0 (FuMainAuthHelper, 1); + helper->priv = priv; + helper->key = g_steal_pointer (&key); + helper->value = g_steal_pointer (&value); + helper->invocation = g_object_ref (invocation); + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (priv->authority, subject, + "org.freedesktop.fwupd.modify-config", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_modify_config_cb, + g_steal_pointer (&helper)); return; } if (g_strcmp0 (method_name, "ModifyRemote") == 0) { - FuMainAuthHelper *helper; const gchar *remote_id = NULL; const gchar *key = NULL; const gchar *value = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; g_autoptr(PolkitSubject) subject = NULL; /* check the id exists */ @@ -664,18 +1158,18 @@ /* authenticate */ fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); subject = polkit_system_bus_name_new (sender); - polkit_authority_check_authorization (helper->priv->authority, subject, + polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.modify-remote", NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, fu_main_authorize_modify_remote_cb, - helper); + g_steal_pointer (&helper)); return; } if (g_strcmp0 (method_name, "VerifyUpdate") == 0) { - FuMainAuthHelper *helper; const gchar *device_id = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; g_autoptr(PolkitSubject) subject = NULL; /* check the id exists */ @@ -695,13 +1189,13 @@ /* authenticate */ fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); subject = polkit_system_bus_name_new (sender); - polkit_authority_check_authorization (helper->priv->authority, subject, + polkit_authority_check_authorization (priv->authority, subject, "org.freedesktop.fwupd.verify-update", NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, fu_main_authorize_verify_update_cb, - helper); + g_steal_pointer (&helper)); return; } if (g_strcmp0 (method_name, "Verify") == 0) { @@ -720,9 +1214,7 @@ return; } if (g_strcmp0 (method_name, "Install") == 0) { - FuMainAuthHelper *helper; GVariant *prop_value; - const gchar *action_id; const gchar *device_id = NULL; gchar *prop_key; gint32 fd_handle = 0; @@ -730,7 +1222,7 @@ guint64 archive_size_max; GDBusMessage *message; GUnixFDList *fd_list; - g_autoptr(PolkitSubject) subject = NULL; + g_autoptr(FuMainAuthHelper) helper = NULL; g_autoptr(GVariantIter) iter = NULL; /* check the id exists */ @@ -762,6 +1254,9 @@ if (g_strcmp0 (prop_key, "force") == 0 && g_variant_get_boolean (prop_value) == TRUE) helper->flags |= FWUPD_INSTALL_FLAG_FORCE; + if (g_strcmp0 (prop_key, "no-history") == 0 && + g_variant_get_boolean (prop_value) == TRUE) + helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY; g_variant_unref (prop_value); } @@ -792,32 +1287,15 @@ g_dbus_method_invocation_return_gerror (invocation, error); return; } - helper->store = fu_engine_get_store_from_blob (priv->engine, - helper->blob_cab, - &error); - if (helper->store == NULL) { - g_dbus_method_invocation_return_gerror (invocation, error); - return; - } - /* authenticate */ - action_id = fu_engine_get_action_id_for_device (priv->engine, - helper->device_id, - helper->store, - helper->flags, - &error); - if (action_id == NULL) { + /* install all the things in the store */ + helper->subject = polkit_system_bus_name_new (sender); + if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) { g_dbus_method_invocation_return_gerror (invocation, error); return; } - fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH); - subject = polkit_system_bus_name_new (sender); - polkit_authority_check_authorization (priv->authority, subject, - action_id, NULL, - POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - NULL, - fu_main_authorize_install_cb, - helper); + + /* async return */ return; } if (g_strcmp0 (method_name, "GetDetails") == 0) { @@ -873,9 +1351,15 @@ { FuMainPrivate *priv = (FuMainPrivate *) user_data; + /* activity */ + fu_engine_idle_reset (priv->engine); + if (g_strcmp0 (property_name, "DaemonVersion") == 0) return g_variant_new_string (VERSION); + if (g_strcmp0 (property_name, "Tainted") == 0) + return g_variant_new_boolean (fu_engine_get_tainted (priv->engine)); + if (g_strcmp0 (property_name, "Status") == 0) return g_variant_new_uint32 (fu_engine_get_status (priv->engine)); @@ -927,10 +1411,6 @@ g_warning ("cannot connect to DBus: %s", error->message); return; } - - /* dump startup profile data */ - if (g_getenv ("FWUPD_VERBOSE") != NULL) - fu_engine_profile_dump (priv->engine); } static void @@ -959,6 +1439,21 @@ return G_SOURCE_REMOVE; } +static void +fu_main_argv_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, + GFileMonitorEvent event_type, gpointer user_data) +{ + FuMainPrivate *priv = (FuMainPrivate *) user_data; + + /* can do straight away? */ + if (priv->update_in_progress) { + g_warning ("binary changed during a firmware update, ignoring"); + return; + } + g_debug ("binary changed, shutting down"); + g_main_loop_quit (priv->loop); +} + static GDBusNodeInfo * fu_main_load_introspection (const gchar *filename, GError **error) { @@ -978,31 +1473,6 @@ return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error); } -static gboolean -fu_main_perhaps_own_name (gpointer user_data) -{ - FuMainPrivate *priv = (FuMainPrivate *) user_data; - g_autoptr(GError) error = NULL; - - /* are any plugins pending */ - if (!fu_engine_check_plugins_pending (priv->engine, &error)) { - g_debug ("trying again: %s", error->message); - return G_SOURCE_CONTINUE; - } - - /* own the object */ - g_debug ("registering D-Bus service"); - priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, - FWUPD_DBUS_SERVICE, - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | - G_BUS_NAME_OWNER_FLAGS_REPLACE, - fu_main_on_bus_acquired_cb, - fu_main_on_name_acquired_cb, - fu_main_on_name_lost_cb, - priv, NULL); - return G_SOURCE_REMOVE; -} - static void fu_main_private_free (FuMainPrivate *priv) { @@ -1018,12 +1488,17 @@ g_object_unref (priv->connection); if (priv->authority != NULL) g_object_unref (priv->authority); + if (priv->argv0_monitor != NULL) + g_object_unref (priv->argv0_monitor); if (priv->introspection_daemon != NULL) g_dbus_node_info_unref (priv->introspection_daemon); g_free (priv); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free) +#pragma clang diagnostic pop int main (int argc, char *argv[]) @@ -1041,6 +1516,7 @@ }; g_autoptr(FuMainPrivate) priv = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GFile) argv0_file = g_file_new_for_path (argv[0]); g_autoptr(GOptionContext) context = NULL; setlocale (LC_ALL, ""); @@ -1066,7 +1542,7 @@ priv->loop = g_main_loop_new (NULL, FALSE); /* load engine */ - priv->engine = fu_engine_new (); + priv->engine = fu_engine_new (FU_APP_FLAGS_NONE); g_signal_connect (priv->engine, "changed", G_CALLBACK (fu_main_engine_changed_cb), priv); @@ -1085,13 +1561,20 @@ g_signal_connect (priv->engine, "percentage-changed", G_CALLBACK (fu_main_engine_percentage_changed_cb), priv); - if (!fu_engine_load (priv->engine, &error)) { + if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NONE, &error)) { g_printerr ("Failed to load engine: %s\n", error->message); return EXIT_FAILURE; } - /* keep polling until all the plugins are ready */ - g_timeout_add (200, fu_main_perhaps_own_name, priv); + g_unix_signal_add_full (G_PRIORITY_DEFAULT, + SIGTERM, fu_main_sigterm_cb, + priv, NULL); + + /* restart the daemon if the binary gets replaced */ + priv->argv0_monitor = g_file_monitor_file (argv0_file, G_FILE_MONITOR_NONE, + NULL, &error); + g_signal_connect (priv->argv0_monitor, "changed", + G_CALLBACK (fu_main_argv_changed_cb), priv); /* load introspection from file */ priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml", @@ -1108,6 +1591,16 @@ return EXIT_FAILURE; } + /* own the object */ + priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + FWUPD_DBUS_SERVICE, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + G_BUS_NAME_OWNER_FLAGS_REPLACE, + fu_main_on_bus_acquired_cb, + fu_main_on_name_acquired_cb, + fu_main_on_name_lost_cb, + priv, NULL); + /* Only timeout and close the mainloop if we have specified it * on the command line */ if (immediate_exit) @@ -1115,6 +1608,8 @@ else if (timed_exit) g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop); + g_debug ("Started with locale %s", g_getenv ("LANG")); + /* wait */ g_message ("Daemon ready for requests"); g_main_loop_run (priv->loop); diff -Nru fwupd-1.0.6/src/fu-mutex.h fwupd-1.2.10/src/fu-mutex.h --- fwupd-1.0.6/src/fu-mutex.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-mutex.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 Richard Hughes + * Copyright (C) 2019 Kalev Lember + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#if !GLIB_CHECK_VERSION(2, 61, 1) + +/* Backported GRWLock autoptr support for older glib versions */ + +typedef void GRWLockWriterLocker; + +static inline GRWLockWriterLocker * +g_rw_lock_writer_locker_new (GRWLock *rw_lock) +{ + g_rw_lock_writer_lock (rw_lock); + return (GRWLockWriterLocker *) rw_lock; +} + +static inline void +g_rw_lock_writer_locker_free (GRWLockWriterLocker *locker) +{ + g_rw_lock_writer_unlock ((GRWLock *) locker); +} + +typedef void GRWLockReaderLocker; + +static inline GRWLockReaderLocker * +g_rw_lock_reader_locker_new (GRWLock *rw_lock) +{ + g_rw_lock_reader_lock (rw_lock); + return (GRWLockReaderLocker *) rw_lock; +} + +static inline void +g_rw_lock_reader_locker_free (GRWLockReaderLocker *locker) +{ + g_rw_lock_reader_unlock ((GRWLock *) locker); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRWLockWriterLocker, g_rw_lock_writer_locker_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRWLockReaderLocker, g_rw_lock_reader_locker_free) + +#endif + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-offline.c fwupd-1.2.10/src/fu-offline.c --- fwupd-1.0.6/src/fu-offline.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-offline.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2015-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "fu-history.h" +#include "fu-plugin-private.h" +#include "fu-util-common.h" + +typedef enum { + FU_OFFLINE_FLAG_NONE = 0, + FU_OFFLINE_FLAG_ENABLE = 1 << 0, + FU_OFFLINE_FLAG_USE_PROGRESS = 1 << 1, +} FuOfflineFlag; + +struct FuUtilPrivate { + gchar *splash_cmd; + GTimer *splash_timer; + FuOfflineFlag splash_flags; +}; + +static gboolean +fu_offline_set_splash_progress (FuUtilPrivate *priv, guint percentage, GError **error) +{ + g_autofree gchar *str = g_strdup_printf ("%u", percentage); + const gchar *argv[] = { priv->splash_cmd, "system-update", "--progress", str, NULL }; + + /* call into plymouth if installed */ + if (priv->splash_flags == FU_OFFLINE_FLAG_NONE) { + /* TRANSLATORS: console message when not using plymouth */ + g_printerr ("%s: %u%%\n", _("Percentage complete"), percentage); + return TRUE; + } + + /* fall back to really old mode that should be supported by anything */ + if ((priv->splash_flags & FU_OFFLINE_FLAG_USE_PROGRESS) == 0) { + argv[1] = "display-message"; + argv[2] = "--text"; + } + return fu_common_spawn_sync (argv, NULL, NULL, 200, NULL, error); +} + +static gboolean +fu_offline_set_splash_mode (FuUtilPrivate *priv, GError **error) +{ + g_autoptr(GError) error_local = NULL; + const gchar *argv[] = { priv->splash_cmd, "change-mode", "--system-upgrade", NULL }; + + /* call into plymouth if installed */ + if (priv->splash_cmd == NULL) { + /* TRANSLATORS: console message when no Plymouth is installed */ + g_printerr ("%s\n", _("Installing Firmware…")); + return TRUE; + } + + /* try the new fancy mode, then fall back to really old mode */ + if (!fu_common_spawn_sync (argv, NULL, NULL, 1500, NULL, &error_local)) { + argv[2] = "--updates"; + if (!fu_common_spawn_sync (argv, NULL, NULL, 1500, NULL, error)) { + g_prefix_error (error, "%s: ", error_local->message); + return FALSE; + } + priv->splash_flags = FU_OFFLINE_FLAG_ENABLE; + return TRUE; + } + + /* success */ + priv->splash_flags = FU_OFFLINE_FLAG_ENABLE | FU_OFFLINE_FLAG_USE_PROGRESS; + return TRUE; +} + +static gboolean +fu_offline_set_splash_reboot (FuUtilPrivate *priv, GError **error) +{ + g_autoptr(GError) error_local = NULL; + const gchar *argv[] = { priv->splash_cmd, "change-mode", "--reboot", NULL }; + + /* call into plymouth if installed */ + if (priv->splash_flags == FU_OFFLINE_FLAG_NONE) { + /* TRANSLATORS: console message when not using plymouth */ + g_printerr ("%s\n", _("Rebooting…")); + return TRUE; + } + + /* try the new fancy mode, then fall back to really old mode */ + if (!fu_common_spawn_sync (argv, NULL, NULL, 200, NULL, &error_local)) { + /* fall back to really old mode that should be supported */ + argv[2] = "--shutdown"; + if (!fu_common_spawn_sync (argv, NULL, NULL, 200, NULL, error)) { + g_prefix_error (error, "%s: ", error_local->message); + return FALSE; + } + return TRUE; + } + + /* success */ + return TRUE; +} + +static void +fu_offline_client_notify_cb (GObject *object, GParamSpec *pspec, gpointer user_data) +{ + FuUtilPrivate *priv = (FuUtilPrivate *) user_data; + FwupdClient *client = FWUPD_CLIENT (object); + + /* rate limit to 1 second */ + if (g_timer_elapsed (priv->splash_timer, NULL) < 1.f || + fwupd_client_get_percentage (client) < 5) + return; + fu_offline_set_splash_progress (priv, fwupd_client_get_percentage (client), NULL); + g_timer_reset (priv->splash_timer); +} + +static void +fu_util_private_free (FuUtilPrivate *priv) +{ + if (priv->splash_timer != NULL) + g_timer_destroy (priv->splash_timer); + g_free (priv->splash_cmd); + g_free (priv); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop + +int +main (int argc, char *argv[]) +{ + gint vercmp; + guint cnt = 0; + g_autofree gchar *link = NULL; + g_autofree gchar *target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + g_autoptr(FuHistory) history = NULL; + g_autoptr(FwupdClient) client = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) results = NULL; + g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* verify this is pointing to our cache */ + link = g_file_read_link (FU_OFFLINE_TRIGGER_FILENAME, NULL); + if (link == NULL) + return EXIT_SUCCESS; + if (g_strcmp0 (link, target) != 0) + return EXIT_SUCCESS; + + /* do this first to avoid a loop if this tool segfaults */ + g_unlink (FU_OFFLINE_TRIGGER_FILENAME); + + /* ensure root user */ + if (getuid () != 0 || geteuid () != 0) { + /* TRANSLATORS: the user needs to stop playing with stuff */ + g_printerr ("%s\n", _("This tool can only be used by the root user")); + return EXIT_FAILURE; + } + + /* find plymouth, but not an error if not found */ + priv->splash_cmd = g_find_program_in_path ("plymouth"); + priv->splash_timer = g_timer_new (); + + /* ensure D-Bus errors are registered */ + fwupd_error_quark (); + + /* get prepared updates */ + history = fu_history_new (); + results = fu_history_get_devices (history, &error); + if (results == NULL) { + /* TRANSLATORS: we could not get the devices to update offline */ + g_printerr ("%s: %s\n", _("Failed to get pending devices"), + error->message); + return EXIT_FAILURE; + } + + /* connect to the daemon */ + client = fwupd_client_new (); + g_signal_connect (client, "notify::percentage", + G_CALLBACK (fu_offline_client_notify_cb), priv); + if (!fwupd_client_connect (client, NULL, &error)) { + /* TRANSLATORS: we could not talk to the fwupd daemon */ + g_printerr ("%s: %s\n", _("Failed to connect to daemon"), + error->message); + return EXIT_FAILURE; + } + + /* set up splash */ + if (!fu_offline_set_splash_mode (priv, &error)) { + /* TRANSLATORS: we could not talk to plymouth */ + g_printerr ("%s: %s\n", _("Failed to set splash mode"), + error->message); + return EXIT_FAILURE; + } + + /* apply each update */ + for (guint i = 0; i < results->len; i++) { + FwupdDevice *dev = g_ptr_array_index (results, i); + FwupdRelease *rel = fwupd_device_get_release_default (dev); + + /* check not already done */ + if (fwupd_device_get_update_state (dev) != FWUPD_UPDATE_STATE_PENDING) + continue; + + /* tell the user what's going to happen */ + vercmp = fu_common_vercmp (fwupd_device_get_version (dev), + fwupd_release_get_version (rel)); + if (vercmp == 0) { + /* TRANSLATORS: the first replacement is a display name + * e.g. "ColorHugALS" and the second is a version number + * e.g. "1.2.3" */ + g_print (_("Reinstalling %s with %s... "), + fwupd_device_get_name (dev), + fwupd_release_get_version (rel)); + } else if (vercmp > 0) { + /* TRANSLATORS: the first replacement is a display name + * e.g. "ColorHugALS" and the second and third are + * version numbers e.g. "1.2.3" */ + g_print (_("Downgrading %s from %s to %s... "), + fwupd_device_get_name (dev), + fwupd_device_get_version (dev), + fwupd_release_get_version (rel)); + } else if (vercmp < 0) { + /* TRANSLATORS: the first replacement is a display name + * e.g. "ColorHugALS" and the second and third are + * version numbers e.g. "1.2.3" */ + g_print (_("Updating %s from %s to %s... "), + fwupd_device_get_name (dev), + fwupd_device_get_version (dev), + fwupd_release_get_version (rel)); + } + if (!fwupd_client_install (client, + fwupd_device_get_id (dev), + fwupd_release_get_filename (rel), + FWUPD_INSTALL_FLAG_ALLOW_REINSTALL | + FWUPD_INSTALL_FLAG_ALLOW_OLDER | + FWUPD_INSTALL_FLAG_OFFLINE, + NULL, + &error)) { + /* TRANSLATORS: we could not install for some reason */ + g_printerr ("%s: %s\n", _("Failed to install firmware update"), + error->message); + return EXIT_FAILURE; + } + cnt++; + } + + /* nothing to do */ + if (cnt == 0) { + /* TRANSLATORS: nothing was updated offline */ + g_printerr ("%s\n", _("No updates were applied")); + return EXIT_FAILURE; + } + + /* reboot */ + fu_offline_set_splash_reboot (priv, NULL); + if (!fu_util_update_reboot (&error)) { + /* TRANSLATORS: we could not reboot for some reason */ + g_printerr ("%s: %s\n", _("Failed to reboot"), error->message); + return EXIT_FAILURE; + } + + /* success */ + g_print ("%s\n", _("Done!")); + return EXIT_SUCCESS; +} diff -Nru fwupd-1.0.6/src/fu-plugin.c fwupd-1.2.10/src/fu-plugin.c --- fwupd-1.0.6/src/fu-plugin.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-plugin.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,31 +1,18 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2018 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuPlugin" + #include "config.h" #include #include -#include #include #include +#include #include #ifdef HAVE_VALGRIND #include @@ -34,6 +21,7 @@ #include "fu-device-private.h" #include "fu-plugin-private.h" #include "fu-history.h" +#include "fu-mutex.h" /** * SECTION:fu-plugin @@ -53,14 +41,18 @@ GUsbContext *usb_ctx; gboolean enabled; guint order; + guint priority; GPtrArray *rules[FU_PLUGIN_RULE_LAST]; gchar *name; + gchar *build_hash; FuHwids *hwids; FuQuirks *quirks; - GPtrArray *supported_guids; + GHashTable *runtime_versions; + GHashTable *compile_versions; + GPtrArray *udev_subsystems; FuSmbios *smbios; GHashTable *devices; /* platform_id:GObject */ - GHashTable *devices_delay; /* FuDevice:FuPluginHelper */ + GRWLock devices_mutex; GHashTable *report_metadata; /* key:value */ FuPluginData *data; } FuPluginPrivate; @@ -69,8 +61,10 @@ SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_DEVICE_REGISTER, + SIGNAL_RULES_CHANGED, SIGNAL_RECOLDPLUG, SIGNAL_SET_COLDPLUG_DELAY, + SIGNAL_CHECK_SUPPORTED, SIGNAL_LAST }; @@ -80,30 +74,40 @@ #define GET_PRIVATE(o) (fu_plugin_get_instance_private (o)) typedef const gchar *(*FuPluginGetNameFunc) (void); -typedef void (*FuPluginInitFunc) (FuPlugin *plugin); -typedef gboolean (*FuPluginStartupFunc) (FuPlugin *plugin, +typedef void (*FuPluginInitFunc) (FuPlugin *self); +typedef gboolean (*FuPluginStartupFunc) (FuPlugin *self, GError **error); -typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *plugin, +typedef void (*FuPluginDeviceRegisterFunc) (FuPlugin *self, FuDevice *device); -typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *plugin, +typedef gboolean (*FuPluginDeviceFunc) (FuPlugin *self, + FuDevice *device, + GError **error); +typedef gboolean (*FuPluginFlaggedDeviceFunc) (FuPlugin *self, + FwupdInstallFlags flags, FuDevice *device, GError **error); -typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *plugin, +typedef gboolean (*FuPluginDeviceArrayFunc) (FuPlugin *self, + GPtrArray *devices, + GError **error); +typedef gboolean (*FuPluginVerifyFunc) (FuPlugin *self, FuDevice *device, FuPluginVerifyFlags flags, GError **error); -typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *plugin, +typedef gboolean (*FuPluginUpdateFunc) (FuPlugin *self, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error); -typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *plugin, - GUsbDevice *usb_device, +typedef gboolean (*FuPluginUsbDeviceAddedFunc) (FuPlugin *self, + FuUsbDevice *device, + GError **error); +typedef gboolean (*FuPluginUdevDeviceAddedFunc) (FuPlugin *self, + FuUdevDevice *device, GError **error); /** * fu_plugin_get_name: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * * Gets the plugin name. * @@ -112,26 +116,54 @@ * Since: 0.8.0 **/ const gchar * -fu_plugin_get_name (FuPlugin *plugin) +fu_plugin_get_name (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); return priv->name; } void -fu_plugin_set_name (FuPlugin *plugin, const gchar *name) +fu_plugin_set_name (FuPlugin *self, const gchar *name) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_if_fail (FU_IS_PLUGIN (plugin)); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (name != NULL); g_free (priv->name); priv->name = g_strdup (name); } /** + * fu_plugin_set_build_hash: + * @self: A #FuPlugin + * @build_hash: A checksum + * + * Sets the plugin build hash, typically a SHA256 checksum. All plugins must + * set the correct checksum to avoid the daemon being marked as tainted. + * + * Since: 1.2.4 + **/ +void +fu_plugin_set_build_hash (FuPlugin *self, const gchar *build_hash) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); + g_return_if_fail (build_hash != NULL); + g_free (priv->build_hash); + priv->build_hash = g_strdup (build_hash); +} + +const gchar * +fu_plugin_get_build_hash (FuPlugin *self) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); + return priv->build_hash; +} + +/** * fu_plugin_cache_lookup: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @id: the key * * Finds an object in the per-plugin cache. @@ -141,17 +173,19 @@ * Since: 0.8.0 **/ gpointer -fu_plugin_cache_lookup (FuPlugin *plugin, const gchar *id) +fu_plugin_cache_lookup (FuPlugin *self, const gchar *id) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&priv->devices_mutex); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (locker != NULL, NULL); return g_hash_table_lookup (priv->devices, id); } /** * fu_plugin_cache_add: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @id: the key * @dev: a #GObject, typically a #FuDevice * @@ -160,17 +194,19 @@ * Since: 0.8.0 **/ void -fu_plugin_cache_add (FuPlugin *plugin, const gchar *id, gpointer dev) +fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_if_fail (FU_IS_PLUGIN (plugin)); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (id != NULL); + g_return_if_fail (locker != NULL); g_hash_table_insert (priv->devices, g_strdup (id), g_object_ref (dev)); } /** * fu_plugin_cache_remove: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @id: the key * * Removes an object from the per-plugin cache. @@ -178,17 +214,19 @@ * Since: 0.8.0 **/ void -fu_plugin_cache_remove (FuPlugin *plugin, const gchar *id) +fu_plugin_cache_remove (FuPlugin *self, const gchar *id) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_if_fail (FU_IS_PLUGIN (plugin)); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&priv->devices_mutex); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (id != NULL); + g_return_if_fail (locker != NULL); g_hash_table_remove (priv->devices, id); } /** * fu_plugin_get_data: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * * Gets the per-plugin allocated private data. This will return %NULL unless * fu_plugin_alloc_data() has been called by the plugin. @@ -198,16 +236,16 @@ * Since: 0.8.0 **/ FuPluginData * -fu_plugin_get_data (FuPlugin *plugin) +fu_plugin_get_data (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); return priv->data; } /** * fu_plugin_alloc_data: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @data_sz: the size to allocate * * Allocates the per-plugin allocated private data. @@ -217,10 +255,10 @@ * Since: 0.8.0 **/ FuPluginData * -fu_plugin_alloc_data (FuPlugin *plugin, gsize data_sz) +fu_plugin_alloc_data (FuPlugin *self, gsize data_sz) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); if (priv->data != NULL) { g_critical ("fu_plugin_alloc_data() already used by plugin"); return priv->data; @@ -231,7 +269,7 @@ /** * fu_plugin_get_usb_context: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * * Gets the shared USB context that all plugins can use. * @@ -240,23 +278,23 @@ * Since: 0.8.0 **/ GUsbContext * -fu_plugin_get_usb_context (FuPlugin *plugin) +fu_plugin_get_usb_context (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); return priv->usb_ctx; } void -fu_plugin_set_usb_context (FuPlugin *plugin, GUsbContext *usb_ctx) +fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); g_set_object (&priv->usb_ctx, usb_ctx); } /** * fu_plugin_get_enabled: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * * Returns if the plugin is enabled. Plugins may self-disable using * fu_plugin_set_enabled() or can be disabled by the daemon. @@ -266,16 +304,16 @@ * Since: 0.8.0 **/ gboolean -fu_plugin_get_enabled (FuPlugin *plugin) +fu_plugin_get_enabled (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), FALSE); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), FALSE); return priv->enabled; } /** * fu_plugin_set_enabled: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @enabled: the enabled value * * Enables or disables a plugin. Plugins can self-disable at any point. @@ -283,19 +321,31 @@ * Since: 0.8.0 **/ void -fu_plugin_set_enabled (FuPlugin *plugin, gboolean enabled) +fu_plugin_set_enabled (FuPlugin *self, gboolean enabled) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_if_fail (FU_IS_PLUGIN (plugin)); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_if_fail (FU_IS_PLUGIN (self)); priv->enabled = enabled; } +gchar * +fu_plugin_guess_name_from_fn (const gchar *filename) +{ + const gchar *prefix = "libfu_plugin_"; + gchar *name; + gchar *str = g_strstr_len (filename, -1, prefix); + if (str == NULL) + return NULL; + name = g_strdup (str + strlen (prefix)); + g_strdelimit (name, ".", '\0'); + return name; +} + gboolean -fu_plugin_open (FuPlugin *plugin, const gchar *filename, GError **error) +fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginInitFunc func = NULL; - gchar *str; priv->module = g_module_open (filename, 0); if (priv->module == NULL) { @@ -308,17 +358,14 @@ } /* set automatically */ - str = g_strstr_len (filename, -1, "libfu_plugin_"); - if (str != NULL) { - priv->name = g_strdup (str + 13); - g_strdelimit (priv->name, ".", '\0'); - } + if (priv->name == NULL) + priv->name = fu_plugin_guess_name_from_fn (filename); /* optional */ g_module_symbol (priv->module, "fu_plugin_init", (gpointer *) &func); if (func != NULL) { g_debug ("performing init() on %s", filename); - func (plugin); + func (self); } return TRUE; @@ -326,7 +373,7 @@ /** * fu_plugin_device_add: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @device: A #FuDevice * * Asks the daemon to add a device to the exported list. If this device ID @@ -340,22 +387,39 @@ * Since: 0.8.0 **/ void -fu_plugin_device_add (FuPlugin *plugin, FuDevice *device) +fu_plugin_device_add (FuPlugin *self, FuDevice *device) { - g_return_if_fail (FU_IS_PLUGIN (plugin)); + GPtrArray *children; + g_autoptr(GError) error = NULL; + + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (FU_IS_DEVICE (device)); + /* ensure the device ID is set from the physical and logical IDs */ + if (!fu_device_ensure_id (device, &error)) { + g_warning ("ignoring add: %s", error->message); + return; + } + g_debug ("emit added from %s: %s", - fu_plugin_get_name (plugin), + fu_plugin_get_name (self), fu_device_get_id (device)); fu_device_set_created (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); - fu_device_set_plugin (device, fu_plugin_get_name (plugin)); - g_signal_emit (plugin, signals[SIGNAL_DEVICE_ADDED], 0, device); + fu_device_set_plugin (device, fu_plugin_get_name (self)); + g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device); + + /* add children if they have not already been added */ + children = fu_device_get_children (device); + for (guint i = 0; i < children->len; i++) { + FuDevice *child = g_ptr_array_index (children, i); + if (fu_device_get_created (child) == 0) + fu_plugin_device_add (self, child); + } } /** * fu_plugin_device_register: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @device: A #FuDevice * * Registers the device with other plugins so they can set metadata. @@ -368,99 +432,28 @@ * Since: 0.9.7 **/ void -fu_plugin_device_register (FuPlugin *plugin, FuDevice *device) +fu_plugin_device_register (FuPlugin *self, FuDevice *device) { - g_return_if_fail (FU_IS_PLUGIN (plugin)); - g_return_if_fail (FU_IS_DEVICE (device)); + g_autoptr(GError) error = NULL; - g_debug ("emit device-register from %s: %s", - fu_plugin_get_name (plugin), - fu_device_get_id (device)); - g_signal_emit (plugin, signals[SIGNAL_DEVICE_REGISTER], 0, device); -} - -typedef struct { - FuPlugin *plugin; - FuDevice *device; - guint timeout_id; - GHashTable *devices; -} FuPluginHelper; - -static void -fu_plugin_helper_free (FuPluginHelper *helper) -{ - g_object_unref (helper->plugin); - g_object_unref (helper->device); - g_hash_table_unref (helper->devices); - g_free (helper); -} - -static gboolean -fu_plugin_device_add_delay_cb (gpointer user_data) -{ - FuPluginHelper *helper = (FuPluginHelper *) user_data; - fu_plugin_device_add (helper->plugin, helper->device); - g_hash_table_remove (helper->devices, helper->device); - fu_plugin_helper_free (helper); - return FALSE; -} - -/** - * fu_plugin_has_device_delay: - * @plugin: A #FuPlugin - * - * Returns if the device has a pending device that is waiting to be added. - * - * Returns: %TRUE if a device is waiting to be added - * - * Since: 0.8.0 - **/ -gboolean -fu_plugin_has_device_delay (FuPlugin *plugin) -{ - FuPluginPrivate *priv = GET_PRIVATE (plugin); - return g_hash_table_size (priv->devices_delay) > 0; -} - -/** - * fu_plugin_device_add_delay: - * @plugin: A #FuPlugin - * @device: A #FuDevice - * - * Asks the daemon to add a device to the exported list after a small delay. - * - * Since: 0.8.0 - **/ -void -fu_plugin_device_add_delay (FuPlugin *plugin, FuDevice *device) -{ - FuPluginPrivate *priv = GET_PRIVATE (plugin); - FuPluginHelper *helper; - - g_return_if_fail (FU_IS_PLUGIN (plugin)); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (FU_IS_DEVICE (device)); - /* already waiting for add */ - helper = g_hash_table_lookup (priv->devices_delay, device); - if (helper != NULL) { - g_debug ("ignoring add-delay as device %s already pending", - fu_device_get_id (device)); + /* ensure the device ID is set from the physical and logical IDs */ + if (!fu_device_ensure_id (device, &error)) { + g_warning ("ignoring registration: %s", error->message); return; } - /* add after a small delay */ - g_debug ("waiting a small time for other plugins"); - helper = g_new0 (FuPluginHelper, 1); - helper->plugin = g_object_ref (plugin); - helper->device = g_object_ref (device); - helper->timeout_id = g_timeout_add (500, fu_plugin_device_add_delay_cb, helper); - helper->devices = g_hash_table_ref (priv->devices_delay); - g_hash_table_insert (helper->devices, device, helper); + g_debug ("emit device-register from %s: %s", + fu_plugin_get_name (self), + fu_device_get_id (device)); + g_signal_emit (self, signals[SIGNAL_DEVICE_REGISTER], 0, device); } /** * fu_plugin_device_remove: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @device: A #FuDevice * * Asks the daemon to remove a device from the exported list. @@ -468,33 +461,20 @@ * Since: 0.8.0 **/ void -fu_plugin_device_remove (FuPlugin *plugin, FuDevice *device) +fu_plugin_device_remove (FuPlugin *self, FuDevice *device) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - FuPluginHelper *helper; - - g_return_if_fail (FU_IS_PLUGIN (plugin)); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (FU_IS_DEVICE (device)); - /* waiting for add */ - helper = g_hash_table_lookup (priv->devices_delay, device); - if (helper != NULL) { - g_debug ("ignoring remove from delayed addition"); - g_source_remove (helper->timeout_id); - g_hash_table_remove (priv->devices_delay, helper->device); - fu_plugin_helper_free (helper); - return; - } - g_debug ("emit removed from %s: %s", - fu_plugin_get_name (plugin), + fu_plugin_get_name (self), fu_device_get_id (device)); - g_signal_emit (plugin, signals[SIGNAL_DEVICE_REMOVED], 0, device); + g_signal_emit (self, signals[SIGNAL_DEVICE_REMOVED], 0, device); } /** * fu_plugin_request_recoldplug: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * * Ask all the plugins to coldplug all devices, which will include the prepare() * and cleanup() phases. Duplicate devices added will be ignored. @@ -502,15 +482,15 @@ * Since: 0.8.0 **/ void -fu_plugin_request_recoldplug (FuPlugin *plugin) +fu_plugin_request_recoldplug (FuPlugin *self) { - g_return_if_fail (FU_IS_PLUGIN (plugin)); - g_signal_emit (plugin, signals[SIGNAL_RECOLDPLUG], 0); + g_return_if_fail (FU_IS_PLUGIN (self)); + g_signal_emit (self, signals[SIGNAL_RECOLDPLUG], 0); } /** * fu_plugin_check_hwid: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @hwid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234` * * Checks to see if a specific GUID exists. All hardware IDs on a @@ -521,17 +501,37 @@ * Since: 0.9.1 **/ gboolean -fu_plugin_check_hwid (FuPlugin *plugin, const gchar *hwid) +fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); if (priv->hwids == NULL) return FALSE; return fu_hwids_has_guid (priv->hwids, hwid); } /** + * fu_plugin_get_hwids: + * @self: A #FuPlugin + * + * Returns all the HWIDs defined in the system. All hardware IDs on a + * specific system can be shown using the `fwupdmgr hwids` command. + * + * Returns: (transfer none) (element-type utf-8): An array of GUIDs + * + * Since: 1.1.1 + **/ +GPtrArray * +fu_plugin_get_hwids (FuPlugin *self) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->hwids == NULL) + return NULL; + return fu_hwids_get_guids (priv->hwids); +} + +/** * fu_plugin_check_supported: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @guid: A Hardware ID GUID, e.g. `6de5d951-d755-576b-bd09-c5cf66b27234` * * Checks to see if a specific device GUID is supported, i.e. available in the @@ -542,22 +542,16 @@ * Since: 1.0.0 **/ gboolean -fu_plugin_check_supported (FuPlugin *plugin, const gchar *guid) +fu_plugin_check_supported (FuPlugin *self, const gchar *guid) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - if (priv->supported_guids == NULL) - return FALSE; - for (guint i = 0; i < priv->supported_guids->len; i++) { - const gchar *guid_tmp = g_ptr_array_index (priv->supported_guids, i); - if (g_strcmp0 (guid, guid_tmp) == 0) - return TRUE; - } - return FALSE; + gboolean retval = FALSE; + g_signal_emit (self, signals[SIGNAL_CHECK_SUPPORTED], 0, guid, &retval); + return retval; } /** * fu_plugin_get_dmi_value: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @dmi_id: A DMI ID, e.g. `BiosVersion` * * Gets a hardware DMI value. @@ -567,9 +561,9 @@ * Since: 0.9.7 **/ const gchar * -fu_plugin_get_dmi_value (FuPlugin *plugin, const gchar *dmi_id) +fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); if (priv->hwids == NULL) return NULL; return fu_hwids_get_value (priv->hwids, dmi_id); @@ -577,7 +571,7 @@ /** * fu_plugin_get_smbios_string: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS * @offset: A SMBIOS offset * @@ -591,9 +585,9 @@ * Since: 0.9.8 **/ const gchar * -fu_plugin_get_smbios_string (FuPlugin *plugin, guint8 structure_type, guint8 offset) +fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); if (priv->smbios == NULL) return NULL; return fu_smbios_get_string (priv->smbios, structure_type, offset, NULL); @@ -601,7 +595,7 @@ /** * fu_plugin_get_smbios_data: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @structure_type: A SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS * * Gets a hardware SMBIOS data. @@ -611,40 +605,40 @@ * Since: 0.9.8 **/ GBytes * -fu_plugin_get_smbios_data (FuPlugin *plugin, guint8 structure_type) +fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); if (priv->smbios == NULL) return NULL; return fu_smbios_get_data (priv->smbios, structure_type, NULL); } void -fu_plugin_set_hwids (FuPlugin *plugin, FuHwids *hwids) +fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); g_set_object (&priv->hwids, hwids); } void -fu_plugin_set_supported (FuPlugin *plugin, GPtrArray *supported_guids) +fu_plugin_set_udev_subsystems (FuPlugin *self, GPtrArray *udev_subsystems) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - if (priv->supported_guids != NULL) - g_ptr_array_unref (priv->supported_guids); - priv->supported_guids = g_ptr_array_ref (supported_guids); + FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->udev_subsystems != NULL) + g_ptr_array_unref (priv->udev_subsystems); + priv->udev_subsystems = g_ptr_array_ref (udev_subsystems); } void -fu_plugin_set_quirks (FuPlugin *plugin, FuQuirks *quirks) +fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); g_set_object (&priv->quirks, quirks); } /** * fu_plugin_get_quirks: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * * Returns the hardware database object. This can be used to discover device * quirks or other device-specific settings. @@ -654,86 +648,124 @@ * Since: 1.0.1 **/ FuQuirks * -fu_plugin_get_quirks (FuPlugin *plugin) +fu_plugin_get_quirks (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); return priv->quirks; } +void +fu_plugin_set_runtime_versions (FuPlugin *self, GHashTable *runtime_versions) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + priv->runtime_versions = g_hash_table_ref (runtime_versions); +} + /** - * fu_plugin_lookup_quirk_by_id: - * @plugin: A #FuPlugin - * @prefix: A string prefix that matches the quirks file basename, e.g. "dfu-quirks" - * @id: An ID to match the entry, e.g. "012345" + * fu_plugin_add_runtime_version: + * @self: A #FuPlugin + * @component_id: An AppStream component id, e.g. "org.gnome.Software" + * @version: A version string, e.g. "1.2.3" * - * Looks up an entry in the hardware database using a string value. - * - * Returns: (transfer none): values from the database, or %NULL if not found + * Sets a runtime version of a specific dependency. * - * Since: 1.0.1 + * Since: 1.0.7 **/ -const gchar * -fu_plugin_lookup_quirk_by_id (FuPlugin *plugin, const gchar *prefix, const gchar *id) +void +fu_plugin_add_runtime_version (FuPlugin *self, + const gchar *component_id, + const gchar *version) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); + FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->runtime_versions == NULL) + return; + g_hash_table_insert (priv->runtime_versions, + g_strdup (component_id), + g_strdup (version)); +} - /* wildcard */ - if (g_strstr_len (id, -1, "*") != NULL) - return fu_quirks_lookup_by_glob (priv->quirks, prefix, id); +void +fu_plugin_set_compile_versions (FuPlugin *self, GHashTable *compile_versions) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + priv->compile_versions = g_hash_table_ref (compile_versions); +} - /* exact ID */ - return fu_quirks_lookup_by_id (priv->quirks, prefix, id); +/** + * fu_plugin_add_compile_version: + * @self: A #FuPlugin + * @component_id: An AppStream component id, e.g. "org.gnome.Software" + * @version: A version string, e.g. "1.2.3" + * + * Sets a compile-time version of a specific dependency. + * + * Since: 1.0.7 + **/ +void +fu_plugin_add_compile_version (FuPlugin *self, + const gchar *component_id, + const gchar *version) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + if (priv->compile_versions == NULL) + return; + g_hash_table_insert (priv->compile_versions, + g_strdup (component_id), + g_strdup (version)); } /** - * fu_plugin_lookup_quirk_by_usb_device: - * @plugin: A #FuPlugin - * @prefix: A string prefix that matches the quirks file basename, e.g. "dfu-quirks" - * @dev: A #GUsbDevice + * fu_plugin_lookup_quirk_by_id: + * @self: A #FuPlugin + * @group: A string, e.g. "DfuFlags" + * @key: An ID to match the entry, e.g. "Summary" * - * Looks up an entry in the hardware database using various keys generated - * from @dev. + * Looks up an entry in the hardware database using a string value. * * Returns: (transfer none): values from the database, or %NULL if not found * * Since: 1.0.1 **/ const gchar * -fu_plugin_lookup_quirk_by_usb_device (FuPlugin *plugin, const gchar *prefix, GUsbDevice *dev) +fu_plugin_lookup_quirk_by_id (FuPlugin *self, const gchar *group, const gchar *key) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - g_return_val_if_fail (FU_IS_PLUGIN (plugin), NULL); - return fu_quirks_lookup_by_usb_device (priv->quirks, prefix, dev); + FuPluginPrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_PLUGIN (self), NULL); + + /* exact ID */ + return fu_quirks_lookup_by_id (priv->quirks, group, key); } /** - * fu_plugin_get_supported: - * @plugin: A #FuPlugin + * fu_plugin_lookup_quirk_by_id_as_uint64: + * @self: A #FuPlugin + * @group: A string, e.g. "DfuFlags" + * @key: An ID to match the entry, e.g. "Size" * - * Gets all the device GUIDs supported by the daemon. + * Looks up an entry in the hardware database using a string key, returning + * an integer value. Values are assumed base 10, unless prefixed with "0x" + * where they are parsed as base 16. * - * Returns: (element-type utf8) (transfer none): GUIDs + * Returns: (transfer none): value from the database, or 0 if not found * - * Since: 1.0.0 + * Since: 1.1.2 **/ -GPtrArray * -fu_plugin_get_supported (FuPlugin *plugin) +guint64 +fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, const gchar *group, const gchar *key) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); - return priv->supported_guids; + return fu_common_strtoull (fu_plugin_lookup_quirk_by_id (self, group, key)); } void -fu_plugin_set_smbios (FuPlugin *plugin, FuSmbios *smbios) +fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); g_set_object (&priv->smbios, smbios); } /** * fu_plugin_set_coldplug_delay: - * @plugin: A #FuPlugin + * @self: A #FuPlugin * @duration: A delay in milliseconds * * Set the minimum time that should be waited inbetween the call to @@ -751,9 +783,9 @@ * Since: 0.8.0 **/ void -fu_plugin_set_coldplug_delay (FuPlugin *plugin, guint duration) +fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration) { - g_return_if_fail (FU_IS_PLUGIN (plugin)); + g_return_if_fail (FU_IS_PLUGIN (self)); g_return_if_fail (duration > 0); /* check sanity */ @@ -765,14 +797,15 @@ } /* emit */ - g_signal_emit (plugin, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration); + g_signal_emit (self, signals[SIGNAL_SET_COLDPLUG_DELAY], 0, duration); } gboolean -fu_plugin_runner_startup (FuPlugin *plugin, GError **error) +fu_plugin_runner_startup (FuPlugin *self, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -787,8 +820,18 @@ if (func == NULL) return TRUE; g_debug ("performing startup() on %s", priv->name); - if (!func (plugin, error)) { - g_prefix_error (error, "failed to startup %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for startup()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to startup using %s: ", + priv->name); return FALSE; } return TRUE; @@ -821,11 +864,21 @@ fu_plugin_runner_offline_setup (GError **error) { gint rc; + g_autofree gchar *filename = NULL; + g_autofree gchar *symlink_target = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* does already exist */ + filename = fu_common_realpath (FU_OFFLINE_TRIGGER_FILENAME, NULL); + if (g_strcmp0 (filename, symlink_target) == 0) { + g_debug ("%s already points to %s, skipping creation", + FU_OFFLINE_TRIGGER_FILENAME, symlink_target); + return TRUE; + } + /* create symlink for the systemd-system-update-generator */ - rc = symlink ("/var/lib/fwupd", FU_OFFLINE_TRIGGER_FILENAME); + rc = symlink (symlink_target, FU_OFFLINE_TRIGGER_FILENAME); if (rc < 0) { g_set_error (error, FWUPD_ERROR, @@ -839,11 +892,12 @@ } static gboolean -fu_plugin_runner_device_generic (FuPlugin *plugin, FuDevice *device, +fu_plugin_runner_device_generic (FuPlugin *self, FuDevice *device, const gchar *symbol_name, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -858,20 +912,107 @@ if (func == NULL) return TRUE; g_debug ("performing %s() on %s", symbol_name + 10, priv->name); - if (!func (plugin, device, error)) { - g_prefix_error (error, "failed to run %s() on %s: ", - symbol_name + 10, - priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); + return FALSE; + } + return TRUE; +} + +static gboolean +fu_plugin_runner_flagged_device_generic (FuPlugin *self, FwupdInstallFlags flags, + FuDevice *device, + const gchar *symbol_name, GError **error) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginFlaggedDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; + + /* not enabled */ + if (!priv->enabled) + return TRUE; + + /* no object loaded */ + if (priv->module == NULL) + return TRUE; + + /* optional */ + g_module_symbol (priv->module, symbol_name, (gpointer *) &func); + if (func == NULL) + return TRUE; + g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + if (!func (self, flags, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); + return FALSE; + } + return TRUE; + +} + +static gboolean +fu_plugin_runner_device_array_generic (FuPlugin *self, GPtrArray *devices, + const gchar *symbol_name, GError **error) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginDeviceArrayFunc func = NULL; + g_autoptr(GError) error_local = NULL; + + /* not enabled */ + if (!priv->enabled) + return TRUE; + + /* no object loaded */ + if (priv->module == NULL) + return TRUE; + + /* optional */ + g_module_symbol (priv->module, symbol_name, (gpointer *) &func); + if (func == NULL) + return TRUE; + g_debug ("performing %s() on %s", symbol_name + 10, priv->name); + if (!func (self, devices, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for %s()", + priv->name, symbol_name + 10); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to %s using %s: ", + symbol_name + 10, priv->name); return FALSE; } return TRUE; } gboolean -fu_plugin_runner_coldplug (FuPlugin *plugin, GError **error) +fu_plugin_runner_coldplug (FuPlugin *self, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -886,18 +1027,28 @@ if (func == NULL) return TRUE; g_debug ("performing coldplug() on %s", priv->name); - if (!func (plugin, error)) { - g_prefix_error (error, "failed to coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug using %s: ", priv->name); return FALSE; } return TRUE; } gboolean -fu_plugin_runner_recoldplug (FuPlugin *plugin, GError **error) +fu_plugin_runner_recoldplug (FuPlugin *self, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -912,18 +1063,29 @@ if (func == NULL) return TRUE; g_debug ("performing recoldplug() on %s", priv->name); - if (!func (plugin, error)) { - g_prefix_error (error, "failed to recoldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for recoldplug()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to recoldplug using %s: ", + priv->name); return FALSE; } return TRUE; } gboolean -fu_plugin_runner_coldplug_prepare (FuPlugin *plugin, GError **error) +fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -938,18 +1100,29 @@ if (func == NULL) return TRUE; g_debug ("performing coldplug_prepare() on %s", priv->name); - if (!func (plugin, error)) { - g_prefix_error (error, "failed to prepare for coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug_prepare()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug_prepare using %s: ", + priv->name); return FALSE; } return TRUE; } gboolean -fu_plugin_runner_coldplug_cleanup (FuPlugin *plugin, GError **error) +fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginStartupFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -964,53 +1137,106 @@ if (func == NULL) return TRUE; g_debug ("performing coldplug_cleanup() on %s", priv->name); - if (!func (plugin, error)) { - g_prefix_error (error, "failed to cleanup coldplug %s: ", priv->name); + if (!func (self, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for coldplug_cleanup()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to coldplug_cleanup using %s: ", + priv->name); return FALSE; } return TRUE; } gboolean -fu_plugin_runner_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_composite_prepare (FuPlugin *self, GPtrArray *devices, GError **error) +{ + return fu_plugin_runner_device_array_generic (self, devices, + "fu_plugin_composite_prepare", + error); +} + +gboolean +fu_plugin_runner_composite_cleanup (FuPlugin *self, GPtrArray *devices, GError **error) { - return fu_plugin_runner_device_generic (plugin, device, - "fu_plugin_update_prepare", error); + return fu_plugin_runner_device_array_generic (self, devices, + "fu_plugin_composite_cleanup", + error); } gboolean -fu_plugin_runner_update_cleanup (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_update_prepare (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device, + GError **error) { - return fu_plugin_runner_device_generic (plugin, device, - "fu_plugin_update_cleanup", error); + return fu_plugin_runner_flagged_device_generic (self, flags, device, + "fu_plugin_update_prepare", + error); } gboolean -fu_plugin_runner_update_attach (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_update_cleanup (FuPlugin *self, FwupdInstallFlags flags, FuDevice *device, + GError **error) { - return fu_plugin_runner_device_generic (plugin, device, + return fu_plugin_runner_flagged_device_generic (self, flags, device, + "fu_plugin_update_cleanup", + error); +} + +gboolean +fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error) +{ + return fu_plugin_runner_device_generic (self, device, "fu_plugin_update_attach", error); } gboolean -fu_plugin_runner_update_detach (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error) { - return fu_plugin_runner_device_generic (plugin, device, + return fu_plugin_runner_device_generic (self, device, "fu_plugin_update_detach", error); } gboolean -fu_plugin_runner_update_reload (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error) { - return fu_plugin_runner_device_generic (plugin, device, + return fu_plugin_runner_device_generic (self, device, "fu_plugin_update_reload", error); } +/** + * fu_plugin_add_udev_subsystem: + * @self: a #FuPlugin + * @subsystem: a subsystem name, e.g. `pciport` + * + * Registers the udev subsystem to be watched by the daemon. + * + * Plugins can use this method only in fu_plugin_init() + **/ +void +fu_plugin_add_udev_subsystem (FuPlugin *self, const gchar *subsystem) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + for (guint i = 0; i < priv->udev_subsystems->len; i++) { + const gchar *subsystem_tmp = g_ptr_array_index (priv->udev_subsystems, i); + if (g_strcmp0 (subsystem_tmp, subsystem) == 0) + return; + } + g_debug ("added udev subsystem watch of %s", subsystem); + g_ptr_array_add (priv->udev_subsystems, g_strdup (subsystem)); +} + gboolean -fu_plugin_runner_usb_device_added (FuPlugin *plugin, GUsbDevice *usb_device, GError **error) +fu_plugin_runner_usb_device_added (FuPlugin *self, FuUsbDevice *device, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginUsbDeviceAddedFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1022,17 +1248,78 @@ /* optional */ g_module_symbol (priv->module, "fu_plugin_usb_device_added", (gpointer *) &func); - if (func != NULL) { - g_debug ("performing usb_device_added() on %s", priv->name); - return func (plugin, usb_device, error); + if (func == NULL) + return TRUE; + g_debug ("performing usb_device_added() on %s", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for usb_device_added()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to add device using on %s: ", + priv->name); + return FALSE; + } + return TRUE; +} + +gboolean +fu_plugin_runner_udev_device_added (FuPlugin *self, FuUdevDevice *device, GError **error) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); + FuPluginUdevDeviceAddedFunc func = NULL; + g_autoptr(GError) error_local = NULL; + + /* not enabled */ + if (!priv->enabled) + return TRUE; + + /* no object loaded */ + if (priv->module == NULL) + return TRUE; + + /* optional */ + g_module_symbol (priv->module, "fu_plugin_udev_device_added", (gpointer *) &func); + if (func == NULL) + return TRUE; + g_debug ("performing udev_device_added() on %s", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for udev_device_added()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to add device using on %s: ", + priv->name); + return FALSE; } return TRUE; } void -fu_plugin_runner_device_register (FuPlugin *plugin, FuDevice *device) +fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + g_autoptr(GError) error_local= NULL; + + if (!fu_plugin_runner_device_generic (self, device, + "fu_plugin_device_removed", + &error_local)) + g_warning ("%s", error_local->message); +} + +void +fu_plugin_runner_device_register (FuPlugin *self, FuDevice *device) +{ + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceRegisterFunc func = NULL; /* not enabled */ @@ -1041,43 +1328,50 @@ if (priv->module == NULL) return; + /* don't notify plugins on their own devices */ + if (g_strcmp0 (fu_device_get_plugin (device), fu_plugin_get_name (self)) == 0) + return; + /* optional */ g_module_symbol (priv->module, "fu_plugin_device_registered", (gpointer *) &func); if (func != NULL) { - g_debug ("performing device_added() on %s", priv->name); - func (plugin, device); + g_debug ("performing fu_plugin_device_registered() on %s", priv->name); + func (self, device); } } -static gboolean -fu_plugin_runner_schedule_update (FuPlugin *plugin, +gboolean +fu_plugin_runner_schedule_update (FuPlugin *self, FuDevice *device, + FwupdRelease *release, GBytes *blob_cab, + FwupdInstallFlags flags, GError **error) { - FwupdRelease *release; - gchar tmpname[] = {"XXXXXX.cap"}; + gchar tmpname[] = {"XXXXXX.cab"}; g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; - g_autoptr(FuDevice) res_tmp = NULL; g_autoptr(FuHistory) history = NULL; - g_autoptr(FwupdRelease) release_tmp = fwupd_release_new (); g_autoptr(GFile) file = NULL; /* id already exists */ history = fu_history_new (); - res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL); - if (res_tmp != NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_ALREADY_PENDING, - "%s is already scheduled to be updated", - fu_device_get_id (device)); - return FALSE; + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + g_autoptr(FuDevice) res_tmp = NULL; + res_tmp = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL); + if (res_tmp != NULL && + fu_device_get_update_state (res_tmp) == FWUPD_UPDATE_STATE_PENDING) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_ALREADY_PENDING, + "%s is already scheduled to be updated", + fu_device_get_id (device)); + return FALSE; + } } /* create directory */ - dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); + dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); file = g_file_new_for_path (dirname); if (!g_file_query_exists (file, NULL)) { if (!g_file_make_directory_with_parents (file, NULL, error)) @@ -1100,28 +1394,29 @@ /* schedule for next boot */ g_debug ("schedule %s to be installed to %s on next boot", filename, fu_device_get_id (device)); - release = fu_device_get_release_default (device); - fwupd_release_set_version (release_tmp, fwupd_release_get_version (release)); - fwupd_release_set_filename (release_tmp, filename); + fwupd_release_set_filename (release, filename); /* add to database */ + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT); fu_device_set_update_state (device, FWUPD_UPDATE_STATE_PENDING); - if (!fu_history_add_device (history, device, release_tmp, error)) + if (!fu_history_add_device (history, device, release, error)) return FALSE; /* next boot we run offline */ + fu_device_set_progress (device, 100); return fu_plugin_runner_offline_setup (error); } gboolean -fu_plugin_runner_verify (FuPlugin *plugin, +fu_plugin_runner_verify (FuPlugin *self, FuDevice *device, FuPluginVerifyFlags flags, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginVerifyFunc func = NULL; GPtrArray *checksums; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1131,24 +1426,85 @@ if (priv->module == NULL) return TRUE; - /* clear any existing verification checksums */ - checksums = fu_device_get_checksums (device); - g_ptr_array_set_size (checksums, 0); - /* optional */ g_module_symbol (priv->module, "fu_plugin_verify", (gpointer *) &func); if (func == NULL) return TRUE; + + /* clear any existing verification checksums */ + checksums = fu_device_get_checksums (device); + g_ptr_array_set_size (checksums, 0); + + /* run additional detach */ + if (!fu_plugin_runner_device_generic (self, device, + "fu_plugin_verify_detach", + error)) + return FALSE; + + /* run vfunc */ g_debug ("performing verify() on %s", priv->name); - if (!func (plugin, device, flags, error)) { - g_prefix_error (error, "failed to verify %s: ", priv->name); + if (!func (self, device, flags, &error_local)) { + g_autoptr(GError) error_attach = NULL; + if (error_local == NULL) { + g_critical ("unset error in plugin %s for verify()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to verify using %s: ", + priv->name); + /* make the device "work" again, but don't prefix the error */ + if (!fu_plugin_runner_device_generic (self, device, + "fu_plugin_verify_attach", + &error_attach)) { + g_warning ("failed to attach whilst aborting verify(): %s", + error_attach->message); + } + return FALSE; + } + + /* run optional attach */ + if (!fu_plugin_runner_device_generic (self, device, + "fu_plugin_verify_attach", + error)) + return FALSE; + + /* success */ + return TRUE; +} + +gboolean +fu_plugin_runner_activate (FuPlugin *self, FuDevice *device, GError **error) +{ + guint64 flags; + + /* final check */ + flags = fu_device_get_flags (device); + if ((flags & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION) == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "Device %s does not need activation", + fu_device_get_id (device)); return FALSE; } + + /* run vfunc */ + if (!fu_plugin_runner_device_generic (self, device, + "fu_plugin_activate", error)) + return FALSE; + + /* update with correct flags */ + fu_device_remove_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION); + fu_device_set_modified (device, (guint64) g_get_real_time () / G_USEC_PER_SEC); return TRUE; } gboolean -fu_plugin_runner_unlock (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_unlock (FuPlugin *self, FuDevice *device, GError **error) { guint64 flags; @@ -1164,7 +1520,7 @@ } /* run vfunc */ - if (!fu_plugin_runner_device_generic (plugin, device, + if (!fu_plugin_runner_device_generic (self, device, "fu_plugin_unlock", error)) return FALSE; @@ -1176,19 +1532,17 @@ } gboolean -fu_plugin_runner_update (FuPlugin *plugin, +fu_plugin_runner_update (FuPlugin *self, FuDevice *device, - GBytes *blob_cab, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginUpdateFunc update_func; g_autoptr(FuHistory) history = NULL; g_autoptr(FuDevice) device_pending = NULL; - GError *error_update = NULL; - GPtrArray *checksums; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) { @@ -1212,14 +1566,6 @@ return FALSE; } - /* just schedule this for the next reboot */ - if (flags & FWUPD_INSTALL_FLAG_OFFLINE) { - return fu_plugin_runner_schedule_update (plugin, - device, - blob_cab, - error); - } - /* cancel the pending action */ if (!fu_plugin_runner_offline_invalidate (error)) return FALSE; @@ -1227,15 +1573,27 @@ /* online */ history = fu_history_new (); device_pending = fu_history_get_device_by_id (history, fu_device_get_id (device), NULL); - if (!update_func (plugin, device, blob_fw, flags, &error_update)) { - fu_device_set_update_error (device, error_update->message); - g_propagate_error (error, error_update); + if (!update_func (self, device, blob_fw, flags, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for update()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + return FALSE; + } + fu_device_set_update_error (device, error_local->message); + g_propagate_error (error, g_steal_pointer (&error_local)); return FALSE; } /* no longer valid */ - checksums = fu_device_get_checksums (device); - g_ptr_array_set_size (checksums, 0); + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT) && + !fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) { + GPtrArray *checksums = fu_device_get_checksums (device); + g_ptr_array_set_size (checksums, 0); + } /* cleanup */ if (device_pending != NULL) { @@ -1253,15 +1611,15 @@ release = fu_device_get_release_default (device_pending); tmp = fwupd_release_get_filename (release); if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) { - g_autoptr(GError) error_local = NULL; + g_autoptr(GError) error_delete = NULL; g_autoptr(GFile) file = NULL; file = g_file_new_for_path (tmp); - if (!g_file_delete (file, NULL, &error_local)) { + if (!g_file_delete (file, NULL, &error_delete)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to delete %s: %s", - tmp, error_local->message); + tmp, error_delete->message); return FALSE; } } @@ -1270,10 +1628,11 @@ } gboolean -fu_plugin_runner_clear_results (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1288,18 +1647,29 @@ if (func == NULL) return TRUE; g_debug ("performing clear_result() on %s", priv->name); - if (!func (plugin, device, error)) { - g_prefix_error (error, "failed to clear_result %s: ", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for clear_result()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to clear_result using %s: ", + priv->name); return FALSE; } return TRUE; } gboolean -fu_plugin_runner_get_results (FuPlugin *plugin, FuDevice *device, GError **error) +fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginDeviceFunc func = NULL; + g_autoptr(GError) error_local = NULL; /* not enabled */ if (!priv->enabled) @@ -1314,8 +1684,18 @@ if (func == NULL) return TRUE; g_debug ("performing get_results() on %s", priv->name); - if (!func (plugin, device, error)) { - g_prefix_error (error, "failed to get_results %s: ", priv->name); + if (!func (self, device, &error_local)) { + if (error_local == NULL) { + g_critical ("unset error in plugin %s for get_results()", + priv->name); + g_set_error_literal (&error_local, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "unspecified error"); + } + g_propagate_prefixed_error (error, g_steal_pointer (&error_local), + "failed to get_results using %s: ", + priv->name); return FALSE; } return TRUE; @@ -1323,7 +1703,7 @@ /** * fu_plugin_get_order: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * * Gets the plugin order, where higher numbers are run after lower * numbers. @@ -1331,30 +1711,59 @@ * Returns: the integer value **/ guint -fu_plugin_get_order (FuPlugin *plugin) +fu_plugin_get_order (FuPlugin *self) { - FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin); + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); return priv->order; } /** * fu_plugin_set_order: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * @order: a integer value * * Sets the plugin order, where higher numbers are run after lower * numbers. **/ void -fu_plugin_set_order (FuPlugin *plugin, guint order) +fu_plugin_set_order (FuPlugin *self, guint order) { - FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin); + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); priv->order = order; } /** + * fu_plugin_get_priority: + * @self: a #FuPlugin + * + * Gets the plugin priority, where higher numbers are better. + * + * Returns: the integer value + **/ +guint +fu_plugin_get_priority (FuPlugin *self) +{ + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + return priv->priority; +} + +/** + * fu_plugin_set_priority: + * @self: a #FuPlugin + * @priority: a integer value + * + * Sets the plugin priority, where higher numbers are better. + **/ +void +fu_plugin_set_priority (FuPlugin *self, guint priority) +{ + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + priv->priority = priority; +} + +/** * fu_plugin_add_rule: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS * @name: a plugin name, e.g. `upower` * @@ -1366,15 +1775,16 @@ * If depsolving fails then fwupd will not start. **/ void -fu_plugin_add_rule (FuPlugin *plugin, FuPluginRule rule, const gchar *name) +fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) { - FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin); + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); g_ptr_array_add (priv->rules[rule], g_strdup (name)); + g_signal_emit (self, signals[SIGNAL_RULES_CHANGED], 0); } /** * fu_plugin_get_rules: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS * * Gets the plugin IDs that should be run after this plugin. @@ -1382,15 +1792,37 @@ * Returns: (element-type utf8) (transfer none): the list of plugin names, e.g. ['appstream'] **/ GPtrArray * -fu_plugin_get_rules (FuPlugin *plugin, FuPluginRule rule) +fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule) { - FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin); + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); return priv->rules[rule]; } /** + * fu_plugin_has_rule: + * @self: a #FuPlugin + * @rule: a #FuPluginRule, e.g. %FU_PLUGIN_RULE_CONFLICTS + * @name: a plugin name, e.g. `upower` + * + * Gets the plugin IDs that should be run after this plugin. + * + * Returns: %TRUE if the name exists for the specific rule + **/ +gboolean +fu_plugin_has_rule (FuPlugin *self, FuPluginRule rule, const gchar *name) +{ + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); + for (guint i = 0; i < priv->rules[rule]->len; i++) { + const gchar *tmp = g_ptr_array_index (priv->rules[rule], i); + if (g_strcmp0 (tmp, name) == 0) + return TRUE; + } + return FALSE; +} + +/** * fu_plugin_add_report_metadata: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * @key: a string, e.g. `FwupdateVersion` * @value: a string, e.g. `10` * @@ -1401,30 +1833,30 @@ * confirmation. **/ void -fu_plugin_add_report_metadata (FuPlugin *plugin, const gchar *key, const gchar *value) +fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value) { - FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin); + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); g_hash_table_insert (priv->report_metadata, g_strdup (key), g_strdup (value)); } /** * fu_plugin_get_report_metadata: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * * Returns the list of additional metadata to be added when filing a report. * * Returns: (transfer none): the map of report metadata **/ GHashTable * -fu_plugin_get_report_metadata (FuPlugin *plugin) +fu_plugin_get_report_metadata (FuPlugin *self) { - FuPluginPrivate *priv = fu_plugin_get_instance_private (plugin); + FuPluginPrivate *priv = fu_plugin_get_instance_private (self); return priv->report_metadata; } /** * fu_plugin_get_config_value: - * @plugin: a #FuPlugin + * @self: a #FuPlugin * @key: A settings key * * Return the value of a key if it's been configured @@ -1432,16 +1864,18 @@ * Since: 1.0.6 **/ gchar * -fu_plugin_get_config_value (FuPlugin *plugin, const gchar *key) +fu_plugin_get_config_value (FuPlugin *self, const gchar *key) { + g_autofree gchar *conf_dir = NULL; g_autofree gchar *conf_file = NULL; g_autofree gchar *conf_path = NULL; g_autoptr(GKeyFile) keyfile = NULL; const gchar *plugin_name; - plugin_name = fu_plugin_get_name (plugin); + conf_dir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG); + plugin_name = fu_plugin_get_name (self); conf_file = g_strdup_printf ("%s.conf", plugin_name); - conf_path = g_build_filename (FWUPDCONFIGDIR, conf_file, NULL); + conf_path = g_build_filename (conf_dir, conf_file, NULL); if (!g_file_test (conf_path, G_FILE_TEST_IS_REGULAR)) return NULL; keyfile = g_key_file_new (); @@ -1451,6 +1885,44 @@ return g_key_file_get_string (keyfile, plugin_name, key, NULL); } +/** + * fu_plugin_name_compare: + * @plugin1: first #FuPlugin to compare. + * @plugin2: second #FuPlugin to compare. + * + * Compares two plugins by their names. + * + * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2. + **/ +gint +fu_plugin_name_compare (FuPlugin *plugin1, FuPlugin *plugin2) +{ + FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1); + FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2); + return g_strcmp0 (priv1->name, priv2->name); +} + +/** + * fu_plugin_order_compare: + * @plugin1: first #FuPlugin to compare. + * @plugin2: second #FuPlugin to compare. + * + * Compares two plugins by their depsolved order. + * + * Returns: 1, 0 or -1 if @plugin1 is greater, equal, or less than @plugin2. + **/ +gint +fu_plugin_order_compare (FuPlugin *plugin1, FuPlugin *plugin2) +{ + FuPluginPrivate *priv1 = fu_plugin_get_instance_private (plugin1); + FuPluginPrivate *priv2 = fu_plugin_get_instance_private (plugin2); + if (priv1->order < priv2->order) + return -1; + if (priv1->order > priv2->order) + return 1; + return 0; +} + static void fu_plugin_class_init (FuPluginClass *klass) { @@ -1486,16 +1958,28 @@ G_STRUCT_OFFSET (FuPluginClass, set_coldplug_delay), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); + signals[SIGNAL_CHECK_SUPPORTED] = + g_signal_new ("check-supported", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, check_supported), + NULL, NULL, g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + signals[SIGNAL_RULES_CHANGED] = + g_signal_new ("rules-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FuPluginClass, rules_changed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void -fu_plugin_init (FuPlugin *plugin) +fu_plugin_init (FuPlugin *self) { - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPluginPrivate *priv = GET_PRIVATE (self); priv->enabled = TRUE; priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); - priv->devices_delay = g_hash_table_new (g_direct_hash, g_direct_equal); + g_rw_lock_init (&priv->devices_mutex); priv->report_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); for (guint i = 0; i < FU_PLUGIN_RULE_LAST; i++) priv->rules[i] = g_ptr_array_new_with_free_func (g_free); @@ -1504,8 +1988,8 @@ static void fu_plugin_finalize (GObject *object) { - FuPlugin *plugin = FU_PLUGIN (object); - FuPluginPrivate *priv = GET_PRIVATE (plugin); + FuPlugin *self = FU_PLUGIN (object); + FuPluginPrivate *priv = GET_PRIVATE (self); FuPluginInitFunc func = NULL; /* optional */ @@ -1513,7 +1997,7 @@ g_module_symbol (priv->module, "fu_plugin_destroy", (gpointer *) &func); if (func != NULL) { g_debug ("performing destroy() on %s", priv->name); - func (plugin); + func (self); } } @@ -1526,19 +2010,26 @@ g_object_unref (priv->hwids); if (priv->quirks != NULL) g_object_unref (priv->quirks); - if (priv->supported_guids != NULL) - g_ptr_array_unref (priv->supported_guids); + if (priv->udev_subsystems != NULL) + g_ptr_array_unref (priv->udev_subsystems); if (priv->smbios != NULL) g_object_unref (priv->smbios); -#ifndef RUNNING_ON_VALGRIND - if (priv->module != NULL) - g_module_close (priv->module); -#endif + if (priv->runtime_versions != NULL) + g_hash_table_unref (priv->runtime_versions); + if (priv->compile_versions != NULL) + g_hash_table_unref (priv->compile_versions); g_hash_table_unref (priv->devices); - g_hash_table_unref (priv->devices_delay); g_hash_table_unref (priv->report_metadata); + g_rw_lock_clear (&priv->devices_mutex); + g_free (priv->build_hash); g_free (priv->name); g_free (priv->data); + /* Must happen as the last step to avoid prematurely + * freeing memory held by the plugin */ +#ifndef RUNNING_ON_VALGRIND + if (priv->module != NULL) + g_module_close (priv->module); +#endif G_OBJECT_CLASS (fu_plugin_parent_class)->finalize (object); } @@ -1546,7 +2037,5 @@ FuPlugin * fu_plugin_new (void) { - FuPlugin *plugin; - plugin = g_object_new (FU_TYPE_PLUGIN, NULL); - return plugin; + return FU_PLUGIN (g_object_new (FU_TYPE_PLUGIN, NULL)); } diff -Nru fwupd-1.0.6/src/fu-plugin.h fwupd-1.2.10/src/fu-plugin.h --- fwupd-1.0.6/src/fu-plugin.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-plugin.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,38 +1,25 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_H -#define __FU_PLUGIN_H +#pragma once -#include #include -#include #include +#include #include "fu-common.h" +#include "fu-common-guid.h" +#include "fu-common-version.h" #include "fu-device.h" #include "fu-device-locker.h" #include "fu-quirks.h" #include "fu-hwids.h" #include "fu-usb-device.h" +#include "fu-udev-device.h" +#include "fwupd-common.h" G_BEGIN_DECLS @@ -43,21 +30,24 @@ { GObjectClass parent_class; /* signals */ - void (* device_added) (FuPlugin *plugin, + void (* device_added) (FuPlugin *self, FuDevice *device); - void (* device_removed) (FuPlugin *plugin, + void (* device_removed) (FuPlugin *self, FuDevice *device); - void (* status_changed) (FuPlugin *plugin, + void (* status_changed) (FuPlugin *self, FwupdStatus status); - void (* percentage_changed) (FuPlugin *plugin, + void (* percentage_changed) (FuPlugin *self, guint percentage); - void (* recoldplug) (FuPlugin *plugin); - void (* set_coldplug_delay) (FuPlugin *plugin, + void (* recoldplug) (FuPlugin *self); + void (* set_coldplug_delay) (FuPlugin *self, guint duration); - void (* device_register) (FuPlugin *plugin, + void (* device_register) (FuPlugin *self, FuDevice *device); + gboolean (* check_supported) (FuPlugin *self, + const gchar *guid); + void (* rules_changed) (FuPlugin *self); /*< private >*/ - gpointer padding[24]; + gpointer padding[22]; }; /** @@ -77,6 +67,10 @@ * @FU_PLUGIN_RULE_CONFLICTS: The plugin conflicts with another * @FU_PLUGIN_RULE_RUN_AFTER: Order the plugin after another * @FU_PLUGIN_RULE_RUN_BEFORE: Order the plugin before another + * @FU_PLUGIN_RULE_REQUIRES_QUIRK: Requires a specific quirk + * @FU_PLUGIN_RULE_BETTER_THAN: Is better than another plugin + * @FU_PLUGIN_RULE_INHIBITS_IDLE: The plugin inhibits the idle shutdown + * @FU_PLUGIN_RULE_SUPPORTS_PROTOCOL: The plugin supports a well known protocol * * The rules used for ordering plugins. * Plugins are expected to add rules in fu_plugin_initialize(). @@ -85,6 +79,10 @@ FU_PLUGIN_RULE_CONFLICTS, FU_PLUGIN_RULE_RUN_AFTER, FU_PLUGIN_RULE_RUN_BEFORE, + FU_PLUGIN_RULE_REQUIRES_QUIRK, + FU_PLUGIN_RULE_BETTER_THAN, + FU_PLUGIN_RULE_INHIBITS_IDLE, + FU_PLUGIN_RULE_SUPPORTS_PROTOCOL, /*< private >*/ FU_PLUGIN_RULE_LAST } FuPluginRule; @@ -92,64 +90,66 @@ typedef struct FuPluginData FuPluginData; /* for plugins to use */ -const gchar *fu_plugin_get_name (FuPlugin *plugin); -FuPluginData *fu_plugin_get_data (FuPlugin *plugin); -FuPluginData *fu_plugin_alloc_data (FuPlugin *plugin, +const gchar *fu_plugin_get_name (FuPlugin *self); +FuPluginData *fu_plugin_get_data (FuPlugin *self); +FuPluginData *fu_plugin_alloc_data (FuPlugin *self, gsize data_sz); -gboolean fu_plugin_get_enabled (FuPlugin *plugin); -void fu_plugin_set_enabled (FuPlugin *plugin, +gboolean fu_plugin_get_enabled (FuPlugin *self); +void fu_plugin_set_enabled (FuPlugin *self, gboolean enabled); -GUsbContext *fu_plugin_get_usb_context (FuPlugin *plugin); -GPtrArray *fu_plugin_get_supported (FuPlugin *plugin); -void fu_plugin_device_add (FuPlugin *plugin, - FuDevice *device); -void fu_plugin_device_add_delay (FuPlugin *plugin, +void fu_plugin_set_build_hash (FuPlugin *self, + const gchar *build_hash); +GUsbContext *fu_plugin_get_usb_context (FuPlugin *self); +void fu_plugin_device_add (FuPlugin *self, FuDevice *device); -void fu_plugin_device_remove (FuPlugin *plugin, +void fu_plugin_device_remove (FuPlugin *self, FuDevice *device); -void fu_plugin_device_register (FuPlugin *plugin, +void fu_plugin_device_register (FuPlugin *self, FuDevice *device); -void fu_plugin_set_status (FuPlugin *plugin, - FwupdStatus status); -void fu_plugin_set_percentage (FuPlugin *plugin, - guint percentage); -void fu_plugin_request_recoldplug (FuPlugin *plugin); -void fu_plugin_set_coldplug_delay (FuPlugin *plugin, +void fu_plugin_request_recoldplug (FuPlugin *self); +void fu_plugin_set_coldplug_delay (FuPlugin *self, guint duration); -gpointer fu_plugin_cache_lookup (FuPlugin *plugin, +gpointer fu_plugin_cache_lookup (FuPlugin *self, const gchar *id); -void fu_plugin_cache_remove (FuPlugin *plugin, +void fu_plugin_cache_remove (FuPlugin *self, const gchar *id); -void fu_plugin_cache_add (FuPlugin *plugin, +void fu_plugin_cache_add (FuPlugin *self, const gchar *id, gpointer dev); -gboolean fu_plugin_check_hwid (FuPlugin *plugin, +gboolean fu_plugin_check_hwid (FuPlugin *self, const gchar *hwid); -gboolean fu_plugin_check_supported (FuPlugin *plugin, +GPtrArray *fu_plugin_get_hwids (FuPlugin *self); +gboolean fu_plugin_check_supported (FuPlugin *self, const gchar *guid); -const gchar *fu_plugin_get_dmi_value (FuPlugin *plugin, +const gchar *fu_plugin_get_dmi_value (FuPlugin *self, const gchar *dmi_id); -const gchar *fu_plugin_get_smbios_string (FuPlugin *plugin, +const gchar *fu_plugin_get_smbios_string (FuPlugin *self, guint8 structure_type, guint8 offset); -GBytes *fu_plugin_get_smbios_data (FuPlugin *plugin, +GBytes *fu_plugin_get_smbios_data (FuPlugin *self, guint8 structure_type); -void fu_plugin_add_rule (FuPlugin *plugin, +void fu_plugin_add_rule (FuPlugin *self, FuPluginRule rule, const gchar *name); -FuQuirks *fu_plugin_get_quirks (FuPlugin *plugin); -const gchar *fu_plugin_lookup_quirk_by_id (FuPlugin *plugin, - const gchar *prefix, - const gchar *id); -const gchar *fu_plugin_lookup_quirk_by_usb_device (FuPlugin *plugin, - const gchar *prefix, - GUsbDevice *dev); -void fu_plugin_add_report_metadata (FuPlugin *plugin, +void fu_plugin_add_udev_subsystem (FuPlugin *self, + const gchar *subsystem); +FuQuirks *fu_plugin_get_quirks (FuPlugin *self); +const gchar *fu_plugin_lookup_quirk_by_id (FuPlugin *self, + const gchar *group, + const gchar *key); +guint64 fu_plugin_lookup_quirk_by_id_as_uint64 (FuPlugin *self, + const gchar *group, + const gchar *key); +void fu_plugin_add_report_metadata (FuPlugin *self, const gchar *key, const gchar *value); -gchar *fu_plugin_get_config_value (FuPlugin *plugin, +gchar *fu_plugin_get_config_value (FuPlugin *self, const gchar *key); -G_END_DECLS - -#endif /* __FU_PLUGIN_H */ +void fu_plugin_add_runtime_version (FuPlugin *self, + const gchar *component_id, + const gchar *version); +void fu_plugin_add_compile_version (FuPlugin *self, + const gchar *component_id, + const gchar *version); +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-plugin-list.c fwupd-1.2.10/src/fu-plugin-list.c --- fwupd-1.0.6/src/fu-plugin-list.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-plugin-list.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,24 +1,11 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuPluginList" + #include "config.h" #include @@ -34,7 +21,7 @@ * * This list of plugins provides a way to get the specific plugin quickly using * a hash table and also any plugin-list specific functionality such as - * sorting by dependancy order. + * sorting by dependency order. * * See also: #FuPlugin */ @@ -124,11 +111,7 @@ { FuPlugin **pa = (FuPlugin **) a; FuPlugin **pb = (FuPlugin **) b; - if (fu_plugin_get_order (*pa) < fu_plugin_get_order (*pb)) - return -1; - if (fu_plugin_get_order (*pa) > fu_plugin_get_order (*pb)) - return 1; - return 0; + return fu_plugin_order_compare (*pa, *pb); } /** @@ -214,6 +197,36 @@ changes = TRUE; } } + } + + /* set priority as well */ + for (guint i = 0; i < self->plugins->len; i++) { + FuPlugin *plugin = g_ptr_array_index (self->plugins, i); + deps = fu_plugin_get_rules (plugin, FU_PLUGIN_RULE_BETTER_THAN); + for (guint j = 0; j < deps->len && !changes; j++) { + const gchar *plugin_name = g_ptr_array_index (deps, j); + dep = fu_plugin_list_find_by_name (self, plugin_name, NULL); + if (dep == NULL) { + g_debug ("cannot find plugin '%s' " + "referenced by '%s'", + plugin_name, + fu_plugin_get_name (plugin)); + continue; + } + if (!fu_plugin_get_enabled (dep)) + continue; + if (fu_plugin_get_priority (plugin) <= fu_plugin_get_priority (dep)) { + g_debug ("%s [%u] better than %s [%u] " + "so bumping to [%u]", + fu_plugin_get_name (plugin), + fu_plugin_get_priority (plugin), + fu_plugin_get_name (dep), + fu_plugin_get_priority (dep), + fu_plugin_get_priority (dep) + 1); + fu_plugin_set_priority (plugin, fu_plugin_get_priority (dep) + 1); + changes = TRUE; + } + } } /* check we're not stuck */ diff -Nru fwupd-1.0.6/src/fu-plugin-list.h fwupd-1.2.10/src/fu-plugin-list.h --- fwupd-1.0.6/src/fu-plugin-list.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-plugin-list.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,33 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_LIST_H -#define __FU_PLUGIN_LIST_H - -G_BEGIN_DECLS +#pragma once #include #include "fu-plugin.h" +G_BEGIN_DECLS + #define FU_TYPE_PLUGIN_LIST (fu_plugin_list_get_type ()) G_DECLARE_FINAL_TYPE (FuPluginList, fu_plugin_list, FU, PLUGIN_LIST, GObject) @@ -42,6 +26,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_PLUGIN_LIST_H */ - diff -Nru fwupd-1.0.6/src/fu-plugin-private.h fwupd-1.2.10/src/fu-plugin-private.h --- fwupd-1.0.6/src/fu-plugin-private.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-plugin-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2018 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_PRIVATE_H -#define __FU_PLUGIN_PRIVATE_H +#pragma once #include "fu-quirks.h" #include "fu-plugin.h" @@ -31,78 +15,114 @@ #define FU_OFFLINE_TRIGGER_FILENAME FU_OFFLINE_DESTDIR "/system-update" FuPlugin *fu_plugin_new (void); -gboolean fu_plugin_has_device_delay (FuPlugin *plugin); -void fu_plugin_set_usb_context (FuPlugin *plugin, +void fu_plugin_set_usb_context (FuPlugin *self, GUsbContext *usb_ctx); -void fu_plugin_set_hwids (FuPlugin *plugin, +void fu_plugin_set_hwids (FuPlugin *self, FuHwids *hwids); -void fu_plugin_set_supported (FuPlugin *plugin, - GPtrArray *supported_guids); -void fu_plugin_set_quirks (FuPlugin *plugin, +void fu_plugin_set_udev_subsystems (FuPlugin *self, + GPtrArray *udev_subsystems); +void fu_plugin_set_quirks (FuPlugin *self, FuQuirks *quirks); -void fu_plugin_set_smbios (FuPlugin *plugin, +void fu_plugin_set_runtime_versions (FuPlugin *self, + GHashTable *runtime_versions); +void fu_plugin_set_compile_versions (FuPlugin *self, + GHashTable *compile_versions); +void fu_plugin_set_smbios (FuPlugin *self, FuSmbios *smbios); -guint fu_plugin_get_order (FuPlugin *plugin); -void fu_plugin_set_order (FuPlugin *plugin, +guint fu_plugin_get_order (FuPlugin *self); +void fu_plugin_set_order (FuPlugin *self, guint order); -void fu_plugin_set_name (FuPlugin *plugin, +guint fu_plugin_get_priority (FuPlugin *self); +void fu_plugin_set_priority (FuPlugin *self, + guint priority); +void fu_plugin_set_name (FuPlugin *self, const gchar *name); -GPtrArray *fu_plugin_get_rules (FuPlugin *plugin, +const gchar *fu_plugin_get_build_hash (FuPlugin *self); +GPtrArray *fu_plugin_get_rules (FuPlugin *self, FuPluginRule rule); -GHashTable *fu_plugin_get_report_metadata (FuPlugin *plugin); -gboolean fu_plugin_open (FuPlugin *plugin, +gboolean fu_plugin_has_rule (FuPlugin *self, + FuPluginRule rule, + const gchar *name); +GHashTable *fu_plugin_get_report_metadata (FuPlugin *self); +gboolean fu_plugin_open (FuPlugin *self, const gchar *filename, GError **error); -gboolean fu_plugin_runner_startup (FuPlugin *plugin, +gboolean fu_plugin_runner_startup (FuPlugin *self, GError **error); -gboolean fu_plugin_runner_coldplug (FuPlugin *plugin, +gboolean fu_plugin_runner_coldplug (FuPlugin *self, GError **error); -gboolean fu_plugin_runner_coldplug_prepare (FuPlugin *plugin, +gboolean fu_plugin_runner_coldplug_prepare (FuPlugin *self, GError **error); -gboolean fu_plugin_runner_coldplug_cleanup (FuPlugin *plugin, +gboolean fu_plugin_runner_coldplug_cleanup (FuPlugin *self, GError **error); -gboolean fu_plugin_runner_recoldplug (FuPlugin *plugin, +gboolean fu_plugin_runner_recoldplug (FuPlugin *self, GError **error); -gboolean fu_plugin_runner_update_prepare (FuPlugin *plugin, +gboolean fu_plugin_runner_update_prepare (FuPlugin *self, + FwupdInstallFlags flags, FuDevice *device, GError **error); -gboolean fu_plugin_runner_update_cleanup (FuPlugin *plugin, +gboolean fu_plugin_runner_update_cleanup (FuPlugin *self, + FwupdInstallFlags flags, FuDevice *device, GError **error); -gboolean fu_plugin_runner_update_attach (FuPlugin *plugin, +gboolean fu_plugin_runner_composite_prepare (FuPlugin *self, + GPtrArray *devices, + GError **error); +gboolean fu_plugin_runner_composite_cleanup (FuPlugin *self, + GPtrArray *devices, + GError **error); +gboolean fu_plugin_runner_update_attach (FuPlugin *self, FuDevice *device, GError **error); -gboolean fu_plugin_runner_update_detach (FuPlugin *plugin, +gboolean fu_plugin_runner_update_detach (FuPlugin *self, FuDevice *device, GError **error); -gboolean fu_plugin_runner_update_reload (FuPlugin *plugin, +gboolean fu_plugin_runner_update_reload (FuPlugin *self, FuDevice *device, GError **error); -gboolean fu_plugin_runner_usb_device_added (FuPlugin *plugin, - GUsbDevice *usb_device, +gboolean fu_plugin_runner_usb_device_added (FuPlugin *self, + FuUsbDevice *device, + GError **error); +gboolean fu_plugin_runner_udev_device_added (FuPlugin *self, + FuUdevDevice *device, GError **error); -void fu_plugin_runner_device_register (FuPlugin *plugin, +void fu_plugin_runner_device_removed (FuPlugin *self, FuDevice *device); -gboolean fu_plugin_runner_update (FuPlugin *plugin, +void fu_plugin_runner_device_register (FuPlugin *self, + FuDevice *device); +gboolean fu_plugin_runner_update (FuPlugin *self, FuDevice *device, - GBytes *blob_cab, GBytes *blob_fw, FwupdInstallFlags flags, GError **error); -gboolean fu_plugin_runner_verify (FuPlugin *plugin, +gboolean fu_plugin_runner_verify (FuPlugin *self, FuDevice *device, FuPluginVerifyFlags flags, GError **error); -gboolean fu_plugin_runner_unlock (FuPlugin *plugin, +gboolean fu_plugin_runner_activate (FuPlugin *self, + FuDevice *device, + GError **error); +gboolean fu_plugin_runner_unlock (FuPlugin *self, + FuDevice *device, + GError **error); +gboolean fu_plugin_runner_clear_results (FuPlugin *self, FuDevice *device, GError **error); -gboolean fu_plugin_runner_clear_results (FuPlugin *plugin, +gboolean fu_plugin_runner_get_results (FuPlugin *self, FuDevice *device, GError **error); -gboolean fu_plugin_runner_get_results (FuPlugin *plugin, +gboolean fu_plugin_runner_schedule_update (FuPlugin *self, FuDevice *device, + FwupdRelease *release, + GBytes *blob_cab, + FwupdInstallFlags flags, GError **error); +gint fu_plugin_name_compare (FuPlugin *plugin1, + FuPlugin *plugin2); +gint fu_plugin_order_compare (FuPlugin *plugin1, + FuPlugin *plugin2); -G_END_DECLS +/* utils */ +gchar *fu_plugin_guess_name_from_fn (const gchar *filename); -#endif /* __FU_PLUGIN_PRIVATE_H */ +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-plugin-vfuncs.h fwupd-1.2.10/src/fu-plugin-vfuncs.h --- fwupd-1.0.6/src/fu-plugin-vfuncs.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-plugin-vfuncs.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,14 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2016-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PLUGIN_VFUNCS_H -#define __FU_PLUGIN_VFUNCS_H +#pragma once #include "fu-plugin.h" #include "fu-device.h" +#include "fu-hash.h" G_BEGIN_DECLS @@ -48,9 +33,18 @@ FuDevice *dev, FuPluginVerifyFlags flags, GError **error); +gboolean fu_plugin_verify_attach (FuPlugin *plugin, + FuDevice *dev, + GError **error); +gboolean fu_plugin_verify_detach (FuPlugin *plugin, + FuDevice *dev, + GError **error); gboolean fu_plugin_unlock (FuPlugin *plugin, FuDevice *dev, GError **error); +gboolean fu_plugin_activate (FuPlugin *plugin, + FuDevice *dev, + GError **error); gboolean fu_plugin_clear_results (FuPlugin *plugin, FuDevice *dev, GError **error); @@ -67,17 +61,29 @@ FuDevice *dev, GError **error); gboolean fu_plugin_update_prepare (FuPlugin *plugin, + FwupdInstallFlags flags, FuDevice *dev, GError **error); gboolean fu_plugin_update_cleanup (FuPlugin *plugin, + FwupdInstallFlags flags, FuDevice *dev, GError **error); +gboolean fu_plugin_composite_prepare (FuPlugin *plugin, + GPtrArray *devices, + GError **error); +gboolean fu_plugin_composite_cleanup (FuPlugin *plugin, + GPtrArray *devices, + GError **error); gboolean fu_plugin_usb_device_added (FuPlugin *plugin, - GUsbDevice *usb_device, + FuUsbDevice *device, + GError **error); +gboolean fu_plugin_udev_device_added (FuPlugin *plugin, + FuUdevDevice *device, + GError **error); +gboolean fu_plugin_device_removed (FuPlugin *plugin, + FuDevice *device, GError **error); void fu_plugin_device_registered (FuPlugin *plugin, FuDevice *dev); G_END_DECLS - -#endif /* __FU_PLUGIN_VFUNCS_H */ diff -Nru fwupd-1.0.6/src/fu-progressbar.c fwupd-1.2.10/src/fu-progressbar.c --- fwupd-1.0.6/src/fu-progressbar.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-progressbar.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,14 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuProgressBar" + #include "config.h" +#include #include #include "fu-progressbar.h" @@ -39,6 +27,9 @@ guint to_erase; /* chars */ guint timer_id; gint64 last_animated; /* monotonic */ + GTimer *time_elapsed; + gdouble last_estimate; + gboolean interactive; }; G_DEFINE_TYPE (FuProgressbar, fu_progressbar, G_TYPE_OBJECT) @@ -104,6 +95,53 @@ } static void +fu_progressbar_erase_line (FuProgressbar *self) +{ + if (!self->interactive) + return; + for (guint i = 0; i < self->to_erase; i++) + g_print ("\b"); + self->to_erase = 0; +} + +static gboolean +fu_progressbar_estimate_ready (FuProgressbar *self, guint percentage) +{ + gdouble old; + gdouble elapsed; + + if (percentage == 0 || percentage == 100) + return FALSE; + + old = self->last_estimate; + elapsed = g_timer_elapsed (self->time_elapsed, NULL); + self->last_estimate = elapsed / percentage * (100 - percentage); + + /* estimate is ready if we have decreased */ + return old > self->last_estimate; +} + +static gchar * +fu_progressbar_time_remaining_str (FuProgressbar *self) +{ + /* less than 5 seconds remaining */ + if (self->last_estimate < 5) + return NULL; + + /* less than 60 seconds remaining */ + if (self->last_estimate < 60) { + /* TRANSLATORS: time remaining for completing firmware flash */ + return g_strdup (_("Less than one minute remaining")); + } + + /* more than a minute */ + return g_strdup_printf (ngettext ("%.0f minute remaining", + "%.0f minutes remaining", + self->last_estimate / 60), + self->last_estimate / 60); +} + +static void fu_progressbar_refresh (FuProgressbar *self, FwupdStatus status, guint percentage) { const gchar *title; @@ -112,8 +150,7 @@ g_autoptr(GString) str = g_string_new (NULL); /* erase previous line */ - for (i = 0; i < self->to_erase; i++) - g_print ("\b"); + fu_progressbar_erase_line (self); /* add status */ if (status == FWUPD_STATUS_IDLE) { @@ -123,7 +160,7 @@ } title = fu_progressbar_status_to_string (status); g_string_append (str, title); - for (i = str->len; i < self->length_status; i++) + for (i = g_utf8_strlen (str->str, -1); i < self->length_status; i++) g_string_append_c (str, ' '); /* add progressbar */ @@ -143,9 +180,16 @@ } g_string_append_c (str, ']'); + /* once we have good data show an estimate of time remaining */ + if (fu_progressbar_estimate_ready (self, percentage)) { + g_autofree gchar *remaining = fu_progressbar_time_remaining_str (self); + if (remaining != NULL) + g_string_append_printf (str, " %s…", remaining); + } + /* dump to screen */ g_print ("%s", str->str); - self->to_erase = str->len - 2; + self->to_erase = str->len; /* done */ if (is_idle_newline) { @@ -155,6 +199,14 @@ } } +void +fu_progressbar_set_title (FuProgressbar *self, const gchar *title) +{ + fu_progressbar_erase_line (self); + g_print ("%s\n", title); + fu_progressbar_refresh (self, self->status, self->percentage); +} + static void fu_progressbar_spin_inc (FuProgressbar *self) { @@ -195,6 +247,9 @@ if (self->timer_id != 0) { g_source_remove (self->timer_id); self->timer_id = 0; + + /* reset when the spinner has been stopped */ + g_timer_start (self->time_elapsed); } /* go back to the start when we next go into unknown percentage mode */ @@ -219,6 +274,14 @@ if (status == FWUPD_STATUS_UNKNOWN) status = self->status; + if (!self->interactive) { + if (self->status != status) { + g_debug ("%s\n", fu_progressbar_status_to_string (status)); + self->status = status; + } + return; + } + /* if the main loop isn't spinning and we've not had a chance to * execute the callback just do the refresh now manually */ if (percentage == 0 && @@ -251,6 +314,13 @@ } void +fu_progressbar_set_interactive (FuProgressbar *self, gboolean interactive) +{ + g_return_if_fail (FU_IS_PROGRESSBAR (self)); + self->interactive = interactive; +} + +void fu_progressbar_set_length_status (FuProgressbar *self, guint len) { g_return_if_fail (FU_IS_PROGRESSBAR (self)); @@ -279,6 +349,8 @@ self->length_percentage = 40; self->length_status = 25; self->spinner_count_up = TRUE; + self->time_elapsed = g_timer_new (); + self->interactive = TRUE; } static void @@ -288,6 +360,7 @@ if (self->timer_id != 0) g_source_remove (self->timer_id); + g_timer_destroy (self->time_elapsed); G_OBJECT_CLASS (fu_progressbar_parent_class)->finalize (obj); } diff -Nru fwupd-1.0.6/src/fu-progressbar.h fwupd-1.2.10/src/fu-progressbar.h --- fwupd-1.0.6/src/fu-progressbar.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-progressbar.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_PROGRESSBAR_H -#define __FU_PROGRESSBAR_H +#pragma once #include @@ -39,8 +23,9 @@ guint len); void fu_progressbar_set_length_percentage (FuProgressbar *self, guint len); +void fu_progressbar_set_title (FuProgressbar *self, + const gchar *title); +void fu_progressbar_set_interactive (FuProgressbar *self, + gboolean interactive); G_END_DECLS - -#endif /* __FU_PROGRESSBAR_H */ - diff -Nru fwupd-1.0.6/src/fu-quirks.c fwupd-1.2.10/src/fu-quirks.c --- fwupd-1.0.6/src/fu-quirks.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-quirks.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,33 +1,22 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017-2018 Richard Hughes * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuQuirks" + #include "config.h" #include #include -#include #include +#include "fu-common.h" +#include "fu-mutex.h" #include "fu-quirks.h" +#include "fwupd-common.h" #include "fwupd-error.h" #include "fwupd-remote-private.h" @@ -62,7 +51,8 @@ { GObject parent_instance; GPtrArray *monitors; - GHashTable *hash; /* of prefix/id:string */ + GHashTable *hash; /* of group:{key:value} */ + GRWLock hash_mutex; }; G_DEFINE_TYPE (FuQuirks, fu_quirks, G_TYPE_OBJECT) @@ -98,11 +88,30 @@ return TRUE; } +static gchar * +fu_quirks_build_group_key (const gchar *group) +{ + const gchar *guid_prefixes[] = { "DeviceInstanceId=", "Guid=", "HwId=", NULL }; + + /* this is a GUID */ + for (guint i = 0; guid_prefixes[i] != NULL; i++) { + if (g_str_has_prefix (group, guid_prefixes[i])) { + gsize len = strlen (guid_prefixes[i]); + if (fwupd_guid_is_valid (group + len)) + return g_strdup (group + len); + return fwupd_guid_hash_string (group + len); + } + } + + /* fallback */ + return g_strdup (group); +} + /** * fu_quirks_lookup_by_id: * @self: A #FuPlugin - * @prefix: A string prefix that matches the quirks file basename, e.g. "dfu-quirks" - * @id: An ID to match the entry, e.g. "012345" + * @group: A string group, e.g. "DeviceInstanceId=USB\VID_1235&PID_AB11" + * @key: An ID to match the entry, e.g. "Name" * * Looks up an entry in the hardware database using a string value. * @@ -111,102 +120,116 @@ * Since: 1.0.1 **/ const gchar * -fu_quirks_lookup_by_id (FuQuirks *self, const gchar *prefix, const gchar *id) +fu_quirks_lookup_by_id (FuQuirks *self, const gchar *group, const gchar *key) { - g_autofree gchar *key = NULL; + GHashTable *kvs; + g_autofree gchar *group_key = NULL; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->hash_mutex); g_return_val_if_fail (FU_IS_QUIRKS (self), NULL); - g_return_val_if_fail (prefix != NULL, NULL); - g_return_val_if_fail (id != NULL, NULL); - - key = g_strdup_printf ("%s/%s", prefix, id); - return g_hash_table_lookup (self->hash, key); + g_return_val_if_fail (group != NULL, NULL); + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (locker != NULL, NULL); + + group_key = fu_quirks_build_group_key (group); + kvs = g_hash_table_lookup (self->hash, group_key); + if (kvs == NULL) + return NULL; + return g_hash_table_lookup (kvs, key); } /** - * fu_quirks_lookup_by_glob: + * fu_quirks_get_kvs_for_guid: * @self: A #FuPlugin - * @prefix: A string prefix that matches the quirks file basename, e.g. "dfu-quirks" - * @glob: An glob to match the entry, e.g. "foo*bar?baz" + * @guid: a GUID + * @iter: A #GHashTableIter, typically allocated on the stack by the caller * - * Looks up an entry in the hardware database using a key glob. - * NOTE: This is *much* slower than using fu_quirks_lookup_by_id() as each key - * in the quirk database is compared. + * Looks up all entries in the hardware database using a GUID value. * - * Returns: (transfer none): values from the database, or %NULL if not found + * Returns: %TRUE if the GUID was found, and @iter was set * - * Since: 1.0.1 + * Since: 1.1.2 **/ -const gchar * -fu_quirks_lookup_by_glob (FuQuirks *self, const gchar *prefix, const gchar *glob) +gboolean +fu_quirks_get_kvs_for_guid (FuQuirks *self, const gchar *guid, GHashTableIter *iter) { - g_autoptr(GList) keys = NULL; - gsize prefix_len; - - g_return_val_if_fail (FU_IS_QUIRKS (self), NULL); - g_return_val_if_fail (prefix != NULL, NULL); - g_return_val_if_fail (glob != NULL, NULL); + GHashTable *kvs; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->hash_mutex); + g_return_val_if_fail (locker != NULL, FALSE); + kvs = g_hash_table_lookup (self->hash, guid); + if (kvs == NULL) + return FALSE; + g_hash_table_iter_init (iter, kvs); + return TRUE; +} - prefix_len = strlen (prefix); - keys = g_hash_table_get_keys (self->hash); - for (GList *l = keys; l != NULL; l = l->next) { - const gchar *id = l->data; - if (strncmp (id, prefix, prefix_len) != 0) - continue; - id += prefix_len + 1; - if (fnmatch (glob, id, 0) == 0) - return fu_quirks_lookup_by_id (self, prefix, id); - if (fnmatch (id, glob, 0) == 0) - return fu_quirks_lookup_by_id (self, prefix, id); +static gchar * +fu_quirks_merge_values (const gchar *old, const gchar *new) +{ + guint cnt = 0; + g_autofree gchar **resv = NULL; + g_auto(GStrv) newv = g_strsplit (new, ",", -1); + g_auto(GStrv) oldv = g_strsplit (old, ",", -1); + + /* segment flags, and append if they do not already exists */ + resv = g_new0 (gchar *, g_strv_length (oldv) + g_strv_length (newv) + 1); + for (guint i = 0; oldv[i] != NULL; i++) { + if (!g_strv_contains ((const gchar * const *) resv, oldv[i])) + resv[cnt++] = oldv[i]; + } + for (guint i = 0; newv[i] != NULL; i++) { + if (!g_strv_contains ((const gchar * const *) resv, newv[i])) + resv[cnt++] = newv[i]; } - return NULL; + return g_strjoinv (",", resv); } /** - * fu_quirks_lookup_by_usb_device: - * @self: A #FuPlugin - * @prefix: A string prefix that matches the quirks file basename, e.g. "dfu-quirks" - * @dev: A #GUsbDevice + * fu_quirks_add_value: (skip) + * @self: A #FuQuirks + * @group: group, e.g. `DeviceInstanceId=USB\VID_0BDA&PID_1100` + * @key: group, e.g. `Name` + * @value: group, e.g. `Unknown Device` * - * Looks up an entry in the hardware database using various keys generated - * from @dev. + * Adds a value to the quirk database. Normally this is achieved by loading a + * quirk file using fu_quirks_load(). * - * Returns: (transfer none): values from the database, or %NULL if not found - * - * Since: 1.0.1 + * Since: 1.1.2 **/ -const gchar * -fu_quirks_lookup_by_usb_device (FuQuirks *self, const gchar *prefix, GUsbDevice *dev) +void +fu_quirks_add_value (FuQuirks *self, const gchar *group, const gchar *key, const gchar *value) { - const gchar *tmp; - g_autofree gchar *key1 = NULL; - g_autofree gchar *key2 = NULL; - g_autofree gchar *key3 = NULL; - - g_return_val_if_fail (FU_IS_QUIRKS (self), NULL); - g_return_val_if_fail (prefix != NULL, NULL); - g_return_val_if_fail (G_USB_IS_DEVICE (dev), NULL); + GHashTable *kvs; + const gchar *value_old; + g_autofree gchar *group_key = NULL; + g_autofree gchar *value_new = NULL; + g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_writer_locker_new (&self->hash_mutex); + + g_return_if_fail (locker != NULL); + + /* does the key already exists in our hash */ + group_key = fu_quirks_build_group_key (group); + kvs = g_hash_table_lookup (self->hash, group_key); + if (kvs == NULL) { + kvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert (self->hash, + g_steal_pointer (&group_key), + kvs); + value_new = g_strdup (value); + } else { + /* look up in the 2nd level hash */ + value_old = g_hash_table_lookup (kvs, key); + if (value_old != NULL) { + g_debug ("already found %s=%s, merging with %s", + group_key, value_old, value); + value_new = fu_quirks_merge_values (value_old, value); + } else { + value_new = g_strdup (value); + } + } - /* prefer an exact match, VID:PID:REV */ - key1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&REV_%04X", - g_usb_device_get_vid (dev), - g_usb_device_get_pid (dev), - g_usb_device_get_release (dev)); - tmp = fu_quirks_lookup_by_id (self, prefix, key1); - if (tmp != NULL) - return tmp; - - /* VID:PID */ - key2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - g_usb_device_get_vid (dev), - g_usb_device_get_pid (dev)); - tmp = fu_quirks_lookup_by_id (self, prefix, key2); - if (tmp != NULL) - return tmp; - - /* VID */ - key3 = g_strdup_printf ("USB\\VID_%04X", g_usb_device_get_vid (dev)); - return fu_quirks_lookup_by_id (self, prefix, key3); + /* insert the new value */ + g_hash_table_insert (kvs, g_strdup (key), g_steal_pointer (&value_new)); } static gboolean @@ -227,16 +250,14 @@ if (keys == NULL) return FALSE; for (guint j = 0; keys[j] != NULL; j++) { - g_autofree gchar *tmp = NULL; - tmp = g_key_file_get_value (kf, groups[i], keys[j], error); - if (tmp == NULL) + g_autofree gchar *value = NULL; + /* get value from keyfile */ + value = g_key_file_get_value (kf, groups[i], keys[j], error); + if (value == NULL) return FALSE; - g_hash_table_insert (self->hash, - g_strdup_printf ("%s/%s", groups[i], keys[j]), - g_steal_pointer (&tmp)); + fu_quirks_add_value (self, groups[i], keys[j], value); } } - g_debug ("now %u quirk entries", g_hash_table_size (self->hash)); return TRUE; } @@ -293,6 +314,7 @@ } /* success */ + g_debug ("now %u quirk entries", g_hash_table_size (self->hash)); return TRUE; } @@ -310,20 +332,25 @@ gboolean fu_quirks_load (FuQuirks *self, GError **error) { - g_autofree gchar *localstate_fwupd = NULL; + g_autofree gchar *datadir = NULL; + g_autofree gchar *localstatedir = NULL; + g_return_val_if_fail (FU_IS_QUIRKS (self), FALSE); /* ensure empty in case we're called from a monitor change */ g_ptr_array_set_size (self->monitors, 0); + g_rw_lock_writer_lock (&self->hash_mutex); g_hash_table_remove_all (self->hash); + g_rw_lock_writer_unlock (&self->hash_mutex); /* system datadir */ - if (!fu_quirks_add_quirks_for_path (self, FWUPDDATADIR, error)) + datadir = fu_common_get_path (FU_PATH_KIND_DATADIR_PKG); + if (!fu_quirks_add_quirks_for_path (self, datadir, error)) return FALSE; /* something we can write when using Ostree */ - localstate_fwupd = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); - if (!fu_quirks_add_quirks_for_path (self, localstate_fwupd, error)) + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + if (!fu_quirks_add_quirks_for_path (self, localstatedir, error)) return FALSE; /* success */ @@ -341,7 +368,8 @@ fu_quirks_init (FuQuirks *self) { self->monitors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - self->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + self->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_unref); + g_rw_lock_init (&self->hash_mutex); } static void @@ -349,6 +377,7 @@ { FuQuirks *self = FU_QUIRKS (obj); g_ptr_array_unref (self->monitors); + g_rw_lock_clear (&self->hash_mutex); g_hash_table_unref (self->hash); G_OBJECT_CLASS (fu_quirks_parent_class)->finalize (obj); } diff -Nru fwupd-1.0.6/src/fu-quirks.h fwupd-1.2.10/src/fu-quirks.h --- fwupd-1.0.6/src/fu-quirks.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-quirks.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,32 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2016 Mario Limonciello +/* + * Copyright (C) 2016 Mario Limonciello * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_QUIRKS_H -#define __FU_QUIRKS_H - -G_BEGIN_DECLS +#pragma once #include -#include + +G_BEGIN_DECLS #define FU_TYPE_QUIRKS (fu_quirks_get_type ()) G_DECLARE_FINAL_TYPE (FuQuirks, fu_quirks, FU, QUIRKS, GObject) @@ -35,213 +18,34 @@ gboolean fu_quirks_load (FuQuirks *self, GError **error); const gchar *fu_quirks_lookup_by_id (FuQuirks *self, - const gchar *prefix, - const gchar *id); -const gchar *fu_quirks_lookup_by_glob (FuQuirks *self, - const gchar *prefix, - const gchar *glob); -const gchar *fu_quirks_lookup_by_usb_device (FuQuirks *self, - const gchar *prefix, - GUsbDevice *dev); - -/** - * FU_QUIRKS_DFU: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: a string, separated using `|`, e.g. `ignore-polltimeout|no-pid-change` - * - * Assigns optional quirks to use for a DFU device which does not follow the - * DFU 1.0 or 1.1 specification. The list of supported quirks is thus: - * - * * `none`: No device quirks - * * `action-required`: User has to do something manually, e.g. press a button - * * `attach-extra-reset`: Device needs resetting twice for attach - * * `attach-upload-download`: An upload or download is required for attach - * * `force-dfu-mode`: Force DFU mode - * * `ignore-polltimeout`: Ignore the device download timeout - * * `ignore-runtime`: Device has broken DFU runtime support - * * `ignore-upload`: Uploading from the device is broken - * * `no-dfu-runtime`: No DFU runtime interface is provided - * * `no-get-status-upload`: Do not do GetStatus when uploading - * * `no-pid-change`: Accept the same VID:PID when changing modes - * * `use-any-interface`: Use any interface for DFU - * * `use-atmel-avr`: Device uses the ATMEL bootloader - * * `use-protocol-zero`: Fix up the protocol number - * * `legacy-protocol`: Use a legacy protocol version - * - * Default value: `none` - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU "fwupd-dfu" - -/** - * FU_QUIRKS_UEFI_VERSION_FORMAT: - * @key: a %FU_HWIDS_KEY_MANUFACTURER, e.g. `Alienware` - * @value: the version format, e.g. `none` - * - * Assigns the version format to use for a specific manufacturer. - * A specific version format is sometimes chosen to match the appearance of - * other systems or specifications. - * - * Default value: `use-triplet` - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_UEFI_VERSION_FORMAT "fwupd-uefi-version-format" - -/** - * FU_QUIRKS_DAEMON_VERSION_FORMAT: - * @key: the optionally wildcarded AppStream ID e.g. `com.dell.uefi*.firmware` - * @value: the version format, e.g. `none` - * - * Assigns the version format to use for a specific AppStream component. - * A specific version format is sometimes chosen to match the appearance of - * other systems or specifications. - * - * Default value: `use-triplet` - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DAEMON_VERSION_FORMAT "fwupd-daemon-version-format" - -/** - * FU_QUIRKS_DFU_JABRA_DETACH: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the two uint8_t unlock values, encoded in base 16, e.g. `0201` - * - * Assigns the two magic bytes sent to the Jabra hardware when the device is - * in runtime mode to make it switch into DFU mode. - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU_JABRA_DETACH "fwupd-dfu-jabra-detach" - -/** - * FU_QUIRKS_DFU_AVR_CHIP_ID: - * @key: the AVR chip ID, e.g. `0x58200204` - * @value: the UM0424 sector description, e.g. `@Flash/0x2000/1*248Kg` - * - * Assigns a sector description for the chip ID. This is required so fwupd can - * program the user firmware avoiding the bootloader and for checking the total - * element size. - * - * The chip ID can be found from a datasheet or using `dfu-tool list` when the - * hardware is connected and in bootloader mode. - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU_AVR_CHIP_ID "fwupd-dfu-avr-chip-id" - -/** - * FU_QUIRKS_DFU_FORCE_VERSION: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the uint16_t DFU version, encoded in base 16, e.g. `0110` - * - * Forces a specific DFU version for the hardware device. This is required - * if the device does not set, or sets incorrectly, items in the DFU functional - * descriptor. - * - * Since: 1.0.1 - */ -#define FU_QUIRKS_DFU_FORCE_VERSION "fwupd-dfu-force-version" - -/** - * FU_QUIRKS_USB_SUMMARY: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the USB device summary, e.g. `An open source display colorimeter` - * - * Sets a name for a specific hardware device. - * - * Since: 1.0.2 - */ -#define FU_QUIRKS_USB_SUMMARY "FuUsbDevice:summary" - -/** - * FU_QUIRKS_USB_ICON: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the USB device icon name, e.g. `media-removable` - * - * Adds an icon name for a specific hardware device. - * - * Since: 1.0.2 - */ -#define FU_QUIRKS_USB_ICON "FuUsbDevice:icon" - -/** - * FU_QUIRKS_USB_NAME: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the USB device name, e.g. `ColorHug` - * - * Sets a name for a specific hardware device. - * - * Since: 1.0.2 - */ -#define FU_QUIRKS_USB_NAME "FuUsbDevice:name" - -/** - * FU_QUIRKS_USB_GUID: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` - * - * Adds an extra GUID for a specific hardware device. If the value provided is - * not already a suitable GUID, it will be converted to one. - * - * Since: 1.0.3 - */ -#define FU_QUIRKS_USB_GUID "FuUsbDevice:guid" - -/** - * FU_QUIRKS_USB_VERSION: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806&REV_0001` - * @value: the version number, e.g. `1.2` - * - * Sets a version for a specific hardware device. - * - * Since: 1.0.3 - */ -#define FU_QUIRKS_USB_VERSION "FuUsbDevice:version" - -/** - * FU_QUIRKS_USB_VENDOR: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the vendor, e.g. `Hughski Limited` - * - * Sets a vendor name for a specific hardware device. - * - * Since: 1.0.3 - */ -#define FU_QUIRKS_USB_VENDOR "FuUsbDevice:vendor" - -/** - * FU_QUIRKS_CSR: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the quirk, e.g. `require-delay` - * - * Assigns optional quirks to use for a CSR device which does not follow the - * CSR specification. The list of supported quirks is thus: - * - * * `none`: No device quirks - * * `require-delay`: Respect the write timeout value - * - * Since: 1.0.3 - */ -#define FU_QUIRKS_CSR_DEVICE "FuCsrDevice" - -/** - * FU_QUIRKS_EBITDO: - * @key: the USB device ID, e.g. `USB\VID_0763&PID_2806` - * @value: the quirk, e.g. `bootloader` - * - * Assigns optional quirks to use for a 8Bitdo device. The list of supported - * quirks is thus: - * - * * `none`: No device quirks - * * `bootloader`: Device is in bootloader mode - * - * Since: 1.0.3 - */ -#define FU_QUIRKS_EBITDO_DEVICE "FuEditdoDevice" + const gchar *group, + const gchar *key); +void fu_quirks_add_value (FuQuirks *self, + const gchar *group, + const gchar *key, + const gchar *value); +gboolean fu_quirks_get_kvs_for_guid (FuQuirks *self, + const gchar *guid, + GHashTableIter *iter); + +#define FU_QUIRKS_PLUGIN "Plugin" +#define FU_QUIRKS_UEFI_VERSION_FORMAT "UefiVersionFormat" +#define FU_QUIRKS_DAEMON_VERSION_FORMAT "ComponentIDs" +#define FU_QUIRKS_FLAGS "Flags" +#define FU_QUIRKS_SUMMARY "Summary" +#define FU_QUIRKS_ICON "Icon" +#define FU_QUIRKS_NAME "Name" +#define FU_QUIRKS_GUID "Guid" +#define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid" +#define FU_QUIRKS_PARENT_GUID "ParentGuid" +#define FU_QUIRKS_CHILDREN "Children" +#define FU_QUIRKS_VERSION "Version" +#define FU_QUIRKS_VENDOR "Vendor" +#define FU_QUIRKS_VENDOR_ID "VendorId" +#define FU_QUIRKS_FIRMWARE_SIZE_MIN "FirmwareSizeMin" +#define FU_QUIRKS_FIRMWARE_SIZE_MAX "FirmwareSizeMax" +#define FU_QUIRKS_FIRMWARE_SIZE "FirmwareSize" +#define FU_QUIRKS_INSTALL_DURATION "InstallDuration" +#define FU_QUIRKS_VERSION_FORMAT "VersionFormat" G_END_DECLS - -#endif /* __FU_QUIRKS_H */ diff -Nru fwupd-1.0.6/src/fu-self-test.c fwupd-1.2.10/src/fu-self-test.c --- fwupd-1.0.6/src/fu-self-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-self-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,27 +1,12 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" -#include +#include #include #include #include @@ -30,7 +15,10 @@ #include #include +#include "fu-archive.h" #include "fu-common-cab.h" +#include "fu-common-version.h" +#include "fu-chunk.h" #include "fu-config.h" #include "fu-device-list.h" #include "fu-device-private.h" @@ -38,9 +26,11 @@ #include "fu-quirks.h" #include "fu-keyring.h" #include "fu-history.h" +#include "fu-install-task.h" #include "fu-plugin-private.h" #include "fu-plugin-list.h" #include "fu-progressbar.h" +#include "fu-hash.h" #include "fu-hwids.h" #include "fu-smbios.h" #include "fu-test.h" @@ -53,19 +43,624 @@ #endif static void +fu_self_test_mkroot (void) +{ + if (g_file_test ("/tmp/fwupd-self-test", G_FILE_TEST_EXISTS)) { + g_autoptr(GError) error = NULL; + if (!fu_common_rmtree ("/tmp/fwupd-self-test", &error)) + g_warning ("failed to mkroot: %s", error->message); + } + g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); +} + +static void +fu_archive_invalid_func (void) +{ + g_autofree gchar *filename = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + + filename = fu_test_get_filename (TESTDATADIR, "metadata.xml"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + + archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_assert_null (archive); +} + +static void +fu_engine_generate_md_func (void) +{ + const gchar *tmp; + gboolean ret; + g_autofree gchar *filename = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + + /* put cab file somewhere we can parse it */ + filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + ret = fu_common_set_contents_bytes ("/tmp/fwupd-self-test/var/cache/fwupd/foo.cab", + data, &error); + g_assert_no_error (error); + g_assert (ret); + + /* load engine and check the device was found */ + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + component = fu_engine_get_component_by_guids (engine, device); + g_assert_nonnull (component); + + /* check remote ID set */ + tmp = xb_node_query_text (component, "../custom/value[@key='fwupd::RemoteId']", NULL); + g_assert_cmpstr (tmp, ==, "directory"); + + /* verify checksums */ + tmp = xb_node_query_text (component, "releases/release/checksum[@target='container']", NULL); + g_assert_cmpstr (tmp, !=, NULL); + tmp = xb_node_query_text (component, "releases/release/checksum[@target='content']", NULL); + g_assert_cmpstr (tmp, ==, NULL); +} + +static void +fu_archive_cab_func (void) +{ + g_autofree gchar *checksum1 = NULL; + g_autofree gchar *checksum2 = NULL; + g_autofree gchar *filename = NULL; + g_autoptr(FuArchive) archive = NULL; + g_autoptr(GBytes) data = NULL; + g_autoptr(GError) error = NULL; + GBytes *data_tmp; + + filename = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab"); + g_assert_nonnull (filename); + data = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert_nonnull (data); + + archive = fu_archive_new (data, FU_ARCHIVE_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert_nonnull (archive); + + data_tmp = fu_archive_lookup_by_fn (archive, "firmware.metainfo.xml", &error); + g_assert_no_error (error); + g_assert_nonnull (data_tmp); + checksum1 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp); + g_assert_cmpstr (checksum1, ==, "8611114f51f7151f190de86a5c9259d79ff34216"); + + data_tmp = fu_archive_lookup_by_fn (archive, "firmware.bin", &error); + g_assert_no_error (error); + g_assert_nonnull (data_tmp); + checksum2 = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, data_tmp); + g_assert_cmpstr (checksum2, ==, "7c0ae84b191822bcadbdcbe2f74a011695d783c7"); + + data_tmp = fu_archive_lookup_by_fn (archive, "NOTGOINGTOEXIST.xml", &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert_null (data_tmp); +} + +static void +fu_common_version_guess_format_func (void) +{ + g_assert_cmpint (fu_common_version_guess_format (NULL), ==, FWUPD_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format (""), ==, FWUPD_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1234ac"), ==, FWUPD_VERSION_FORMAT_PLAIN); + g_assert_cmpint (fu_common_version_guess_format ("1.2"), ==, FWUPD_VERSION_FORMAT_PAIR); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3"), ==, FWUPD_VERSION_FORMAT_TRIPLET); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4"), ==, FWUPD_VERSION_FORMAT_QUAD); + g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4.5"), ==, FWUPD_VERSION_FORMAT_UNKNOWN); + g_assert_cmpint (fu_common_version_guess_format ("1a.2b.3"), ==, FWUPD_VERSION_FORMAT_PLAIN); + g_assert_cmpint (fu_common_version_guess_format ("1"), ==, FWUPD_VERSION_FORMAT_NUMBER); + g_assert_cmpint (fu_common_version_guess_format ("0x10201"), ==, FWUPD_VERSION_FORMAT_NUMBER); +} + +static void +fu_engine_requirements_missing_func (void) +{ + gboolean ret; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " not.going.to.exist" + " " + ""; + + /* set up a dummy version */ + fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); + + /* make the component require one thing */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this fails */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert (!ret); +} + +static void +fu_engine_requirements_unsupported_func (void) +{ + gboolean ret; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + const gchar *xml = + "" + " " + " " + " " + ""; + + /* set up a dummy version */ + fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); + + /* make the component require one thing that we don't support */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this fails */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert (!ret); +} + +static void +fu_engine_requirements_child_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuDevice) child = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " not-child" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; + + /* set up a dummy device */ + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_bootloader (device, "4.5.6"); + fu_device_set_vendor_id (device, "FFFF"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_set_version (child, "0.0.999", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_child (device, child); + + /* make the component require three things */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (device, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + +static void +fu_engine_requirements_child_fail_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuDevice) child = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " not-child" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; + + /* set up a dummy device */ + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_bootloader (device, "4.5.6"); + fu_device_set_vendor_id (device, "FFFF"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_set_version (child, "0.0.1", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_child (device, child); + + /* make the component require three things */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (device, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert_nonnull (g_strstr_len (error->message, -1, + "Not compatible with child device version")); + g_assert (!ret); +} + +static void +fu_engine_requirements_func (void) +{ + gboolean ret; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " org.test.dummy" + " " + ""; + + /* set up some dummy versions */ + fu_engine_add_runtime_version (engine, "org.test.dummy", "1.2.3"); + fu_engine_add_runtime_version (engine, "com.hughski.colorhug", "7.8.9"); + + /* make the component require one thing */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (NULL, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + +static void +fu_engine_requirements_device_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " " + " bootloader" + " vendor-id" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; + + /* set up a dummy device */ + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_version_bootloader (device, "4.5.6"); + fu_device_set_vendor_id (device, "FFFF"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + + /* make the component require three things */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (device, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + +static void +fu_engine_requirements_version_format_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + const gchar *xml = + "" + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + " " + " triplet" + " " + ""; + + /* set up a dummy device */ + fu_device_set_version (device, "1.2.3.4", FWUPD_VERSION_FORMAT_QUAD); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + + /* make the component require three things */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this fails */ + task = fu_install_task_new (device, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); + g_assert_nonnull (g_strstr_len (error->message, -1, + "Firmware version formats were different")); + g_assert (!ret); +} + +static void +fu_engine_requirements_other_device_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device1 = fu_device_new (); + g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + const gchar *xml = + "" + " " + " 1ff60ab2-3905-06a1-b476-0371f00c9e9b" + " " + " " + " 12345678-1234-1234-1234-123456789012" + " " + " " + " " + " " + " " + " " + ""; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* set up a dummy device */ + fu_device_set_version (device1, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_guid (device1, "12345678-1234-1234-1234-123456789012"); + + /* set up a different device */ + fu_device_set_id (device2, "id2"); + fu_device_set_name (device2, "Secondary firmware"); + fu_device_set_version (device2, "4.5.6", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_vendor_id (device2, "FFFF"); + fu_device_add_guid (device2, "1ff60ab2-3905-06a1-b476-0371f00c9e9b"); + fu_engine_add_device (engine, device2); + + /* import firmware metainfo */ + silo = xb_silo_new_from_xml (xml, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "component", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check this passes */ + task = fu_install_task_new (device1, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert (ret); +} + +static void +fu_engine_device_priority_func (void) +{ + g_autoptr(FuDevice) device1 = fu_device_new (); + g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuDevice) device3 = fu_device_new (); + g_autoptr(FuDevice) device = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GError) error = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* add low prio then high then low */ + fu_device_set_id (device1, "id1"); + fu_device_set_priority (device1, 0); + fu_device_set_plugin (device1, "udev"); + fu_device_add_instance_id (device1, "GUID1"); + fu_device_convert_instance_ids (device1); + fu_engine_add_device (engine, device1); + fu_device_set_id (device2, "id2"); + fu_device_set_priority (device2, 1); + fu_device_set_plugin (device2, "redfish"); + fu_device_add_instance_id (device2, "GUID1"); + fu_device_convert_instance_ids (device2); + fu_engine_add_device (engine, device2); + fu_device_set_id (device3, "id3"); + fu_device_set_priority (device3, 0); + fu_device_set_plugin (device3, "uefi"); + fu_device_add_instance_id (device3, "GUID1"); + fu_device_convert_instance_ids (device3); + fu_engine_add_device (engine, device3); + + /* get the high prio device */ + device = fu_engine_get_device (engine, "867d5f8110f8aa79dd63d7440f21724264f10430", &error); + g_assert_no_error (error); + g_assert_cmpint (fu_device_get_priority (device), ==, 1); + g_clear_object (&device); + + /* the now-removed low-prio device */ + device = fu_engine_get_device (engine, "4e89d81a2e6fb4be2578d245fd8511c1f4ad0b58", &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert_null (device); + g_clear_error (&error); + + /* the never-added 2nd low-prio device */ + device = fu_engine_get_device (engine, "c48feddbbcfee514f530ce8f7f2dccd98b6cc150", &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert_null (device); +} + +static void +fu_engine_device_parent_func (void) +{ + g_autoptr(FuDevice) device1 = fu_device_new (); + g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuDevice) device3 = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* add child */ + fu_device_set_id (device1, "child"); + fu_device_add_instance_id (device1, "child-GUID-1"); + fu_device_add_parent_guid (device1, "parent-GUID"); + fu_device_convert_instance_ids (device1); + fu_engine_add_device (engine, device1); + + /* parent */ + fu_device_set_id (device2, "parent"); + fu_device_add_instance_id (device2, "parent-GUID"); + fu_device_set_vendor (device2, "oem"); + fu_device_convert_instance_ids (device2); + + /* add another child */ + fu_device_set_id (device3, "child2"); + fu_device_add_instance_id (device3, "child-GUID-2"); + fu_device_add_parent_guid (device3, "parent-GUID"); + fu_device_convert_instance_ids (device3); + fu_device_add_child (device2, device3); + + /* add two together */ + fu_engine_add_device (engine, device2); + + /* verify both children were adopted */ + g_assert (fu_device_get_parent (device3) == device2); + g_assert (fu_device_get_parent (device1) == device2); + g_assert_cmpstr (fu_device_get_vendor (device3), ==, "oem"); + g_assert_cmpstr (fu_device_get_vendor (device1), ==, "oem"); + + /* verify order */ + g_assert_cmpint (fu_device_get_order (device1), ==, 0); + g_assert_cmpint (fu_device_get_order (device2), ==, 1); + g_assert_cmpint (fu_device_get_order (device3), ==, 0); +} + +static void fu_engine_partial_hash_func (void) { gboolean ret; g_autoptr(FuDevice) device1 = fu_device_new (); g_autoptr(FuDevice) device2 = fu_device_new (); - g_autoptr(FuEngine) engine = fu_engine_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuPlugin) plugin = fu_plugin_new (); g_autoptr(GError) error = NULL; g_autoptr(GError) error_none = NULL; g_autoptr(GError) error_both = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ fu_plugin_set_name (plugin, "test"); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_engine_add_plugin (engine, plugin); /* add two dummy devices */ @@ -112,20 +707,62 @@ } static void +fu_engine_device_unlock_func (void) +{ + gboolean ret; + g_autofree gchar *filename = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbSilo) silo = NULL; + + /* load engine to get FuConfig set up */ + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add the hardcoded 'fwupd' metadata */ + filename = fu_test_get_filename (TESTDATADIR, "metadata.xml"); + g_assert (filename != NULL); + file = g_file_new_for_path (filename); + ret = xb_builder_source_load_file (source, file, + XB_BUILDER_SOURCE_FLAG_NONE, + NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + fu_engine_set_silo (engine, silo); + + /* add a dummy device */ + fu_device_set_id (device, "UEFI-dummy-dev0"); + fu_device_add_guid (device, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_LOCKED); + fu_device_set_version_format (device, FWUPD_VERSION_FORMAT_PLAIN); + fu_engine_add_device (engine, device); + + /* ensure the metainfo was matched */ + g_assert_nonnull (fwupd_device_get_release_default (FWUPD_DEVICE (device))); +} + +static void fu_engine_require_hwid_func (void) { gboolean ret; g_autofree gchar *filename = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device = fu_device_new (); - g_autoptr(FuEngine) engine = fu_engine_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; - -#if !AS_CHECK_VERSION(0,7,4) - g_test_skip ("HWID requirements only supported with appstream-glib 0.7.4"); - return; -#endif + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; #if !defined(HAVE_GCAB_0_8) && defined(__s390x__) /* See https://github.com/hughsie/fwupd/issues/318 for more information */ @@ -133,8 +770,11 @@ return; #endif + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + /* load engine to get FuConfig set up */ - ret = fu_engine_load (engine, &error); + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); @@ -144,19 +784,27 @@ blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* add a dummy device */ fu_device_set_id (device, "test_device"); + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_engine_add_device (engine, device); - /* install it */ - ret = fu_engine_install (engine, fu_device_get_id (device), - store, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); + /* get component */ + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* check requirements */ + task = fu_install_task_new (device, component); + ret = fu_engine_check_requirements (engine, task, + FWUPD_INSTALL_FLAG_NONE, + &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); g_assert (error != NULL); g_assert_cmpstr (error->message, ==, @@ -171,7 +819,7 @@ gboolean ret; g_autofree gchar *testdatadir = NULL; g_autoptr(FuDevice) device = fu_device_new (); - g_autoptr(FuEngine) engine = fu_engine_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GPtrArray) devices_pre = NULL; @@ -179,6 +827,13 @@ g_autoptr(GPtrArray) releases = NULL; g_autoptr(GPtrArray) releases_up = NULL; g_autoptr(GPtrArray) remotes = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* write a broken file */ ret = g_file_set_contents ("/tmp/fwupd-self-test/broken.xml.gz", @@ -246,14 +901,10 @@ g_assert_no_error (error); g_assert (ret); - /* expect just one broken remote to fail */ - g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, - "failed to load remote broken: *"); - testdatadir = fu_test_get_filename (TESTDATADIR, "."); g_assert (testdatadir != NULL); g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); - ret = fu_engine_load (engine, &error); + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE); @@ -263,7 +914,7 @@ remotes = fu_engine_get_remotes (engine, &error); g_assert_no_error (error); g_assert (remotes != NULL); - g_assert_cmpint (remotes->len, ==, 3); + g_assert_cmpint (remotes->len, ==, 4); /* ensure there are no devices already */ devices_pre = fu_engine_get_devices (engine, &error); @@ -272,7 +923,7 @@ g_clear_error (&error); /* add a device so we can get upgrades and downgrades */ - fu_device_set_version (device, "1.2.3"); + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_id (device, "test_device"); fu_device_set_name (device, "Test Device"); fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); @@ -291,6 +942,16 @@ g_assert (releases != NULL); g_assert_cmpint (releases->len, ==, 4); + /* no upgrades, as no firmware is approved */ + releases_up = fu_engine_get_upgrades (engine, fu_device_get_id (device), &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO); + g_assert_null (releases_up); + g_clear_error (&error); + + /* retry with approved firmware set */ + fu_engine_add_approved_firmware (engine, "deadbeefdeadbeefdeadbeefdeadbeef"); + fu_engine_add_approved_firmware (engine, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + /* upgrades */ releases_up = fu_engine_get_upgrades (engine, fu_device_get_id (device), &error); g_assert_no_error (error); @@ -313,25 +974,102 @@ } static void +fu_engine_install_duration_func (void) +{ + FwupdRelease *rel; + gboolean ret; + g_autofree gchar *testdatadir = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) releases = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* write the main file */ + ret = g_file_set_contents ("/tmp/fwupd-self-test/stable.xml", + "" + " " + " test" + " " + " aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + " " + " " + " " + " https://test.org/foo.cab" + " deadbeefdeadbeefdeadbeefdeadbeef" + " deadbeefdeadbeefdeadbeefdeadbeef" + " " + " " + " " + "", -1, &error); + g_assert_no_error (error); + g_assert (ret); + + testdatadir = fu_test_get_filename (TESTDATADIR, "."); + g_assert (testdatadir != NULL); + g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add a device so we can get the install duration */ + fu_device_set_version (device, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_id (device, "test_device"); + fu_device_add_guid (device, "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + fu_device_set_install_duration (device, 999); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_engine_add_device (engine, device); + devices = fu_engine_get_devices (engine, &error); + g_assert_no_error (error); + g_assert (devices != NULL); + g_assert_cmpint (devices->len, ==, 1); + g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_SUPPORTED)); + + /* check the release install duration */ + releases = fu_engine_get_releases (engine, fu_device_get_id (device), &error); + g_assert_no_error (error); + g_assert (releases != NULL); + g_assert_cmpint (releases->len, ==, 1); + rel = FWUPD_RELEASE (g_ptr_array_index (releases, 0)); + g_assert_cmpint (fwupd_release_get_install_duration (rel), ==, 120); +} + +static void fu_engine_history_func (void) { gboolean ret; + g_autofree gchar *checksum = NULL; g_autofree gchar *device_str_expected = NULL; g_autofree gchar *device_str = NULL; g_autofree gchar *filename = NULL; - g_autofree gchar *checksum = NULL; g_autofree gchar *testdatadir = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device2 = NULL; - g_autoptr(FwupdDevice) device3 = NULL; - g_autoptr(FwupdDevice) device4 = NULL; g_autoptr(FuDevice) device = fu_device_new (); - g_autoptr(FuEngine) engine = fu_engine_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuHistory) history = NULL; + g_autoptr(FuInstallTask) task = NULL; g_autoptr(FuPlugin) plugin = fu_plugin_new (); + g_autoptr(FwupdDevice) device3 = NULL; + g_autoptr(FwupdDevice) device4 = NULL; g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* ensure empty tree */ + fu_self_test_mkroot (); + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); @@ -342,17 +1080,18 @@ testdatadir = fu_test_get_filename (TESTDATADIR, "."); g_assert (testdatadir != NULL); g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); - ret = fu_engine_load (engine, &error); + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE); /* add a device so we can get upgrade it */ - fu_device_set_version (device, "1.2.2"); + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_id (device, "test_device"); fu_device_set_name (device, "Test Device"); fu_device_set_plugin (device, "test"); fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_add_checksum (device, "0123456789abcdef0123456789abcdef01234567"); fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); fu_device_set_created (device, 1515338000); fu_engine_add_device (engine, device); @@ -367,16 +1106,29 @@ blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); + + /* get component */ + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* set the counter */ + g_setenv ("FWUPD_PLUGIN_TEST", "another-write-required", TRUE); + fu_device_set_metadata_integer (device, "nr-update", 0); /* install it */ - ret = fu_engine_install (engine, fu_device_get_id (device), - store, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); + task = fu_install_task_new (device, component); + ret = fu_engine_install (engine, task, blob_cab, + FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); + /* check the write was done more than once */ + g_assert_cmpint (fu_device_get_metadata_integer (device, "nr-update"), ==, 2); + /* check the history database */ history = fu_history_new (); device2 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error); @@ -402,7 +1154,7 @@ " [Release]\n" " Version: 1.2.3\n" " Checksum: SHA1(%s)\n" - " TrustFlags: none\n", + " Flags: none\n", checksum); ret = fu_test_compare_lines (device_str, device_str_expected, &error); g_assert_no_error (error); @@ -428,24 +1180,134 @@ } static void +fu_engine_history_inherit (void) +{ + gboolean ret; + g_autofree gchar *filename = NULL; + g_autofree gchar *testdatadir = NULL; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(FuPlugin) plugin = fu_plugin_new (); + g_autoptr(GBytes) blob_cab = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* set up dummy plugin */ + g_setenv ("FWUPD_PLUGIN_TEST", "fail", TRUE); + ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); + g_assert_no_error (error); + g_assert (ret); + fu_engine_add_plugin (engine, plugin); + testdatadir = fu_test_get_filename (TESTDATADIR, "."); + g_assert (testdatadir != NULL); + g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE); + + /* add a device so we can get upgrade it */ + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_set_id (device, "test_device"); + fu_device_set_name (device, "Test Device"); + fu_device_set_plugin (device, "test"); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_set_created (device, 1515338000); + fu_engine_add_device (engine, device); + devices = fu_engine_get_devices (engine, &error); + g_assert_no_error (error); + g_assert (devices != NULL); + g_assert_cmpint (devices->len, ==, 1); + g_assert (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REGISTERED)); + + filename = fu_test_get_filename (TESTDATADIR, "missing-hwid/noreqs-1.2.3.cab"); + g_assert (filename != NULL); + blob_cab = fu_common_get_contents_bytes (filename, &error); + g_assert_no_error (error); + g_assert (blob_cab != NULL); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + + /* get component */ + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + + /* install it */ + g_setenv ("FWUPD_PLUGIN_TEST", "requires-activation", TRUE); + task = fu_install_task_new (device, component); + ret = fu_engine_install (engine, task, blob_cab, + FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check the device requires an activation */ + g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)); + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.2"); + + /* activate the device */ + ret = fu_engine_activate (engine, fu_device_get_id (device), &error); + g_assert_no_error (error); + g_assert (ret); + + /* check the device no longer requires an activation */ + g_assert_false (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)); + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3"); + + /* emulate getting the flag for a fresh boot on old firmware */ + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); + ret = fu_engine_install (engine, task, blob_cab, + FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + g_object_unref (engine); + g_object_unref (device); + engine = fu_engine_new (FU_APP_FLAGS_NONE); + fu_engine_set_silo (engine, silo_empty); + fu_engine_add_plugin (engine, plugin); + device = fu_device_new (); + fu_device_set_id (device, "test_device"); + fu_device_set_name (device, "Test Device"); + fu_device_add_guid (device, "12345678-1234-1234-1234-123456789012"); + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); + fu_engine_add_device (engine, device); + g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)); +} + +static void fu_engine_history_error_func (void) { gboolean ret; + g_autofree gchar *checksum = NULL; g_autofree gchar *device_str_expected = NULL; g_autofree gchar *device_str = NULL; g_autofree gchar *filename = NULL; - g_autofree gchar *checksum = NULL; g_autofree gchar *testdatadir = NULL; - g_autoptr(AsStore) store = NULL; g_autoptr(FuDevice) device2 = NULL; g_autoptr(FuDevice) device = fu_device_new (); - g_autoptr(FuEngine) engine = fu_engine_new (); + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); g_autoptr(FuHistory) history = NULL; + g_autoptr(FuInstallTask) task = NULL; g_autoptr(FuPlugin) plugin = fu_plugin_new (); g_autoptr(GBytes) blob_cab = NULL; g_autoptr(GError) error2 = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) devices = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); /* set up dummy plugin */ g_setenv ("FWUPD_PLUGIN_TEST", "fail", TRUE); @@ -457,13 +1319,13 @@ testdatadir = fu_test_get_filename (TESTDATADIR, "."); g_assert (testdatadir != NULL); g_setenv ("FU_SELF_TEST_REMOTES_DIR", testdatadir, TRUE); - ret = fu_engine_load (engine, &error); + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (fu_engine_get_status (engine), ==, FWUPD_STATUS_IDLE); /* add a device so we can get upgrade it */ - fu_device_set_version (device, "1.2.2"); + fu_device_set_version (device, "1.2.2", FWUPD_VERSION_FORMAT_TRIPLET); fu_device_set_id (device, "test_device"); fu_device_set_name (device, "Test Device"); fu_device_set_plugin (device, "test"); @@ -483,11 +1345,15 @@ blob_cab = fu_common_get_contents_bytes (filename, &error); g_assert_no_error (error); g_assert (blob_cab != NULL); - store = fu_engine_get_store_from_blob (engine, blob_cab, &error); + silo = fu_engine_get_silo_from_blob (engine, blob_cab, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + component = xb_silo_query_first (silo, "components/component/id[text()='com.hughski.test.firmware']/..", &error); g_assert_no_error (error); - g_assert (store != NULL); - ret = fu_engine_install (engine, fu_device_get_id (device), - store, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); + g_assert_nonnull (component); + task = fu_install_task_new (device, component); + ret = fu_engine_install (engine, task, blob_cab, + FWUPD_INSTALL_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED); g_assert (error != NULL); g_assert_cmpstr (error->message, ==, @@ -521,7 +1387,7 @@ " [Release]\n" " Version: 1.2.3\n" " Checksum: SHA1(%s)\n" - " TrustFlags: none\n", + " Flags: none\n", checksum); ret = fu_test_compare_lines (device_str, device_str_expected, &error); g_assert_no_error (error); @@ -557,8 +1423,9 @@ /* add one device */ fu_device_set_id (device1, "device1"); - fu_device_add_guid (device1, "foobar"); + fu_device_add_instance_id (device1, "foobar"); fu_device_set_remove_delay (device1, 100); + fu_device_convert_instance_ids (device1); fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); @@ -590,11 +1457,142 @@ g_assert_cmpint (changed_cnt, ==, 1); } +typedef struct { + FuDevice *device_new; + FuDevice *device_old; + FuDeviceList *device_list; +} FuDeviceListReplugHelper; + +static gboolean +fu_device_list_remove_cb (gpointer user_data) +{ + FuDeviceListReplugHelper *helper = (FuDeviceListReplugHelper *) user_data; + fu_device_list_remove (helper->device_list, helper->device_old); + return FALSE; +} + +static gboolean +fu_device_list_add_cb (gpointer user_data) +{ + FuDeviceListReplugHelper *helper = (FuDeviceListReplugHelper *) user_data; + fu_device_list_add (helper->device_list, helper->device_new); + return FALSE; +} + +static void +fu_device_list_replug_auto_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device1 = fu_device_new (); + g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuDevice) parent = fu_device_new (); + g_autoptr(FuDeviceList) device_list = fu_device_list_new (); + g_autoptr(GError) error = NULL; + FuDeviceListReplugHelper helper; + + /* parent */ + fu_device_set_id (parent, "parent"); + + /* fake child devices */ + fu_device_set_id (device1, "device1"); + fu_device_set_physical_id (device1, "ID"); + fu_device_set_plugin (device1, "self-test"); + fu_device_set_remove_delay (device1, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + fu_device_add_child (parent, device1); + fu_device_set_id (device2, "device2"); + fu_device_set_physical_id (device2, "ID"); /* matches */ + fu_device_set_plugin (device2, "self-test"); + fu_device_set_remove_delay (device2, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + + /* not yet added */ + ret = fu_device_list_wait_for_replug (device_list, device1, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add device */ + fu_device_list_add (device_list, device1); + + /* not waiting */ + ret = fu_device_list_wait_for_replug (device_list, device1, &error); + g_assert_no_error (error); + g_assert (ret); + + /* waiting */ + helper.device_old = device1; + helper.device_new = device2; + helper.device_list = device_list; + g_timeout_add (100, fu_device_list_remove_cb, &helper); + g_timeout_add (200, fu_device_list_add_cb, &helper); + fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + ret = fu_device_list_wait_for_replug (device_list, device1, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check device2 now has parent too */ + g_assert (fu_device_get_parent (device2) == parent); + + /* waiting, failed */ + fu_device_add_flag (device2, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + ret = fu_device_list_wait_for_replug (device_list, device2, &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); + g_assert (!ret); +} + +static void +fu_device_list_replug_user_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device1 = fu_device_new (); + g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuDeviceList) device_list = fu_device_list_new (); + g_autoptr(GError) error = NULL; + FuDeviceListReplugHelper helper; + + /* fake devices */ + fu_device_set_id (device1, "device1"); + fu_device_add_instance_id (device1, "foo"); + fu_device_add_instance_id (device1, "bar"); + fu_device_set_plugin (device1, "self-test"); + fu_device_set_remove_delay (device1, FU_DEVICE_REMOVE_DELAY_USER_REPLUG); + fu_device_convert_instance_ids (device1); + fu_device_set_id (device2, "device2"); + fu_device_add_instance_id (device2, "baz"); + fu_device_add_instance_id (device2, "bar"); /* matches */ + fu_device_set_plugin (device2, "self-test"); + fu_device_set_remove_delay (device2, FU_DEVICE_REMOVE_DELAY_USER_REPLUG); + fu_device_convert_instance_ids (device2); + + /* not yet added */ + ret = fu_device_list_wait_for_replug (device_list, device1, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add device */ + fu_device_list_add (device_list, device1); + + /* not waiting */ + ret = fu_device_list_wait_for_replug (device_list, device1, &error); + g_assert_no_error (error); + g_assert (ret); + + /* waiting */ + helper.device_old = device1; + helper.device_new = device2; + helper.device_list = device_list; + g_timeout_add (100, fu_device_list_remove_cb, &helper); + g_timeout_add (200, fu_device_list_add_cb, &helper); + fu_device_add_flag (device1, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + ret = fu_device_list_wait_for_replug (device_list, device1, &error); + g_assert_no_error (error); + g_assert (ret); +} + static void fu_device_list_compatible_func (void) { g_autoptr(FuDevice) device1 = fu_device_new (); g_autoptr(FuDevice) device2 = fu_device_new (); + g_autoptr(FuDevice) device_old = NULL; g_autoptr(FuDeviceList) device_list = fu_device_list_new (); g_autoptr(GPtrArray) devices_all = NULL; g_autoptr(GPtrArray) devices_active = NULL; @@ -617,10 +1615,11 @@ fu_device_set_id (device1, "device1"); fu_device_set_plugin (device1, "plugin-for-runtime"); fu_device_set_vendor_id (device1, "USB:0x20A0"); - fu_device_set_version (device1, "1.2.3"); - fu_device_add_guid (device1, "foobar"); - fu_device_add_guid (device1, "bootloader"); + fu_device_set_version (device1, "1.2.3", FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_instance_id (device1, "foobar"); + fu_device_add_instance_id (device1, "bootloader"); fu_device_set_remove_delay (device1, 100); + fu_device_convert_instance_ids (device1); fu_device_list_add (device_list, device1); g_assert_cmpint (added_cnt, ==, 1); g_assert_cmpint (removed_cnt, ==, 0); @@ -629,7 +1628,8 @@ /* add another device in bootloader mode */ fu_device_set_id (device2, "device2"); fu_device_set_plugin (device2, "plugin-for-bootloader"); - fu_device_add_guid (device2, "bootloader"); + fu_device_add_instance_id (device2, "bootloader"); + fu_device_convert_instance_ids (device2); /* verify only a changed event was generated */ added_cnt = removed_cnt = changed_cnt = 0; @@ -661,8 +1661,55 @@ "99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a"); /* verify we can get the old device from the new device */ - device = fu_device_list_get_old (device_list, device2); - g_assert (device == device1); + device_old = fu_device_list_get_old (device_list, device2); + g_assert (device_old == device1); +} + +static void +fu_device_list_remove_chain_func (void) +{ + g_autoptr(FuDeviceList) device_list = fu_device_list_new (); + g_autoptr(FuDevice) device_child = fu_device_new (); + g_autoptr(FuDevice) device_parent = fu_device_new (); + + guint added_cnt = 0; + guint changed_cnt = 0; + guint removed_cnt = 0; + + g_signal_connect (device_list, "added", + G_CALLBACK (_device_list_count_cb), + &added_cnt); + g_signal_connect (device_list, "removed", + G_CALLBACK (_device_list_count_cb), + &removed_cnt); + g_signal_connect (device_list, "changed", + G_CALLBACK (_device_list_count_cb), + &changed_cnt); + + /* add child */ + fu_device_set_id (device_child, "child"); + fu_device_add_instance_id (device_child, "child-GUID-1"); + fu_device_convert_instance_ids (device_child); + fu_device_list_add (device_list, device_child); + g_assert_cmpint (added_cnt, ==, 1); + g_assert_cmpint (removed_cnt, ==, 0); + g_assert_cmpint (changed_cnt, ==, 0); + + /* add parent */ + fu_device_set_id (device_parent, "parent"); + fu_device_add_instance_id (device_parent, "parent-GUID-1"); + fu_device_convert_instance_ids (device_parent); + fu_device_add_child (device_parent, device_child); + fu_device_list_add (device_list, device_parent); + g_assert_cmpint (added_cnt, ==, 2); + g_assert_cmpint (removed_cnt, ==, 0); + g_assert_cmpint (changed_cnt, ==, 0); + + /* make sure that removing the parent causes both to go; but the child to go first */ + fu_device_list_remove (device_list, device_parent); + g_assert_cmpint (added_cnt, ==, 2); + g_assert_cmpint (removed_cnt, ==, 2); + g_assert_cmpint (changed_cnt, ==, 0); } static void @@ -691,10 +1738,12 @@ /* add both */ fu_device_set_id (device1, "device1"); - fu_device_add_guid (device1, "foobar"); + fu_device_add_instance_id (device1, "foobar"); + fu_device_convert_instance_ids (device1); fu_device_list_add (device_list, device1); fu_device_set_id (device2, "device2"); - fu_device_add_guid (device2, "baz"); + fu_device_add_instance_id (device2, "baz"); + fu_device_convert_instance_ids (device2); fu_device_list_add (device_list, device2); g_assert_cmpint (added_cnt, ==, 2); g_assert_cmpint (removed_cnt, ==, 0); @@ -715,6 +1764,7 @@ g_assert (device != NULL); g_assert_cmpstr (fu_device_get_id (device), ==, "99249eb1bd9ef0b6e192b271a8cb6a3090cfec7a"); + g_clear_object (&device); /* find by GUID */ device = fu_device_list_get_by_guid (device_list, @@ -724,6 +1774,7 @@ g_assert (device != NULL); g_assert_cmpstr (fu_device_get_id (device), ==, "1a8d0d9a96ad3e67ba76cf3033623625dc6d6882"); + g_clear_object (&device); /* find by missing GUID */ device = fu_device_list_get_by_guid (device_list, "notfound", &error); @@ -743,6 +1794,38 @@ "1a8d0d9a96ad3e67ba76cf3033623625dc6d6882"); } +static void +fu_device_version_format_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_ENSURE_SEMVER); + fu_device_set_version (device, "Ver1.2.3 RELEASE", FWUPD_VERSION_FORMAT_TRIPLET); + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3"); +} + +static void +fu_device_open_refcount_func (void) +{ + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(GError) error = NULL; + fu_device_set_id (device, "test_device"); + ret = fu_device_open (device, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_device_open (device, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_device_close (device, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_device_close (device, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_device_close (device, &error); + g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL); + g_assert_false (ret); +} static void fu_device_metadata_func (void) @@ -852,7 +1935,7 @@ { "Manufacturer", "6de5d951-d755-576b-bd09-c5cf66b27234" }, { "HardwareID-14", "6de5d951-d755-576b-bd09-c5cf66b27234" }, { "HardwareID-13", "f8e1de5f-b68c-5f52-9d1a-f1ba52f1f773" }, - { "HardwareID-12", "5e820764-888e-529d-a6f9-dfd12bacb160" }, + { "HardwareID-12", "e093d715-70f7-51f4-b6c8-b4a7e31def85" }, { "HardwareID-11", "db73af4c-4612-50f7-b8a7-787cf4871847" }, { "HardwareID-10", "f4275c1f-6130-5191-845c-3426247eb6a1" }, { "HardwareID-9", "0cf8618d-9eff-537c-9f35-46861406eb9c" }, @@ -862,9 +1945,9 @@ { "HardwareID-5", "8dc9b7c5-f5d5-5850-9ab3-bd6f0549d814" }, { "HardwareID-4", "660ccba8-1b78-5a33-80e6-9fb8354ee873" }, { "HardwareID-3", "3faec92a-3ae3-5744-be88-495e90a7d541" }, - { "HardwareID-2", "705f45c6-fbca-5245-b9dd-6d4fab25e262" }, - { "HardwareID-1", "309d9985-e453-587e-8486-ff7c835a9ef2" }, - { "HardwareID-0", "d37363b8-5ec4-5725-b618-b75368a1ad28" }, + { "HardwareID-2", "f5ff077f-3eeb-5bae-be1c-e98ffe8ce5f8" }, + { "HardwareID-1", "b7cceb67-774c-537e-bf8b-22c6107e9a74" }, + { "HardwareID-0", "147efce9-f201-5fc8-ab0c-c859751c3440" }, { NULL, NULL } }; @@ -881,7 +1964,7 @@ g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_MANUFACTURER), ==, "LENOVO"); g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_ENCLOSURE_KIND), ==, - "10"); + "a"); g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_FAMILY), ==, "ThinkPad T440s"); g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_PRODUCT_NAME), ==, @@ -890,8 +1973,8 @@ "LENOVO"); g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_VERSION), ==, "GJET75WW (2.25 )"); - g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE), ==, "2"); - g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MINOR_RELEASE), ==, "25"); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MAJOR_RELEASE), ==, "02"); + g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_BIOS_MINOR_RELEASE), ==, "19"); g_assert_cmpstr (fu_hwids_get_value (hwids, FU_HWIDS_KEY_PRODUCT_SKU), ==, "LENOVO_MT_20AR_BU_Think_FM_ThinkPad T440s"); for (guint i = 0; guids[i].key != NULL; i++) { @@ -950,23 +2033,6 @@ g_assert (device_tmp != NULL); g_assert_cmpstr (fu_device_get_id (device_tmp), ==, "b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d"); g_clear_object (&device_tmp); - - /* add it with a small delay */ - fu_plugin_device_add_delay (plugin, device); - g_assert (device_tmp == NULL); - fu_test_loop_run_with_timeout (1000); - g_assert (device_tmp != NULL); - g_assert_cmpstr (fu_device_get_id (device_tmp), ==, "b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d"); - g_clear_object (&device_tmp); - - /* add it again, twice quickly */ - fu_plugin_device_add_delay (plugin, device); - fu_plugin_device_add_delay (plugin, device); - g_assert (device_tmp == NULL); - fu_test_loop_run_with_timeout (1000); - g_assert (device_tmp != NULL); - g_assert_cmpstr (fu_device_get_id (device_tmp), ==, "b7eccd0059d6d7dc2ef76c35d6de0048cc8c029d"); - g_clear_object (&device_tmp); } static void @@ -991,28 +2057,111 @@ fu_plugin_set_quirks (plugin, quirks); /* exact */ - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-plugin-test", "USB\\VID_0A5C&PID_6412"); - g_assert_cmpstr (tmp, ==, "ignore-runtime"); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-plugin-test", "ACME Inc."); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "USB\\VID_0A5C&PID_6412", "Flags"); + g_assert_cmpstr (tmp, ==, "MERGE_ME,ignore-runtime"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "ACME Inc.=True", "Test"); g_assert_cmpstr (tmp, ==, "awesome"); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-plugin-test", "CORP*"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "CORP*", "Test"); g_assert_cmpstr (tmp, ==, "town"); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-plugin-test", "USB\\VID_FFFF&PID_FFFF"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "USB\\VID_FFFF&PID_FFFF", "Flags"); g_assert_cmpstr (tmp, ==, ""); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-Unfound", "baz"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "baz", "Unfound"); g_assert_cmpstr (tmp, ==, NULL); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-tests", "unfound"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "unfound", "tests"); g_assert_cmpstr (tmp, ==, NULL); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-unfound", "unfound"); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "unfound", "unfound"); g_assert_cmpstr (tmp, ==, NULL); + tmp = fu_plugin_lookup_quirk_by_id (plugin, "bb9ec3e2-77b3-53bc-a1f1-b05916715627", "Flags"); + g_assert_cmpstr (tmp, ==, "clever"); +} - /* glob */ - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-plugin-test", "ACME*"); - g_assert_cmpstr (tmp, ==, "awesome"); - tmp = fu_quirks_lookup_by_glob (quirks, "fwupd-plugin-test", "CORPORATION"); - g_assert_cmpstr (tmp, ==, "town"); - tmp = fu_plugin_lookup_quirk_by_id (plugin, "fwupd-plugin-test", "unfound*"); - g_assert_cmpstr (tmp, ==, NULL); +static void +fu_plugin_quirks_performance_func (void) +{ + g_autoptr(FuQuirks) quirks = fu_quirks_new (); + g_autoptr(GTimer) timer = g_timer_new (); + const gchar *keys[] = { + "Name", "Icon", "Children", "Plugin", "Flags", + "FirmwareSizeMin", "FirmwareSizeMax", NULL }; + + /* insert */ + for (guint j = 0; j < 1000; j++) { + g_autofree gchar *group = NULL; + group = g_strdup_printf ("DeviceInstanceId=USB\\VID_0BDA&PID_%04X", j); + for (guint i = 0; keys[i] != NULL; i++) + fu_quirks_add_value (quirks, group, keys[i], "Value"); + } + g_print ("insert=%.3fms ", g_timer_elapsed (timer, NULL) * 1000.f); + + /* lookup */ + g_timer_reset (timer); + for (guint j = 0; j < 1000; j++) { + g_autofree gchar *group = NULL; + group = g_strdup_printf ("DeviceInstanceId=USB\\VID_0BDA&PID_%04X", j); + for (guint i = 0; keys[i] != NULL; i++) { + const gchar *tmp = fu_quirks_lookup_by_id (quirks, group, keys[i]); + g_assert_cmpstr (tmp, ==, "Value"); + } + } + g_print ("lookup=%.3fms ", g_timer_elapsed (timer, NULL) * 1000.f); +} + +static void +fu_plugin_quirks_device_func (void) +{ + FuDevice *device_tmp; + GPtrArray *children; + gboolean ret; + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuQuirks) quirks = fu_quirks_new (); + g_autoptr(GError) error = NULL; + + ret = fu_quirks_load (quirks, &error); + g_assert_no_error (error); + g_assert (ret); + + /* use quirk file to set device attributes */ + fu_device_set_physical_id (device, "usb:00:05"); + fu_device_set_quirks (device, quirks); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_instance_id (device, "USB\\VID_0BDA&PID_1100"); + fu_device_convert_instance_ids (device); + g_assert_cmpstr (fu_device_get_name (device), ==, "Hub"); + + /* ensure children are created */ + children = fu_device_get_children (device); + g_assert_cmpint (children->len, ==, 1); + device_tmp = g_ptr_array_index (children, 0); + g_assert_cmpstr (fu_device_get_name (device_tmp), ==, "HDMI"); + g_assert (fu_device_has_flag (device_tmp, FWUPD_DEVICE_FLAG_UPDATABLE)); +} + +static void +fu_plugin_hash_func (void) +{ + GError *error = NULL; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuPlugin) plugin = fu_plugin_new (); + gboolean ret = FALSE; + + ret = fu_engine_load (engine, FU_ENGINE_LOAD_FLAG_NONE, &error); + g_assert_no_error (error); + g_assert (ret); + + /* make sure not tainted */ + ret = fu_engine_get_tainted (engine); + g_assert_false (ret); + + /* create a tainted plugin */ + g_setenv ("FWUPD_PLUGIN_TEST", "build-hash", TRUE); + ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); + g_assert_no_error (error); + + /* make sure it tainted now */ + g_test_expect_message ("FuEngine", G_LOG_LEVEL_WARNING, "* has incorrect built version*"); + fu_engine_add_plugin (engine, plugin); + ret = fu_engine_get_tainted (engine); + g_assert_true (ret); } static void @@ -1023,6 +2172,7 @@ FwupdRelease *release; gboolean ret; guint cnt = 0; + g_autofree gchar *localstatedir = NULL; g_autofree gchar *mapped_file_fn = NULL; g_autofree gchar *pending_cap = NULL; g_autofree gchar *history_db = NULL; @@ -1073,13 +2223,17 @@ g_assert_no_error (error); g_assert (mapped_file != NULL); blob_cab = g_mapped_file_get_bytes (mapped_file); - fwupd_release_set_version (fu_device_get_release_default (device), "1.2.3"); - ret = fu_plugin_runner_update (plugin, device, blob_cab, NULL, - FWUPD_INSTALL_FLAG_OFFLINE, &error); + release = fu_device_get_release_default (device); + fwupd_release_set_version (release, "1.2.3"); + ret = fu_plugin_runner_schedule_update (plugin, device, release, blob_cab, + FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (cnt, ==, 1); + /* set on the current device */ + g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)); + /* lets check the history */ history = fu_history_new (); device2 = fu_history_get_device_by_id (history, fu_device_get_id (device), &error); @@ -1087,6 +2241,7 @@ g_assert (device2 != NULL); g_assert_cmpint (fu_device_get_update_state (device2), ==, FWUPD_UPDATE_STATE_PENDING); g_assert_cmpstr (fu_device_get_update_error (device2), ==, NULL); + g_assert_true (fu_device_has_flag (device2, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)); release = fu_device_get_release_default (device2); g_assert (release != NULL); g_assert_cmpstr (fwupd_release_get_filename (release), !=, NULL); @@ -1096,7 +2251,7 @@ pending_cap = g_strdup (fwupd_release_get_filename (release)); /* lets do this online */ - ret = fu_plugin_runner_update (plugin, device, blob_cab, NULL, + ret = fu_plugin_runner_update (plugin, device, blob_cab, FWUPD_INSTALL_FLAG_NONE, &error); g_assert_no_error (error); g_assert (ret); @@ -1131,7 +2286,8 @@ g_clear_error (&error); /* delete files */ - history_db = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", "pending.db", NULL); + localstatedir = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + history_db = g_build_filename (localstatedir, "pending.db", NULL); g_unlink (history_db); g_unlink (pending_cap); } @@ -1251,6 +2407,7 @@ FwupdRelease *release; g_autoptr(FuDevice) device_found = NULL; g_autoptr(FuHistory) history = NULL; + g_autoptr(GPtrArray) approved_firmware = NULL; g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; @@ -1259,7 +2416,7 @@ g_assert (history != NULL); /* delete the database */ - dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); + dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); if (!g_file_test (dirname, G_FILE_TEST_IS_DIR)) return; filename = g_build_filename (dirname, "pending.db", NULL); @@ -1269,7 +2426,7 @@ device = fu_device_new (); fu_device_set_id (device, "self-test"); fu_device_set_name (device, "ColorHug"), - fu_device_set_version (device, "3.0.1"), + fu_device_set_version (device, "3.0.1", FWUPD_VERSION_FORMAT_TRIPLET), fu_device_set_update_state (device, FWUPD_UPDATE_STATE_FAILED); fu_device_set_update_error (device, "word"); fu_device_add_guid (device, "827edddd-9bb6-5632-889f-2c01255503da"); @@ -1340,6 +2497,23 @@ g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND); g_assert (device_found == NULL); g_clear_error (&error); + + /* approved firmware */ + ret = fu_history_clear_approved_firmware (history, &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_history_add_approved_firmware (history, "foo", &error); + g_assert_no_error (error); + g_assert (ret); + ret = fu_history_add_approved_firmware (history, "bar", &error); + g_assert_no_error (error); + g_assert (ret); + approved_firmware = fu_history_get_approved_firmware (history, &error); + g_assert_no_error (error); + g_assert_nonnull (approved_firmware); + g_assert_cmpint (approved_firmware->len, ==, 2); + g_assert_cmpstr (g_ptr_array_index (approved_firmware, 0), ==, "foo"); + g_assert_cmpstr (g_ptr_array_index (approved_firmware, 1), ==, "bar"); } static void @@ -1387,7 +2561,9 @@ g_assert_no_error (error); g_assert_nonnull (blob_pass); blob_sig = g_bytes_new_static (sig_gpgme, strlen (sig_gpgme)); - result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, &error); + result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, + FU_KEYRING_VERIFY_FLAG_NONE, + &error); g_assert_no_error (error); g_assert_nonnull (result_pass); g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), == , 1438072952); @@ -1400,7 +2576,8 @@ blob_fail = fu_common_get_contents_bytes (fw_fail, &error); g_assert_no_error (error); g_assert_nonnull (blob_fail); - result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, &error); + result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, + FU_KEYRING_VERIFY_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); g_assert_null (result_fail); g_clear_error (&error); @@ -1450,7 +2627,8 @@ blob_sig = fu_common_get_contents_bytes (sig_fn, &error); g_assert_no_error (error); g_assert_nonnull (blob_sig); - result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, &error); + result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, + FU_KEYRING_VERIFY_FLAG_NONE, &error); g_assert_no_error (error); g_assert_nonnull (result_pass); g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), >= , 1502871248); @@ -1462,7 +2640,8 @@ blob_sig2 = fu_common_get_contents_bytes (sig_fn2, &error); g_assert_no_error (error); g_assert_nonnull (blob_sig2); - result_fail = fu_keyring_verify_data (keyring, blob_pass, blob_sig2, &error); + result_fail = fu_keyring_verify_data (keyring, blob_pass, blob_sig2, + FU_KEYRING_VERIFY_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); g_assert_null (result_fail); g_clear_error (&error); @@ -1473,7 +2652,8 @@ blob_fail = fu_common_get_contents_bytes (fw_fail, &error); g_assert_no_error (error); g_assert_nonnull (blob_fail); - result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, &error); + result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, + FU_KEYRING_VERIFY_FLAG_NONE, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID); g_assert_null (result_fail); g_clear_error (&error); @@ -1483,22 +2663,54 @@ } static void +fu_keyring_pkcs7_self_signed_func (void) +{ +#ifdef ENABLE_PKCS7 + gboolean ret; + g_autoptr(FuKeyring) kr = NULL; + g_autoptr(FuKeyringResult) kr_result = NULL; + g_autoptr(GBytes) payload = NULL; + g_autoptr(GBytes) signature = NULL; + g_autoptr(GError) error = NULL; + +#ifndef HAVE_GNUTLS_3_6_0 + /* required to create the private key correctly */ + g_test_skip ("GnuTLS version too old"); + return; +#endif + + /* create detached signature and verify */ + kr = fu_keyring_pkcs7_new (); + ret = fu_keyring_setup (kr, &error); + g_assert_no_error (error); + g_assert_true (ret); + payload = fu_common_get_contents_bytes ("/etc/machine-id", &error); + g_assert_no_error (error); + g_assert_nonnull (payload); + signature = fu_keyring_sign_data (kr, payload, FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP, &error); + g_assert_no_error (error); + g_assert_nonnull (signature); + ret = fu_common_set_contents_bytes ("/tmp/test.p7b", signature, &error); + g_assert_no_error (error); + g_assert_true (ret); + kr_result = fu_keyring_verify_data (kr, payload, signature, + FU_KEYRING_VERIFY_FLAG_USE_CLIENT_CERT, &error); + g_assert_no_error (error); + g_assert_nonnull (kr_result); +#else + g_test_skip ("no GnuTLS support enabled"); +#endif +} + +static void fu_common_firmware_builder_func (void) { const gchar *data; g_autofree gchar *archive_fn = NULL; - g_autofree gchar *bwrap_fn = NULL; g_autoptr(GBytes) archive_blob = NULL; g_autoptr(GBytes) firmware_blob = NULL; g_autoptr(GError) error = NULL; - /* we can't do this in travis: capset failed: Operation not permitted */ - bwrap_fn = g_find_program_in_path ("bwrap"); - if (bwrap_fn == NULL) { - g_test_skip ("no bwrap in path, so skipping"); - return; - } - /* get test file */ archive_fn = fu_test_get_filename (TESTDATADIR, "builder/firmware.tar"); g_assert (archive_fn != NULL); @@ -1511,8 +2723,17 @@ "startup.sh", "firmware.bin", &error); - g_assert_no_error (error); - g_assert (firmware_blob != NULL); + if (firmware_blob == NULL) { + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_PERMISSION_DENIED)) { + g_test_skip ("Missing permissions to create namespace in container"); + return; + } + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) { + g_test_skip ("User namespaces not supported in container"); + return; + } + g_assert_no_error (error); + } /* check it */ data = g_bytes_get_data (firmware_blob, NULL); @@ -1596,13 +2817,31 @@ g_assert (fn != NULL); argv[0] = fn; ret = fu_common_spawn_sync (argv, - fu_test_stdout_cb, &lines, NULL, &error); + fu_test_stdout_cb, &lines, 0, NULL, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpint (lines, ==, 6); } static void +fu_common_spawn_timeout_func (void) +{ + gboolean ret; + guint lines = 0; + g_autoptr(GError) error = NULL; + g_autofree gchar *fn = NULL; + const gchar *argv[3] = { "replace", "test", NULL }; + + fn = fu_test_get_filename (TESTDATADIR, "spawn.sh"); + g_assert (fn != NULL); + argv[0] = fn; + ret = fu_common_spawn_sync (argv, fu_test_stdout_cb, &lines, 50, NULL, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert (!ret); + g_assert_cmpint (lines, ==, 1); +} + +static void fu_progressbar_func (void) { g_autoptr(FuProgressbar) progressbar = fu_progressbar_new (); @@ -1707,18 +2946,192 @@ } static void +_plugin_composite_device_added_cb (FuPlugin *plugin, FuDevice *device, gpointer user_data) +{ + GPtrArray *devices = (GPtrArray *) user_data; + g_ptr_array_add (devices, g_object_ref (device)); +} + +static void +fu_plugin_composite_func (void) +{ + GError *error = NULL; + gboolean ret; + g_autoptr(FuEngine) engine = fu_engine_new (FU_APP_FLAGS_NONE); + g_autoptr(FuPlugin) plugin = fu_plugin_new (); + g_autoptr(GBytes) blob = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GPtrArray) install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_autoptr(XbSilo) silo_empty = xb_silo_new (); + g_autoptr(XbSilo) silo = NULL; + + /* no metadata in daemon */ + fu_engine_set_silo (engine, silo_empty); + + /* create CAB file */ + blob = _build_cab (GCAB_COMPRESSION_NONE, + "acme.metainfo.xml", + "\n" + " com.acme.example.firmware\n" + " \n" + " b585990a-003e-5270-89d5-3705a17f9a43\n" + " \n" + " \n" + " \n" + " \n" + "", + "acme.module1.metainfo.xml", + "\n" + " com.acme.example.firmware.module1\n" + " \n" + " 7fddead7-12b5-4fb9-9fa0-6d30305df755\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " plain\n" + " \n" + "", + "acme.module2.metainfo.xml", + "\n" + " com.acme.example.firmware.module2\n" + " \n" + " b8fe6b45-8702-4bcd-8120-ef236caac76f\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " plain\n" + " \n" + "", + "firmware.bin", "world", + NULL); + if (blob == NULL) { + g_test_skip ("libgcab too old"); + return; + } + silo = fu_common_cab_build_silo (blob, 10240, &error); + g_assert_no_error (error); + g_assert_nonnull (silo); + components = xb_silo_query (silo, "components/component", 0, &error); + g_assert_no_error (error); + g_assert_nonnull (components); + g_assert_cmpint (components->len, ==, 3); + + /* set up dummy plugin */ + g_setenv ("FWUPD_PLUGIN_TEST", "composite", TRUE); + ret = fu_plugin_open (plugin, PLUGINBUILDDIR "/libfu_plugin_test.so", &error); + g_assert_no_error (error); + g_assert_true (ret); + fu_engine_add_plugin (engine, plugin); + + ret = fu_plugin_runner_startup (plugin, &error); + g_assert_no_error (error); + g_assert_true (ret); + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_signal_connect (plugin, "device-added", + G_CALLBACK (_plugin_composite_device_added_cb), + devices); + + ret = fu_plugin_runner_coldplug (plugin, &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* check we found all composite devices */ + g_assert_cmpint (devices->len, ==, 3); + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + fu_engine_add_device (engine, device); + if (g_strcmp0 (fu_device_get_id (device), + "08d460be0f1f9f128413f816022a6439e0078018") == 0) { + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.2"); + } else if (g_strcmp0 (fu_device_get_id (device), + "c0a0a4aa6480ac28eea1ce164fbb466ca934e1ff") == 0) { + g_assert_cmpstr (fu_device_get_version (device), ==, "1"); + g_assert_nonnull (fu_device_get_parent (device)); + } else if (g_strcmp0 (fu_device_get_id (device), + "bf455e9f371d2608d1cb67660fd2b335d3f6ef73") == 0) { + g_assert_cmpstr (fu_device_get_version (device), ==, "10"); + g_assert_nonnull (fu_device_get_parent (device)); + } + } + + /* produce install tasks */ + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + + /* do any devices pass the requirements */ + for (guint j = 0; j < devices->len; j++) { + FuDevice *device = g_ptr_array_index (devices, j); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error_local = NULL; + + /* is this component valid for the device */ + task = fu_install_task_new (device, component); + if (!fu_engine_check_requirements (engine, + task, + 0, + &error_local)) { + g_debug ("requirement on %s:%s failed: %s", + fu_device_get_id (device), + xb_node_query_text (component, "id", NULL), + error_local->message); + continue; + } + + g_ptr_array_add (install_tasks, g_steal_pointer (&task)); + } + } + g_assert_cmpint (install_tasks->len, ==, 3); + + /* install the cab */ + ret = fu_engine_install_tasks (engine, + install_tasks, + blob, + FWUPD_DEVICE_FLAG_NONE, + &error); + g_assert_no_error (error); + g_assert_true (ret); + + /* verify everything upgraded */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + const gchar *metadata; + if (g_strcmp0 (fu_device_get_id (device), + "08d460be0f1f9f128413f816022a6439e0078018") == 0) { + g_assert_cmpstr (fu_device_get_version (device), ==, "1.2.3"); + } else if (g_strcmp0 (fu_device_get_id (device), + "c0a0a4aa6480ac28eea1ce164fbb466ca934e1ff") == 0) { + g_assert_cmpstr (fu_device_get_version (device), ==, "2"); + } else if (g_strcmp0 (fu_device_get_id (device), + "bf455e9f371d2608d1cb67660fd2b335d3f6ef73") == 0) { + g_assert_cmpstr (fu_device_get_version (device), ==, "11"); + } + + /* verify prepare and cleanup ran on all devices */ + metadata = fu_device_get_metadata (device, "frimbulator"); + g_assert_cmpstr (metadata, ==, "1"); + metadata = fu_device_get_metadata (device, "frombulator"); + g_assert_cmpstr (metadata, ==, "1"); + } +} + +static void fu_common_store_cab_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; - AsRequire *req; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbNode) req = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "acme.metainfo.xml", "\n" @@ -1729,9 +3142,8 @@ " \n" " \n" " \n" - " \n" " 5\n" - " 7c211433f02071597741e6ff5a8ea34789abbf43\n" + " 7c211433f02071597741e6ff5a8ea34789abbf43\n" "

We fixed things

\n" "
\n" "
\n" @@ -1746,38 +3158,42 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.dfu"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + csum = xb_node_query_first (rel, "checksum[@target='content']", &error); + g_assert_nonnull (csum); + g_assert_cmpstr (xb_node_get_text (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu)"); g_assert_nonnull (blob_tmp); - blob_tmp = as_release_get_blob (rel, "firmware.dfu.asc"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.dfu.asc)"); g_assert_nonnull (blob_tmp); - req = as_app_get_require_by_value (app, AS_REQUIRE_KIND_ID, "org.freedesktop.fwupd"); + req = xb_node_query_first (component, "requires/id", &error); + g_assert_no_error (error); g_assert_nonnull (req); } static void fu_common_store_cab_unsigned_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) csum = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "acme.metainfo.xml", "\n" @@ -1792,36 +3208,37 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.bin"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + csum = xb_node_query_first (rel, "checksum[@target='content']", &error); + g_assert_null (csum); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); g_assert_nonnull (blob_tmp); - blob_tmp = as_release_get_blob (rel, "firmware.bin.asc"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin.asc)"); g_assert_null (blob_tmp); } static void fu_common_store_cab_folder_func (void) { - AsApp *app; - AsChecksum *csum; - AsRelease *rel; GBytes *blob_tmp; - g_autoptr(AsStore) store = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; + g_autoptr(XbNode) component = NULL; + g_autoptr(XbNode) rel = NULL; + g_autoptr(XbSilo) silo = NULL; - /* create store */ + /* create silo */ blob = _build_cab (GCAB_COMPRESSION_NONE, "lvfs\\acme.metainfo.xml", "\n" @@ -1836,26 +3253,26 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_no_error (error); - g_assert (store != NULL); + g_assert_nonnull (silo); /* verify */ - app = as_store_get_app_by_id (store, "com.acme.example.firmware"); - g_assert_nonnull (app); - rel = as_app_get_release_default (app); + component = xb_silo_query_first (silo, "components/component/id[text()='com.acme.example.firmware']/..", &error); + g_assert_no_error (error); + g_assert_nonnull (component); + rel = xb_node_query_first (component, "releases/release", &error); + g_assert_no_error (error); g_assert_nonnull (rel); - g_assert_cmpstr (as_release_get_version (rel), ==, "1.2.3"); - csum = as_release_get_checksum_by_target (rel, AS_CHECKSUM_TARGET_CONTENT); - g_assert_cmpstr (as_checksum_get_value (csum), ==, "7c211433f02071597741e6ff5a8ea34789abbf43"); - blob_tmp = as_release_get_blob (rel, "firmware.bin"); + g_assert_cmpstr (xb_node_get_attr (rel, "version"), ==, "1.2.3"); + blob_tmp = xb_node_get_data (rel, "fwupd::ReleaseBlob(firmware.bin)"); g_assert_nonnull (blob_tmp); } static void fu_common_store_cab_error_no_metadata_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -1867,15 +3284,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_wrong_size_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -1896,15 +3313,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_missing_file_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -1924,15 +3341,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_size_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -1950,15 +3367,15 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 123, &error); + silo = fu_common_cab_build_silo (blob, 123, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); } static void fu_common_store_cab_error_wrong_checksum_func (void) { - g_autoptr(AsStore) store = NULL; + g_autoptr(XbSilo) silo = NULL; g_autoptr(GBytes) blob = NULL; g_autoptr(GError) error = NULL; @@ -1978,9 +3395,273 @@ g_test_skip ("libgcab too old"); return; } - store = fu_common_store_from_cab_bytes (blob, 10240, &error); + silo = fu_common_cab_build_silo (blob, 10240, &error); g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE); - g_assert (store == NULL); + g_assert_null (silo); +} + +static gboolean +fu_device_poll_cb (FuDevice *device, GError **error) +{ + guint64 cnt = fu_device_get_metadata_integer (device, "cnt"); + g_debug ("poll cnt=%" G_GUINT64_FORMAT, cnt); + fu_device_set_metadata_integer (device, "cnt", cnt + 1); + return TRUE; +} + +static void +fu_device_poll_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + FuDeviceClass *klass = FU_DEVICE_GET_CLASS (device); + guint cnt; + + /* set up a 10ms poll */ + klass->poll = fu_device_poll_cb; + fu_device_set_metadata_integer (device, "cnt", 0); + fu_device_set_poll_interval (device, 10); + fu_test_loop_run_with_timeout (100); + fu_test_loop_quit (); + cnt = fu_device_get_metadata_integer (device, "cnt"); + g_assert_cmpint (cnt, >=, 8); + + /* disable the poll */ + fu_device_set_poll_interval (device, 0); + fu_test_loop_run_with_timeout (100); + fu_test_loop_quit (); + g_assert_cmpint (fu_device_get_metadata_integer (device, "cnt"), ==, cnt); +} + +static void +fu_device_incorporate_func (void) +{ + g_autoptr(FuDevice) device = fu_device_new (); + g_autoptr(FuDevice) donor = fu_device_new (); + + /* set up donor device */ + fu_device_set_alternate_id (donor, "alt-id"); + fu_device_set_equivalent_id (donor, "equiv-id"); + fu_device_set_metadata (donor, "test", "me"); + fu_device_set_metadata (donor, "test2", "me"); + + /* base properties */ + fu_device_add_flag (donor, FWUPD_DEVICE_FLAG_REQUIRE_AC); + fu_device_set_created (donor, 123); + fu_device_set_modified (donor, 456); + fu_device_add_icon (donor, "computer"); + + /* existing properties */ + fu_device_set_equivalent_id (device, "DO_NOT_OVERWRITE"); + fu_device_set_metadata (device, "test2", "DO_NOT_OVERWRITE"); + fu_device_set_modified (device, 789); + + /* incorporate properties from donor to device */ + fu_device_incorporate (device, donor); + g_assert_cmpstr (fu_device_get_alternate_id (device), ==, "alt-id"); + g_assert_cmpstr (fu_device_get_equivalent_id (device), ==, "DO_NOT_OVERWRITE"); + g_assert_cmpstr (fu_device_get_metadata (device, "test"), ==, "me"); + g_assert_cmpstr (fu_device_get_metadata (device, "test2"), ==, "DO_NOT_OVERWRITE"); + g_assert_true (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC)); + g_assert_cmpint (fu_device_get_created (device), ==, 123); + g_assert_cmpint (fu_device_get_modified (device), ==, 789); + g_assert_cmpint (fu_device_get_icons(device)->len, ==, 1); +} + +static void +fu_chunk_func (void) +{ + g_autofree gchar *chunked1_str = NULL; + g_autofree gchar *chunked2_str = NULL; + g_autofree gchar *chunked3_str = NULL; + g_autofree gchar *chunked4_str = NULL; + g_autoptr(GPtrArray) chunked1 = NULL; + g_autoptr(GPtrArray) chunked2 = NULL; + g_autoptr(GPtrArray) chunked3 = NULL; + g_autoptr(GPtrArray) chunked4 = NULL; + + chunked3 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x0, 3, 3); + chunked3_str = fu_chunk_array_to_string (chunked3); + g_print ("\n%s", chunked3_str); + g_assert_cmpstr (chunked3_str, ==, "#00: page:00 addr:0000 len:03 123\n" + "#01: page:01 addr:0000 len:03 456\n"); + + chunked4 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x4, 4, 4); + chunked4_str = fu_chunk_array_to_string (chunked4); + g_print ("\n%s", chunked4_str); + g_assert_cmpstr (chunked4_str, ==, "#00: page:01 addr:0000 len:04 1234\n" + "#01: page:02 addr:0000 len:02 56\n"); + + chunked1 = fu_chunk_array_new ((const guint8 *) "0123456789abcdef", 16, 0x0, 10, 4); + chunked1_str = fu_chunk_array_to_string (chunked1); + g_print ("\n%s", chunked1_str); + g_assert_cmpstr (chunked1_str, ==, "#00: page:00 addr:0000 len:04 0123\n" + "#01: page:00 addr:0004 len:04 4567\n" + "#02: page:00 addr:0008 len:02 89\n" + "#03: page:01 addr:0000 len:04 abcd\n" + "#04: page:01 addr:0004 len:02 ef\n"); + + chunked2 = fu_chunk_array_new ((const guint8 *) "XXXXXXYYYYYYZZZZZZ", 18, 0x0, 6, 4); + chunked2_str = fu_chunk_array_to_string (chunked2); + g_print ("\n%s", chunked2_str); + g_assert_cmpstr (chunked2_str, ==, "#00: page:00 addr:0000 len:04 XXXX\n" + "#01: page:00 addr:0004 len:02 XX\n" + "#02: page:01 addr:0000 len:04 YYYY\n" + "#03: page:01 addr:0004 len:02 YY\n" + "#04: page:02 addr:0000 len:04 ZZZZ\n" + "#05: page:02 addr:0004 len:02 ZZ\n"); +} + +static void +fu_common_strstrip_func (void) +{ + + struct { + const gchar *old; + const gchar *new; + } map[] = { + { "same", "same" }, + { " leading", "leading" }, + { "tailing ", "tailing" }, + { " b ", "b" }, + { " ", "" }, + { NULL, NULL } + }; + for (guint i = 0; map[i].old != NULL; i++) { + g_autofree gchar *tmp = fu_common_strstrip (map[i].old); + g_assert_cmpstr (tmp, ==, map[i].new); + } +} + +static void +fu_common_version_func (void) +{ + guint i; + struct { + guint32 val; + const gchar *ver; + FwupdVersionFormat flags; + } version_from_uint32[] = { + { 0x0, "0.0.0.0", FWUPD_VERSION_FORMAT_QUAD }, + { 0xff, "0.0.0.255", FWUPD_VERSION_FORMAT_QUAD }, + { 0xff01, "0.0.255.1", FWUPD_VERSION_FORMAT_QUAD }, + { 0xff0001, "0.255.0.1", FWUPD_VERSION_FORMAT_QUAD }, + { 0xff000100, "255.0.1.0", FWUPD_VERSION_FORMAT_QUAD }, + { 0x0, "0.0.0", FWUPD_VERSION_FORMAT_TRIPLET }, + { 0xff, "0.0.255", FWUPD_VERSION_FORMAT_TRIPLET }, + { 0xff01, "0.0.65281", FWUPD_VERSION_FORMAT_TRIPLET }, + { 0xff0001, "0.255.1", FWUPD_VERSION_FORMAT_TRIPLET }, + { 0xff000100, "255.0.256", FWUPD_VERSION_FORMAT_TRIPLET }, + { 0x0, "0", FWUPD_VERSION_FORMAT_NUMBER }, + { 0xff000100, "4278190336", FWUPD_VERSION_FORMAT_NUMBER }, + { 0x0, "11.0.0.0", FWUPD_VERSION_FORMAT_INTEL_ME }, + { 0xffffffff, "18.31.255.65535", FWUPD_VERSION_FORMAT_INTEL_ME }, + { 0x0b32057a, "11.11.50.1402", FWUPD_VERSION_FORMAT_INTEL_ME }, + { 0xb8320d84, "11.8.50.3460", FWUPD_VERSION_FORMAT_INTEL_ME2 }, + { 0, NULL } + }; + struct { + guint16 val; + const gchar *ver; + FwupdVersionFormat flags; + } version_from_uint16[] = { + { 0x0, "0.0", FWUPD_VERSION_FORMAT_PAIR }, + { 0xff, "0.255", FWUPD_VERSION_FORMAT_PAIR }, + { 0xff01, "255.1", FWUPD_VERSION_FORMAT_PAIR }, + { 0x0, "0.0", FWUPD_VERSION_FORMAT_BCD }, + { 0x0110, "1.10", FWUPD_VERSION_FORMAT_BCD }, + { 0x9999, "99.99", FWUPD_VERSION_FORMAT_BCD }, + { 0x0, "0", FWUPD_VERSION_FORMAT_NUMBER }, + { 0x1234, "4660", FWUPD_VERSION_FORMAT_NUMBER }, + { 0, NULL } + }; + struct { + const gchar *old; + const gchar *new; + } version_parse[] = { + { "0", "0" }, + { "0x1a", "0.0.26" }, + { "257", "0.0.257" }, + { "1.2.3", "1.2.3" }, + { "0xff0001", "0.255.1" }, + { "16711681", "0.255.1" }, + { "20150915", "20150915" }, + { "dave", "dave" }, + { "0x1x", "0x1x" }, + { NULL, NULL } + }; + + /* check version conversion */ + for (i = 0; version_from_uint32[i].ver != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint32 (version_from_uint32[i].val, + version_from_uint32[i].flags); + g_assert_cmpstr (ver, ==, version_from_uint32[i].ver); + } + for (i = 0; version_from_uint16[i].ver != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_from_uint16 (version_from_uint16[i].val, + version_from_uint16[i].flags); + g_assert_cmpstr (ver, ==, version_from_uint16[i].ver); + } + + /* check version parsing */ + for (i = 0; version_parse[i].old != NULL; i++) { + g_autofree gchar *ver = NULL; + ver = fu_common_version_parse (version_parse[i].old); + g_assert_cmpstr (ver, ==, version_parse[i].new); + } +} + +static void +fu_common_vercmp_func (void) +{ + /* same */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.003", "001.002.003"), ==, 0); + + /* same, not dotted decimal */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "0x1020003"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("0x10203", "0x10203"), ==, 0); + + /* upgrade and downgrade */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.4"), <, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.000", "001.002.009"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.2"), >, 0); + g_assert_cmpint (fu_common_vercmp ("001.002.009", "001.002.000"), >, 0); + + /* unequal depth */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3.1"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3.1", "1.2.4"), <, 0); + + /* mixed-alpha-numeric */ + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3a"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3b"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3b", "1.2.3a"), >, 0); + + /* alpha version append */ + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3a"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3a", "1.2.3"), >, 0); + + /* alpha only */ + g_assert_cmpint (fu_common_vercmp ("alpha", "alpha"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("alpha", "beta"), <, 0); + g_assert_cmpint (fu_common_vercmp ("beta", "alpha"), >, 0); + + /* alpha-compare */ + g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2a.3"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2a.3", "1.2b.3"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2b.3", "1.2a.3"), >, 0); + + /* tilde is all-powerful */ + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc1", "1.2.3"), <, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3", "1.2.3~rc1"), >, 0); + g_assert_cmpint (fu_common_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0); + + /* invalid */ + g_assert_cmpint (fu_common_vercmp ("1", NULL), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp (NULL, "1"), ==, G_MAXINT); + g_assert_cmpint (fu_common_vercmp (NULL, NULL), ==, G_MAXINT); } int @@ -1991,24 +3672,53 @@ /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + g_setenv ("FWUPD_DATADIR", TESTDATADIR_SRC, TRUE); + g_setenv ("FWUPD_PLUGINDIR", TESTDATADIR_SRC, TRUE); + g_setenv ("FWUPD_SYSCONFDIR", TESTDATADIR_SRC, TRUE); + g_setenv ("FWUPD_SYSFSFWDIR", TESTDATADIR_SRC, TRUE); + g_setenv ("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE); - fu_common_rmtree ("/tmp/fwupd-self-test", NULL); - g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0); + /* ensure empty tree */ + fu_self_test_mkroot (); /* tests go here */ if (g_test_slow ()) g_test_add_func ("/fwupd/progressbar", fu_progressbar_func); + g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); + g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); + g_test_add_func ("/fwupd/engine{requirements-other-device}", fu_engine_requirements_other_device_func); + g_test_add_func ("/fwupd/device{incorporate}", fu_device_incorporate_func); + g_test_add_func ("/fwupd/device{poll}", fu_device_poll_func); g_test_add_func ("/fwupd/device-locker{success}", fu_device_locker_func); g_test_add_func ("/fwupd/device-locker{fail}", fu_device_locker_fail_func); g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func); + g_test_add_func ("/fwupd/device{open-refcount}", fu_device_open_refcount_func); + g_test_add_func ("/fwupd/device{version-format}", fu_device_version_format_func); g_test_add_func ("/fwupd/device-list", fu_device_list_func); g_test_add_func ("/fwupd/device-list{delay}", fu_device_list_delay_func); g_test_add_func ("/fwupd/device-list{compatible}", fu_device_list_compatible_func); + g_test_add_func ("/fwupd/device-list{remove-chain}", fu_device_list_remove_chain_func); + g_test_add_func ("/fwupd/engine{device-unlock}", fu_engine_device_unlock_func); g_test_add_func ("/fwupd/engine{history-success}", fu_engine_history_func); g_test_add_func ("/fwupd/engine{history-error}", fu_engine_history_error_func); + if (g_test_slow ()) + g_test_add_func ("/fwupd/device-list{replug-auto}", fu_device_list_replug_auto_func); + g_test_add_func ("/fwupd/device-list{replug-user}", fu_device_list_replug_user_func); g_test_add_func ("/fwupd/engine{require-hwid}", fu_engine_require_hwid_func); + g_test_add_func ("/fwupd/engine{history-inherit}", fu_engine_history_inherit); g_test_add_func ("/fwupd/engine{partial-hash}", fu_engine_partial_hash_func); g_test_add_func ("/fwupd/engine{downgrade}", fu_engine_downgrade_func); + g_test_add_func ("/fwupd/engine{requirements-success}", fu_engine_requirements_func); + g_test_add_func ("/fwupd/engine{requirements-missing}", fu_engine_requirements_missing_func); + g_test_add_func ("/fwupd/engine{requirements-not-child}", fu_engine_requirements_child_func); + g_test_add_func ("/fwupd/engine{requirements-not-child-fail}", fu_engine_requirements_child_fail_func); + g_test_add_func ("/fwupd/engine{requirements-unsupported}", fu_engine_requirements_unsupported_func); + g_test_add_func ("/fwupd/engine{requirements-device}", fu_engine_requirements_device_func); + g_test_add_func ("/fwupd/engine{requirements-version-format}", fu_engine_requirements_version_format_func); + g_test_add_func ("/fwupd/engine{device-auto-parent}", fu_engine_device_parent_func); + g_test_add_func ("/fwupd/engine{device-priority}", fu_engine_device_priority_func); + g_test_add_func ("/fwupd/engine{install-duration}", fu_engine_install_duration_func); + g_test_add_func ("/fwupd/engine{generate-md}", fu_engine_generate_md_func); g_test_add_func ("/fwupd/hwids", fu_hwids_func); g_test_add_func ("/fwupd/smbios", fu_smbios_func); g_test_add_func ("/fwupd/smbios3", fu_smbios3_func); @@ -2019,8 +3729,18 @@ g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func); g_test_add_func ("/fwupd/plugin{module}", fu_plugin_module_func); g_test_add_func ("/fwupd/plugin{quirks}", fu_plugin_quirks_func); + g_test_add_func ("/fwupd/plugin{quirks-performance}", fu_plugin_quirks_performance_func); + g_test_add_func ("/fwupd/plugin{quirks-device}", fu_plugin_quirks_device_func); + g_test_add_func ("/fwupd/plugin{composite}", fu_plugin_composite_func); g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func); g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); + g_test_add_func ("/fwupd/keyring{pkcs7-self-signed}", fu_keyring_pkcs7_self_signed_func); + g_test_add_func ("/fwupd/plugin{build-hash}", fu_plugin_hash_func); + g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func); + g_test_add_func ("/fwupd/common{version}", fu_common_version_func); + g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func); + g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func); g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func); g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func); g_test_add_func ("/fwupd/common{cab-success-unsigned}", fu_common_store_cab_unsigned_func); @@ -2031,6 +3751,7 @@ g_test_add_func ("/fwupd/common{cab-error-missing-file}", fu_common_store_cab_error_missing_file_func); g_test_add_func ("/fwupd/common{cab-error-size}", fu_common_store_cab_error_size_func); g_test_add_func ("/fwupd/common{spawn)", fu_common_spawn_func); + g_test_add_func ("/fwupd/common{spawn-timeout)", fu_common_spawn_timeout_func); g_test_add_func ("/fwupd/common{firmware-builder}", fu_common_firmware_builder_func); return g_test_run (); } diff -Nru fwupd-1.0.6/src/fu-smbios.c fwupd-1.2.10/src/fu-smbios.c --- fwupd-1.0.6/src/fu-smbios.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-smbios.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,17 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuSmbios" + #include "config.h" #include #include +#include "fu-common.h" #include "fu-smbios.h" #include "fwupd-error.h" @@ -325,8 +313,10 @@ fu_smbios_setup (FuSmbios *self, GError **error) { g_autofree gchar *path = NULL; + g_autofree gchar *sysfsfwdir = NULL; g_return_val_if_fail (FU_IS_SMBIOS (self), FALSE); - path = g_build_filename (SYSFSFIRMWAREDIR, "dmi", "tables", NULL); + sysfsfwdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW); + path = g_build_filename (sysfsfwdir, "dmi", "tables", NULL); return fu_smbios_setup_from_path (self, path, error); } diff -Nru fwupd-1.0.6/src/fu-smbios.h fwupd-1.2.10/src/fu-smbios.h --- fwupd-1.0.6/src/fu-smbios.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-smbios.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_SMBIOS_H -#define __FU_SMBIOS_H +#pragma once #include @@ -56,5 +40,3 @@ GError **error); G_END_DECLS - -#endif /* __FU_SMBIOS_H */ diff -Nru fwupd-1.0.6/src/fu-systemd.c fwupd-1.2.10/src/fu-systemd.c --- fwupd-1.0.6/src/fu-systemd.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-systemd.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2017-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +#include +#include +#include + +#include "fu-systemd.h" + +#define SYSTEMD_SERVICE "org.freedesktop.systemd1" +#define SYSTEMD_OBJECT_PATH "/org/freedesktop/systemd1" +#define SYSTEMD_INTERFACE "org.freedesktop.systemd1" +#define SYSTEMD_MANAGER_INTERFACE "org.freedesktop.systemd1.Manager" + +static GDBusProxy * +fu_systemd_get_manager (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) { + g_prefix_error (error, "failed to get bus: "); + return NULL; + } + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, NULL, + SYSTEMD_SERVICE, + SYSTEMD_OBJECT_PATH, + SYSTEMD_MANAGER_INTERFACE, + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "failed to find %s: ", SYSTEMD_SERVICE); + return NULL; + } + return g_steal_pointer (&proxy); +} + +static gchar * +fu_systemd_unit_get_path (GDBusProxy *proxy_manager, const gchar *unit, GError **error) +{ + g_autofree gchar *path = NULL; + g_autoptr(GVariant) val = NULL; + + val = g_dbus_proxy_call_sync (proxy_manager, + "GetUnit", + g_variant_new ("(s)", unit), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) { + g_prefix_error (error, "failed to find %s: ", unit); + return NULL; + } + g_variant_get (val, "(o)", &path); + return g_steal_pointer (&path); +} + +static GDBusProxy * +fu_systemd_unit_get_proxy (GDBusProxy *proxy_manager, const gchar *unit, GError **error) +{ + g_autofree gchar *path = NULL; + g_autoptr(GDBusProxy) proxy_unit = NULL; + + path = fu_systemd_unit_get_path (proxy_manager, unit, error); + if (path == NULL) + return NULL; + proxy_unit = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy_manager), + G_DBUS_PROXY_FLAGS_NONE, NULL, + SYSTEMD_SERVICE, + path, + SYSTEMD_INTERFACE, + NULL, error); + if (proxy_unit == NULL) { + g_prefix_error (error, "failed to register proxy for %s: ", path); + return NULL; + } + return g_steal_pointer (&proxy_unit); +} + +gchar * +fu_systemd_get_default_target (GError **error) +{ + const gchar *path = NULL; + g_autoptr(GDBusProxy) proxy_manager = NULL; + g_autoptr(GVariant) val = NULL; + + proxy_manager = fu_systemd_get_manager (error); + if (proxy_manager == NULL) + return NULL; + val = g_dbus_proxy_call_sync (proxy_manager, + "GetDefaultTarget", NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return NULL; + g_variant_get (val, "(&s)", &path); + return g_strdup (path); + +} + +gboolean +fu_systemd_unit_stop (const gchar *unit, GError **error) +{ + g_autoptr(GDBusProxy) proxy_manager = NULL; + g_autoptr(GDBusProxy) proxy_unit = NULL; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (unit != NULL, FALSE); + + proxy_manager = fu_systemd_get_manager (error); + if (proxy_manager == NULL) + return FALSE; + proxy_unit = fu_systemd_unit_get_proxy (proxy_manager, unit, error); + if (proxy_unit == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy_unit, + "StopUnit", + g_variant_new ("(ss)", unit, "replace"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + return val != NULL; +} + +gboolean +fu_systemd_unit_enable (const gchar *unit, GError **error) +{ + const gchar *units[] = { unit, NULL }; + g_autoptr(GDBusProxy) proxy_manager = NULL; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (unit != NULL, FALSE); + + proxy_manager = fu_systemd_get_manager (error); + if (proxy_manager == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy_manager, + "EnableUnitFiles", + g_variant_new ("(^asbb)", units, TRUE, TRUE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + return val != NULL; +} + +gboolean +fu_systemd_unit_disable (const gchar *unit, GError **error) +{ + const gchar *units[] = { unit, NULL }; + g_autoptr(GDBusProxy) proxy_manager = NULL; + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (unit != NULL, FALSE); + + proxy_manager = fu_systemd_get_manager (error); + if (proxy_manager == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy_manager, + "DisableUnitFiles", + g_variant_new ("(^asb)", units, TRUE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + return val != NULL; +} + +gboolean +fu_systemd_unit_check_exists (const gchar *unit, GError **error) +{ + g_autoptr(GDBusProxy) proxy_manager = NULL; + g_autofree gchar *path = NULL; + + g_return_val_if_fail (unit != NULL, FALSE); + + proxy_manager = fu_systemd_get_manager (error); + if (proxy_manager == NULL) + return FALSE; + path = fu_systemd_unit_get_path (proxy_manager, unit, error); + return path != NULL; +} diff -Nru fwupd-1.0.6/src/fu-systemd.h fwupd-1.2.10/src/fu-systemd.h --- fwupd-1.0.6/src/fu-systemd.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-systemd.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean fu_systemd_unit_check_exists (const gchar *unit, + GError **error); +gboolean fu_systemd_unit_stop (const gchar *unit, + GError **error); +gboolean fu_systemd_unit_enable (const gchar *unit, + GError **error); +gboolean fu_systemd_unit_disable (const gchar *unit, + GError **error); +gchar *fu_systemd_get_default_target (GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-test.c fwupd-1.2.10/src/fu-test.c --- fwupd-1.0.6/src/fu-test.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-test.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,22 +1,7 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2010-2017 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" diff -Nru fwupd-1.0.6/src/fu-test.h fwupd-1.2.10/src/fu-test.h --- fwupd-1.0.6/src/fu-test.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-test.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2010-2011 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_TEST_H__ -#define __FU_TEST_H__ +#pragma once #include +G_BEGIN_DECLS + gchar *fu_test_get_filename (const gchar *testdatadirs, const gchar *filename); void fu_test_loop_run_with_timeout (guint timeout_ms); @@ -32,4 +18,4 @@ const gchar *txt2, GError **error); -#endif /* __FU_TEST_H__ */ +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-tool.c fwupd-1.2.10/src/fu-tool.c --- fwupd-1.0.6/src/fu-tool.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-tool.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,1534 @@ +/* + * Copyright (C) 2015-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuMain" + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fu-device-private.h" +#include "fu-engine.h" +#include "fu-history.h" +#include "fu-plugin-private.h" +#include "fu-progressbar.h" +#include "fu-smbios.h" +#include "fu-util-common.h" +#include "fu-debug.h" +#include "fwupd-common-private.h" +#include "fwupd-device-private.h" + +#ifdef HAVE_SYSTEMD +#include "fu-systemd.h" +#endif + +/* custom return code */ +#define EXIT_NOTHING_TO_DO 2 + +typedef enum { + FU_UTIL_OPERATION_UNKNOWN, + FU_UTIL_OPERATION_UPDATE, + FU_UTIL_OPERATION_INSTALL, + FU_UTIL_OPERATION_LAST +} FuUtilOperation; + +struct FuUtilPrivate { + GCancellable *cancellable; + GMainLoop *loop; + GOptionContext *context; + FuEngine *engine; + FuProgressbar *progressbar; + gboolean no_reboot_check; + gboolean prepare_blob; + gboolean cleanup_blob; + gboolean enable_json_state; + FwupdInstallFlags flags; + gboolean show_all_devices; + /* only valid in update and downgrade */ + FuUtilOperation current_operation; + FwupdDevice *current_device; + gchar *current_message; + FwupdDeviceFlags completion_flags; +}; + +static gboolean +fu_util_save_current_state (FuUtilPrivate *priv, GError **error) +{ + g_autoptr(JsonBuilder) builder = NULL; + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; + g_autoptr(GPtrArray) devices = NULL; + g_autofree gchar *state = NULL; + g_autofree gchar *dirname = NULL; + g_autofree gchar *filename = NULL; + + if (!priv->enable_json_state) + return TRUE; + + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + + /* create header */ + builder = json_builder_new (); + json_builder_begin_object (builder); + + /* add each device */ + json_builder_set_member_name (builder, "Devices"); + json_builder_begin_array (builder); + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + json_builder_begin_object (builder); + fwupd_device_to_json (dev, builder); + json_builder_end_object (builder); + } + json_builder_end_array (builder); + json_builder_end_object (builder); + + /* export as a string */ + json_root = json_builder_get_root (builder); + json_generator = json_generator_new (); + json_generator_set_pretty (json_generator, TRUE); + json_generator_set_root (json_generator, json_root); + state = json_generator_to_data (json_generator, NULL); + if (state == NULL) + return FALSE; + dirname = fu_common_get_path (FU_PATH_KIND_LOCALSTATEDIR_PKG); + filename = g_build_filename (dirname, "state.json", NULL); + return g_file_set_contents (filename, state, -1, error); +} + +static gboolean +fu_util_start_engine (FuUtilPrivate *priv, FuEngineLoadFlags flags, GError **error) +{ + g_autoptr(GError) error_local = NULL; + +#ifdef HAVE_SYSTEMD + if (!fu_systemd_unit_stop (fu_util_get_systemd_unit (), &error_local)) + g_debug ("Failed top stop daemon: %s", error_local->message); +#endif + if (!fu_engine_load (priv->engine, flags, error)) + return FALSE; + if (fu_engine_get_tainted (priv->engine)) { + g_printerr ("WARNING: This tool has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n"); + } + return TRUE; +} + +static void +fu_util_maybe_prefix_sandbox_error (const gchar *value, GError **error) +{ + g_autofree gchar *path = g_path_get_dirname (value); + if (!g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + g_prefix_error (error, + "Unable to access %s. You may need to copy %s to %s: ", + path, value, g_getenv ("HOME")); + } +} + +static void +fu_util_cancelled_cb (GCancellable *cancellable, gpointer user_data) +{ + FuUtilPrivate *priv = (FuUtilPrivate *) user_data; + /* TRANSLATORS: this is when a device ctrl+c's a watch */ + g_print ("%s\n", _("Cancelled")); + g_main_loop_quit (priv->loop); +} + +static gboolean +fu_util_smbios_dump (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *tmp = NULL; + g_autoptr(FuSmbios) smbios = NULL; + if (g_strv_length (values) < 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + smbios = fu_smbios_new (); + if (!fu_smbios_setup_from_file (smbios, values[0], error)) + return FALSE; + tmp = fu_smbios_to_string (smbios); + g_print ("%s\n", tmp); + return TRUE; +} + +static gboolean +fu_util_sigint_cb (gpointer user_data) +{ + FuUtilPrivate *priv = (FuUtilPrivate *) user_data; + g_debug ("Handling SIGINT"); + g_cancellable_cancel (priv->cancellable); + return FALSE; +} + +static void +fu_util_private_free (FuUtilPrivate *priv) +{ + if (priv->current_device != NULL) + g_object_unref (priv->current_device); + if (priv->engine != NULL) + g_object_unref (priv->engine); + if (priv->loop != NULL) + g_main_loop_unref (priv->loop); + if (priv->cancellable != NULL) + g_object_unref (priv->cancellable); + if (priv->progressbar != NULL) + g_object_unref (priv->progressbar); + if (priv->context != NULL) + g_option_context_free (priv->context); + g_free (priv->current_message); + g_free (priv); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop + + +static void +fu_main_engine_device_added_cb (FuEngine *engine, + FuDevice *device, + FuUtilPrivate *priv) +{ + g_autofree gchar *tmp = fu_device_to_string (device); + g_debug ("ADDED:\n%s", tmp); +} + +static void +fu_main_engine_device_removed_cb (FuEngine *engine, + FuDevice *device, + FuUtilPrivate *priv) +{ + g_autofree gchar *tmp = fu_device_to_string (device); + g_debug ("REMOVED:\n%s", tmp); +} + +static void +fu_main_engine_status_changed_cb (FuEngine *engine, + FwupdStatus status, + FuUtilPrivate *priv) +{ + fu_progressbar_update (priv->progressbar, status, 0); +} + +static void +fu_main_engine_percentage_changed_cb (FuEngine *engine, + guint percentage, + FuUtilPrivate *priv) +{ + fu_progressbar_update (priv->progressbar, FWUPD_STATUS_UNKNOWN, percentage); +} + +static gboolean +fu_util_watch (FuUtilPrivate *priv, gchar **values, GError **error) +{ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + g_main_loop_run (priv->loop); + return TRUE; +} + +static gint +fu_util_plugin_name_sort_cb (FuPlugin **item1, FuPlugin **item2) +{ + return fu_plugin_name_compare (*item1, *item2); +} + +static gboolean +fu_util_get_plugins (FuUtilPrivate *priv, gchar **values, GError **error) +{ + GPtrArray *plugins; + guint cnt = 0; + + /* load engine */ + if (!fu_engine_load_plugins (priv->engine, error)) + return FALSE; + + /* print */ + plugins = fu_engine_get_plugins (priv->engine); + g_ptr_array_sort (plugins, (GCompareFunc) fu_util_plugin_name_sort_cb); + for (guint i = 0; i < plugins->len; i++) { + FuPlugin *plugin = g_ptr_array_index (plugins, i); + if (!fu_plugin_get_enabled (plugin)) + continue; + g_print ("%s\n", fu_plugin_get_name (plugin)); + cnt++; + } + if (cnt == 0) { + /* TRANSLATORS: nothing found */ + g_print ("%s\n", _("No plugins found")); + return TRUE; + } + + return TRUE; +} + +static gboolean +fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* get devices from daemon */ + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + /* not going to have results, so save a D-Bus round-trip */ + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + /* get the releases for this device and filter for validity */ + rels = fu_engine_get_upgrades (priv->engine, + fwupd_device_get_id (dev), + &error_local); + if (rels == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + g_print ("%s", fwupd_device_to_string (dev)); + g_print (" Release information:\n"); + /* print all releases */ + for (guint j = 0; j < rels->len; j++) { + FwupdRelease *rel = g_ptr_array_index (rels, j); + g_print ("%s\n", fwupd_release_to_string (rel)); + } + } + + /* save the device state for other applications to see */ + if (!fu_util_save_current_state (priv, error)) + return FALSE; + + /* success */ + return TRUE; +} + +static gboolean +fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) array = NULL; + gint fd; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* check args */ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* open file */ + fd = open (values[0], O_RDONLY); + if (fd < 0) { + fu_util_maybe_prefix_sandbox_error (values[0], error); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "failed to open %s", + values[0]); + return FALSE; + } + array = fu_engine_get_details (priv->engine, fd, error); + close (fd); + + if (array == NULL) + return FALSE; + for (guint i = 0; i < array->len; i++) { + FwupdDevice *dev = g_ptr_array_index (array, i); + g_autofree gchar *tmp = NULL; + tmp = fwupd_device_to_string (dev); + g_print ("%s\n", tmp); + } + return TRUE; +} + +static gboolean +fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devs = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* print */ + devs = fu_engine_get_devices (priv->engine, error); + if (devs == NULL) + return FALSE; + if (devs->len == 0) { + /* TRANSLATORS: nothing attached */ + g_print ("%s\n", _("No hardware detected with firmware update capability")); + return TRUE; + } + for (guint i = 0; i < devs->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devs, i); + if (priv->show_all_devices || fu_util_is_interesting_device (dev)) { + g_autofree gchar *tmp = fwupd_device_to_string (dev); + g_print ("%s\n", tmp); + } + } + + /* save the device state for other applications to see */ + if (!fu_util_save_current_state (priv, error)) + return FALSE; + + return TRUE; +} + +static void +fu_util_build_device_tree (FuUtilPrivate *priv, GNode *root, GPtrArray *devs, FuDevice *dev) +{ + for (guint i = 0; i < devs->len; i++) { + FuDevice *dev_tmp = g_ptr_array_index (devs, i); + if (!priv->show_all_devices && + !fu_util_is_interesting_device (FWUPD_DEVICE (dev_tmp))) + continue; + if (fu_device_get_parent (dev_tmp) == dev) { + GNode *child = g_node_append_data (root, dev_tmp); + fu_util_build_device_tree (priv, child, devs, dev_tmp); + } + } +} + +static gboolean +fu_util_get_topology (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GNode) root = g_node_new (NULL); + g_autoptr(GPtrArray) devs = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* print */ + devs = fu_engine_get_devices (priv->engine, error); + if (devs == NULL) + return FALSE; + + /* print */ + if (devs->len == 0) { + /* TRANSLATORS: nothing attached that can be upgraded */ + g_print ("%s\n", _("No hardware detected with firmware update capability")); + return TRUE; + } + fu_util_build_device_tree (priv, root, devs, NULL); + g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + fu_util_print_device_tree, priv); + + return TRUE; +} + + +static FuDevice * +fu_util_prompt_for_device (FuUtilPrivate *priv, GError **error) +{ + FuDevice *dev; + guint idx; + g_autoptr(GPtrArray) devices = NULL; + + /* get devices from daemon */ + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return NULL; + + /* exactly one */ + if (devices->len == 1) { + dev = g_ptr_array_index (devices, 0); + return g_object_ref (dev); + } + + /* TRANSLATORS: get interactive prompt */ + g_print ("%s\n", _("Choose a device:")); + /* TRANSLATORS: this is to abort the interactive prompt */ + g_print ("0.\t%s\n", _("Cancel")); + for (guint i = 0; i < devices->len; i++) { + dev = g_ptr_array_index (devices, i); + g_print ("%u.\t%s (%s)\n", + i + 1, + fu_device_get_id (dev), + fu_device_get_name (dev)); + } + idx = fu_util_prompt_for_number (devices->len); + if (idx == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Request canceled"); + return NULL; + } + dev = g_ptr_array_index (devices, idx - 1); + return g_object_ref (dev); +} + +static void +fu_util_update_device_changed_cb (FwupdClient *client, + FwupdDevice *device, + FuUtilPrivate *priv) +{ + g_autofree gchar *str = NULL; + + /* allowed to set whenever the device has changed */ + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + + /* same as last time, so ignore */ + if (priv->current_device != NULL && + fwupd_device_compare (priv->current_device, device) == 0) + return; + + /* show message in progressbar */ + if (priv->current_operation == FU_UTIL_OPERATION_UPDATE) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Updating %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else if (priv->current_operation == FU_UTIL_OPERATION_INSTALL) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Installing on %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else { + g_warning ("no FuUtilOperation set"); + } + g_set_object (&priv->current_device, device); + + if (priv->current_message == NULL) { + const gchar *tmp = fwupd_device_get_update_message (priv->current_device); + if (tmp != NULL) + priv->current_message = g_strdup (tmp); + } +} + +static void +fu_util_display_current_message (FuUtilPrivate *priv) +{ + if (priv->current_message == NULL) + return; + g_print ("%s\n", priv->current_message); + g_clear_pointer (&priv->current_message, g_free); +} + +static gboolean +fu_util_install_blob (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuDevice) device = NULL; + g_autoptr(GBytes) blob_fw = NULL; + + /* invalid args */ + if (g_strv_length (values) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* parse blob */ + blob_fw = fu_common_get_contents_bytes (values[0], error); + if (blob_fw == NULL) { + fu_util_maybe_prefix_sandbox_error (values[0], error); + return FALSE; + } + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* get device */ + if (g_strv_length (values) >= 2) { + device = fu_engine_get_device (priv->engine, values[1], error); + if (device == NULL) + return FALSE; + } else { + device = fu_util_prompt_for_device (priv, error); + if (device == NULL) + return FALSE; + } + + priv->current_operation = FU_UTIL_OPERATION_INSTALL; + g_signal_connect (priv->engine, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + + /* write bare firmware */ + if (priv->prepare_blob) { + g_autoptr(GPtrArray) devices = NULL; + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices, g_object_ref (device)); + if (!fu_engine_composite_prepare (priv->engine, devices, error)) { + g_prefix_error (error, "failed to prepare composite action: "); + return FALSE; + } + } + priv->flags = FWUPD_INSTALL_FLAG_NO_HISTORY; + if (!fu_engine_install_blob (priv->engine, device, blob_fw, priv->flags, error)) + return FALSE; + if (priv->cleanup_blob) { + g_autoptr(FuDevice) device_new = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the possibly new device from the old ID */ + device_new = fu_engine_get_device (priv->engine, + fu_device_get_id (device), + &error_local); + if (device_new == NULL) { + g_debug ("failed to find new device: %s", + error_local->message); + } else { + g_autoptr(GPtrArray) devices_new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices_new, g_steal_pointer (&device_new)); + if (!fu_engine_composite_cleanup (priv->engine, devices_new, error)) { + g_prefix_error (error, "failed to cleanup composite action: "); + return FALSE; + } + } + } + + fu_util_display_current_message (priv); + + /* success */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + +static gint +fu_util_install_task_sort_cb (gconstpointer a, gconstpointer b) +{ + FuInstallTask *task1 = *((FuInstallTask **) a); + FuInstallTask *task2 = *((FuInstallTask **) b); + return fu_install_task_compare (task1, task2); +} + +static gboolean +fu_util_download_out_of_process (const gchar *uri, const gchar *fn, GError **error) +{ + const gchar *argv[][5] = { { "wget", uri, "-o", fn, NULL }, + { "curl", uri, "--output", fn, NULL }, + { NULL } }; + for (guint i = 0; argv[i][0] != NULL; i++) { + g_autoptr(GError) error_local = NULL; + if (!fu_common_find_program_in_path (argv[i][0], &error_local)) { + g_debug ("%s", error_local->message); + continue; + } + return fu_common_spawn_sync (argv[i], NULL, NULL, 0, NULL, error); + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "no supported out-of-process downloaders found"); + return FALSE; +} + +static gchar * +fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GError **error) +{ + g_autofree gchar *filename = NULL; + g_autoptr(SoupURI) uri = NULL; + + /* a local file */ + uri = soup_uri_new (perhapsfn); + if (uri == NULL) + return g_strdup (perhapsfn); + + /* download the firmware to a cachedir */ + filename = fu_util_get_user_cache_path (perhapsfn); + if (!fu_common_mkdir_parent (filename, error)) + return NULL; + if (!fu_util_download_out_of_process (perhapsfn, filename, error)) + return NULL; + return g_steal_pointer (&filename); +} + +static gboolean +fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *filename = NULL; + g_autoptr(GBytes) blob_cab = NULL; + g_autoptr(GPtrArray) components = NULL; + g_autoptr(GPtrArray) devices_possible = NULL; + g_autoptr(GPtrArray) errors = NULL; + g_autoptr(GPtrArray) install_tasks = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* handle both forms */ + if (g_strv_length (values) == 1) { + devices_possible = fu_engine_get_devices (priv->engine, error); + if (devices_possible == NULL) + return FALSE; + } else if (g_strv_length (values) == 2) { + FuDevice *device = fu_engine_get_device (priv->engine, + values[1], + error); + if (device == NULL) + return FALSE; + devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices_possible, device); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* download if required */ + filename = fu_util_download_if_required (priv, values[0], error); + if (filename == NULL) + return FALSE; + + /* parse silo */ + blob_cab = fu_common_get_contents_bytes (filename, error); + if (blob_cab == NULL) { + fu_util_maybe_prefix_sandbox_error (filename, error); + return FALSE; + } + silo = fu_engine_get_silo_from_blob (priv->engine, blob_cab, error); + if (silo == NULL) + return FALSE; + components = xb_silo_query (silo, "components/component", 0, error); + if (components == NULL) + return FALSE; + + /* for each component in the silo */ + errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free); + install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (guint i = 0; i < components->len; i++) { + XbNode *component = g_ptr_array_index (components, i); + + /* do any devices pass the requirements */ + for (guint j = 0; j < devices_possible->len; j++) { + FuDevice *device = g_ptr_array_index (devices_possible, j); + g_autoptr(FuInstallTask) task = NULL; + g_autoptr(GError) error_local = NULL; + + /* is this component valid for the device */ + task = fu_install_task_new (device, component); + if (!fu_engine_check_requirements (priv->engine, + task, priv->flags, + &error_local)) { + g_debug ("requirement on %s:%s failed: %s", + fu_device_get_id (device), + xb_node_query_text (component, "id", NULL), + error_local->message); + g_ptr_array_add (errors, g_steal_pointer (&error_local)); + continue; + } + + /* if component should have an update message from CAB */ + fu_device_incorporate_from_component (device, component); + + /* success */ + g_ptr_array_add (install_tasks, g_steal_pointer (&task)); + } + } + + /* order the install tasks by the device priority */ + g_ptr_array_sort (install_tasks, fu_util_install_task_sort_cb); + + /* nothing suitable */ + if (install_tasks->len == 0) { + GError *error_tmp = fu_common_error_array_get_best (errors); + g_propagate_error (error, error_tmp); + return FALSE; + } + + priv->current_operation = FU_UTIL_OPERATION_INSTALL; + g_signal_connect (priv->engine, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + + /* install all the tasks */ + if (!fu_engine_install_tasks (priv->engine, install_tasks, blob_cab, priv->flags, error)) + return FALSE; + + fu_util_display_current_message (priv); + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + /* save the device state for other applications to see */ + if (!fu_util_save_current_state (priv, error)) + return FALSE; + + /* success */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + +static gboolean +fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + priv->current_operation = FU_UTIL_OPERATION_UPDATE; + g_signal_connect (priv->engine, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + + devices = fu_engine_get_devices (priv->engine, error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + FwupdRelease *rel; + const gchar *remote_id; + const gchar *device_id; + const gchar *uri_tmp; + g_autoptr(GPtrArray) rels = NULL; + g_autoptr(GError) error_local = NULL; + + if (!fu_util_is_interesting_device (dev)) + continue; + /* only show stuff that has metadata available */ + if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED)) + continue; + + device_id = fu_device_get_id (dev); + rels = fu_engine_get_upgrades (priv->engine, device_id, &error_local); + if (rels == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + + rel = g_ptr_array_index (rels, 0); + uri_tmp = fwupd_release_get_uri (rel); + remote_id = fwupd_release_get_remote_id (rel); + if (remote_id != NULL) { + FwupdRemote *remote; + g_auto(GStrv) argv = NULL; + + remote = fu_engine_get_remote_by_id (priv->engine, + remote_id, + &error_local); + if (remote == NULL) { + g_printerr ("%s\n", error_local->message); + continue; + } + + argv = g_new0 (gchar *, 2); + /* local remotes have the firmware already */ + if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { + const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); + g_autofree gchar *path = g_path_get_dirname (fn_cache); + argv[0] = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + argv[0] = g_strdup (uri_tmp + 7); + /* web remote, fu_util_install will download file */ + } else { + argv[0] = fwupd_remote_build_firmware_uri (remote, uri_tmp, error); + } + if (!fu_util_install (priv, argv, &error_local)) { + g_printerr ("%s\n", error_local->message); + continue; + } + fu_util_display_current_message (priv); + } + } + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + /* save the device state for other applications to see */ + if (!fu_util_save_current_state (priv, error)) + return FALSE; + + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + +static gboolean +fu_util_detach (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuDevice) device = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* invalid args */ + if (g_strv_length (values) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* get device */ + if (g_strv_length (values) >= 1) { + device = fu_engine_get_device (priv->engine, values[0], error); + if (device == NULL) + return FALSE; + } else { + device = fu_util_prompt_for_device (priv, error); + if (device == NULL) + return FALSE; + } + + /* run vfunc */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_detach (device, error); +} + +static gboolean +fu_util_attach (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuDevice) device = NULL; + g_autoptr(FuDeviceLocker) locker = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* invalid args */ + if (g_strv_length (values) == 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* get device */ + if (g_strv_length (values) >= 1) { + device = fu_engine_get_device (priv->engine, values[0], error); + if (device == NULL) + return FALSE; + } else { + device = fu_util_prompt_for_device (priv, error); + if (device == NULL) + return FALSE; + } + + /* run vfunc */ + locker = fu_device_locker_new (device, error); + if (locker == NULL) + return FALSE; + return fu_device_attach (device, error); +} + +static gboolean +fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) +{ + gboolean has_pending = FALSE; + g_autoptr(FuHistory) history = fu_history_new (); + g_autoptr(GPtrArray) devices = NULL; + + /* check the history database before starting the daemon */ + if (g_strv_length (values) == 0) { + devices = fu_history_get_devices (history, error); + if (devices == NULL) + return FALSE; + } else if (g_strv_length (values) == 1) { + FuDevice *device; + device = fu_history_get_device_by_id (history, values[0], error); + if (device == NULL) + return FALSE; + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices, device); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* nothing to do */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *dev = g_ptr_array_index (devices, i); + if (fu_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { + fu_engine_add_plugin_filter (priv->engine, + fu_device_get_plugin (dev)); + has_pending = TRUE; + } + } + if (!has_pending) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No firmware to activate"); + return FALSE; + + } + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_READONLY_FS, error)) + return FALSE; + + /* activate anything with _NEEDS_ACTIVATION */ + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) + continue; + /* TRANSLATORS: shown when shutting down to switch to the new version */ + g_print ("%s %s…\n", _("Activating firmware update"), fu_device_get_name (device)); + if (!fu_engine_activate (priv->engine, fu_device_get_id (device), error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_util_hwids (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FuSmbios) smbios = fu_smbios_new (); + g_autoptr(FuHwids) hwids = fu_hwids_new (); + const gchar *hwid_keys[] = { + FU_HWIDS_KEY_BIOS_VENDOR, + FU_HWIDS_KEY_BIOS_VERSION, + FU_HWIDS_KEY_BIOS_MAJOR_RELEASE, + FU_HWIDS_KEY_BIOS_MINOR_RELEASE, + FU_HWIDS_KEY_MANUFACTURER, + FU_HWIDS_KEY_FAMILY, + FU_HWIDS_KEY_PRODUCT_NAME, + FU_HWIDS_KEY_PRODUCT_SKU, + FU_HWIDS_KEY_ENCLOSURE_KIND, + FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, + FU_HWIDS_KEY_BASEBOARD_PRODUCT, + NULL }; + + /* read DMI data */ + if (g_strv_length (values) == 0) { + if (!fu_smbios_setup (smbios, error)) + return FALSE; + } else if (g_strv_length (values) == 1) { + if (!fu_smbios_setup_from_file (smbios, values[0], error)) + return FALSE; + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + if (!fu_hwids_setup (hwids, smbios, error)) + return FALSE; + + /* show debug output */ + g_print ("Computer Information\n"); + g_print ("--------------------\n"); + for (guint i = 0; hwid_keys[i] != NULL; i++) { + const gchar *tmp = fu_hwids_get_value (hwids, hwid_keys[i]); + if (tmp == NULL) + continue; + if (g_strcmp0 (hwid_keys[i], FU_HWIDS_KEY_BIOS_MAJOR_RELEASE) == 0 || + g_strcmp0 (hwid_keys[i], FU_HWIDS_KEY_BIOS_MINOR_RELEASE) == 0) { + guint64 val = g_ascii_strtoull (tmp, NULL, 16); + g_print ("%s: %" G_GUINT64_FORMAT "\n", hwid_keys[i], val); + } else { + g_print ("%s: %s\n", hwid_keys[i], tmp); + } + } + + /* show GUIDs */ + g_print ("\nHardware IDs\n"); + g_print ("------------\n"); + for (guint i = 0; i < 15; i++) { + const gchar *keys = NULL; + g_autofree gchar *guid = NULL; + g_autofree gchar *key = NULL; + g_autofree gchar *keys_str = NULL; + g_auto(GStrv) keysv = NULL; + g_autoptr(GError) error_local = NULL; + + /* get the GUID */ + key = g_strdup_printf ("HardwareID-%u", i); + keys = fu_hwids_get_replace_keys (hwids, key); + guid = fu_hwids_get_guid (hwids, key, &error_local); + if (guid == NULL) { + g_print ("%s\n", error_local->message); + continue; + } + + /* show what makes up the GUID */ + keysv = g_strsplit (keys, "&", -1); + keys_str = g_strjoinv (" + ", keysv); + g_print ("{%s} <- %s\n", guid, keys_str); + } + + return TRUE; +} + +static gboolean +fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) +{ + const gchar *script_fn = "startup.sh"; + const gchar *output_fn = "firmware.bin"; + g_autoptr(GBytes) archive_blob = NULL; + g_autoptr(GBytes) firmware_blob = NULL; + if (g_strv_length (values) < 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + archive_blob = fu_common_get_contents_bytes (values[0], error); + if (archive_blob == NULL) + return FALSE; + if (g_strv_length (values) > 2) + script_fn = values[2]; + if (g_strv_length (values) > 3) + output_fn = values[3]; + firmware_blob = fu_common_firmware_builder (archive_blob, script_fn, output_fn, error); + if (firmware_blob == NULL) + return FALSE; + return fu_common_set_contents_bytes (values[1], firmware_blob, error); +} + +static gboolean +fu_util_self_sign (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *sig = NULL; + + /* check args */ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: value expected"); + return FALSE; + } + + /* start engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + sig = fu_engine_self_sign (priv->engine, values[0], + FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP | + FU_KEYRING_SIGN_FLAG_ADD_CERT, error); + if (sig == NULL) + return FALSE; + g_print ("%s\n", sig); + return TRUE; +} + +static void +fu_util_device_added_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device is hotplugged */ + g_print ("%s\n%s", _("Device added:"), tmp); +} + +static void +fu_util_device_removed_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device is hotplugged */ + g_print ("%s\n%s", _("Device removed:"), tmp); +} + +static void +fu_util_device_changed_cb (FwupdClient *client, + FwupdDevice *device, + gpointer user_data) +{ + g_autofree gchar *tmp = fwupd_device_to_string (device); + /* TRANSLATORS: this is when a device has been updated */ + g_print ("%s\n%s", _("Device changed:"), tmp); +} + +static void +fu_util_changed_cb (FwupdClient *client, gpointer user_data) +{ + /* TRANSLATORS: this is when the daemon state changes */ + g_print ("%s\n", _("Changed")); +} + +static gboolean +fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(FwupdClient) client = fwupd_client_new (); + + /* get all the devices */ + if (!fwupd_client_connect (client, priv->cancellable, error)) + return FALSE; + + /* watch for any hotplugged device */ + g_signal_connect (client, "changed", + G_CALLBACK (fu_util_changed_cb), priv); + g_signal_connect (client, "device-added", + G_CALLBACK (fu_util_device_added_cb), priv); + g_signal_connect (client, "device-removed", + G_CALLBACK (fu_util_device_removed_cb), priv); + g_signal_connect (client, "device-changed", + G_CALLBACK (fu_util_device_changed_cb), priv); + g_signal_connect (priv->cancellable, "cancelled", + G_CALLBACK (fu_util_cancelled_cb), priv); + g_main_loop_run (priv->loop); + return TRUE; +} + +static gboolean +fu_util_verify_update (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *str = NULL; + g_autoptr(FuDevice) dev = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* get device */ + if (g_strv_length (values) == 1) { + dev = fu_engine_get_device (priv->engine, values[1], error); + if (dev == NULL) + return FALSE; + } else { + dev = fu_util_prompt_for_device (priv, error); + if (dev == NULL) + return FALSE; + } + + /* add checksums */ + if (!fu_engine_verify_update (priv->engine, fu_device_get_id (dev), error)) + return FALSE; + + /* show checksums */ + str = fu_device_to_string (dev); + g_print ("%s\n", str); + return TRUE; +} + +static gboolean +fu_util_get_history (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* load engine */ + if (!fu_util_start_engine (priv, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + + /* get all devices from the history database */ + devices = fu_engine_get_history (priv->engine, error); + if (devices == NULL) + return FALSE; + + /* show each device */ + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + g_autofree gchar *str = fwupd_device_to_string (dev); + g_print ("%s\n", str); + } + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + gboolean allow_older = FALSE; + gboolean allow_reinstall = FALSE; + gboolean force = FALSE; + gboolean ret; + gboolean version = FALSE; + gboolean interactive = isatty (fileno (stdout)) != 0; + g_auto(GStrv) plugin_glob = NULL; + g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) cmd_array = fu_util_cmd_array_new (); + g_autofree gchar *cmd_descriptions = NULL; + const GOptionEntry options[] = { + { "version", '\0', 0, G_OPTION_ARG_NONE, &version, + /* TRANSLATORS: command line option */ + _("Show client and daemon versions"), NULL }, + { "allow-reinstall", '\0', 0, G_OPTION_ARG_NONE, &allow_reinstall, + /* TRANSLATORS: command line option */ + _("Allow re-installing existing firmware versions"), NULL }, + { "allow-older", '\0', 0, G_OPTION_ARG_NONE, &allow_older, + /* TRANSLATORS: command line option */ + _("Allow downgrading firmware versions"), NULL }, + { "force", '\0', 0, G_OPTION_ARG_NONE, &force, + /* TRANSLATORS: command line option */ + _("Override plugin warning"), NULL }, + { "no-reboot-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_reboot_check, + /* TRANSLATORS: command line option */ + _("Do not check for reboot after update"), NULL }, + { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, + /* TRANSLATORS: command line option */ + _("Show devices that are not updatable"), NULL }, + { "plugin-whitelist", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &plugin_glob, + /* TRANSLATORS: command line option */ + _("Manually whitelist specific plugins"), NULL }, + { "prepare", '\0', 0, G_OPTION_ARG_NONE, &priv->prepare_blob, + /* TRANSLATORS: command line option */ + _("Run the plugin composite prepare routine when using install-blob"), NULL }, + { "cleanup", '\0', 0, G_OPTION_ARG_NONE, &priv->cleanup_blob, + /* TRANSLATORS: command line option */ + _("Run the plugin composite cleanup routine when using install-blob"), NULL }, + { "enable-json-state", '\0', 0, G_OPTION_ARG_NONE, &priv->enable_json_state, + /* TRANSLATORS: command line option */ + _("Save device state into a JSON file between executions"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + /* ensure root user */ + if (interactive && (getuid () != 0 || geteuid () != 0)) + /* TRANSLATORS: we're poking around as a power user */ + g_printerr ("%s\n", _("This program may only work correctly as root")); + + /* create helper object */ + priv->loop = g_main_loop_new (NULL, FALSE); + priv->progressbar = fu_progressbar_new (); + + /* add commands */ + fu_util_cmd_array_add (cmd_array, + "build-firmware", + "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]", + /* TRANSLATORS: command description */ + _("Build firmware using a sandbox"), + fu_util_firmware_builder); + fu_util_cmd_array_add (cmd_array, + "smbios-dump", + "FILE", + /* TRANSLATORS: command description */ + _("Dump SMBIOS data from a file"), + fu_util_smbios_dump); + fu_util_cmd_array_add (cmd_array, + "get-plugins", + NULL, + /* TRANSLATORS: command description */ + _("Get all enabled plugins registered with the system"), + fu_util_get_plugins); + fu_util_cmd_array_add (cmd_array, + "get-details", + NULL, + /* TRANSLATORS: command description */ + _("Gets details about a firmware file"), + fu_util_get_details); + fu_util_cmd_array_add (cmd_array, + "get-history", + NULL, + /* TRANSLATORS: command description */ + _("Show history of firmware updates"), + fu_util_get_history); + fu_util_cmd_array_add (cmd_array, + "get-updates", + NULL, + /* TRANSLATORS: command description */ + _("Gets the list of updates for connected hardware"), + fu_util_get_updates); + fu_util_cmd_array_add (cmd_array, + "get-devices", + NULL, + /* TRANSLATORS: command description */ + _("Get all devices that support firmware updates"), + fu_util_get_devices); + fu_util_cmd_array_add (cmd_array, + "get-topology", + NULL, + /* TRANSLATORS: command description */ + _("Get all devices according to the system topology"), + fu_util_get_topology); + fu_util_cmd_array_add (cmd_array, + "watch", + NULL, + /* TRANSLATORS: command description */ + _("Watch for hardware changes"), + fu_util_watch); + fu_util_cmd_array_add (cmd_array, + "install-blob", + "FILENAME DEVICE-ID", + /* TRANSLATORS: command description */ + _("Install a firmware blob on a device"), + fu_util_install_blob); + fu_util_cmd_array_add (cmd_array, + "install", + "FILE [ID]", + /* TRANSLATORS: command description */ + _("Install a firmware file on this hardware"), + fu_util_install); + fu_util_cmd_array_add (cmd_array, + "attach", + "DEVICE-ID", + /* TRANSLATORS: command description */ + _("Attach to firmware mode"), + fu_util_attach); + fu_util_cmd_array_add (cmd_array, + "detach", + "DEVICE-ID", + /* TRANSLATORS: command description */ + _("Detach to bootloader mode"), + fu_util_detach); + fu_util_cmd_array_add (cmd_array, + "activate", + "[DEVICE-ID]", + /* TRANSLATORS: command description */ + _("Activate pending devices"), + fu_util_activate); + fu_util_cmd_array_add (cmd_array, + "hwids", + "[FILE]", + /* TRANSLATORS: command description */ + _("Return all the hardware IDs for the machine"), + fu_util_hwids); + fu_util_cmd_array_add (cmd_array, + "monitor", + NULL, + /* TRANSLATORS: command description */ + _("Monitor the daemon for events"), + fu_util_monitor); + fu_util_cmd_array_add (cmd_array, + "update", + NULL, + /* TRANSLATORS: command description */ + _("Update all devices that match local metadata"), + fu_util_update); + fu_util_cmd_array_add (cmd_array, + "self-sign", + "TEXT", + /* TRANSLATORS: command description */ + C_("command-description", + "Sign data using the client certificate"), + fu_util_self_sign); + fu_util_cmd_array_add (cmd_array, + "verify-update", + "[DEVICE_ID]", + /* TRANSLATORS: command description */ + _("Update the stored metadata with current contents"), + fu_util_verify_update); + + /* do stuff on ctrl+c */ + priv->cancellable = g_cancellable_new (); + g_unix_signal_add_full (G_PRIORITY_DEFAULT, + SIGINT, fu_util_sigint_cb, + priv, NULL); + g_signal_connect (priv->cancellable, "cancelled", + G_CALLBACK (fu_util_cancelled_cb), priv); + + /* sort by command name */ + fu_util_cmd_array_sort (cmd_array); + + /* non-TTY consoles cannot answer questions */ + if (!interactive) { + priv->no_reboot_check = TRUE; + fu_progressbar_set_interactive (priv->progressbar, FALSE); + } + + /* get a list of the commands */ + priv->context = g_option_context_new (NULL); + cmd_descriptions = fu_util_cmd_array_to_string (cmd_array); + g_option_context_set_summary (priv->context, cmd_descriptions); + g_option_context_set_description (priv->context, + "This tool allows an administrator to use the fwupd plugins " + "without being installed on the host system."); + + /* TRANSLATORS: program name */ + g_set_application_name (_("Firmware Utility")); + g_option_context_add_main_entries (priv->context, options, NULL); + g_option_context_add_group (priv->context, fu_debug_get_option_group ()); + ret = g_option_context_parse (priv->context, &argc, &argv, &error); + if (!ret) { + /* TRANSLATORS: the user didn't read the man page */ + g_print ("%s: %s\n", _("Failed to parse arguments"), + error->message); + return EXIT_FAILURE; + } + + /* set flags */ + if (allow_reinstall) + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL; + if (allow_older) + priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; + if (force) + priv->flags |= FWUPD_INSTALL_FLAG_FORCE; + + /* load engine */ + priv->engine = fu_engine_new (FU_APP_FLAGS_NO_IDLE_SOURCES); + g_signal_connect (priv->engine, "device-added", + G_CALLBACK (fu_main_engine_device_added_cb), + priv); + g_signal_connect (priv->engine, "device-removed", + G_CALLBACK (fu_main_engine_device_removed_cb), + priv); + g_signal_connect (priv->engine, "status-changed", + G_CALLBACK (fu_main_engine_status_changed_cb), + priv); + g_signal_connect (priv->engine, "percentage-changed", + G_CALLBACK (fu_main_engine_percentage_changed_cb), + priv); + + /* just show versions and exit */ + if (version) { + g_autofree gchar *version_str = fu_util_get_versions (); + g_print ("%s\n", version_str); + return EXIT_SUCCESS; + } + + /* any plugin whitelist specified */ + for (guint i = 0; plugin_glob != NULL && plugin_glob[i] != NULL; i++) + fu_engine_add_plugin_filter (priv->engine, plugin_glob[i]); + + /* run the specified command */ + ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); + if (!ret) { + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) { + g_autofree gchar *tmp = NULL; + tmp = g_option_context_get_help (priv->context, TRUE, NULL); + g_print ("%s\n\n%s", error->message, tmp); + return EXIT_FAILURE; + } + if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) { + g_print ("%s\n", error->message); + return EXIT_NOTHING_TO_DO; + } + g_print ("%s\n", error->message); + return EXIT_FAILURE; + } + + /* success */ + return EXIT_SUCCESS; +} diff -Nru fwupd-1.0.6/src/fu-udev-device.c fwupd-1.2.10/src/fu-udev-device.c --- fwupd-1.0.6/src/fu-udev-device.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-udev-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,593 @@ +/* + * Copyright (C) 2017-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuUdevDevice" + +#include "config.h" + +#include + +#include "fu-device-private.h" +#include "fu-udev-device-private.h" + +/** + * SECTION:fu-udev-device + * @short_description: a udev device + * + * An object that represents a udev device. + * + * See also: #FuDevice + */ + +typedef struct +{ + GUdevDevice *udev_device; + guint16 vendor; + guint16 model; + guint8 revision; +} FuUdevDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FuUdevDevice, fu_udev_device, FU_TYPE_DEVICE) + +#ifndef HAVE_GUDEV_232 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref) +#pragma clang diagnostic pop +#endif + +enum { + PROP_0, + PROP_UDEV_DEVICE, + PROP_LAST +}; + +enum { + SIGNAL_CHANGED, + SIGNAL_LAST +}; + +static guint signals[SIGNAL_LAST] = { 0 }; + +#define GET_PRIVATE(o) (fu_udev_device_get_instance_private (o)) + +/** + * fu_udev_device_emit_changed: + * @self: A #FuUdevDevice + * + * Emits the ::changed signal for the object. + * + * Since: 1.1.2 + **/ +void +fu_udev_device_emit_changed (FuUdevDevice *self) +{ + g_return_if_fail (FU_IS_UDEV_DEVICE (self)); + g_debug ("FuUdevDevice emit changed"); + g_signal_emit (self, signals[SIGNAL_CHANGED], 0); +} + +static guint64 +fu_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *udev_device, const gchar *name) +{ + return fu_common_strtoull (g_udev_device_get_sysfs_attr (udev_device, name)); +} + +static guint16 +fu_udev_device_read_uint16 (const gchar *str) +{ + gchar buf[5] = { 0x0, 0x0, 0x0, 0x0, 0x0 }; + memcpy (buf, str, 4); + return (guint16) g_ascii_strtoull (buf, NULL, 16); +} + +static void +fu_udev_device_dump_internal (GUdevDevice *udev_device) +{ +#ifdef HAVE_GUDEV_232 + const gchar * const *keys; + + keys = g_udev_device_get_property_keys (udev_device); + for (guint i = 0; keys[i] != NULL; i++) { + g_debug ("%s={%s}", keys[i], + g_udev_device_get_property (udev_device, keys[i])); + } + keys = g_udev_device_get_sysfs_attr_keys (udev_device); + for (guint i = 0; keys[i] != NULL; i++) { + g_debug ("%s=[%s]", keys[i], + g_udev_device_get_sysfs_attr (udev_device, keys[i])); + } +#endif +} + +void +fu_udev_device_dump (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + fu_udev_device_dump_internal (priv->udev_device); +} + +static gboolean +fu_udev_device_probe (FuDevice *device, GError **error) +{ + FuUdevDeviceClass *klass = FU_UDEV_DEVICE_GET_CLASS (device); + FuUdevDevice *self = FU_UDEV_DEVICE (device); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *tmp; + g_autofree gchar *subsystem = NULL; + g_autoptr(GUdevDevice) udev_parent = NULL; + + /* set ven:dev:rev */ + priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "vendor"); + priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "device"); + priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (priv->udev_device, "revision"); + + /* fallback to the parent */ + udev_parent = g_udev_device_get_parent (priv->udev_device); + if (udev_parent != NULL && + priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0) { + priv->vendor = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "vendor"); + priv->model = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "device"); + priv->revision = fu_udev_device_get_sysfs_attr_as_uint64 (udev_parent, "revision"); + } + + /* hidraw helpfully encodes the information in a different place */ + if (udev_parent != NULL && + priv->vendor == 0x0 && priv->model == 0x0 && priv->revision == 0x0 && + g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), "hidraw") == 0) { + tmp = g_udev_device_get_property (udev_parent, "HID_ID"); + if (tmp != NULL && strlen (tmp) == 22) { + priv->vendor = fu_udev_device_read_uint16 (tmp + 10); + priv->model = fu_udev_device_read_uint16 (tmp + 18); + } + tmp = g_udev_device_get_property (udev_parent, "HID_NAME"); + if (tmp != NULL) { + g_auto(GStrv) vm = g_strsplit (tmp, " ", 2); + if (g_strv_length (vm) == 2) { + if (fu_device_get_vendor (device) == NULL) + fu_device_set_vendor (device, vm[0]); + if (fu_device_get_name (device) == NULL) + fu_device_set_name (device, vm[1]); + } + } + } + + /* set the version if the revision has been set */ + if (fu_device_get_version (device) == NULL) { + if (priv->revision != 0x00) { + g_autofree gchar *version = g_strdup_printf ("%02x", priv->revision); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_PLAIN); + } + } + + /* set model */ + if (fu_device_get_name (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_MODEL"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL_FROM_DATABASE"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_MODEL"); + if (tmp != NULL) + fu_device_set_name (device, tmp); + } + + /* set vendor */ + if (fu_device_get_vendor (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "FWUPD_VENDOR"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR_FROM_DATABASE"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_VENDOR"); + if (tmp != NULL) + fu_device_set_vendor (device, tmp); + } + + /* set serial */ + if (fu_device_get_serial (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL_SHORT"); + if (tmp == NULL) + tmp = g_udev_device_get_property (priv->udev_device, "ID_SERIAL"); + if (tmp != NULL) + fu_device_set_serial (device, tmp); + } + + /* set revision */ + if (fu_device_get_version (device) == NULL) { + tmp = g_udev_device_get_property (priv->udev_device, "ID_REVISION"); + if (tmp != NULL) + fu_device_set_version (device, tmp, FWUPD_VERSION_FORMAT_UNKNOWN); + } + + /* set vendor ID */ + subsystem = g_ascii_strup (fu_udev_device_get_subsystem (self), -1); + if (subsystem != NULL && priv->vendor != 0x0000) { + g_autofree gchar *vendor_id = NULL; + vendor_id = g_strdup_printf ("%s:0x%04X", subsystem, (guint) priv->vendor); + fu_device_set_vendor_id (device, vendor_id); + } + + /* add GUIDs in order of priority */ + if (priv->vendor != 0x0000 && priv->model != 0x0000 && priv->revision != 0x00) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X&REV_%02X", + subsystem, priv->vendor, + priv->model, priv->revision); + fu_device_add_instance_id (device, devid); + } + if (priv->vendor != 0x0000 && priv->model != 0x0000) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\VEN_%04X&DEV_%04X", + subsystem, priv->vendor, priv->model); + fu_device_add_instance_id (device, devid); + } + if (priv->vendor != 0x0000) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf ("%s\\VEN_%04X", subsystem, priv->vendor); + fu_device_add_instance_id_full (device, devid, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } + + /* subclassed */ + if (klass->probe != NULL) { + if (!klass->probe (self, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static void +fu_udev_device_set_dev (FuUdevDevice *self, GUdevDevice *udev_device) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + g_return_if_fail (FU_IS_UDEV_DEVICE (self)); + + /* set new device */ + g_set_object (&priv->udev_device, udev_device); + if (priv->udev_device == NULL) + return; +} + +guint +fu_udev_device_get_slot_depth (FuUdevDevice *self, const gchar *subsystem) +{ + GUdevDevice *udev_device = fu_udev_device_get_dev (FU_UDEV_DEVICE (self)); + g_autoptr(GUdevDevice) device_tmp = NULL; + + device_tmp = g_udev_device_get_parent_with_subsystem (udev_device, subsystem, NULL); + if (device_tmp == NULL) + return 0; + for (guint i = 0; i < 0xff; i++) { + g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (device_tmp); + if (parent == NULL) + return i; + g_set_object (&device_tmp, parent); + } + return 0; +} + +static void +fu_udev_device_incorporate (FuDevice *self, FuDevice *donor) +{ + g_return_if_fail (FU_IS_UDEV_DEVICE (self)); + g_return_if_fail (FU_IS_UDEV_DEVICE (donor)); + fu_udev_device_set_dev (FU_UDEV_DEVICE (self), + fu_udev_device_get_dev (FU_UDEV_DEVICE (donor))); +} + +/** + * fu_udev_device_get_dev: + * @self: A #FuUdevDevice + * + * Gets the #GUdevDevice. + * + * Returns: (transfer none): a #GUdevDevice, or %NULL + * + * Since: 1.1.2 + **/ +GUdevDevice * +fu_udev_device_get_dev (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + return priv->udev_device; +} + +/** + * fu_udev_device_get_subsystem: + * @self: A #GUdevDevice + * + * Gets the device subsystem, e.g. "pci". + * + * Returns: a subsystem, or NULL if unset or invalid + * + * Since: 1.1.2 + **/ +const gchar * +fu_udev_device_get_subsystem (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + return g_udev_device_get_subsystem (priv->udev_device); +} + +/** + * fu_udev_device_get_sysfs_path: + * @self: A #GUdevDevice + * + * Gets the device sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:14.0". + * + * Returns: a local path, or NULL if unset or invalid + * + * Since: 1.1.2 + **/ +const gchar * +fu_udev_device_get_sysfs_path (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), NULL); + return g_udev_device_get_sysfs_path (priv->udev_device); +} + +/** + * fu_udev_device_get_vendor: + * @self: A #GUdevDevice + * + * Gets the device vendor code. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.1.2 + **/ +guint16 +fu_udev_device_get_vendor (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x0000); + return priv->vendor; +} + +/** + * fu_udev_device_get_model: + * @self: A #GUdevDevice + * + * Gets the device device code. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.1.2 + **/ +guint16 +fu_udev_device_get_model (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x0000); + return priv->model; +} + +/** + * fu_udev_device_get_revision: + * @self: A #GUdevDevice + * + * Gets the device revision. + * + * Returns: a vendor code, or 0 if unset or invalid + * + * Since: 1.1.2 + **/ +guint8 +fu_udev_device_get_revision (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), 0x00); + return priv->revision; +} + +static GString * +fu_udev_device_get_parent_subsystems (FuUdevDevice *self) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + GString *str = g_string_new (NULL); + g_autoptr(GUdevDevice) udev_device = g_object_ref (priv->udev_device); + + /* find subsystems of all parent devices */ + while (TRUE) { + g_autoptr(GUdevDevice) parent = g_udev_device_get_parent (udev_device); + if (parent == NULL) + break; + if (g_udev_device_get_subsystem (parent) != NULL) { + g_string_append_printf (str, "%s,", + g_udev_device_get_subsystem (parent)); + } + g_set_object (&udev_device, g_steal_pointer (&parent)); + } + if (str->len > 0) + g_string_truncate (str, str->len - 1); + return str; +} + +/** + * fu_udev_device_set_physical_id: + * @self: A #GUdevDevice + * @subsystem: A subsystem string, e.g. `usb` + * @error: A #GError, or %NULL + * + * Sets the physical ID from the device subsystem. Plugins should choose the + * subsystem that is "deepest" in the udev tree, for instance choosing 'usb' + * over 'pci' for a mouse device. + * + * Returns: %TRUE if the physical device was set. + * + * Since: 1.1.2 + **/ +gboolean +fu_udev_device_set_physical_id (FuUdevDevice *self, const gchar *subsystem, GError **error) +{ + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + const gchar *tmp; + g_autofree gchar *physical_id = NULL; + g_autoptr(GUdevDevice) udev_device = NULL; + + g_return_val_if_fail (FU_IS_UDEV_DEVICE (self), FALSE); + g_return_val_if_fail (subsystem != NULL, FALSE); + + /* get the correct device */ + if (g_strcmp0 (g_udev_device_get_subsystem (priv->udev_device), subsystem) == 0) { + udev_device = g_object_ref (priv->udev_device); + } else { + udev_device = g_udev_device_get_parent_with_subsystem (priv->udev_device, + subsystem, NULL); + if (udev_device == NULL) { + g_autoptr(GString) str = NULL; + str = fu_udev_device_get_parent_subsystems (self); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find device with subsystem %s, only got %s", + subsystem, str->str); + return FALSE; + } + } + if (g_strcmp0 (subsystem, "pci") == 0) { + tmp = g_udev_device_get_property (udev_device, "PCI_SLOT_NAME"); + if (tmp == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find PCI_SLOT_NAME"); + return FALSE; + } + physical_id = g_strdup_printf ("PCI_SLOT_NAME=%s", tmp); + } else if (g_strcmp0 (subsystem, "usb") == 0 || + g_strcmp0 (subsystem, "scsi") == 0) { + tmp = g_udev_device_get_property (udev_device, "DEVPATH"); + if (tmp == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find DEVPATH"); + return FALSE; + } + physical_id = g_strdup_printf ("DEVPATH=%s", tmp); + } else if (g_strcmp0 (subsystem, "hid") == 0) { + tmp = g_udev_device_get_property (udev_device, "HID_PHYS"); + if (tmp == NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "failed to find HID_PHYS"); + return FALSE; + } + physical_id = g_strdup_printf ("HID_PHYS=%s", tmp); + } else { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot handle subsystem %s", + subsystem); + return FALSE; + } + + /* success */ + fu_device_set_physical_id (FU_DEVICE (self), physical_id); + return TRUE; +} + +static void +fu_udev_device_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + FuUdevDevice *self = FU_UDEV_DEVICE (object); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + switch (prop_id) { + case PROP_UDEV_DEVICE: + g_value_set_object (value, priv->udev_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_udev_device_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + FuUdevDevice *self = FU_UDEV_DEVICE (object); + switch (prop_id) { + case PROP_UDEV_DEVICE: + fu_udev_device_set_dev (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fu_udev_device_finalize (GObject *object) +{ + FuUdevDevice *self = FU_UDEV_DEVICE (object); + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + + if (priv->udev_device != NULL) + g_object_unref (priv->udev_device); + + G_OBJECT_CLASS (fu_udev_device_parent_class)->finalize (object); +} + +static void +fu_udev_device_init (FuUdevDevice *self) +{ +} + +static void +fu_udev_device_class_init (FuUdevDeviceClass *klass) +{ + FuDeviceClass *device_class = FU_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fu_udev_device_finalize; + object_class->get_property = fu_udev_device_get_property; + object_class->set_property = fu_udev_device_set_property; + device_class->probe = fu_udev_device_probe; + device_class->incorporate = fu_udev_device_incorporate; + + signals[SIGNAL_CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + pspec = g_param_spec_object ("udev-device", NULL, NULL, + G_UDEV_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_UDEV_DEVICE, pspec); +} + +/** + * fu_udev_device_new: + * @udev_device: A #GUdevDevice + * + * Creates a new #FuUdevDevice. + * + * Returns: (transfer full): a #FuUdevDevice + * + * Since: 1.1.2 + **/ +FuUdevDevice * +fu_udev_device_new (GUdevDevice *udev_device) +{ + FuUdevDevice *self = g_object_new (FU_TYPE_UDEV_DEVICE, + "udev-device", udev_device, + NULL); + return FU_UDEV_DEVICE (self); +} diff -Nru fwupd-1.0.6/src/fu-udev-device.h fwupd-1.2.10/src/fu-udev-device.h --- fwupd-1.0.6/src/fu-udev-device.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-udev-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017-2019 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include + +#include "fu-plugin.h" + +G_BEGIN_DECLS + +#define FU_TYPE_UDEV_DEVICE (fu_udev_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FuUdevDevice, fu_udev_device, FU, UDEV_DEVICE, FuDevice) + +struct _FuUdevDeviceClass +{ + FuDeviceClass parent_class; + gboolean (*probe) (FuUdevDevice *device, + GError **error); + gpointer __reserved[31]; +}; + +FuUdevDevice *fu_udev_device_new (GUdevDevice *udev_device); +GUdevDevice *fu_udev_device_get_dev (FuUdevDevice *self); +const gchar *fu_udev_device_get_sysfs_path (FuUdevDevice *self); +const gchar *fu_udev_device_get_subsystem (FuUdevDevice *self); +guint16 fu_udev_device_get_vendor (FuUdevDevice *self); +guint16 fu_udev_device_get_model (FuUdevDevice *self); +guint8 fu_udev_device_get_revision (FuUdevDevice *self); +guint fu_udev_device_get_slot_depth (FuUdevDevice *self, + const gchar *subsystem); +gboolean fu_udev_device_set_physical_id (FuUdevDevice *self, + const gchar *subsystem, + GError **error); +void fu_udev_device_dump (FuUdevDevice *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-udev-device-private.h fwupd-1.2.10/src/fu-udev-device-private.h --- fwupd-1.0.6/src/fu-udev-device-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-udev-device-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-udev-device.h" + +G_BEGIN_DECLS + +void fu_udev_device_emit_changed (FuUdevDevice *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-usb-device.c fwupd-1.2.10/src/fu-usb-device.c --- fwupd-1.0.6/src/fu-usb-device.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-usb-device.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,29 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- +/* + * Copyright (C) 2017-2018 Richard Hughes * - * Copyright (C) 2017 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#include "config.h" +#define G_LOG_DOMAIN "FuUsbDevice" -#include +#include "config.h" -#include "fu-usb-device.h" +#include "fu-device-private.h" +#include "fu-usb-device-private.h" /** * SECTION:fu-device @@ -38,7 +24,6 @@ { GUsbDevice *usb_device; FuDeviceLocker *usb_device_locker; - gboolean done_probe; } FuUsbDevicePrivate; G_DEFINE_TYPE_WITH_PRIVATE (FuUsbDevice, fu_usb_device, FU_TYPE_DEVICE) @@ -51,65 +36,6 @@ #define GET_PRIVATE(o) (fu_usb_device_get_instance_private (o)) static void -fu_usb_device_apply_quirks (FuUsbDevice *device) -{ - FuQuirks *quirks = fu_device_get_quirks (FU_DEVICE (device)); - GUsbDevice *usb_device = fu_usb_device_get_dev (device); - const gchar *type_name = G_OBJECT_TYPE_NAME (device); - const gchar *tmp; - - /* not set */ - if (quirks == NULL) - return; - - /* type */ - g_debug ("looking for USB quirks for %s type", type_name); - tmp = fu_quirks_lookup_by_usb_device (quirks, type_name, usb_device); - if (tmp != NULL) { - g_debug ("default plugin hints set to: %s", tmp); - fu_device_set_plugin_hints (FU_DEVICE (device), tmp); - } - - /* name */ - g_debug ("looking for USB quirks for %s device", - fu_device_get_platform_id (FU_DEVICE (device))); - tmp = fu_quirks_lookup_by_usb_device (quirks, FU_QUIRKS_USB_NAME, usb_device); - if (tmp != NULL) - fu_device_set_name (FU_DEVICE (device), tmp); - - /* summary */ - tmp = fu_quirks_lookup_by_usb_device (quirks, FU_QUIRKS_USB_SUMMARY, usb_device); - if (tmp != NULL) - fu_device_set_summary (FU_DEVICE (device), tmp); - - /* vendor */ - tmp = fu_quirks_lookup_by_usb_device (quirks, FU_QUIRKS_USB_VENDOR, usb_device); - if (tmp != NULL) - fu_device_set_vendor (FU_DEVICE (device), tmp); - - /* version */ - tmp = fu_quirks_lookup_by_usb_device (quirks, FU_QUIRKS_USB_VERSION, usb_device); - if (tmp != NULL) - fu_device_set_version (FU_DEVICE (device), tmp); - - /* icon */ - tmp = fu_quirks_lookup_by_usb_device (quirks, FU_QUIRKS_USB_ICON, usb_device); - if (tmp != NULL) - fu_device_add_icon (FU_DEVICE (device), tmp); - - /* GUID */ - tmp = fu_quirks_lookup_by_usb_device (quirks, FU_QUIRKS_USB_GUID, usb_device); - if (tmp != NULL) - fu_device_add_guid (FU_DEVICE (device), tmp); -} - -static void -fu_usb_device_notify_quirks_cb (FuUsbDevice *device, GParamSpec *pspec, gpointer user_data) -{ - fu_usb_device_apply_quirks (device); -} - -static void fu_usb_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -157,26 +83,6 @@ static void fu_usb_device_init (FuUsbDevice *device) { - g_signal_connect (device, "notify::quirks", - G_CALLBACK (fu_usb_device_notify_quirks_cb), NULL); -} - -static void -fu_usb_device_class_init (FuUsbDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *pspec; - - object_class->finalize = fu_usb_device_finalize; - object_class->get_property = fu_usb_device_get_property; - object_class->set_property = fu_usb_device_set_property; - - pspec = g_param_spec_object ("usb-device", NULL, NULL, - G_USB_TYPE_DEVICE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_USB_DEVICE, pspec); } /** @@ -197,51 +103,29 @@ return priv->usb_device_locker != NULL; } -/** - * fu_usb_device_open: - * @device: A #FuUsbDevice - * @error: A #GError, or %NULL - * - * Opens a USB device, optionally running a object-specific vfunc. - * - * Returns: %TRUE for success - * - * Since: 1.0.2 - **/ -gboolean -fu_usb_device_open (FuUsbDevice *device, GError **error) +static gboolean +fu_usb_device_open (FuDevice *device, GError **error) { - FuUsbDevicePrivate *priv = GET_PRIVATE (device); + FuUsbDevice *self = FU_USB_DEVICE (device); + FuUsbDevicePrivate *priv = GET_PRIVATE (self); FuUsbDeviceClass *klass = FU_USB_DEVICE_GET_CLASS (device); guint idx; - g_autoptr(AsProfile) profile = as_profile_new (); - g_autoptr(AsProfileTask) ptask = NULL; g_autoptr(FuDeviceLocker) locker = NULL; - g_return_val_if_fail (FU_IS_USB_DEVICE (device), FALSE); + g_return_val_if_fail (FU_IS_USB_DEVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* already open */ if (priv->usb_device_locker != NULL) return TRUE; - /* probe */ - if (!fu_usb_device_probe (device, error)) - return FALSE; - - /* profile */ - ptask = as_profile_start (profile, "added{%04x:%04x}", - g_usb_device_get_vid (priv->usb_device), - g_usb_device_get_pid (priv->usb_device)); - g_assert (ptask != NULL); - /* open */ locker = fu_device_locker_new (priv->usb_device, error); if (locker == NULL) return FALSE; /* get vendor */ - if (fu_device_get_vendor (FU_DEVICE (device)) == NULL) { + if (fu_device_get_vendor (device) == NULL) { idx = g_usb_device_get_manufacturer_index (priv->usb_device); if (idx != 0x00) { g_autofree gchar *tmp = NULL; @@ -249,12 +133,12 @@ idx, error); if (tmp == NULL) return FALSE; - fu_device_set_vendor (FU_DEVICE (device), tmp); + fu_device_set_vendor (device, tmp); } } /* get product */ - if (fu_device_get_name (FU_DEVICE (device)) == NULL) { + if (fu_device_get_name (device) == NULL) { idx = g_usb_device_get_product_index (priv->usb_device); if (idx != 0x00) { g_autofree gchar *tmp = NULL; @@ -262,12 +146,12 @@ idx, error); if (tmp == NULL) return FALSE; - fu_device_set_name (FU_DEVICE (device), tmp); + fu_device_set_name (device, tmp); } } /* get serial number */ - if (fu_device_get_serial (FU_DEVICE (device)) == NULL) { + if (fu_device_get_serial (device) == NULL) { idx = g_usb_device_get_serial_number_index (priv->usb_device); if (idx != 0x00) { g_autofree gchar *tmp = NULL; @@ -275,7 +159,7 @@ idx, error); if (tmp == NULL) return FALSE; - fu_device_set_serial (FU_DEVICE (device), tmp); + fu_device_set_serial (device, tmp); } } @@ -286,7 +170,10 @@ if (idx != 0x00) { g_autofree gchar *tmp = NULL; tmp = g_usb_device_get_string_descriptor (priv->usb_device, idx, NULL); - fu_device_set_version (FU_DEVICE (device), tmp); + /* although guessing is a route to insanity, if the device has + * provided the extra data it's because the BCD type was not + * suitable -- and INTEL_ME is not relevant here */ + fu_device_set_version (device, tmp, fu_common_version_guess_format (tmp)); } /* get GUID from the descriptor if set */ @@ -296,12 +183,12 @@ if (idx != 0x00) { g_autofree gchar *tmp = NULL; tmp = g_usb_device_get_string_descriptor (priv->usb_device, idx, NULL); - fu_device_add_guid (FU_DEVICE (device), tmp); + fu_device_add_guid (device, tmp); } /* subclassed */ if (klass->open != NULL) { - if (!klass->open (device, error)) + if (!klass->open (self, error)) return FALSE; } @@ -310,24 +197,14 @@ return TRUE; } -/** - * fu_usb_device_open: - * @device: A #FuUsbDevice - * @error: A #GError, or %NULL - * - * Closes a USB device, optionally running a object-specific vfunc. - * - * Returns: %TRUE for success - * - * Since: 1.0.2 - **/ -gboolean -fu_usb_device_close (FuUsbDevice *device, GError **error) +static gboolean +fu_usb_device_close (FuDevice *device, GError **error) { - FuUsbDevicePrivate *priv = GET_PRIVATE (device); + FuUsbDevice *self = FU_USB_DEVICE (device); + FuUsbDevicePrivate *priv = GET_PRIVATE (self); FuUsbDeviceClass *klass = FU_USB_DEVICE_GET_CLASS (device); - g_return_val_if_fail (FU_IS_USB_DEVICE (device), FALSE); + g_return_val_if_fail (FU_IS_USB_DEVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* already open */ @@ -336,7 +213,7 @@ /* subclassed */ if (klass->close != NULL) { - if (!klass->close (device, error)) + if (!klass->close (self, error)) return FALSE; } @@ -344,51 +221,140 @@ return TRUE; } -/** - * fu_usb_device_probe: - * @device: A #FuUsbDevice - * @error: A #GError, or %NULL - * - * Probes a USB device, setting parameters on the object that does not need - * the device open or the interface claimed. - * If the device is not compatible then an error should be returned. - * - * Returns: %TRUE for success - * - * Since: 1.0.2 - **/ -gboolean -fu_usb_device_probe (FuUsbDevice *device, GError **error) +static gboolean +fu_usb_device_probe (FuDevice *device, GError **error) { - FuUsbDevicePrivate *priv = GET_PRIVATE (device); + FuUsbDevice *self = FU_USB_DEVICE (device); FuUsbDeviceClass *klass = FU_USB_DEVICE_GET_CLASS (device); + FuUsbDevicePrivate *priv = GET_PRIVATE (self); + guint16 release; + g_autofree gchar *devid0 = NULL; + g_autofree gchar *devid1 = NULL; + g_autofree gchar *devid2 = NULL; + g_autofree gchar *vendor_id = NULL; + g_autoptr(GPtrArray) intfs = NULL; - g_return_val_if_fail (FU_IS_USB_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* set vendor ID */ + vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (priv->usb_device)); + fu_device_set_vendor_id (device, vendor_id); - /* already done */ - if (priv->done_probe) - return TRUE; + /* set the version if the release has been set */ + release = g_usb_device_get_release (priv->usb_device); + if (release != 0x0) { + g_autofree gchar *version = NULL; + version = fu_common_version_from_uint16 (release, FWUPD_VERSION_FORMAT_BCD); + fu_device_set_version (device, version, FWUPD_VERSION_FORMAT_BCD); + } + + /* add GUIDs in order of priority */ + devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&REV_%04X", + g_usb_device_get_vid (priv->usb_device), + g_usb_device_get_pid (priv->usb_device), + release); + fu_device_add_instance_id (device, devid2); + devid1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", + g_usb_device_get_vid (priv->usb_device), + g_usb_device_get_pid (priv->usb_device)); + fu_device_add_instance_id (device, devid1); + devid0 = g_strdup_printf ("USB\\VID_%04X", + g_usb_device_get_vid (priv->usb_device)); + fu_device_add_instance_id_full (device, devid0, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + + /* add the interface GUIDs */ + intfs = g_usb_device_get_interfaces (priv->usb_device, error); + if (intfs == NULL) + return FALSE; + for (guint i = 0; i < intfs->len; i++) { + GUsbInterface *intf = g_ptr_array_index (intfs, i); + g_autofree gchar *intid1 = NULL; + g_autofree gchar *intid2 = NULL; + g_autofree gchar *intid3 = NULL; + intid1 = g_strdup_printf ("USB\\CLASS_%02X&SUBCLASS_%02X&PROT_%02X", + g_usb_interface_get_class (intf), + g_usb_interface_get_subclass (intf), + g_usb_interface_get_protocol (intf)); + fu_device_add_instance_id_full (device, intid1, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + intid2 = g_strdup_printf ("USB\\CLASS_%02X&SUBCLASS_%02X", + g_usb_interface_get_class (intf), + g_usb_interface_get_subclass (intf)); + fu_device_add_instance_id_full (device, intid2, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + intid3 = g_strdup_printf ("USB\\CLASS_%02X", + g_usb_interface_get_class (intf)); + fu_device_add_instance_id_full (device, intid3, + FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } /* subclassed */ if (klass->probe != NULL) { - if (!klass->probe (device, error)) + if (!klass->probe (self, error)) return FALSE; } - priv->done_probe = TRUE; + + /* success */ return TRUE; } -static gchar * -_bcd_version_from_uint16 (guint16 val) +/** + * fu_usb_device_get_vid: + * @self: A #FuUsbDevice + * + * Gets the device vendor code. + * + * Returns: integer, or 0x0 if unset or invalid + * + * Since: 1.1.2 + **/ +guint16 +fu_usb_device_get_vid (FuUsbDevice *self) +{ + FuUsbDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_USB_DEVICE (self), 0x0000); + if (priv->usb_device == NULL) + return 0x0; + return g_usb_device_get_vid (priv->usb_device); +} + +/** + * fu_usb_device_get_pid: + * @self: A #FuUsbDevice + * + * Gets the device product code. + * + * Returns: integer, or 0x0 if unset or invalid + * + * Since: 1.1.2 + **/ +guint16 +fu_usb_device_get_pid (FuUsbDevice *self) +{ + FuUsbDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_USB_DEVICE (self), 0x0000); + if (priv->usb_device == NULL) + return 0x0; + return g_usb_device_get_pid (priv->usb_device); +} + +/** + * fu_usb_device_get_platform_id: + * @self: A #FuUsbDevice + * + * Gets the device platform ID. + * + * Returns: string, or NULL if unset or invalid + * + * Since: 1.1.2 + **/ +const gchar * +fu_usb_device_get_platform_id (FuUsbDevice *self) { -#if AS_CHECK_VERSION(0,7,3) - return as_utils_version_from_uint16 (val, AS_VERSION_PARSE_FLAG_USE_BCD); -#else - guint maj = ((val >> 12) & 0x0f) * 10 + ((val >> 8) & 0x0f); - guint min = ((val >> 4) & 0x0f) * 10 + (val & 0x0f); - return g_strdup_printf ("%u.%u", maj, min); -#endif + FuUsbDevicePrivate *priv = GET_PRIVATE (self); + g_return_val_if_fail (FU_IS_USB_DEVICE (self), NULL); + if (priv->usb_device == NULL) + return NULL; + return g_usb_device_get_platform_id (priv->usb_device); } /** @@ -404,15 +370,11 @@ fu_usb_device_set_dev (FuUsbDevice *device, GUsbDevice *usb_device) { FuUsbDevicePrivate *priv = GET_PRIVATE (device); - guint16 release; - g_autofree gchar *devid1 = NULL; - g_autofree gchar *devid2 = NULL; - g_autofree gchar *vendor_id = NULL; g_return_if_fail (FU_IS_USB_DEVICE (device)); /* need to re-probe hardware */ - priv->done_probe = FALSE; + fu_device_probe_invalidate (FU_DEVICE (device)); /* allow replacement */ g_set_object (&priv->usb_device, usb_device); @@ -421,34 +383,9 @@ return; } - /* add both device IDs */ - devid1 = g_strdup_printf ("USB\\VID_%04X&PID_%04X", - g_usb_device_get_vid (usb_device), - g_usb_device_get_pid (usb_device)); - fu_device_add_guid (FU_DEVICE (device), devid1); - release = g_usb_device_get_release (usb_device); - devid2 = g_strdup_printf ("USB\\VID_%04X&PID_%04X&REV_%04X", - g_usb_device_get_vid (usb_device), - g_usb_device_get_pid (usb_device), - release); - fu_device_add_guid (FU_DEVICE (device), devid2); - - /* set vendor ID */ - vendor_id = g_strdup_printf ("USB:0x%04X", g_usb_device_get_vid (usb_device)); - fu_device_set_vendor_id (FU_DEVICE (device), vendor_id); - - /* set the version if the release has been set */ - if (release != 0x0) { - g_autofree gchar *version = _bcd_version_from_uint16 (release); - fu_device_set_version (FU_DEVICE (device), version); - } - - /* set USB platform ID automatically */ - fu_device_set_platform_id (FU_DEVICE (device), + /* set device ID automatically */ + fu_device_set_physical_id (FU_DEVICE (device), g_usb_device_get_platform_id (usb_device)); - - /* set the quirks again */ - fu_usb_device_apply_quirks (device); } /** @@ -469,8 +406,18 @@ return priv->usb_device; } +static void +fu_usb_device_incorporate (FuDevice *self, FuDevice *donor) +{ + g_return_if_fail (FU_IS_USB_DEVICE (self)); + g_return_if_fail (FU_IS_USB_DEVICE (donor)); + fu_usb_device_set_dev (FU_USB_DEVICE (self), + fu_usb_device_get_dev (FU_USB_DEVICE (donor))); +} + /** * fu_usb_device_new: + * @usb_device: A #GUsbDevice * * Creates a new #FuUsbDevice. * @@ -478,10 +425,33 @@ * * Since: 1.0.2 **/ -FuDevice * +FuUsbDevice * fu_usb_device_new (GUsbDevice *usb_device) { FuUsbDevice *device = g_object_new (FU_TYPE_USB_DEVICE, NULL); fu_usb_device_set_dev (device, usb_device); - return FU_DEVICE (device); + return FU_USB_DEVICE (device); +} + +static void +fu_usb_device_class_init (FuUsbDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuDeviceClass *device_class = FU_DEVICE_CLASS (klass); + GParamSpec *pspec; + + object_class->finalize = fu_usb_device_finalize; + object_class->get_property = fu_usb_device_get_property; + object_class->set_property = fu_usb_device_set_property; + device_class->open = fu_usb_device_open; + device_class->close = fu_usb_device_close; + device_class->probe = fu_usb_device_probe; + device_class->incorporate = fu_usb_device_incorporate; + + pspec = g_param_spec_object ("usb-device", NULL, NULL, + G_USB_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME); + g_object_class_install_property (object_class, PROP_USB_DEVICE, pspec); } diff -Nru fwupd-1.0.6/src/fu-usb-device.h fwupd-1.2.10/src/fu-usb-device.h --- fwupd-1.0.6/src/fu-usb-device.h 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-usb-device.h 2019-07-15 18:25:54.000000000 +0000 @@ -1,26 +1,10 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2017 Richard Hughes * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * SPDX-License-Identifier: LGPL-2.1+ */ -#ifndef __FU_USB_DEVICE_H -#define __FU_USB_DEVICE_H +#pragma once #include #include @@ -32,6 +16,16 @@ #define FU_TYPE_USB_DEVICE (fu_usb_device_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuUsbDevice, fu_usb_device, FU, USB_DEVICE, FuDevice) +/* HID */ +#define HID_REPORT_GET 0x01 +#define HID_REPORT_SET 0x09 + +#define HID_REPORT_TYPE_INPUT 0x01 +#define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x03 + +#define HID_FEATURE 0x0300 + struct _FuUsbDeviceClass { FuDeviceClass parent_class; @@ -44,18 +38,12 @@ gpointer __reserved[28]; }; -FuDevice *fu_usb_device_new (GUsbDevice *usb_device); +FuUsbDevice *fu_usb_device_new (GUsbDevice *usb_device); +guint16 fu_usb_device_get_vid (FuUsbDevice *self); +guint16 fu_usb_device_get_pid (FuUsbDevice *self); GUsbDevice *fu_usb_device_get_dev (FuUsbDevice *device); void fu_usb_device_set_dev (FuUsbDevice *device, GUsbDevice *usb_device); -gboolean fu_usb_device_open (FuUsbDevice *device, - GError **error); -gboolean fu_usb_device_close (FuUsbDevice *device, - GError **error); -gboolean fu_usb_device_probe (FuUsbDevice *device, - GError **error); gboolean fu_usb_device_is_open (FuUsbDevice *device); G_END_DECLS - -#endif /* __FU_USB_DEVICE_H */ diff -Nru fwupd-1.0.6/src/fu-usb-device-private.h fwupd-1.2.10/src/fu-usb-device-private.h --- fwupd-1.0.6/src/fu-usb-device-private.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-usb-device-private.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-usb-device.h" + +G_BEGIN_DECLS + +const gchar *fu_usb_device_get_platform_id (FuUsbDevice *self); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/fu-util.c fwupd-1.2.10/src/fu-util.c --- fwupd-1.0.6/src/fu-util.c 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/fu-util.c 2019-07-15 18:25:54.000000000 +0000 @@ -1,28 +1,15 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * +/* * Copyright (C) 2015-2018 Richard Hughes * - * Licensed under the GNU General Public License Version 2 - * - * 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 2 of the License, 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. + * SPDX-License-Identifier: LGPL-2.1+ */ +#define G_LOG_DOMAIN "FuMain" + #include "config.h" #include -#include +#include #include #include #include @@ -32,28 +19,34 @@ #include #include #include -#include #include -#include #include -#include "fu-hwids.h" #include "fu-history.h" #include "fu-plugin-private.h" #include "fu-progressbar.h" +#include "fu-util-common.h" #include "fwupd-common-private.h" -/* this is only valid in this file */ -#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) +#ifdef HAVE_SYSTEMD +#include "fu-systemd.h" +#endif /* custom return code */ #define EXIT_NOTHING_TO_DO 2 -typedef struct { +typedef enum { + FU_UTIL_OPERATION_UNKNOWN, + FU_UTIL_OPERATION_UPDATE, + FU_UTIL_OPERATION_DOWNGRADE, + FU_UTIL_OPERATION_INSTALL, + FU_UTIL_OPERATION_LAST +} FuUtilOperation; + +struct FuUtilPrivate { GCancellable *cancellable; GMainLoop *loop; GOptionContext *context; - GPtrArray *cmd_array; SoupSession *soup_session; FwupdInstallFlags flags; FwupdClient *client; @@ -62,128 +55,21 @@ gboolean no_reboot_check; gboolean no_unreported_check; gboolean assume_yes; -} FuUtilPrivate; - -typedef gboolean (*FuUtilPrivateCb) (FuUtilPrivate *util, - gchar **values, - GError **error); + gboolean sign; + gboolean show_all_devices; + /* only valid in update and downgrade */ + FuUtilOperation current_operation; + FwupdDevice *current_device; + gchar *current_message; + FwupdDeviceFlags completion_flags; +}; static gboolean fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error); - -typedef struct { - gchar *name; - gchar *arguments; - gchar *description; - FuUtilPrivateCb callback; -} FuUtilItem; - -static void -fu_util_item_free (FuUtilItem *item) -{ - g_free (item->name); - g_free (item->arguments); - g_free (item->description); - g_free (item); -} - -/* - * fu_sort_command_name_cb: - */ -static gint -fu_sort_command_name_cb (FuUtilItem **item1, FuUtilItem **item2) -{ - return g_strcmp0 ((*item1)->name, (*item2)->name); -} - -static void -fu_util_add (GPtrArray *array, - const gchar *name, - const gchar *arguments, - const gchar *description, - FuUtilPrivateCb callback) -{ - g_auto(GStrv) names = NULL; - - g_return_if_fail (name != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (callback != NULL); - - /* add each one */ - names = g_strsplit (name, ",", -1); - for (guint i = 0; names[i] != NULL; i++) { - FuUtilItem *item = g_new0 (FuUtilItem, 1); - item->name = g_strdup (names[i]); - if (i == 0) { - item->description = g_strdup (description); - } else { - /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ - item->description = g_strdup_printf (_("Alias to %s"), - names[0]); - } - item->arguments = g_strdup (arguments); - item->callback = callback; - g_ptr_array_add (array, item); - } -} - -static gchar * -fu_util_get_descriptions (GPtrArray *array) -{ - gsize len; - const gsize max_len = 35; - GString *string; - - /* print each command */ - string = g_string_new (""); - for (guint i = 0; i < array->len; i++) { - FuUtilItem *item = g_ptr_array_index (array, i); - g_string_append (string, " "); - g_string_append (string, item->name); - len = strlen (item->name) + 2; - if (item->arguments != NULL) { - g_string_append (string, " "); - g_string_append (string, item->arguments); - len += strlen (item->arguments) + 1; - } - if (len < max_len) { - for (gsize j = len; j < max_len + 1; j++) - g_string_append_c (string, ' '); - g_string_append (string, item->description); - g_string_append_c (string, '\n'); - } else { - g_string_append_c (string, '\n'); - for (gsize j = 0; j < max_len + 1; j++) - g_string_append_c (string, ' '); - g_string_append (string, item->description); - g_string_append_c (string, '\n'); - } - } - - /* remove trailing newline */ - if (string->len > 0) - g_string_set_size (string, string->len - 1); - - return g_string_free (string, FALSE); -} - -static gboolean -fu_util_run (FuUtilPrivate *priv, const gchar *command, gchar **values, GError **error) -{ - /* find command */ - for (guint i = 0; i < priv->cmd_array->len; i++) { - FuUtilItem *item = g_ptr_array_index (priv->cmd_array, i); - if (g_strcmp0 (item->name, command) == 0) - return item->callback (priv, values, error); - } - - /* not found */ - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - /* TRANSLATORS: error message */ - _("Command not found")); - return FALSE; -} +static gboolean fu_util_download_file (FuUtilPrivate *priv, + SoupURI *uri, + const gchar *fn, + const gchar *checksum_expected, + GError **error); static void fu_util_client_notify_cb (GObject *object, @@ -196,72 +82,49 @@ } static void -fu_util_print_data (const gchar *title, const gchar *msg) -{ - gsize title_len; - g_auto(GStrv) lines = NULL; - - if (msg == NULL) +fu_util_update_device_changed_cb (FwupdClient *client, + FwupdDevice *device, + FuUtilPrivate *priv) +{ + g_autofree gchar *str = NULL; + + /* allowed to set whenever the device has changed */ + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + + /* same as last time, so ignore */ + if (priv->current_device != NULL && + fwupd_device_compare (priv->current_device, device) == 0) return; - g_print ("%s:", title); - /* pad */ - title_len = strlen (title) + 1; - lines = g_strsplit (msg, "\n", -1); - for (guint j = 0; lines[j] != NULL; j++) { - for (gsize i = title_len; i < 25; i++) - g_print (" "); - g_print ("%s\n", lines[j]); - title_len = 0; + /* show message in progressbar */ + if (priv->current_operation == FU_UTIL_OPERATION_UPDATE) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Updating %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else if (priv->current_operation == FU_UTIL_OPERATION_DOWNGRADE) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Downgrading %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else if (priv->current_operation == FU_UTIL_OPERATION_INSTALL) { + /* TRANSLATORS: %1 is a device name */ + str = g_strdup_printf (_("Installing on %s…"), + fwupd_device_get_name (device)); + fu_progressbar_set_title (priv->progressbar, str); + } else { + g_warning ("no FuUtilOperation set"); } -} - -static guint -fu_util_prompt_for_number (guint maxnum) -{ - gint retval; - guint answer = 0; - - do { - char buffer[64]; - - /* swallow the \n at end of line too */ - if (!fgets (buffer, sizeof (buffer), stdin)) - break; - if (strlen (buffer) == sizeof (buffer) - 1) - continue; - - /* get a number */ - retval = sscanf (buffer, "%u", &answer); - - /* positive */ - if (retval == 1 && answer <= maxnum) - break; - - /* TRANSLATORS: the user isn't reading the question */ - g_print (_("Please enter a number from 0 to %u: "), maxnum); - } while (TRUE); - return answer; -} + g_set_object (&priv->current_device, device); -static gboolean -fu_util_prompt_for_boolean (gboolean def) -{ - do { - char buffer[4]; - if (!fgets (buffer, sizeof (buffer), stdin)) - continue; - if (strlen (buffer) == sizeof (buffer) - 1) - continue; - if (g_strcmp0 (buffer, "\n") == 0) - return def; - buffer[0] = g_ascii_toupper (buffer[0]); - if (g_strcmp0 (buffer, "Y\n") == 0) - return TRUE; - if (g_strcmp0 (buffer, "N\n") == 0) - return FALSE; - } while (TRUE); - return FALSE; + if (priv->current_message == NULL) { + const gchar *tmp = fwupd_device_get_update_message (priv->current_device); + if (tmp != NULL) + priv->current_message = g_strdup (tmp); + } } static FwupdDevice * @@ -325,50 +188,6 @@ } static gboolean -fu_util_setup_networking (FuUtilPrivate *priv, GError **error) -{ - const gchar *http_proxy; - g_autofree gchar *user_agent = NULL; - - /* already done */ - if (priv->soup_session != NULL) - return TRUE; - - /* create the soup session */ - user_agent = fwupd_build_user_agent (PACKAGE_NAME, PACKAGE_VERSION); - priv->soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, - SOUP_SESSION_TIMEOUT, 60, - NULL); - if (priv->soup_session == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "failed to setup networking"); - return FALSE; - } - - /* set the proxy */ - http_proxy = g_getenv ("https_proxy"); - if (http_proxy == NULL) - http_proxy = g_getenv ("http_proxy"); - if (http_proxy != NULL) { - g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); - if (proxy_uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INTERNAL, - "invalid proxy URI: %s", http_proxy); - return FALSE; - } - g_object_set (priv->soup_session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); - } - - /* this disables the double-compression of the firmware.xml.gz file */ - soup_session_remove_feature_by_type (priv->soup_session, SOUP_TYPE_CONTENT_DECODER); - return TRUE; -} - -static gboolean fu_util_perhaps_show_unreported (FuUtilPrivate *priv, GError **error) { g_autoptr(GError) error_local = NULL; @@ -450,8 +269,12 @@ } /* ask for permission */ - g_print ("\n%s (%s) [Y|n]: ", + g_print ("\n%s\n%s (%s) [Y|n]: ", /* TRANSLATORS: explain why we want to upload */ + _("Uploading firmware reports helps hardware vendors" + " to quickly identify failing and successful updates" + " on real devices."), + /* TRANSLATORS: ask the user to upload */ _("Upload report now?"), /* TRANSLATORS: metadata is downloaded from the Internet */ _("Requires internet connection")); @@ -463,6 +286,155 @@ return fu_util_report_history (priv, NULL, error); } +static gchar * +fu_util_convert_appstream_description (const gchar *xml, GError **error) +{ + g_autoptr(GString) str = g_string_new (NULL); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* parse XML */ + silo = xb_silo_new_from_xml (xml, error); + if (silo == NULL) + return NULL; + + n = xb_silo_get_root (silo); + while (n != NULL) { + g_autoptr(XbNode) n2 = NULL; + + /* support

,

    ,
      and
    1. , ignore all else */ + if (g_strcmp0 (xb_node_get_element (n), "p") == 0) { + g_string_append_printf (str, "%s\n\n", xb_node_get_text (n)); + } else if (g_strcmp0 (xb_node_get_element (n), "ul") == 0) { + g_autoptr(GPtrArray) children = xb_node_get_children (n); + for (guint i = 0; i < children->len; i++) { + XbNode *nc = g_ptr_array_index (children, i); + if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { + g_string_append_printf (str, " • %s\n", + xb_node_get_text (nc)); + } + } + g_string_append (str, "\n"); + } else if (g_strcmp0 (xb_node_get_element (n), "ol") == 0) { + g_autoptr(GPtrArray) children = xb_node_get_children (n); + for (guint i = 0; i < children->len; i++) { + XbNode *nc = g_ptr_array_index (children, i); + if (g_strcmp0 (xb_node_get_element (nc), "li") == 0) { + g_string_append_printf (str, " %u. %s\n", + i + 1, + xb_node_get_text (nc)); + } + } + g_string_append (str, "\n"); + } + + n2 = xb_node_get_next (n); + g_set_object (&n, n2); + } + + /* remove extra newline */ + if (str->len > 0) + g_string_truncate (str, str->len - 1); + + /* success */ + return g_string_free (g_steal_pointer (&str), FALSE); +} + +static gboolean +fu_util_modify_remote_warning (FuUtilPrivate *priv, FwupdRemote *remote, GError **error) +{ + const gchar *warning_markup = NULL; + g_autofree gchar *warning_plain = NULL; + + /* get formatted text */ + warning_markup = fwupd_remote_get_agreement (remote); + if (warning_markup == NULL) + return TRUE; + warning_plain = fu_util_convert_appstream_description (warning_markup, error); + if (warning_plain == NULL) + return FALSE; + + /* show and ask user to confirm */ + fu_util_warning_box (warning_plain, 80); + if (!priv->assume_yes) { + /* ask for permission */ + g_print ("\n%s [Y|n]: ", + /* TRANSLATORS: should the remote still be enabled */ + _("Agree and enable the remote?")); + if (!fu_util_prompt_for_boolean (TRUE)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "Declined agreement"); + return FALSE; + } + } + return TRUE; +} + +static gboolean +fu_util_modify_remote (FuUtilPrivate *priv, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GError **error) +{ + g_autoptr(FwupdRemote) remote = NULL; + + /* ensure the remote exists */ + remote = fwupd_client_get_remote_by_id (priv->client, remote_id, NULL, error); + if (remote == NULL) + return FALSE; + + /* show some kind of warning when enabling download-type remotes */ + if (g_strcmp0 (key, "Enabled") == 0 && g_strcmp0 (value, "true") == 0) { + if (!fu_util_modify_remote_warning (priv, remote, error)) + return FALSE; + } + return fwupd_client_modify_remote (priv->client, + remote_id, key, value, + NULL, error); +} + +static void +fu_util_build_device_tree (FuUtilPrivate *priv, GNode *root, GPtrArray *devs, FwupdDevice *dev) +{ + for (guint i = 0; i < devs->len; i++) { + FwupdDevice *dev_tmp = g_ptr_array_index (devs, i); + if (!priv->show_all_devices && + !fu_util_is_interesting_device (dev_tmp)) + continue; + if (fwupd_device_get_parent (dev_tmp) == dev) { + GNode *child = g_node_append_data (root, dev_tmp); + fu_util_build_device_tree (priv, child, devs, dev_tmp); + } + } +} + +static gboolean +fu_util_get_topology (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_autoptr(GNode) root = g_node_new (NULL); + g_autoptr(GPtrArray) devs = NULL; + + /* get results from daemon */ + devs = fwupd_client_get_devices (priv->client, NULL, error); + if (devs == NULL) + return FALSE; + + /* print */ + if (devs->len == 0) { + /* TRANSLATORS: nothing attached that can be upgraded */ + g_print ("%s\n", _("No hardware detected with firmware update capability")); + return TRUE; + } + fu_util_build_device_tree (priv, root, devs, NULL); + g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + fu_util_print_device_tree, priv); + + return TRUE; +} + static gboolean fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -483,6 +455,10 @@ for (guint i = 0; i < devs->len; i++) { g_autofree gchar *tmp = NULL; FwupdDevice *dev = g_ptr_array_index (devs, i); + if (!priv->show_all_devices) { + if (!fu_util_is_interesting_device (dev)) + continue; + } tmp = fwupd_device_to_string (dev); g_print ("%s\n", tmp); } @@ -494,10 +470,40 @@ return TRUE; } +static gchar * +fu_util_download_if_required (FuUtilPrivate *priv, const gchar *perhapsfn, GError **error) +{ + g_autofree gchar *filename = NULL; + g_autoptr(SoupURI) uri = NULL; + + /* a local file */ + uri = soup_uri_new (perhapsfn); + if (uri == NULL) + return g_strdup (perhapsfn); + + /* download the firmware to a cachedir */ + filename = fu_util_get_user_cache_path (perhapsfn); + if (!fu_common_mkdir_parent (filename, error)) + return NULL; + if (!fu_util_download_file (priv, uri, filename, NULL, error)) + return NULL; + return g_steal_pointer (&filename); +} + +static void +fu_util_display_current_message (FuUtilPrivate *priv) +{ + if (priv->current_message == NULL) + return; + g_print ("%s\n", priv->current_message); + g_clear_pointer (&priv->current_message, g_free); +} + static gboolean fu_util_install (FuUtilPrivate *priv, gchar **values, GError **error) { const gchar *id; + g_autofree gchar *filename = NULL; /* handle both forms */ if (g_strv_length (values) == 1) { @@ -512,8 +518,28 @@ return FALSE; } + priv->current_operation = FU_UTIL_OPERATION_INSTALL; + g_signal_connect (priv->client, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + /* install with flags chosen by the user */ - return fwupd_client_install (priv->client, id, values[0], priv->flags, NULL, error); + filename = fu_util_download_if_required (priv, values[0], error); + if (filename == NULL) + return FALSE; + + if (!fwupd_client_install (priv->client, id, filename, priv->flags, NULL, error)) + return FALSE; + + fu_util_display_current_message (priv); + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; + } + + /* show reboot if needed */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -536,162 +562,8 @@ FwupdDevice *dev = g_ptr_array_index (array, i); g_autofree gchar *tmp = NULL; tmp = fwupd_device_to_string (dev); - g_print ("%s", tmp); - } - return TRUE; -} - -static gboolean -fu_util_update_reboot (GError **error) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) val = NULL; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); - if (connection == NULL) - return FALSE; - -#ifdef HAVE_SYSTEMD - /* reboot using systemd */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "Reboot", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#elif HAVE_CONSOLEKIT - /* reboot using ConsoleKit */ - val = g_dbus_connection_call_sync (connection, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "Restart", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); -#else - g_set_error_literal (&error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "No supported backend compiled in to perform the operation."); -#endif - return val != NULL; -} - -static gboolean -fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) -{ - gint vercmp; - guint cnt = 0; - g_autofree gchar *link = NULL; - g_autoptr(GPtrArray) results = NULL; - g_autoptr(FuHistory) history = NULL; - - /* verify this is pointing to our cache */ - link = g_file_read_link (FU_OFFLINE_TRIGGER_FILENAME, NULL); - if (link == NULL) { - g_debug ("No %s, exiting", FU_OFFLINE_TRIGGER_FILENAME); - return TRUE; - } - if (g_strcmp0 (link, "/var/lib/fwupd") != 0) { - g_debug ("Another framework set up the trigger, exiting"); - return TRUE; - } - - /* do this first to avoid a loop if this tool segfaults */ - g_unlink (FU_OFFLINE_TRIGGER_FILENAME); - - if (g_strv_length (values) != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "Invalid arguments: none expected"); - return FALSE; - } - - /* ensure root user */ - if (getuid () != 0 || geteuid () != 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "This function can only be used as root"); - return FALSE; - } - - /* get prepared updates */ - history = fu_history_new (); - results = fu_history_get_devices (history, error); - if (results == NULL) - return FALSE; - - /* apply each update */ - for (guint i = 0; i < results->len; i++) { - FwupdDevice *dev = g_ptr_array_index (results, i); - FwupdRelease *rel = fwupd_device_get_release_default (dev); - - /* check not already done */ - if (fwupd_device_get_update_state (dev) != FWUPD_UPDATE_STATE_PENDING) - continue; - - /* tell the user what's going to happen */ - vercmp = as_utils_vercmp (fwupd_device_get_version (dev), - fwupd_release_get_version (rel)); - if (vercmp == 0) { - /* TRANSLATORS: the first replacement is a display name - * e.g. "ColorHugALS" and the second is a version number - * e.g. "1.2.3" */ - g_print (_("Reinstalling %s with %s... "), - fwupd_device_get_name (dev), - fwupd_release_get_version (rel)); - } else if (vercmp > 0) { - /* TRANSLATORS: the first replacement is a display name - * e.g. "ColorHugALS" and the second and third are - * version numbers e.g. "1.2.3" */ - g_print (_("Downgrading %s from %s to %s... "), - fwupd_device_get_name (dev), - fwupd_device_get_version (dev), - fwupd_release_get_version (rel)); - } else if (vercmp < 0) { - /* TRANSLATORS: the first replacement is a display name - * e.g. "ColorHugALS" and the second and third are - * version numbers e.g. "1.2.3" */ - g_print (_("Updating %s from %s to %s... "), - fwupd_device_get_name (dev), - fwupd_device_get_version (dev), - fwupd_release_get_version (rel)); - } - if (!fwupd_client_install (priv->client, - fwupd_device_get_id (dev), - fwupd_release_get_filename (rel), - priv->flags, - NULL, - error)) - return FALSE; - cnt++; - } - - /* nothing to do */ - if (cnt == 0) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_NOTHING_TO_DO, - "No updates prepared"); - return FALSE; + g_print ("%s\n", tmp); } - - /* reboot */ - if (!fu_util_update_reboot (error)) - return FALSE; - - g_print ("%s\n", _("Done!")); return TRUE; } @@ -713,6 +585,7 @@ const gchar *server_msg = NULL; guint status_code; g_autofree gchar *data = NULL; + g_autofree gchar *sig = NULL; g_autoptr(JsonParser) json_parser = NULL; g_autoptr(SoupMessage) msg = NULL; @@ -721,10 +594,21 @@ if (data == NULL) return FALSE; + /* self sign data */ + if (priv->sign) { + sig = fwupd_client_self_sign (priv->client, data, + FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP, + priv->cancellable, error); + if (sig == NULL) + return FALSE; + } + /* ask for permission */ if (!priv->assume_yes) { fu_util_print_data (_("Target"), report_uri); fu_util_print_data (_("Payload"), data); + if (sig != NULL) + fu_util_print_data (_("Signature"), sig); g_print ("%s [Y|n]: ", _("Proceed with upload?")); if (!fu_util_prompt_for_boolean (TRUE)) { g_set_error_literal (error, @@ -736,9 +620,17 @@ } /* POST request */ - msg = soup_message_new (SOUP_METHOD_POST, report_uri); - soup_message_set_request (msg, "application/json; charset=utf-8", - SOUP_MEMORY_COPY, data, strlen (data)); + if (sig != NULL) { + g_autoptr(SoupMultipart) mp = NULL; + mp = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART); + soup_multipart_append_form_string (mp, "payload", data); + soup_multipart_append_form_string (mp, "signature", sig); + msg = soup_form_request_new_from_multipart (report_uri, mp); + } else { + msg = soup_message_new (SOUP_METHOD_POST, report_uri); + soup_message_set_request (msg, "application/json; charset=utf-8", + SOUP_MEMORY_COPY, data, strlen (data)); + } status_code = soup_session_send_message (priv->soup_session, msg); g_debug ("server returned: %s", msg->response_body->data); @@ -835,8 +727,11 @@ g_autoptr(GPtrArray) remotes = NULL; /* set up networking */ - if (!fu_util_setup_networking (priv, error)) - return FALSE; + if (priv->soup_session == NULL) { + priv->soup_session = fu_util_setup_networking (error); + if (priv->soup_session == NULL) + return FALSE; + } /* create a map of RemoteID to RemoteURI */ remotes = fwupd_client_get_remotes (priv->client, NULL, error); @@ -1090,7 +985,7 @@ if (header_size < body_length) return; - /* calulate percentage */ + /* calculate percentage */ percentage = (guint) ((100 * body_length) / header_size); g_debug ("progress: %u%%", percentage); fu_progressbar_update (priv->progressbar, FWUPD_STATUS_DOWNLOADING, percentage); @@ -1118,8 +1013,11 @@ } /* set up networking */ - if (!fu_util_setup_networking (priv, error)) - return FALSE; + if (priv->soup_session == NULL) { + priv->soup_session = fu_util_setup_networking (error); + if (priv->soup_session == NULL) + return FALSE; + } /* download data */ uri_str = soup_uri_to_string (uri, FALSE); @@ -1151,6 +1049,23 @@ G_CALLBACK (fu_util_download_chunk_cb), priv); status_code = soup_session_send_message (priv->soup_session, msg); g_print ("\n"); + if (status_code == 429) { + g_autofree gchar *str = g_strndup (msg->response_body->data, + msg->response_body->length); + if (g_strcmp0 (str, "Too Many Requests") == 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + /* TRANSLATORS: the server is rate-limiting downloads */ + "%s", _("Failed to download due to server limit")); + return FALSE; + } + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to download due to server limit: %s", str); + return FALSE; + } if (status_code != SOUP_STATUS_OK) { g_set_error (error, FWUPD_ERROR, @@ -1199,7 +1114,6 @@ g_autofree gchar *basename_id_asc = NULL; g_autofree gchar *basename_id = NULL; g_autofree gchar *basename = NULL; - g_autofree gchar *cache_dir = NULL; g_autofree gchar *filename = NULL; g_autofree gchar *filename_asc = NULL; g_autoptr(SoupURI) uri = NULL; @@ -1210,8 +1124,7 @@ basename_id = g_strdup_printf ("%s-%s", fwupd_remote_get_id (remote), basename); /* download the metadata */ - cache_dir = g_build_filename (g_get_user_cache_dir (), "fwupdmgr", NULL); - filename = g_build_filename (cache_dir, basename_id, NULL); + filename = fu_util_get_user_cache_path (basename_id); if (!fu_common_mkdir_parent (filename, error)) return FALSE; uri = soup_uri_new (fwupd_remote_get_metadata_uri (remote)); @@ -1221,7 +1134,7 @@ /* download the signature */ basename_asc = g_path_get_basename (fwupd_remote_get_filename_cache_sig (remote)); basename_id_asc = g_strdup_printf ("%s-%s", fwupd_remote_get_id (remote), basename_asc); - filename_asc = g_build_filename (cache_dir, basename_id_asc, NULL); + filename_asc = fu_util_get_user_cache_path (basename_id_asc); uri_sig = soup_uri_new (fwupd_remote_get_metadata_uri_sig (remote)); if (!fu_util_download_file (priv, uri_sig, filename_asc, NULL, error)) return FALSE; @@ -1235,9 +1148,36 @@ } static gboolean +fu_util_download_metadata_enable_lvfs (FuUtilPrivate *priv, GError **error) +{ + g_autoptr(FwupdRemote) remote = NULL; + + /* is the LVFS available but disabled? */ + remote = fwupd_client_get_remote_by_id (priv->client, "lvfs", NULL, error); + if (remote == NULL) + return TRUE; + g_print ("%s\n%s\n%s [Y|n]: ", + /* TRANSLATORS: explain why no metadata available */ + _("No remotes are currently enabled so no metadata is available."), + /* TRANSLATORS: explain why no metadata available */ + _("Metadata can be obtained from the Linux Vendor Firmware Service."), + /* TRANSLATORS: Turn on the remote */ + _("Enable this remote?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + if (!fu_util_modify_remote (priv, "lvfs", "Enabled", "true", error)) + return FALSE; + + /* refresh the newly-enabled remote */ + return fu_util_download_metadata_for_remote (priv, remote, error); +} + +static gboolean fu_util_download_metadata (FuUtilPrivate *priv, GError **error) { + gboolean download_remote_enabled = FALSE; g_autoptr(GPtrArray) remotes = NULL; + remotes = fwupd_client_get_remotes (priv->client, NULL, error); if (remotes == NULL) return FALSE; @@ -1247,9 +1187,16 @@ continue; if (fwupd_remote_get_kind (remote) != FWUPD_REMOTE_KIND_DOWNLOAD) continue; + download_remote_enabled = TRUE; if (!fu_util_download_metadata_for_remote (priv, remote, error)) return FALSE; } + + /* no web remote is declared; try to enable LVFS */ + if (!download_remote_enabled) { + if (!fu_util_download_metadata_enable_lvfs (priv, error)) + return FALSE; + } return TRUE; } @@ -1311,6 +1258,7 @@ g_print ("%s:\n", fwupd_device_get_name (dev)); for (guint i = 0; i < rels->len; i++) { FwupdRelease *rel = g_ptr_array_index (rels, i); + FwupdReleaseFlags flags = fwupd_release_get_flags (rel); GPtrArray *checksums; const gchar *tmp; @@ -1318,7 +1266,7 @@ fu_util_print_data (_("Version"), fwupd_release_get_version (rel)); /* TRANSLATORS: section header for the release name */ - fu_util_print_data (_("Name"), fwupd_release_get_name (rel)); + fu_util_print_data (_("Name"), fu_util_release_get_name (rel)); /* TRANSLATORS: section header for the release one line summary */ fu_util_print_data (_("Summary"), fwupd_release_get_summary (rel)); @@ -1331,7 +1279,7 @@ tmp = fwupd_release_get_description (rel); if (tmp != NULL) { g_autofree gchar *desc = NULL; - desc = as_markup_convert_simple (tmp, NULL); + desc = fu_util_convert_appstream_description (tmp, NULL); /* TRANSLATORS: section header for firmware description */ fu_util_print_data (_("Description"), desc); } @@ -1344,6 +1292,24 @@ fu_util_print_data (_("Checksum"), checksum_display); } + /* show flags if set */ + if (flags != FWUPD_RELEASE_FLAG_NONE) { + g_autoptr(GString) str = g_string_new (""); + for (guint j = 0; j < 64; j++) { + if ((flags & ((guint64) 1 << j)) == 0) + continue; + g_string_append_printf (str, "%s,", + fwupd_release_flag_to_string ((guint64) 1 << j)); + } + if (str->len == 0) { + g_string_append (str, fwupd_release_flag_to_string (0)); + } else { + g_string_truncate (str, str->len - 1); + } + /* TRANSLATORS: section header for firmware flags */ + fu_util_print_data (_("Flags"), str->str); + } + /* new line between all but last entries */ if (i != rels->len - 1) g_print ("\n"); @@ -1440,7 +1406,15 @@ if (dev == NULL) return FALSE; - return fwupd_client_unlock (priv->client, fwupd_device_get_id (dev), NULL, error); + if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN; + if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) + priv->completion_flags |= FWUPD_DEVICE_FLAG_NEEDS_REBOOT; + + if (!fwupd_client_unlock (priv->client, fwupd_device_get_id (dev), NULL, error)) + return FALSE; + + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); } static gboolean @@ -1492,8 +1466,47 @@ return TRUE; } - /* downloads new metadata */ - return fu_util_download_metadata (priv, error); + /* downloads new metadata */ + return fu_util_download_metadata (priv, error); +} + +static gchar * +fu_util_time_to_str (guint64 tmp) +{ + g_return_val_if_fail (tmp != 0, NULL); + + /* seconds */ + if (tmp < 60) { + /* TRANSLATORS: duration in seconds */ + return g_strdup_printf (ngettext ("%u second", "%u seconds", + (gint) tmp), + (guint) tmp); + } + + /* minutes */ + tmp /= 60; + if (tmp < 60) { + /* TRANSLATORS: duration in minutes */ + return g_strdup_printf (ngettext ("%u minute", "%u minutes", + (gint) tmp), + (guint) tmp); + } + + /* hours */ + tmp /= 60; + if (tmp < 60) { + /* TRANSLATORS: duration in minutes */ + return g_strdup_printf (ngettext ("%u hour", "%u hours", + (gint) tmp), + (guint) tmp); + } + + /* days */ + tmp /= 24; + /* TRANSLATORS: duration in days! */ + return g_strdup_printf (ngettext ("%u day", "%u days", + (gint) tmp), + (guint) tmp); } static gboolean @@ -1533,6 +1546,9 @@ g_print (_("%s has firmware updates:"), fwupd_device_get_name (dev)); g_print ("\n"); + /* TRANSLATORS: ID for hardware, typically a SHA1 sum */ + fu_util_print_data (_("Device ID"), fwupd_device_get_id (dev)); + /* TRANSLATORS: a GUID for the hardware */ guids = fwupd_device_get_guids (dev); for (guint j = 0; j < guids->len; j++) { @@ -1543,6 +1559,7 @@ /* print all releases */ for (guint j = 0; j < rels->len; j++) { FwupdRelease *rel = g_ptr_array_index (rels, j); + guint64 duration; GPtrArray *checksums; /* TRANSLATORS: Appstream ID for the hardware type */ @@ -1553,7 +1570,7 @@ fwupd_release_get_version (rel)); /* TRANSLATORS: section header for the release name */ - fu_util_print_data (_("Update Name"), fwupd_release_get_name (rel)); + fu_util_print_data (_("Update Name"), fu_util_release_get_name (rel)); /* TRANSLATORS: section header for the release one line summary */ fu_util_print_data (_("Update Summary"), fwupd_release_get_summary (rel)); @@ -1562,6 +1579,15 @@ fu_util_print_data (_("Update Remote ID"), fwupd_release_get_remote_id (rel)); + /* optional approximate duration */ + duration = fwupd_release_get_install_duration (rel); + if (duration > 0) { + g_autofree gchar *str = fu_util_time_to_str (duration); + /* TRANSLATORS: section header for the amount + * of time it takes to install the update */ + fu_util_print_data (_("Update Duration"), str); + } + checksums = fwupd_release_get_checksums (rel); for (guint k = 0; k < checksums->len; k++) { const gchar *checksum = g_ptr_array_index (checksums, k); @@ -1578,9 +1604,7 @@ tmp = fwupd_release_get_description (rel); if (tmp != NULL) { g_autofree gchar *md = NULL; - md = as_markup_convert (tmp, - AS_MARKUP_CONVERT_FORMAT_SIMPLE, - NULL); + md = fu_util_convert_appstream_description (tmp, NULL); if (md != NULL) { /* TRANSLATORS: section header for long firmware desc */ fu_util_print_data (_("Update Description"), md); @@ -1634,7 +1658,7 @@ /* TRANSLATORS: if the remote is enabled */ fu_util_print_data (_("Enabled"), - fwupd_remote_get_enabled (remote) ? "True" : "False"); + fwupd_remote_get_enabled (remote) ? "true" : "false"); /* TRANSLATORS: remote checksum */ fu_util_print_data (_("Checksum"), @@ -1680,8 +1704,9 @@ } tmp = fwupd_remote_get_password (remote); if (tmp != NULL) { + g_autofree gchar *hidden = g_strnfill (strlen (tmp), '*'); /* TRANSLATORS: remote filename base */ - fu_util_print_data (_("Password"), tmp); + fu_util_print_data (_("Password"), hidden); } tmp = fwupd_remote_get_filename_cache (remote); if (tmp != NULL) { @@ -1722,121 +1747,6 @@ return TRUE; } -static void -fu_util_cancelled_cb (GCancellable *cancellable, gpointer user_data) -{ - FuUtilPrivate *priv = (FuUtilPrivate *) user_data; - /* TRANSLATORS: this is when a device ctrl+c's a watch */ - g_print ("%s\n", _("Cancelled")); - g_main_loop_quit (priv->loop); -} - -static void -fu_util_device_added_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device is hotplugged */ - g_print ("%s\n%s", _("Device added:"), tmp); -} - -static void -fu_util_device_removed_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device is hotplugged */ - g_print ("%s\n%s", _("Device removed:"), tmp); -} - -static void -fu_util_device_changed_cb (FwupdClient *client, - FwupdDevice *device, - gpointer user_data) -{ - g_autofree gchar *tmp = fwupd_device_to_string (device); - /* TRANSLATORS: this is when a device has been updated */ - g_print ("%s\n%s", _("Device changed:"), tmp); -} - -static void -fu_util_changed_cb (FwupdClient *client, gpointer user_data) -{ - /* TRANSLATORS: this is when the daemon state changes */ - g_print ("%s\n", _("Changed")); -} - -static gboolean -fu_util_smbios_dump (FuUtilPrivate *priv, gchar **values, GError **error) -{ - g_autofree gchar *tmp = NULL; - g_autoptr(FuSmbios) smbios = NULL; - if (g_strv_length (values) < 1) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "Invalid arguments"); - return FALSE; - } - smbios = fu_smbios_new (); - if (!fu_smbios_setup_from_file (smbios, values[0], error)) - return FALSE; - tmp = fu_smbios_to_string (smbios); - g_print ("%s\n", tmp); - return TRUE; -} - -static gboolean -fu_util_firmware_builder (FuUtilPrivate *priv, gchar **values, GError **error) -{ - const gchar *script_fn = "startup.sh"; - const gchar *output_fn = "firmware.bin"; - g_autoptr(GBytes) archive_blob = NULL; - g_autoptr(GBytes) firmware_blob = NULL; - if (g_strv_length (values) < 2) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_ARGS, - "Invalid arguments"); - return FALSE; - } - archive_blob = fu_common_get_contents_bytes (values[0], error); - if (archive_blob == NULL) - return FALSE; - if (g_strv_length (values) > 2) - script_fn = values[2]; - if (g_strv_length (values) > 3) - output_fn = values[3]; - firmware_blob = fu_common_firmware_builder (archive_blob, script_fn, output_fn, error); - if (firmware_blob == NULL) - return FALSE; - return fu_common_set_contents_bytes (values[1], firmware_blob, error); -} - -static gboolean -fu_util_monitor (FuUtilPrivate *priv, gchar **values, GError **error) -{ - /* get all the devices */ - if (!fwupd_client_connect (priv->client, priv->cancellable, error)) - return FALSE; - - /* watch for any hotplugged device */ - g_signal_connect (priv->client, "changed", - G_CALLBACK (fu_util_changed_cb), priv); - g_signal_connect (priv->client, "device-added", - G_CALLBACK (fu_util_device_added_cb), priv); - g_signal_connect (priv->client, "device-removed", - G_CALLBACK (fu_util_device_removed_cb), priv); - g_signal_connect (priv->client, "device-changed", - G_CALLBACK (fu_util_device_changed_cb), priv); - g_signal_connect (priv->cancellable, "cancelled", - G_CALLBACK (fu_util_cancelled_cb), priv); - g_main_loop_run (priv->loop); - return TRUE; -} - static gboolean fu_util_update_device_with_release (FuUtilPrivate *priv, FwupdDevice *dev, @@ -1846,7 +1756,6 @@ GPtrArray *checksums; const gchar *remote_id; const gchar *uri_tmp; - g_autofree gchar *basename = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *uri_str = NULL; g_autoptr(SoupURI) uri = NULL; @@ -1863,13 +1772,17 @@ if (remote == NULL) return FALSE; - /* local remotes have the firmware already */ + /* local and directory remotes have the firmware already */ if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_LOCAL) { const gchar *fn_cache = fwupd_remote_get_filename_cache (remote); g_autofree gchar *path = g_path_get_dirname (fn_cache); - /* install with flags chosen by the user */ fn = g_build_filename (path, uri_tmp, NULL); + } else if (fwupd_remote_get_kind (remote) == FWUPD_REMOTE_KIND_DIRECTORY) { + fn = g_strdup (uri_tmp + 7); + } + /* install with flags chosen by the user */ + if (fn != NULL) { return fwupd_client_install (priv->client, fwupd_device_get_id (dev), fn, priv->flags, NULL, error); @@ -1886,8 +1799,7 @@ g_print ("Downloading %s for %s...\n", fwupd_release_get_version (rel), fwupd_device_get_name (dev)); - basename = g_path_get_basename (uri_str); - fn = g_build_filename (g_get_user_cache_dir (), "fwupdmgr", basename, NULL); + fn = fu_util_get_user_cache_path (uri_str); if (!fu_common_mkdir_parent (fn, error)) return FALSE; checksums = fwupd_release_get_checksums (rel); @@ -1896,24 +1808,26 @@ fwupd_checksum_get_best (checksums), error)) return FALSE; - g_print ("Updating %s on %s...\n", - fwupd_release_get_version (rel), - fwupd_device_get_name (dev)); + /* if the device specifies ONLY_OFFLINE automatically set this flag */ + if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_ONLY_OFFLINE)) + priv->flags |= FWUPD_INSTALL_FLAG_OFFLINE; return fwupd_client_install (priv->client, fwupd_device_get_id (dev), fn, priv->flags, NULL, error); } static gboolean -fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) +fu_util_update_all (FuUtilPrivate *priv, GError **error) { - gboolean requires_reboot = FALSE; g_autoptr(GPtrArray) devices = NULL; /* get devices from daemon */ devices = fwupd_client_get_devices (priv->client, NULL, error); if (devices == NULL) return FALSE; + priv->current_operation = FU_UTIL_OPERATION_UPDATE; + g_signal_connect (priv->client, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); for (guint i = 0; i < devices->len; i++) { FwupdDevice *dev = g_ptr_array_index (devices, i); FwupdRelease *rel; @@ -1935,8 +1849,8 @@ rel = g_ptr_array_index (rels, 0); if (!fu_util_update_device_with_release (priv, dev, rel, error)) return FALSE; - if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) - requires_reboot = TRUE; + + fu_util_display_current_message (priv); } /* we don't want to ask anything */ @@ -1945,22 +1859,64 @@ return TRUE; } - /* at least one of the updates needed a reboot */ - if (requires_reboot) { - g_print ("\n%s %s [Y|n]: ", - /* TRANSLATORS: explain why we want to upload */ - _("An update requires a reboot to complete."), - /* TRANSLATORS: reboot to apply the update */ - _("Restart now?")); - if (!fu_util_prompt_for_boolean (TRUE)) - return TRUE; - return fu_util_update_reboot (error); + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + +static gboolean +fu_util_update_by_id (FuUtilPrivate *priv, const gchar *device_id, GError **error) +{ + FwupdRelease *rel; + g_autoptr(FwupdDevice) dev = NULL; + g_autoptr(GPtrArray) rels = NULL; + + /* do not allow a partial device-id */ + dev = fwupd_client_get_device_by_id (priv->client, device_id, NULL, error); + if (dev == NULL) + return FALSE; + + /* get devices from daemon */ + priv->current_operation = FU_UTIL_OPERATION_UPDATE; + g_signal_connect (priv->client, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); + + /* get the releases for this device and filter for validity */ + rels = fwupd_client_get_upgrades (priv->client, + fwupd_device_get_id (dev), + NULL, error); + if (rels == NULL) + return FALSE; + rel = g_ptr_array_index (rels, 0); + if (!fu_util_update_device_with_release (priv, dev, rel, error)) + return FALSE; + + fu_util_display_current_message (priv); + + /* we don't want to ask anything */ + if (priv->no_reboot_check) { + g_debug ("skipping reboot check"); + return TRUE; } - return TRUE; + + /* the update needs the user to restart the computer */ + return fu_util_prompt_complete (priv->completion_flags, TRUE, error); +} + +static gboolean +fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) +{ + if (g_strv_length (values) == 0) + return fu_util_update_all (priv, error); + if (g_strv_length (values) == 1) + return fu_util_update_by_id (priv, values[0], error); + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; } static gboolean -fu_util_modify_remote (FuUtilPrivate *priv, gchar **values, GError **error) +fu_util_remote_modify (FuUtilPrivate *priv, gchar **values, GError **error) { if (g_strv_length (values) < 3) { g_set_error_literal (error, @@ -1969,9 +1925,33 @@ "Invalid arguments"); return FALSE; } - return fwupd_client_modify_remote (priv->client, - values[0], values[1], values[2], - NULL, error); + return fu_util_modify_remote (priv, values[0], values[1], values[2], error); +} + +static gboolean +fu_util_remote_enable (FuUtilPrivate *priv, gchar **values, GError **error) +{ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + return fu_util_modify_remote (priv, values[0], "Enabled", "true", error); +} + +static gboolean +fu_util_remote_disable (FuUtilPrivate *priv, gchar **values, GError **error) +{ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + return fu_util_modify_remote (priv, values[0], "Enabled", "false", error); } static gboolean @@ -1996,71 +1976,163 @@ rel = fu_util_prompt_for_release (priv, rels, error); if (rel == NULL) return FALSE; + + /* update the console if composite devices are also updated */ + priv->current_operation = FU_UTIL_OPERATION_DOWNGRADE; + g_signal_connect (priv->client, "device-changed", + G_CALLBACK (fu_util_update_device_changed_cb), priv); priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; return fu_util_update_device_with_release (priv, dev, rel, error); } static gboolean -fu_util_hwids (FuUtilPrivate *priv, gchar **values, GError **error) +fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error) { - g_autoptr(FuSmbios) smbios = fu_smbios_new (); - g_autoptr(FuHwids) hwids = fu_hwids_new (); - const gchar *hwid_keys[] = { - FU_HWIDS_KEY_BIOS_VENDOR, - FU_HWIDS_KEY_BIOS_VERSION, - FU_HWIDS_KEY_BIOS_MAJOR_RELEASE, - FU_HWIDS_KEY_BIOS_MINOR_RELEASE, - FU_HWIDS_KEY_MANUFACTURER, - FU_HWIDS_KEY_FAMILY, - FU_HWIDS_KEY_PRODUCT_NAME, - FU_HWIDS_KEY_PRODUCT_SKU, - FU_HWIDS_KEY_ENCLOSURE_KIND, - FU_HWIDS_KEY_BASEBOARD_MANUFACTURER, - FU_HWIDS_KEY_BASEBOARD_PRODUCT, - NULL }; - - /* read DMI data */ - if (!fu_smbios_setup (smbios, error)) - return FALSE; - if (!fu_hwids_setup (hwids, smbios, error)) - return FALSE; - - /* show debug output */ - g_print ("Computer Information\n"); - g_print ("--------------------\n"); - for (guint i = 0; hwid_keys[i] != NULL; i++) { - const gchar *tmp = fu_hwids_get_value (hwids, hwid_keys[i]); - if (tmp == NULL) - continue; - g_print ("%s: %s\n", hwid_keys[i], tmp); - } - - /* show GUIDs */ - g_print ("\nHardware IDs\n"); - g_print ("------------\n"); - for (guint i = 0; i < 15; i++) { - const gchar *keys = NULL; - g_autofree gchar *guid = NULL; - g_autofree gchar *key = NULL; - g_autofree gchar *keys_str = NULL; - g_auto(GStrv) keysv = NULL; - g_autoptr(GError) error_local = NULL; + g_autoptr(GPtrArray) devices = NULL; + gboolean has_pending = FALSE; - /* get the GUID */ - key = g_strdup_printf ("HardwareID-%u", i); - keys = fu_hwids_get_replace_keys (hwids, key); - guid = fu_hwids_get_guid (hwids, key, &error_local); - if (guid == NULL) { - g_print ("%s\n", error_local->message); - continue; + /* handle both forms */ + if (g_strv_length (values) == 0) { + /* activate anything with _NEEDS_ACTIVATION */ + devices = fwupd_client_get_devices (priv->client, NULL, error); + if (devices == NULL) + return FALSE; + for (guint i = 0; i < devices->len; i++) { + FuDevice *device = g_ptr_array_index (devices, i); + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) { + has_pending = TRUE; + break; + } } + } else if (g_strv_length (values) == 1) { + FwupdDevice *device = fwupd_client_get_device_by_id (priv->client, + values[0], + NULL, + error); + if (device == NULL) + return FALSE; + devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_ptr_array_add (devices, device); + if (fwupd_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) + has_pending = TRUE; + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments"); + return FALSE; + } + + /* nothing to do */ + if (!has_pending) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_NOTHING_TO_DO, + "No firmware to activate"); + return FALSE; + } + + /* activate anything with _NEEDS_ACTIVATION */ + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *device = g_ptr_array_index (devices, i); + if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)) + continue; + /* TRANSLATORS: shown when shutting down to switch to the new version */ + g_print ("%s %s…\n", _("Activating firmware update for"), + fwupd_device_get_name (device)); + if (!fwupd_client_activate (priv->client, NULL, + fwupd_device_get_id (device), error)) + return FALSE; + } + + return TRUE; +} - /* show what makes up the GUID */ - keysv = g_strsplit (keys, "&", -1); - keys_str = g_strjoinv (" + ", keysv); - g_print ("{%s} <- %s\n", guid, keys_str); +static gboolean +fu_util_set_approved_firmware (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_auto(GStrv) checksums = NULL; + + /* check args */ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: list of checksums expected"); + return FALSE; + } + + /* call into daemon */ + checksums = g_strsplit (values[0], ",", -1); + return fwupd_client_set_approved_firmware (priv->client, + checksums, + priv->cancellable, + error); +} + +static gboolean +fu_util_get_approved_firmware (FuUtilPrivate *priv, gchar **values, GError **error) +{ + g_auto(GStrv) checksums = NULL; + + /* check args */ + if (g_strv_length (values) != 0) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: none expected"); + return FALSE; + } + + /* call into daemon */ + checksums = fwupd_client_get_approved_firmware (priv->client, + priv->cancellable, + error); + if (checksums == NULL) + return FALSE; + if (g_strv_length (checksums) == 0) { + /* TRANSLATORS: approved firmware has been checked by + * the domain administrator */ + g_print ("%s\n", _("There is no approved firmware.")); + } else { + /* TRANSLATORS: approved firmware has been checked by + * the domain administrator */ + g_print ("%s\n", ngettext ("Approved firmware:", + "Approved firmware:", + g_strv_length (checksums))); + for (guint i = 0; checksums[i] != NULL; i++) + g_print (" * %s\n", checksums[i]); } + return TRUE; +} +static gboolean +fu_util_modify_config (FuUtilPrivate *priv, gchar **values, GError **error) +{ + /* check args */ + if (g_strv_length (values) != 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: KEY VALUE expected"); + return FALSE; + } + if (!fwupd_client_modify_config (priv->client, + values[0], values[1], + priv->cancellable, + error)) + return FALSE; + if (!priv->assume_yes) { + g_print ("%s\n [Y|n]: ", + /* TRANSLATORS: configuration changes only take effect on restart */ + _("Restart the daemon to make the change effective?")); + if (!fu_util_prompt_for_boolean (FALSE)) + return TRUE; + } +#ifdef HAVE_SYSTEMD + if (!fu_systemd_unit_stop (fu_util_get_systemd_unit (), error)) + return FALSE; +#endif return TRUE; } @@ -2082,12 +2154,13 @@ static void fu_util_private_free (FuUtilPrivate *priv) { - if (priv->cmd_array != NULL) - g_ptr_array_unref (priv->cmd_array); if (priv->client != NULL) g_object_unref (priv->client); + if (priv->current_device != NULL) + g_object_unref (priv->current_device); if (priv->soup_session != NULL) g_object_unref (priv->soup_session); + g_free (priv->current_message); g_main_loop_unref (priv->loop); g_object_unref (priv->cancellable); g_object_unref (priv->progressbar); @@ -2095,7 +2168,50 @@ g_free (priv); } +static gboolean +fu_util_check_daemon_version (FuUtilPrivate *priv, GError **error) +{ + g_autofree gchar *client = g_strdup_printf ("%i.%i.%i", + FWUPD_MAJOR_VERSION, + FWUPD_MINOR_VERSION, + FWUPD_MICRO_VERSION); + const gchar *daemon = fwupd_client_get_daemon_version (priv->client); + + if (g_strcmp0 (daemon, client) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + /* TRANSLATORS: error message */ + _("Unsupported daemon version %s, client version is %s"), + daemon, client); + return FALSE; + } + + return TRUE; +} + +static gboolean +fu_util_check_polkit_actions (GError **error) +{ + g_autofree gchar *directory = fu_common_get_path (FU_PATH_KIND_POLKIT_ACTIONS); + g_autofree gchar *filename = g_build_filename (directory, + "org.freedesktop.fwupd.policy", + NULL); + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_AUTH_FAILED, + "PolicyKit files are missing, see https://github.com/hughsie/fwupd/wiki/PolicyKit-files-are-missing"); + return FALSE; + } + + return TRUE; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop int main (int argc, char *argv[]) @@ -2103,12 +2219,14 @@ gboolean force = FALSE; gboolean allow_older = FALSE; gboolean allow_reinstall = FALSE; + gboolean no_history = FALSE; gboolean offline = FALSE; gboolean ret; gboolean verbose = FALSE; gboolean version = FALSE; g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) cmd_array = fu_util_cmd_array_new (); g_autofree gchar *cmd_descriptions = NULL; const GOptionEntry options[] = { { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, @@ -2128,10 +2246,13 @@ _("Allow downgrading firmware versions"), NULL }, { "force", '\0', 0, G_OPTION_ARG_NONE, &force, /* TRANSLATORS: command line option */ - _("Override plugin warning"), NULL }, + _("Override warnings and force the action"), NULL }, { "assume-yes", 'y', 0, G_OPTION_ARG_NONE, &priv->assume_yes, /* TRANSLATORS: command line option */ _("Answer yes to all questions"), NULL }, + { "sign", '\0', 0, G_OPTION_ARG_NONE, &priv->sign, + /* TRANSLATORS: command line option */ + _("Sign the uploaded data with the client certificate"), NULL }, { "no-unreported-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_unreported_check, /* TRANSLATORS: command line option */ _("Do not check for unreported history"), NULL }, @@ -2141,6 +2262,12 @@ { "no-reboot-check", '\0', 0, G_OPTION_ARG_NONE, &priv->no_reboot_check, /* TRANSLATORS: command line option */ _("Do not check for reboot after update"), NULL }, + { "no-history", '\0', 0, G_OPTION_ARG_NONE, &no_history, + /* TRANSLATORS: command line option */ + _("Do not write to the history database"), NULL }, + { "show-all-devices", '\0', 0, G_OPTION_ARG_NONE, &priv->show_all_devices, + /* TRANSLATORS: command line option */ + _("Show devices that are not updatable"), NULL }, { NULL} }; @@ -2158,151 +2285,162 @@ priv->progressbar = fu_progressbar_new (); /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_util_item_free); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "get-devices", NULL, /* TRANSLATORS: command description */ _("Get all devices that support firmware updates"), fu_util_get_devices); - fu_util_add (priv->cmd_array, - "hwids", - NULL, - /* TRANSLATORS: command description */ - _("Return all the hardware IDs for the machine"), - fu_util_hwids); - fu_util_add (priv->cmd_array, - "install-prepared", + fu_util_cmd_array_add (cmd_array, + "get-topology", NULL, /* TRANSLATORS: command description */ - _("Install prepared updates now"), - fu_util_install_prepared); - fu_util_add (priv->cmd_array, + _("Get all devices according to the system topology"), + fu_util_get_topology); + fu_util_cmd_array_add (cmd_array, "get-history", NULL, /* TRANSLATORS: command description */ _("Show history of firmware updates"), fu_util_get_history); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "clear-history", NULL, /* TRANSLATORS: command description */ _("Erase all firmware update history"), fu_util_clear_history); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "report-history", NULL, /* TRANSLATORS: command description */ _("Share firmware history with the developers"), fu_util_report_history); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "install", "FILE [ID]", /* TRANSLATORS: command description */ _("Install a firmware file on this hardware"), fu_util_install); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "get-details", "FILE", /* TRANSLATORS: command description */ _("Gets details about a firmware file"), fu_util_get_details); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "get-updates", NULL, /* TRANSLATORS: command description */ _("Gets the list of updates for connected hardware"), fu_util_get_updates); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "update", NULL, /* TRANSLATORS: command description */ _("Updates all firmware to latest versions available"), fu_util_update); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "verify", "[DEVICE_ID]", /* TRANSLATORS: command description */ _("Gets the cryptographic hash of the dumped firmware"), fu_util_verify); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "unlock", "DEVICE_ID", /* TRANSLATORS: command description */ _("Unlocks the device for firmware access"), fu_util_unlock); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "clear-results", "DEVICE_ID", /* TRANSLATORS: command description */ _("Clears the results from the last update"), fu_util_clear_results); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "clear-offline", NULL, /* TRANSLATORS: command description */ _("Clears any updates scheduled to be updated offline"), fu_util_clear_offline); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "get-results", "DEVICE_ID", /* TRANSLATORS: command description */ _("Gets the results from the last update"), fu_util_get_results); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "get-releases", "[DEVICE_ID]", /* TRANSLATORS: command description */ _("Gets the releases for a device"), fu_util_get_releases); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "get-remotes", NULL, /* TRANSLATORS: command description */ _("Gets the configured remotes"), fu_util_get_remotes); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "downgrade", "[DEVICE_ID]", /* TRANSLATORS: command description */ _("Downgrades the firmware on a device"), fu_util_downgrade); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "refresh", "[FILE FILE_SIG REMOTE_ID]", /* TRANSLATORS: command description */ _("Refresh metadata from remote server"), fu_util_refresh); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "verify-update", "[DEVICE_ID]", /* TRANSLATORS: command description */ _("Update the stored metadata with current ROM contents"), fu_util_verify_update); - fu_util_add (priv->cmd_array, - "monitor", - NULL, - /* TRANSLATORS: command description */ - _("Monitor the daemon for events"), - fu_util_monitor); - fu_util_add (priv->cmd_array, - "build-firmware", - "FILE-IN FILE-OUT [SCRIPT] [OUTPUT]", - /* TRANSLATORS: command description */ - _("Build firmware using a sandbox"), - fu_util_firmware_builder); - fu_util_add (priv->cmd_array, - "smbios-dump", - "FILE", - /* TRANSLATORS: command description */ - _("Dump SMBIOS data from a file"), - fu_util_smbios_dump); - fu_util_add (priv->cmd_array, + fu_util_cmd_array_add (cmd_array, "modify-remote", "REMOTE-ID KEY VALUE", /* TRANSLATORS: command description */ _("Modifies a given remote"), - fu_util_modify_remote); + fu_util_remote_modify); + fu_util_cmd_array_add (cmd_array, + "enable-remote", + "REMOTE-ID", + /* TRANSLATORS: command description */ + _("Enables a given remote"), + fu_util_remote_enable); + fu_util_cmd_array_add (cmd_array, + "disable-remote", + "REMOTE-ID", + /* TRANSLATORS: command description */ + _("Disables a given remote"), + fu_util_remote_disable); + fu_util_cmd_array_add (cmd_array, + "activate", + "[DEVICE-ID]", + /* TRANSLATORS: command description */ + _("Activate devices"), + fu_util_activate); + fu_util_cmd_array_add (cmd_array, + "get-approved-firmware", + NULL, + /* TRANSLATORS: firmware approved by the admin */ + _("Gets the list of approved firmware."), + fu_util_get_approved_firmware); + fu_util_cmd_array_add (cmd_array, + "set-approved-firmware", + "CHECKSUM1[,CHECKSUM2][,CHECKSUM3]", + /* TRANSLATORS: firmware approved by the admin */ + _("Sets the list of approved firmware."), + fu_util_set_approved_firmware); + fu_util_cmd_array_add (cmd_array, + "modify-config", + "KEY,VALUE", + /* TRANSLATORS: sets something in daemon.conf */ + _("Modifies a daemon configuration value."), + fu_util_modify_config); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); @@ -2311,19 +2449,19 @@ priv, NULL); /* sort by command name */ - g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) fu_sort_command_name_cb); + fu_util_cmd_array_sort (cmd_array); /* non-TTY consoles cannot answer questions */ if (isatty (fileno (stdout)) == 0) { priv->no_unreported_check = TRUE; priv->no_metadata_check = TRUE; priv->no_reboot_check = TRUE; + fu_progressbar_set_interactive (priv->progressbar, FALSE); } /* get a list of the commands */ priv->context = g_option_context_new (NULL); - cmd_descriptions = fu_util_get_descriptions (priv->cmd_array); + cmd_descriptions = fu_util_cmd_array_to_string (cmd_array); g_option_context_set_summary (priv->context, cmd_descriptions); g_option_context_set_description (priv->context, "This tool allows an administrator to query and control the " @@ -2358,6 +2496,8 @@ priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER; if (force) priv->flags |= FWUPD_INSTALL_FLAG_FORCE; + if (no_history) + priv->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY; /* connect to the daemon */ priv->client = fwupd_client_new (); @@ -2368,10 +2508,8 @@ /* just show versions and exit */ if (version) { - g_print ("client version:\t%i.%i.%i\n", - FWUPD_MAJOR_VERSION, - FWUPD_MINOR_VERSION, - FWUPD_MICRO_VERSION); + g_autofree gchar *version_str = fu_util_get_versions(); + g_print ("%s\n", version_str); if (!fwupd_client_connect (priv->client, priv->cancellable, &error)) { g_printerr ("Failed to connect to daemon: %s\n", error->message); @@ -2379,31 +2517,43 @@ } g_print ("daemon version:\t%s\n", fwupd_client_get_daemon_version (priv->client)); -#ifdef FWUPD_GIT_DESCRIBE - g_print ("checkout info:\t%s\n", FWUPD_GIT_DESCRIBE); -#endif - g_print ("compile-time dependency versions\n"); - g_print ("\tappstream-glib:\t%d.%d.%d\n", - AS_MAJOR_VERSION, - AS_MINOR_VERSION, - AS_MICRO_VERSION); - g_print ("\tgusb:\t%d.%d.%d\n", - G_USB_MAJOR_VERSION, - G_USB_MINOR_VERSION, - G_USB_MICRO_VERSION); -#ifdef LIBFWUP_LIBRARY_VERSION - g_print ("\tfwupdate:\t%s\n", - LIBFWUP_LIBRARY_VERSION); -#endif -#ifdef EFIVAR_LIBRARY_VERSION - g_print ("\tefivar:\t%s\n", - EFIVAR_LIBRARY_VERSION); -#endif return EXIT_SUCCESS; } + /* show a warning if the daemon is tainted */ + if (!fwupd_client_connect (priv->client, priv->cancellable, &error)) { + g_printerr ("Failed to connect to daemon: %s\n", + error->message); + return EXIT_FAILURE; + } + if (fwupd_client_get_tainted (priv->client)) { + g_printerr ("WARNING: The daemon has loaded 3rd party code and " + "is no longer supported by the upstream developers!\n"); + } + + /* check that we have at least this version daemon running */ + if (!fu_util_check_daemon_version (priv, &error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + +#ifdef HAVE_SYSTEMD + /* make sure the correct daemon is in use */ + if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0 && + !fu_util_using_correct_daemon (&error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } +#endif + + /* make sure polkit actions were installed */ + if (!fu_util_check_polkit_actions (&error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + /* run the specified command */ - ret = fu_util_run (priv, argv[1], (gchar**) &argv[2], &error); + ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { if (g_error_matches (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_ARGS)) { g_autofree gchar *tmp = NULL; diff -Nru fwupd-1.0.6/src/fu-util-common.c fwupd-1.2.10/src/fu-util-common.c --- fwupd-1.0.6/src/fu-util-common.c 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-util-common.c 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,653 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +#include +#include +#include + +#include "fu-util-common.h" +#include "fu-device.h" + +#ifdef HAVE_SYSTEMD +#include "fu-systemd.h" +#endif + +#define SYSTEMD_FWUPD_UNIT "fwupd.service" +#define SYSTEMD_SNAP_FWUPD_UNIT "snap.fwupd.fwupd.service" + +const gchar * +fu_util_get_systemd_unit (void) +{ + if (g_getenv ("SNAP") != NULL) + return SYSTEMD_SNAP_FWUPD_UNIT; + return SYSTEMD_FWUPD_UNIT; +} + +#ifdef HAVE_SYSTEMD +static const gchar * +fu_util_get_expected_command (const gchar *target) +{ + if (g_strcmp0 (target, SYSTEMD_SNAP_FWUPD_UNIT) == 0) + return "fwupd.fwupdmgr"; + return "fwupdmgr"; +} +#endif + +gboolean +fu_util_using_correct_daemon (GError **error) +{ +#ifdef HAVE_SYSTEMD + g_autofree gchar *default_target = NULL; + g_autoptr(GError) error_local = NULL; + const gchar *target = fu_util_get_systemd_unit (); + + default_target = fu_systemd_get_default_target (&error_local); + if (default_target == NULL) { + g_debug ("Systemd isn't accessible: %s\n", error_local->message); + return TRUE; + } + if (!fu_systemd_unit_check_exists (target, &error_local)) { + g_debug ("wrong target: %s\n", error_local->message); + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + /* TRANSLATORS: error message */ + _("Mismatched daemon and client, use %s instead"), + fu_util_get_expected_command (target)); + return FALSE; + } +#endif + return TRUE; +} + +void +fu_util_print_data (const gchar *title, const gchar *msg) +{ + gsize title_len; + g_auto(GStrv) lines = NULL; + + if (msg == NULL) + return; + g_print ("%s:", title); + + /* pad */ + title_len = strlen (title) + 1; + lines = g_strsplit (msg, "\n", -1); + for (guint j = 0; lines[j] != NULL; j++) { + for (gsize i = title_len; i < 25; i++) + g_print (" "); + g_print ("%s\n", lines[j]); + title_len = 0; + } +} + +guint +fu_util_prompt_for_number (guint maxnum) +{ + gint retval; + guint answer = 0; + + do { + char buffer[64]; + + /* swallow the \n at end of line too */ + if (!fgets (buffer, sizeof (buffer), stdin)) + break; + if (strlen (buffer) == sizeof (buffer) - 1) + continue; + + /* get a number */ + retval = sscanf (buffer, "%u", &answer); + + /* positive */ + if (retval == 1 && answer <= maxnum) + break; + + /* TRANSLATORS: the user isn't reading the question */ + g_print (_("Please enter a number from 0 to %u: "), maxnum); + } while (TRUE); + return answer; +} + +gboolean +fu_util_prompt_for_boolean (gboolean def) +{ + do { + char buffer[4]; + if (!fgets (buffer, sizeof (buffer), stdin)) + continue; + if (strlen (buffer) == sizeof (buffer) - 1) + continue; + if (g_strcmp0 (buffer, "\n") == 0) + return def; + buffer[0] = g_ascii_toupper (buffer[0]); + if (g_strcmp0 (buffer, "Y\n") == 0) + return TRUE; + if (g_strcmp0 (buffer, "N\n") == 0) + return FALSE; + } while (TRUE); + return FALSE; +} + +gboolean +fu_util_print_device_tree (GNode *n, gpointer data) +{ + FwupdDevice *dev = FWUPD_DEVICE (n->data); + const gchar *name; + g_autoptr(GString) str = g_string_new (NULL); + + /* root node */ + if (dev == NULL) { + g_print ("○\n"); + return FALSE; + } + + /* add previous branches */ + for (GNode *c = n->parent; c->parent != NULL; c = c->parent) { + if (g_node_next_sibling (c) == NULL) + g_string_prepend (str, " "); + else + g_string_prepend (str, "│ "); + } + + /* add this branch */ + if (g_node_last_sibling (n) == n) + g_string_append (str, "└─ "); + else + g_string_append (str, "├─ "); + + /* dump to the console */ + name = fwupd_device_get_name (dev); + if (name == NULL) + name = "Unknown device"; + g_string_append (str, name); + for (guint i = strlen (name) + 2 * g_node_depth (n); i < 45; i++) + g_string_append_c (str, ' '); + g_print ("%s %s\n", str->str, fu_device_get_id (dev)); + return FALSE; +} + +gboolean +fu_util_is_interesting_device (FwupdDevice *dev) +{ + if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE)) + return TRUE; + if (fwupd_device_get_update_error (dev) != NULL) + return TRUE; + return FALSE; +} + +gchar * +fu_util_get_user_cache_path (const gchar *fn) +{ + g_autofree gchar *basename = g_path_get_basename (fn); + g_autofree gchar *cachedir_legacy = NULL; + + /* return the legacy path if it exists rather than renaming it to + * prevent problems when using old and new versions of fwupd */ + cachedir_legacy = g_build_filename (g_get_user_cache_dir (), "fwupdmgr", NULL); + if (g_file_test (cachedir_legacy, G_FILE_TEST_IS_DIR)) + return g_build_filename (cachedir_legacy, basename, NULL); + + return g_build_filename (g_get_user_cache_dir (), "fwupd", basename, NULL); +} + +gchar * +fu_util_get_versions (void) +{ + GString *string = g_string_new (""); + + g_string_append_printf (string, + "client version:\t%i.%i.%i\n", + FWUPD_MAJOR_VERSION, + FWUPD_MINOR_VERSION, + FWUPD_MICRO_VERSION); +#ifdef FWUPD_GIT_DESCRIBE + g_string_append_printf (string, + "checkout info:\t%s\n", FWUPD_GIT_DESCRIBE); +#endif + g_string_append_printf (string, + "compile-time dependency versions\n"); + g_string_append_printf (string, + "\tgusb:\t%d.%d.%d\n", + G_USB_MAJOR_VERSION, + G_USB_MINOR_VERSION, + G_USB_MICRO_VERSION); +#ifdef EFIVAR_LIBRARY_VERSION + g_string_append_printf (string, + "\tefivar:\t%s", + EFIVAR_LIBRARY_VERSION); +#endif + return g_string_free (string, FALSE); +} + +static gboolean +fu_util_update_shutdown (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_LOGIND + /* shutdown using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "PowerOff", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* shutdown using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Stop", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + +gboolean +fu_util_update_reboot (GError **error) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GVariant) val = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (connection == NULL) + return FALSE; + +#ifdef HAVE_LOGIND + /* reboot using logind */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Reboot", + g_variant_new ("(b)", TRUE), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#elif defined(HAVE_CONSOLEKIT) + /* reboot using ConsoleKit */ + val = g_dbus_connection_call_sync (connection, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "Restart", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); +#else + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "No supported backend compiled in to perform the operation."); +#endif + return val != NULL; +} + +gboolean +fu_util_prompt_complete (FwupdDeviceFlags flags, gboolean prompt, GError **error) +{ + if (flags & FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN) { + if (prompt) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to shutdown */ + _("An update requires the system to shutdown to complete."), + /* TRANSLATORS: shutdown to apply the update */ + _("Shutdown now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + } + return fu_util_update_shutdown (error); + } + if (flags & FWUPD_DEVICE_FLAG_NEEDS_REBOOT) { + if (prompt) { + g_print ("\n%s %s [Y|n]: ", + /* TRANSLATORS: explain why we want to reboot */ + _("An update requires a reboot to complete."), + /* TRANSLATORS: reboot to apply the update */ + _("Restart now?")); + if (!fu_util_prompt_for_boolean (TRUE)) + return TRUE; + } + return fu_util_update_reboot (error); + } + + return TRUE; +} + +static void +fu_util_cmd_free (FuUtilCmd *item) +{ + g_free (item->name); + g_free (item->arguments); + g_free (item->description); + g_free (item); +} + +GPtrArray * +fu_util_cmd_array_new (void) +{ + return g_ptr_array_new_with_free_func ((GDestroyNotify) fu_util_cmd_free); +} + +static gint +fu_util_cmd_sort_cb (FuUtilCmd **item1, FuUtilCmd **item2) +{ + return g_strcmp0 ((*item1)->name, (*item2)->name); +} + +void +fu_util_cmd_array_sort (GPtrArray *array) +{ + g_ptr_array_sort (array, (GCompareFunc) fu_util_cmd_sort_cb); +} + +void +fu_util_cmd_array_add (GPtrArray *array, + const gchar *name, + const gchar *arguments, + const gchar *description, + FuUtilCmdFunc callback) +{ + g_auto(GStrv) names = NULL; + + g_return_if_fail (name != NULL); + g_return_if_fail (description != NULL); + g_return_if_fail (callback != NULL); + + /* add each one */ + names = g_strsplit (name, ",", -1); + for (guint i = 0; names[i] != NULL; i++) { + FuUtilCmd *item = g_new0 (FuUtilCmd, 1); + item->name = g_strdup (names[i]); + if (i == 0) { + item->description = g_strdup (description); + } else { + /* TRANSLATORS: this is a command alias, e.g. 'get-devices' */ + item->description = g_strdup_printf (_("Alias to %s"), + names[0]); + } + item->arguments = g_strdup (arguments); + item->callback = callback; + g_ptr_array_add (array, item); + } +} + +gboolean +fu_util_cmd_array_run (GPtrArray *array, + FuUtilPrivate *priv, + const gchar *command, + gchar **values, + GError **error) +{ + /* find command */ + for (guint i = 0; i < array->len; i++) { + FuUtilCmd *item = g_ptr_array_index (array, i); + if (g_strcmp0 (item->name, command) == 0) + return item->callback (priv, values, error); + } + + /* not found */ + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + /* TRANSLATORS: error message */ + _("Command not found")); + return FALSE; +} + +gchar * +fu_util_cmd_array_to_string (GPtrArray *array) +{ + gsize len; + const gsize max_len = 35; + GString *string; + + /* print each command */ + string = g_string_new (""); + for (guint i = 0; i < array->len; i++) { + FuUtilCmd *item = g_ptr_array_index (array, i); + g_string_append (string, " "); + g_string_append (string, item->name); + len = strlen (item->name) + 2; + if (item->arguments != NULL) { + g_string_append (string, " "); + g_string_append (string, item->arguments); + len += strlen (item->arguments) + 1; + } + if (len < max_len) { + for (gsize j = len; j < max_len + 1; j++) + g_string_append_c (string, ' '); + g_string_append (string, item->description); + g_string_append_c (string, '\n'); + } else { + g_string_append_c (string, '\n'); + for (gsize j = 0; j < max_len + 1; j++) + g_string_append_c (string, ' '); + g_string_append (string, item->description); + g_string_append_c (string, '\n'); + } + } + + /* remove trailing newline */ + if (string->len > 0) + g_string_set_size (string, string->len - 1); + + return g_string_free (string, FALSE); +} + +SoupSession * +fu_util_setup_networking (GError **error) +{ + const gchar *http_proxy; + g_autofree gchar *user_agent = NULL; + g_autoptr(SoupSession) session = NULL; + + /* create the soup session */ + user_agent = fwupd_build_user_agent (PACKAGE_NAME, PACKAGE_VERSION); + session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, user_agent, + SOUP_SESSION_TIMEOUT, 60, + NULL); + if (session == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to setup networking"); + return NULL; + } + + /* set the proxy */ + http_proxy = g_getenv ("https_proxy"); + if (http_proxy == NULL) + http_proxy = g_getenv ("HTTPS_PROXY"); + if (http_proxy == NULL) + http_proxy = g_getenv ("http_proxy"); + if (http_proxy == NULL) + http_proxy = g_getenv ("HTTP_PROXY"); + if (http_proxy != NULL && strlen (http_proxy) > 0) { + g_autoptr(SoupURI) proxy_uri = soup_uri_new (http_proxy); + if (proxy_uri == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid proxy URI: %s", http_proxy); + return NULL; + } + g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); + } + + /* this disables the double-compression of the firmware.xml.gz file */ + soup_session_remove_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); + return g_steal_pointer (&session); +} + +gchar * +fu_util_release_get_name (FwupdRelease *release) +{ + const gchar *name = fwupd_release_get_name (release); + GPtrArray *cats = fwupd_release_get_categories (release); + + for (guint i = 0; i < cats->len; i++) { + const gchar *cat = g_ptr_array_index (cats, i); + if (g_strcmp0 (cat, "X-Device") == 0) { + /* TRANSLATORS: a specific part of hardware, + * the first %s is the device name, e.g. 'Unifying Receiver` */ + return g_strdup_printf (_("%s Device Update"), name); + } + if (g_strcmp0 (cat, "X-System") == 0) { + /* TRANSLATORS: the entire system, e.g. all internal devices, + * the first %s is the device name, e.g. 'ThinkPad P50` */ + return g_strdup_printf (_("%s System Update"), name); + } + if (g_strcmp0 (cat, "X-EmbeddedController") == 0) { + /* TRANSLATORS: the EC is typically the keyboard controller chip, + * the first %s is the device name, e.g. 'ThinkPad P50` */ + return g_strdup_printf (_("%s Embedded Controller Update"), name); + } + if (g_strcmp0 (cat, "X-ManagementEngine") == 0) { + /* TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, + * the first %s is the device name, e.g. 'ThinkPad P50` */ + return g_strdup_printf (_("%s ME Update"), name); + } + if (g_strcmp0 (cat, "X-CorporateManagementEngine") == 0) { + /* TRANSLATORS: ME stands for Management Engine (with Intel AMT), + * where the first %s is the device name, e.g. 'ThinkPad P50` */ + return g_strdup_printf (_("%s Corporate ME Update"), name); + } + if (g_strcmp0 (cat, "X-ConsumerManagementEngine") == 0) { + /* TRANSLATORS: ME stands for Management Engine, where + * the first %s is the device name, e.g. 'ThinkPad P50` */ + return g_strdup_printf (_("%s Consumer ME Update"), name); + } + if (g_strcmp0 (cat, "X-Controller") == 0) { + /* TRANSLATORS: the controller is a device that has other devices + * plugged into it, for example ThunderBolt, FireWire or USB, + * the first %s is the device name, e.g. 'Intel ThunderBolt` */ + return g_strdup_printf (_("%s Controller Update"), name); + } + } + + /* TRANSLATORS: this is the fallback where we don't know if the release + * is updating the system, the device, or a device class, or something else -- + * the first %s is the device name, e.g. 'ThinkPad P50` */ + return g_strdup_printf (_("%s Update"), name); +} + +static GPtrArray * +fu_util_strsplit_words (const gchar *text, guint line_len) +{ + g_auto(GStrv) tokens = NULL; + g_autoptr(GPtrArray) lines = g_ptr_array_new (); + g_autoptr(GString) curline = g_string_new (NULL); + + /* sanity check */ + if (text == NULL || text[0] == '\0') + return NULL; + if (line_len == 0) + return NULL; + + /* tokenize the string */ + tokens = g_strsplit (text, " ", -1); + for (guint i = 0; tokens[i] != NULL; i++) { + + /* current line plus new token is okay */ + if (curline->len + strlen (tokens[i]) < line_len) { + g_string_append_printf (curline, "%s ", tokens[i]); + continue; + } + + /* too long, so remove space, add newline and dump */ + if (curline->len > 0) + g_string_truncate (curline, curline->len - 1); + g_ptr_array_add (lines, g_strdup (curline->str)); + g_string_truncate (curline, 0); + g_string_append_printf (curline, "%s ", tokens[i]); + } + + /* any incomplete line? */ + if (curline->len > 0) { + g_string_truncate (curline, curline->len - 1); + g_ptr_array_add (lines, g_strdup (curline->str)); + } + return g_steal_pointer (&lines); +} + +static void +fu_util_warning_box_line (const gchar *start, + const gchar *text, + const gchar *end, + const gchar *padding, + guint width) +{ + guint offset = 0; + if (start != NULL) { + offset += g_utf8_strlen (start, -1); + g_print ("%s", start); + } + if (text != NULL) { + offset += g_utf8_strlen (text, -1); + g_print ("%s", text); + } + if (end != NULL) + offset += g_utf8_strlen (end, -1); + for (guint i = offset; i < width; i++) + g_print ("%s", padding); + if (end != NULL) + g_print ("%s\n", end); +} + +void +fu_util_warning_box (const gchar *str, guint width) +{ + g_auto(GStrv) split = g_strsplit (str, "\n", -1); + + /* header */ + fu_util_warning_box_line ("╔", NULL, "╗", "═", width); + + /* body */ + for (guint i = 0; split[i] != NULL; i++) { + g_autoptr(GPtrArray) lines = fu_util_strsplit_words (split[i], width - 4); + if (lines == NULL) + continue; + for (guint j = 0; j < lines->len; j++) { + const gchar *line = g_ptr_array_index (lines, j); + fu_util_warning_box_line ("║ ", line, " ║", " ", width); + } + fu_util_warning_box_line ("║", NULL, "║", " ", width); + } + + /* footer */ + fu_util_warning_box_line ("╚", NULL, "╝", "═", width); +} diff -Nru fwupd-1.0.6/src/fu-util-common.h fwupd-1.2.10/src/fu-util-common.h --- fwupd-1.0.6/src/fu-util-common.h 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/fu-util-common.h 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +/* this is only valid for tools */ +#define FWUPD_ERROR_INVALID_ARGS (FWUPD_ERROR_LAST+1) + +typedef struct FuUtilPrivate FuUtilPrivate; +typedef gboolean (*FuUtilCmdFunc) (FuUtilPrivate *util, + gchar **values, + GError **error); +typedef struct { + gchar *name; + gchar *arguments; + gchar *description; + FuUtilCmdFunc callback; +} FuUtilCmd; + +void fu_util_print_data (const gchar *title, + const gchar *msg); +guint fu_util_prompt_for_number (guint maxnum); +gboolean fu_util_prompt_for_boolean (gboolean def); + +gboolean fu_util_print_device_tree (GNode *n, gpointer data); +gboolean fu_util_is_interesting_device (FwupdDevice *dev); +gchar *fu_util_get_user_cache_path (const gchar *fn); +SoupSession *fu_util_setup_networking (GError **error); + +gchar *fu_util_get_versions (void); + +void fu_util_warning_box (const gchar *str, + guint width); +gboolean fu_util_prompt_complete (FwupdDeviceFlags flags, + gboolean prompt, + GError **error); +gboolean fu_util_update_reboot (GError **error); + +GPtrArray *fu_util_cmd_array_new (void); +void fu_util_cmd_array_add (GPtrArray *array, + const gchar *name, + const gchar *arguments, + const gchar *description, + FuUtilCmdFunc callback); +gchar *fu_util_cmd_array_to_string (GPtrArray *array); +void fu_util_cmd_array_sort (GPtrArray *array); +gboolean fu_util_cmd_array_run (GPtrArray *array, + FuUtilPrivate *priv, + const gchar *command, + gchar **values, + GError **error); +gchar *fu_util_release_get_name (FwupdRelease *release); + +const gchar *fu_util_get_systemd_unit (void); +gboolean fu_util_using_correct_daemon (GError **error); + +G_END_DECLS diff -Nru fwupd-1.0.6/src/meson.build fwupd-1.2.10/src/meson.build --- fwupd-1.0.6/src/meson.build 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/meson.build 2019-07-15 18:25:54.000000000 +0000 @@ -1,11 +1,13 @@ -cargs = ['-DG_LOG_DOMAIN="Fu"'] - -install_data(['org.freedesktop.fwupd.xml'], - install_dir : join_paths(datadir, 'dbus-1', 'interfaces') -) +if get_option('daemon') + install_data(['org.freedesktop.fwupd.xml'], + install_dir : join_paths(datadir, 'dbus-1', 'interfaces') + ) +endif keyring_deps = [] keyring_src = [] +test_deps = [] +init_src = [] if get_option('gpg') keyring_src += 'fu-keyring-gpg.c' @@ -16,21 +18,35 @@ if get_option('pkcs7') keyring_src += 'fu-keyring-pkcs7.c' keyring_deps += gnutls + if get_option('tests') + test_deps += colorhug_pkcs7_signature + endif +endif + +if get_option('systemd') + init_src += 'fu-systemd.c' endif libfwupdprivate = static_library( 'fwupdprivate', sources : [ + init_src, + 'fu-archive.c', 'fu-common.c', + 'fu-common-guid.c', + 'fu-common-version.c', + 'fu-chunk.c', 'fu-device.c', 'fu-device-locker.c', 'fu-hwids.c', 'fu-history.c', + 'fu-io-channel.c', 'fu-plugin.c', 'fu-progressbar.c', 'fu-quirks.c', 'fu-smbios.c', 'fu-test.c', + 'fu-udev-device.c', 'fu-usb-device.c', ], include_directories : [ @@ -38,41 +54,40 @@ include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, giounix, gudev, gusb, - polkit, soup, sqlite, libarchive, + libjsonglib, + libxmlb, valgrind, ], + link_with : [ + fwupd, + ], c_args : [ - cargs, - '-DLOCALSTATEDIR="' + localstatedir + '"', - '-DSYSFSFIRMWAREDIR="/sys/firmware"', - '-DFWUPDDATADIR="' + join_paths(datadir, 'fwupd') + '"', - '-DFWUPDCONFIGDIR="' + join_paths(default_sysconfdir, 'fwupd') + '"', '-DFU_OFFLINE_DESTDIR=""', ], ) +if get_option('daemon') fwupdmgr = executable( 'fwupdmgr', sources : [ 'fu-util.c', + 'fu-util-common.c', ], include_directories : [ include_directories('..'), include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, giounix, gudev, gusb, - polkit, soup, sqlite, libarchive, @@ -83,15 +98,153 @@ libfwupdprivate, ], c_args : [ - cargs, - '-DLOCALSTATEDIR="' + localstatedir + '"', '-DFU_OFFLINE_DESTDIR=""', ], install : true, install_dir : bindir ) +endif + +if get_option('agent') +fwupdagent = executable( + 'fwupdagent', + sources : [ + 'fu-agent.c', + 'fu-util-common.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libfwupd'), + ], + dependencies : [ + libxmlb, + giounix, + gudev, + gusb, + soup, + libjsonglib, + ], + link_with : [ + fwupd, + libfwupdprivate, + ], + install : true, + install_dir : join_paths(libexecdir, 'fwupd') +) +endif + +if get_option('systemd') +fwupdagent = executable( + 'fwupdoffline', + sources : [ + 'fu-offline.c', + 'fu-util-common.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libfwupd'), + ], + dependencies : [ + giounix, + gudev, + gusb, + soup, + ], + link_with : [ + fwupd, + libfwupdprivate, + ], + c_args : [ + '-DFU_OFFLINE_DESTDIR=""', + ], + install : true, + install_dir : join_paths(libexecdir, 'fwupd') +) +endif + +resources_src = gnome.compile_resources( + 'fwupd-resources', + 'fwupd.gresource.xml', + source_dir : '.', + c_name : 'fu' +) + +fu_hash = custom_target( + 'fu-hash.h', + input : libfwupdprivate, + output : 'fu-hash.h', + command : [python3.path(), + join_paths(meson.current_source_dir(), 'fu-hash.py'), + '@INPUT@', '@OUTPUT@'] +) + +fwupdtool = executable( + 'fwupdtool', + resources_src, + fu_hash, + sources : [ + 'fu-tool.c', + keyring_src, + init_src, + 'fu-archive.c', + 'fu-chunk.c', + 'fu-common.c', + 'fu-common-cab.c', + 'fu-common-guid.c', + 'fu-common-version.c', + 'fu-config.c', + 'fu-keyring.c', + 'fu-keyring-result.c', + 'fu-engine.c', + 'fu-hwids.c', + 'fu-debug.c', + 'fu-device.c', + 'fu-device-list.c', + 'fu-device-locker.c', + 'fu-idle.c', + 'fu-install-task.c', + 'fu-io-channel.c', + 'fu-keyring.c', + 'fu-keyring-utils.c', + 'fu-history.c', + 'fu-plugin.c', + 'fu-plugin-list.c', + 'fu-quirks.c', + 'fu-smbios.c', + 'fu-udev-device.c', + 'fu-usb-device.c', + 'fu-util-common.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libfwupd'), + ], + dependencies : [ + keyring_deps, + libxmlb, + libgcab, + giounix, + gmodule, + gudev, + gusb, + soup, + sqlite, + valgrind, + libarchive, + libjsonglib, + ], + link_with : [ + fwupd, + libfwupdprivate, + ], + c_args : [ + '-DFU_OFFLINE_DESTDIR=""', + ], + install : true, + install_dir : join_paths(libexecdir, 'fwupd') +) -if get_option('man') +if get_option('daemon') and get_option('man') help2man = find_program('help2man') custom_target('fwupdmgr-man', input : fwupdmgr, @@ -109,20 +262,20 @@ ) endif -resources_src = gnome.compile_resources( - 'fwupd-resources', - 'fwupd.gresource.xml', - source_dir : '.', - c_name : 'fu' -) - +if get_option('daemon') executable( 'fwupd', resources_src, + fu_hash, sources : [ keyring_src, + init_src, + 'fu-archive.c', + 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -133,12 +286,17 @@ 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', + 'fu-idle.c', + 'fu-io-channel.c', + 'fu-install-task.c', 'fu-keyring.c', + 'fu-keyring-utils.c', 'fu-history.c', 'fu-plugin.c', 'fu-plugin-list.c', 'fu-quirks.c', 'fu-smbios.c', + 'fu-udev-device.c', 'fu-usb-device.c', ], include_directories : [ @@ -147,7 +305,7 @@ ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, @@ -158,22 +316,18 @@ sqlite, valgrind, libarchive, + libjsonglib, ], link_with : fwupd, c_args : [ - cargs, - '-DLOCALSTATEDIR="' + localstatedir + '"', - '-DPLUGINDIR="' + plugin_dir + '"', - '-DSYSFSFIRMWAREDIR="/sys/firmware"', - '-DSYSCONFDIR="' + default_sysconfdir + '"', - '-DFWUPDDATADIR="' + join_paths(datadir, 'fwupd') + '"', - '-DFWUPDCONFIGDIR="' + join_paths(default_sysconfdir, 'fwupd') + '"', '-DFU_OFFLINE_DESTDIR=""', ], install : true, install_dir : join_paths(libexecdir, 'fwupd') ) +endif + if get_option('tests') testdatadir_src = join_paths(meson.source_root(), 'data', 'tests') testdatadir_dst = join_paths(meson.build_root(), 'data', 'tests') @@ -182,23 +336,33 @@ 'fu-self-test', resources_src, colorhug_test_firmware, - colorhug_pkcs7_signature, builder_test_firmware, hwid_test_firmware, noreqs_test_firmware, + test_deps, + fu_hash, sources : [ keyring_src, + init_src, 'fu-self-test.c', + 'fu-archive.c', + 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', + 'fu-common-version.c', 'fu-config.c', 'fu-engine.c', 'fu-keyring.c', + 'fu-keyring-utils.c', 'fu-hwids.c', 'fu-device.c', 'fu-device-list.c', 'fu-device-locker.c', 'fu-history.c', + 'fu-idle.c', + 'fu-install-task.c', + 'fu-io-channel.c', 'fu-keyring.c', 'fu-keyring-result.c', 'fu-plugin.c', @@ -207,6 +371,7 @@ 'fu-quirks.c', 'fu-smbios.c', 'fu-test.c', + 'fu-udev-device.c', 'fu-usb-device.c', ], include_directories : [ @@ -215,53 +380,56 @@ ], dependencies : [ keyring_deps, - appstream_glib, + libxmlb, libgcab, giounix, gmodule, gudev, gusb, - polkit, soup, sqlite, valgrind, libarchive, + libjsonglib, ], link_with : [ fwupd, ], c_args : [ - cargs, '-DTESTDATADIR_SRC="' + testdatadir_src + '"', '-DTESTDATADIR_DST="' + testdatadir_dst + '"', '-DTESTDATADIR="' + testdatadir_src + ':' + testdatadir_dst + '"', - '-DLOCALSTATEDIR="/tmp/fwupd-self-test/var"', '-DPLUGINBUILDDIR="' + pluginbuilddir + '"', '-DFU_OFFLINE_DESTDIR="/tmp/fwupd-self-test"', - '-DPLUGINDIR="' + testdatadir_src + '"', - '-DSYSFSFIRMWAREDIR="' + testdatadir_src + '"', - '-DFWUPDDATADIR="' + testdatadir_src + '"', - '-DSYSCONFDIR="' + testdatadir_src + '"', - '-DFWUPDCONFIGDIR="' + testdatadir_src + '"', ], ) - test('fu-self-test', e, is_parallel:false) + test('fu-self-test', e, is_parallel:false, timeout:180) endif if get_option('introspection') gir_dep = declare_dependency(sources: gir) gnome.generate_gir(fwupd, sources : [ + 'fu-archive.c', + 'fu-archive.h', + 'fu-chunk.c', + 'fu-chunk.h', 'fu-common.c', + 'fu-common-guid.c', + 'fu-common-guid.h', + 'fu-common-version.c', + 'fu-common-version.h', 'fu-common.h', 'fu-device.c', 'fu-device.h', 'fu-device-locker.c', 'fu-device-locker.h', + 'fu-io-channel.c', 'fu-plugin.c', 'fu-plugin.h', 'fu-quirks.c', 'fu-quirks.h', + 'fu-udev-device.c', 'fu-usb-device.c', ], nsversion : '1.0', @@ -274,7 +442,7 @@ include_directories('../libfwupd'), ], dependencies : [ - appstream_glib, + libxmlb, gir_dep, giounix, gusb, diff -Nru fwupd-1.0.6/src/org.freedesktop.fwupd.xml fwupd-1.2.10/src/org.freedesktop.fwupd.xml --- fwupd-1.0.6/src/org.freedesktop.fwupd.xml 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/src/org.freedesktop.fwupd.xml 2019-07-15 18:25:54.000000000 +0000 @@ -6,7 +6,7 @@ - The interface used for quering firmware for the system. + The interface used for querying firmware for the system. @@ -23,6 +23,17 @@ + + + + + If the daemon has been tainted with a 3rd party plugin. + + + + + + @@ -297,6 +308,25 @@ + + + + + Activate a firmware update on the device. + + + + + + + + An ID, typically the sha hash of the device string. + + + + + + @@ -342,6 +372,44 @@ + + + + + Gets the list of approved firmware that can be applied to devices. + In an enterprise this will be configured by a domain administrator. + + + + + + + The checksums of the archives + + + + + + + + + + + Sets the list of approved firmware that can be applied to devices. + In an enterprise this will be configured by a domain administrator. + + + + + + + The checksums of the archives + + + + + + @@ -400,6 +468,35 @@ + + + + + Modify persistent configuration for daemon + + + + + + + + The key, e.g. 'BlacklistPlugins'. + + + + + + + + + The value of the correct type, e.g. a URL. + + + + + + + @@ -472,6 +569,45 @@ + + + + + + + + + Signs some text, typically using a self-signed PKCS-7 certificate. + + + + + + + + String input data, certainly *NOT* binary data. + + + + + + + + + Options to be used when signing, e.g. + add-cert=True or add-timestamp=True. + + + + + + + + + The detached signature string. + + + diff -Nru fwupd-1.0.6/src/README.md fwupd-1.2.10/src/README.md --- fwupd-1.0.6/src/README.md 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/src/README.md 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,137 @@ +Quirk use +--------- +Quirks are defined by creating an INI style file in the compiled in quirk location (typically `/usr/share/fwupd/quirks.d`). + +The quirk is declared by creating a group based upon the `DeviceInstanceId` or `GUID` +and then mapping out values to keys. + +## All plugins +All fwupd devices support the following quirks: + +### Plugin +Sets the plugin to use for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the plugin name, e.g. `csr` +* Minimum fwupd version: **1.1.0** +### UefiVersionFormat +Assigns the version format to use for a specific manufacturer. A specific version +format is sometimes chosen to match the appearance of other systems or +specifications. +* Key: a %FU_HWIDS_KEY_MANUFACTURER, e.g. `Alienware` +* Value: the version format, e.g. `none` +* Supported values: `none`, `use-triplet` +* Minimum fwupd version: **1.0.1** +### ComponentIDs +Assigns the version format to use for a specific AppStream component. A specific +version format is sometimes chosen to match the appearance of other systems or +specifications. +* Key: the optionally wildcarded AppStream ID e.g. `com.dell.uefi*.firmware` +* Value: the version format, e.g. `none` +* Minimum fwupd version: **1.0.1** +### Flags +Assigns optional quirks to use for a 8bitdo device +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the quirk, e.g. `is-bootloader` +* Supported values: + * `none`: no device quirks + * `is-bootloader`: device is in bootloader mode +* Minimum fwupd version: **1.0.3** +### Summary +Sets a summary for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* the device summary, e.g. `An open source display colorimeter` +* Minimum fwupd version: **1.0.2** +### Icon +Adds an icon name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the device icon name, e.g. `media-removable` +* Minimum fwupd version: **1.0.2** +### Name +Sets a name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the device name, e.g. `ColorHug` +* Minimum fwupd version: **1.0.2** +### Guid +Adds an extra GUID for a specific hardware device. If the value provided is not +already a suitable GUID, it will be converted to one. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.0.3** +### CounterpartGuid +Adds an counterpart GUID for a specific hardware device. If the value provided +is not already a suitable GUID, it will be converted to one. A counterpart +GUID is typically the GUID of the same device in bootloader or runtime mode, +if they have a different device PCI or USB ID. Adding this type of GUID does +not cause a "cascade" by matching using the quirk database. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.1.2** +### ParentGuid +Adds an extra GUID to mark as the parent device. If the value provided is not +already a suitable GUID, it will be converted to one. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the GUID, e.g. `537f7800-8529-5656-b2fa-b0901fe91696` +* Minimum fwupd version: **1.1.2** +### Children +Adds one or more virtual devices to a physical device. To set the object type +of the child device use a pipe before the object type, for instance: +`FuRts54xxDeviceUSB\VID_0763&PID_2806&I2C_01` If the type of device is not +specified the parent device type is used. If the values provided are not +already suitable GUIDs, they will be converted. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: The virtual device, delimited by a comma +* Minimum fwupd version: **1.1.2** +### Vendor +Sets a vendor name for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the vendor, e.g. `Hughski Limited` +* Minimum fwupd version: **1.0.3** +### VendorId +Sets a vendor ID for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: the vendor, e.g. `USB:0x123A` +* Minimum fwupd version: **1.1.2** +### Version +Sets a version for a specific hardware device. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: Version number, e.g. `1.2` +* Minimum fwupd version: **1.0.3** +### FirmwareSizeMin +Sets the minimum allowed firmware size. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in bytes, e.g. `512` +* Minimum fwupd version: **1.1.2** +### FirmwareSizeMax +Sets the maximum allowed firmware size. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in bytes, e.g. `1024` +* Minimum fwupd version: **1.1.2** +### InstallDuration +Sets the estimated time to flash the device +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: A number in seconds, e.g. `60` +* Minimum fwupd version: **1.1.3** +### VersionFormat +Sets the version format the device should use for conversion. +* Key: the device ID, e.g. `DeviceInstanceId=USB\VID_0763&PID_2806` +* Value: The quirk format, e.g. `quad` +* Minimum fwupd version: **1.2.0** + +## Plugin specific +Plugins may add support for additional quirks that are relevant only for +those plugins. View them by looking at the `README.md` in plugin directories. + +## Example +Here is an example as seen in the CSR plugin. + +``` +[DeviceInstanceId=USB\VID_0A12&PID_1337] +Plugin = csr +Name = H05 +Summary = Bluetooth Headphones +Icon = audio-headphones +Vendor = AIAIAI +[DeviceInstanceId=USB\VID_0A12&PID_1337&REV_2520] +Version = 1.2 +``` +Additional samples can be found in other plugins. diff -Nru fwupd-1.0.6/subprojects/flashrom.wrap fwupd-1.2.10/subprojects/flashrom.wrap --- fwupd-1.0.6/subprojects/flashrom.wrap 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/subprojects/flashrom.wrap 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,4 @@ +[wrap-git] +directory = flashrom +url = https://github.com/hughsie/flashrom.git +revision = wip/hughsie/fwupd diff -Nru fwupd-1.0.6/subprojects/.gitignore fwupd-1.2.10/subprojects/.gitignore --- fwupd-1.0.6/subprojects/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/subprojects/.gitignore 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,2 @@ +flashrom +libxmlb diff -Nru fwupd-1.0.6/subprojects/libxmlb.wrap fwupd-1.2.10/subprojects/libxmlb.wrap --- fwupd-1.0.6/subprojects/libxmlb.wrap 1970-01-01 00:00:00.000000000 +0000 +++ fwupd-1.2.10/subprojects/libxmlb.wrap 2019-07-15 18:25:54.000000000 +0000 @@ -0,0 +1,4 @@ +[wrap-git] +directory = libxmlb +url = https://github.com/hughsie/libxmlb.git +revision = 0.1.7 diff -Nru fwupd-1.0.6/.travis.yml fwupd-1.2.10/.travis.yml --- fwupd-1.0.6/.travis.yml 2018-03-12 10:41:58.000000000 +0000 +++ fwupd-1.2.10/.travis.yml 2019-07-15 18:25:54.000000000 +0000 @@ -9,7 +9,6 @@ - OS=fedora - OS=debian-x86_64 - OS=arch - - OS=debian-s390x - OS=debian-i386 - OS=ubuntu-x86_64 @@ -17,4 +16,4 @@ - ./contrib/ci/generate_docker.py script: - - docker run -e CI=true -t -v `pwd`/dist:/build/dist fwupd-$OS + - docker run --privileged -e CI=true -t -v `pwd`/dist:/build/dist fwupd-$OS