diff --git a/DBXUpdate-20100307-x64.cab b/DBXUpdate-20100307-x64.cab
new file mode 100644
index 0000000000000000000000000000000000000000..b9159889515ee4691a86914c8d2a3d59b12bc585
Binary files /dev/null and b/DBXUpdate-20100307-x64.cab differ
diff --git a/DBXUpdate-20140413-x64.cab b/DBXUpdate-20140413-x64.cab
new file mode 100644
index 0000000000000000000000000000000000000000..646b53e3a3f7f0a90b6af877e67f5fe9f4f98208
Binary files /dev/null and b/DBXUpdate-20140413-x64.cab differ
diff --git a/DBXUpdate-20160809-x64.cab b/DBXUpdate-20160809-x64.cab
new file mode 100644
index 0000000000000000000000000000000000000000..c2b1e0a721ae51234749079b02c7c3038cbde0c5
Binary files /dev/null and b/DBXUpdate-20160809-x64.cab differ
diff --git a/DBXUpdate-20200729-aa64.cab b/DBXUpdate-20200729-aa64.cab
new file mode 100644
index 0000000000000000000000000000000000000000..cc8220493512b18e8aaced2292f989c3f677eb88
Binary files /dev/null and b/DBXUpdate-20200729-aa64.cab differ
diff --git a/DBXUpdate-20200729-ia32.cab b/DBXUpdate-20200729-ia32.cab
new file mode 100644
index 0000000000000000000000000000000000000000..c394f75c1498749219a8b1f5ebe70118f0d164c5
Binary files /dev/null and b/DBXUpdate-20200729-ia32.cab differ
diff --git a/DBXUpdate-20200729-x64.cab b/DBXUpdate-20200729-x64.cab
new file mode 100644
index 0000000000000000000000000000000000000000..cfb272a49af72fb7817818144dd4264dc0e15105
Binary files /dev/null and b/DBXUpdate-20200729-x64.cab differ
diff --git a/centos-ca-secureboot.der b/centos-ca-secureboot.der
new file mode 100644
index 0000000000000000000000000000000000000000..44a2563dee3f8eeecd5026306be46d2a8d89970d
Binary files /dev/null and b/centos-ca-secureboot.der differ
diff --git a/centossecureboot001.der b/centossecureboot001.der
new file mode 100644
index 0000000000000000000000000000000000000000..e8216b1db725cd132b515a277368fc89a9d8fa3d
Binary files /dev/null and b/centossecureboot001.der differ
diff --git a/centossecureboot203.der b/centossecureboot203.der
new file mode 100644
index 0000000000000000000000000000000000000000..5df41c254e31fd3a0f878bed4db4e851729e6ec5
Binary files /dev/null and b/centossecureboot203.der differ
diff --git a/centossecurebootca2.der b/centossecurebootca2.der
new file mode 100644
index 0000000000000000000000000000000000000000..42bdfcfbcda649796099fdc87bbe9dc58e2348d5
Binary files /dev/null and b/centossecurebootca2.der differ
diff --git a/fwupd-1.7.4.tar.xz b/fwupd-1.7.4.tar.xz
new file mode 100644
index 0000000000000000000000000000000000000000..897ab0d50ee6ff86ee140d533c910e677968b22c
Binary files /dev/null and b/fwupd-1.7.4.tar.xz differ
diff --git a/fwupd-1.8.6.tar.xz b/fwupd-1.8.6.tar.xz
new file mode 100644
index 0000000000000000000000000000000000000000..f0385284d01474fdc81d7448b7eb57908183ec29
Binary files /dev/null and b/fwupd-1.8.6.tar.xz differ
diff --git a/fwupd-1.8.6/.circleci/config.yml b/fwupd-1.8.6/.circleci/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1fa92e74fb0e3fa1b6ed5995e6e2f12b276bef35
--- /dev/null
+++ b/fwupd-1.8.6/.circleci/config.yml
@@ -0,0 +1,111 @@
+version: 2
+jobs:
+ build-ubuntu-x86_64:
+ machine:
+ image: ubuntu-2204:edge
+ steps:
+ - checkout
+ - run:
+ name: "Build container"
+ command: OS=ubuntu-x86_64 ./contrib/ci/generate_docker.py build
+ - run:
+ name: "Run build script"
+ command: docker run --privileged -e CI=true -t -v `pwd`:/github/workspace fwupd-ubuntu-x86_64
+ - persist_to_workspace:
+ root: .
+ paths:
+ - "dist/share/doc"
+
+ build-windows:
+ docker:
+ - image: fedora:36
+ steps:
+ - checkout
+ - run:
+ name: "Build Win32"
+ command: ./contrib/ci/build_windows.sh
+ - persist_to_workspace:
+ root: .
+ paths:
+ - "dist/setup/*.msi"
+ - "dist/VERSION"
+ - "dist/news.txt"
+ - store_artifacts:
+ path: dist/setup
+
+ publish-docs:
+ machine:
+ image: ubuntu-2204:edge
+ steps:
+ - attach_workspace:
+ at: .
+ - add_ssh_keys:
+ fingerprints:
+ - "d8:73:05:1b:7c:93:8c:12:41:78:15:3d:5d:af:b4:c2"
+ - run:
+ name: Clone docs
+ working_directory: dist/share/doc/fwupd
+ command: |
+ git clone --depth 1 git@github.com:fwupd/fwupd.github.io.git
+ - deploy:
+ name: Trigger docs deployment
+ working_directory: dist/share/doc/fwupd/fwupd.github.io
+ command: |
+ git config credential.helper 'cache --timeout=120'
+ git config user.email "info@fwupd.org"
+ git config user.name "Documentation deployment Bot"
+ rm -rf *
+ cp ../../libfwupd* ../*html . -R
+ git add .
+ git commit -a --allow-empty -m "Trigger deployment"
+ git push git@github.com:fwupd/fwupd.github.io.git
+
+ publish-github-exe-release:
+ docker:
+ - image: circleci/golang:1.17.5
+ steps:
+ - attach_workspace:
+ at: .
+ - run:
+ name: "Publish Release on GitHub"
+ command: |
+ go get github.com/tcnksm/ghr
+ VERSION=$(cat dist/VERSION)
+ BODY=$(cat dist/news.txt)
+ ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -b "${BODY}" ${VERSION} ./dist/setup/
+workflows:
+ version: 2
+ main:
+ jobs:
+ - build-windows
+ - build-ubuntu-x86_64
+ deploy:
+ jobs:
+ - build-ubuntu-x86_64:
+ filters:
+ branches:
+ ignore: /.*/
+ tags:
+ only: /^\d+\.\d+\.\d+$/
+ - build-windows:
+ filters:
+ branches:
+ ignore: /.*/
+ tags:
+ only: /^\d+\.\d+\.\d+$/
+ - publish-github-exe-release:
+ requires:
+ - build-windows
+ filters:
+ branches:
+ ignore: /.*/
+ tags:
+ only: /^\d+\.\d+\.\d+$/
+ - publish-docs:
+ requires:
+ - build-ubuntu-x86_64
+ filters:
+ branches:
+ ignore: /.*/
+ tags:
+ only: /^\d+\.\d+\.\d+$/
diff --git a/fwupd-1.8.6/.clang-format b/fwupd-1.8.6/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..27d9025cd780a65ea056a27e09fde425d8f646ab
--- /dev/null
+++ b/fwupd-1.8.6/.clang-format
@@ -0,0 +1,51 @@
+---
+AlignAfterOpenBracket: 'Align'
+AlignConsecutiveAssignments: 'false'
+AlignConsecutiveDeclarations: 'false'
+AlignConsecutiveMacros: 'true'
+AlignOperands: 'true'
+AlignTrailingComments: 'true'
+AllowAllArgumentsOnNextLine: 'false'
+AllowAllParametersOfDeclarationOnNextLine: 'false'
+AllowShortBlocksOnASingleLine: 'false'
+AllowShortCaseLabelsOnASingleLine: 'false'
+AllowShortFunctionsOnASingleLine: 'Inline'
+AllowShortIfStatementsOnASingleLine: 'false'
+AlwaysBreakAfterReturnType: 'All'
+BinPackParameters: 'false'
+BinPackArguments: 'false'
+BreakBeforeBraces: 'Linux'
+ColumnLimit: '100'
+DerivePointerAlignment: 'false'
+IndentCaseLabels: 'false'
+IndentWidth: '8'
+IncludeBlocks: 'Regroup'
+KeepEmptyLinesAtTheStartOfBlocks: 'false'
+MaxEmptyLinesToKeep: '1'
+PointerAlignment: 'Right'
+SortIncludes: 'true'
+SpaceAfterCStyleCast: 'false'
+SpaceBeforeAssignmentOperators : 'true'
+SpaceBeforeParens: 'ControlStatements'
+SpaceInEmptyParentheses: 'false'
+SpacesInSquareBrackets: 'false'
+TabWidth: '8'
+UseTab: 'Always'
+PenaltyBreakAssignment: '3'
+PenaltyBreakBeforeFirstCallParameter: '15'
+---
+Language: 'Proto'
+---
+Language: 'Cpp'
+IncludeCategories:
+ - Regex: '^"config.h"$'
+ Priority: '0'
+ - Regex: ''
+ Priority: '1'
+ - Regex: '^<'
+ Priority: '2'
+ - Regex: 'fwupd'
+ Priority: '3'
+ - Regex: '.*'
+ Priority: '4'
+...
diff --git a/fwupd-1.8.6/.editorconfig b/fwupd-1.8.6/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..8abc7283ffdc053a7c69a46e6edbb295b7bc2b3a
--- /dev/null
+++ b/fwupd-1.8.6/.editorconfig
@@ -0,0 +1,14 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+
+[*.py]
+indent_style = space
+indent_size = 4
+
+[*.{c|h}]
+indent_style = tab
+indent_size = 8
+
diff --git a/fwupd-1.8.6/.git-blame-ignore-revs b/fwupd-1.8.6/.git-blame-ignore-revs
new file mode 100644
index 0000000000000000000000000000000000000000..9707d0013f9076ff917c2127258fd0348382640a
--- /dev/null
+++ b/fwupd-1.8.6/.git-blame-ignore-revs
@@ -0,0 +1 @@
+72819f91c19e076ca383e6e9fd7c7a510c62792e
diff --git a/fwupd-1.8.6/.gitconfig b/fwupd-1.8.6/.gitconfig
new file mode 100644
index 0000000000000000000000000000000000000000..c78c54fdca17f4bd6a894c2ee06af273174de3c5
--- /dev/null
+++ b/fwupd-1.8.6/.gitconfig
@@ -0,0 +1,2 @@
+[blame]
+ ignoreRevsFile = .git-blame-ignore-revs
diff --git a/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-general.md b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-general.md
new file mode 100644
index 0000000000000000000000000000000000000000..a95cdb14d76c9058250c61b8b4bdadc995e8a8b5
--- /dev/null
+++ b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-general.md
@@ -0,0 +1,44 @@
+---
+name: Bug report (General)
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Steps to Reproduce**
+Steps to reproduce the behavior.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**fwupd version information**
+Please provide the version of the daemon and client.
+
+```shell
+fwupdmgr --version
+```
+
+Please note how you installed it (`apt`, `dnf`, `pacman`, source, etc):
+
+
+
+**fwupd device information**
+
+Please provide the output of the fwupd devices recognized in your system.
+
+```shell
+fwupdmgr get-devices --show-all-devices
+```
+
+
+
+**Additional questions**
+
+- Operating system and version:
+- Have you tried rebooting?
+- Is this a regression?
diff --git a/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-uefi.md b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-uefi.md
new file mode 100644
index 0000000000000000000000000000000000000000..966b02682a7e44e6722c489dca550fa652828d04
--- /dev/null
+++ b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-uefi.md
@@ -0,0 +1,62 @@
+---
+name: Bug report (UEFI Updates)
+about: Issues involving UEFI device updates
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Steps to Reproduce**
+Steps to reproduce the behavior.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**fwupd version information**
+Please provide the version of the daemon and client.
+
+```shell
+fwupdmgr --version
+```
+
+Please note how you installed it (`apt`, `dnf`, `pacman`, source, etc):
+
+
+
+**fwupd device information**
+
+Please provide the output of the fwupd devices recognized in your system.
+
+```shell
+fwupdmgr get-devices --show-all-devices
+```
+
+
+
+**System UEFI configuration**
+Please provide the output of the following commands:
+
+```shell
+efibootmgr -v
+```
+
+```shell
+efivar -l | grep fw
+```
+
+```shell
+tree /boot
+```
+
+**Additional questions**
+
+- Operating system and version:
+- Have you tried rebooting?
+- Is this a regression?
+- Are you using an NVMe disk?
+- Is secure boot enabled?
+- Is this a Lenovo system with 'Boot Order Lock' turned on in the BIOS?
diff --git a/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-wd19.md b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-wd19.md
new file mode 100644
index 0000000000000000000000000000000000000000..f8a1f926430a71696e0ce09ecf336e870ef1efe4
--- /dev/null
+++ b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/bug-report-wd19.md
@@ -0,0 +1,70 @@
+---
+name: Bug report (Dell WD19)
+about: Create a report to help us improve
+title: 'Dell WD19 upgrade issue'
+labels: bug
+assignees: 'cragw'
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Steps to Reproduce**
+Steps to reproduce the behavior.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**fwupd version information**
+Please provide the version of the daemon and client.
+
+```shell
+fwupdmgr --version
+```
+
+Please note how you installed it (`apt`, `dnf`, `pacman`, source, etc):
+
+
+
+**fwupd device information**
+
+Please provide the output of the external fwupd devices recognized in your system.
+
+```shell
+fwupdmgr get-devices --filter=~internal
+```
+
+
+
+**Dock SKU**
+Please mention which module is installed in your WD19.
+
+- [ ] WD19 (Single-C)
+- [ ] WD19TB (Thunderbolt)
+- [ ] WD19DC (Dual-C)
+
+**Peripherals connected to the dock**
+Please describe all devices connected to the dock. Be as specific as possible,
+including USB devices, hubs, monitors, and downstream type-C devices.
+
+**Verbose daemon logs**
+First enable daemon verbose logs collection.
+
+```shell
+fwupdmgr modify-config "VerboseDomains" "*"
+```
+
+Then try to reproduce the issue. Even if it doesn't reproduce, please attach the
+daemon verbose logs collected from the system journal.
+
+```shell
+journalctl -b -u fwupd.service
+```
+
+**Additional questions**
+
+- Operating system and version:
+- Have you tried unplugging the dock or any peripherals from your machine?
+- Have you tried to power cycle the dock from the AC adapter?
+- Is this a regression?
diff --git a/fwupd-1.8.6/.github/ISSUE_TEMPLATE/feature_request.md b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000000000000000000000000000000000..11fc491ef1dae316f2b06bbb40eaba9c757fdfd1
--- /dev/null
+++ b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/fwupd-1.8.6/.github/ISSUE_TEMPLATE/question.md b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/question.md
new file mode 100644
index 0000000000000000000000000000000000000000..d0b97137694ec5141549ae37e6f95a4c14bc7afd
--- /dev/null
+++ b/fwupd-1.8.6/.github/ISSUE_TEMPLATE/question.md
@@ -0,0 +1,18 @@
+---
+name: Question
+about: Ask a question about the project or how to do something
+title: ''
+labels: question
+assignees: ''
+
+---
+
+**Describe the question**
+A clear and concise description of what you are wondering about.
+
+**fwupd version information**
+Please provide the version of the daemon and client if applicable to your current installation of `fwupd`.
+
+```shell
+fwupdmgr --version
+```
diff --git a/fwupd-1.8.6/.github/dependabot.yml b/fwupd-1.8.6/.github/dependabot.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5ace4600a1f26e6892982f3e2f069ebfab108d87
--- /dev/null
+++ b/fwupd-1.8.6/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/fwupd-1.8.6/.github/pull_request_template.md b/fwupd-1.8.6/.github/pull_request_template.md
new file mode 100644
index 0000000000000000000000000000000000000000..a7e1e6e2e1d1aee819eda36f82c2318d9dccbf1f
--- /dev/null
+++ b/fwupd-1.8.6/.github/pull_request_template.md
@@ -0,0 +1,6 @@
+Type of pull request:
+
+- [ ] New plugin (Please include [new plugin checklist](https://github.com/fwupd/fwupd/wiki/New-plugin-checklist))
+- [ ] Code fix
+- [ ] Feature
+- [ ] Documentation
diff --git a/fwupd-1.8.6/.github/stale.yml b/fwupd-1.8.6/.github/stale.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c398d030201bfa727e51fd1ddcc31cb0a1aa2717
--- /dev/null
+++ b/fwupd-1.8.6/.github/stale.yml
@@ -0,0 +1,27 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 30
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - enhancement
+ - regression
+# Label to use when marking an issue as stale
+staleLabel: wontfix
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs.
+ Please note: We are just a few people who contribute to a shared project,
+ and it's impossible for us to fix every bug with such limited resources.
+
+ If you want to investigate and try to help solve this yourself, we will
+ review all pull requests from new contributors.
+
+ If this is issue is important to you for your business please talk with
+ your technical account manager about arranging resources to solve this issue.
+ You might even consider hiring someone to write the code if you're unable
+ to do so yourself, e.g. see: https://fwupd.org/lvfs/docs/consulting
+
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/fwupd-1.8.6/.github/workflows/codeql-analysis.yml b/fwupd-1.8.6/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..57e4b2a585cc75605d9515e11ff3e1a06744a81d
--- /dev/null
+++ b/fwupd-1.8.6/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,46 @@
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-20.04
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'cpp', 'python' ]
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+
+ - name: Install dependencies
+ run: >
+ sudo apt-get update &&
+ sudo ./contrib/ci/fwupd_setup_helpers.py install-dependencies --yes -o ubuntu &&
+ python3 -m pip install --user "meson >= 0.60.0"
+
+ - name: Build
+ run: |
+ mkdir -p $GITHUB_WORKSPACE/build
+ cd $GITHUB_WORKSPACE/build
+ meson .. -Dman=false -Defi_binary=false -Dplugin_uefi_capsule_splash=false --prefix=$GITHUB_WORKSPACE/dist
+ ninja
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/fwupd-1.8.6/.github/workflows/create_containers.yml b/fwupd-1.8.6/.github/workflows/create_containers.yml
new file mode 100644
index 0000000000000000000000000000000000000000..79b9eb2a89fb97f2d2ae5341acce5222e8634dec
--- /dev/null
+++ b/fwupd-1.8.6/.github/workflows/create_containers.yml
@@ -0,0 +1,41 @@
+name: Create containers
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: '0 0 * * *'
+
+permissions:
+ contents: read
+
+jobs:
+ push_to_registry:
+ permissions:
+ packages: write # for docker/build-push-action
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [fedora, debian-x86_64, arch, debian-i386, void]
+
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v3
+ - name: "Generate Dockerfile"
+ env:
+ OS: ${{ matrix.os }}
+ run: ./contrib/ci/generate_docker.py
+ -
+ name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Push to GitHub Packages
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ push: true
+ tags: ghcr.io/fwupd/fwupd/fwupd-${{matrix.os}}:latest
diff --git a/fwupd-1.8.6/.github/workflows/main.yml b/fwupd-1.8.6/.github/workflows/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..012568a992908bc1041223ef9d59c77f66fa19ca
--- /dev/null
+++ b/fwupd-1.8.6/.github/workflows/main.yml
@@ -0,0 +1,114 @@
+name: Continuous Integration
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+permissions:
+ contents: read # to fetch code (actions/checkout)
+
+jobs:
+ pre-commit:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - name: Refresh dependencies
+ run: sudo apt update
+ - name: Install dependencies
+ run: sudo apt install shellcheck clang-format -y
+ - name: Run pre-commit hooks
+ run: |
+ ./contrib/setup
+ source venv/bin/activate
+ sed -i "/no-commit-to-branch/,+1d" .pre-commit-config.yaml
+ pre-commit run --hook-stage commit --all-files
+ abi:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - name: Refresh dependencies
+ run: sudo apt update
+ - name: Install dependencies
+ run: |
+ sudo ./contrib/ci/fwupd_setup_helpers.py install-dependencies -o ubuntu --yes
+ python3 -m pip install --user "meson >= 0.60.0"
+ - name: Check ABI
+ run: ./contrib/ci/check-abi $(git describe --abbrev=0 --tags) $(git rev-parse HEAD)
+
+ openbmc:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v3
+ - name: Refresh dependencies
+ run: sudo apt update
+ - name: Install dependencies
+ run: |
+ sudo ./contrib/ci/fwupd_setup_helpers.py install-dependencies -o ubuntu --yes
+ python3 -m pip install --user "meson >= 0.60.0"
+ - name: Build
+ run: |
+ ./contrib/build-openbmc.sh
+ ninja -C ..
+
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ os: [fedora, debian-x86_64, arch, debian-i386]
+ steps:
+ - uses: actions/checkout@v3
+ - name: Docker login
+ run: docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $GITHUB_TOKEN
+ env:
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
+ - name: Build in container
+ env:
+ CI_NETWORK: true
+ CI: true
+ run: |
+ echo $GITHUB_WORKSPACE
+ docker run --privileged -e CI=true -t -v $GITHUB_WORKSPACE:/github/workspace docker.pkg.github.com/fwupd/fwupd/fwupd-${{matrix.os}}:latest
+
+ macos:
+ runs-on: macos-12
+ steps:
+ - name: install dependencies
+ run: brew install meson gcab libusb gobject-introspection sqlite libarchive json-glib curl gnutls protobuf-c vala
+ - uses: actions/checkout@v3
+ - name: configure
+ run: ./contrib/ci/build_macos.sh
+ - name: build
+ run: ninja -C build-macos
+
+ fuzzing:
+ permissions:
+ actions: read # to fetch the artifacts (google/oss-fuzz/infra/cifuzz/actions/run_fuzzers)
+ contents: read # to clone the repo (google/oss-fuzz/infra/cifuzz/actions/run_fuzzers)
+
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ steps:
+ - name: Build Fuzzers
+ id: build
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'fwupd'
+ dry-run: false
+ - name: Run Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'fwupd'
+ fuzz-seconds: 150
+ dry-run: false
+ - name: Upload Crash
+ uses: actions/upload-artifact@v3
+ if: failure() && steps.build.outcome == 'success'
+ with:
+ name: artifacts
+ path: ./out/artifacts
+
diff --git a/fwupd-1.8.6/.gitignore b/fwupd-1.8.6/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3858bb7b8e00d18bf1c953706bcf33c022b8ad01
--- /dev/null
+++ b/fwupd-1.8.6/.gitignore
@@ -0,0 +1,38 @@
+/build
+/build-win32
+/dist
+/.vscode
+.vscode-ctags
+/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
+/venv
+__pycache__
+plugins/acpi-dmar/tests/
+plugins/acpi-facp/tests/
+plugins/ata/tests/
+plugins/dfu/tests/
+plugins/nvme/tests/
+plugins/synaptics-mst/tests/
+plugins/synaptics-prometheus/tests/
+plugins/tpm-eventlog/tests/
+plugins/uefi-dbx/tests/
+.buildconfig
+.ossfuzz
+*.rej
diff --git a/fwupd-1.8.6/.gitmodules b/fwupd-1.8.6/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..70f1092f0475c68d744b9ccf9a3ae6b47946e892
--- /dev/null
+++ b/fwupd-1.8.6/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "contrib/flatpak"]
+ path = contrib/flatpak
+ url = https://github.com/flathub/org.freedesktop.fwupd
diff --git a/fwupd-1.8.6/.markdownlint.json b/fwupd-1.8.6/.markdownlint.json
new file mode 100644
index 0000000000000000000000000000000000000000..41b3c04fdf283a2abac1e14a82cc77a2d5508b94
--- /dev/null
+++ b/fwupd-1.8.6/.markdownlint.json
@@ -0,0 +1,8 @@
+{
+ "default": true,
+ "MD033": false,
+ "MD013": {
+ "tables": false,
+ "line_length": 1000
+ }
+}
diff --git a/fwupd-1.8.6/.pre-commit-config.yaml b/fwupd-1.8.6/.pre-commit-config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c762a87789f57bc41d87fafa93a301fc1fff8481
--- /dev/null
+++ b/fwupd-1.8.6/.pre-commit-config.yaml
@@ -0,0 +1,84 @@
+default_stages: [commit]
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.0.1
+ hooks:
+ - id: no-commit-to-branch
+ args: [--branch, main, --pattern, 1_.*_X]
+ - id: check-added-large-files
+ - id: check-byte-order-marker
+ - id: check-executables-have-shebangs
+ - id: forbid-new-submodules
+ - id: check-yaml
+ exclude: '.clang-format'
+ - id: check-json
+ - id: check-symlinks
+ - id: check-xml
+ - id: end-of-file-fixer
+ types_or: [c, shell, python, proto]
+ - id: trailing-whitespace
+ types_or: [c, shell, python, xml]
+ - id: check-docstring-first
+ - id: check-merge-conflict
+ - id: mixed-line-ending
+ args: [--fix=lf]
+- repo: https://github.com/codespell-project/codespell
+ rev: v2.1.0
+ hooks:
+ - id: codespell
+ args: ['--config', './contrib/codespell.cfg', --write-changes]
+- repo: https://github.com/ambv/black
+ rev: 22.3.0
+ hooks:
+ - id: black
+- repo: local
+ hooks:
+ - id: check-deprecated
+ name: check for use of any deprecated items
+ language: script
+ entry: ./contrib/ci/check-deprecated.sh
+ - id: check-null-false-returns
+ name: check for null / false return mistmatch
+ language: script
+ entry: ./contrib/ci/check-null-false-returns.py
+ - id: check-potfiles
+ name: check for missing translated files from potfiles
+ language: script
+ entry: ./contrib/ci/check-potfiles.py
+ - id: check-finalizers
+ name: check for missing GObject parent finalize
+ language: script
+ entry: ./contrib/ci/check-finalizers.py
+ - id: check-headers
+ name: check for superfluous includes
+ language: script
+ entry: ./contrib/ci/check-headers.py
+ - id: check-quirks
+ name: check quirk style
+ language: script
+ entry: ./contrib/ci/check-quirks.py
+ - id: shellcheck
+ name: check shellscript style
+ language: system
+ entry: shellcheck --severity=warning -e SC2068
+ types: [shell]
+ - id: run-tests
+ name: run tests before pushing
+ language: script
+ entry: ./contrib/run-tests.sh
+ stages: [push]
+ - id: clang-format
+ name: clang-format
+ language: script
+ entry: ./contrib/reformat-code.py
+ types: [c]
+ - id: check-license
+ name: Check license header
+ types_or: [shell, c, python]
+ language: script
+ entry: ./contrib/ci/check-license.py
+- repo: https://github.com/igorshubovych/markdownlint-cli
+ rev: v0.27.1
+ hooks:
+ - id: markdownlint
+ args: ['--fix', '--ignore', '.github']
diff --git a/fwupd-1.8.6/.tx/config b/fwupd-1.8.6/.tx/config
new file mode 100644
index 0000000000000000000000000000000000000000..ff5e554ac6ab4398d3d50a626ba57b9610c90147
--- /dev/null
+++ b/fwupd-1.8.6/.tx/config
@@ -0,0 +1,8 @@
+[main]
+host = https://www.transifex.com
+
+[fwupd.main]
+file_filter = po/.po
+source_file = po/fwupd.pot
+source_lang = en
+type = PO
diff --git a/fwupd-1.8.6/AUTHORS b/fwupd-1.8.6/AUTHORS
new file mode 100644
index 0000000000000000000000000000000000000000..026b70589356aa8296495aca48d60565804b001f
--- /dev/null
+++ b/fwupd-1.8.6/AUTHORS
@@ -0,0 +1 @@
+Richard Hughes
diff --git a/fwupd-1.8.6/CODE_OF_CONDUCT.md b/fwupd-1.8.6/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000000000000000000000000000000000..0bc4fc038c77b646c4971e55d7dd5eea3d6b2f34
--- /dev/null
+++ b/fwupd-1.8.6/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fwupd@googlegroups.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/fwupd-1.8.6/COMMITMENT b/fwupd-1.8.6/COMMITMENT
new file mode 100644
index 0000000000000000000000000000000000000000..bfa237f419b4dfa0c6c9c0f0979779feefa2bc52
--- /dev/null
+++ b/fwupd-1.8.6/COMMITMENT
@@ -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 --git a/fwupd-1.8.6/CONTRIBUTING.md b/fwupd-1.8.6/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..48cd2355419f2946e5bb946d7e790b34d2d4899a
--- /dev/null
+++ b/fwupd-1.8.6/CONTRIBUTING.md
@@ -0,0 +1,62 @@
+# Contributor Guidelines
+
+## Getting started
+
+To set up your local environment, from the top level of the checkout run
+
+```shell
+./contrib/setup
+```
+
+This will create pre-commit hooks to fixup many code style issues before your
+code is submitted.
+
+On some Linux distributions this will install all build dependencies needed
+to compile fwupd as well.
+
+## Coding Style
+
+The coding style to respect in this project is very similar to most
+GLib projects. In particular, the following rules are largely adapted
+from the PackageKit Coding Style.
+
+* 8-space tabs for indentation
+
+* Prefer lines of less than <= 100 columns
+
+* No spaces between function name and braces (both calls and macro
+ declarations)
+
+* If function signature/call fits in a single line, do not break it
+ into multiple lines
+
+* Prefer descriptive names over abbreviations (unless well-known)
+ and shortening of names. e.g `device` not `dev`
+
+* 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:
+
+ // Fetch the document
+ fetch_the_document();
+
+* Comments should not start with a capital letter or end with a full stop and
+ should be C-style, not C++-style, e.g. `/* this */` not `// this`
+
+* Each object should go in a separate .c file and be named according
+ to the class
+
+* Use g_autoptr() and g_autofree whenever possible, and avoid `goto out`
+ error handling
+
+* Failing methods should return FALSE with a suitable `GError` set
+
+* Trailing whitespace is forbidden
+
+* Pointers should be checked for NULL explicitly, e.g. `foo != NULL` not `!foo`
+
+`./contrib/reformat-code.py` can be used in order to get automated
+formatting. Calling the script without arguments formats the current
+patch while passing commits will do formatting on everything changed since that
+commit.
diff --git a/fwupd-1.8.6/COPYING b/fwupd-1.8.6/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..4362b49151d7b34ef83b3067a8f9c9f877d72a0e
--- /dev/null
+++ b/fwupd-1.8.6/COPYING
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ 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
+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
+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. 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 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
+covered by this License; they are outside its scope. The act of
+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) 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.
+
+ 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 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 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.
+
+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 Library.
+
+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 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.
+
+ 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.
+
+ 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+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 Library or works based on it.
+
+ 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 with
+this License.
+
+ 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 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 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.
+
+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
+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
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 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 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
+
+ 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
+
+ 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 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+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
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/fwupd-1.8.6/MAINTAINERS b/fwupd-1.8.6/MAINTAINERS
new file mode 100644
index 0000000000000000000000000000000000000000..0634d575e015e6fce25e90e3b28b7a8293f29728
--- /dev/null
+++ b/fwupd-1.8.6/MAINTAINERS
@@ -0,0 +1,2 @@
+Richard Hughes
+Mario Limonciello
diff --git a/fwupd-1.8.6/README.md b/fwupd-1.8.6/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..74aaa367d425c073ce651a0221f2de5dbd22ccb0
--- /dev/null
+++ b/fwupd-1.8.6/README.md
@@ -0,0 +1,195 @@
+# fwupd
+
+[](https://github.com/fwupd/fwupd/actions/workflows/main.yml)
+[](https://github.com/fwupd/fwupd/actions/workflows/codeql-analysis.yml)
+[](https://scan.coverity.com/projects/10744)
+[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fwupd)
+[](https://circleci.com/gh/fwupd/fwupd/tree/main)
+
+This project aims to make updating firmware on Linux automatic, safe and reliable.
+
+Additional information is available [at the website](https://fwupd.org/).
+
+## Where to get help?
+
+- GitHub issues & discussions in [this repository](https://github.com/fwupd/fwupd)
+- Libera IRC channel `#fwupd`.
+ You can join through Libera's [IRC](https://libera.chat/)
+ or via the IRC bridge on [Matrix](https://matrix.to/#/#fwupd:libera.chat).
+
+## Compiling
+
+The most up to date compilation instructions are available in the [Wiki](https://github.com/fwupd/fwupd/wiki/Compilation).
+
+**NOTE:** In most cases end users should never compile fwupd from scratch; it's a
+complicated project with dozens of dependencies (and as many configuration options)
+and there's just too many things that can go wrong.
+
+Users should just have fwupd installed and updated by their distro, managed and
+tested by the package maintainer.
+The distribution will have also done some testing with how fwupd interacts with
+other software on your system, for instance using GNOME Software.
+
+Installing fwupd using [Snap](https://github.com/fwupd/fwupd/wiki/fwupd-snap)
+or using [Flatpak](https://github.com/fwupd/fwupd/wiki/fwupd-flatpak) might be
+useful to update a specific device on the command line that needs a bleeding
+edge fwupd version, but it should not be considered as a replacement to the
+distro-provided system version.
+
+## LVFS
+
+This project is configured by default to download firmware from the [Linux Vendor
+Firmware Service (LVFS)](https://fwupd.org/).
+
+This service is available to all OEMs and firmware creators who would like to make
+their firmware available to Linux users.
+
+You can find more information about the technical details of creating a firmware
+capsule in the hardware vendors section of the [fwupd website](https://fwupd.org).
+
+## Basic usage flow (command line)
+
+If you have a device with firmware supported by fwupd, this is how you will check
+for updates and apply them using fwupd's command line tools.
+
+`# fwupdmgr get-devices`
+
+This will display all devices detected by fwupd.
+
+`# fwupdmgr refresh`
+
+This will download the latest metadata from LVFS.
+
+`# fwupdmgr get-updates`
+
+If updates are available for any devices on the system, they'll be displayed.
+
+`# fwupdmgr update`
+
+This will download and apply all updates for your system.
+
+- Updates that can be applied live will be done immediately.
+- Updates that run at bootup will be staged for the next reboot.
+
+You can find more information about the update workflow in the end
+users section of the [fwupd website](https://fwupd.org).
+
+## Reporting status
+
+fwupd will encourage users to report both successful and failed updates back
+to LVFS. This is an optional feature, but encouraged as it provides valuable
+feedback to LVFS administrators and OEM developers regarding firmware update
+process efficacy.
+
+The privacy policy regarding this data can be viewed on the [fwupd website](https://fwupd.org/privacy).
+
+To report the status of an update run:
+
+`# fwupdmgr report-history`
+
+ 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 organization.
+
+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.
+
+## Local metadata
+
+Local metadata can be saved in `/var/lib/fwupd/local.d` or `/usr/share/fwupd/local.d`
+which are scanned at daemon startup. This can be used to add site-specific BKC
+tags to existing metadata stores. For instance:
+
+
+
+
+
+ 3ef35d3b-ceeb-5e27-8c0a-ac25f90367ab
+ 2ef35d3b-ceeb-5e27-8c0a-ac25f90367ac
+ 1ef35d3b-ceeb-5e27-8c0a-ac25f90367ad
+
+
+
+
+
+
+ mycompanyname-2022q1
+
+
+
+
+This then appears when getting the releases for that specific GUID:
+
+ fwupdmgr get-releases --json 3ef35d3b-ceeb-5e27-8c0a-ac25f90367ab
+ {
+ "Releases" : [
+ {
+ ...
+ "Version" : "225.53.1649",
+ "Tags" : [
+ "mycompanyname-2022q1"
+ ],
+ ...
+ },
+ {
+ ...
+ "Version" : "224.48.1605",
+ "Tags" : [
+ "mycompanyname-2022q1"
+ ],
+ ...
+ },
+ {
+ ...
+ "Version" : "224.45.1389",
+ ...
+ }
+ ]
+ }
+
+## Other frontends
+
+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 center,
+ 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.
+
+## Fuzzing
+
+There are several automated fuzzing tests in fwupd. These take some time to run:
+
+ CC=hfuzz-clang meson --default-library=static \
+ -Dudevdir=/tmp -Dsystemd_root_prefix=/tmp \
+ -Dplugin_redfish=disabled -Dcurl=disabled \
+ -Dintrospection=false ../
+ ninja install
+ ninja fuzz-firmware
+ ninja fuzz-tpm-eventlog
diff --git a/fwupd-1.8.6/RELEASE b/fwupd-1.8.6/RELEASE
new file mode 100644
index 0000000000000000000000000000000000000000..633706746fd2365ba94b1065d9629ba179299341
--- /dev/null
+++ b/fwupd-1.8.6/RELEASE
@@ -0,0 +1,64 @@
+fwupd Release Notes
+
+Forking stable branch:
+
+When forking main into a stable 1_7_X, be sure to disable the following CI jobs:
+ * publish-docs
+ * publish-stable
+
+To make sure it's done right, you can reference commit 433e809318c68c9ab6d4ae50ee9c4312503185d8
+
+Write release entries:
+
+git log --format="%s" --cherry-pick --right-only 1.8.5... | 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 --force --minimum-perc=5
+ninja-build fix-translations
+git add ../po/*.po
+
+2. Commit changes to git:
+
+# MAKE SURE THIS IS CORRECT
+export release_ver="1.8.6"
+
+git commit -a -m "Release fwupd ${release_ver}" --no-verify
+git tag -s -f -m "Release fwupd ${release_ver}" "${release_ver}"
+
+git push --tags
+git push
+
+3. Generate the tarball:
+
+ninja dist
+
+3a. Generate the additional verification metadata
+
+gpg -b -a meson-dist/fwupd-${release_ver}.tar.xz
+
+4. Upload tarball:
+
+scp meson-dist/fwupd-${release_ver}.tar.* hughsient@people.freedesktop.org:~/public_html/releases
+
+5. Do post release version bump in meson.build
+
+6. Commit changes:
+
+git commit -a -m "trivial: post release version bump" --no-verify
+git push
+
+7. Update flatpak package for new release:
+
+https://github.com/flathub/org.freedesktop.fwupd
+
+8. Promote snap package from edge to stable:
+
+https://snapcraft.io/fwupd/releases
+or
+
+snapcraft promote fwupd --from-channel edge --to-channel stable
diff --git a/fwupd-1.8.6/SECURITY.md b/fwupd-1.8.6/SECURITY.md
new file mode 100644
index 0000000000000000000000000000000000000000..16095665462e49311589f597817f2acce9a63cd1
--- /dev/null
+++ b/fwupd-1.8.6/SECURITY.md
@@ -0,0 +1,40 @@
+# 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 `main`, and `1.7.x`, branches are fully supported by the upstream authors.
+Additionally, the `1.5.x` and `1.6.x` branches are supported for security fixes.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 1.8.x | :heavy_check_mark: |
+| 1.7.x | :heavy_check_mark: |
+| 1.6.x | :white_check_mark: |
+| 1.5.x | :white_check_mark: |
+| 1.4.x | :x: |
+| 1.3.x | :x: |
+| 1.2.x | :x: |
+| 1.1.x | :x: |
+| 1.0.x | :x: |
+| 0.9.x | :x: |
+| 0.8.x | :x: |
+
+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.
+
+## 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 bounty program, but we're happy to credit you in updates
+if this is what you would like us to do.
diff --git a/fwupd-1.8.6/contrib/PKGBUILD b/fwupd-1.8.6/contrib/PKGBUILD
new file mode 100644
index 0000000000000000000000000000000000000000..8577f43b7c6db073c0edc4e1a814b350835e6560
--- /dev/null
+++ b/fwupd-1.8.6/contrib/PKGBUILD
@@ -0,0 +1,46 @@
+# Maintainer: Bruno Pagani (a.k.a. ArchangeGabriel)
+# Contributor: Mirco Tischler
+
+pkgname=fwupd
+pkgver=dummy
+pkgrel=1
+pkgdesc='A system daemon to allow session software to update firmware'
+arch=('i686' 'x86_64')
+url='https://github.com/fwupd/fwupd'
+license=('GPL2')
+depends=('libgusb' 'modemmanager' 'tpm2-tss')
+makedepends=('meson' 'valgrind' 'gobject-introspection' 'gi-docgen' 'git'
+ 'python-cairo' 'noto-fonts' 'noto-fonts-cjk' 'python-gobject' 'vala'
+ 'curl' 'polkit' 'gcab' 'xz')
+
+pkgver() {
+ cd ${pkgname}
+
+ VERSION=$(git describe | sed 's/-/.r/;s/-/./')
+ [ -z $VERSION ] && VERSION=$(head meson.build | grep ' version:' | cut -d \' -f2)
+
+ echo $VERSION
+}
+
+build() {
+ cd ${pkgname}
+ if [ -n "$CI" ]; then
+ export CI="--wrap-mode=default"
+ fi
+ arch-meson -D b_lto=false $CI ../build \
+ -Dplugin_intel_spi=true \
+ -Dplugin_powerd=disabled \
+ -Ddocs=enabled \
+ -Defi_binary=false \
+ -Dsupported_build=enabled
+
+ ninja -v -C ../build
+}
+
+check() {
+ CACHE_DIRECTORY=/tmp ninja -C build test
+}
+
+package() {
+ DESTDIR="${pkgdir}" ninja -C build install
+}
diff --git a/fwupd-1.8.6/contrib/README.md b/fwupd-1.8.6/contrib/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c1f1e26a299082ec7dfc9df8bd93442e042e456b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/README.md
@@ -0,0 +1,89 @@
+# Distribution packages
+
+The relevant packaging necessary to generate *RPM*, *DEB* and *PKG* distribution packages is contained here.
+It is used regularly for continuous integration using [Travis CI](http://travis-ci.org). The generated packages can be used on a distribution such as Fedora, Debian, Ubuntu or Arch Linux.
+
+The build can be performed using Linux containers with [Docker](https://www.docker.com).
+
+## RPM packages
+
+A Dockerfile for Fedora can be generated in `contrib`.
+
+To prepare the Docker container run this command:
+
+```shell
+OS=fedora ./generate_docker.py build
+```
+
+To build the RPMs run this command (from the root of your git checkout):
+
+```shell
+docker run --privileged -t -v `pwd`:/github/workspace fwupd-fedora
+```
+
+RPMs will be made available in your working directory when complete.
+
+To build additional RPM packages for Qubes OS (fwupd-qubes-dom0 and
+fwupd-qubes-vm) add `QUBES=true` environment variable:
+
+```shell
+docker run --privileged -e QUBES=true -t -v `pwd`:/github/workspace fwupd-fedora
+```
+
+## DEB packages
+
+A Dockerfile for Debian or Ubuntu can be generated in `contrib`.
+
+To prepare the Docker container run one of these commands:
+
+```shell
+OS=debian-x86_64 ./generate_docker.py build
+OS=debian-i386 ./generate_docker.py build
+OS=ubuntu-x86_64 ./generate_docker.py build
+```
+
+To build the DEBs run one of these commands (from the root of your git checkout):
+
+```shell
+docker run --privileged -t -v `pwd`:/github/workspace fwupd-debian-x86_64
+docker run --privileged -t -v `pwd`:/github/workspace fwupd-debian-i386
+docker run --privileged -t -v `pwd`:/github/workspace fwupd-ubuntu-x86_64
+```
+
+DEBs will be made available in your working directory when complete.
+
+To build additional DEB package for Qubes OS (fwupd-qubes-vm-whonix)
+add `QUBES=true` environment variable:
+
+```shell
+docker run --privileged -t -v `pwd`:/github/workspace fwupd-debian-x86_64-qubes
+```
+
+## PKG packages
+
+A Dockerfile for Arch can be generated in `contrib`.
+
+To prepare the Docker container run this command:
+
+```shell
+OS=arch ./generate_docker.py
+```
+
+To build the PKGs run this command (from the root of your git checkout):
+
+```shell
+docker run -t -v `pwd`:/build fwupd-arch
+```
+
+PKGs will be made available in your working directory when complete.
+
+## Additional packages
+
+Submissions for generating additional packages for other distribution mechanisms are also welcome.
+All builds should occur in Docker containers.
+
+Please feel free to submit the following:
+
+* Dockerfile for the container for your distro
+* Relevant technical packaging scripts (such as ebuilds, spec file etc)
+* A shell script that can be launched in the container to generate distribution packages
diff --git a/fwupd-1.8.6/contrib/build-openbmc.sh b/fwupd-1.8.6/contrib/build-openbmc.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4427ebd09af9efa8f045e34dd6e279489bd970ab
--- /dev/null
+++ b/fwupd-1.8.6/contrib/build-openbmc.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+meson ../ \
+ -Dauto_features=disabled \
+ -Dbash_completion=false \
+ -Dcompat_cli=false \
+ -Dfish_completion=false \
+ -Dfirmware-packager=false \
+ -Dhsi=disabled \
+ -Dman=false \
+ -Dmetainfo=false \
+ -Dtests=false \
+ -Dudevdir=/tmp \
+ -Dsystemd_root_prefix=/tmp \
+ $@
diff --git a/fwupd-1.8.6/contrib/build-windows.sh b/fwupd-1.8.6/contrib/build-windows.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c60a8024e36a0d1b8c6eb9e8404f04e882c3361a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/build-windows.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+set -e
+
+root=$(pwd)
+export DESTDIR=${root}/dist
+build=$root/build-win32
+mkdir -p "$build" && cd "$build"
+
+# install deps
+if [ ! -f /usr/share/mingw/toolchain-mingw64.meson ]; then
+ ./contrib/ci/fwupd_setup_helpers.py -v mingw64 install-dependencies
+fi
+
+# try to keep this and ../contrib/ci/build_windows.sh in sync as much as makes sense
+meson .. \
+ --cross-file=/usr/share/mingw/toolchain-mingw64.meson \
+ --cross-file=../contrib/mingw64.cross \
+ --prefix=/ \
+ --sysconfdir="etc" \
+ --libexecdir="bin" \
+ --bindir="bin" \
+ -Dbuild=all \
+ -Dman=false \
+ -Dfish_completion=false \
+ -Dbash_completion=false \
+ -Dfirmware-packager=false \
+ -Dmetainfo=false \
+ -Dcompat_cli=false \
+ -Dsoup_session_compat=false \
+ -Dgcab:introspection=false \
+ -Dgcab:docs=false \
+ -Dgcab:nls=false \
+ -Dgcab:vapi=false \
+ -Dgcab:tests=false \
+ -Dlibxmlb:introspection=false \
+ -Dlibxmlb:gtkdoc=false \
+ -Dlibjcat:man=false \
+ -Dlibjcat:gpg=false \
+ -Dlibjcat:tests=false \
+ -Dlibjcat:introspection=false \
+ -Dgusb:tests=false \
+ -Dgusb:docs=false \
+ -Dgusb:introspection=false \
+ -Dgusb:vapi=false
+
+# run tests
+export WINEPATH="/usr/x86_64-w64-mingw32/sys-root/mingw/bin/;$build/libfwupd/;$build/libfwupdplugin/;$build/subprojects/libxmlb/src/;$build/subprojects/gcab/libgcab/;$build/subprojects/libjcat/libjcat/;$build/subprojects/gusb/gusb/"
+ninja -C "$build" install
+ninja -C "$build" test
+
+MINGW32BINDIR=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
+
+#disable motd for Windows
+sed -i 's,UpdateMotd=.*,UpdateMotd=false,' "$DESTDIR/etc/fwupd/daemon.conf"
+
+# copy deps
+cp -f -v \
+ $MINGW32BINDIR/gspawn-win64-helper-console.exe \
+ $MINGW32BINDIR/gspawn-win64-helper.exe \
+ $MINGW32BINDIR/iconv.dll \
+ $MINGW32BINDIR/libarchive-13.dll \
+ $MINGW32BINDIR/libbrotlicommon.dll \
+ $MINGW32BINDIR/libbrotlidec.dll \
+ $MINGW32BINDIR/libbz2-1.dll \
+ $MINGW32BINDIR/libcrypto-1_1-x64.dll \
+ $MINGW32BINDIR/libcurl-4.dll \
+ $MINGW32BINDIR/libffi-*.dll \
+ $MINGW32BINDIR/libgcc_s_seh-1.dll \
+ $MINGW32BINDIR/libgio-2.0-0.dll \
+ $MINGW32BINDIR/libglib-2.0-0.dll \
+ $MINGW32BINDIR/libgmodule-2.0-0.dll \
+ $MINGW32BINDIR/libgmp-10.dll \
+ $MINGW32BINDIR/libgnutls-30.dll \
+ $MINGW32BINDIR/libgobject-2.0-0.dll \
+ $MINGW32BINDIR/libgusb-2.dll \
+ $MINGW32BINDIR/libhogweed-*.dll \
+ $MINGW32BINDIR/libidn2-0.dll \
+ $MINGW32BINDIR/libintl-8.dll \
+ $MINGW32BINDIR/libjson-glib-1.0-0.dll \
+ $MINGW32BINDIR/liblzma-5.dll \
+ $MINGW32BINDIR/libnettle-*.dll \
+ $MINGW32BINDIR/libp11-kit-0.dll \
+ $MINGW32BINDIR/libpcre-1.dll \
+ $MINGW32BINDIR/libsqlite3-0.dll \
+ $MINGW32BINDIR/libssh2-1.dll \
+ $MINGW32BINDIR/libssl-1_1-x64.dll \
+ $MINGW32BINDIR/libssp-0.dll \
+ $MINGW32BINDIR/libtasn1-6.dll \
+ $MINGW32BINDIR/libusb-1.0.dll \
+ $MINGW32BINDIR/libwinpthread-1.dll \
+ $MINGW32BINDIR/libxml2-2.dll \
+ $MINGW32BINDIR/zlib1.dll \
+ "$DESTDIR/bin/"
diff --git a/fwupd-1.8.6/contrib/ci/Dockerfile-arch.in b/fwupd-1.8.6/contrib/ci/Dockerfile-arch.in
new file mode 100644
index 0000000000000000000000000000000000000000..e30765d2a85b1863148f66f5e35cd3f14b957785
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/Dockerfile-arch.in
@@ -0,0 +1,13 @@
+FROM archlinux:latest
+%%%OS%%%
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+ENV CI_NETWORK true
+RUN echo fubar > /etc/machine-id
+RUN sed "s,#en_US.UTF-8,en_US.UTF-8," /etc/locale.gen -i
+RUN echo "LANG=en_US.UTF-8" > /etc/locale.conf
+RUN locale-gen
+RUN pacman -Syu --noconfirm archlinux-keyring
+%%%INSTALL_DEPENDENCIES_COMMAND%%%
+WORKDIR /github/workspace
+CMD ["./contrib/ci/arch.sh"]
diff --git a/fwupd-1.8.6/contrib/ci/Dockerfile-debian.in b/fwupd-1.8.6/contrib/ci/Dockerfile-debian.in
new file mode 100644
index 0000000000000000000000000000000000000000..82e4c189862cbba7471051f353a7c7111f92d565
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/Dockerfile-debian.in
@@ -0,0 +1,9 @@
+FROM %%%ARCH_PREFIX%%%debian:testing
+%%%OS%%%
+ENV CI_NETWORK true
+RUN echo fubar > /etc/machine-id
+%%%ARCH_SPECIFIC_COMMAND%%%
+%%%INSTALL_DEPENDENCIES_COMMAND%%%
+RUN apt install -yq --no-install-recommends python3-apt
+WORKDIR /github/workspace
+CMD ["./contrib/ci/debian.sh"]
diff --git a/fwupd-1.8.6/contrib/ci/Dockerfile-fedora.in b/fwupd-1.8.6/contrib/ci/Dockerfile-fedora.in
new file mode 100644
index 0000000000000000000000000000000000000000..6b1b9742960d89a939d2fc8711b7ae12160d6e87
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/Dockerfile-fedora.in
@@ -0,0 +1,11 @@
+FROM fedora:36
+%%%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 -y update
+RUN echo fubar > /etc/machine-id
+%%%INSTALL_DEPENDENCIES_COMMAND%%%
+WORKDIR /github/workspace
+CMD ["./contrib/ci/fedora.sh"]
diff --git a/fwupd-1.8.6/contrib/ci/Dockerfile-snap.in b/fwupd-1.8.6/contrib/ci/Dockerfile-snap.in
new file mode 100644
index 0000000000000000000000000000000000000000..a440cf6b23173017a2fedac5f05dca0edc79e272
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/Dockerfile-snap.in
@@ -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 --git a/fwupd-1.8.6/contrib/ci/Dockerfile-ubuntu.in b/fwupd-1.8.6/contrib/ci/Dockerfile-ubuntu.in
new file mode 100644
index 0000000000000000000000000000000000000000..826be84b970a51181da8c5f1621103ef6f0bafad
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/Dockerfile-ubuntu.in
@@ -0,0 +1,10 @@
+FROM ubuntu:rolling
+%%%OS%%%
+ENV CI_NETWORK true
+ENV CC clang
+ENV DEBIAN_FRONTEND noninteractive
+RUN echo fubar > /etc/machine-id
+%%%ARCH_SPECIFIC_COMMAND%%%
+RUN apt update -qq && apt install -yq --no-install-recommends python3-apt
+WORKDIR /github/workspace
+CMD ["./contrib/ci/ubuntu.sh"]
diff --git a/fwupd-1.8.6/contrib/ci/Dockerfile-void.in b/fwupd-1.8.6/contrib/ci/Dockerfile-void.in
new file mode 100644
index 0000000000000000000000000000000000000000..bb6ece3e29a58eb40dc35393f770759709a6a940
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/Dockerfile-void.in
@@ -0,0 +1,9 @@
+FROM ghcr.io/void-linux/void-linux:latest-full-x86_64-musl
+%%%OS%%%
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+ENV CI_NETWORK true
+RUN echo fubar > /etc/machine-id
+%%%INSTALL_DEPENDENCIES_COMMAND%%%
+WORKDIR /github/workspace
+CMD ["./contrib/ci/void.sh"]
diff --git a/fwupd-1.8.6/contrib/ci/README.md b/fwupd-1.8.6/contrib/ci/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f0a9e891a58e3f45948bfb83a2daba5134fa1012
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/README.md
@@ -0,0 +1,106 @@
+# Continuous Integration
+
+By using CI, builds are exercised across a variety of environments attempting to maximize code coverage.
+For every commit or pull request 6 builds are performed:
+
+## Fedora (x86_64)
+
+* A fully packaged RPM build with all plugins enabled
+* 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)
+
+* A fully packaged DEB build with all plugins enabled
+* Compiled under gcc
+* 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.
+* All packages are removed
+
+## Debian testing (i386)
+
+* A fully packaged DEB build with all plugins enabled
+* Compiled under gcc
+* 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.
+* All packages are removed
+
+## Ubuntu devel release (x86_64)
+
+* A fully packaged DEB build with all plugins enabled
+* Compiled under clang
+* Tests without -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.
+* All packages are removed
+
+## Debian testing (cross compile s390x)
+
+* 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)
+
+* A fully packaged pkg build with all plugins enabled
+* Compiled under gcc
+* Tests with -Werror enabled
+* Compile with the deprecated USB plugin enabled
+* 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```.
+The python script will recognize the environment variable `OS` to determine what target to generate a Dockerfile for.
+
+### dependencies.xml
+
+Initially the python script will read in `dependencies.xml` to generate a dependency list for that target.
+The XML is organized by a top level element representing the dependencies needed for building fwupd.
+
+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 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.
+
+Each distribution will have `package` elements and `control` elements.
+`Package` elements represent the name of the package needed for the distribution.
+
+* An optional attribute `variant` represents one deviation of that distribution. For example building a specific architecture or with a different compiler.
+* If the `package` element is empty the `id` of the `dependency` element will be used.
+* `Control` elements represent specific requirements associated to a dependency. They will contain elements with individual details.
+* `version` elements represent a minimum version to be installed
+* `inclusive` elements represent an inclusive list of architectures to be installed on
+* `exclusive` elements represent an exclusive list of architectures to not be installed on
+
+For convenience there is also a helper script `./contrib/ci/fwupd_setup_helpers.p install-dependencies` that parses `dependencies.xml`.
+
+### Dockerfile.in
+
+The `Dockerfile.in` file will be used as a template to build the container. No hardcoded dependencies should be put in this file. They should be stored in `dependencies.xml`.
diff --git a/fwupd-1.8.6/contrib/ci/abidiff.suppr b/fwupd-1.8.6/contrib/ci/abidiff.suppr
new file mode 100644
index 0000000000000000000000000000000000000000..114636b5baa5ae95b7d332176c3a887dce59ef8d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/abidiff.suppr
@@ -0,0 +1,3 @@
+[suppress_type]
+ type_kind = enum
+ changed_enumerators = FWUPD_ERROR_LAST,FWUPD_GUID_FLAG_LAST,FWUPD_INSTALL_FLAG_LAST,FWUPD_KEYRING_KIND_LAST,FWUPD_REMOTE_KIND_LAST,FWUPD_SELF_SIGN_FLAG_LAST,FWUPD_STATUS_LAST,FWUPD_TRUST_FLAG_LAST,FWUPD_UPDATE_STATE_LAST,FWUPD_VERSION_FORMAT_LAST,FWUPD_CLIENT_DOWNLOAD_FLAG_LAST,FWUPD_FEATURE_FLAG_LAST
diff --git a/fwupd-1.8.6/contrib/ci/arch.sh b/fwupd-1.8.6/contrib/ci/arch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..3392918bb54cbd4c58663f98780bf63cc8d818fb
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/arch.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+set -e
+set -x
+shopt -s extglob
+
+#clone test firmware if necessary
+. ./contrib/ci/get_test_firmware.sh
+
+#refresh package cache and update image
+pacman -Syu --noconfirm
+
+#install anything missing from the container
+./contrib/ci/fwupd_setup_helpers.py install-dependencies -o arch
+
+# prepare the build tree
+rm -rf build
+mkdir build && pushd build
+cp ../contrib/PKGBUILD .
+mkdir -p src/fwupd && pushd src/fwupd
+cp -R ../../../!(build|dist) .
+popd
+chown nobody . -R
+
+# install and run the custom redfish simulator
+pacman -S --noconfirm python-flask
+../plugins/redfish/tests/redfish.py &
+
+# install and run TPM simulator necessary for plugins/uefi-capsule/uefi-self-test
+pacman -S --noconfirm swtpm tpm2-tools
+swtpm socket --tpm2 --server port=2321 --ctrl type=tcp,port=2322 --flags not-need-init --tpmstate "dir=$PWD" &
+trap 'kill $!' EXIT
+# extend a PCR0 value for test suite
+sleep 2
+tpm2_startup -c
+tpm2_pcrextend 0:sha1=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
+export TPM_SERVER_RUNNING=1
+
+# build the package and install it
+sudo -E -u nobody PKGEXT='.pkg.tar' makepkg -e --noconfirm
+pacman -U --noconfirm *.pkg.*
+
+#run the CI tests for Qt5
+pacman -S --noconfirm qt5-base
+meson qt5-thread-test ../contrib/ci/qt5-thread-test
+ninja -C qt5-thread-test test
+
+# move the package to working dir
+mv *.pkg.* ../dist
+
+# no testing here because gnome-desktop-testing isn’t available in Arch
diff --git a/fwupd-1.8.6/contrib/ci/build_freebsd_package.sh b/fwupd-1.8.6/contrib/ci/build_freebsd_package.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0b04893ef3cefea9aa3d36bdf461bfcf5c3c45fa
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/build_freebsd_package.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+GITHUB_SHA=
+GITHUB_REPOSITORY=
+GITHUB_REPOSITORY_OWNER=
+GITHUB_TAG=
+
+while [ -n "$1" ]; do
+ case $1 in
+ --GITHUB_SHA=*)
+ GITHUB_SHA=${1#--GITHUB_SHA=}
+ ;;
+ --GITHUB_REPOSITORY=*)
+ GITHUB_REPOSITORY=${1#--GITHUB_REPOSITORY=}
+ ;;
+ --GITHUB_REPOSITORY_OWNER=*)
+ GITHUB_REPOSITORY_OWNER=${1#--GITHUB_REPOSITORY_OWNER=}
+ ;;
+ --GITHUB_TAG=*)
+ GITHUB_TAG=${1#--GITHUB_TAG=}
+ ;;
+ *)
+ echo "Command $1 unknown. exiting..."
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+if [ -z "$GITHUB_SHA" ] || [ -z "$GITHUB_REPOSITORY" ] || \
+ [ -z "$GITHUB_REPOSITORY_OWNER" ] || [ -z "$GITHUB_TAG" ]; then
+ exit 1
+fi
+
+# Include-file of libefivar port uses GCC-specific builtin function
+export CC=gcc
+
+set -xe
+mkdir -p /usr/local/etc/pkg/repos/
+# Fix meson flag problem https://www.mail-archive.com/freebsd-ports@freebsd.org/msg86617.html
+cp /etc/pkg/FreeBSD.conf /usr/local/etc/pkg/repos/FreeBSD.conf
+# Use latest pkg repo instead of quaterly https://wiki.freebsd.org/Ports/QuarterlyBranch
+sed -i .old 's|url: "pkg+http://pkg.FreeBSD.org/${ABI}/quarterly"|url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest"|' \
+/usr/local/etc/pkg/repos/FreeBSD.conf
+pkg install -y meson efivar
+pkg upgrade -y meson
+cd /usr
+git clone https://github.com/3mdeb/freebsd-ports.git --depth 1 -b fwupd ports
+cd /usr/ports/sysutils/fwupd
+rm -rf ./*
+ls .
+cp -r ~/work/fwupd/fwupd/contrib/freebsd/* .
+ls .
+sed -i .old "s/GH_TAGNAME=.*$/GH_TAGNAME=\t${GITHUB_SHA}/" Makefile
+sed -i .old "s/GH_ACCOUNT=.*$/GH_ACCOUNT=\t${GITHUB_REPOSITORY_OWNER}/" Makefile
+sed -i .old "s/DISTVERSION=.*$/DISTVERSION=\t${GITHUB_TAG}/" Makefile
+make makesum
+make clean
+make
+# Generate current list of files in the pkg-plist
+make makeplist > pkg-plist
+sed -i "" "1d" pkg-plist
+sed -i "" "s/%%PORTDOCS%%%%DOCSDIR%%/%%DOCSDIR%%/g" pkg-plist
+# Build artifact
+make clean
+make package
+make install
+cp /usr/ports/sysutils/fwupd/work/pkg/fwupd*.pkg \
+~/work/fwupd/fwupd/fwupd-freebsd-${GITHUB_TAG}-${GITHUB_SHA}.pkg || exit 1
diff --git a/fwupd-1.8.6/contrib/ci/build_macos.sh b/fwupd-1.8.6/contrib/ci/build_macos.sh
new file mode 100755
index 0000000000000000000000000000000000000000..80ad4a5cd37b7a4c1ba5b7b8a65a3c837d5edd01
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/build_macos.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+set -e
+set -x
+
+mkdir -p build-macos && cd build-macos
+meson .. \
+ -Dbuild=standalone \
+ -Dsoup_session_compat=false \
+ -Dgusb:docs=false \
+ -Dlibjcat:gpg=false \
+ -Dlibxmlb:gtkdoc=false \
+ $@
diff --git a/fwupd-1.8.6/contrib/ci/build_windows.sh b/fwupd-1.8.6/contrib/ci/build_windows.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9bb589a326a9259339bccbf96367bbdef5875c67
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/build_windows.sh
@@ -0,0 +1,175 @@
+#!/bin/sh
+set -e
+
+# if invoked outside of CI
+if [ "$CI" != "true" ]; then
+ echo "Not running in CI, please manually configure Windows build"
+ exit 1
+fi
+
+# install deps
+./contrib/ci/fwupd_setup_helpers.py --yes -o fedora -v mingw64 install-dependencies
+
+# update to latest version of meson
+if [ "$(id -u)" -eq 0 ]; then
+ dnf install -y python-pip
+ pip install meson --force-reinstall
+fi
+
+#prep
+export LC_ALL=C.UTF-8
+root=$(pwd)
+export DESTDIR=${root}/dist
+build=$root/build-win32
+
+rm -rf $DESTDIR $build
+
+# For logitech bulk controller being disabled (-Dplugin_logitech_bulkcontroller=disabled):
+# See https://bugzilla.redhat.com/show_bug.cgi?id=1991749
+# When fixed need to do the following to enable:
+# 1. need to add mingw64-protobuf mingw64-protobuf-tools to CI build deps
+# 2. add protoc = /path/to/protoc-c.exe in mingw64.cross
+# 3. Only enable when not a tagged release (Unsupported by Logitech)
+
+# try to keep this and ../contrib/build-windows.sh in sync as much as makes sense
+mkdir -p $build $DESTDIR && cd $build
+meson .. \
+ --cross-file=/usr/share/mingw/toolchain-mingw64.meson \
+ --cross-file=../contrib/mingw64.cross \
+ --prefix=/ \
+ --sysconfdir="etc" \
+ --libexecdir="bin" \
+ --bindir="bin" \
+ -Dbuild=all \
+ -Dman=false \
+ -Dfish_completion=false \
+ -Dbash_completion=false \
+ -Dfirmware-packager=false \
+ -Dmetainfo=false \
+ -Dcompat_cli=false \
+ -Dsoup_session_compat=false \
+ -Dgcab:introspection=false \
+ -Dgcab:docs=false \
+ -Dgcab:nls=false \
+ -Dgcab:vapi=false \
+ -Dgcab:tests=false \
+ -Dlibxmlb:introspection=false \
+ -Dlibxmlb:gtkdoc=false \
+ -Dlibjcat:man=false \
+ -Dlibjcat:gpg=false \
+ -Dlibjcat:tests=false \
+ -Dlibjcat:introspection=false \
+ -Dgusb:tests=false \
+ -Dgusb:docs=false \
+ -Dgusb:introspection=false \
+ -Dgusb:vapi=false $@
+VERSION=$(meson introspect . --projectinfo | jq -r .version)
+
+# run tests
+export WINEPATH="/usr/x86_64-w64-mingw32/sys-root/mingw/bin/;$build/libfwupd/;$build/libfwupdplugin/;$build/subprojects/libxmlb/src/;$build/subprojects/gcab/libgcab/;$build/subprojects/libjcat/libjcat/;$build/subprojects/gusb/gusb/"
+ninja --verbose -C "$build" -v
+ninja -C "$build" test
+
+# switch to release optimizations
+meson configure -Dtests=false -Dbuildtype=release
+ninja -C "$build" -v install
+
+#disable motd for Windows
+cd $root
+sed -i 's,UpdateMotd=.*,UpdateMotd=false,' "$DESTDIR/etc/fwupd/daemon.conf"
+
+# create a setup binary
+CERTDIR=/etc/pki/tls/certs
+MINGW32BINDIR=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
+
+# deps
+find $MINGW32BINDIR \
+ -name gspawn-win64-helper-console.exe \
+ -o -name gspawn-win64-helper.exe \
+ -o -name iconv.dll \
+ -o -name libarchive-13.dll \
+ -o -name libbrotlicommon.dll \
+ -o -name libbrotlidec.dll \
+ -o -name libbz2-1.dll \
+ -o -name libcrypto-1_1-x64.dll \
+ -o -name libcurl-4.dll \
+ -o -name "libffi-*.dll" \
+ -o -name libgcc_s_seh-1.dll \
+ -o -name libgio-2.0-0.dll \
+ -o -name libglib-2.0-0.dll \
+ -o -name libgmodule-2.0-0.dll \
+ -o -name libgmp-10.dll \
+ -o -name libgnutls-30.dll \
+ -o -name libgobject-2.0-0.dll \
+ -o -name libgusb-2.dll \
+ -o -name "libhogweed-*.dll" \
+ -o -name libidn2-0.dll \
+ -o -name libintl-8.dll \
+ -o -name libjson-glib-1.0-0.dll \
+ -o -name liblzma-5.dll \
+ -o -name "libnettle-*.dll" \
+ -o -name libp11-kit-0.dll \
+ -o -name libpcre-1.dll \
+ -o -name libsqlite3-0.dll \
+ -o -name libssh2-1.dll \
+ -o -name libssl-1_1-x64.dll \
+ -o -name libssp-0.dll \
+ -o -name libtasn1-6.dll \
+ -o -name libusb-1.0.dll \
+ -o -name libwinpthread-1.dll \
+ -o -name libxml2-2.dll \
+ -o -name zlib1.dll \
+ | wixl-heat \
+ -p $MINGW32BINDIR/ \
+ --win64 \
+ --directory-ref BINDIR \
+ --var "var.MINGW32BINDIR" \
+ --component-group "CG.fwupd-deps" | \
+ tee $build/contrib/fwupd-deps.wxs
+
+# no static libraries
+find "$DESTDIR/" -type f -name "*.a" -print0 | xargs rm -f
+
+# our files
+find "$DESTDIR" | \
+ wixl-heat \
+ -p "$DESTDIR/" \
+ -x include/ \
+ -x share/fwupd/device-tests/ \
+ -x share/tests/ \
+ -x share/man/ \
+ -x share/doc/ \
+ -x lib/pkgconfig/ \
+ --win64 \
+ --directory-ref INSTALLDIR \
+ --var "var.DESTDIR" \
+ --component-group "CG.fwupd-files" | \
+ tee "$build/contrib/fwupd-files.wxs"
+
+#add service install key
+sed -i "$build/contrib/fwupd-files.wxs" -f - << EOF
+s,fwupd.exe"/>,fwupd.exe"/>\\
+ ,
+EOF
+
+MSI_FILENAME="$DESTDIR/setup/fwupd-$VERSION-setup-x86_64.msi"
+mkdir -p "$DESTDIR/setup"
+wixl -v \
+ "$build/contrib/fwupd.wxs" \
+ "$build/contrib/fwupd-deps.wxs" \
+ "$build/contrib/fwupd-files.wxs" \
+ -D CRTDIR=$CERTDIR \
+ -D MINGW32BINDIR=$MINGW32BINDIR \
+ -D Win64="yes" \
+ -D DESTDIR="$DESTDIR" \
+ -o "${MSI_FILENAME}"
+
+# check the msi archive can be installed and removed (use "wine uninstaller" to do manually)
+# wine msiexec /i "${MSI_FILENAME}"
+# ls -R ~/.wine/drive_c/Program\ Files/fwupd/
+# wine ~/.wine/drive_c/Program\ Files/fwupd/bin/fwupdtool get-plugins --json
+# wine msiexec /x "${MSI_FILENAME}"
+
+#generate news release
+contrib/ci/generate_news.py $VERSION > $DESTDIR/news.txt
+echo $VERSION > $DESTDIR/VERSION
diff --git a/fwupd-1.8.6/contrib/ci/centos.sh b/fwupd-1.8.6/contrib/ci/centos.sh
new file mode 100755
index 0000000000000000000000000000000000000000..14e5e23f9bb6663faa1fbe75930ce89d936aeb41
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/centos.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+set -x
+
+#clone test firmware if necessary
+. ./contrib/ci/get_test_firmware.sh
+
+#build
+rm -rf build
+mkdir -p build
+cd build
+meson .. \
+ --werror \
+ -Dplugin_uefi_capsule=disabled \
+ -Dplugin_dell=disabled \
+ -Dplugin_modem_manager=disabled \
+ -Dplugin_synaptics_mst=enabled \
+ -Dplugin_flashrom=enabled \
+ -Dintrospection=true \
+ -Dpkcs7=false \
+ -Dman=true
+ninja-build -v
+ninja-build test -v
+cd ..
diff --git a/fwupd-1.8.6/contrib/ci/check-abi b/fwupd-1.8.6/contrib/ci/check-abi
new file mode 100755
index 0000000000000000000000000000000000000000..4a1f6c8a350adbcfca3f012ba38b39cedb9cf6f3
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-abi
@@ -0,0 +1,152 @@
+#!/usr/bin/python3
+
+
+import argparse
+import contextlib
+import os
+import shutil
+import subprocess
+import sys
+
+
+def format_title(title):
+ box = {
+ "tl": "╔",
+ "tr": "╗",
+ "bl": "╚",
+ "br": "╝",
+ "h": "═",
+ "v": "║",
+ }
+ hline = box["h"] * (len(title) + 2)
+
+ return "\n".join(
+ [
+ f"{box['tl']}{hline}{box['tr']}",
+ f"{box['v']} {title} {box['v']}",
+ f"{box['bl']}{hline}{box['br']}",
+ ]
+ )
+
+
+def rm_rf(path):
+ try:
+ shutil.rmtree(path)
+ except FileNotFoundError:
+ pass
+
+
+def sanitize_path(name):
+ return name.replace("/", "-")
+
+
+def get_current_revision():
+ revision = subprocess.check_output(
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"], encoding="utf-8"
+ ).strip()
+
+ if revision == "HEAD":
+ # This is a detached HEAD, get the commit hash
+ revision = (
+ subprocess.check_output(["git", "rev-parse", "HEAD"])
+ .strip()
+ .decode("utf-8")
+ )
+
+ return revision
+
+
+@contextlib.contextmanager
+def checkout_git_revision(revision):
+ current_revision = get_current_revision()
+ subprocess.check_call(["git", "checkout", "-q", revision])
+
+ try:
+ yield
+ finally:
+ subprocess.check_call(["git", "checkout", "-q", current_revision])
+
+
+def build_install(revision):
+ build_dir = "_build"
+ dest_dir = os.path.abspath(sanitize_path(revision))
+ print(
+ format_title(f"# Building and installing {revision} in {dest_dir}"),
+ end="\n\n",
+ flush=True,
+ )
+
+ with checkout_git_revision(revision):
+ rm_rf(build_dir)
+ rm_rf(revision)
+
+ subprocess.check_call(
+ [
+ "meson",
+ build_dir,
+ "--prefix=/usr",
+ "--libdir=lib",
+ "-Dauto_features=disabled",
+ "-Ddocs=none",
+ "-Db_coverage=false",
+ "-Dgusb:docs=false",
+ "-Dtests=false",
+ ]
+ )
+ subprocess.check_call(["ninja", "-v", "-C", build_dir])
+ subprocess.check_call(
+ ["ninja", "-v", "-C", build_dir, "install"], env={"DESTDIR": dest_dir}
+ )
+
+ return dest_dir
+
+
+def compare(old_tree, new_tree):
+ print(format_title(f"# Comparing the two ABIs"), end="\n\n", flush=True)
+
+ old_headers = os.path.join(old_tree, "usr", "include")
+ old_lib = os.path.join(old_tree, "usr", "lib", "libfwupd.so")
+
+ new_headers = os.path.join(new_tree, "usr", "include")
+ new_lib = os.path.join(new_tree, "usr", "lib", "libfwupd.so")
+
+ subprocess.check_call(
+ [
+ "abidiff",
+ "--headers-dir1",
+ old_headers,
+ "--headers-dir2",
+ new_headers,
+ "--drop-private-types",
+ "--suppressions",
+ "contrib/ci/abidiff.suppr",
+ "--fail-no-debug-info",
+ "--no-added-syms",
+ old_lib,
+ new_lib,
+ ]
+ )
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument("old", help="the previous revision, considered the reference")
+ parser.add_argument("new", help="the new revision, to compare to the reference")
+
+ args = parser.parse_args()
+
+ if args.old == args.new:
+ print("Let's not waste time comparing something to itself")
+ sys.exit(0)
+
+ old_tree = build_install(args.old)
+ new_tree = build_install(args.new)
+
+ try:
+ compare(old_tree, new_tree)
+
+ except subprocess.CalledProcessError:
+ sys.exit(1)
+
+ print(f"Hurray! {args.old} and {args.new} are ABI-compatible!")
diff --git a/fwupd-1.8.6/contrib/ci/check-deprecated.sh b/fwupd-1.8.6/contrib/ci/check-deprecated.sh
new file mode 100755
index 0000000000000000000000000000000000000000..78b0d1915190c230fd9ebc71d3a71dc224a9132d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-deprecated.sh
@@ -0,0 +1,15 @@
+#!/bin/sh -e
+set -e
+
+# these are deprecated in favor of INTERNAL flags
+deprecated="FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS
+ FWUPD_DEVICE_FLAG_ONLY_SUPPORTED
+ FWUPD_DEVICE_FLAG_MD_SET_NAME
+ FWUPD_DEVICE_FLAG_MD_SET_VERFMT
+ FWUPD_DEVICE_FLAG_NO_GUID_MATCHING
+ FWUPD_DEVICE_FLAG_MD_SET_ICON"
+for val in $deprecated; do
+ if grep -- $val plugins/*/*.c ; then
+ exit 1
+ fi
+done
diff --git a/fwupd-1.8.6/contrib/ci/check-finalizers.py b/fwupd-1.8.6/contrib/ci/check-finalizers.py
new file mode 100755
index 0000000000000000000000000000000000000000..3a0023d5da6d3370fb751560322075b513bee116
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-finalizers.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring,consider-using-f-string
+# pylint: disable=too-few-public-methods
+#
+# Copyright (C) 2022 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import glob
+import sys
+from typing import List
+
+
+class ReturnValidator:
+ def __init__(self):
+ self.warnings: List[str] = []
+
+ def parse(self, fn: str) -> None:
+
+ with open(fn, "rb") as f:
+ infunc = False
+ has_parent_finalize = False
+ for line in f.read().decode().split("\n"):
+
+ # found the function, but ignore the prototype
+ if line.find("_finalize(") != -1:
+ if line.endswith(";"):
+ continue
+ infunc = True
+ continue
+
+ # got it
+ if line.find("->finalize(") != -1:
+ has_parent_finalize = True
+ continue
+
+ # finalize is done
+ if infunc and line.startswith("}"):
+ if not has_parent_finalize:
+ self.warnings.append(
+ "{} did not have parent ->finalize()".format(fn)
+ )
+ break
+
+
+def test_files():
+
+ # test all C source files
+ validator = ReturnValidator()
+ for fn in glob.glob("**/*.c", recursive=True):
+ if fn.startswith("dist/") or fn.startswith("subprojects/"):
+ continue
+ validator.parse(fn)
+ for warning in validator.warnings:
+ print(warning)
+
+ return 1 if validator.warnings else 0
+
+
+if __name__ == "__main__":
+
+ # all done!
+ sys.exit(test_files())
diff --git a/fwupd-1.8.6/contrib/ci/check-headers.py b/fwupd-1.8.6/contrib/ci/check-headers.py
new file mode 100755
index 0000000000000000000000000000000000000000..897b27e129f5cf626abe49270899017856149957
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-headers.py
@@ -0,0 +1,151 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-module-docstring,missing-function-docstring
+#
+# Copyright (C) 2021 Richard Hughes
+# Copyright (C) 2021 Mario Limonciello
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import glob
+import sys
+import os
+from typing import List
+
+
+def __get_includes(fn: str) -> List[str]:
+ includes: List[str] = []
+ with open(fn, "r") as f:
+ for line in f.read().split("\n"):
+ if line.find("#include") == -1:
+ continue
+ if line.find("waive-pre-commit") > 0:
+ continue
+ for char in ["<", ">", '"']:
+ line = line.replace(char, "")
+ for char in ["\t"]:
+ line = line.replace(char, " ")
+ includes.append(line.split(" ")[-1])
+ return includes
+
+
+def test_files() -> int:
+
+ rc: int = 0
+
+ lib_headers1 = glob.glob("libfwupd/*.h")
+ lib_headers1.remove("libfwupd/fwupd.h")
+
+ lib_headers2 = glob.glob("libfwupdplugin/*.h")
+ lib_headers2.remove("libfwupdplugin/fwupdplugin.h")
+
+ toplevel_headers = ["libfwupd/fwupd.h", "libfwupdplugin/fwupdplugin.h"]
+ toplevel_headers_nopath = [os.path.basename(fn) for fn in toplevel_headers]
+ lib_headers = lib_headers1 + lib_headers2
+ lib_headers_nopath = [os.path.basename(fn) for fn in lib_headers]
+
+ # test all C and H files
+ for fn in glob.glob("**/*.[c|h]", recursive=True):
+ includes = __get_includes(fn)
+
+ # we do not care
+ if fn.startswith("subprojects"):
+ continue
+ if fn.startswith("build"):
+ continue
+ if fn.startswith("dist"):
+ continue
+ if fn.startswith("contrib/ci"):
+ continue
+ if fn in [
+ "libfwupd/fwupd-context-test.c",
+ "libfwupd/fwupd-thread-test.c",
+ "libfwupdplugin/fu-fuzzer-main.c",
+ ]:
+ continue
+
+ if (
+ fn.startswith("plugins")
+ and not fn.endswith("self-test.c")
+ and not fn.endswith("tool.c")
+ ):
+ for include in includes:
+ # check for using private header use in plugins
+ if include.endswith("private.h"):
+ print("{} uses private header {}".format(fn, include))
+ rc = 1
+ continue
+
+ # check for referring to anything but top level header
+ if include in lib_headers or include in lib_headers_nopath:
+ print(
+ "{} contains {}, should only use top level includes".format(
+ fn, include
+ )
+ )
+ rc = 1
+
+ # check for double top level headers
+ for toplevel_header in toplevel_headers:
+
+ toplevel_fn = os.path.basename(toplevel_header)
+ toplevel_includes = __get_includes(toplevel_header)
+ toplevel_includes_nopath = [
+ os.path.basename(fn) for fn in toplevel_includes
+ ]
+
+ # we do not need both toplevel headers
+ if set(toplevel_headers_nopath).issubset(set(includes)):
+ print(
+ "{} contains both {}".format(fn, ", ".join(toplevel_headers_nopath))
+ )
+
+ # toplevel not listed
+ if toplevel_fn not in includes:
+ continue
+
+ # includes toplevel and *also* something listed in the toplevel
+ for include in includes:
+ if include in toplevel_includes or include in toplevel_includes_nopath:
+ print(
+ "{} contains {} but also includes {}".format(
+ fn, toplevel_fn, include
+ )
+ )
+ rc = 1
+
+ # check for missing config.h
+ if fn.endswith(".c") and "config.h" not in includes:
+ print("{} does not include config.h".format(fn))
+ rc = 1
+
+ # check for one header implying the other
+ implied_headers = {
+ "fu-common.h": ["xmlb.h"],
+ "fwupdplugin.h": [
+ "gio/gio.h",
+ "glib.h",
+ "glib-object.h",
+ "xmlb.h",
+ "fwupd.h",
+ ]
+ + lib_headers1,
+ "gio/gio.h": ["glib.h", "glib-object.h"],
+ "glib-object.h": ["glib.h"],
+ "json-glib/json-glib.h": ["glib.h", "glib-object.h"],
+ "xmlb.h": ["gio/gio.h"],
+ }
+ for key, values in implied_headers.items():
+ for value in values:
+ if key in includes and value in includes:
+ print(
+ "{} contains {} which is implied by {}".format(fn, value, key)
+ )
+ rc = 1
+
+ return rc
+
+
+if __name__ == "__main__":
+
+ # all done!
+ sys.exit(test_files())
diff --git a/fwupd-1.8.6/contrib/ci/check-license.py b/fwupd-1.8.6/contrib/ci/check-license.py
new file mode 100755
index 0000000000000000000000000000000000000000..5f5b80512612cf6d92c141c2c1f8fc76d20f5863
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-license.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2021 Richard Hughes
+# Copyright (C) 2021 Mario Limonciello
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import glob
+import os
+import sys
+
+
+def __get_license(fn: str) -> str:
+ with open(fn, "r") as f:
+ for line in f.read().split("\n"):
+ if line.find("SPDX-License-Identifier:") > 0:
+ return line.split(":")[1]
+ return ""
+
+
+def test_files() -> int:
+
+ rc: int = 0
+ build_dirs = [os.path.dirname(cf) for cf in glob.glob("**/config.h")]
+
+ for fn in glob.glob("**/*.[c|h|py|sh]", recursive=True):
+ if "meson-private" in fn:
+ continue
+ if os.path.isdir(fn):
+ continue
+ if fn.startswith(tuple(build_dirs)):
+ continue
+ if fn.startswith("subprojects"):
+ continue
+ if fn.startswith("dist"):
+ continue
+ lic = __get_license(fn)
+ if not lic:
+ print("{} does not specify a license".format(fn))
+ rc = 1
+ continue
+ if not "GPL" in lic:
+ print("{} does not contain LGPL or GPL ({})".format(fn, lic))
+ rc = 1
+ continue
+ return rc
+
+
+if __name__ == "__main__":
+
+ # all done!
+ sys.exit(test_files())
diff --git a/fwupd-1.8.6/contrib/ci/check-null-false-returns.py b/fwupd-1.8.6/contrib/ci/check-null-false-returns.py
new file mode 100755
index 0000000000000000000000000000000000000000..48fbbe85bbe20c566ac742151f60e6ba749b9531
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-null-false-returns.py
@@ -0,0 +1,240 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring,too-many-branches
+# pylint: disable=too-many-statements,too-many-return-statements,too-few-public-methods
+#
+# Copyright (C) 2021 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import glob
+import sys
+from typing import List
+
+
+def _tokenize(line: str) -> List[str]:
+
+ # remove whitespace
+ line = line.strip()
+ line = line.replace("\t", "")
+ line = line.replace(";", "")
+
+ # find value
+ line = line.replace(" ", "|")
+ line = line.replace(",", "|")
+ line = line.replace(")", "|")
+ line = line.replace("(", "|")
+
+ # return empty tokens
+ tokens = []
+ for token in line.rsplit("|"):
+ if token:
+ tokens.append(token)
+ return tokens
+
+
+class ReturnValidator:
+ def __init__(self):
+ self.warnings: List[str] = []
+
+ # internal state
+ self._fn = None
+ self._line_num = None
+ self._value = None
+ self._nret = None
+ self._rvif = None
+ self._line = None
+
+ @property
+ def _tokens(self) -> List[str]:
+ return _tokenize(self._line)
+
+ @property
+ def _value_relaxed(self) -> str:
+ if self._value in ["0x0", "0x00", "0x0000"]:
+ return "0"
+ if self._value in ["0xffffffff"]:
+ return "G_MAXUINT32"
+ if self._value in ["0xffff"]:
+ return "G_MAXUINT16"
+ if self._value in ["0xff"]:
+ return "G_MAXUINT8"
+ if self._value in ["G_SOURCE_REMOVE"]:
+ return "FALSE"
+ if self._value in ["G_SOURCE_CONTINUE"]:
+ return "TRUE"
+ return self._value
+
+ def _test_rvif(self) -> None:
+
+ # parse "g_return_val_if_fail (SOMETHING (foo), NULL);"
+ self._value = self._tokens[-1]
+
+ # enumerated enum, so ignore
+ if self._value.find("_") != -1:
+ return
+
+ # is invalid
+ if self._rvif and self._value_relaxed not in self._rvif:
+ self.warnings.append(
+ "{} line {} got {}, expected {}".format(
+ self._fn, self._line_num, self._value, ", ".join(self._rvif)
+ )
+ )
+
+ def _test_return(self) -> None:
+
+ # parse "return 0x0;"
+ self._value = self._tokens[-1]
+
+ # is invalid
+ if self._nret and self._value_relaxed in self._nret:
+ self.warnings.append(
+ "{} line {} got {}, which is not valid".format(
+ self._fn, self._line_num, self._value
+ )
+ )
+
+ def parse(self, fn: str) -> None:
+
+ self._fn = fn
+ with open(fn) as f:
+ self._rvif = None
+ self._nret = None
+ self._line_num = 0
+ for line in f.readlines():
+ self._line_num += 1
+ line = line.rstrip()
+ if not line:
+ continue
+ if line.endswith("\\"):
+ continue
+ if line.endswith("&&"):
+ continue
+ self._line = line
+ idx = line.find("g_return_val_if_fail")
+ if idx != -1:
+ self._test_rvif()
+ continue
+ idx = line.find("return")
+ if idx != -1:
+ # continue
+ if len(self._tokens) == 2:
+ self._test_return()
+ continue
+
+ # not a function header
+ if line[0] in ["#", " ", "\t", "{", "}", "/"]:
+ continue
+
+ # label
+ if line.endswith(":"):
+ continue
+
+ # remove prefixes
+ if line.startswith("static"):
+ line = line[7:]
+ if line.startswith("inline"):
+ line = line[7:]
+
+ # a pointer
+ if line.endswith("*"):
+ self._rvif = ["NULL"]
+ self._nret = ["FALSE"]
+ continue
+
+ # not a leading line
+ if line.find(" ") != -1:
+ continue
+
+ # a type we know
+ if line in ["void"]:
+ self._rvif = []
+ self._nret = []
+ continue
+ if line in ["gpointer"]:
+ self._rvif = ["NULL"]
+ self._nret = ["FALSE"]
+ continue
+ if line in ["gboolean"]:
+ self._rvif = ["TRUE", "FALSE"]
+ self._nret = ["NULL", "0"]
+ continue
+ if line in ["guint32"]:
+ self._rvif = ["0", "G_MAXUINT32"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["GQuark", "GType"]:
+ self._rvif = ["0"]
+ self._nret = ["NULL", "0", "TRUE", "FALSE"]
+ continue
+ if line in ["guint64"]:
+ self._rvif = ["0", "G_MAXUINT64"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["guint16"]:
+ self._rvif = ["0", "G_MAXUINT16"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["guint8"]:
+ self._rvif = ["0", "G_MAXUINT8"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gint64"]:
+ self._rvif = ["0", "-1", "G_MAXINT64"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gint32"]:
+ self._rvif = ["0", "-1", "G_MAXINT32"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gint16"]:
+ self._rvif = ["0", "-1", "G_MAXINT16"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gint8"]:
+ self._rvif = ["0", "-1", "G_MAXINT8"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gint", "int"]:
+ self._rvif = ["0", "-1", "G_MAXINT"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["guint"]:
+ self._rvif = ["0", "G_MAXUINT"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gulong"]:
+ self._rvif = ["0", "G_MAXLONG"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gsize", "size_t"]:
+ self._rvif = ["0", "G_MAXSIZE"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ if line in ["gssize", "ssize_t"]:
+ self._rvif = ["0", "-1", "G_MAXSSIZE"]
+ self._nret = ["NULL", "TRUE", "FALSE"]
+ continue
+ # print('unknown return type {}'.format(line))
+ self._rvif = None
+ self._nret = None
+
+
+def test_files():
+
+ # test all C source files
+ validator = ReturnValidator()
+ for fn in glob.glob("**/*.c", recursive=True):
+ if fn.startswith("dist/") or fn.startswith("subprojects/"):
+ continue
+ validator.parse(fn)
+ for warning in validator.warnings:
+ print(warning)
+
+ return 1 if validator.warnings else 0
+
+
+if __name__ == "__main__":
+
+ # all done!
+ sys.exit(test_files())
diff --git a/fwupd-1.8.6/contrib/ci/check-potfiles.py b/fwupd-1.8.6/contrib/ci/check-potfiles.py
new file mode 100755
index 0000000000000000000000000000000000000000..15dda5341d165ac065e7d56e0193881be3a5280a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-potfiles.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring,consider-using-f-string
+# pylint: disable=too-few-public-methods
+#
+# Copyright (C) 2022 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import glob
+import sys
+
+from typing import List
+
+
+def test_files():
+
+ # compare with POTFILES.in
+ with open("po/POTFILES.in", "rb") as f:
+ potfiles_fns: List[str] = f.read().decode().split("\n")
+ for fn in sorted(
+ glob.glob("src/*.c")
+ + glob.glob("plugins/*/*.c")
+ + glob.glob("policy/*.policy.in")
+ + glob.glob("data/*/*.xml")
+ + glob.glob("libfwupdplugin/tests/bios-attrs/*/*.txt")
+ ):
+ if (
+ fn.startswith("dist/")
+ or fn.startswith("subprojects/")
+ or fn.startswith("build/")
+ ):
+ continue
+ with open(fn, "rb") as f:
+ blob = f.read().decode()
+ if blob.find('_("') != -1 or blob.find("TRANSLATORS") != -1:
+ if fn not in potfiles_fns:
+ print("{} is missing from po/POTFILES.in".format(fn))
+ return 1
+
+ # success
+ return 0
+
+
+if __name__ == "__main__":
+
+ # all done!
+ sys.exit(test_files())
diff --git a/fwupd-1.8.6/contrib/ci/check-quirks.py b/fwupd-1.8.6/contrib/ci/check-quirks.py
new file mode 100755
index 0000000000000000000000000000000000000000..83b09fac8f854e34927b626f67a1c5050334c281
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check-quirks.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2021 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import glob
+import sys
+
+
+def test_files() -> int:
+
+ rc: int = 0
+
+ for fn in glob.glob("**/*.quirk", recursive=True):
+ with open(fn, "r") as f:
+ for line in f.read().split("\n"):
+ if line.startswith(" ") or line.endswith(" "):
+ print("{} has leading or trailing whitespace: {}".format(fn, line))
+ rc = 1
+ continue
+ if not line or line.startswith("#"):
+ continue
+ if line.startswith("["):
+ if not line.endswith("]"):
+ print("{} has invalid section header: {}".format(fn, line))
+ rc = 1
+ continue
+ for deprecated in ["DeviceInstanceId", "Guid"]:
+ if line.find(deprecated) != -1:
+ print("{} has deprecated prefix: {}".format(fn, deprecated))
+ rc = 1
+ continue
+ else:
+ sections = line.split(" = ")
+ if len(sections) != 2:
+ print("{} has invalid line: {}".format(fn, line))
+ rc = 1
+ continue
+ for section in sections:
+ if section.strip() != section:
+ print("{} has invalid spacing: {}".format(fn, line))
+ rc = 1
+ break
+ return rc
+
+
+if __name__ == "__main__":
+
+ # all done!
+ sys.exit(test_files())
diff --git a/fwupd-1.8.6/contrib/ci/check_missing_translations.sh b/fwupd-1.8.6/contrib/ci/check_missing_translations.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0139ff3535abffb813a9ac7906cc0701e32d9dde
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/check_missing_translations.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+
+cd po
+intltool-update -m
+if [ -f missing ]; then
+ exit 1
+fi
diff --git a/fwupd-1.8.6/contrib/ci/debian.sh b/fwupd-1.8.6/contrib/ci/debian.sh
new file mode 100755
index 0000000000000000000000000000000000000000..bc7e888a94955c2366d3986e9a7b90c044959000
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/debian.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+set -e
+set -x
+
+export QUBES_OPTION=
+
+
+#although it's debian, we don't build packages
+if [ "$OS" = "debian-s390x" ]; then
+ ./contrib/ci/debian_s390x.sh
+ exit 0
+fi
+
+# Set Qubes Os vars if -Dqubes=true is parameter
+if [ "$QUBES" = "true" ]; then
+ export QUBES_OPTION='-Dqubes=true'
+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|venv) build/
+pushd build
+mv contrib/debian .
+sed s/quilt/native/ debian/source/format -i
+#generate control file
+./contrib/ci/generate_debian.py
+
+#check if we have all deps available
+#if some are missing, we're going to use subproject instead and
+#packaging CI will fail
+apt update -qq && apt install python3-apt -y
+./contrib/ci/fwupd_setup_helpers.py install-dependencies -o debian --yes || true
+if ! dpkg-checkbuilddeps; then
+ ./contrib/ci/ubuntu.sh
+ exit 0
+fi
+
+#clone test firmware if necessary
+. ./contrib/ci/get_test_firmware.sh
+
+#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 \
+ --preserve-envvar QUBES_OPTION
+
+#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 library-not-linked-against-libc \
+ --suppress-tags bad-distribution-in-changes-file \
+ --suppress-tags debian-watch-file-in-native-package \
+ --suppress-tags source-nmu-has-incorrect-version-number \
+ --suppress-tags no-symbols-control-file \
+ --suppress-tags gzip-file-is-not-multi-arch-same-safe \
+ --suppress-tags missing-dependency-on-libc \
+ --suppress-tags arch-dependent-file-not-in-arch-specific-directory \
+ --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=$(find .. -type f -name "*.deb" | grep -v 'fwupd-tests\|dbgsym')
+dpkg -i $PACKAGES
+
+# copy in more non-generated data
+mkdir -p /usr/share/installed-tests/fwupd
+cp fwupd-test-firmware/installed-tests/* /usr/share/installed-tests/fwupd/ -LRv
+
+# 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
diff --git a/fwupd-1.8.6/contrib/ci/debian_s390x.sh b/fwupd-1.8.6/contrib/ci/debian_s390x.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4bff8baba2df6fdadadaf567f9152813d9c52e53
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/debian_s390x.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+set -e
+set -x
+
+export LC_ALL=C.UTF-8
+
+#evaluate using Debian's build flags
+eval "$(dpkg-buildflags --export=sh)"
+#filter out -Bsymbolic-functions
+LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//")
+export LDFLAGS
+
+rm -rf build
+mkdir -p build
+cp contrib/ci/s390x_cross.txt build/
+cd build
+meson .. \
+ --cross-file s390x_cross.txt \
+ --werror \
+ -Dplugin_flashrom=disabled \
+ -Dplugin_uefi_capsule=disabled \
+ -Dplugin_dell=disabled \
+ -Dplugin_modem_manager=disabled \
+ -Dplugin_msr=disabled \
+ -Dplugin_mtd=false \
+ -Dplugin_powerd=disabled \
+ -Dintrospection=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 --git a/fwupd-1.8.6/contrib/ci/dependencies.xml b/fwupd-1.8.6/contrib/ci/dependencies.xml
new file mode 100644
index 0000000000000000000000000000000000000000..acef65818cc999f288907dd2ea2bbb2f0a58c27f
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/dependencies.xml
@@ -0,0 +1,1759 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clang-tools-extra
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mingw64-gcc
+
+
+
+
+
+
+
+
+
+ cairo-devel
+
+
+ cairo-devel
+ cairo-devel
+
+
+ cairo-devel
+
+
+
+
+ libcairo-dev:s390x
+
+
+
+
+
+
+
+
+
+ cairo-gobject-devel
+
+
+ cairo-gobject-devel
+ cairo-gobject-devel
+
+
+
+
+ libcairo-gobject2:s390x
+
+
+
+
+
+
+
+
+
+ json-glib
+
+
+ json-glib-devel
+
+
+ json-glib-devel
+ json-glib-devel
+ mingw64-json-glib
+
+
+ json-glib-devel
+
+
+
+ (>= 1.1.1)
+
+
+ libjson-glib-dev:s390x
+
+
+
+
+ (>= 1.1.1)
+
+
+
+
+
+
+ libftdi
+
+
+ libftdi-devel
+
+
+ libftdi-devel
+ libftdi-devel
+
+
+
+
+
+
+
+
+
+
+
+
+ pciutils
+
+
+ pciutils-devel
+
+
+ pciutils-devel
+ pciutils-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+ noto-fonts
+
+
+ google-noto-sans-cjk-ttc-fonts
+
+
+ google-noto-sans-cjk-ttc-fonts
+ google-noto-sans-cjk-ttc-fonts
+
+
+ noto-fonts-cjk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (>= 12)
+
+
+
+
+
+
+ (>= 12)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ freetype
+
+
+ freetype
+ freetype
+
+
+
+
+ libfreetype6-dev:s390x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ flashrom-devel
+ flashrom-devel
+
+
+
+ ia64
+
+
+
+
+
+
+ ia64
+
+
+
+
+
+
+
+
+
+
+
+
+ gcab
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ gettext
+ mingw64-gettext
+
+
+
+
+
+
+ (>= 0.19.8.1)
+
+
+
+
+
+
+
+ (>= 0.19.8.1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ gnu-efi-libs
+
+
+
+
+
+
+
+
+
+ gnu-efi-libs
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+ gnu-efi
+ gnu-efi
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+ gnu-efi
+ gnu-efi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ glib2-devel
+
+
+ glib2-devel
+ glib2-devel
+
+ glib2-devel
+ mingw64-glib2
+
+
+ glib-devel
+
+
+
+ (>= 2.45.8)
+
+
+ libglib2.0-dev:s390x
+
+
+
+
+ (>= 2.45.8)
+
+
+
+
+
+
+ glibc-langpack-en
+ glibc-langpack-en
+
+
+
+
+
+
+
+ gobject-introspection-devel
+
+
+ gobject-introspection-devel
+ gobject-introspection-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ gnutls-devel
+
+
+ gnutls-devel
+ gnutls-devel
+ mingw64-gnutls
+
+
+ gnutls-devel
+
+
+
+
+ libgnutls28-dev:s390x
+ libgnutls28-dev
+
+
+
+
+
+
+
+
+ gnutls-utils
+
+
+ gnutls-utils
+ gnutls-utils
+
+
+ gnutls-tools
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ libxmlb
+
+
+
+ libxmlb-devel
+ libxmlb-devel
+
+
+ libxmlb-devel
+
+
+
+ (>= 0.1.13)
+
+
+ libxmlb-dev:s390x
+
+
+
+
+ (>= 0.1.13)
+
+
+
+
+
+
+ libjcat-devel
+ libjcat-devel
+
+
+
+
+
+
+
+
+
+
+
+
+ libjcat-devel
+
+
+
+
+ xz-devel
+ xz-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ libarchive-devel
+
+
+ libarchive-devel
+ libarchive-devel
+ mingw64-libarchive
+
+
+
+
+ libarchive-dev:s390x
+
+
+
+
+
+
+
+ libarchive-devel
+
+
+
+
+ libcbor
+
+
+ libcbor-devel
+
+
+ libcbor-devel
+ libcbor-devel
+
+
+
+
+ libcbor-dev:s390x
+
+
+
+
+
+
+
+ libcbor-devel
+
+
+
+
+ efivar
+
+
+ efivar-devel
+
+
+ efivar-devel
+ efivar-devel
+
+
+ libefivar-devel
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+ gcab
+
+
+ libgcab1-devel
+
+
+ libgcab1-devel
+ libgcab1-devel
+
+
+
+
+ libgcab-dev:s390x
+
+
+
+
+
+
+
+ gcab-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ libgudev1-devel
+
+
+ libgudev1-devel
+ libgudev1-devel
+
+
+
+
+ libgudev-1.0-dev:s390x
+
+
+
+
+
+
+
+
+
+ libgusb
+
+
+ libgusb-devel
+
+
+ libgusb-devel
+ libgusb-devel
+ mingw64-libgusb
+
+
+ libgusb-devel
+
+
+
+ (>= 0.3.5)
+
+
+ libgusb-dev:s390x
+
+
+
+
+ (>= 0.3.3)
+
+
+
+
+
+
+ libicu-dev:s390x
+
+
+
+
+
+ libidn2-0-dev:s390x
+
+
+
+
+
+ libsmbios
+
+
+ libsmbios-devel
+
+
+ libsmbios-devel
+
+
+ libsmbios-devel
+
+
+
+ i386
+ amd64
+
+
+
+
+
+
+ i386
+ amd64
+
+
+
+
+
+
+
+
+
+
+ libsoup-devel
+
+
+
+
+ curl
+
+
+ libcurl-devel
+
+
+ libcurl-devel
+ libcurl-devel
+ mingw64-curl
+
+
+ libcurl-devel
+
+
+
+
+ libcurl4-gnutls-dev:s390x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+
+
+ pango-devel
+
+
+ pango-devel
+ pango-devel
+
+
+ pango-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mingw64-pkg-config
+
+
+
+
+
+
+
+ polkit
+
+
+ polkit
+
+
+ polkit
+ polkit
+
+
+ polkit
+
+
+
+ (>> 0.105-14)
+
+
+
+
+
+
+
+ (>> 0.105-14)
+
+
+
+
+
+
+ ModemManager-glib-devel
+
+
+ ModemManager-glib-devel
+ ModemManager-glib-devel
+
+
+ modemmanager
+
+
+
+
+ libmm-glib-dev:s390x
+
+
+
+
+
+
+
+
+
+ libqmi-devel
+
+
+ libqmi-devel
+ libqmi-devel
+
+
+ libqmi
+
+
+
+
+ libqmi-glib-dev:s390x
+
+
+
+
+
+
+
+
+
+ libmbim-devel
+
+
+ libmbim-devel
+ libmbim-devel
+
+
+ libmbim
+
+
+
+
+ libmbim-glib-dev:s390x
+
+
+
+
+
+
+
+
+
+
+
+ libqrtr-glib-dev:s390x
+
+
+
+
+
+ polkit-devel
+
+
+ polkit-devel
+ polkit-devel
+
+
+ polkit-devel
+
+
+
+
+ libpolkit-gobject-1-dev:s390x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ python34-devel
+
+
+
+
+
+
+
+
+
+
+
+ python-cairo
+
+
+ python3-cairo
+ python3-cairo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ python-gobject
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ python-packaging
+
+
+
+
+
+
+
+
+
+
+
+
+
+ qemu-user
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sqlite-devel
+
+
+ sqlite-devel
+ sqlite-devel
+ mingw64-sqlite
+
+
+
+
+ libsqlite3-dev:s390x
+
+
+
+
+
+
+
+ sqlite-devel
+
+
+
+
+ elogind-devel
+
+
+
+
+
+
+
+
+
+
+
+
+ (>= 231)
+
+
+
+
+
+
+
+ (>= 231)
+
+
+
+
+
+
+ systemd-devel
+
+
+ systemd-devel
+ systemd-devel
+
+
+
+
+ libsystemd-dev:s390x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ umockdev-devel
+
+
+ umockdev-devel
+ umockdev-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+ vala
+
+
+ vala
+
+
+ vala
+ vala
+
+
+ vala
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ valgrind-devel
+
+
+ valgrind-devel
+ valgrind-devel
+
+
+
+ ia64
+ riscv64
+ x32
+ mips
+ sparc64
+ sh4
+ ppc64
+ powerpcspe
+ hppa
+ alpha
+ mips64el
+ armhf
+ armel
+ mipsel
+ m68k
+
+
+
+
+
+
+ ia64
+ riscv64
+ x32
+ mips
+ sparc64
+ sh4
+ ppc64
+ powerpcspe
+ hppa
+ alpha
+ mips64el
+ armhf
+ armel
+ mipsel
+ m68k
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tpm2-tss
+
+
+ tpm2-tss-devel
+
+
+ tpm2-tss-devel
+ tpm2-tss-devel
+
+
+
+
+ libtss2-dev:s390x
+
+
+
+
+ amd64
+ arm64
+ armhf
+ i386
+
+
+
+
+ tpm2-tss-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ShellCheck
+
+
+
+
+ protobuf-c
+
+
+
+
+
+
+
+
+
+
+
+ protobuf-c-devel
+ protobuf-c-devel
+
+
+ protobuf-c-devel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ protobuf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ wine
+
+
+
+
+
+ msitools
+
+
+
diff --git a/fwupd-1.8.6/contrib/ci/fedora.sh b/fwupd-1.8.6/contrib/ci/fedora.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cdb398a10a61905c05ae3232551444fed622ba01
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/fedora.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+set -e
+set -x
+
+#get any missing deps from the container
+./contrib/ci/fwupd_setup_helpers.py install-dependencies --yes -o fedora
+
+# disable the safe directory feature
+git config --global safe.directory "*"
+
+#generate a tarball
+mkdir -p build && pushd build
+rm -rf *
+
+if [ "$QUBES" = "true" ]; then
+ QUBES_MACRO=(--define "qubes_packages 1")
+fi
+
+meson .. \
+ -Ddocs=disabled \
+ -Dman=true \
+ -Dtests=true \
+ -Db_sanitize=address,undefined \
+ -Dgusb:tests=false \
+ -Dplugin_dummy=true \
+ -Dplugin_flashrom=enabled \
+ -Dplugin_modem_manager=disabled \
+ -Dplugin_uefi_capsule=enabled \
+ -Dplugin_dell=enabled \
+ -Dplugin_synaptics_mst=enabled $@
+ninja-build dist
+popd
+VERSION=`meson introspect build --projectinfo | jq -r .version`
+RPMVERSION=${VERSION//-/.}
+mkdir -p $HOME/rpmbuild/SOURCES/
+mv build/meson-dist/fwupd-$VERSION.tar.xz $HOME/rpmbuild/SOURCES/
+
+#generate a spec file
+sed "s,#VERSION#,$RPMVERSION,;
+ s,#BUILD#,1,;
+ s,#LONGDATE#,`date '+%a %b %d %Y'`,;
+ s,#ALPHATAG#,alpha,;
+ s,enable_dummy 0,enable_dummy 1,;
+ s,Source0.*,Source0:\tfwupd-$VERSION.tar.xz," \
+ build/contrib/fwupd.spec.in > build/fwupd.spec
+
+if [ -n "$CI" ]; then
+ sed -i "s,enable_ci 0,enable_ci 1,;" build/fwupd.spec
+fi
+
+#build RPM packages
+rpmbuild -ba "${QUBES_MACRO[@]}" build/fwupd.spec
+
+#if invoked outside of CI
+if [ ! -f /.dockerenv ]; then
+ echo "Not running in a container, please manually install packages"
+ exit 0
+fi
+
+#install RPM packages
+dnf install -y $HOME/rpmbuild/RPMS/*/*.rpm
+
+mkdir -p dist
+cp $HOME/rpmbuild/RPMS/*/*.rpm dist
+
+if [ "$CI" = "true" ]; then
+ sed "s,^DisabledPlugins=.*,DisabledPlugins=," -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 --git a/fwupd-1.8.6/contrib/ci/flatpak.py b/fwupd-1.8.6/contrib/ci/flatpak.py
new file mode 100755
index 0000000000000000000000000000000000000000..28c3ce0d8d01148f996bd435ec4776a4c1d49772
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/flatpak.py
@@ -0,0 +1,90 @@
+#!/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 main
+ data["branch"] = "main"
+ 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 -i flatpak run org.freedesktop.fwupd --verbose get-devices
diff --git a/fwupd-1.8.6/contrib/ci/fwupd_setup_helpers.py b/fwupd-1.8.6/contrib/ci/fwupd_setup_helpers.py
new file mode 100755
index 0000000000000000000000000000000000000000..936589851cd6be3c10b920f3f8965f167ab90c91
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/fwupd_setup_helpers.py
@@ -0,0 +1,244 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2017 Dell, Inc.
+# Copyright (C) 2020 Intel, Inc.
+# Copyright (C) 2021 Mario Limonciello
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+import os
+import sys
+import argparse
+
+WARNING = "\033[93m"
+ENDC = "\033[0m"
+
+# Minimum version of markdown required
+MINIMUM_MARKDOWN = (3, 2, 0)
+
+# Minimum meson required
+MINIMUM_MESON = "0.61.0"
+
+
+def get_possible_profiles():
+ return ["fedora", "centos", "debian", "ubuntu", "arch", "void"]
+
+
+def detect_profile():
+ try:
+ import distro
+
+ target = distro.id()
+ if not target in get_possible_profiles():
+ target = distro.like()
+ except ModuleNotFoundError:
+ target = ""
+ return target
+
+
+def pip_install_package(debug, name):
+ import subprocess
+
+ cmd = ["python3", "-m", "pip", "install", "--upgrade", name]
+ if debug:
+ print(cmd)
+ subprocess.call(cmd)
+
+
+def test_markdown(debug):
+ try:
+ import markdown
+
+ new_enough = markdown.__version_info__ >= MINIMUM_MARKDOWN
+ except ModuleNotFoundError:
+ new_enough = False
+ if not new_enough:
+ print("python3-markdown must be installed/upgraded")
+ pip_install_package(debug, "markdown")
+
+
+def test_meson(debug):
+ from importlib.metadata import version, PackageNotFoundError
+
+ try:
+ new_enough = version("meson") >= MINIMUM_MESON
+ except PackageNotFoundError:
+ import subprocess
+
+ try:
+ ver = (
+ subprocess.check_output(["meson", "--version"]).strip().decode("utf-8")
+ )
+ new_enough = ver >= MINIMUM_MESON
+ except FileNotFoundError:
+ new_enough = False
+ if not new_enough:
+ print("meson must be installed/upgraded")
+ pip_install_package(debug, "meson")
+
+
+def parse_dependencies(OS, variant, add_control):
+ import xml.etree.ElementTree as etree
+
+ deps = []
+ dep = ""
+ directory = os.path.dirname(sys.argv[0])
+ tree = etree.parse(os.path.join(directory, "dependencies.xml"))
+ root = tree.getroot()
+ for child in root:
+ if "id" not in child.attrib:
+ continue
+ for distro in child:
+ if "id" not in distro.attrib:
+ continue
+ if distro.attrib["id"] != OS:
+ continue
+ control = ""
+ if add_control:
+ inclusive = []
+ exclusive = []
+ if not distro.findall("control"):
+ continue
+ for control_parent in distro.findall("control"):
+ for obj in control_parent.findall("inclusive"):
+ inclusive.append(obj.text)
+ for obj in control_parent.findall("exclusive"):
+ exclusive.append(obj.text)
+ if inclusive or exclusive:
+ inclusive = " ".join(inclusive).strip()
+ exclusive = " !".join(exclusive).strip()
+ if exclusive:
+ exclusive = "!%s" % exclusive
+ control = " [%s%s]" % (inclusive, exclusive)
+ for package in distro.findall("package"):
+ if variant:
+ if "variant" not in package.attrib:
+ continue
+ if package.attrib["variant"] != variant:
+ continue
+ if package.text:
+ dep = package.text
+ else:
+ dep = child.attrib["id"]
+ dep += control
+ if dep:
+ deps.append(dep)
+ return deps
+
+
+def _validate_deps(os, deps):
+ validated = deps
+ if os == "debian" or os == "ubuntu":
+ try:
+ from apt import cache
+
+ cache = cache.Cache()
+ for pkg in deps:
+ if not cache.has_key(pkg) and not cache.is_virtual_package(pkg):
+ print(
+ f"{WARNING}WARNING:{ENDC} ignoring unavailable package %s" % pkg
+ )
+ validated.remove(pkg)
+ except ModuleNotFoundError:
+ print(
+ f"{WARNING}WARNING:{ENDC} Unable to validate package dependency list without python3-apt"
+ )
+ return validated
+
+
+def get_build_dependencies(os, variant):
+ parsed = parse_dependencies(os, variant, False)
+ return _validate_deps(os, parsed)
+
+
+def _get_installer_cmd(os, yes):
+ if os == "debian" or os == "ubuntu":
+ installer = ["apt", "install"]
+ elif os == "fedora":
+ installer = ["dnf", "install"]
+ elif os == "arch":
+ installer = ["pacman", "-Syu", "--noconfirm", "--needed"]
+ elif os == "void":
+ installer = ["xbps-install", "-Syu"]
+ else:
+ print("unable to detect OS profile, use --os= to specify")
+ print("\tsupported profiles: %s" % get_possible_profiles())
+ sys.exit(1)
+ if yes:
+ installer += ["-y"]
+ return installer
+
+
+def install_packages(os, variant, yes, debugging, packages):
+ import subprocess
+
+ if packages == "build-dependencies":
+ packages = get_build_dependencies(os, variant)
+ installer = _get_installer_cmd(os, yes)
+ installer += packages
+ if debugging:
+ print(installer)
+ subprocess.call(installer)
+
+
+if __name__ == "__main__":
+
+ command = None
+ # compat mode for old training documentation
+ if "generate_dependencies.py" in sys.argv[0]:
+ command = "get-dependencies"
+
+ parser = argparse.ArgumentParser()
+ if not command:
+ parser.add_argument(
+ "command",
+ choices=[
+ "get-dependencies",
+ "test-markdown",
+ "test-meson",
+ "detect-profile",
+ "install-dependencies",
+ "install-pip",
+ ],
+ help="command to run",
+ )
+ parser.add_argument(
+ "-o",
+ "--os",
+ default=detect_profile(),
+ choices=get_possible_profiles(),
+ help="calculate dependencies for OS profile",
+ )
+ parser.add_argument(
+ "-v", "--variant", help="optional machine variant for the OS profile"
+ )
+ parser.add_argument(
+ "-y", "--yes", action="store_true", help="Don't prompt to install"
+ )
+ parser.add_argument(
+ "-d", "--debug", action="store_true", help="Display all launched commands"
+ )
+ args = parser.parse_args()
+
+ # fall back in all cases
+ if not args.variant:
+ args.variant = os.uname().machine
+ if not command:
+ command = args.command
+
+ # command to run
+ if command == "test-markdown":
+ test_markdown(args.debug)
+ elif command == "test-meson":
+ test_meson(args.debug)
+ elif command == "detect-profile":
+ print(detect_profile())
+ elif command == "get-dependencies":
+ dependencies = get_build_dependencies(args.os, args.variant)
+ print(*dependencies, sep="\n")
+ elif command == "install-dependencies":
+ install_packages(
+ args.os, args.variant, args.yes, args.debug, "build-dependencies"
+ )
+ elif command == "install-pip":
+ install_packages(args.os, args.variant, args.yes, args.debug, ["python3-pip"])
diff --git a/fwupd-1.8.6/contrib/ci/generate_debian.py b/fwupd-1.8.6/contrib/ci/generate_debian.py
new file mode 100755
index 0000000000000000000000000000000000000000..3741f753ae85e333db30ca9b6c621fbafeaec266
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/generate_debian.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2017 Dell, Inc.
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+import os
+import sys
+from fwupd_setup_helpers import parse_dependencies
+
+
+def parse_control_dependencies():
+ QUBES = os.getenv("QUBES")
+ return parse_dependencies("debian", "x86_64", True), QUBES
+
+
+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, QUBES = parse_control_dependencies()
+ deps.sort()
+
+ if QUBES:
+ lines += "\n"
+ control_qubes_in = os.path.join(target, "control.qubes.in")
+ with open(control_qubes_in, "r") as rfd:
+ lines += rfd.readlines()
+
+ with open(control_out, "w") as wfd:
+ for line in lines:
+ if "Build-Depends:" in line and "%%%DYNAMIC%%%" in line:
+ wfd.write("Build-Depends:\n")
+ for i in range(0, len(deps)):
+ wfd.write("\t%s,\n" % deps[i])
+ elif "fwupd-qubes-vm-whonix" in line and not QUBES:
+ break
+ 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
+ except FileNotFoundError:
+ 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 --git a/fwupd-1.8.6/contrib/ci/generate_dependencies.py b/fwupd-1.8.6/contrib/ci/generate_dependencies.py
new file mode 120000
index 0000000000000000000000000000000000000000..cc1f5adae6f2c45841c726c1ae9e2b0bb699406a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/generate_dependencies.py
@@ -0,0 +1 @@
+fwupd_setup_helpers.py
\ No newline at end of file
diff --git a/fwupd-1.8.6/contrib/ci/generate_docker.py b/fwupd-1.8.6/contrib/ci/generate_docker.py
new file mode 100755
index 0000000000000000000000000000000000000000..ae43eae2b3f0de237b9db3dfad6437bc0a075525
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/generate_docker.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2017 Dell, Inc.
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+import os
+import subprocess
+import sys
+import shutil
+from fwupd_setup_helpers import parse_dependencies
+
+
+def get_container_cmd():
+ """return docker or podman as container manager"""
+
+ if shutil.which("docker"):
+ return "docker"
+ if shutil.which("podman"):
+ return "podman"
+
+
+directory = os.path.dirname(sys.argv[0])
+TARGET = os.getenv("OS")
+
+if TARGET is None:
+ print("Missing OS environment variable")
+ sys.exit(1)
+OS = TARGET
+SUBOS = ""
+split = TARGET.split("-")
+if len(split) >= 2:
+ OS = split[0]
+ SUBOS = split[1]
+
+deps = parse_dependencies(OS, SUBOS, False)
+
+f = os.path.join(directory, "Dockerfile-%s.in" % OS)
+if not os.path.exists(f):
+ print("Missing input file %s for %s" % (f, OS))
+ sys.exit(1)
+
+with open(f, "r") as rfd:
+ lines = rfd.readlines()
+
+with open("Dockerfile", "w") as wfd:
+ for line in lines:
+ if line.startswith("FROM %%%ARCH_PREFIX%%%"):
+ 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":
+ 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(
+ "\tDEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends\\\n"
+ )
+ elif OS == "arch":
+ wfd.write("RUN pacman -Syu --noconfirm --needed\\\n")
+ elif OS == "void":
+ wfd.write(
+ "RUN xbps-install -Suy xbps && xbps-install -uy && xbps-install -y \\\n"
+ )
+ for i in range(0, len(deps)):
+ if i < len(deps) - 1:
+ wfd.write("\t%s \\\n" % deps[i])
+ else:
+ wfd.write("\t%s || true\n" % deps[i])
+ elif line == "%%%ARCH_SPECIFIC_COMMAND%%%\n":
+ if OS == "debian" and SUBOS == "s390x":
+ # add sources
+ wfd.write(
+ 'RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list\n'
+ )
+ # add new architecture
+ wfd.write("RUN dpkg --add-architecture %s\n" % SUBOS)
+ elif line == "%%%OS%%%\n":
+ wfd.write("ENV OS %s\n" % TARGET)
+ else:
+ wfd.write(line)
+ wfd.flush()
+
+if len(sys.argv) == 2 and sys.argv[1] == "build":
+ cmd = get_container_cmd()
+ args = [cmd, "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", "./Dockerfile", "."]
+ subprocess.check_call(args)
diff --git a/fwupd-1.8.6/contrib/ci/generate_news.py b/fwupd-1.8.6/contrib/ci/generate_news.py
new file mode 100755
index 0000000000000000000000000000000000000000..9dbf0d6d78efe083ac2d54e206510b557ac8258a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/generate_news.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2020 Dell Inc.
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+import os
+import argparse
+import xml.etree.ElementTree as etree
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("version", help="Generate news for release")
+ args = parser.parse_args()
+
+ tree = etree.parse(os.path.join("data", "org.freedesktop.fwupd.metainfo.xml"))
+ root = tree.getroot()
+ for release in root.iter("release"):
+ if "version" not in release.attrib:
+ continue
+ if release.attrib["version"] != args.version:
+ continue
+ description = release.find("description")
+ result = etree.tostring(description, encoding="unicode", method="text")
+ print(result.strip())
diff --git a/fwupd-1.8.6/contrib/ci/get_test_firmware.sh b/fwupd-1.8.6/contrib/ci/get_test_firmware.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5a5b10271aa5791b04c4a3ca63f68df79db14036
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/get_test_firmware.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ "$CI_NETWORK" = "true" ]; then
+ #clone fwupd-test-firmware
+ rm -rf fwupd-test-firmware
+ git clone https://github.com/fwupd/fwupd-test-firmware
+ #copy data for self-tests into the source tree
+ cp fwupd-test-firmware/ci-tests/* . -R
+fi
diff --git a/fwupd-1.8.6/contrib/ci/oss-fuzz.py b/fwupd-1.8.6/contrib/ci/oss-fuzz.py
new file mode 100755
index 0000000000000000000000000000000000000000..ed850511230572d5fecf096ebec22746d5109381
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/oss-fuzz.py
@@ -0,0 +1,459 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2021 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# pylint: disable=too-many-instance-attributes,no-self-use
+
+import os
+import sys
+import subprocess
+import glob
+from typing import Dict, Optional, List, Union
+
+DEFAULT_BUILDDIR = ".ossfuzz"
+
+
+class Builder:
+ def __init__(self) -> None:
+
+ self.cc = self._ensure_environ("CC", "gcc")
+ self.cxx = self._ensure_environ("CXX", "g++")
+ self.builddir = self._ensure_environ("WORK", os.path.realpath(DEFAULT_BUILDDIR))
+ self.installdir = self._ensure_environ(
+ "OUT", os.path.realpath(os.path.join(DEFAULT_BUILDDIR, "out"))
+ )
+ self.srcdir = self._ensure_environ("SRC", os.path.realpath(".."))
+ self.ldflags = [
+ "-lpthread",
+ "-lresolv",
+ "-ldl",
+ "-lffi",
+ "-lz",
+ "-llzma",
+ ]
+
+ # defined in env
+ self.cflags = ["-Wno-deprecated-declarations", "-g"]
+ if "CFLAGS" in os.environ:
+ self.cflags += os.environ["CFLAGS"].split(" ")
+ self.cxxflags = []
+ if "CXXFLAGS" in os.environ:
+ self.cxxflags += os.environ["CXXFLAGS"].split(" ")
+
+ # set up shared / static
+ os.environ["PKG_CONFIG"] = "pkg-config --static"
+ if "PATH" in os.environ:
+ os.environ["PATH"] = "{}:{}".format(
+ os.environ["PATH"], os.path.join(self.builddir, "bin")
+ )
+ else:
+ os.environ["PATH"] = os.path.join(self.builddir, "bin")
+ os.environ["PKG_CONFIG_PATH"] = os.path.join(self.builddir, "lib", "pkgconfig")
+
+ # writable
+ os.makedirs(self.builddir, exist_ok=True)
+ os.makedirs(self.installdir, exist_ok=True)
+
+ def _ensure_environ(self, key: str, value: str) -> str:
+ """set the environment unless already set"""
+ if key not in os.environ:
+ os.environ[key] = value
+ return os.environ[key]
+
+ def checkout_source(self, name: str, url: str, commit: Optional[str] = None) -> str:
+ """checkout source tree, optionally to a specific commit"""
+ srcdir_name = os.path.join(self.srcdir, name)
+ if os.path.exists(srcdir_name):
+ return srcdir_name
+ subprocess.run(["git", "clone", url], cwd=self.srcdir, check=True)
+ if commit:
+ subprocess.run(["git", "checkout", commit], cwd=srcdir_name, check=True)
+ return srcdir_name
+
+ def build_meson_project(self, srcdir: str, argv) -> None:
+ """configure and build the meson project"""
+ srcdir_build = os.path.join(srcdir, DEFAULT_BUILDDIR)
+ if not os.path.exists(srcdir_build):
+ subprocess.run(
+ [
+ "meson",
+ "--prefix",
+ self.builddir,
+ "--libdir",
+ "lib",
+ "--default-library",
+ "static",
+ ]
+ + argv
+ + [DEFAULT_BUILDDIR],
+ cwd=srcdir,
+ check=True,
+ )
+ subprocess.run(["ninja", "install"], cwd=srcdir_build, check=True)
+
+ def build_cmake_project(self, srcdir: str, argv=None) -> None:
+ """configure and build the meson project"""
+ if not argv:
+ argv = []
+ srcdir_build = os.path.join(srcdir, DEFAULT_BUILDDIR)
+ if not os.path.exists(srcdir_build):
+ os.makedirs(srcdir_build, exist_ok=True)
+ subprocess.run(
+ [
+ "cmake",
+ "-DCMAKE_INSTALL_PREFIX:PATH={}".format(self.builddir),
+ "-DCMAKE_INSTALL_LIBDIR={}".format("lib"),
+ ]
+ + argv
+ + [".."],
+ cwd=srcdir_build,
+ check=True,
+ )
+ subprocess.run(["make", "all", "install"], cwd=srcdir_build, check=True)
+
+ def add_work_includedir(self, value: str) -> None:
+ """add a CFLAG"""
+ self.cflags.append("-I{}/{}".format(self.builddir, value))
+
+ def add_src_includedir(self, value: str) -> None:
+ """add a CFLAG"""
+ self.cflags.append("-I{}/{}".format(self.srcdir, value))
+
+ def add_build_ldflag(self, value: str) -> None:
+ """add a LDFLAG"""
+ self.ldflags.append(os.path.join(self.builddir, value))
+
+ def substitute(self, src: str, replacements: Dict[str, str]) -> str:
+ """map changes"""
+
+ dst = os.path.basename(src).replace(".in", "")
+ with open(os.path.join(self.srcdir, src), "r") as f:
+ blob = f.read()
+ for key in replacements:
+ blob = blob.replace(key, replacements[key])
+ with open(os.path.join(self.builddir, dst), "w") as out:
+ out.write(blob)
+ return dst
+
+ def compile(self, src: str) -> str:
+ """compile a specific source file"""
+ argv = [self.cc]
+ argv.extend(self.cflags)
+ fullsrc = os.path.join(self.srcdir, src)
+ if not os.path.exists(fullsrc):
+ fullsrc = os.path.join(self.builddir, src)
+ dst = os.path.basename(src).replace(".c", ".o")
+ argv.extend(["-c", fullsrc, "-o", os.path.join(self.builddir, dst)])
+ print("building {} into {}".format(src, dst))
+ try:
+ subprocess.run(argv, cwd=self.srcdir, check=True)
+ except subprocess.CalledProcessError as e:
+ print(e)
+ sys.exit(1)
+ return os.path.join(self.builddir, "{}".format(dst))
+
+ def link(self, objs: List[str], dst: str) -> None:
+ """link multiple obects into a binary"""
+ argv = [self.cxx] + self.cxxflags
+ for obj in objs:
+ if obj.startswith("-"):
+ argv.append(obj)
+ else:
+ argv.append(os.path.join(self.builddir, obj))
+ argv += ["-o", os.path.join(self.installdir, dst)]
+ argv += self.ldflags
+ print("building {} into {}".format(",".join(objs), dst))
+ subprocess.run(argv, cwd=self.srcdir, check=True)
+
+ def mkfuzztargets(self, globstr: str) -> None:
+ """make binary fuzzing targets from builder.xml files"""
+ builder_xmls = glob.glob(globstr)
+ if not builder_xmls:
+ print("failed to find {}".format(globstr))
+ sys.exit(1)
+ for fn_src in builder_xmls:
+ fn_dst = fn_src.replace(".builder.xml", ".bin")
+ if os.path.exists(fn_dst):
+ continue
+ print("building {} into {}".format(fn_src, fn_dst))
+ try:
+ argv = [
+ "build/src/fwupdtool",
+ "firmware-build",
+ fn_src,
+ fn_dst,
+ ]
+ subprocess.run(argv, check=True)
+ except subprocess.CalledProcessError as e:
+ print("tried to run: `{}` and got {}".format(" ".join(argv), str(e)))
+ sys.exit(1)
+
+ def write_header(
+ self, dst: str, defines: Dict[str, Optional[Union[str, int]]]
+ ) -> None:
+ """write a header file"""
+ dstdir = os.path.join(self.builddir, os.path.dirname(dst))
+ os.makedirs(dstdir, exist_ok=True)
+ print("writing {}".format(dst))
+ with open(os.path.join(dstdir, os.path.basename(dst)), "w") as f:
+ for key in defines:
+ value = defines[key]
+ if value is not None:
+ if isinstance(value, int):
+ f.write("#define {} {}\n".format(key, value))
+ else:
+ f.write('#define {} "{}"\n'.format(key, value))
+ else:
+ f.write("#define {}\n".format(key))
+ self.add_work_includedir(os.path.dirname(dst))
+
+ def makezip(self, dst: str, globstr: str) -> None:
+ """create a zip file archive from a glob"""
+ argv = ["zip", "--junk-paths", os.path.join(self.installdir, dst)] + glob.glob(
+ os.path.join(self.srcdir, globstr)
+ )
+ print("assembling {}".format(dst))
+ subprocess.run(argv, cwd=self.srcdir, check=True)
+
+ def grep_meson(self, src: str, token: str = "fuzzing") -> List[str]:
+ """find source files tagged with a specific comment"""
+ srcs = []
+ with open(os.path.join(self.srcdir, src, "meson.build"), "r") as f:
+ for line in f.read().split("\n"):
+ if line.find(token) == -1:
+ continue
+
+ # get rid of token
+ line = line.split("#")[0]
+
+ # get rid of variable
+ try:
+ line = line.split("=")[1]
+ except IndexError:
+ pass
+
+ # get rid of whitespace
+ for char in ["'", ",", " "]:
+ line = line.replace(char, "")
+
+ # all done
+ srcs.append(os.path.join(src, line))
+ return srcs
+
+
+class Fuzzer:
+ def __init__(self, name, srcdir=None, globstr=None, pattern=None) -> None:
+
+ self.name = name
+ self.srcdir = srcdir or name
+ self.globstr = globstr or "{}*.bin".format(name)
+ self.pattern = pattern or "{}-firmware".format(name)
+
+ @property
+ def new_gtype(self) -> str:
+ return "fu_{}_new".format(self.pattern).replace("-", "_")
+
+ @property
+ def header(self) -> str:
+ return "fu-{}.h".format(self.pattern)
+
+
+def _build(bld: Builder) -> None:
+
+ # CBOR
+ src = bld.checkout_source(
+ "libcbor", url="https://github.com/PJK/libcbor.git", commit="v0.9.0"
+ )
+ bld.build_cmake_project(src)
+ bld.add_build_ldflag("lib/libcbor.a")
+
+ # GLib
+ src = bld.checkout_source(
+ "glib", url="https://gitlab.gnome.org/GNOME/glib.git", commit="glib-2-68"
+ )
+ bld.build_meson_project(
+ src,
+ [
+ "-Dlibmount=disabled",
+ "-Dselinux=disabled",
+ "-Dnls=disabled",
+ "-Dlibelf=disabled",
+ "-Dbsymbolic_functions=false",
+ "-Dtests=false",
+ "-Dinternal_pcre=true",
+ "--force-fallback-for=libpcre",
+ ],
+ )
+ bld.add_work_includedir("include/glib-2.0")
+ bld.add_work_includedir("lib/glib-2.0/include")
+ bld.add_build_ldflag("lib/libgio-2.0.a")
+ bld.add_build_ldflag("lib/libgmodule-2.0.a")
+ bld.add_build_ldflag("lib/libgobject-2.0.a")
+ bld.add_build_ldflag("lib/libglib-2.0.a")
+ bld.add_build_ldflag("lib/libgthread-2.0.a")
+
+ # JSON-GLib
+ src = bld.checkout_source(
+ "json-glib", url="https://gitlab.gnome.org/GNOME/json-glib.git"
+ )
+ bld.build_meson_project(
+ src, ["-Dgtk_doc=disabled", "-Dtests=false", "-Dintrospection=disabled"]
+ )
+ bld.add_work_includedir("include/json-glib-1.0/json-glib")
+ bld.add_work_includedir("include/json-glib-1.0")
+ bld.add_build_ldflag("lib/libjson-glib-1.0.a")
+
+ # libxmlb
+ src = bld.checkout_source("libxmlb", url="https://github.com/hughsie/libxmlb.git")
+ bld.build_meson_project(
+ src, ["-Dgtkdoc=false", "-Dintrospection=false", "-Dtests=false"]
+ )
+ bld.add_work_includedir("include/libxmlb-2")
+ bld.add_work_includedir("include/libxmlb-2/libxmlb")
+ bld.add_build_ldflag("lib/libxmlb.a")
+
+ # write required headers
+ bld.write_header("libfwupd/fwupd-version.h", {})
+ bld.write_header(
+ "config.h",
+ {
+ "FWUPD_DATADIR": "/tmp",
+ "FWUPD_LOCALSTATEDIR": "/tmp",
+ "FWUPD_LIBDIR_PKG": "/tmp",
+ "FWUPD_SYSCONFDIR": "/tmp",
+ "HAVE_REALPATH": None,
+ "PACKAGE_NAME": "fwupd",
+ "PACKAGE_VERSION": "0.0.0",
+ },
+ )
+ bld.write_header(
+ "libfwupdplugin/fu-version.h",
+ {
+ "FU_MAJOR_VERSION": 0,
+ "FU_MINOR_VERSION": 0,
+ "FU_MICRO_VERSION": 0,
+ },
+ )
+
+ # libfwupd + libfwupdplugin
+ built_objs: List[str] = []
+ bld.add_src_includedir("fwupd")
+ for path in ["fwupd/libfwupd", "fwupd/libfwupdplugin"]:
+ bld.add_src_includedir(path)
+ for src in bld.grep_meson(path):
+ built_objs.append(bld.compile(src))
+
+ # dummy binary entrypoint
+ if "LIB_FUZZING_ENGINE" in os.environ:
+ built_objs.append(os.environ["LIB_FUZZING_ENGINE"])
+ else:
+ built_objs.append(bld.compile("fwupd/libfwupdplugin/fu-fuzzer-main.c"))
+
+ # built in formats
+ for fzr in [
+ Fuzzer("dfuse"),
+ Fuzzer("fdt"),
+ Fuzzer("fit"),
+ Fuzzer("fmap"),
+ Fuzzer("ihex"),
+ Fuzzer("srec"),
+ Fuzzer("intel-thunderbolt"),
+ Fuzzer("ifwi-cpd"),
+ Fuzzer("ifwi-fpt"),
+ Fuzzer("oprom"),
+ Fuzzer("uswid"),
+ Fuzzer("efi-firmware-filesystem", pattern="efi-firmware-filesystem"),
+ Fuzzer("efi-firmware-volume", pattern="efi-firmware-volume"),
+ Fuzzer("ifd"),
+ ]:
+ src = bld.substitute(
+ "fwupd/libfwupdplugin/fu-fuzzer-firmware.c.in",
+ {
+ "@FIRMWARENEW@": fzr.new_gtype,
+ "@INCLUDE@": os.path.join("libfwupdplugin", fzr.header),
+ },
+ )
+ bld.link([bld.compile(src)] + built_objs, "{}_fuzzer".format(fzr.name))
+ bld.mkfuzztargets(
+ os.path.join(
+ bld.srcdir,
+ "fwupd",
+ "libfwupdplugin",
+ "tests",
+ "{}*.builder.xml".format(fzr.name),
+ )
+ )
+ bld.makezip(
+ "{}_fuzzer_seed_corpus.zip".format(fzr.name),
+ "fwupd/libfwupdplugin/tests/{}".format(fzr.globstr),
+ )
+
+ # plugins
+ for fzr in [
+ Fuzzer("acpi-phat", pattern="acpi-phat"),
+ Fuzzer("bcm57xx"),
+ Fuzzer("ccgx-dmc", srcdir="ccgx", globstr="ccgx-dmc*.bin"),
+ Fuzzer("ccgx"),
+ Fuzzer("cros-ec"),
+ Fuzzer("ebitdo"),
+ Fuzzer("elanfp"),
+ Fuzzer("elantp"),
+ Fuzzer("genesys-scaler", srcdir="genesys", pattern="genesys-scaler-firmware"),
+ Fuzzer("genesys-usbhub", srcdir="genesys", pattern="genesys-usbhub-firmware"),
+ Fuzzer("pixart", srcdir="pixart-rf", pattern="pxi-firmware"),
+ Fuzzer("redfish-smbios", srcdir="redfish", pattern="redfish-smbios"),
+ Fuzzer("synaptics-prometheus", pattern="synaprom-firmware"),
+ Fuzzer("synaptics-cape"),
+ Fuzzer("synaptics-mst"),
+ Fuzzer("synaptics-rmi"),
+ Fuzzer("uf2"),
+ Fuzzer("wacom-usb", pattern="wac-firmware"),
+ ]:
+ fuzz_objs = []
+ for obj in bld.grep_meson("fwupd/plugins/{}".format(fzr.srcdir)):
+ fuzz_objs.append(bld.compile(obj))
+ src = bld.substitute(
+ "fwupd/libfwupdplugin/fu-fuzzer-firmware.c.in",
+ {
+ "@FIRMWARENEW@": fzr.new_gtype,
+ "@INCLUDE@": os.path.join("plugins", fzr.srcdir, fzr.header),
+ },
+ )
+ fuzz_objs.append(bld.compile(src))
+ bld.link(fuzz_objs + built_objs, "{}_fuzzer".format(fzr.name))
+ bld.mkfuzztargets(
+ os.path.join(
+ bld.srcdir,
+ "fwupd",
+ "plugins",
+ fzr.srcdir,
+ "tests",
+ "{}*.builder.xml".format(fzr.name),
+ )
+ )
+ bld.makezip(
+ "{}_fuzzer_seed_corpus.zip".format(fzr.name),
+ "fwupd/plugins/{}/tests/{}".format(fzr.srcdir, fzr.globstr),
+ )
+
+
+if __name__ == "__main__":
+
+ # install missing deps here rather than patching the Dockerfile in oss-fuzz
+ try:
+ subprocess.check_call(
+ ["apt-get", "install", "-y", "liblzma-dev", "libcbor-dev"],
+ stdout=open(os.devnull, "wb"),
+ )
+ except FileNotFoundError:
+ pass
+ except subprocess.CalledProcessError as e:
+ print(e.output)
+ sys.exit(1)
+
+ _builder = Builder()
+ _build(_builder)
+ sys.exit(0)
diff --git a/fwupd-1.8.6/contrib/ci/populate-bios-setting-translations.py b/fwupd-1.8.6/contrib/ci/populate-bios-setting-translations.py
new file mode 100755
index 0000000000000000000000000000000000000000..126ae72264ab998ea3573da56025de3b51ad092b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/populate-bios-setting-translations.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python3
+#
+# Helper script to generate a list of translations
+# Sample call:
+# ./contrib/ci/populate-bios-attr-translations.py ./libfwupdplugin/tests/bios-attrs/dell-xps13-9310/
+# will lead to ./libfwupdplugin/tests/bios-attrs/dell-xps13-9310/strings.txt
+# which can be added to po/POTFILES.in
+#
+# Copyright (C) 2022 Mario Limonciello
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import os
+import sys
+
+
+def populate_translations(path):
+ output = open(os.path.join(path, "strings.txt"), "w")
+ for root, _, files in os.walk(path):
+ for file in files:
+ val: str = ""
+ if not file.endswith("display_name"):
+ continue
+ with open(os.path.join(root, file), "r") as f:
+ val = f.read().replace('"', "").strip()
+ if not val:
+ continue
+ output.write("#TRANSLATORS: Description of BIOS setting\n")
+ output.write("%s\n\n" % val)
+ output.close()
+
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ print("path to bios settings directory required")
+ sys.exit(1)
+ populate_translations(sys.argv[1])
diff --git a/fwupd-1.8.6/contrib/ci/qt5-thread-test/meson.build b/fwupd-1.8.6/contrib/ci/qt5-thread-test/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..6d1525dbd63f3c128447f7867f1c280c067b5ee7
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/qt5-thread-test/meson.build
@@ -0,0 +1,25 @@
+project('qt5-thread-test', 'cpp',
+ license: 'LGPL-2.1+',
+)
+add_project_arguments('-fPIC', language: 'cpp')
+qt5core = dependency('Qt5Core')
+qt5concurrent = dependency('Qt5Concurrent')
+glib2 = dependency('glib-2.0')
+gio2 = dependency('gio-2.0')
+fwupd = dependency('fwupd')
+env = environment()
+env.set('G_DEBUG', 'fatal-criticals')
+e = executable(
+ 'qt-thread-test',
+ sources: [
+ 'qt-thread-test.cpp'
+ ],
+ dependencies: [
+ qt5core,
+ qt5concurrent,
+ glib2,
+ gio2,
+ fwupd,
+ ],
+)
+test('qt-thread-test', e, timeout: 60, env: env)
diff --git a/fwupd-1.8.6/contrib/ci/qt5-thread-test/qt-thread-test.cpp b/fwupd-1.8.6/contrib/ci/qt5-thread-test/qt-thread-test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..daa6cb2e44d894720157377d201e9c373c683721
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/qt5-thread-test/qt-thread-test.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 Aleix Pol
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include
+
+#include
+#include
+#include
+
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+
+ auto client = fwupd_client_new();
+ auto cancellable = g_cancellable_new();
+ g_autoptr(GError) error = nullptr;
+
+ auto fw = new QFutureWatcher(&app);
+ QObject::connect(fw, &QFutureWatcher::finished, [fw]() {
+ QCoreApplication::exit(0);
+ });
+ fw->setFuture(QtConcurrent::run([&] {
+ return fwupd_client_get_devices(client, cancellable, &error);
+ }));
+
+ return app.exec();
+}
diff --git a/fwupd-1.8.6/contrib/ci/s390x_cross.txt b/fwupd-1.8.6/contrib/ci/s390x_cross.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c7c0e143a7d9b9dc1f37faa619951af7e98e1aa6
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/s390x_cross.txt
@@ -0,0 +1,13 @@
+[binaries]
+c = 's390x-linux-gnu-gcc'
+cpp = 's390x-linux-gnu-cpp'
+ar = 's390x-linux-gnu-ar'
+strip = 's390x-linux-gnu-strip'
+pkgconfig = 's390x-linux-gnu-pkg-config'
+exe_wrapper = 'qemu-s390x'
+
+[host_machine]
+system = 'linux'
+cpu_family = 's390x'
+cpu = 's390x'
+endian = 'big'
diff --git a/fwupd-1.8.6/contrib/ci/snap.sh b/fwupd-1.8.6/contrib/ci/snap.sh
new file mode 100755
index 0000000000000000000000000000000000000000..997660e226122cca918524109a39d36d33127152
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/snap.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -e
+
+mkdir -p /build
+cd /build
+snapcraft
diff --git a/fwupd-1.8.6/contrib/ci/snapcraft-wrapper b/fwupd-1.8.6/contrib/ci/snapcraft-wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..0072ed079689439b4b3f9f5b23ed251a6668fb11
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/snapcraft-wrapper
@@ -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 --git a/fwupd-1.8.6/contrib/ci/ubuntu.sh b/fwupd-1.8.6/contrib/ci/ubuntu.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c70a1b6eb7152c765f8dbc5989de0e8a8659960b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/ubuntu.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+set -e
+set -x
+
+#check for and install missing dependencies
+./contrib/ci/fwupd_setup_helpers.py install-dependencies --yes -o ubuntu
+
+#check we have pip
+./contrib/ci/fwupd_setup_helpers.py install-pip --yes -o ubuntu
+
+#check meson is new enough
+./contrib/ci/fwupd_setup_helpers.py test-meson
+
+#check markdown is new enough
+./contrib/ci/fwupd_setup_helpers.py test-markdown
+
+#clone test firmware if necessary
+. ./contrib/ci/get_test_firmware.sh
+
+#evaluate using Ubuntu's buildflags
+#evaluate using Debian/Ubuntu's buildflags
+#disable link time optimization, Ubuntu currently only sets it for GCC
+export DEB_BUILD_MAINT_OPTIONS="optimize=-lto"
+eval "$(dpkg-buildflags --export=sh)"
+#filter out -Bsymbolic-functions
+LDFLAGS=$(dpkg-buildflags --get LDFLAGS | sed "s/-Wl,-Bsymbolic-functions\s//")
+export LDFLAGS
+
+root=$(pwd)
+rm -rf ${root}/build
+chown -R nobody ${root}
+sudo -u nobody meson ${root}/build -Dman=false -Ddocs=enabled -Dgusb:tests=false --prefix=${root}/dist
+#build with clang
+sudo -u nobody ninja -C ${root}/build test -v
+
+#make docs available outside of docker
+ninja -C ${root}/build install -v
diff --git a/fwupd-1.8.6/contrib/ci/void.sh b/fwupd-1.8.6/contrib/ci/void.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f1957e3cee5029823d79788d0a48763b103e791e
--- /dev/null
+++ b/fwupd-1.8.6/contrib/ci/void.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+set -e
+set -x
+
+#install dependencies
+xbps-install -Suy python3
+./contrib/ci/fwupd_setup_helpers.py install-dependencies --yes -o void
+
+#clone test firmware if necessary
+. ./contrib/ci/get_test_firmware.sh
+
+#build
+rm -rf build
+meson build \
+ -Dgusb:tests=false \
+ -Dgcab:docs=false \
+ -Dconsolekit=disabled \
+ -Dsystemd=disabled \
+ -Doffline=disabled \
+ -Delogind=enabled
+ninja -C build test -v
diff --git a/fwupd-1.8.6/contrib/codespell.cfg b/fwupd-1.8.6/contrib/codespell.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..0de0d9896c1a784721162ce8d030f6d131b6646d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/codespell.cfg
@@ -0,0 +1,4 @@
+[codespell]
+builtin = clear,informal,en-GB_to_en-US
+skip = *.po,*.csv,*.svg,*.p7c,subprojects,.git,pcrs,build*,.ossfuzz,*/tests/*
+ignore-words-list = conexant,Conexant,gir,GIR,hsi,HSI,cancelled,Cancelled,te
diff --git a/fwupd-1.8.6/contrib/debian/README.Debian b/fwupd-1.8.6/contrib/debian/README.Debian
new file mode 100644
index 0000000000000000000000000000000000000000..9dc82b53429790e88345fbf91d88190539038a41
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/README.Debian
@@ -0,0 +1,18 @@
+signed vs unsigned fwupd programs
+------------------------------------
+
+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.
+
diff --git a/fwupd-1.8.6/contrib/debian/README.source b/fwupd-1.8.6/contrib/debian/README.source
new file mode 100644
index 0000000000000000000000000000000000000000..85620815eb492707da42bf299ade020986990012
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/README.source
@@ -0,0 +1,9 @@
+fwupd for Debian
+----------------
+
+To build from the git tree, run:
+ git-buildpackage -us -uc -S
+Then, if using sbuild, you can use something like:
+ sbuild -s -c sid-amd64 -d unstable
+
+ -- Daniel Jared Dominguez Thu, 21 May 2015 13:44:16 -0500
diff --git a/fwupd-1.8.6/contrib/debian/clean b/fwupd-1.8.6/contrib/debian/clean
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/clean
@@ -0,0 +1 @@
+
diff --git a/fwupd-1.8.6/contrib/debian/compat b/fwupd-1.8.6/contrib/debian/compat
new file mode 100644
index 0000000000000000000000000000000000000000..48082f72f087ce7e6fa75b9c41d7387daecd447b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/compat
@@ -0,0 +1 @@
+12
diff --git a/fwupd-1.8.6/contrib/debian/control.in b/fwupd-1.8.6/contrib/debian/control.in
new file mode 100644
index 0000000000000000000000000000000000000000..85d1af4b42d81a868ee4aa0b5647bc5b43d8b6c0
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/control.in
@@ -0,0 +1,140 @@
+Source: fwupd
+Priority: optional
+Maintainer: Debian EFI
+Uploaders: Steve McIntyre <93sam@debian.org>,
+ Matthias Klumpp ,
+ Mario Limonciello
+Build-Depends: %%%DYNAMIC%%%
+Build-Depends-Indep: gi-docgen ,
+ libglib2.0-doc ,
+Rules-Requires-Root: no
+Standards-Version: 4.6.0.1
+Section: admin
+Homepage: https://github.com/fwupd/fwupd
+Vcs-Git: https://salsa.debian.org/efi-team/fwupd.git
+Vcs-Browser: https://salsa.debian.org/efi-team/fwupd
+
+Package: libfwupd2
+Section: libs
+Architecture: linux-any
+Depends: ${misc:Depends},
+ ${shlibs:Depends}
+Multi-Arch: same
+Description: Firmware update daemon library
+ 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.
+ Firmware updates are supported for a variety of technologies.
+ See for details
+ .
+ This package provides the library used by the daemon.
+
+Package: fwupd
+Architecture: linux-any
+Depends: ${misc:Depends},
+ ${shlibs:Depends},
+ adduser,
+ shared-mime-info
+Recommends: python3,
+ bolt,
+ dbus,
+ secureboot-db,
+ udisks2,
+ fwupd-signed,
+ jq
+Suggests: gir1.2-fwupd-2.0
+Provides: fwupdate
+Conflicts: fwupdate-amd64-signed,
+ fwupdate-i386-signed,
+ fwupdate-arm64-signed,
+ fwupdate-armhf-signed
+Breaks: gir1.2-dfu-1.0 (<< 0.9.7-1),
+ libdfu1 (<< 0.9.7-1),
+ fwupdate (<< 12-7),
+ libdfu-dev (<< 0.9.7-1)
+Replaces: gir1.2-dfu-1.0 (<< 0.9.7-1),
+ libdfu1 (<< 0.9.7-1),
+ libdfu-dev (<< 0.9.7-1),
+ fwupdate (<< 12-7)
+Multi-Arch: foreign
+Description: Firmware update daemon
+ 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.
+ Firmware updates are supported for a variety of technologies.
+ See for details
+
+Package: fwupd-tests
+Architecture: linux-any
+Depends: ${misc:Depends},
+ ${shlibs:Depends},
+ ca-certificates,
+ dbus-x11,
+ fwupd,
+ gnome-desktop-testing,
+ policykit-1,
+ python3,
+ python3-gi,
+ python3-requests,
+Breaks: fwupd (<< 0.9.4-1)
+Replaces: fwupd (<< 0.9.4-1)
+Multi-Arch: foreign
+Description: Test suite for firmware update daemon
+ 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.
+ 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
+ the daemon in a continuous integration system.
+
+Package: fwupd-doc
+Section: doc
+Architecture: all
+Multi-Arch: foreign
+Depends: ${misc:Depends},
+Build-Profiles:
+Description: Firmware update daemon documentation (HTML format)
+ 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.
+ Firmware updates are supported for a variety of technologies.
+ See for details
+ .
+ This package provides development documentation for creating a package that
+ uses fwupd.
+
+Package: libfwupd-dev
+Architecture: linux-any
+Multi-Arch: same
+Depends: libfwupd2 (= ${binary:Version}),
+ gir1.2-fwupd-2.0 (= ${binary:Version}),
+ libcurl4-gnutls-dev,
+ libglib2.0-dev (>= 2.45.8),
+ libjcat-dev,
+ libjson-glib-dev (>= 1.1.1),
+ ${misc:Depends}
+Breaks: fwupd-dev (<< 0.5.4-2~)
+Replaces: fwupd-dev (<< 0.5.4-2~)
+Section: libdevel
+Description: development files for libfwupd
+ 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.
+ Firmware updates are supported for a variety of technologies.
+ See for details
+ .
+ This package provides the development files for libfwupd
+
+Package: gir1.2-fwupd-2.0
+Architecture: linux-any
+Multi-Arch: same
+Depends: ${misc:Depends},
+ ${gir:Depends}
+Section: introspection
+Description: GObject introspection data for libfwupd
+ This package provides the introspection data for libfwupd.
+ .
+ It can be used by packages using the GIRepository format to generate
+ dynamic bindings.
\ No newline at end of file
diff --git a/fwupd-1.8.6/contrib/debian/control.qubes.in b/fwupd-1.8.6/contrib/debian/control.qubes.in
new file mode 100644
index 0000000000000000000000000000000000000000..03ab18b90b4669517ff0008390390fe706994844
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/control.qubes.in
@@ -0,0 +1,4 @@
+Package: fwupd-qubes-vm-whonix
+Architecture: amd64
+Description: Whonix support for Qubes OS
+ This package is used to download firmware updates and metadata via TOR.
diff --git a/fwupd-1.8.6/contrib/debian/copyright.in b/fwupd-1.8.6/contrib/debian/copyright.in
new file mode 100644
index 0000000000000000000000000000000000000000..2849465834728519ab7721fab59818f2e4c92df2
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/copyright.in
@@ -0,0 +1,140 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: fwupd
+Source: https://github.com/fwupd/fwupd
+
+%%%DYNAMIC%%%
+Files: *.metainfo.xml
+Copyright: 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".
+
+
+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 --git a/fwupd-1.8.6/contrib/debian/docs b/fwupd-1.8.6/contrib/debian/docs
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/docs
@@ -0,0 +1 @@
+
diff --git a/fwupd-1.8.6/contrib/debian/fwupd-doc.links b/fwupd-1.8.6/contrib/debian/fwupd-doc.links
new file mode 100644
index 0000000000000000000000000000000000000000..9d0a00d2b409e3e4f6542d9cf35df9d238f18d56
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-doc.links
@@ -0,0 +1,2 @@
+usr/share/doc/libfwupd /usr/share/gtk-doc/html/libfwupd
+usr/share/doc/libfwupdplugin /usr/share/gtk-doc/html/libfwupdplugin
diff --git a/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.install b/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.install
new file mode 100644
index 0000000000000000000000000000000000000000..6f64b6ca16caaadb6de3f06ab81e0c74b8e2e486
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.install
@@ -0,0 +1,2 @@
+usr/libexec/qubes-fwupd/fwupd_download_updates.py
+usr/libexec/qubes-fwupd/fwupd_common_vm.py
diff --git a/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.postinst b/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.postinst
new file mode 100644
index 0000000000000000000000000000000000000000..6d8d203b34ca212c7d858dc6d40c5b64d5de3fdf
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.postinst
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+HOME_DIR=`getent passwd user | awk '{ split($$0,a,":"); print a[6]}'`
+
+if [ -z "$HOME_DIR" ]; then
+ echo "Default user does not exist!!" >&2
+ echo "Package does not create fwupd directories" >&2
+else
+ mkdir -p $HOME_DIR/.cache/fwupd_download_updates
+ chown -R user:user $HOME_DIR/.cache/fwupd_download_updates
+fi
diff --git a/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.postrm b/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.postrm
new file mode 100644
index 0000000000000000000000000000000000000000..ac210c073f62c2149b5c787b88f5d37c0d6fa8aa
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-qubes-vm-whonix.postrm
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+HOME_DIR=`getent passwd user | awk '{ split($$0,a,":"); print a[6]}'`
+
+if [ -z "$HOME_DIR" ] && [ "$1" = "purge" ]; then
+ rm -rf $HOME_DIR/.cache/fwupd
+fi
diff --git a/fwupd-1.8.6/contrib/debian/fwupd-tests.install b/fwupd-1.8.6/contrib/debian/fwupd-tests.install
new file mode 100644
index 0000000000000000000000000000000000000000..f1bd212994d98625e848a23ec96e3f233c262670
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-tests.install
@@ -0,0 +1,10 @@
+#These are in a generic looking directory because
+#that is where gnome-desktop-testing expects to
+#find them. for more information see:
+#https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872458
+usr/share/installed-tests/*
+usr/share/fwupd/device-tests/*.json
+usr/libexec/installed-tests/fwupd/fwupd.sh
+usr/libexec/installed-tests/fwupd/*-self-test
+debian/lintian/fwupd-tests usr/share/lintian/overrides
+etc/fwupd/remotes.d/fwupd-tests.conf
diff --git a/fwupd-1.8.6/contrib/debian/fwupd-tests.postinst b/fwupd-1.8.6/contrib/debian/fwupd-tests.postinst
new file mode 100644
index 0000000000000000000000000000000000000000..81a462c455de72afaa964d3bee0b9860f71f07f3
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-tests.postinst
@@ -0,0 +1,23 @@
+#!/bin/sh
+set -e
+
+#DEBHELPER#
+
+#only enable on installation not upgrade
+if [ "$1" = configure ] && [ -z "$2" ]; then
+ if [ -f /etc/fwupd/daemon.conf ]; then
+ if [ "$CI" = "true" ]; then
+ sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf
+ else
+ 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 --git a/fwupd-1.8.6/contrib/debian/fwupd-tests.postrm b/fwupd-1.8.6/contrib/debian/fwupd-tests.postrm
new file mode 100644
index 0000000000000000000000000000000000000000..c43835526d90892b53672e69e99147db4d5d108c
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd-tests.postrm
@@ -0,0 +1,14 @@
+#!/bin/sh
+set -e
+
+#DEBHELPER#
+
+if [ "$1" = remove -o "$1" = purge ]; then
+ if [ -f /etc/fwupd/daemon.conf ]; then
+ if [ "$CI" = "true" ]; then
+ sed "s,^DisabledPlugins=,DisabledPlugins=test," -i /etc/fwupd/daemon.conf
+ else
+ echo "To disable test suite, modify /etc/fwupd/daemon.conf"
+ fi
+ fi
+fi
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.dirs b/fwupd-1.8.6/contrib/debian/fwupd.dirs
new file mode 100644
index 0000000000000000000000000000000000000000..a7c32e1dcd3d7708ca1e4e5df70e3ac5a856f6bf
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.dirs
@@ -0,0 +1 @@
+var/cache/app-info/xmls
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.install b/fwupd-1.8.6/contrib/debian/fwupd.install
new file mode 100644
index 0000000000000000000000000000000000000000..e1d5abcd914bd67771e9bb717f746af3a00124ec
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.install
@@ -0,0 +1,23 @@
+usr/bin/*
+etc/*
+usr/share/bash-completion
+usr/share/fish/vendor_completions.d
+usr/share/fwupd/*.*
+usr/share/fwupd/metainfo/*
+usr/share/fwupd/remotes.d/*
+usr/share/dbus-1/*
+usr/share/icons/*
+usr/share/polkit-1/*
+usr/share/locale
+usr/share/metainfo/*
+usr/libexec/fwupd/*
+usr/share/man/man1/*
+lib/systemd/system/*
+lib/systemd/system-preset/*
+lib/systemd/system-shutdown/*
+lib/udev/rules.d/*
+data/daemon.conf etc/fwupd
+debian/fwupd.pkla /var/lib/polkit-1/localauthority/10-vendor.d
+usr/lib/*/fwupd-*/*.so
+debian/lintian/fwupd usr/share/lintian/overrides
+obj*/data/motd/85-fwupd /etc/update-motd.d
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.maintscript b/fwupd-1.8.6/contrib/debian/fwupd.maintscript
new file mode 100644
index 0000000000000000000000000000000000000000..fb26d1bd79978db04c0808e19a714db74db0036c
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.maintscript
@@ -0,0 +1,6 @@
+
+rm_conffile /etc/fwupd.conf 1.0.0~
+rm_conffile /etc/fwupd/remotes.d/fwupd.conf 1.2.7~
+rm_conffile /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~
+rm_conffile /etc/modules-load.d/fwupd-msr.conf 1.5.3~
+rm_conffile /etc/modules-load.d/fwupd-platform-integrity.conf 1.5.3~
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.pkla b/fwupd-1.8.6/contrib/debian/fwupd.pkla
new file mode 100644
index 0000000000000000000000000000000000000000..834fda570fb408b59ccb0b14acaa170ceb79c128
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.pkla
@@ -0,0 +1,5 @@
+[Call internal fwupd actions]
+Identity=unix-group:admin;unix-group:sudo
+Action=org.freedesktop.fwupd.update-internal
+ResultActive=yes
+
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.postinst b/fwupd-1.8.6/contrib/debian/fwupd.postinst
new file mode 100644
index 0000000000000000000000000000000000000000..02f2827830aa103cb50875888f850501d179c46f
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.postinst
@@ -0,0 +1,57 @@
+#!/bin/sh
+set -e
+
+#DEBHELPER#
+
+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~ -- "$@"
+ dpkg-maintscript-helper rm_conffile \
+ /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@"
+ dpkg-maintscript-helper rm_conffile \
+ /etc/fwupd/ata.conf 1.5.5~ -- "$@"
+fi
+
+#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf
+if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then
+ ORIGINAL=/etc/fwupd/uefi.conf
+ NEW=/etc/fwupd/uefi_capsule.conf
+ #If already upgraded this file won't exist
+ #If in the middle of an upgrade:
+ # -> If unmodified then preinst would have renamed to /etc/fwupd/uefi.conf.dpkg-remove
+ # -> If modified, we need to do an in-place upgrade with sed
+ if [ -f $ORIGINAL ]; then
+ sed "s,\[uefi\],\[uefi_capsule\]," -i $ORIGINAL
+ fi
+ dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@"
+fi
+
+# Clean up from fwupdate->fwupd transition
+# This can be removed after bullseye and focal are released
+EFIDIR=$(awk '/^ID=/ {gsub(/"/,""); split($$0,a,"="); print tolower(a[2])}' /etc/os-release)
+if [ "${DPKG_MAINTSCRIPT_ARCH}" = "amd64" ]; then
+ EFI_NAME=x64
+elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "i386" ]; then
+ EFI_NAME=ia32
+elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "arm64" ]; then
+ EFI_NAME=aa64
+elif [ "${DPKG_MAINTSCRIPT_ARCH}" = "armhf" ]; then
+ EFI_NAME=arm
+fi
+rm -f /boot/efi/EFI/$EFIDIR/fwup$EFI_NAME.efi
+rm -f /var/lib/fwupdate/done
+rm -f /var/cache/fwupdate/done
+for dir in /var/cache/fwupdate /var/lib/fwupdate; do
+ if [ -d $dir ]; then
+ rmdir --ignore-fail-on-non-empty $dir || true
+ fi
+done
+
+#create a user for fwupd-refresh.service/fwupd-refresh.timer
+adduser --quiet --system --group --no-create-home --home /run/systemd \
+ --gecos "fwupd-refresh user" fwupd-refresh
+if [ -d /run/systemd/system ]; then
+ deb-systemd-invoke reload dbus || true
+fi
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.postrm b/fwupd-1.8.6/contrib/debian/fwupd.postrm
new file mode 100644
index 0000000000000000000000000000000000000000..2610c625f1d22022130983d1b7e1bf1f662a45ee
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.postrm
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+#DEBHELPER#
+
+if [ "$1" = purge ]; then
+ rm -rf /var/lib/fwupd/gnupg
+ rm -f /var/cache/app-info/xmls/fwupd.xml
+fi
+
+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~ -- "$@"
+ dpkg-maintscript-helper rm_conffile \
+ /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@"
+ dpkg-maintscript-helper rm_conffile \
+ /etc/fwupd/ata.conf 1.5.5~ -- "$@"
+fi
+
+#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf
+if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then
+ ORIGINAL=/etc/fwupd/uefi.conf
+ NEW=/etc/fwupd/uefi_capsule.conf
+ dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@"
+fi
diff --git a/fwupd-1.8.6/contrib/debian/fwupd.preinst b/fwupd-1.8.6/contrib/debian/fwupd.preinst
new file mode 100644
index 0000000000000000000000000000000000000000..51ee2e2bf7552aa6710b37276615017321beefae
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/fwupd.preinst
@@ -0,0 +1,29 @@
+#!/bin/sh
+set -e
+
+#DEBHELPER#
+
+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~ -- "$@"
+ dpkg-maintscript-helper rm_conffile \
+ /etc/dbus-1/system.d/org.freedesktop.fwupd.conf 1.3.2~ -- "$@"
+ dpkg-maintscript-helper rm_conffile \
+ /etc/fwupd/ata.conf 1.5.5~ -- "$@"
+fi
+
+#Perform transition from /etc/fwupd/uefi.conf to /etc/fwupd/uefi_capsule.conf
+if dpkg-maintscript-helper supports mv_conffile 2>/dev/null; then
+ ORIGINAL=/etc/fwupd/uefi.conf
+ NEW=/etc/fwupd/uefi_capsule.conf
+ dpkg-maintscript-helper mv_conffile $ORIGINAL $NEW 1.5.5~ -- "$@"
+fi
+
+# 1.3.2 had fwupd-refresh.service and fwupd.service both claiming
+# this directory, but fwupd-refresh.service used DynamicUser directive
+# meaning no other unit could access it.
+if [ -L /var/cache/fwupd ]; then
+ rm -f /var/cache/fwupd
+fi
diff --git a/fwupd-1.8.6/contrib/debian/gbp.conf b/fwupd-1.8.6/contrib/debian/gbp.conf
new file mode 100644
index 0000000000000000000000000000000000000000..980ac86f60b002a2478a5c68571d00065011d09e
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/gbp.conf
@@ -0,0 +1,7 @@
+[DEFAULT]
+debian-branch = debian
+upstream-tag = %(version)s
+
+[buildpackage]
+sign-tags = True
+dist = experimental
diff --git a/fwupd-1.8.6/contrib/debian/gir1.2-fwupd-2.0.install b/fwupd-1.8.6/contrib/debian/gir1.2-fwupd-2.0.install
new file mode 100644
index 0000000000000000000000000000000000000000..341e8490034cd497cdc82b3572e26fc534ff6464
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/gir1.2-fwupd-2.0.install
@@ -0,0 +1 @@
+usr/lib/*/girepository-1.0/Fwupd-*.typelib
diff --git a/fwupd-1.8.6/contrib/debian/libfwupd-dev.install b/fwupd-1.8.6/contrib/debian/libfwupd-dev.install
new file mode 100644
index 0000000000000000000000000000000000000000..97661f753782ab8868b813478e0c797eca60e5d8
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/libfwupd-dev.install
@@ -0,0 +1,7 @@
+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/share/vala/vapi/fwupd.deps
+usr/share/vala/vapi/fwupd.vapi
diff --git a/fwupd-1.8.6/contrib/debian/libfwupd2.install b/fwupd-1.8.6/contrib/debian/libfwupd2.install
new file mode 100644
index 0000000000000000000000000000000000000000..927e37b5070291994c3f6833422c1a49f364b5ce
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/libfwupd2.install
@@ -0,0 +1 @@
+usr/lib/*/libfwupd.so.*
diff --git a/fwupd-1.8.6/contrib/debian/lintian/fwupd b/fwupd-1.8.6/contrib/debian/lintian/fwupd
new file mode 100644
index 0000000000000000000000000000000000000000..7d69af79fe13248fa40d0981c3e3ae4c03d64b9f
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/lintian/fwupd
@@ -0,0 +1,2 @@
+#see Debian bug 896012
+fwupd: library-not-linked-against-libc usr/lib/*/fwupd-plugins-*/*
diff --git a/fwupd-1.8.6/contrib/debian/lintian/fwupd-tests b/fwupd-1.8.6/contrib/debian/lintian/fwupd-tests
new file mode 100644
index 0000000000000000000000000000000000000000..43863ac40b7fa8c02771edae3d6f122dc51e28ce
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/lintian/fwupd-tests
@@ -0,0 +1,2 @@
+#see Debian bug 896012
+fwupd-tests: library-not-linked-against-libc usr/lib/*/fwupd-plugins-*/*
diff --git a/fwupd-1.8.6/contrib/debian/not-installed b/fwupd-1.8.6/contrib/debian/not-installed
new file mode 100644
index 0000000000000000000000000000000000000000..0a4eedd8636ddaf7fc0d3caf0515dd1ef5056c4d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/not-installed
@@ -0,0 +1,4 @@
+usr/libexec/qubes-fwupd/fwupd_usbvm_validate.py
+usr/sbin/qubes-fwupdmgr
+usr/share/qubes-fwupd/src/*
+usr/share/qubes-fwupd/test/*
diff --git a/fwupd-1.8.6/contrib/debian/rules b/fwupd-1.8.6/contrib/debian/rules
new file mode 100755
index 0000000000000000000000000000000000000000..2b3b6b48a523d30edcdd8ebc22b4489b27e30fc4
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/rules
@@ -0,0 +1,94 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+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)
+ export DEB_CFLAGS_MAINT_APPEND = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+endif
+
+CONFARGS =
+
+ifneq ($(CI),)
+ CONFARGS += --werror
+endif
+
+ifneq ($(DEB_HOST_ARCH_CPU),ia64)
+ CONFARGS += -Dplugin_flashrom=enabled
+else
+ CONFARGS += -Dplugin_flashrom=disabled
+endif
+
+ifeq (yes,$(shell pkg-config --exists libsmbios_c && echo yes))
+ CONFARGS += -Dplugin_dell=enabled
+else
+ CONFARGS += -Dplugin_dell=disabled
+endif
+
+ifeq (yes,$(shell pkg-config --exists efivar && echo yes))
+ CONFARGS += -Dplugin_uefi_capsule=enabled -Defi_binary=false
+else
+ CONFARGS += -Dplugin_uefi_capsule=disabled
+endif
+
+ifneq ($(filter $(DEB_HOST_ARCH_CPU),i386 amd64),)
+ CONFARGS += -Dplugin_msr=enabled
+else
+ CONFARGS += -Dplugin_msr=disabled
+endif
+
+ifneq ($(QUBES_OPTION),)
+ CONFARGS += -Dqubes=true
+endif
+
+ifneq ($(filter nodoc,$(DEB_BUILD_PROFILES)),)
+ CONFARGS += -Ddocs=disabled
+endif
+
+CONFARGS += -Dplugin_dummy=true -Dplugin_powerd=disabled -Dsupported_build=enabled -Dplugin_modem_manager=enabled -Dsystemd_unit_user=fwupd-refresh
+
+%:
+ dh $@ --with gir
+
+override_dh_auto_clean:
+ rm -fr obj-*
+ rm -fr debian/build
+
+override_dh_auto_configure:
+ dh_auto_configure -- $(CONFARGS)
+
+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
+ #install MSR conf if needed (depending on distro)
+ [ ! -d debian/tmp/usr/lib/modules-load.d ] || dh_install -pfwupd usr/lib/modules-load.d
+ [ ! -d debian/tmp/lib/modules-load.d ] || dh_install -pfwupd lib/modules-load.d
+ [ ! -d debian/tmp/usr/share/fwupd/quirks.d ] || dh_install -pfwupd usr/share/fwupd/quirks.d
+
+ #install docs (maybe)
+ [ ! -d debian/tmp/usr/share/doc ] || dh_install -pfwupd-doc usr/share/doc
+
+ dh_missing -a --fail-missing
+
+ #this is placed in fwupd-tests
+ rm -f debian/fwupd/usr/lib/*/fwupd-plugins-*/libfu_plugin_test.so
+ rm -f debian/fwupd/usr/lib/*/fwupd-plugins-*/libfu_plugin_test_ble.so
+ rm -f debian/fwupd/etc/fwupd/remotes.d/fwupd-tests.conf
+
+ #enable fwupd-refresh.service by default (we have a dedicated user)
+ rm -f debian/fwupd/lib/systemd/system-preset/fwupd-refresh.preset
+
+override_dh_strip_nondeterminism:
+ dh_strip_nondeterminism -Xfirmware-example.xml.gz
+
+ifneq (yes,$(shell command -v valgrind >/dev/null 2>&1 && echo yes))
+override_dh_auto_test:
+ :
+endif
+
+override_dh_builddeb:
+ dh_builddeb
diff --git a/fwupd-1.8.6/contrib/debian/source/format b/fwupd-1.8.6/contrib/debian/source/format
new file mode 100644
index 0000000000000000000000000000000000000000..163aaf8d82b6c54f23c45f32895dbdfdcc27b047
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/fwupd-1.8.6/contrib/debian/source/lintian-overrides b/fwupd-1.8.6/contrib/debian/source/lintian-overrides
new file mode 100644
index 0000000000000000000000000000000000000000..1e5cac9aae79b01aefeef5010d96999ef499b3cc
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/source/lintian-overrides
@@ -0,0 +1,2 @@
+#github doesn't have these
+fwupd source: debian-watch-does-not-check-gpg-signature
diff --git a/fwupd-1.8.6/contrib/debian/source/options b/fwupd-1.8.6/contrib/debian/source/options
new file mode 100644
index 0000000000000000000000000000000000000000..9e1e2a2eef034217472ee407222de5df5da7b6c0
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/source/options
@@ -0,0 +1 @@
+extend-diff-ignore=".vscode|venv|subprojects|build"
diff --git a/fwupd-1.8.6/contrib/debian/tests/ci b/fwupd-1.8.6/contrib/debian/tests/ci
new file mode 100755
index 0000000000000000000000000000000000000000..2ecab73f25142830eec5ab86fac6379f64a02b18
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/tests/ci
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+# try loading the mtdram module to run our mtd tests
+modprobe mtdram 2>&1 || true
+sed "s,^DisabledPlugins=.*,DisabledPlugins=," -i /etc/fwupd/daemon.conf
+sed "s,^VerboseDomains=.*,VerboseDomains=*," -i /etc/fwupd/daemon.conf
+sed "s,ConditionVirtualization=.*,," \
+ /lib/systemd/system/fwupd.service > \
+ /etc/systemd/system/fwupd.service
+systemctl daemon-reload
+gnome-desktop-testing-runner fwupd
diff --git a/fwupd-1.8.6/contrib/debian/tests/control b/fwupd-1.8.6/contrib/debian/tests/control
new file mode 100644
index 0000000000000000000000000000000000000000..456bc583a1c5631815f1b76661298eeb35b60ebf
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/tests/control
@@ -0,0 +1,6 @@
+Tests: ci
+Restrictions: needs-root
+
+Tests: libfwupd-dev
+Depends: build-essential, libfwupd-dev, pkg-config
+Restrictions: allow-stderr, superficial
diff --git a/fwupd-1.8.6/contrib/debian/tests/libfwupd-dev b/fwupd-1.8.6/contrib/debian/tests/libfwupd-dev
new file mode 100755
index 0000000000000000000000000000000000000000..92a95c87524c17ec24c1954fbf82992e82bf4897
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/tests/libfwupd-dev
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright 2020 Collabora Ltd.
+# Copyright 2021 Simon McVittie
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+set -eux
+
+WORKDIR="$(mktemp -d)"
+trap 'cd /; rm -fr "$WORKDIR"' 0 INT QUIT ABRT PIPE TERM
+
+if [ -n "${DEB_HOST_GNU_TYPE:-}" ]; then
+ CROSS_COMPILE="$DEB_HOST_GNU_TYPE-"
+else
+ CROSS_COMPILE=
+fi
+
+CC="${CROSS_COMPILE}gcc"
+PKG_CONFIG="${CROSS_COMPILE}pkg-config"
+
+cd "$WORKDIR"
+
+cat > trivial.c <<'EOF'
+#undef NDEBUG
+#include
+
+#include
+
+int main (void)
+{
+ assert (fwupd_error_to_string (FWUPD_ERROR_NOTHING_TO_DO) != NULL);
+ return 0;
+}
+EOF
+
+# Deliberately word-splitting pkg-config's output:
+# shellcheck disable=SC2046
+"${CC}" -otrivial trivial.c $("${PKG_CONFIG}" --cflags --libs fwupd)
+./trivial
diff --git a/fwupd-1.8.6/contrib/debian/watch b/fwupd-1.8.6/contrib/debian/watch
new file mode 100644
index 0000000000000000000000000000000000000000..4350c7f6314260ae8ebed174b65b4afa385a0856
--- /dev/null
+++ b/fwupd-1.8.6/contrib/debian/watch
@@ -0,0 +1,6 @@
+# You can run the "uscan" command to check for upstream updates and more.
+# See uscan(1) for format
+
+version=3
+opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/fwupd-$1\.tar\.gz/ \
+https://github.com/fwupd/fwupd/tags .*/v?(\d\S*)\.tar\.gz
diff --git a/fwupd-1.8.6/contrib/firmware_packager/README.md b/fwupd-1.8.6/contrib/firmware_packager/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..21015234c606d6e6e65bce708f672c2ba3690153
--- /dev/null
+++ b/fwupd-1.8.6/contrib/firmware_packager/README.md
@@ -0,0 +1,87 @@
+# Firmware Packager
+
+This script is intended to make firmware updating easier until OEMs upload their firmware packages to the LVFS. It works by extracting the firmware binary contained in a Microsoft .exe file (intended for performing the firmware update from a Windows system) and repackaging it in a cab file usable by fwupd. The cab file can then be install using `fwupdmgr install`
+
+## Prerequisites
+
+To run this script you will need
+
+1. Python3.5, a standard install should include all packages you need
+2. 7z (for extracting .exe files)
+3. gcab (for creating the cab file)
+
+## Usage
+
+To create a firmware package, you must supply, at a minimum:
+
+1. A string ID to name the firmware (`--firmware-id`). You are free to choose this, but [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)
+2. A short name for the firmware package, again you are free to choose this (`--firmware-name`).
+3. The unique ID of the device that the firmware is intended for (`--device-unique-id`). This *must* match the unique ID from `fwupdmgr get-devices`
+4. The firmware version (`--release-version`), try to match the manufacturers versioning scheme
+5. The path to the executable file to repackage (`--exe`)
+6. The path *relative to the root of the exe archive* of the .bin file to package (`--bin`). Use 7z or archive-manager to inspect the .exe file and find this path.
+For example, if I want to package `dell-thunderbolt-firmware.exe` and I open the .exe with archive-manager and find that `Intel/tbt.bin` is the path to the
+bin file inside the archive, I would pass `--exe dell-thunderbolt-firmware.exe --bin Intel/tbt.bin`
+7. The path to the cab file to output (`--out`).
+
+## Documentation
+
+`--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-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. )
+
+`-contact-info` Email address of the firmware developer (e.g. someone@something.net)
+
+`--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 didn't try it.
+
+`--exe` Executable file to extract firmware from (e.g. `dell-thunderbolt-firmware.exe`) **REQUIRED**
+
+`--bin` Path to the .bin file inside the executable to use as the firmware image', relative to the root of the archive (e.g. `Intel/tbt.bin`) **REQUIRED**
+
+`--out` Output cab file path (e.g. `updates/firmware.cab`) **REQUIRED**
+
+## Example
+
+Let's say we downloaded `Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe` (available [here](https://downloads.dell.com/FOLDER04421073M/1/Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe)) containing updated firmware for Dell laptops thunderbolt controllers. Since Dell hasn't made this available on the LVFS yet, we want to package and install it ourselves.
+
+Opening the .exe with archive manager, we see it has a single folder: `Intel` and inside that, a set of firmware binaries (along with some microsoft junk). We pick the file `0x07BE_secure.bin` since we have a Dell XPS 9560 and that is its device string.
+
+Next we use `fwupdmgr` to get the device ID for the thunderbolt controller:
+
+```shell
+$ fwupdmgr get-devices
+Thunderbolt Controller
+ Guid: 72533768-6a6c-5c06-994a-367374336810
+ DeviceID: 08001575
+ Plugin: thunderbolt
+ Flags: internal|allow-online
+ DeviceVendor: Intel
+ Version: 21.00
+ Created: 2017-08-16
+```
+
+The GUID field contains what we are looking for
+
+We can then run the firmware-packager with the following arguments:
+
+```shell
+$ firmware-packager --firmware-id net.queuecumber.DellTBT.firmware --firmware-name DellTBT --device-unique-id 72533768-6a6c-5c06-994a-367374336810 --release-version 4.21.01.002 --exe ~/Downloads/Intel_TBT3_FW_UPDATE_NVM21_318RY_A01_4.21.01.002.exe --bin Intel/0x07BE_secure.bin --out firmware.cab
+Using temp directory /tmp/tmpoey6_zx_
+Extracting firmware exe
+Locating firmware bin
+Creating metainfo
+Cabbing firmware files
+Done
+```
+
+And we should have a firmware.cab that contains the packaged firmware.
+We can then install this firmware with `fwupdmgr install firmware.cab`.
diff --git a/fwupd-1.8.6/contrib/firmware_packager/__init__.py b/fwupd-1.8.6/contrib/firmware_packager/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/fwupd-1.8.6/contrib/firmware_packager/add_capsule_header.py b/fwupd-1.8.6/contrib/firmware_packager/add_capsule_header.py
new file mode 100755
index 0000000000000000000000000000000000000000..92e26c9dccdd6037d0fabd50babf8506ecf43ac2
--- /dev/null
+++ b/fwupd-1.8.6/contrib/firmware_packager/add_capsule_header.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2019 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import sys
+import uuid
+import argparse
+import ctypes
+
+CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000
+CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000
+CAPSULE_FLAGS_INITIATE_RESET = 0x00040000
+
+
+def add_header(infile, outfile, gd, fl=None):
+ # parse GUID from command line
+ try:
+ guid = uuid.UUID(gd)
+ except ValueError as e:
+ print(e)
+ return 1
+ import struct
+
+ try:
+ with open(infile, "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
+ | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
+ )
+ if fl:
+ flags = int(fl, 16)
+
+ # build update capsule header
+ hdrsz = 4096
+ imgsz = hdrsz + len(bin_data)
+ hdr = ctypes.create_string_buffer(hdrsz)
+ struct.pack_into("<16sIII", hdr, 0, guid.bytes_le, hdrsz, flags, imgsz)
+ with open(outfile, "wb") as f:
+ f.write(hdr)
+ f.write(bin_data)
+ print("Wrote capsule %s" % outfile)
+ print("GUID: %s" % guid)
+ print("HdrSz: 0x%04x" % hdrsz)
+ print("Flags: 0x%04x" % flags)
+ print("PayloadSz: 0x%04x" % imgsz)
+ return 0
+
+
+if __name__ == "__main__":
+ 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(add_header(args.bin, args.cap, args.guid, args.flags))
diff --git a/fwupd-1.8.6/contrib/firmware_packager/add_dfu_header.py b/fwupd-1.8.6/contrib/firmware_packager/add_dfu_header.py
new file mode 100755
index 0000000000000000000000000000000000000000..749c99e75e427a9c06c4cdc185fb8c1523391d28
--- /dev/null
+++ b/fwupd-1.8.6/contrib/firmware_packager/add_dfu_header.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2020 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import struct
+import zlib
+import argparse
+
+
+def main(bin_fn, dfu_fn, pad, vid, pid, rev):
+
+ # read binary file
+ with open(bin_fn, "rb") as f:
+ blob = f.read()
+
+ # pad blob to a specific size
+ if pad:
+ while len(blob) < int(pad, 16):
+ blob += b"\0"
+
+ # create DFU footer with checksum
+ blob += struct.pack(
+ "
+
+ org.{developer_name}.guid{firmware_id}
+ {firmware_name}
+ {firmware_summary}
+
+ {firmware_description}
+
+
+ {device_guid}
+
+ {firmware_homepage}
+ CC0-1.0
+ proprietary
+ {contact_info}
+ {developer_name}
+
+
+
+ {release_description}
+
+
+
+
+ {version_format}
+ {update_protocol}
+
+
+"""
+
+
+def make_firmware_metainfo(firmware_info, dst):
+ 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)
+
+
+def extract_exe(exe, dst):
+ command = ["7z", "x", "-o{}".format(dst), exe]
+ subprocess.check_call(command, stdout=subprocess.DEVNULL)
+
+
+def get_firmware_bin(root, bin_path, dst):
+ with cd(root):
+ shutil.copy(bin_path, os.path.join(dst, "firmware.bin"))
+
+
+def create_firmware_cab(exe, folder):
+ with cd(folder):
+ 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)
+
+
+def main(args):
+ with tempfile.TemporaryDirectory() as d:
+ print("Using temp directory {}".format(d))
+
+ if args.exe:
+ print("Extracting firmware exe")
+ extract_exe(args.exe, d)
+
+ print("Locating firmware bin")
+ get_firmware_bin(d, args.bin, d)
+
+ print("Creating metainfo")
+ make_firmware_metainfo(args, d)
+
+ print("Creating cabinet file")
+ create_firmware_cab(args, d)
+
+ print("Done")
+ shutil.copy(os.path.join(d, "firmware.cab"), args.out)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Create fwupd packaged from windows executables"
+ )
+ 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-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", required=True
+ )
+ parser.add_argument(
+ "--release-version",
+ help="Version number of the firmware package",
+ required=True,
+ )
+ parser.add_argument(
+ "--version-format",
+ help="Version format, e.g. quad or triplet",
+ required=True,
+ )
+ parser.add_argument(
+ "--update-protocol",
+ help="Update protocol, e.g. org.uefi.capsule",
+ required=True,
+ )
+ parser.add_argument(
+ "--release-description", help="Description of the firmware release"
+ )
+ 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()
+
+ main(args)
diff --git a/fwupd-1.8.6/contrib/firmware_packager/install_dell_bios_exe.py b/fwupd-1.8.6/contrib/firmware_packager/install_dell_bios_exe.py
new file mode 100755
index 0000000000000000000000000000000000000000..209c99b0c6fb26ff82ee15c7c5782800ba614c1a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/firmware_packager/install_dell_bios_exe.py
@@ -0,0 +1,128 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2019 Mario Limonciello
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import dbus
+import os.path
+import sys
+import tempfile
+import gi
+
+try:
+ gi.require_version("Fwupd", "2.0")
+except ValueError:
+ print("Missing gobject-introspection packages. Try to install gir1.2-fwupd-2.0.")
+ sys.exit(1)
+from gi.repository import Fwupd # pylint: disable=wrong-import-position
+from simple_client import get_daemon_property, install, check_exists, modify_config
+from add_capsule_header import add_header
+from firmware_packager import make_firmware_metainfo, create_firmware_cab
+
+
+class Variables:
+ def __init__(self, device_guid, version):
+ self.device_guid = device_guid
+ self.developer_name = "Dell Inc"
+ self.firmware_name = "New firmware"
+ self.firmware_summary = "Unknown"
+ self.firmware_description = "Unknown"
+ self.firmware_homepage = "https://support.dell.com"
+ self.contact_info = "Unknown"
+ self.release_version = version
+ self.release_description = "Unknown"
+ self.update_protocol = "org.uefi.capsule"
+ self.version_format = "dell-bios"
+
+
+def parse_args():
+ """Parse arguments for this client"""
+ import argparse
+
+ parser = argparse.ArgumentParser(description="Interact with fwupd daemon")
+ parser.add_argument("exe", nargs="?", help="exe file")
+ parser.add_argument("deviceid", nargs="?", help="DeviceID to operate on(optional)")
+ args = parser.parse_args()
+ return args
+
+
+def generate_cab(infile, directory, guid, version):
+ output = os.path.join(directory, "firmware.bin")
+ ret = add_header(infile, output, guid)
+ if ret:
+ sys.exit(ret)
+ variables = Variables(guid, version)
+ make_firmware_metainfo(variables, directory)
+ create_firmware_cab(variables, directory)
+ cab = os.path.join(directory, "firmware.cab")
+ print("Generated CAB file %s" % cab)
+ return cab
+
+
+def find_uefi_device(client, deviceid):
+ devices = client.get_devices()
+ for item in devices:
+ # match the device we were given
+ if deviceid:
+ if item.get_id() != deviceid:
+ continue
+ # internal
+ if not item.has_flag(1 << 0):
+ continue
+ # needs reboot
+ if not item.has_flag(1 << 8):
+ continue
+ # return the first hit for UEFI plugin
+ if item.get_plugin() == "uefi" or item.get_plugin() == "uefi_capsule":
+ print("Installing to %s" % item.get_name())
+ return item.get_guid_default(), item.get_id(), item.get_version()
+ print("Couldn't find any UEFI devices")
+ sys.exit(1)
+
+
+def set_conf_only_trusted(client, setval):
+ prop = "OnlyTrusted"
+ current_val = get_daemon_property(prop)
+ if current_val:
+ pass
+ elif setval:
+ pass
+ else:
+ return False
+ modify_config(client, prop, str(setval).lower())
+ return get_daemon_property(prop) == setval
+
+
+def prompt_reboot():
+ print("An update requires a reboot to complete")
+ while True:
+ res = input("Restart now? (Y/N) ")
+ if res.lower() == "n":
+ print("Reboot your machine manually to finish the update.")
+ break
+ if res.lower() != "y":
+ continue
+ # reboot using logind
+ obj = dbus.SystemBus().get_object(
+ "org.freedesktop.login1", "/org/freedesktop/login1"
+ )
+ obj.Reboot(True, dbus_interface="org.freedesktop.login1.Manager")
+
+
+if __name__ == "__main__":
+ ARGS = parse_args()
+ CLIENT = Fwupd.Client()
+ check_exists(ARGS.exe)
+ try:
+ is_restore_required = set_conf_only_trusted(CLIENT, False)
+ directory = tempfile.mkdtemp()
+ guid, deviceid, version = find_uefi_device(CLIENT, ARGS.deviceid)
+ cab = generate_cab(ARGS.exe, directory, guid, version)
+ install(CLIENT, cab, deviceid, True, True)
+ except Exception as e:
+ print(e)
+
+ if is_restore_required:
+ set_conf_only_trusted(CLIENT, True)
+ prompt_reboot()
diff --git a/fwupd-1.8.6/contrib/firmware_packager/meson.build b/fwupd-1.8.6/contrib/firmware_packager/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..8b8709a3c1e726e91074ee8454612b582b481dc0
--- /dev/null
+++ b/fwupd-1.8.6/contrib/firmware_packager/meson.build
@@ -0,0 +1,17 @@
+if get_option('firmware-packager')
+ install_data('firmware_packager.py',
+ install_dir: 'share/fwupd')
+ install_data('add_capsule_header.py',
+ install_dir: 'share/fwupd')
+ install_data('install_dell_bios_exe.py',
+ install_dir: 'share/fwupd')
+ con2 = configuration_data()
+ con2.set('FWUPD_VERSION', fwupd_version)
+ configure_file(
+ input: 'simple_client.py',
+ output: 'simple_client.py',
+ configuration: con2,
+ install: true,
+ install_dir: 'share/fwupd',
+ )
+endif
diff --git a/fwupd-1.8.6/contrib/firmware_packager/simple_client.py b/fwupd-1.8.6/contrib/firmware_packager/simple_client.py
new file mode 100755
index 0000000000000000000000000000000000000000..9f1b860f4b5616f11a077309d08749c3893175cd
--- /dev/null
+++ b/fwupd-1.8.6/contrib/firmware_packager/simple_client.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: LGPL-2.1+
+"""A simple fwupd frontend"""
+import sys
+import os
+import dbus
+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)
+ self.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",
+ "refresh",
+ "get-bios-setting",
+ ],
+ help="What to do",
+ )
+ parser.add_argument("cab", nargs="?", help="CAB file")
+ parser.add_argument("deviceid", nargs="?", help="DeviceID to operate on(optional)")
+ parser.add_argument("--setting", help="BIOS setting to operate on(optional)")
+ args = parser.parse_args()
+ return args
+
+
+def refresh(client):
+ """Uses fwupd client to refresh metadata"""
+ remotes = client.get_remotes()
+ client.set_user_agent_for_package("simple_client", "@FWUPD_VERSION@")
+ for remote in remotes:
+ if not remote.get_enabled():
+ continue
+ if remote.get_kind() != Fwupd.RemoteKind.DOWNLOAD:
+ continue
+ client.refresh_remote(remote)
+
+
+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 get_bios_settings(client, setting):
+ """Use fwupd client to get BIOS settings"""
+ settings = client.get_bios_settings()
+ for i in settings:
+ if not setting or setting == i.get_name() or setting == i.get_id():
+ print(i.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 modify_config(client, key, value):
+ """Use fwupd client to modify daemon configuration value"""
+ try:
+ print("setting configuration key %s to %s" % (key, value))
+ client.modify_config(key, value, None)
+ except Exception as e:
+ print("%s" % str(e))
+ sys.exit(1)
+
+
+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)
+ print("\n")
+
+
+def get_daemon_property(key: str):
+ try:
+ bus = dbus.SystemBus()
+ proxy = bus.get_object(bus_name="org.freedesktop.fwupd", object_path="/")
+ iface = dbus.Interface(proxy, "org.freedesktop.DBus.Properties")
+ val = iface.Get("org.freedesktop.fwupd", key)
+ if isinstance(val, dbus.Boolean):
+ print(
+ "org.freedesktop.fwupd property %s, current value is %s"
+ % (key, bool(val))
+ )
+ else:
+ print("org.freedesktop.fwupd property %s, current value is %s" % (key, val))
+ return val
+ except dbus.DBusException as e:
+ print(e)
+ return None
+
+
+def check_exists(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()
+
+ if ARGS.command == "get-devices":
+ get_devices(CLIENT)
+ elif ARGS.command == "get-details":
+ check_exists(ARGS.cab)
+ get_details(CLIENT, ARGS.cab)
+ elif ARGS.command == "refresh":
+ refresh(CLIENT)
+ elif ARGS.command == "install":
+ check_exists(ARGS.cab)
+ install(CLIENT, ARGS.cab, ARGS.deviceid, ARGS.allow_older, ARGS.allow_reinstall)
+ elif ARGS.command == "get-bios-setting":
+ get_bios_settings(CLIENT, ARGS.setting)
diff --git a/fwupd-1.8.6/contrib/fix_translations.py b/fwupd-1.8.6/contrib/fix_translations.py
new file mode 100755
index 0000000000000000000000000000000000000000..07a45e96711bedad60a749f34396b158db948cb3
--- /dev/null
+++ b/fwupd-1.8.6/contrib/fix_translations.py
@@ -0,0 +1,56 @@
+#!/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:
+ print("path required")
+ sys.exit(2)
diff --git a/fwupd-1.8.6/contrib/flatpak/.gitmodules b/fwupd-1.8.6/contrib/flatpak/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..1e7a9909148311bdc9fe9b00fb1102909dd4fb42
--- /dev/null
+++ b/fwupd-1.8.6/contrib/flatpak/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "shared-modules"]
+ path = shared-modules
+ url = https://github.com/flathub/shared-modules.git
diff --git a/fwupd-1.8.6/contrib/flatpak/flathub.json b/fwupd-1.8.6/contrib/flatpak/flathub.json
new file mode 100644
index 0000000000000000000000000000000000000000..96509113c6f42faab10c335bd10b94fe7540bbb3
--- /dev/null
+++ b/fwupd-1.8.6/contrib/flatpak/flathub.json
@@ -0,0 +1,3 @@
+{
+ "skip-appstream-check": true
+}
diff --git a/fwupd-1.8.6/contrib/flatpak/org.freedesktop.fwupd.json b/fwupd-1.8.6/contrib/flatpak/org.freedesktop.fwupd.json
new file mode 100644
index 0000000000000000000000000000000000000000..4f81f96ce43c453eae284bc030421fa8ffbbbcfb
--- /dev/null
+++ b/fwupd-1.8.6/contrib/flatpak/org.freedesktop.fwupd.json
@@ -0,0 +1,220 @@
+{
+ "app-id": "org.freedesktop.fwupd",
+ "runtime": "org.gnome.Platform",
+ "runtime-version": "3.30",
+ "branch": "stable",
+ "sdk": "org.gnome.Sdk",
+ "command": "/app/libexec/fwupd/fwupdtool",
+ "finish-args": [
+ "--device=all",
+ "--filesystem=/boot",
+ "--filesystem=/sys",
+ "--filesystem=xdg-download",
+ "--share=network",
+ "--system-talk-name=org.freedesktop.fwupd",
+ "--system-talk-name=org.freedesktop.UPower"
+ ],
+ "cleanup": [
+ "*.a",
+ "*.la",
+ "/include",
+ "/lib/girepository-1.0",
+ "/lib/pkgconfig",
+ "/share/bash-completion",
+ "/share/dbus-1/system-services",
+ "/share/gir-1.0",
+ "/share/gtk-doc",
+ "/share/info",
+ "/share/man",
+ "/share/pkgconfig"
+ ],
+ "modules": [
+ "shared-modules/udev/udev-175.json",
+ {
+ "name": "libusb",
+ "config-opts": [
+ "--disable-static"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "https://github.com/libusb/libusb/releases/download/v1.0.22/libusb-1.0.22.tar.bz2",
+ "sha256": "75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157"
+ }
+ ]
+ },
+ {
+ "name": "gusb",
+ "buildsystem": "meson",
+ "config-opts": [
+ "-Ddocs=false",
+ "-Dvapi=false",
+ "-Dtests=false"
+ ],
+ "cleanup": [
+ "/bin/gusbcmd"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "https://people.freedesktop.org/~hughsient/releases/libgusb-0.3.0.tar.xz",
+ "sha256": "d8e7950f99b6ae4c3e9b8c65f3692b9635289e6cff8de40c4af41b2e9b348edc"
+ }
+ ]
+ },
+ {
+ "name": "efivar",
+ "buildsystem": "simple",
+ "build-commands": [
+ "make prefix=/app libdir=/app/lib",
+ "make install prefix=/app libdir=/app/lib"
+ ],
+ "cleanup": [
+ "/bin/efivar"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "https://github.com/rhboot/efivar/releases/download/35/efivar-35.tar.bz2",
+ "sha256": "1e033dc5d099a44fd473b0887dbcc4b105613efab0fb3c5df9f111ea5d147394"
+ }
+ ]
+ },
+ {
+ "name": "libsmbios_c",
+ "only-arches": [
+ "x86_64"
+ ],
+ "config-opts": [
+ "--disable-doxygen",
+ "--disable-graphviz",
+ "--disable-python"
+ ],
+ "cleanup": [
+ "/sbin/smbios*",
+ "/share/locale/*/LC_MESSAGES/libsmbios.mo"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "https://github.com/dell/libsmbios/archive/v2.4.2.tar.gz",
+ "sha256": "ebfe18415e24bbec06d0a9ea1066c8dcd82982555373712713d7e194138650de"
+ }
+ ]
+ },
+ {
+ "name": "gnu-efi",
+ "only-arches": [
+ "aarch64",
+ "x86_64"
+ ],
+ "buildsystem": "simple",
+ "build-commands": [
+ "make",
+ "make PREFIX=/app install"
+ ],
+ "no-autogen": true,
+ "cleanup": [
+ "/bin/efivar"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "http://superb-dca2.dl.sourceforge.net/project/gnu-efi/gnu-efi-3.0.9.tar.bz2",
+ "sha256": "6715ea7eae1c7e4fc5041034bd3f107ec2911962ed284a081e491646b12277f0"
+ }
+ ]
+ },
+ {
+ "name": "python3-olefile",
+ "only-arches": [
+ "aarch64",
+ "x86_64"
+ ],
+ "buildsystem": "simple",
+ "build-commands": [
+ "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} olefile"
+ ],
+ "sources": [
+ {
+ "type": "file",
+ "url": "https://pypi.python.org/packages/35/17/c15d41d5a8f8b98cc3df25eb00c5cee76193114c78e5674df6ef4ac92647/olefile-0.44.zip",
+ "sha256": "61f2ca0cd0aa77279eb943c07f607438edf374096b66332fae1ee64a6f0f73ad"
+ }
+ ]
+ },
+ {
+ "name": "python3-pillow",
+ "only-arches": [
+ "aarch64",
+ "x86_64"
+ ],
+ "buildsystem": "simple",
+ "build-commands": [
+ "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} Pillow"
+ ],
+ "cleanup": [
+ "/bin/*.py"
+ ],
+ "sources": [
+ {
+ "type": "file",
+ "url": "https://pypi.python.org/packages/93/73/66854f63b1941aad9af18a1de59f9cf95ad1a87c801540222e332f6688d7/Pillow-4.1.1.tar.gz",
+ "sha256": "00b6a5f28d00f720235a937ebc2f50f4292a5c7e2d6ab9a8b26153b625c4f431"
+ }
+ ]
+ },
+ {
+ "name": "fwupd",
+ "buildsystem": "meson",
+ "config-opts": [
+ "-Dconsolekit=false",
+ "-Ddaemon=false",
+ "-Dgpg=false",
+ "-Dgtkdoc=false",
+ "-Dintrospection=false",
+ "-Dman=false",
+ "-Dpkcs7=false",
+ "-Dsystemd=false",
+ "-Dtests=false",
+ "-Defi-includedir=/app/include/efi",
+ "-Defi-ldsdir=/app/lib",
+ "-Defi-libdir=/app/lib",
+ "--sysconfdir=/app/etc",
+ "--localstatedir=/var/data"
+ ],
+ "build-options" : {
+ "arch": {
+ "i386": {
+ "config-opts": [
+ "-Dplugin_dell=false",
+ "-Dplugin_uefi=false"
+ ]
+ },
+ "arm": {
+ "config-opts": [
+ "-Dplugin_dell=false",
+ "-Dplugin_uefi=false"
+ ]
+ },
+ "aarch64": {
+ "config-opts": [
+ "-Dplugin_dell=false"
+ ]
+ }
+ }
+ },
+ "cleanup": [
+ "/etc/dbus-1/system.d/org.freedesktop.fwupd.conf",
+ "/share/fwupd/remotes.d/vendor"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "https://people.freedesktop.org/~hughsient/releases/fwupd-1.1.3.tar.xz",
+ "sha256": "474568a98af8ae82255c18da90ce2e4d290875da98638c4b1c44632c758314af"
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/contrib/freebsd/Makefile b/fwupd-1.8.6/contrib/freebsd/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..79a47eb606c2830960f058c7cfddea8a77824831
--- /dev/null
+++ b/fwupd-1.8.6/contrib/freebsd/Makefile
@@ -0,0 +1,53 @@
+# Created by: Norbert Kamiński
+# $FreeBSD$
+
+PORTNAME= fwupd
+DISTVERSION=
+GH_TAGNAME=
+CATEGORIES= sysutils
+
+MAINTAINER= norbert.kaminski@3mdeb.com
+COMMENT= Update firmware automatically, safely, and reliably
+
+LICENSE= LGPL21
+
+BUILD_DEPENDS= gi-docgen:textproc/gi-docgen \
+ help2man:misc/help2man \
+ vala:lang/vala \
+ ${LOCALBASE}/libexec/fwupd/efi/fwupdx64.efi:sysutils/fwupd-efi \
+ ${PYTHON_PKGNAMEPREFIX}gobject3>0:devel/py-gobject3@${PY_FLAVOR}
+LIB_DEPENDS= libcurl.so:ftp/curl \
+ libefiboot.so:devel/libefiboot \
+ libgcab-1.0.so:archivers/gcab \
+ libgnutls.so:security/gnutls \
+ libgpg-error.so:security/libgpg-error \
+ libgpgme.so:security/gpgme \
+ libgusb.so:devel/libgusb \
+ libjcat.so:textproc/libjcat \
+ libjson-glib-1.0.so:devel/json-glib \
+ libprotobuf-c.so:devel/protobuf-c \
+ libcbor.so:devel/libcbor \
+ libxmlb.so:textproc/libxmlb \
+ libefiboot.so:devel/gnu-efi
+
+RUN_DEPENDS= ${LOCALBASE}/libexec/fwupd/efi/fwupdx64.efi:sysutils/fwupd-efi
+
+USES= gnome libarchive meson pkgconfig python:3.8+ shebangfix sqlite
+USE_GITHUB= yes
+USE_GNOME= glib20 introspection:build
+GH_ACCOUNT=
+INSTALLS_ICONS= yes
+USE_LDCONFIG= yes
+
+SHEBANG_GLOB= *.py
+
+MESON_ARGS= -Dgudev=disabled \
+ -Dplugin_amt=false \
+ -Dpolkit=disabled \
+ -Dsystemd=disabled \
+ -Doffline=false \
+ -Dtests=false \
+ -Ddocs=enabled \
+ -Defi_binary=false
+
+.include
diff --git a/fwupd-1.8.6/contrib/freebsd/pkg-descr b/fwupd-1.8.6/contrib/freebsd/pkg-descr
new file mode 100644
index 0000000000000000000000000000000000000000..cb60b1cd5ea4f33f3f3f70c3b01ffb188692c4f2
--- /dev/null
+++ b/fwupd-1.8.6/contrib/freebsd/pkg-descr
@@ -0,0 +1,9 @@
+Make firmware updates automatic, safe, and reliable.
+
+fwupd is a system daemon to allow session software to update device firmware on
+your local machine. It is designed for desktops, but also usable on phones and
+headless servers. 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.
+
+WWW: https://fwupd.org/
diff --git a/fwupd-1.8.6/contrib/fwupd.spec.in b/fwupd-1.8.6/contrib/fwupd.spec.in
new file mode 100644
index 0000000000000000000000000000000000000000..aa18b34b4b965efa149bfbf8093ab3406fac00a6
--- /dev/null
+++ b/fwupd-1.8.6/contrib/fwupd.spec.in
@@ -0,0 +1,497 @@
+%global glib2_version 2.45.8
+%global libxmlb_version 0.1.3
+%global libgusb_version 0.3.5
+%global libcurl_version 7.61.0
+%global libjcat_version 0.1.0
+%global systemd_version 231
+%global json_glib_version 1.1.1
+
+# although we ship a few tiny python files these are utilities that 99.99%
+# of users do not need -- use this to avoid dragging python onto CoreOS
+%global __requires_exclude ^%{python3}$
+
+%define alphatag #ALPHATAG#
+
+%global enable_ci 0
+%global enable_tests 1
+%global enable_dummy 1
+%global __meson_wrap_mode nodownload
+
+# fwupd.efi is only available on these arches
+%ifarch x86_64 aarch64
+%global have_uefi 1
+%endif
+
+# gpio.h is only available on these arches
+%ifarch x86_64 aarch64
+%global have_gpio 1
+%endif
+
+# flashrom is only available on these arches
+%ifarch i686 x86_64 armv7hl aarch64 ppc64le
+%global have_flashrom 1
+%endif
+
+%ifarch i686 x86_64
+%global have_msr 1
+%endif
+
+# libsmbios is only available on x86
+%ifarch x86_64
+%global have_dell 1
+%endif
+
+# Until we actually have seen it outside x86
+%ifarch i686 x86_64
+%global have_thunderbolt 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: LGPLv2+
+URL: https://github.com/fwupd/fwupd
+Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz
+
+BuildRequires: gettext
+BuildRequires: glib2-devel >= %{glib2_version}
+BuildRequires: libxmlb-devel >= %{libxmlb_version}
+BuildRequires: libgcab1-devel
+BuildRequires: libgudev1-devel
+BuildRequires: libgusb-devel >= %{libgusb_version}
+BuildRequires: libcurl-devel >= %{libcurl_version}
+BuildRequires: libjcat-devel >= %{libjcat_version}
+BuildRequires: polkit-devel >= 0.103
+BuildRequires: protobuf-c-devel
+BuildRequires: python3-packaging
+BuildRequires: sqlite-devel
+BuildRequires: systemd >= %{systemd_version}
+BuildRequires: systemd-devel
+BuildRequires: libarchive-devel
+BuildRequires: libcbor-devel
+BuildRequires: gobject-introspection-devel
+BuildRequires: gcab
+%ifarch %{valgrind_arches}
+BuildRequires: valgrind
+BuildRequires: valgrind-devel
+%endif
+BuildRequires: gi-docgen
+BuildRequires: gnutls-devel
+BuildRequires: gnutls-utils
+BuildRequires: meson
+BuildRequires: json-glib-devel >= %{json_glib_version}
+BuildRequires: vala
+BuildRequires: bash-completion
+BuildRequires: git-core
+%if 0%{?have_flashrom}
+BuildRequires: flashrom-devel >= 1.2-2
+%endif
+
+%if 0%{?have_modem_manager}
+BuildRequires: ModemManager-glib-devel >= 1.10.0
+BuildRequires: libqmi-devel >= 1.22.0
+BuildRequires: libmbim-devel
+%endif
+
+%if 0%{?have_uefi}
+BuildRequires: efivar-devel >= 33
+BuildRequires: python3 python3-cairo python3-gobject
+BuildRequires: pango-devel
+BuildRequires: cairo-devel cairo-gobject-devel
+BuildRequires: freetype
+BuildRequires: fontconfig
+BuildRequires: google-noto-sans-cjk-ttc-fonts
+BuildRequires: tpm2-tss-devel >= 2.2.3
+%endif
+
+%if 0%{?have_dell}
+BuildRequires: efivar-devel >= 33
+BuildRequires: libsmbios-devel >= 2.3.0
+%endif
+
+Requires(post): systemd
+Requires(preun): systemd
+Requires(postun): systemd
+
+Requires: glib2%{?_isa} >= %{glib2_version}
+Requires: libxmlb%{?_isa} >= %{libxmlb_version}
+Requires: libgusb%{?_isa} >= %{libgusb_version}
+Requires: shared-mime-info
+
+%if 0%{?rhel} > 7 || 0%{?fedora} > 28
+Recommends: python3
+%endif
+
+Obsoletes: fwupd-sign < 0.1.6
+Obsoletes: libebitdo < 0.7.5-3
+Obsoletes: libdfu < 1.0.0
+Obsoletes: fwupd-labels < 1.1.0-1
+
+Obsoletes: dbxtool < 9
+Provides: dbxtool
+
+%if 0%{?rhel} > 7
+Obsoletes: fwupdate < 11-4
+Obsoletes: fwupdate-efi < 11-4
+
+Provides: fwupdate
+Provides: fwupdate-efi
+%endif
+
+# optional, but a really good idea
+Recommends: udisks2
+Recommends: bluez
+Recommends: jq
+
+%if 0%{?have_modem_manager}
+Recommends: %{name}-plugin-modem-manager
+%endif
+%if 0%{?have_flashrom}
+Recommends: %{name}-plugin-flashrom
+%endif
+%if 0%{?have_uefi}
+Recommends: %{name}-efi
+Recommends: %{name}-plugin-uefi-capsule-data
+%endif
+
+%description
+fwupd is a daemon to allow session software to update device firmware.
+
+%package devel
+Summary: Development package for %{name}
+Requires: %{name}%{?_isa} = %{version}-%{release}
+Obsoletes: libebitdo-devel < 0.7.5-3
+Obsoletes: libdfu-devel < 1.0.0
+
+%description devel
+Files for development with %{name}.
+
+%package tests
+Summary: Data files for installed tests
+Requires: %{name}%{?_isa} = %{version}-%{release}
+
+%description tests
+Data files for installed tests.
+
+%if 0%{?have_modem_manager}
+%package plugin-modem-manager
+Summary: fwupd plugin using ModemManger
+Requires: %{name}%{?_isa} = %{version}-%{release}
+
+%description plugin-modem-manager
+This provides the optional package which is only required on hardware that
+might have mobile broadband hardware. It is probably not required on servers.
+%endif
+
+%if 0%{?have_flashrom}
+%package plugin-flashrom
+Summary: fwupd plugin using flashrom
+Requires: %{name}%{?_isa} = %{version}-%{release}
+
+%description plugin-flashrom
+This provides the optional package which is only required on hardware that
+can be flashed using flashrom. It is probably not required on servers.
+%endif
+
+%if 0%{?have_uefi}
+%package plugin-uefi-capsule-data
+Summary: Localized data for the UEFI UX capsule
+Requires: %{name}%{?_isa} = %{version}-%{release}
+
+%description plugin-uefi-capsule-data
+This provides the pregenerated BMP artwork for the UX capsule, which allows the
+"Installing firmware update…" localized text to be shown during a UEFI firmware
+update operation. This subpackage is probably not required on embedded hardware
+or server machines.
+%endif
+
+%if 0%{?qubes_packages}
+%package qubes-dom0
+Summary: fwupd wrapper for Qubes OS - dom0 scripts
+Requires: gcab
+Requires: fwupd >= 1.5.7
+Requires: libjcat >= 0.1.6
+
+%description qubes-dom0
+fwupd wrapper for Qubes OS
+
+%package qubes-vm
+Summary: fwupd wrapper for Qubes OS - VM scripts
+Requires: gcab
+Requires: fwupd >= 1.5.7
+Requires: libjcat >= 0.1.6
+
+%description qubes-vm
+fwupd wrapper for Qubes OS
+%endif
+
+%prep
+%autosetup -p1
+
+%build
+
+%meson \
+%if 0%{?enable_ci}
+ --werror \
+%endif
+ -Ddocs=enabled \
+%if 0%{?enable_tests}
+ -Dtests=true \
+%else
+ -Dtests=false \
+%endif
+%if 0%{?enable_dummy}
+ -Dplugin_dummy=true \
+%else
+ -Dplugin_dummy=false \
+%endif
+%if 0%{?have_flashrom}
+ -Dplugin_flashrom=enabled \
+%else
+ -Dplugin_flashrom=disabled \
+%endif
+%if 0%{?have_msr}
+ -Dplugin_msr=enabled \
+%else
+ -Dplugin_msr=disabled \
+%endif
+%if 0%{?have_gpio}
+ -Dplugin_gpio=enabled \
+%else
+ -Dplugin_gpio=disabled \
+%endif
+%if 0%{?have_uefi}
+ -Dplugin_uefi_capsule=enabled \
+ -Dplugin_uefi_pk=enabled \
+ -Dplugin_tpm=enabled \
+ -Defi_binary=false \
+%else
+ -Dplugin_uefi_capsule=disabled \
+ -Dplugin_uefi_pk=disabled \
+ -Dplugin_tpm=disabled \
+%endif
+%if 0%{?have_dell}
+ -Dplugin_dell=enabled \
+%else
+ -Dplugin_dell=disabled \
+%endif
+%if 0%{?have_modem_manager}
+ -Dplugin_modem_manager=enabled \
+%else
+ -Dplugin_modem_manager=disabled \
+%endif
+%if 0%{?qubes_packages}
+ -Dqubes=true \
+%endif
+ -Dman=true \
+ -Dbluez=enabled \
+ -Dplugin_powerd=disabled \
+ -Dsupported_build=enabled
+
+%meson_build
+
+%if 0%{?enable_tests}
+%if 0%{?enable_ci}
+ ./contrib/ci/get_test_firmware.sh
+%endif
+%check
+%meson_test
+%endif
+
+%install
+%meson_install
+
+mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg
+
+# workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1757948
+mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/cache/fwupd
+
+%find_lang %{name}
+
+%post
+%systemd_post fwupd.service
+
+# change vendor-installed remotes to use the default keyring type
+for fn in /etc/fwupd/remotes.d/*.conf; do
+ if grep -q "Keyring=gpg" "$fn"; then
+ sed -i 's/Keyring=gpg/#Keyring=pkcs/g' "$fn";
+ fi
+done
+
+%preun
+%systemd_preun fwupd.service
+
+%postun
+%systemd_postun_with_restart fwupd.service
+
+%files -f %{name}.lang
+%doc README.md AUTHORS
+%license COPYING
+%config(noreplace)%{_sysconfdir}/fwupd/daemon.conf
+%if 0%{?have_uefi}
+%config(noreplace)%{_sysconfdir}/fwupd/uefi_capsule.conf
+%endif
+%config(noreplace)%{_sysconfdir}/fwupd/redfish.conf
+%if 0%{?have_thunderbolt}
+%config(noreplace)%{_sysconfdir}/fwupd/thunderbolt.conf
+%endif
+%dir %{_libexecdir}/fwupd
+%{_libexecdir}/fwupd/fwupd
+%ifarch i686 x86_64
+%{_libexecdir}/fwupd/fwupd-detect-cet
+%endif
+%{_libexecdir}/fwupd/fwupdoffline
+%if 0%{?have_uefi}
+%{_bindir}/fwupdate
+%endif
+%{_bindir}/dfu-tool
+%if 0%{?have_uefi}
+%{_bindir}/dbxtool
+%endif
+%{_bindir}/fwupdmgr
+%{_bindir}/fwupdtool
+%{_bindir}/fwupdagent
+%dir %{_sysconfdir}/fwupd
+%dir %{_sysconfdir}/fwupd/bios-settings.d
+%config%(noreplace)%{_sysconfdir}/fwupd/bios-settings.d/README.md
+%dir %{_sysconfdir}/fwupd/remotes.d
+%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
+%if 0%{?have_msr}
+/usr/lib/modules-load.d/fwupd-msr.conf
+%config(noreplace)%{_sysconfdir}/fwupd/msr.conf
+%endif
+%{_datadir}/dbus-1/system.d/org.freedesktop.fwupd.conf
+%{_datadir}/bash-completion/completions/fwupdmgr
+%{_datadir}/bash-completion/completions/fwupdtool
+%{_datadir}/bash-completion/completions/fwupdagent
+%{_datadir}/fish/vendor_completions.d/fwupdmgr.fish
+%{_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
+%{_datadir}/polkit-1/rules.d/org.freedesktop.fwupd.rules
+%{_datadir}/dbus-1/system-services/org.freedesktop.fwupd.service
+%{_mandir}/man1/fwupdtool.1*
+%{_mandir}/man1/fwupdagent.1*
+%{_mandir}/man1/dfu-tool.1*
+%if 0%{?have_uefi}
+%{_mandir}/man1/dbxtool.*
+%endif
+%{_mandir}/man1/fwupdmgr.1*
+%if 0%{?have_uefi}
+%{_mandir}/man1/fwupdate.1*
+%endif
+%{_datadir}/metainfo/org.freedesktop.fwupd.metainfo.xml
+%{_datadir}/icons/hicolor/scalable/apps/org.freedesktop.fwupd.svg
+%{_datadir}/fwupd/firmware_packager.py
+%{_datadir}/fwupd/simple_client.py
+%{_datadir}/fwupd/add_capsule_header.py
+%{_datadir}/fwupd/install_dell_bios_exe.py
+%{_unitdir}/fwupd-offline-update.service
+%{_unitdir}/fwupd.service
+%{_unitdir}/fwupd-refresh.service
+%{_unitdir}/fwupd-refresh.timer
+%{_presetdir}/fwupd-refresh.preset
+%{_unitdir}/system-update.target.wants/
+%dir %{_localstatedir}/lib/fwupd
+%dir %{_localstatedir}/cache/fwupd
+%dir %{_datadir}/fwupd/quirks.d
+%{_datadir}/fwupd/quirks.d/builtin.quirk.gz
+%{_datadir}/doc/fwupd/*.html
+%if 0%{?have_uefi}
+%{_sysconfdir}/grub.d/35_fwupd
+%endif
+%{_libdir}/libfwupd.so.2*
+%{_libdir}/girepository-1.0/Fwupd-2.0.typelib
+/usr/lib/udev/rules.d/*.rules
+/usr/lib/systemd/system-shutdown/fwupd.shutdown
+%dir %{_libdir}/fwupd-%{version}
+%{_libdir}/fwupd-%{version}/libfwupd*.so
+%ghost %{_localstatedir}/lib/fwupd/gnupg
+
+%if 0%{?have_modem_manager}
+%files plugin-modem-manager
+%{_libdir}/fwupd-%{version}/libfu_plugin_modem_manager.so
+%endif
+%if 0%{?have_flashrom}
+%files plugin-flashrom
+%{_libdir}/fwupd-%{version}/libfu_plugin_flashrom.so
+%endif
+%if 0%{?have_uefi}
+%files plugin-uefi-capsule-data
+%{_datadir}/fwupd/uefi-capsule-ux.tar.xz
+%endif
+
+%files devel
+%{_datadir}/gir-1.0/Fwupd-2.0.gir
+%{_datadir}/doc/fwupd/libfwupdplugin
+%{_datadir}/doc/fwupd/libfwupd
+%{_datadir}/doc/libfwupdplugin
+%{_datadir}/doc/libfwupd
+%{_datadir}/vala/vapi
+%{_includedir}/fwupd-1
+%{_libdir}/libfwupd*.so
+%{_libdir}/pkgconfig/fwupd.pc
+
+%files tests
+%if 0%{?enable_tests}
+%{_datadir}/fwupd/host-emulate.d/*.json.gz
+%dir %{_datadir}/installed-tests/fwupd
+%{_datadir}/installed-tests/fwupd/tests/*
+%{_datadir}/installed-tests/fwupd/fwupd-tests.xml
+%{_datadir}/installed-tests/fwupd/*.test
+%{_datadir}/installed-tests/fwupd/*.cab
+%{_datadir}/installed-tests/fwupd/*.sh
+%if 0%{?have_uefi}
+%{_datadir}/installed-tests/fwupd/efi
+%endif
+%{_datadir}/fwupd/device-tests/*.json
+%{_libexecdir}/installed-tests/fwupd/*
+%dir %{_sysconfdir}/fwupd/remotes.d
+%config(noreplace)%{_sysconfdir}/fwupd/remotes.d/fwupd-tests.conf
+%endif
+
+%if 0%{?qubes_packages}
+%files qubes-vm
+%{_libexecdir}/qubes-fwupd/fwupd_common_vm.py
+%{_libexecdir}/qubes-fwupd/fwupd_download_updates.py
+%{_libexecdir}/qubes-fwupd/fwupd_usbvm_validate.py
+
+%files qubes-dom0
+%{_datadir}/qubes-fwupd/src/fwupd_receive_updates.py
+/usr/sbin/qubes-fwupdmgr
+%{_datadir}/qubes-fwupd/src/qubes_fwupd_heads.py
+%{_datadir}/qubes-fwupd/src/qubes_fwupd_update.py
+%{_datadir}/qubes-fwupd/src/__init__.py
+%{_datadir}/qubes-fwupd/test/fwupd_logs.py
+%{_datadir}/qubes-fwupd/test/test_qubes_fwupdmgr.py
+%{_datadir}/qubes-fwupd/test/test_qubes_fwupd_heads.py
+%{_datadir}/qubes-fwupd/test/__init__.py
+%{_datadir}/qubes-fwupd/test/logs/get_devices.log
+%{_datadir}/qubes-fwupd/test/logs/get_updates.log
+%{_datadir}/qubes-fwupd/test/logs/help.log
+%{_datadir}/qubes-fwupd/test/logs/firmware.metainfo.xml
+%{_datadir}/qubes-fwupd/test/logs/metainfo_name/firmware.metainfo.xml
+%{_datadir}/qubes-fwupd/test/logs/metainfo_version/firmware.metainfo.xml
+%endif
+
+%changelog
+* #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG#
+- Update from git
diff --git a/fwupd-1.8.6/contrib/fwupd.wxs.in b/fwupd-1.8.6/contrib/fwupd.wxs.in
new file mode 100644
index 0000000000000000000000000000000000000000..6414d9f51ad65a064e46fd2b35a95d8782999deb
--- /dev/null
+++ b/fwupd-1.8.6/contrib/fwupd.wxs.in
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT NEWERVERSIONDETECTED
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fwupd-1.8.6/contrib/generate-ds20.py b/fwupd-1.8.6/contrib/generate-ds20.py
new file mode 100755
index 0000000000000000000000000000000000000000..d3bdc9d65249215aa22a0039900e9fadde0929d6
--- /dev/null
+++ b/fwupd-1.8.6/contrib/generate-ds20.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2022 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# pylint: disable=consider-using-f-string
+
+import sys
+import argparse
+import configparser
+import base64
+from typing import List
+
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-b",
+ "--bufsz",
+ type=int,
+ help="Buffer size in bytes",
+ )
+ parser.add_argument("-i", "--instance-id", type=str, help="Device instance ID")
+ parser.add_argument("filename", action="store", type=str, help="Quirk filename")
+
+ args = parser.parse_args()
+ if not args.bufsz:
+ parser.print_help()
+ sys.exit(1)
+
+ config = configparser.ConfigParser()
+ config.optionxform = str
+ try:
+ config.read(args.filename)
+ except configparser.MissingSectionHeaderError:
+ print("Not a quirk file")
+ sys.exit(1)
+
+ # fall back to the default if there is only one device in the quirk file
+ if not args.instance_id:
+ sections = config.sections()
+ if len(sections) != 1:
+ print("Multiple devices found, use --instance-id to choose between:")
+ for section in sections:
+ print(" • {}".format(section))
+ sys.exit(1)
+ args.instance_id = sections[0]
+
+ # create the smallest kv store possible
+ lines: List[str] = []
+ try:
+ for key in config[args.instance_id]:
+ if key in ["Inhibit", "Issue"]:
+ print("WARNING: skipping key {}".format(key))
+ continue
+ value = config[args.instance_id][key]
+ lines.append("{}={}".format(key, value))
+ except KeyError:
+ print("No {} section".format(args.instance_id))
+ sys.exit(1)
+
+ # pad to the buffer size
+ buf: bytes = "\n".join(lines).encode()
+ if len(buf) > args.bufsz:
+ print("Quirk data is larger than bufsz")
+ sys.exit(1)
+ buf = buf.ljust(args.bufsz, b"\0")
+
+ # success
+ print("DS20 descriptor control transfer data:")
+ print(" ".join(["{:02x}".format(val) for val in list(buf)]))
+ print(base64.b64encode(buf).decode())
diff --git a/fwupd-1.8.6/contrib/generate-emulation.py b/fwupd-1.8.6/contrib/generate-emulation.py
new file mode 100755
index 0000000000000000000000000000000000000000..5af3ec7671943fbb75a5572fdc81a092b1f405ed
--- /dev/null
+++ b/fwupd-1.8.6/contrib/generate-emulation.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2017 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# pylint: disable=invalid-name,missing-docstring,consider-using-f-string
+
+import json
+import sys
+
+from typing import Dict, List, Any
+
+import gi
+from gi.repository import GLib
+
+gi.require_version("Fwupd", "2.0")
+gi.require_version("Json", "1.0")
+
+from gi.repository import Fwupd # pylint: disable=wrong-import-position
+from gi.repository import Json # pylint: disable=wrong-import-position
+
+
+def _minimize_json(json_str: str) -> str:
+ nodes = json.loads(json_str)
+ new_attrs: List[Dict[str, Any]] = []
+ new_devices: List[Dict[str, Any]] = []
+ new_bios_settings: List[Dict[str, Any]] = []
+ try:
+ for attr in nodes["SecurityAttributes"]:
+ new_attr: Dict[str, Any] = {}
+ for key in attr:
+ if key in ["AppstreamId", "HsiResult", "Flags", "Plugin"]:
+ new_attr[key] = attr[key]
+ new_attrs.append(new_attr)
+ except KeyError:
+ pass
+ try:
+ for device in nodes["Devices"]:
+ new_device: Dict[str, Any] = {}
+ for key in device:
+ if key not in ["Created", "Modified", "Releases", "Plugin"]:
+ new_device[key] = device[key]
+ new_devices.append(new_device)
+ except KeyError:
+ pass
+ try:
+ for device in nodes["BiosSettings"]:
+ new_attr: Dict[str, Any] = {}
+ for key in device:
+ if key not in ["Filename"]:
+ new_attr[key] = device[key]
+ new_bios_settings.append(new_attr)
+ except KeyError:
+ pass
+ return json.dumps(
+ {
+ "SecurityAttributes": new_attrs,
+ "Devices": new_devices,
+ "BiosSettings": new_bios_settings,
+ },
+ indent=2,
+ separators=(",", " : "),
+ )
+
+
+def _get_host_devices_and_attrs() -> str:
+
+ # connect to the running daemon
+ client = Fwupd.Client()
+ builder = Json.Builder()
+ builder.begin_object()
+
+ # add devices
+ try:
+ devices = client.get_devices()
+ except GLib.GError as e:
+ print("ignoring {}".format(e))
+ else:
+ builder.set_member_name("Devices")
+ builder.begin_array()
+ for device in devices:
+ builder.begin_object()
+ device.to_json_full(builder, Fwupd.DEVICE_FLAG_TRUSTED)
+ builder.end_object()
+ builder.end_array()
+
+ # add security attributes
+ try:
+ attrs = client.get_host_security_attrs()
+ except GLib.GError as e:
+ print("ignoring {}".format(e))
+ else:
+ builder.set_member_name("SecurityAttributes")
+ builder.begin_array()
+ for attr in attrs:
+ builder.begin_object()
+ attr.to_json(builder)
+ builder.end_object()
+ builder.end_array()
+
+ # add BIOS settings
+ try:
+ attrs = client.get_bios_settings()
+ except GLib.GError as e:
+ print("ignoring {}".format(e))
+ else:
+ builder.set_member_name("BiosSettings")
+ builder.begin_array()
+ for attr in attrs:
+ builder.begin_object()
+ attr.to_json(builder)
+ builder.end_object()
+ builder.end_array()
+
+ # export to JSON
+ builder.end_object()
+ generator = Json.Generator()
+ generator.set_pretty(True)
+ generator.set_root(builder.get_root())
+ return generator.to_data()[0]
+
+
+if len(sys.argv) < 2:
+ sys.stdout.write(_minimize_json(sys.stdin.read()))
+else:
+ for fn in sys.argv[1:]:
+
+ try:
+ with open(fn, "rb") as f_in:
+ json_in = f_in.read().decode()
+ except FileNotFoundError:
+ json_in = _get_host_devices_and_attrs()
+ json_out = _minimize_json(json_in).encode()
+ with open(fn, "wb") as f_out:
+ f_out.write(json_out)
diff --git a/fwupd-1.8.6/contrib/generate-metainfo.py b/fwupd-1.8.6/contrib/generate-metainfo.py
new file mode 100755
index 0000000000000000000000000000000000000000..44dc90fa0d83672b91742617d3de7cd067ebea73
--- /dev/null
+++ b/fwupd-1.8.6/contrib/generate-metainfo.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2022 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import argparse
+import xml.etree.ElementTree as ET
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-r",
+ "--releases",
+ type=int,
+ default=5,
+ )
+ parser.add_argument(
+ "filename_src", action="store", type=str, help="metainfo source"
+ )
+ parser.add_argument(
+ "filename_dst", action="store", type=str, help="metainfo destination"
+ )
+ args = parser.parse_args()
+
+ tree = ET.parse(args.filename_src)
+ root = tree.getroot().findall("releases")[0]
+ for release in root.findall("release")[args.releases :]:
+ root.remove(release)
+
+ with open(args.filename_dst, "wb") as f:
+ tree.write(f, encoding="UTF-8", xml_declaration=True)
diff --git a/fwupd-1.8.6/contrib/generate-plugins-header.py b/fwupd-1.8.6/contrib/generate-plugins-header.py
new file mode 100644
index 0000000000000000000000000000000000000000..54d549bd74faf92565ccaf0a7d965b7d131764a5
--- /dev/null
+++ b/fwupd-1.8.6/contrib/generate-plugins-header.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2022 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import sys
+
+if len(sys.argv) < 3:
+ print("not enough arguments")
+ sys.exit(1)
+
+with open(sys.argv[1], "w") as f:
+
+ # empty argument is no plugins
+ plugin_names = []
+ if sys.argv[3]:
+ for fullpath in sys.argv[3].split(","):
+ parts = fullpath.split("/")
+ name = parts[-1]
+ if name.startswith("libfu_plugin_"):
+ name = name[13:]
+ if name.endswith(".a"):
+ name = name[:-2]
+ plugin_names.append((parts[-2], name))
+
+ # includes
+ for dirname, name in plugin_names:
+ f.write(
+ '#include "{srcdir}/plugins/{dirname}/fu-{name}-plugin.h"\n'.format(
+ srcdir=sys.argv[2], dirname=dirname, name=name.replace("_", "-")
+ )
+ )
+
+ # GTypes
+ gtypes = ["fu_{}_plugin_get_type".format(name) for _, name in plugin_names]
+ f.write(
+ "GType (*fu_plugin_externals[])(void) = { %s };\n"
+ % ", ".join(gtypes + ["NULL"])
+ )
+
+sys.exit(0)
diff --git a/fwupd-1.8.6/contrib/generate-version-script.py b/fwupd-1.8.6/contrib/generate-version-script.py
new file mode 100755
index 0000000000000000000000000000000000000000..7b0ecdf3f53ab446014f281ab463f2c1b7121568
--- /dev/null
+++ b/fwupd-1.8.6/contrib/generate-version-script.py
@@ -0,0 +1,142 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2017 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import sys
+import argparse
+import xml.etree.ElementTree as ET
+
+XMLNS = "{http://www.gtk.org/introspection/core/1.0}"
+XMLNS_C = "{http://www.gtk.org/introspection/c/1.0}"
+
+
+def parse_version(ver):
+ return tuple(map(int, ver.split(".")))
+
+
+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: %s \n" % sys.argv[0])
+ sys.exit(return_code)
+
+
+class LdVersionScript:
+ """Rasterize some text"""
+
+ def __init__(self, library_name):
+ self.library_name = library_name
+ self.releases = {}
+ self.overrides = {}
+
+ def _add_node(self, node):
+ identifier = node.attrib[XMLNS_C + "identifier"]
+ introspectable = int(node.get("introspectable", 1))
+ version = node.get("version", None)
+ if introspectable and not version:
+ print("No version for", identifier)
+ sys.exit(1)
+ if not version:
+ return None
+ version = node.attrib["version"]
+ if version not in self.releases:
+ self.releases[version] = []
+ release = self.releases[version]
+ if identifier not in release:
+ 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)
+
+ # choose the lowest version method for the _get_type symbol
+ version_lowest = None
+
+ # 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 parse_version(version_tmp) < parse_version(
+ version_lowest
+ ):
+ version_lowest = version_tmp
+
+ # add the constructor
+ for node in cls.findall(XMLNS + "constructor"):
+ version_tmp = self._add_node(node)
+ if version_tmp:
+ if not version_lowest or parse_version(version_tmp) < parse_version(
+ version_lowest
+ ):
+ version_lowest = version_tmp
+
+ 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"]
+
+ # finally add the get_type symbol
+ version = self.overrides.get(type_name, version_lowest)
+ if version:
+ self.releases[version].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"):
+ self._add_cls(cls)
+
+ def render(self):
+
+ # get a sorted list of all the versions
+ versions = []
+ for version in self.releases:
+ versions.append(version)
+
+ # output the version data to a file
+ verout = "# generated automatically, do not edit!\n"
+ oldversion = None
+ 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"
+ for symbol in symbols:
+ verout += " %s;\n" % symbol
+ verout += " local: *;\n"
+ if oldversion:
+ verout += "} %s_%s;\n" % (self.library_name, oldversion)
+ else:
+ verout += "};\n"
+ oldversion = version
+ return verout
+
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-r", "--override", action="append", nargs=2, metavar=("symbol", "version")
+ )
+ args, argv = parser.parse_known_args()
+ if len(argv) != 3:
+ usage(1)
+
+ ld = LdVersionScript(library_name=argv[0])
+ if args.override:
+ for override_symbol, override_version in args.override:
+ ld.overrides[override_symbol] = override_version
+ ld.import_gir(argv[1])
+ open(argv[2], "w").write(ld.render())
diff --git a/fwupd-1.8.6/contrib/meson.build b/fwupd-1.8.6/contrib/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..e4ca0958e8a149e918862f0266e2fa5d07b6ac39
--- /dev/null
+++ b/fwupd-1.8.6/contrib/meson.build
@@ -0,0 +1,21 @@
+subdir('firmware_packager')
+if get_option('qubes')
+ subdir('qubes')
+endif
+
+con2 = configuration_data()
+con2.set('FWUPD_VERSION', fwupd_version)
+
+configure_file(
+ input: 'fwupd.spec.in',
+ output: 'fwupd.spec.in',
+ configuration: con2,
+)
+
+if host_machine.system() == 'windows'
+ configure_file(
+ input: 'fwupd.wxs.in',
+ output: 'fwupd.wxs',
+ configuration: conf
+ )
+endif
diff --git a/fwupd-1.8.6/contrib/migrate.py b/fwupd-1.8.6/contrib/migrate.py
new file mode 100755
index 0000000000000000000000000000000000000000..f4e90a42f0308623ecd1ab41273909ed81854e27
--- /dev/null
+++ b/fwupd-1.8.6/contrib/migrate.py
@@ -0,0 +1,142 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2022 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+# import os
+import sys
+import glob
+
+
+if __name__ == "__main__":
+
+ fns = []
+
+ if len(sys.argv) > 1:
+ fns.extend(sys.argv[1:])
+ else:
+ exts = ["c", "h", "map"]
+ for ext in exts:
+ for fn in glob.glob("**/*.{}".format(ext), recursive=True):
+ if fn.startswith("build"):
+ continue
+ if fn.startswith("subprojects"):
+ continue
+ if fn.startswith(".git"):
+ continue
+ fns.append(fn)
+
+ for fn in fns:
+ modified: bool = False
+ with open(fn, "r") as f:
+ buf = f.read()
+ for old, new in {
+ "fu_common_sum8": "fu_sum8",
+ "fu_common_sum8_bytes": "fu_sum8_bytes",
+ "fu_common_sum16": "fu_sum16",
+ "fu_common_sum16_bytes": "fu_sum16_bytes",
+ "fu_common_sum16w": "fu_sum16w",
+ "fu_common_sum16w_bytes": "fu_sum16w_bytes",
+ "fu_common_sum32": "fu_sum32",
+ "fu_common_sum32_bytes": "fu_sum32_bytes",
+ "fu_common_sum32w": "fu_sum32w",
+ "fu_common_sum32w_bytes": "fu_sum32w_bytes",
+ "fu_common_crc8": "fu_crc8",
+ "fu_common_crc8_full": "fu_crc8_full",
+ "fu_common_crc16": "fu_crc16",
+ "fu_common_crc16_full": "fu_crc16_full",
+ "fu_common_crc32": "fu_crc32",
+ "fu_common_crc32_full": "fu_crc32_full",
+ "fu_byte_array_set_size_full": "fu_byte_array_set_size",
+ "fu_common_string_replace": "fu_string_replace",
+ "fu_common_string_append_kv": "fu_string_append",
+ "fu_common_string_append_ku": "fu_string_append_ku",
+ "fu_common_string_append_kx": "fu_string_append_kx",
+ "fu_common_string_append_kb": "fu_string_append_kb",
+ "fu_common_strnsplit": "fu_strsplit",
+ "fu_common_strnsplit_full": "fu_strsplit_full",
+ "fu_common_strjoin_array": "fu_strjoin",
+ "fu_common_strsafe": "fu_strsafe",
+ "fu_common_strwidth": "fu_strwidth",
+ "fu_common_strstrip": "fu_strstrip",
+ "fu_common_strtoull": "fu_strtoull",
+ "fu_common_strtoull_full": "fu_strtoull",
+ "FuCommonStrsplitFunc": "FuStrsplitFunc",
+ "fu_common_bytes_pad": "fu_bytes_pad",
+ "fu_common_bytes_new_offset": "fu_bytes_new_offset",
+ "fu_common_bytes_align": "fu_bytes_align",
+ "fu_common_bytes_is_empty": "fu_bytes_is_empty",
+ "fu_common_bytes_compare(": "fu_bytes_compare(",
+ "fu_common_set_contents_bytes": "fu_bytes_set_contents",
+ "fu_common_get_contents_bytes": "fu_bytes_get_contents",
+ "fu_common_get_contents_stream": "fu_bytes_get_contents_stream",
+ "fu_common_get_contents_fd": "fu_bytes_get_contents_fd",
+ "fu_common_read_uint8_safe": "fu_memread_uint8_safe",
+ "fu_common_read_uint16_safe": "fu_memread_uint16_safe",
+ "fu_common_read_uint32_safe": "fu_memread_uint32_safe",
+ "fu_common_read_uint64_safe": "fu_memread_uint64_safe",
+ "fu_common_write_uint8_safe": "fu_memwrite_uint8_safe",
+ "fu_common_write_uint16_safe": "fu_memwrite_uint16_safe",
+ "fu_common_write_uint32_safe": "fu_memwrite_uint32_safe",
+ "fu_common_write_uint64_safe": "fu_memwrite_uint64_safe",
+ "fu_common_write_uint16": "fu_memwrite_uint16",
+ "fu_common_write_uint24": "fu_memwrite_uint24",
+ "fu_common_write_uint32": "fu_memwrite_uint32",
+ "fu_common_write_uint64": "fu_memwrite_uint64",
+ "fu_common_read_uint16": "fu_memread_uint16",
+ "fu_common_read_uint24": "fu_memread_uint24",
+ "fu_common_read_uint32": "fu_memread_uint32",
+ "fu_common_read_uint64": "fu_memread_uint64",
+ "fu_common_bytes_compare_raw": "fu_memcmp_safe",
+ "FuOutputHandler": "FuSpawnOutputHandler",
+ "fu_common_spawn_sync": "fu_spawn_sync",
+ "fu_common_kernel_locked_down": "fu_kernel_locked_down",
+ "fu_common_check_kernel_version": "fu_kernel_check_version",
+ "fu_common_get_firmware_search_path": "fu_kernel_get_firmware_search_path",
+ "fu_common_set_firmware_search_path": "fu_kernel_set_firmware_search_path",
+ "fu_common_reset_firmware_search_path": "fu_kernel_reset_firmware_search_path",
+ "fu_common_firmware_builder": "fu_firmware_builder_process",
+ "fu_common_uri_get_scheme": "fu_release_uri_get_scheme",
+ "fu_common_dump_raw": "fu_dump_raw",
+ "fu_common_dump_full": "fu_dump_full",
+ "fu_common_dump_bytes": "fu_dump_bytes",
+ "fu_common_error_array_get_best": "fu_engine_error_array_get_best",
+ "fu_common_get_path": "fu_path_from_kind",
+ "fu_common_filename_glob": "fu_path_glob",
+ "fu_common_fnmatch": "fu_path_fnmatch",
+ "fu_common_rmtree": "fu_path_rmtree",
+ "fu_common_get_files_recursive": "fu_path_get_files",
+ "fu_common_mkdir": "fu_path_mkdir",
+ "fu_common_mkdir_parent": "fu_path_mkdir_parent",
+ "fu_common_find_program_in_path": "fu_path_find_program",
+ "fu_common_cpuid": "fu_cpuid",
+ "fu_common_get_cpu_vendor": "fu_cpu_get_vendor",
+ "fu_common_vercmp_full": "fu_version_compare",
+ "fu_common_version_ensure_semver_full": "fu_version_ensure_semver",
+ "fu_common_version_from_uint16": "fu_version_from_uint16",
+ "fu_common_version_from_uint32": "fu_version_from_uint32",
+ "fu_common_version_from_uint64": "fu_version_from_uint64",
+ "fu_common_version_guess_format": "fu_version_guess_format",
+ "fu_common_version_parse_from_format": "fu_version_parse_from_format",
+ "fu_common_version_verify_format": "fu_version_verify_format",
+ "fu_common_get_volumes_by_kind": "fu_volume_new_by_kind",
+ "fu_common_get_volume_by_device": "fu_volume_new_by_device",
+ "fu_common_get_volume_by_devnum": "fu_volume_new_by_devnum",
+ "fu_common_get_esp_for_path": "fu_volume_new_esp_for_path",
+ "fu_common_get_esp_default": "fu_context_get_esp_volumes",
+ "fu_smbios_to_string": "fu_firmware_to_string",
+ "fu_i2c_device_read_full": "fu_i2c_device_read",
+ "fu_i2c_device_write_full": "fu_i2c_device_write",
+ }.items():
+ if buf.find(old) == -1:
+ continue
+ buf = buf.replace(old, new)
+ modified = True
+ if modified:
+ print("MODIFIED: {}".format(fn))
+ with open(fn, "w") as f:
+ f.write(buf)
+
+ sys.exit(0)
diff --git a/fwupd-1.8.6/contrib/mingw64.cross b/fwupd-1.8.6/contrib/mingw64.cross
new file mode 100644
index 0000000000000000000000000000000000000000..31a289932e78e1d1003996732fc9268cc926644c
--- /dev/null
+++ b/fwupd-1.8.6/contrib/mingw64.cross
@@ -0,0 +1,2 @@
+[binaries]
+windmc = '/usr/bin/x86_64-w64-mingw32-windmc'
diff --git a/fwupd-1.8.6/contrib/prepare-system b/fwupd-1.8.6/contrib/prepare-system
new file mode 100755
index 0000000000000000000000000000000000000000..0d8b6c6d472521da2f46d830a7808f3b10323149
--- /dev/null
+++ b/fwupd-1.8.6/contrib/prepare-system
@@ -0,0 +1,48 @@
+#!/bin/bash -e
+# Setup local system for running development version
+
+PREFIX=$1
+ACTION=$2
+
+cleanup ()
+{
+ sudo rm -f /etc/dbus-1/system-local.conf \
+ /usr/share/polkit-1/actions/org.freedesktop.fwupd.policy \
+ /usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules \
+ /etc/grub.d/35_fwupd
+}
+
+install ()
+{
+ cat > system-local.conf << EOF
+
+ PREFIX/share/dbus-1/system.d
+
+EOF
+ sed -i s,PREFIX,$1, system-local.conf
+ sudo mv system-local.conf /etc/dbus-1/system-local.conf
+ sudo ln -s $1/share/polkit-1/actions/org.freedesktop.fwupd.policy \
+ /usr/share/polkit-1/actions/org.freedesktop.fwupd.policy
+ sudo ln -s $1/polkit-1/rules.d/org.freedesktop.fwupd.rules \
+ /usr/share/polkit-1/rules.d/org.freedesktop.fwupd.rules
+ sudo ln -s /usr/local/etc/grub.d/35_fwupd /etc/grub.d/35_fwupd
+}
+
+if [ "$PREFIX" = "/" ]; then
+ echo "Invalid prefix: $PREFIX"
+ exit 1
+fi
+case $ACTION in
+ remove)
+ cleanup
+ ;;
+ install)
+ cleanup
+ install $PREFIX
+ ;;
+ *)
+ echo "Unknown action $ACTION"
+ exit 1
+ ;;
+esac
+sudo systemctl reload dbus.service
diff --git a/fwupd-1.8.6/contrib/qubes/README.md b/fwupd-1.8.6/contrib/qubes/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4b3aa2daf8d9b80eea0e710511e580cd1d2118b1
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/README.md
@@ -0,0 +1,222 @@
+# qubes-fwupd
+
+fwupd wrapper for QubesOS
+
+## Table of Contents
+
+* [Requirements](#Requirements)
+* [Usage](#Usage)
+* [Installation](#Installation)
+* [Testing](#Testing)
+* [Whonix support](doc/whonix.md)
+* [UEFI capsule update](doc/uefi_capsule_update.md)
+* [Heads update](doc/heads_update.md)
+
+## OS Requirements
+
+**Operating System:** Qubes OS R4.1
+
+**Admin VM (dom0):** Fedora 32
+
+**Template VM:** Fedora 32
+
+**Whonix VM:** whonix-gw-15
+
+## Usage
+
+```text
+==========================================================================================
+Usage:
+==========================================================================================
+ Command: qubes-fwupdmgr [OPTION…][FLAG..]
+ Example: qubes-fwupdmgr refresh --whonix --url=
+
+Options:
+==========================================================================================
+ get-devices: Get all devices that support firmware updates
+ get-updates: Get the list of updates for connected hardware
+ refresh: Refresh metadata from remote server
+ update: Update chosen device to latest firmware version
+ update-heads: Updates heads firmware to the latest version
+ downgrade: Downgrade chosen device to chosen firmware version
+ clean: Delete all cached update files
+
+Flags:
+==========================================================================================
+ --whonix: Download firmware updates via Tor
+ --device: Specify device for heads update (default - x230)
+ --url: Address of the custom metadata remote server
+
+Help:
+==========================================================================================
+ -h --help: Show help options
+```
+
+## Installation
+
+For development purpose:
+
+* Build the package for fedora and debian as it is shown in the contrib
+[README](../README.md).
+* The build artifacts are placed in `dist` directory:
+ -- dom0 package - `dist/fwupd-qubes-dom0--0.1alpha.fc32.x86_64.rpm`
+ -- vm package - `dist/fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm`
+ -- whonix package - `dist/fwupd-qubes-vm-whonix-_amd64.deb`
+
+* Copy packages to the Qubes OS.
+* Move the `fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm` to the Fedora 32
+template VM (replace `` with the current version)
+
+```shell
+qvm-copy fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm
+```
+
+* Install package dependencies
+
+```shell
+# dnf install gcab fwupd
+```
+
+* Run terminal in the template VM and go to
+`~/QubesIncoming/`. Compare SHA sums of the package in
+TemplateVM and qubes-builder VM. If they match, install the package:
+
+```shell
+# rpm -U fwupd-qubes-vm--0.1alpha.fc32.x86_64.rpm
+```
+
+* Shutdown TemplateVM
+
+* Run whonix-gw-15 and copy whonix a package from qubes builder VM
+
+```shell
+qvm-copy fwupd-qubes-vm-whonix-_amd64.deb
+```
+
+* Install dependencies
+
+```shell
+# apt install gcab fwupd
+```
+
+* Run terminal in the whonix-gw-15 and go to `~/QubesIncoming/qubes-builder`.
+ Compare SHA sums of the package in TemplateVM and qubes-builder VM. If they
+ match, install the package:
+
+ ```shell
+ # dpkg -i fwupd-qubes-vm-whonix-_amd64.deb
+ ```
+
+* Shutdown whonix-gw-15
+
+* Run dom0 terminal in the dom0 and copy package:
+
+ ```shell
+ $ qvm-run --pass-io \
+ 'cat /qubes-src/fwupd/pkgs/dom0-fc32/x86_64/fwupd-qubes-dom0--0.1alpha.fc32.x86_64.rpm' > \
+ fwupd-qubes-dom0--0.1alpha.fc32.x86_64.rpm
+ ```
+
+* Install package dependencies:
+
+ ```shell
+ # qubes-dom0-update gcab fwupd python36
+ ```
+
+* Make sure that sys-firewall, sys-whonix, and sys-usb (if exists) are running.
+
+* Compare the SHA sums of the package in dom0 and qubes-builder VM.
+ If they match, install the package:
+
+ ```shell
+ # rpm -U qubes-fwupd-dom0-0.2.0-1.fc32.x86_64.rpm
+ ```
+
+* Reboot system (or reboot sys-firewall, sys-whonix, and sys-usb)
+
+* Run the tests to verify the installation process
+
+## Testing
+
+### Outside the Qubes OS
+
+A test case covers the whole qubes_fwupdmgr script. It could be run outside the
+Qubes OS. If the requirements of a single test are not met, it will be omitted.
+To run the tests, move to the repo directory and type the following:
+
+```shell
+$ python3 -m unittest -v test.test_qubes_fwupdmgr
+
+test_clean_cache (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_downgrade_firmware (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'Required device not connected'
+test_download_firmware_updates (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_download_metadata (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_get_devices (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_get_devices_qubes (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_get_updates (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_get_updates_qubes (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_help (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_output_crawler (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_parse_downgrades (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_parse_parameters (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_parse_updates_info (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_refresh_metadata (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... skipped 'requires Qubes OS'
+test_user_input_choice (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_user_input_downgrade (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_user_input_empty_list (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_user_input_n (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_verify_dmi (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_verify_dmi_argument_version (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_verify_dmi_version (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+test_verify_dmi_wrong_vendor (test.test_qubes_fwupdmgr.TestQubesFwupdmgr) ... ok
+
+----------------------------------------------------------------------
+Ran 22 tests in 0.003s
+
+OK (skipped=8)
+```
+
+### In the Qubes OS
+
+In the dom0, move to:
+
+```shell
+cd /usr/share/qubes-fwupd/
+```
+
+#### Qubes OS 4.1
+
+Run the tests with sudo privileges:
+
+```shell
+# python3 -m unittest -v test.test_qubes_fwupdmgr
+```
+
+Note: If the whonix tests failed, make sure that you are connected to the Tor
+
+## Whonix support
+
+```shell
+# qubes-fwupdmgr [refresh/update/downgrade] --whonix [FLAG]
+```
+
+More specified information you will find in the
+[whonix documentation](doc/whonix.md).
+
+## UEFI capsule update
+
+```shell
+# qubes-fwupdmgr [update/downgrade]
+```
+
+Requirements and more specified information you will find in the
+[UEFI capsule update documentation](doc/uefi_capsule_update.md).
+
+## Heads update
+
+```shell
+# qubes-fwupdmgr update-heads --device=x230 --url=
+```
+
+Requirements and more specified information you will find in the
+[heads update documentation](doc/heads_update.md).
diff --git a/fwupd-1.8.6/contrib/qubes/doc/heads_update.md b/fwupd-1.8.6/contrib/qubes/doc/heads_update.md
new file mode 100644
index 0000000000000000000000000000000000000000..a9559443f88941f29946dd91e63c00ca914bc079
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/doc/heads_update.md
@@ -0,0 +1,63 @@
+# Heads update
+
+The Heads update was tested on the `Lenovo ThinkPad x230`.
+
+## Requirements
+
+You need to build and flash Heads ROM from the
+[3mdeb fork](https://github.com/3mdeb/heads/tree/qubes-fwupd).
+You will find there Heads ROMs for ThinkPad x230.
+
+## Update process
+
+ThinkPad x230 is now the only laptop that has Heads ROM in the custom LVFS
+storage. Nevertheless, qubes-fwupd has already implemented a `device` flag, that
+will allow updates for other hardware.
+
+At first run the qubes-fwupd Heads update.
+
+```shell
+sudo qubes-fwupdmgr update-heads --device=x230
+```
+
+Press Y to reboot the device.
+
+In the main menu, choose `options` and then go to `Flash/Update the BIOS`
+
+
+
+Decide to retain or erase the settings.
+
+
+
+The tool will inform you that heads update has been detected in `/boot`
+directory. If you will decide not to update, you will be asked to attach the
+USB drive.
+
+
+
+Select a ROM file.
+
+
+
+Press yes to confirm the choice. The Heads update will begin.
+
+
+
+Wait until the end of the update process.
+
+
+
+Press OK to reboot the system.
+
+
+
+## Test
+
+Change directory to `/usr/share/qubes-fwupd` and run test case with sudo
+privileges.
+
+### Qubes OS R4.1
+
+```shell
+# python3 -m unittest -v test.test_qubes_fwupd_heads
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_detected.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_detected.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8c322f90e1ec8e89408bd3cda72e0183be39b49c
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_detected.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_firmware_managment_menu.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_firmware_managment_menu.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..74da7bd16b6825262722b70e707a8629f040fe4c
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_firmware_managment_menu.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_flash_rom.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_flash_rom.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7770da5dfdbe4827b729c4edd1e40963fce6a49b
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_flash_rom.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_options.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_options.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8f55d57686c353c41a6bcb62291f31d7f47e7e0e
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_options.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_selecting_rom.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_selecting_rom.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..10066b1208f95a7333db3b79c7de9c2ea3ee655f
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_selecting_rom.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_success.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_success.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..987be595b8d917c2c8edad1c904561763e5381b2
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_success.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/heads_update_process.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/heads_update_process.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..668b1d717e9987cbb1e704176456f2674532f9df
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/heads_update_process.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/qubes_manager.png b/fwupd-1.8.6/contrib/qubes/doc/img/qubes_manager.png
new file mode 100644
index 0000000000000000000000000000000000000000..8775127ffce6d2e803756326283a21e9d79b3106
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/qubes_manager.png differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/uefi_ME.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/uefi_ME.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..89790da0e499fbb0272a40728dfe59524b323e49
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/uefi_ME.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/uefi_capsule_found.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/uefi_capsule_found.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..fba123330de0e72e2b83394a54b00ebb0fecb95f
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/uefi_capsule_found.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/img/uefi_success.jpg b/fwupd-1.8.6/contrib/qubes/doc/img/uefi_success.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a329a45c8c36b6515cdb9f16dbe434896ca304c7
Binary files /dev/null and b/fwupd-1.8.6/contrib/qubes/doc/img/uefi_success.jpg differ
diff --git a/fwupd-1.8.6/contrib/qubes/doc/uefi_capsule_update.md b/fwupd-1.8.6/contrib/qubes/doc/uefi_capsule_update.md
new file mode 100644
index 0000000000000000000000000000000000000000..932cb23b841bca67477d18d092a8749e80181e6c
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/doc/uefi_capsule_update.md
@@ -0,0 +1,47 @@
+# UEFI capsule update
+
+The qubes-fwupd handle the UEFI capsule update under several conditions.
+The fwupd uses ESRT tables to read GUID, and that causes trouble when the OS
+is running under a hypervisor. The Xen does not pass the ESRT tables to
+paravirtualized dom0, so the Qubes is not able to provide sysfs information.
+More information you can find it this thread:
+
+
+
+## Requirements
+
+### Qubes OS
+
+You need Qubes R4.1 to use the UEFI capsule update.
+
+### Hardware
+
+Make sure that your hardware has available firmware updates in the [LVFS](https://fwupd.org/)
+
+## UEFI capsule update - downgrade
+
+UEFI capsule updates and downgrades were tested on DELL XPS 15 9560.
+
+```shell
+sudo qubes-fwupdmgr downgrade
+```
+
+## UEFI capsule update - update
+
+```shell
+sudo qubes-fwupdmgr update
+```
+
+## Update process
+
+### Capsule found
+
+
+
+### ME updated
+
+
+
+### Success
+
+
diff --git a/fwupd-1.8.6/contrib/qubes/doc/whonix.md b/fwupd-1.8.6/contrib/qubes/doc/whonix.md
new file mode 100644
index 0000000000000000000000000000000000000000..a2064b885f5184fbae5c8dc303c08dc51de522c2
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/doc/whonix.md
@@ -0,0 +1,23 @@
+# Whonix support
+
+The qubes-fwupd uses the sys-whonix VM as the update VM to handle downloading
+updates and metadata via Tor. The tests detect if sys-whonix is running, but
+do not check if you are connected with Tor. So before running the test make sure
+that sys-whonix has access to the network.
+
+## Refresh
+
+```shell
+sudo qubes-fwupdmgr refresh --whonix
+```
+
+## Update
+
+```shell
+sudo qubes-fwupdmgr update --whonix
+```
+
+## Downgrade
+
+```shell
+sudo qubes-fwupdmgr downgrade --whonix
diff --git a/fwupd-1.8.6/contrib/qubes/meson.build b/fwupd-1.8.6/contrib/qubes/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..639ae9e14c2527b3e4fed2e40311662d29b5bd34
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/meson.build
@@ -0,0 +1,53 @@
+install_data([
+ 'src/__init__.py',
+ 'src/fwupd_receive_updates.py',
+ 'src/qubes_fwupd_heads.py',
+ 'src/qubes_fwupd_update.py',
+ ],
+ install_dir: 'share/qubes-fwupd/src',
+)
+
+install_data([
+ 'test/__init__.py',
+ 'test/fwupd_logs.py',
+ 'test/test_qubes_fwupd_heads.py',
+ 'test/test_qubes_fwupdmgr.py',
+ ],
+ install_dir: 'share/qubes-fwupd/test',
+)
+
+install_data([
+ 'test/logs/firmware.metainfo.xml',
+ 'test/logs/get_devices.log',
+ 'test/logs/get_updates.log',
+ 'test/logs/help.log',
+ ],
+ install_dir: 'share/qubes-fwupd/test/logs',
+)
+
+install_data([
+ 'src/vms/fwupd_common_vm.py',
+ 'src/vms/fwupd_download_updates.py',
+ 'src/vms/fwupd_usbvm_validate.py',
+ ],
+ install_dir: 'libexec/qubes-fwupd',
+ install_mode: 'rwxrwxr-x',
+)
+
+install_data([
+ 'test/logs/metainfo_name/firmware.metainfo.xml',
+ ],
+ install_dir: 'share/qubes-fwupd/test/logs/metainfo_name',
+)
+
+install_data(
+ 'test/logs/metainfo_version/firmware.metainfo.xml',
+ install_dir: 'share/qubes-fwupd/test/logs/metainfo_version',
+)
+
+install_data(
+ 'src/qubes_fwupdmgr.py',
+ install_dir: 'sbin',
+ rename: 'qubes-fwupdmgr',
+ install_mode: 'rwxrwxr-x',
+)
diff --git a/fwupd-1.8.6/contrib/qubes/src/__init__.py b/fwupd-1.8.6/contrib/qubes/src/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/fwupd-1.8.6/contrib/qubes/src/fwupd_receive_updates.py b/fwupd-1.8.6/contrib/qubes/src/fwupd_receive_updates.py
new file mode 100644
index 0000000000000000000000000000000000000000..edf1de9f028758100cc4a72f0b99570042d60cee
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/fwupd_receive_updates.py
@@ -0,0 +1,258 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2010 Rafal Wojtczuk
+# 2020 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import glob
+import grp
+import hashlib
+import os
+import re
+import shutil
+import subprocess
+
+FWUPD_DOM0_DIR = "/root/.cache/fwupd"
+FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
+FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted")
+FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata")
+FWUPD_DOM0_METADATA_FILE = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
+FWUPD_DOM0_METADATA_JCAT = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz.jcat")
+
+FWUPD_VM_DIR = "/home/user/.cache/fwupd"
+FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
+FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
+FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
+FWUPD_VM_METADATA_JCAT = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat")
+FWUPD_PKI = "/etc/pki/fwupd"
+FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
+FWUPD_METADATA_FLAG_REGEX = re.compile(r"^metaflag")
+FWUPD_METADATA_FILES_REGEX = re.compile(
+ r"^firmware[a-z0-9\[\]\@\<\>\.\"\-]{0,128}.xml.gz.?[aj]?[sc]?[ca]?t?$"
+)
+HEADS_UPDATES_DIR = "/boot/updates"
+WARNING_COLOR = "\033[93m"
+
+
+class FwupdReceiveUpdates:
+ def _check_shasum(self, file_path, sha):
+ """Compares computed SHA256 checksum with `sha` parameter.
+
+ Keyword arguments:
+ file_path -- absolute path to the file
+ sha -- SHA256 checksum of the file
+ """
+ with open(file_path, "rb") as f:
+ c_sha = hashlib.sha256(f.read()).hexdigest()
+ if c_sha != sha:
+ self.clean_cache()
+ raise ValueError(f"Computed checksum {c_sha} did NOT match {sha}.")
+
+ def _check_domain(self, updatevm):
+ """Checks if domain given as `updatevm` is allowed to send update
+ files.
+
+ Keyword argument:
+ updatevm - domain to be checked
+ """
+ cmd = ["qubes-prefs", "--force-root", "updatevm"]
+ p = subprocess.check_output(cmd)
+ source = p.decode("ascii").rstrip()
+ if source != updatevm and "sys-whonix" != updatevm:
+ raise Exception(f"Domain {updatevm} not allowed to send dom0 updates")
+
+ def _verify_received(self, files_path, regex_pattern, updatevm):
+ """Checks if sent files match regex filename pattern.
+
+ Keyword arguments:
+
+ files_path -- absolute path to inspected directory
+ regex_pattern -- pattern of the expected files
+ updatevm - domain to be checked
+ """
+ for untrusted_f in os.listdir(files_path):
+ if not regex_pattern.match(untrusted_f):
+ raise Exception(f"Domain {updatevm} sent unexpected file")
+ f = untrusted_f
+ assert "/" not in f
+ assert "\0" not in f
+ assert "\x1b" not in f
+ path_f = os.path.join(files_path, f)
+ if os.path.islink(path_f) or not os.path.isfile(path_f):
+ raise Exception(f"Domain {updatevm} sent not regular file")
+
+ def _create_dirs(self, *args):
+ """Method creates directories.
+
+ Keyword arguments:
+ *args -- paths to be created
+ """
+ qubes_gid = grp.getgrnam("qubes").gr_gid
+ self.old_umask = os.umask(0o002)
+ if args is None:
+ raise Exception("Creating directories failed, no paths given.")
+ for file_path in args:
+ if not os.path.exists(file_path):
+ os.mkdir(file_path)
+ os.chown(file_path, -1, qubes_gid)
+ os.chmod(file_path, 0o0775)
+ elif os.stat(file_path).st_gid != qubes_gid:
+ print(
+ f"{WARNING_COLOR}Warning: You should move a personal files"
+ f" from {file_path}. Cleaning cache will cause lose of "
+ f"the personal data!!{WARNING_COLOR}"
+ )
+
+ def _extract_archive(self, archive_path, output_path):
+ """Extracts archive file to the specified directory.
+
+ Keyword arguments:
+ archive_path -- absolute path to archive file
+ output_path -- absolute path to the output directory
+ """
+ cmd_extract = ["gcab", "-x", f"--directory={output_path}", f"{archive_path}"]
+ shutil.copy(archive_path, FWUPD_DOM0_UPDATES_DIR)
+ p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE)
+ p.communicate()[0].decode("ascii")
+ if p.returncode != 0:
+ raise Exception(f"gcab: Error while extracting {archive_path}.")
+
+ def _jcat_verification(self, file_path, file_directory):
+ """Verifies sha1 and sha256 checksum, GPG signature,
+ and PKCS#7 signature.
+
+ Keyword argument:
+ file_path -- absolute path to jcat file
+ file_directory -- absolute path to the directory to jcat file location
+ """
+ cmd_jcat = ["jcat-tool", "verify", f"{file_path}", "--public-keys", FWUPD_PKI]
+ p = subprocess.Popen(
+ cmd_jcat, cwd=file_directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ stdout, __ = p.communicate()
+ verification = stdout.decode("utf-8")
+ print(verification)
+ if p.returncode != 0:
+ self.clean_cache()
+ raise Exception("jcat-tool: Verification failed")
+
+ def handle_fw_update(self, updatevm, sha, filename):
+ """Copies firmware update archives from the updateVM.
+
+ Keyword arguments:
+ updatevm -- update VM name
+ sha -- SHA256 checksum of the firmware update archive
+ filename -- name of the firmware update archive
+ """
+ fwupd_firmware_file_regex = re.compile(filename)
+ dom0_firmware_untrusted_path = os.path.join(FWUPD_DOM0_UNTRUSTED_DIR, filename)
+ updatevm_firmware_file_path = os.path.join(FWUPD_VM_UPDATES_DIR, filename)
+
+ self._check_domain(updatevm)
+ if os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR):
+ shutil.rmtree(FWUPD_DOM0_UNTRUSTED_DIR)
+ self._create_dirs(FWUPD_DOM0_UPDATES_DIR, FWUPD_DOM0_UNTRUSTED_DIR)
+
+ cmd_copy = "qvm-run --pass-io %s %s > %s" % (
+ updatevm,
+ "'cat %s'" % updatevm_firmware_file_path,
+ dom0_firmware_untrusted_path,
+ )
+ p = subprocess.Popen(cmd_copy, shell=True)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("qvm-run: Copying firmware file failed!!")
+
+ self._verify_received(
+ FWUPD_DOM0_UNTRUSTED_DIR, fwupd_firmware_file_regex, updatevm
+ )
+ self._check_shasum(dom0_firmware_untrusted_path, sha)
+ untrusted_dir_name = filename.replace(".cab", "")
+ self._extract_archive(dom0_firmware_untrusted_path, FWUPD_DOM0_UNTRUSTED_DIR)
+ signature_name = os.path.join(FWUPD_DOM0_UNTRUSTED_DIR, "firmware*.jcat")
+ file_path = glob.glob(signature_name)
+ if not file_path:
+ raise FileNotFoundError("jcat file not found!")
+ self._jcat_verification(file_path[0], FWUPD_DOM0_UNTRUSTED_DIR)
+ os.umask(self.old_umask)
+ if untrusted_dir_name == "untrusted":
+ untrusted_dir_name = "trusted"
+ verified_file = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename)
+ self.arch_name = "trusted.cab"
+ self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, self.arch_name)
+ shutil.move(verified_file, self.arch_path)
+ else:
+ self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename)
+ dir_name = os.path.join(FWUPD_DOM0_UPDATES_DIR, untrusted_dir_name)
+ os.remove(dom0_firmware_untrusted_path)
+ shutil.move(FWUPD_DOM0_UNTRUSTED_DIR, dir_name)
+
+ def handle_metadata_update(self, updatevm, metadata_url=None):
+ """Copies metadata files from the updateVM.
+
+ Keyword argument:
+ updatevm -- update VM name
+ """
+ if metadata_url:
+ metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
+ self.metadata_file = os.path.join(FWUPD_DOM0_METADATA_DIR, metadata_name)
+ self.metadata_file_jcat = self.metadata_file + ".jcat"
+ else:
+ self.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.metadata_file_jcat = FWUPD_DOM0_METADATA_JCAT
+ self.metadata_file_updatevm = self.metadata_file.replace(
+ FWUPD_DOM0_METADATA_DIR, FWUPD_VM_METADATA_DIR
+ )
+ self.metadata_file_jcat_updatevm = self.metadata_file_jcat.replace(
+ FWUPD_DOM0_METADATA_DIR, FWUPD_VM_METADATA_DIR
+ )
+ self._check_domain(updatevm)
+ self._create_dirs(FWUPD_DOM0_METADATA_DIR)
+ cmd_file = "'cat %s'" % self.metadata_file_updatevm
+ cmd_jcat = "'cat %s'" % self.metadata_file_jcat_updatevm
+ cmd_copy_metadata_file = "qvm-run --pass-io %s %s > %s" % (
+ updatevm,
+ cmd_file,
+ self.metadata_file,
+ )
+ cmd_copy_metadata_jcat = "qvm-run --pass-io %s %s > %s" % (
+ updatevm,
+ cmd_jcat,
+ self.metadata_file_jcat,
+ )
+
+ p = subprocess.Popen(cmd_copy_metadata_file, shell=True)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("qvm-run: Copying metadata file failed!!")
+ p = subprocess.Popen(cmd_copy_metadata_jcat, shell=True)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception('qvm-run": Copying metadata jcat failed!!')
+
+ self._verify_received(
+ FWUPD_DOM0_METADATA_DIR, FWUPD_METADATA_FILES_REGEX, updatevm
+ )
+ self._jcat_verification(self.metadata_file_jcat, FWUPD_DOM0_METADATA_DIR)
+ os.umask(self.old_umask)
+
+ def clean_cache(self, usbvm=False):
+ """Removes updates data
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ """
+ print("Cleaning dom0 cache directories")
+ if os.path.exists(FWUPD_DOM0_METADATA_DIR):
+ shutil.rmtree(FWUPD_DOM0_METADATA_DIR)
+ if os.path.exists(FWUPD_DOM0_UPDATES_DIR):
+ shutil.rmtree(FWUPD_DOM0_UPDATES_DIR)
+ if os.path.exists(HEADS_UPDATES_DIR):
+ shutil.rmtree(HEADS_UPDATES_DIR)
+ if usbvm:
+ print("Cleaning usbvm cache directories")
+ self._clean_usbvm()
diff --git a/fwupd-1.8.6/contrib/qubes/src/qubes_fwupd_heads.py b/fwupd-1.8.6/contrib/qubes/src/qubes_fwupd_heads.py
new file mode 100644
index 0000000000000000000000000000000000000000..d551c73dcaea70661177236d6a180334320c1d26
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/qubes_fwupd_heads.py
@@ -0,0 +1,117 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import subprocess
+import os
+import shutil
+import xml.etree.ElementTree as ET
+from packaging.version import Version
+
+FWUPDTOOL = "/bin/fwupdtool"
+
+BOOT = "/boot"
+HEADS_UPDATES_DIR = os.path.join(BOOT, "updates")
+
+EXIT_CODES = {"ERROR": 1, "SUCCESS": 0, "NOTHING_TO_DO": 2}
+
+
+class FwupdHeads:
+ def _get_hwids(self):
+ cmd_hwids = [FWUPDTOOL, "hwids"]
+ p = subprocess.Popen(cmd_hwids, stdout=subprocess.PIPE)
+ self.dom0_hwids_info = p.communicate()[0].decode()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Getting hwids info failed")
+
+ def _gather_firmware_version(self):
+ """
+ Checks if Qubes works under heads
+ """
+ if "Heads" in self.dom0_hwids_info:
+ self.heads_version = None
+ hwids = self.dom0_hwids_info.split("\n")
+ for line in hwids:
+ if "Heads" in line:
+ self.heads_version = line.split("Heads-v")[1]
+ else:
+ print("Device is not running under the heads firmware!!")
+ print("Exiting...")
+ return EXIT_CODES["NOTHING_TO_DO"]
+
+ def _parse_metadata(self, metadata_file):
+ """
+ Parse metadata info.
+ """
+ cmd_metadata = ["zcat", metadata_file]
+ p = subprocess.Popen(cmd_metadata, stdout=subprocess.PIPE)
+ self.metadata_info = p.communicate()[0].decode()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Parsing metadata failed")
+
+ def _parse_heads_updates(self, device):
+ """
+ Parses heads updates info.
+
+ Keyword arguments:
+ device -- Model of the updated device
+ """
+ self.heads_update_url = None
+ self.heads_update_sha = None
+ self.heads_update_version = None
+ heads_metadata_info = None
+ root = ET.fromstring(self.metadata_info)
+ for component in root.findall("component"):
+ if f"heads.{device}" in component.find("id").text:
+ heads_metadata_info = component
+ if not heads_metadata_info:
+ print("No metadata info for chosen board")
+ return EXIT_CODES["NOTHING_TO_DO"]
+ for release in heads_metadata_info.find("releases").findall("release"):
+ release_ver = release.get("version")
+ if self.heads_version == "heads" or Version(release_ver) > Version(
+ self.heads_version
+ ):
+ if not self.heads_update_version or Version(release_ver) > Version(
+ self.heads_update_version
+ ):
+ self.heads_update_url = release.find("location").text
+ for sha in release.findall("checksum"):
+ if (
+ ".cab" in sha.attrib["filename"]
+ and sha.attrib["type"] == "sha256"
+ ):
+ self.heads_update_sha = sha.text
+ self.heads_update_version = release_ver
+ if self.heads_update_url:
+ return EXIT_CODES["SUCCESS"]
+ else:
+ print("Heads firmware is up to date.")
+ return EXIT_CODES["NOTHING_TO_DO"]
+
+ def _copy_heads_firmware(self, arch_path):
+ """
+ Copies heads update to the boot path
+ """
+ heads_boot_path = os.path.join(HEADS_UPDATES_DIR, self.heads_update_version)
+ update_path = arch_path.replace(".cab", "/firmware.rom")
+
+ heads_update_path = os.path.join(heads_boot_path, "firmware.rom")
+ if not os.path.exists(HEADS_UPDATES_DIR):
+ os.mkdir(HEADS_UPDATES_DIR)
+ if os.path.exists(heads_update_path):
+ print(f"Heads Update == {self.heads_update_version} " "already downloaded.")
+ return EXIT_CODES["NOTHING_TO_DO"]
+ else:
+ os.mkdir(heads_boot_path)
+ shutil.copyfile(update_path, heads_update_path)
+ print(
+ f"Heads Update == {self.heads_update_version} "
+ f"available at {heads_boot_path}"
+ )
+ return EXIT_CODES["SUCCESS"]
diff --git a/fwupd-1.8.6/contrib/qubes/src/qubes_fwupd_update.py b/fwupd-1.8.6/contrib/qubes/src/qubes_fwupd_update.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ae4f965d99e943856585256472d136f7b395c98
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/qubes_fwupd_update.py
@@ -0,0 +1,156 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kaminski
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import grp
+import os
+import re
+import subprocess
+
+FWUPD_DOM0_DIR = "/root/.cache/fwupd"
+FWUPD_VM_DOWNLOAD = "/usr/libexec/qubes-fwupd/fwupd_download_updates.py"
+FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
+FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
+
+SPECIAL_CHAR_REGEX = re.compile(r"%20|&|\||#")
+UPDATEVM_REGEX = re.compile(r"^sys-")
+
+WARNING_COLOR = "\033[93m"
+
+
+class FwupdUpdate:
+ def _create_dirs(self, *args):
+ """Method creates directories.
+
+ Keyword arguments:
+ *args -- paths to be created
+ """
+ qubes_gid = grp.getgrnam("qubes").gr_gid
+ self.old_umask = os.umask(0o002)
+ if args is None:
+ raise Exception("Creating directories failed, no paths given.")
+ for file_path in args:
+ if not os.path.exists(file_path):
+ os.mkdir(file_path)
+ os.chown(file_path, -1, qubes_gid)
+ elif os.stat(file_path).st_gid != qubes_gid:
+ print(
+ f"{WARNING_COLOR}Warning: You should move a personal files"
+ f" from {file_path}. Cleaning cache will cause lose of "
+ f"the personal data!!{WARNING_COLOR}"
+ )
+
+ def _specify_updatevm(self):
+ cmd_updatevm = ["qubes-prefs", "--force-root", "updatevm"]
+ p = subprocess.Popen(cmd_updatevm, stdout=subprocess.PIPE)
+ self.updatevm = p.communicate()[0].decode().split("\n")[0]
+ if p.returncode != 0 and not UPDATEVM_REGEX.match(self.updatevm):
+ self.updatevm = None
+ raise Exception("Specifying updatevm failed")
+
+ def _check_updatevm(self):
+ """Checks if usbvm is running"""
+ cmd_xl_list = ["xl", "list"]
+ p = subprocess.Popen(cmd_xl_list, stdout=subprocess.PIPE)
+ output = p.communicate()[0].decode()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Firmware downgrade failed")
+ return self.updatevm in output
+
+ def _encrypt_update_url(self, url):
+ self.enc_url = url
+ self.arch_name = url.replace(FWUPD_DOWNLOAD_PREFIX, "")
+ self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, self.arch_name)
+ if "&" in url:
+ self.enc_url = self.enc_url.replace("&", "--and--")
+ self.arch_name = "untrusted.cab"
+ if "|" in url:
+ self.enc_url = self.enc_url.replace("|", "--or--")
+ self.arch_name = "untrusted.cab"
+ if "#" in url:
+ self.enc_url = self.enc_url.replace("#", "--hash--")
+ self.arch_name = "untrusted.cab"
+ if "%20" in url:
+ self.arch_name = "untrusted.cab"
+
+ def download_metadata(self, whonix=False, metadata_url=None):
+ """Initialize downloading metadata files.
+
+ Keywords arguments:
+ whonix -- Flag enforces downloading the metadata updates via Tor
+ metadata_url -- Download metadata from the custom url
+ """
+ if not whonix:
+ self._specify_updatevm()
+ else:
+ self.updatevm = "sys-whonix"
+ if not self._check_updatevm():
+ raise Exception(f"{self.updatevm} is not running!!")
+ if not os.path.exists(FWUPD_DOM0_DIR):
+ self._create_dirs(FWUPD_DOM0_DIR)
+ if metadata_url:
+ cmd_metadata = [
+ "qvm-run",
+ "--pass-io",
+ self.updatevm,
+ (
+ "script --quiet --return --command "
+ f'"{FWUPD_VM_DOWNLOAD} --metadata'
+ f' --url={metadata_url}"'
+ ),
+ ]
+ else:
+ cmd_metadata = [
+ "qvm-run",
+ "--pass-io",
+ self.updatevm,
+ (
+ "script --quiet --return --command "
+ f'"{FWUPD_VM_DOWNLOAD} --metadata"'
+ ),
+ ]
+ p = subprocess.Popen(cmd_metadata)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Metadata download failed.")
+
+ def download_firmware_updates(self, url, sha, whonix=False):
+ """Initializes downloading firmware update archive.
+
+ Keywords arguments:
+ url -- url path to the firmware update archive
+ sha -- SHA256 checksum of the firmware update archive
+ whonix -- Flag enforces downloading the updates via Tor
+ """
+ if not whonix:
+ self._specify_updatevm()
+ else:
+ self.updatevm = "sys-whonix"
+ if not self._check_updatevm():
+ raise Exception(f"{self.updatevm} is not running!!")
+ if not os.path.exists(FWUPD_DOM0_DIR):
+ self._create_dirs(FWUPD_DOM0_DIR)
+ self._encrypt_update_url(url)
+ if not os.path.exists(self.arch_path):
+ cmd_firmware_download = [
+ "qvm-run",
+ "--pass-io",
+ self.updatevm,
+ (
+ "script --quiet --return --command "
+ f'"{FWUPD_VM_DOWNLOAD} --url={self.enc_url}'
+ f' --sha={sha}"'
+ ),
+ ]
+ p = subprocess.Popen(cmd_firmware_download)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Firmware download failed.")
+ else:
+ self.cached = True
+ print("Firmware already downloaded. Using cached files.")
diff --git a/fwupd-1.8.6/contrib/qubes/src/qubes_fwupdmgr.py b/fwupd-1.8.6/contrib/qubes/src/qubes_fwupdmgr.py
new file mode 100755
index 0000000000000000000000000000000000000000..93dd9d0b9549e9611fce1d1be274518ea03c9e94
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/qubes_fwupdmgr.py
@@ -0,0 +1,1020 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kaminski
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import json
+import os
+import re
+import shutil
+import subprocess
+import sys
+import xml.etree.ElementTree as ET
+
+from pathlib import Path
+from packaging.version import Version
+
+FWUPD_QUBES_DIR = "/usr/share/qubes-fwupd"
+
+# Check if script is run by tests and append sys path properly
+if __name__ == "__main__":
+ sys.path.append(os.path.join(FWUPD_QUBES_DIR, "src"))
+else:
+ sys.path.append("./src")
+
+try:
+ from qubes_fwupd_heads import FwupdHeads
+ from qubes_fwupd_update import FwupdUpdate
+ from fwupd_receive_updates import FwupdReceiveUpdates
+except ModuleNotFoundError:
+ raise ModuleNotFoundError(
+ "qubes-fwupd modules not found. " "You may need to reinstall package."
+ )
+
+FWUPD_DOM0_DIR = "/root/.cache/fwupd"
+FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata")
+FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
+FWUPD_DOM0_METADATA_SIGNATURE = os.path.join(
+ FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz.asc"
+)
+FWUPD_DOM0_METADATA_FILE = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
+FWUPD_DOM0_METADATA_JCAT = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz.jcat")
+FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log")
+FWUPD_VM_VALIDATE = "/usr/libexec/qubes-fwupd/fwupd_usbvm_validate.py"
+FWUPD_VM_DIR = "/home/user/.cache/fwupd"
+FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
+FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
+FWUPD_VM_METADATA_SIGNATURE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.asc")
+FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
+FWUPD_VM_METADATA_JCAT = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat")
+FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
+
+FWUPDMGR = "/bin/fwupdmgr"
+FWUPDAGENT = "/bin/fwupdagent"
+
+USBVM_N = "sys-usb"
+
+BIOS_UPDATE_FLAG = os.path.join(FWUPD_DOM0_DIR, "bios_update")
+LVFS_TESTING_DOM0_FLAG = os.path.join(FWUPD_DOM0_DIR, "lvfs_testing")
+LVFS_TESTING_USBVM_FLAG = os.path.join(FWUPD_VM_DIR, "lvfs_testing")
+METADATA_REFRESH_REGEX = re.compile(r"^Successfully refreshed metadata manually$")
+
+SPECIAL_CHAR_REGEX = re.compile(r"%20|&|\||#")
+
+
+HELP = {
+ "Usage": [
+ {
+ "Command": "qubes-fwupdmgr [OPTION…][FLAG..]",
+ "Example": "qubes-fwupdmgr refresh --whonix --url=\n",
+ }
+ ],
+ "Options": [
+ {
+ "get-devices": "Get all devices that support firmware updates",
+ "get-updates": "Get the list of updates for connected hardware",
+ "refresh": "Refresh metadata from remote server",
+ "update": "Update chosen device to latest firmware version",
+ "update-heads": "Updates heads firmware to the latest version",
+ "downgrade": "Downgrade chosen device to chosen firmware version",
+ "clean": "Delete all cached update files\n",
+ }
+ ],
+ "Flags": [
+ {
+ "--whonix": "Download firmware updates via Tor",
+ "--device": "Specify device for heads update (default - x230)",
+ "--url": "Address of the custom metadata remote server\n",
+ }
+ ],
+ "Help": [{"-h --help": "Show help options\n"}],
+}
+
+EXIT_CODES = {"ERROR": 1, "SUCCESS": 0, "NOTHING_TO_DO": 2}
+
+
+class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
+ def _download_metadata(self, whonix=False, metadata_url=None):
+ """Initialize downloading metadata files.
+
+ Keywords arguments:
+ whonix -- Flag enforces downloading the metadata updates via Tor
+ metadata_url -- Download metadata from the custom url
+ """
+ self.download_metadata(whonix=whonix, metadata_url=metadata_url)
+ self.handle_metadata_update(self.updatevm, metadata_url=metadata_url)
+ if not os.path.exists(self.metadata_file):
+ raise FileNotFoundError("Metadata file does not exist")
+
+ def _validate_usbvm_dirs(self):
+ """Validates if sys-ubs updates and metadata directories exist."""
+ cmd_validate_dirs = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ f'script --quiet --return --command "{FWUPD_VM_VALIDATE} dirs"',
+ ]
+ p = subprocess.Popen(cmd_validate_dirs)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Validation of usbvm directories failed.")
+
+ def _validate_usbvm_archive(self, arch_name, sha):
+ """Validates checksum and gpg signature of the archive file."""
+ arch_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name)
+ arch_validate = f"{FWUPD_VM_VALIDATE} updates {arch_path} {sha}"
+ cmd_validate_arch = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ f'script --quiet --return --command "{arch_validate}"',
+ ]
+ p = subprocess.Popen(cmd_validate_arch)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Validation of the archive file failed.")
+
+ def _copy_usbvm_metadata(self):
+ """Copies metadata files to usbvm."""
+ self.metadata_file_usbvm = self.metadata_file.replace(
+ FWUPD_DOM0_METADATA_DIR, FWUPD_VM_METADATA_DIR
+ )
+ self.metadata_file_jcat_usbvm = self.metadata_file_usbvm + ".jcat"
+ cat_file = f"cat > {self.metadata_file_usbvm}"
+ cmd_copy_file = (
+ f"cat {self.metadata_file} | "
+ f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"'
+ )
+ cat_jcat = f"cat > {self.metadata_file_jcat_usbvm}"
+ cmd_copy_jcat = (
+ f"cat {self.metadata_file_jcat} | "
+ f'qvm-run --nogui --pass-io {USBVM_N} "{cat_jcat}"'
+ )
+ p = subprocess.Popen(cmd_copy_file, shell=True)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Copying metadata file failed.")
+ p = subprocess.Popen(cmd_copy_jcat, shell=True)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Copying metadata jcat failed.")
+
+ def _validate_usbvm_metadata(self, metadata_url=None):
+ """Checks GPG signature of metadata files in usbvm."""
+ usbvm_cmd = f'"{FWUPD_VM_VALIDATE} metadata"'
+ if metadata_url:
+ usbvm_cmd = f'"{FWUPD_VM_VALIDATE} metadata --url={metadata_url}"'
+ cmd_validate_metadata = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ "script --quiet --return --command" f" {usbvm_cmd}",
+ ]
+ p = subprocess.Popen(cmd_validate_metadata)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Metadata validation failed")
+
+ def _refresh_usbvm_metadata(self):
+ """Refreshes metadata in usbvm."""
+ sig_metadata_file = self.metadata_file_jcat_usbvm
+ cmd_refresh_metadata = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ (
+ "script --quiet --return --command "
+ f'"{FWUPDMGR} refresh {self.metadata_file_usbvm} '
+ f'{sig_metadata_file} {self.lvfs}"'
+ ),
+ ]
+ p = subprocess.Popen(cmd_refresh_metadata)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Metadata refresh in usbvm failed")
+
+ def _copy_firmware_updates(self, arch_name):
+ """Copies updates files to usbvm.
+
+ Keywords arguments:
+ arch_name - name of the archive file
+ """
+ arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, arch_name)
+ output_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name)
+ cat_file = f"cat > {output_path}"
+ cmd_copy_file = (
+ f"cat {arch_path} | " f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"'
+ )
+ p = subprocess.Popen(cmd_copy_file, shell=True)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Copying metadata file failed.")
+
+ def _install_usbvm_firmware_update(self, arch_name):
+ """Installs firmware update for specified device in dom0.
+
+ Keywords arguments:
+ arch_name - name of the archive file
+ """
+ arch_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name)
+ CMD_update = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ f"script --quiet --return --command"
+ f' "{FWUPDMGR} install {arch_path}" /dev/null',
+ ]
+ p = subprocess.Popen(CMD_update)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Firmware update failed")
+
+ def _install_usbvm_firmware_downgrade(self, arch_name):
+ """Installs firmware downgrades for specified device in dom0.
+
+ Keywords arguments:
+ arch_name - name of the archive file
+ """
+ arch_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name)
+ CMD_downgrade = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ f"script --quiet --return --command"
+ f' "{FWUPDMGR} --allow-older install {arch_path}" /dev/null',
+ ]
+ p = subprocess.Popen(CMD_downgrade)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Firmware downgrade failed")
+
+ def _clean_usbvm(self):
+ """Cleans usbvm directories."""
+ cmd_clean = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ f'script --quiet --return --command "{FWUPD_VM_VALIDATE} clean"',
+ ]
+ p = subprocess.Popen(cmd_clean)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Cleaning usbvm directories failed")
+
+ def _enable_lvfs_testing_dom0(self):
+ """Checks and enable lvfs-testing for custom metadata in dom0"""
+ cmd_lvfs_testing = [FWUPDMGR, "enable-remote", "-y", "lvfs-testing"]
+ if not os.path.exists(LVFS_TESTING_DOM0_FLAG):
+ p = subprocess.Popen(cmd_lvfs_testing)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Enabling dom0 lvfs-testing failed!!")
+ Path(LVFS_TESTING_DOM0_FLAG).touch(mode=0o644, exist_ok=False)
+
+ def _enable_lvfs_testing_usbvm(self, usbvm=False):
+ """Checks and enable lvfs-testing for custom metadata in usbvm"""
+ if not usbvm:
+ return 0
+ cmd_refresh_metadata = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ (
+ "script --quiet --return --command "
+ f'"{FWUPDMGR} enable-remote -y lvfs-testing"'
+ ),
+ ]
+ cmd_validate_flag = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ (
+ "script --quiet --return --command "
+ f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"'
+ ),
+ ]
+ cmd_touch_flag = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ ("script --quiet --return --command " f'"touch {LVFS_TESTING_USBVM_FLAG}"'),
+ ]
+ flag = subprocess.Popen(cmd_validate_flag)
+ flag.wait()
+ if flag.returncode != 0:
+ p = subprocess.Popen(cmd_refresh_metadata)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Enabling usbvm lvfs-testing failed!!")
+ p = subprocess.Popen(cmd_touch_flag)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("Creating flag failed!!")
+
+ def refresh_metadata(self, usbvm=False, whonix=False, metadata_url=None):
+ """Updates metadata with downloaded files.
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ whonix -- Flag enforces downloading the metadata updates via Tor
+ metadata_url -- Use custom metadata from the url
+ """
+ if metadata_url:
+ metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
+ self.metadata_file = os.path.join(FWUPD_DOM0_METADATA_DIR, metadata_name)
+ self.metadata_file_jcat = self.metadata_file + ".jcat"
+ self.lvfs = "lvfs-testing"
+ self._enable_lvfs_testing_dom0()
+ self._enable_lvfs_testing_usbvm(usbvm=usbvm)
+ else:
+ self.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.metadata_file_jcat = FWUPD_DOM0_METADATA_JCAT
+ self.lvfs = "lvfs"
+ self._download_metadata(whonix=whonix, metadata_url=metadata_url)
+ if usbvm:
+ self._validate_usbvm_dirs()
+ self._copy_usbvm_metadata()
+ self._validate_usbvm_metadata(metadata_url=metadata_url)
+ self._refresh_usbvm_metadata()
+ cmd_refresh = [
+ FWUPDMGR,
+ "refresh",
+ self.metadata_file,
+ self.metadata_file_jcat,
+ self.lvfs,
+ ]
+ p = subprocess.Popen(cmd_refresh, stdout=subprocess.PIPE)
+ self.output = p.communicate()[0].decode()
+ print(self.output)
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Refresh failed")
+ if not METADATA_REFRESH_REGEX.match(self.output):
+ raise Exception("Manual metadata refresh failed!!!")
+
+ def _get_dom0_updates(self):
+ """Gathers infromations about available updates."""
+ cmd_get_dom0_updates = [FWUPDAGENT, "get-updates"]
+ p = subprocess.Popen(cmd_get_dom0_updates, stdout=subprocess.PIPE)
+ self.dom0_updates_info = p.communicate()[0].decode()
+ if p.returncode != 0 and p.returncode != 2:
+ raise Exception("fwupd-qubes: Getting available updates failed")
+
+ def _parse_dom0_updates_info(self, updates_info):
+ """Creates dictionary and list with information about updates.
+
+ Keywords argument:
+ updates_info - gathered update information
+ """
+ self.dom0_updates_info_dict = json.loads(updates_info)
+ self.dom0_updates_list = [
+ {
+ "Name": device["Name"],
+ "Version": device["Version"],
+ "Releases": [
+ {
+ "Version": update["Version"],
+ "Url": update["Uri"],
+ "Checksum": update["Checksum"][-1],
+ "Description": update["Description"],
+ }
+ for update in device["Releases"]
+ ],
+ }
+ for device in self.dom0_updates_info_dict["Devices"]
+ ]
+
+ def _download_firmware_updates(self, url, sha, whonix=False):
+ """Initializes downloading firmware update archive.
+
+ Keywords arguments:
+ url -- url path to the firmware update archive
+ sha -- SHA256 checksum of the firmware update archive
+ whonix -- Flag enforces downloading the updates via Tor
+ """
+ self.cached = False
+ self.download_firmware_updates(url, sha, whonix=whonix)
+ if not self.cached:
+ self.handle_fw_update(self.updatevm, sha, self.arch_name)
+ update_path = self.arch_path.replace(".cab", "")
+ if not os.path.exists(update_path):
+ raise NotADirectoryError("Firmware update files do not exist")
+
+ def _user_input(self, updates_dict, downgrade=False, usbvm=False):
+ """UI for update process.
+
+ Keywords arguments:
+ updates_dict - list of updates for specified device
+ downgrade -- downgrade flag
+ """
+ decorator = "======================================================"
+ if usbvm:
+ updates_list = updates_dict["dom0"] + updates_dict["usbvm"]
+ else:
+ updates_list = updates_dict["dom0"]
+ dom0_updates_num = len(updates_dict["dom0"])
+ if len(updates_list) == 0:
+ print("No updates available.")
+ return EXIT_CODES["NOTHING_TO_DO"]
+ if downgrade:
+ print("Available downgrades:")
+ else:
+ print("Available updates:")
+ self._updates_crawler(updates_dict["dom0"])
+ if usbvm:
+ self._updates_crawler(
+ updates_dict["usbvm"], usbvm=True, prefix=dom0_updates_num
+ )
+
+ while True:
+ try:
+ print("If you want to abandon process press 'N'.")
+ choice = input("Otherwise choose a device number: ")
+ if choice == "N" or choice == "n":
+ return EXIT_CODES["NOTHING_TO_DO"]
+ device_num = int(choice) - 1
+ if 0 <= device_num < len(updates_list):
+ if not downgrade:
+ if device_num >= dom0_updates_num:
+ return "usbvm", device_num - dom0_updates_num
+ else:
+ return "dom0", device_num
+ break
+ else:
+ raise ValueError()
+ except ValueError:
+ print("Invalid choice.")
+
+ if downgrade:
+ while True:
+ try:
+ releases = updates_list[device_num]["Releases"]
+ for i, fw_dngd in enumerate(releases):
+ print(decorator)
+ print(
+ f" {i+1}. Firmware downgrade version:"
+ f"\t {fw_dngd['Version']}"
+ )
+ description = fw_dngd["Description"].replace("", "")
+ description = description.replace("
", "")
+ description = description.replace("", "")
+ description = description.replace(" ", "")
+ description = description.replace("
", "\n ")
+ description = description.replace("", "\n ")
+ print(f" Description:{description}")
+ print("If you want to abandon downgrade process press N.")
+ choice = input("Otherwise choose downgrade number: ")
+ if choice == "N" or choice == "n":
+ return EXIT_CODES["NOTHING_TO_DO"]
+ downgrade_num = int(choice) - 1
+ if 0 <= downgrade_num < len(releases):
+ if device_num >= dom0_updates_num:
+ device_abs_num = device_num - dom0_updates_num
+ return "usbvm", device_abs_num, downgrade_num
+ else:
+ return "dom0", device_num, downgrade_num
+ else:
+ raise ValueError()
+ except ValueError:
+ print("Invalid choice.")
+
+ def _parse_parameters(self, updates_dict, vm_name, choice):
+ """Parses device name, url, version and SHA256 checksum of the file list.
+
+ Keywords arguments:
+ updates_dict - dictionary of updates for dom0 and usbvm
+ vm_name - VM name
+ choice -- number of device to be updated
+ """
+ self.name = updates_dict[vm_name][choice]["Name"]
+ self.version = updates_dict[vm_name][choice]["Releases"][0]["Version"]
+ for ver_check in updates_dict[vm_name][choice]["Releases"]:
+ if Version(ver_check["Version"]) >= Version(self.version):
+ self.version = ver_check["Version"]
+ self.url = ver_check["Url"]
+ self.sha = ver_check["Checksum"]
+
+ def _install_dom0_firmware_update(self, arch_path):
+ """Installs firmware update for specified device in dom0.
+
+ Keywords arguments:
+ arch_path - absolute path to firmware update archive
+ """
+ cmd_install = [FWUPDMGR, "install", arch_path]
+ p = subprocess.Popen(cmd_install)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Firmware update failed")
+
+ def _read_dmi(self):
+ """Reads BIOS information from DMI."""
+ cmd_dmidecode_version = ["dmidecode", "-s", "bios-version"]
+ p = subprocess.Popen(cmd_dmidecode_version, stdout=subprocess.PIPE)
+ p.wait()
+ self.dmi_version = p.communicate()[0].decode()
+ cmd_dmidecode = ["dmidecode", "-t", "bios"]
+ p = subprocess.Popen(cmd_dmidecode, stdout=subprocess.PIPE)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("dmidecode: Reading DMI failed")
+ return p.communicate()[0].decode()
+
+ def _verify_dmi(self, path, version, downgrade=False):
+ """Verifies DMI tables for BIOS updates.
+
+ Keywords arguments:
+ path -- absolute path of the updates files
+ version -- version of the update
+ downgrade -- downgrade flag
+ """
+ dmi_info = self._read_dmi()
+ path_metainfo = os.path.join(path, "firmware.metainfo.xml")
+ tree = ET.parse(path_metainfo)
+ root = tree.getroot()
+ vendor = root.find("developer_name").text
+ if vendor is None:
+ raise ValueError("No vendor information in firmware metainfo.")
+ if vendor not in dmi_info:
+ raise ValueError("Wrong firmware provider.")
+ if not downgrade and Version(version) <= Version(self.dmi_version):
+ raise ValueError(f"{version} < {self.dmi_version} Downgrade not allowed")
+
+ def _get_dom0_devices(self):
+ """Gathers information about devices connected in dom0."""
+ cmd_get_dom0_devices = [FWUPDAGENT, "get-devices"]
+ p = subprocess.Popen(cmd_get_dom0_devices, stdout=subprocess.PIPE)
+ self.dom0_devices_info = p.communicate()[0].decode()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Getting devices info failed")
+
+ def _get_usbvm_devices(self):
+ """Gathers information about devices connected in usbvm."""
+ if os.path.exists(FWUPD_VM_LOG):
+ os.remove(FWUPD_VM_LOG)
+ usbvm_cmd = f'"{FWUPDAGENT} get-devices"'
+ log_file = f" > {FWUPD_VM_LOG}"
+ cmd_get_usbvm_devices = (
+ f"qvm-run --nogui --pass-io {USBVM_N} {usbvm_cmd}{log_file}"
+ )
+ p = subprocess.Popen(cmd_get_usbvm_devices, shell=True)
+ p.wait()
+ if p.returncode != 0 and p.returncode != 2 and not os.path.exists(FWUPD_VM_LOG):
+ raise Exception("fwupd-qubes: Getting usbvm devices info failed")
+ if not os.path.exists(FWUPD_VM_LOG):
+ raise Exception("usbvm device info log does not exist")
+
+ def _parse_usbvm_updates(self, usbvm_devices_info):
+ """Creates dictionary and list with information about updates.
+
+ Keywords argument:
+ usbvm_devices_info - gathered usbvm information
+ """
+ self.usbvm_updates_list = []
+ if "No detected devices" in usbvm_devices_info:
+ return EXIT_CODES["NOTHING_TO_DO"]
+ usbvm_device_info_dict = json.loads(usbvm_devices_info)
+ for device in usbvm_device_info_dict["Devices"]:
+ if "Releases" in device:
+ self.usbvm_updates_list.append(
+ {
+ "Name": device["Name"],
+ "Version": device["Version"],
+ "Releases": [],
+ }
+ )
+ current_version = device["Version"]
+ for update in device["Releases"]:
+ if Version(update["Version"]) > current_version:
+ self.usbvm_updates_list[-1]["Releases"].append(
+ {
+ "Version": update["Version"],
+ "Url": update["Uri"],
+ "Checksum": update["Checksum"][-1],
+ "Description": update["Description"],
+ }
+ )
+ if not self.usbvm_updates_list[-1]["Releases"]:
+ self.usbvm_updates_list.pop()
+
+ def update_firmware(self, usbvm=False, whonix=False):
+ """Updates firmware of the specified device.
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ whonix -- Flag enforces downloading the metadata updates via Tor
+ """
+ self._get_dom0_updates()
+ self._parse_dom0_updates_info(self.dom0_updates_info)
+ if usbvm:
+ self._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ self._parse_usbvm_updates(raw)
+ update_dict = {
+ "usbvm": self.usbvm_updates_list,
+ "dom0": self.dom0_updates_list,
+ }
+ ret_input = self._user_input(update_dict, usbvm=True)
+ else:
+ update_dict = {"dom0": self.dom0_updates_list}
+ ret_input = self._user_input(update_dict)
+ if ret_input == EXIT_CODES["NOTHING_TO_DO"]:
+ exit(EXIT_CODES["NOTHING_TO_DO"])
+ vm_name, choice = ret_input
+ self._parse_parameters(update_dict, vm_name, choice)
+ self._download_firmware_updates(self.url, self.sha, whonix=whonix)
+ if self.name == "System Firmware":
+ Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True)
+ extracted_path = self.arch_path.replace(".cab", "")
+ self._verify_dmi(extracted_path, self.version)
+ if vm_name == "dom0":
+ self._install_dom0_firmware_update(self.arch_path)
+ if vm_name == "usbvm":
+ self._validate_usbvm_dirs()
+ self._copy_firmware_updates(self.arch_name)
+ self._validate_usbvm_archive(self.arch_name, self.sha)
+ self._install_usbvm_firmware_update(self.arch_name)
+
+ def _parse_downgrades(self, device_list):
+ """Parses information about possible downgrades.
+
+ Keywords argument:
+ device_list -- list of connected devices
+ """
+ downgrades = []
+ if "No detected devices" in device_list:
+ return downgrades
+ dom0_devices_info_dict = json.loads(device_list)
+ for device in dom0_devices_info_dict["Devices"]:
+ if "Releases" in device:
+ try:
+ version = device["Version"]
+ except KeyError:
+ continue
+ downgrades.append(
+ {
+ "Name": device["Name"],
+ "Version": device["Version"],
+ "Releases": [
+ {
+ "Version": downgrade["Version"],
+ "Description": downgrade["Description"],
+ "Url": downgrade["Uri"],
+ "Checksum": downgrade["Checksum"][-1],
+ }
+ for downgrade in device["Releases"]
+ if Version(downgrade["Version"]) < Version(version)
+ ],
+ }
+ )
+ return downgrades
+
+ def _install_dom0_firmware_downgrade(self, arch_path):
+ """Installs firmware downgrade for specified device.
+
+ Keywords arguments:
+ arch_path - absolute path to firmware downgrade archive
+ """
+ cmd_install = [FWUPDMGR, "--allow-older", "install", arch_path]
+ p = subprocess.Popen(cmd_install)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Firmware downgrade failed")
+
+ def downgrade_firmware(self, usbvm=False, whonix=False):
+ """Downgrades firmware of the specified device.
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ whonix -- Flag enforces downloading the metadata updates via Tor
+ """
+ self._get_dom0_devices()
+ dom0_downgrades = self._parse_downgrades(self.dom0_devices_info)
+ if usbvm:
+ self._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ usbvm_downgrades = self._parse_downgrades(raw)
+ downgrade_dict = {"usbvm": usbvm_downgrades, "dom0": dom0_downgrades}
+ ret_input = self._user_input(downgrade_dict, downgrade=True, usbvm=True)
+ else:
+ downgrade_dict = {"dom0": dom0_downgrades}
+ ret_input = self._user_input(downgrade_dict, downgrade=True)
+ if ret_input == EXIT_CODES["NOTHING_TO_DO"]:
+ exit(EXIT_CODES["NOTHING_TO_DO"])
+ vm_name, device_choice, downgrade_choice = ret_input
+ releases = downgrade_dict[vm_name][device_choice]["Releases"]
+ downgrade_url = releases[downgrade_choice]["Url"]
+ downgrade_sha = releases[downgrade_choice]["Checksum"]
+ self._download_firmware_updates(downgrade_url, downgrade_sha, whonix=whonix)
+ if downgrade_dict[vm_name][device_choice]["Name"] == "System Firmware":
+ Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True)
+ extracted_path = self.arch_path.replace(".cab", "")
+ self._verify_dmi(
+ extracted_path,
+ downgrade_dict[vm_name][device_choice]["Version"],
+ downgrade=True,
+ )
+ if vm_name == "dom0":
+ self._install_dom0_firmware_downgrade(self.arch_path)
+ if vm_name == "usbvm":
+ self._validate_usbvm_dirs()
+ self._copy_firmware_updates(self.arch_name)
+ self._validate_usbvm_archive(self.arch_name, downgrade_sha)
+ self._install_usbvm_firmware_downgrade(self.arch_name)
+
+ def _output_crawler(self, updev_dict, level, help_f=False, dom0=True):
+ """Prints device and updates information as a tree.
+
+ Keywords arguments:
+ updev_dict -- update/device information dictionary
+ level -- level of the tree
+ """
+
+ def _tabs(key_word):
+ return key_word + "\t" * (4 - int(len(key_word) / 8))
+
+ decorator = "==================================="
+ print(2 * decorator)
+ for updev_key in updev_dict:
+ style = "\t" * level
+ output = style + _tabs(updev_key + ":")
+ if len(updev_key) > 12:
+ continue
+ if updev_key == "Icons":
+ continue
+ if updev_key == "Releases":
+ continue
+ if updev_key == "Name":
+ print(style + updev_dict["Name"])
+ print(2 * decorator)
+ continue
+ if isinstance(updev_dict[updev_key], str):
+ print(output + updev_dict[updev_key])
+ elif isinstance(updev_dict[updev_key], int):
+ print(output + str(updev_dict[updev_key]))
+ elif isinstance(updev_dict[updev_key][0], str):
+ for i, data in enumerate(updev_dict[updev_key]):
+ if i == 0:
+ print(output + "\u00B7" + data)
+ continue
+ print(style + _tabs(" ") + "\u00B7" + data)
+ elif isinstance(updev_dict[updev_key][0], dict):
+ if level == 0 and help_f is True:
+ print(output)
+ else:
+ if level == 0 and dom0 is True:
+ print(f"Dom0 {output}")
+ elif level == 0 and dom0 is False:
+ print(f"{USBVM_N} {output}")
+
+ for nested_dict in updev_dict[updev_key]:
+ self._output_crawler(nested_dict, level + 1)
+
+ def _updates_crawler(self, updates_list, usbvm=False, prefix=0):
+ """Prints updates information for dom0 and usbvm
+
+ Keywords arguments:
+ updates_list -- list of devices updates
+ usbvm -- usbvm support flag
+ prefix -- device number prefix
+ """
+ available_updates = False
+ decorator = "======================================================"
+ print(decorator)
+ if usbvm:
+ print(f"{USBVM_N} updates:")
+ else:
+ print("Dom0 updates:")
+ print(decorator)
+ if len(updates_list) == 0:
+ print("No updates available.")
+ return EXIT_CODES["NOTHING_TO_DO"]
+ else:
+ for i, device in enumerate(updates_list):
+ if len(device["Releases"]) == 0:
+ continue
+ if not available_updates:
+ print("Available updates:")
+ print(decorator)
+ print("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^")
+ print(f"{i+1+prefix}. Device: {device['Name']}")
+ print(f" Current firmware version:\t {device['Version']}")
+ for update in device["Releases"]:
+ print(decorator)
+ print(" Firmware update " f"version:\t {update['Version']}")
+ print(f" URL:\t {update['Url']}")
+ print(f" SHA256 checksum:\t {update['Checksum']}")
+ description = update["Description"].replace("", "")
+ description = description.replace("
", "")
+ description = description.replace("", "")
+ description = description.replace(" ", "")
+ description = description.replace("", "\n\t")
+ description = description.replace(" ", "\n\t")
+ print(f" Description: {description}")
+ print(decorator)
+ available_updates = True
+ if not available_updates:
+ print("No updates available.")
+ return EXIT_CODES["NOTHING_TO_DO"]
+
+ def get_devices_qubes(self, usbvm=False):
+ """Gathers and prints devices information.
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ """
+ self._get_dom0_devices()
+ dom0_devices_info_dict = json.loads(self.dom0_devices_info)
+ self._output_crawler(dom0_devices_info_dict, 0)
+ if usbvm:
+ self._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ if "No detected devices" not in raw:
+ usbvm_device_info_dict = json.loads(raw)
+ else:
+ print(f"No detected devices in {USBVM_N}")
+ return EXIT_CODES["NOTHING_TO_DO"]
+ self._output_crawler(usbvm_device_info_dict, 0, dom0=False)
+
+ def get_updates_qubes(self, usbvm=False):
+ """Gathers and prints updates information.
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ """
+ self._get_dom0_updates()
+ self._parse_dom0_updates_info(self.dom0_updates_info)
+ self._updates_crawler(self.dom0_updates_list)
+ if usbvm:
+ self._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ self._parse_usbvm_updates(raw)
+ self._updates_crawler(self.usbvm_updates_list, usbvm=True)
+
+ def help(self):
+ """Prints help information"""
+ self._output_crawler(HELP, 0, help_f=True)
+
+ def check_usbvm(self):
+ """Checks if usbvm is running"""
+ cmd_xl_list = ["xl", "list"]
+ p = subprocess.Popen(cmd_xl_list, stdout=subprocess.PIPE)
+ self.output = p.communicate()[0].decode()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Firmware downgrade failed")
+ return USBVM_N in self.output
+
+ def trusted_cleanup(self, usbvm=False):
+ """Deletes trusted directory.
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ """
+ trusted_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, "trusted.cab")
+ if os.path.exists(trusted_path):
+ os.remove(trusted_path)
+ shutil.rmtree(trusted_path.replace(".cab", ""))
+ if usbvm:
+ self._clean_usbvm()
+
+ def refresh_metadata_after_bios_update(self, usbvm=False):
+ """Refreshes metadata after bios update
+
+ Keyword arguments:
+ usbvm -- usbvm support flag
+ """
+ if os.path.exists(BIOS_UPDATE_FLAG):
+ print("BIOS was updated. Refreshing metadata...")
+ if "--whonix" in sys.argv:
+ self.refresh_metadata(usbvm=usbvm, whonix=True)
+ else:
+ self.refresh_metadata(usbvm=usbvm)
+ os.remove(BIOS_UPDATE_FLAG)
+
+ def heads_update(self, device="x230", whonix=False, metadata_url=None):
+ """
+ Updates heads firmware
+
+ Keyword arguments:
+ device -- Model of the updated device
+ whonix -- Flag enforces downloading the metadata updates via Tor
+ metadata_url -- Use custom metadata from the url
+ """
+ if metadata_url:
+ custom_metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
+ self.metadata_file = os.path.join(
+ FWUPD_DOM0_METADATA_DIR, custom_metadata_name
+ )
+ else:
+ self.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self._get_hwids()
+ self._download_metadata(whonix=whonix, metadata_url=metadata_url)
+ self._parse_metadata(self.metadata_file)
+ if self._gather_firmware_version() == EXIT_CODES["NOTHING_TO_DO"]:
+ return EXIT_CODES["NOTHING_TO_DO"]
+ if self._parse_heads_updates(device) == EXIT_CODES["NOTHING_TO_DO"]:
+ return EXIT_CODES["NOTHING_TO_DO"]
+ self._download_firmware_updates(self.heads_update_url, self.heads_update_sha)
+ return_code = self._copy_heads_firmware(self.arch_path)
+ if return_code == EXIT_CODES["NOTHING_TO_DO"]:
+ exit(EXIT_CODES["NOTHING_TO_DO"])
+ elif return_code == EXIT_CODES["SUCCESS"]:
+ print()
+ while True:
+ try:
+ print("An update requires a reboot to complete.")
+ choice = input("Do you want to restart now? (Y|N)\n")
+ if choice == "N" or choice == "n":
+ return EXIT_CODES["SUCCESS"]
+ elif choice == "Y" or choice == "y":
+ print("Rebooting...")
+ os.system("reboot")
+ else:
+ raise ValueError()
+ except ValueError:
+ print("Invalid choice.")
+ else:
+ raise Exception("Copying heads update failed!!")
+
+ def validate_dom0_dirs(self):
+ """Validates and creates directories"""
+ if not os.path.exists(FWUPD_DOM0_DIR):
+ self._create_dirs(FWUPD_DOM0_DIR)
+ if os.path.exists(FWUPD_DOM0_METADATA_DIR):
+ shutil.rmtree(FWUPD_DOM0_METADATA_DIR)
+ self._create_dirs(FWUPD_DOM0_METADATA_DIR)
+ else:
+ self._create_dirs(FWUPD_DOM0_METADATA_DIR)
+ if not os.path.exists(FWUPD_DOM0_UPDATES_DIR):
+ self._create_dirs(FWUPD_DOM0_UPDATES_DIR)
+ os.umask(self.old_umask)
+
+
+def main():
+ if os.geteuid() != 0:
+ print("You need to have root privileges to run this script.\n")
+ exit(EXIT_CODES["ERROR"])
+
+ q = QubesFwupdmgr()
+ sys_usb = q.check_usbvm()
+ q.validate_dom0_dirs()
+ q.trusted_cleanup(usbvm=sys_usb)
+ q.refresh_metadata_after_bios_update(usbvm=sys_usb)
+
+ metadata_url = None
+ device = "x230"
+
+ if not os.path.exists(FWUPD_DOM0_DIR):
+ q.refresh_metadata(usbvm=sys_usb)
+
+ if len(sys.argv) < 2:
+ q.help()
+ exit(1)
+ for arg in sys.argv:
+ if "--url=" in arg:
+ metadata_url = arg.replace("--url=", "")
+ if FWUPD_DOWNLOAD_PREFIX not in metadata_url:
+ print(
+ "Metadata must be stored in the Linux"
+ " Vendor Firmware Service (https://fwupd.org/)"
+ )
+ print("Exiting...")
+ exit(1)
+ if "--device=" in arg:
+ device = arg.replace("--device=", "")
+
+ if sys.argv[1] == "get-updates":
+ q.get_updates_qubes(usbvm=sys_usb)
+ elif sys.argv[1] == "get-devices":
+ q.get_devices_qubes(usbvm=sys_usb)
+ elif sys.argv[1] == "update" and "--whonix" in sys.argv:
+ q.update_firmware(usbvm=sys_usb, whonix=True)
+ elif sys.argv[1] == "update" and "--whonix" not in sys.argv:
+ q.update_firmware(usbvm=sys_usb)
+ elif sys.argv[1] == "downgrade" and "--whonix" in sys.argv:
+ q.downgrade_firmware(usbvm=sys_usb, whonix=True)
+ elif sys.argv[1] == "downgrade" and "--whonix" not in sys.argv:
+ q.downgrade_firmware(usbvm=sys_usb)
+ elif sys.argv[1] == "clean":
+ q.clean_cache(usbvm=sys_usb)
+ elif sys.argv[1] == "refresh" and "--whonix" not in sys.argv:
+ q.refresh_metadata(usbvm=sys_usb, metadata_url=metadata_url)
+ elif sys.argv[1] == "refresh" and "--whonix" in sys.argv:
+ q.refresh_metadata(usbvm=sys_usb, whonix=True, metadata_url=metadata_url)
+ elif sys.argv[1] == "update-heads" and "--whonix" not in sys.argv:
+ q.heads_update(device=device, metadata_url=metadata_url)
+ elif sys.argv[1] == "update-heads" and "--whonix" in sys.argv:
+ q.heads_update(device=device, metadata_url=metadata_url, whonix=True)
+ else:
+ q.help()
+ exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_common_vm.py b/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_common_vm.py
new file mode 100644
index 0000000000000000000000000000000000000000..c8eda536d77ca0188ffa55c33e0e7ea832679902
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_common_vm.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import grp
+import hashlib
+import os
+import shutil
+import subprocess
+
+FWUPD_VM_DIR = "/home/user/.cache/fwupd"
+FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
+FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
+WARNING_COLOR = "\033[93m"
+FWUPD_PKI = "/etc/pki/fwupd"
+
+
+class FwupdVmCommon:
+ def _create_dirs(self, *args):
+ """Method creates directories.
+
+ Keyword arguments:
+ *args -- paths to be created
+ """
+ qubes_gid = grp.getgrnam("qubes").gr_gid
+ self.old_umask = os.umask(0o002)
+ if args is None:
+ raise Exception("Creating directories failed, no paths given.")
+ for file_path in args:
+ if not os.path.exists(file_path):
+ os.mkdir(file_path)
+ os.chown(file_path, -1, qubes_gid)
+ elif os.stat(file_path).st_gid != qubes_gid:
+ print(
+ f"{WARNING_COLOR}Warning: You should move a personal files"
+ f" from {file_path}. Cleaning cache will cause lose of "
+ f"the personal data!!{WARNING_COLOR}"
+ )
+
+ def check_shasum(self, file_path, sha):
+ """Compares computed SHA256 checksum with `sha` parameter.
+
+ Keyword arguments:
+ file_path -- absolute path to the file
+ sha -- SHA256 checksum of the file
+ """
+ with open(file_path, "rb") as f:
+ c_sha = hashlib.sha256(f.read()).hexdigest()
+ if c_sha != sha:
+ self.clean_vm_cache()
+ raise ValueError("Computed checksum %s did NOT match %s. " % (c_sha, sha))
+
+ def validate_vm_dirs(self):
+ """Validates and creates directories"""
+ print("Validating directories")
+ if not os.path.exists(FWUPD_VM_DIR):
+ self._create_dirs(FWUPD_VM_DIR)
+ if os.path.exists(FWUPD_VM_METADATA_DIR):
+ shutil.rmtree(FWUPD_VM_METADATA_DIR)
+ self._create_dirs(FWUPD_VM_METADATA_DIR)
+ else:
+ self._create_dirs(FWUPD_VM_METADATA_DIR)
+ if not os.path.exists(FWUPD_VM_UPDATES_DIR):
+ self._create_dirs(FWUPD_VM_UPDATES_DIR)
+ os.umask(self.old_umask)
+
+ def _jcat_verification(self, file_path, file_directory):
+ """Verifies sha1 and sha256 checksum, GPG signature,
+ and PKCS#7 signature.
+
+ Keyword argument:
+ file_path -- absolute path to jcat file
+ file_directory -- absolute path to the directory to jcat file location
+ """
+ cmd_jcat = ["jcat-tool", "verify", f"{file_path}", "--public-keys", FWUPD_PKI]
+ p = subprocess.Popen(
+ cmd_jcat, cwd=file_directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ stdout, __ = p.communicate()
+ verification = stdout.decode("utf-8")
+ print(verification)
+ if p.returncode != 0:
+ self.clean_vm_cache()
+ raise Exception("jcat-tool: Verification failed")
+
+ def clean_vm_cache(self):
+ """Removes updates data"""
+ print("Cleaning cache directories")
+ if os.path.exists(FWUPD_VM_METADATA_DIR):
+ shutil.rmtree(FWUPD_VM_METADATA_DIR)
+ if os.path.exists(FWUPD_VM_UPDATES_DIR):
+ shutil.rmtree(FWUPD_VM_UPDATES_DIR)
diff --git a/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_download_updates.py b/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_download_updates.py
new file mode 100644
index 0000000000000000000000000000000000000000..0844b6e7aceb92d6646edfbea1062b17091f30ca
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_download_updates.py
@@ -0,0 +1,127 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+import sys
+import subprocess
+import os
+
+from fwupd_common_vm import FwupdVmCommon
+
+FWUPD_VM_DIR = "/home/user/.cache/fwupd"
+FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
+FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
+FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
+METADATA_URL = "https://fwupd.org/downloads/firmware.xml.gz"
+METADATA_URL_JCAT = "https://fwupd.org/downloads/firmware.xml.gz.jcat"
+
+
+class DownloadData(FwupdVmCommon):
+ def _decrypt_update_url(self, url):
+ self.dec_url = url
+ if "--and--" in url:
+ self.dec_url = self.dec_url.replace("--and--", "&")
+ self.arch_name = "untrusted.cab"
+ if "--or--" in url:
+ self.dec_url = self.dec_url.replace("--or--", "|")
+ self.arch_name = "untrusted.cab"
+ if "--hash--" in url:
+ self.dec_url = self.dec_url.replace("--hash--", "#")
+ self.arch_name = "untrusted.cab"
+ if "%20" in url:
+ self.arch_name = "untrusted.cab"
+
+ def _download_metadata_file(self):
+ """Download metadata file"""
+ if self.custom_url is None:
+ metadata_url = METADATA_URL
+ else:
+ metadata_url = self.custom_url
+ cmd_metadata = ["wget", "-P", FWUPD_VM_METADATA_DIR, metadata_url]
+ p = subprocess.Popen(cmd_metadata)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Downloading metadata file failed")
+ if not os.path.exists(self.metadata_file):
+ raise FileNotFoundError(
+ "fwupd-qubes: Downloaded metadata file does not exist"
+ )
+
+ def _download_metadata_jcat(self):
+ """Download metadata jcat signature"""
+ if self.custom_url is None:
+ metadata_url = METADATA_URL
+ else:
+ metadata_url = self.custom_url
+ cmd_metadata = ["wget", "-P", FWUPD_VM_METADATA_DIR, f"{metadata_url}.jcat"]
+ p = subprocess.Popen(cmd_metadata)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Downloading metadata file failed")
+ if not os.path.exists(f"{self.metadata_file}.jcat"):
+ raise FileNotFoundError(
+ "fwupd-qubes: Downloaded metadata file does not exist"
+ )
+
+ def download_metadata(self, url=None):
+ """Downloads default metadata and its signatures"""
+ if url is not None:
+ self.custom_url = url
+ custom_metadata_name = url.replace(FWUPD_DOWNLOAD_PREFIX, "")
+ self.metadata_file = os.path.join(
+ FWUPD_VM_METADATA_DIR, custom_metadata_name
+ )
+ else:
+ self.custom_url = None
+ self.metadata_file = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
+ self.validate_vm_dirs()
+ self._download_metadata_file()
+ self._download_metadata_jcat()
+
+ def download_updates(self, url, sha):
+ """
+ Downloads update form given url
+
+ Keyword argument:
+ url - url address of the update
+ """
+ self.validate_vm_dirs()
+ self.arch_name = url.replace("https://fwupd.org/downloads/", "")
+ self._decrypt_update_url(url)
+ update_path = os.path.join(FWUPD_VM_UPDATES_DIR, self.arch_name)
+ cmd_update = ["wget", "-O", update_path, self.dec_url]
+ p = subprocess.Popen(cmd_update)
+ p.wait()
+ if p.returncode != 0:
+ raise Exception("fwupd-qubes: Downloading update file failed")
+ if not os.path.exists(update_path):
+ raise FileNotFoundError(
+ "fwupd-qubes: Downloaded update file does not exist"
+ )
+ self.check_shasum(update_path, sha)
+ print("Update file downloaded successfully")
+
+
+def main():
+ url = None
+ sha = None
+ dn = DownloadData()
+ for arg in sys.argv:
+ if "--url=" in arg:
+ url = arg.replace("--url=", "")
+ if "--sha=" in arg:
+ sha = arg.replace("--sha=", "")
+ if "--metadata" in sys.argv:
+ dn.download_metadata(url=url)
+ elif url and sha:
+ dn.download_updates(url, sha)
+ else:
+ raise Exception("Invalid command!!!")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_usbvm_validate.py b/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_usbvm_validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..973cd0f1485bb1a9d94786c3855e05e8170c98b7
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/src/vms/fwupd_usbvm_validate.py
@@ -0,0 +1,127 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import glob
+import os
+import shutil
+import subprocess
+import sys
+
+from fwupd_common_vm import FwupdVmCommon
+
+FWUPD_VM_DIR = "/home/user/.cache/fwupd"
+FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
+FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
+FWUPD_VM_METADATA_JCAT = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat")
+FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
+FWUPDMGR = "/bin/fwupdmgr"
+FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
+
+
+class FwupdUsbvmUpdates(FwupdVmCommon):
+ def _verify_received(self, files_path, regex_pattern):
+ """Checks if sent files match regex filename pattern.
+
+ Keyword arguments:
+
+ files_path -- absolute path to inspected directory
+ regex_pattern -- pattern of the expected files
+ """
+ for untrusted_f in os.listdir(files_path):
+ if not regex_pattern.match(untrusted_f):
+ raise Exception("Dom0 sent unexpected file")
+ f = untrusted_f
+ assert "/" not in f
+ assert "\0" not in f
+ assert "\x1b" not in f
+ path_f = os.path.join(files_path, f)
+ if os.path.islink(path_f) or not os.path.isfile(path_f):
+ raise Exception("Dom0 sent not regular file")
+
+ def _extract_archive(self, archive_path, output_path):
+ """Extracts archive file to the specified directory.
+
+ Keyword arguments:
+ archive_path -- absolute path to archive file
+ output_path -- absolute path to the output directory
+ """
+ cmd_extract = ["gcab", "-x", f"--directory={output_path}", f"{archive_path}"]
+ p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE)
+ p.communicate()[0].decode("ascii")
+ if p.returncode != 0:
+ raise Exception("gcab: Error while extracting %s." % archive_path)
+
+ def validate_metadata(self, metadata_url=None):
+ """Validates received the metadata files."""
+ print("Running validation of the metadata files")
+ if metadata_url:
+ metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
+ metadata_file = os.path.join(FWUPD_VM_METADATA_DIR, metadata_name)
+ else:
+ metadata_file = FWUPD_VM_METADATA_FILE
+ try:
+ self._jcat_verification(f"{metadata_file}.jcat", FWUPD_VM_METADATA_DIR)
+ except Exception as e:
+ print(str(e), file=sys.stderr)
+ self.clean_vm_cache()
+ exit(1)
+
+ def validate_updates(self, archive_path, sha):
+ """Validates received an update file.
+
+ Keyword arguments:
+ archive_path - path to the firmware update archive
+ sha -- SHA256 checksum of the firmware update archive
+ """
+ print("Running validation of the update archive")
+ self.check_shasum(archive_path, sha)
+ archive_name = archive_path.replace(f"{FWUPD_VM_UPDATES_DIR}/", "")
+ output_path = archive_path.replace(".cab", "")
+ arch_temp = os.path.join(output_path, archive_name)
+ os.mkdir(output_path)
+ shutil.copyfile(archive_path, arch_temp)
+ self._extract_archive(arch_temp, output_path)
+ signature_name = os.path.join(output_path, "firmware*.jcat")
+ file_path = glob.glob(signature_name)
+ try:
+ self._jcat_verification(file_path[0], output_path)
+ shutil.rmtree(output_path)
+ except Exception as e:
+ print(str(e), file=sys.stderr)
+ self.clean_vm_cache()
+ exit(1)
+
+
+def main():
+ f = FwupdUsbvmUpdates()
+ f_val = FwupdVmCommon()
+ metadata_url = None
+ if len(sys.argv) < 2:
+ raise Exception("Invalid number of arguments.")
+ for arg in sys.argv:
+ if "--url=" in arg:
+ metadata_url = arg.replace("--url=", "")
+ if sys.argv[1] == "metadata":
+ f.validate_metadata(metadata_url=metadata_url)
+ elif sys.argv[1] == "dirs":
+ f_val.validate_vm_dirs()
+ elif sys.argv[1] == "clean":
+ f.clean_vm_cache()
+ elif sys.argv[1] == "updates" and len(sys.argv) < 4:
+ raise Exception(
+ "Invalid number of arguments.\n" "Expected archive path and checksum."
+ )
+ elif sys.argv[1] == "updates" and not len(sys.argv) < 4:
+ f.validate_updates(sys.argv[2], sys.argv[3])
+ else:
+ raise Exception("Invalid command")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/fwupd-1.8.6/contrib/qubes/test/__init__.py b/fwupd-1.8.6/contrib/qubes/test/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/fwupd-1.8.6/contrib/qubes/test/fwupd_logs.py b/fwupd-1.8.6/contrib/qubes/test/fwupd_logs.py
new file mode 100644
index 0000000000000000000000000000000000000000..fc876bb1685d495dcdf7d2eaf116481f5aeb49ed
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/fwupd_logs.py
@@ -0,0 +1,850 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+UPDATE_INFO = """{
+ "Devices" : [
+ {
+ "Name" : "ColorHug2",
+ "DeviceId" : "b0a78eb71f4eeea7df8fb114522556ba8ce22074",
+ "Guid" : [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad",
+ "aa4b4156-9732-55db-9500-bf6388508ee3",
+ "101ee86a-7bea-59fb-9f89-6b6297ceed3b",
+ "2fa8891f-3ece-53a4-adc4-0dd875685f30"
+ ],
+ "Summary" : "An open source display colorimeter",
+ "Plugin" : "colorhug",
+ "Protocol" : "com.hughski.colorhug",
+ "Flags" : [
+ "updatable",
+ "supported",
+ "registered",
+ "self-recovery",
+ "add-counterpart-guids"
+ ],
+ "Vendor" : "Hughski Ltd.",
+ "VendorId" : "USB:0x273F",
+ "Version" : "2.0.6",
+ "VersionFormat" : "triplet",
+ "Icons" : [
+ "colorimeter-colorhug"
+ ],
+ "InstallDuration" : 8,
+ "Created" : 1614224175,
+ "Releases" : [
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.
",
+ "Version" : "2.0.7",
+ "Filename" : "hughski-colorhug2-2.0.7.cab",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "80bddeb898cda5b87d9837e13a9ace19846053bf",
+ "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1482901200,
+ "Locations" : [
+ "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "ipfs://QmUByRuHG9Gb2s8gKKVqDcjhUrn8vy62B4WqjbpWDD42cf"
+ ],
+ "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-upgrade"
+ ],
+ "InstallDuration" : 8
+ }
+ ]
+ }
+ ]
+ }
+"""
+
+DMI_DECODE = """# dmidecode 3.1
+Getting SMBIOS data from sysfs.
+SMBIOS 3.1.1 present.
+
+Handle 0x0000, DMI type 0, 26 bytes
+BIOS Information
+ Vendor: Dell Inc.
+ Version: P1.00
+ Release Date: 02/09/2018
+ Address: 0xF0000
+ Runtime Size: 64 kB
+ ROM Size: 16 MB
+ Characteristics:
+ PCI is supported
+ BIOS is upgradeable
+ BIOS shadowing is allowed
+ Boot from CD is supported
+ Selectable boot is supported
+ BIOS ROM is socketed
+ EDD is supported
+ 5.25"/1.2 MB floppy services are supported (int 13h)
+ 3.5"/720 kB floppy services are supported (int 13h)
+ 3.5"/2.88 MB floppy services are supported (int 13h)
+ Print screen service is supported (int 5h)
+ 8042 keyboard services are supported (int 9h)
+ Serial services are supported (int 14h)
+ Printer services are supported (int 17h)
+ ACPI is supportedUSB legacy is supported
+ BIOS boot specification is supported
+ Targeted content distribution is supported
+ UEFI is supported
+ BIOS Revision: 5.13
+"""
+
+GET_DEVICES = """{
+ "Devices" : [
+ {
+ "Name" : "ColorHug2",
+ "DeviceId" : "cf294bf55b333004beb7c41f952c1838c23e1f4a",
+ "Guid" : [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad",
+ "aa4b4156-9732-55db-9500-bf6388508ee3",
+ "101ee86a-7bea-59fb-9f89-6b6297ceed3b",
+ "2fa8891f-3ece-53a4-adc4-0dd875685f30"
+ ],
+ "Summary" : "An open source display colorimeter",
+ "Plugin" : "colorhug",
+ "Protocol" : "com.hughski.colorhug",
+ "Flags" : [
+ "updatable",
+ "supported",
+ "registered",
+ "self-recovery",
+ "add-counterpart-guids"
+ ],
+ "Vendor" : "Hughski Ltd.",
+ "VendorId" : "USB:0x273F",
+ "Version" : "2.0.6",
+ "VersionFormat" : "triplet",
+ "Icons" : [
+ "colorimeter-colorhug"
+ ],
+ "InstallDuration" : 8,
+ "Created" : 1614246373,
+ "Releases" : [
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.
",
+ "Version" : "2.0.7",
+ "Filename" : "hughski-colorhug2-2.0.7.cab",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "80bddeb898cda5b87d9837e13a9ace19846053bf",
+ "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1482901200,
+ "Locations" : [
+ "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "ipfs://QmUByRuHG9Gb2s8gKKVqDcjhUrn8vy62B4WqjbpWDD42cf"
+ ],
+ "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-upgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on the second half of batch 16 Fix the firmware upgrade process using new versions of fwupd ",
+ "Version" : "2.0.6",
+ "Filename" : "hughski-colorhug2-2.0.6.cab",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "60e28bb402b427dbce19e150d63987f5e18c1880",
+ "a646b1798ce7f5ac26229aa85c35cc4f44a5bd8bfc9e5332a8ec815aef075566"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1450792062,
+ "Locations" : [
+ "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab",
+ "ipfs://QmdWFrYo1YJxgGU37Qy7LkwPQM26vPMVxLRANUga6TzSjW"
+ ],
+ "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on batch 16 Make the self test more sensitive to detect floating pins ",
+ "Version" : "2.0.5",
+ "Filename" : "hughski-colorhug2-2.0.5.cab",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "e37b9d360d61157657335d80585a005ff2593108",
+ "8cd379eb2e1467e4fda92c20650306dc7e598b1d421841bbe19d9ed6ea01e3ee"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1444059405,
+ "Locations" : [
+ "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ "ipfs://QmQ648kwvv52wuqPoKjm5zLGXngQnmuJzp1xtJmTEbzgz5"
+ ],
+ "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This unstable release adds the following features:
Add TakeReadingArray to enable panel latency measurements Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration ",
+ "Version" : "2.0.2",
+ "Filename" : "hughski-colorhug2-2.0.2.cab",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "1b43bd71bbed2cf0e9c9efcca79799f07b3d0dd2",
+ "c09674fb818d4a1033dbde2fab5885716aed1d8b751b428f16687a78f2a4d61f"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 15680,
+ "Created" : 1416675439,
+ "Locations" : [
+ "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab",
+ "ipfs://QmZ1DKKsWZQuvnff2DJTDJESMaXTpsc5zfNGX7Sb2HibAn"
+ ],
+ "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ }
+ ]
+ },
+ {
+ "Name" : "Display controller",
+ "DeviceId" : "ecf0d22adf39a244a723466378a8884aa22b7e78",
+ "Guid" : [
+ "e358a53d-98bc-5565-b55e-7df8e0d06c5e",
+ "7365091f-756a-5c83-878c-edd1120ca718",
+ "06208e9f-1dd0-5857-b700-3d77525793aa",
+ "af9ff5a0-c613-5da3-bab8-5d411adebbca"
+ ],
+ "Plugin" : "optionrom",
+ "Flags" : [
+ "internal",
+ "registered",
+ "can-verify",
+ "can-verify-image"
+ ],
+ "VendorId" : "PCI:0x1234",
+ "Version" : "02",
+ "VersionFormat" : "plain",
+ "Created" : 1614209932
+ },
+ {
+ "Name" : "Intel(R) Core™ i7-7700HQ CPU @ 2.80GHz",
+ "DeviceId" : "4bde70ba4e39b28f9eab1628f9dd6e6244c03027",
+ "Guid" : [
+ "b9a2dd81-159e-5537-a7db-e7101d164d3f",
+ "30249f37-d140-5d3e-9319-186b1bd5cac3",
+ "809a0b93-8a12-5338-a571-ad5583acf896",
+ "d0f754d5-1395-5573-bc83-85ba955da70a"
+ ],
+ "Plugin" : "cpu",
+ "Flags" : [
+ "internal",
+ "registered"
+ ],
+ "Vendor" : "Intel",
+ "Version" : "0x000000de",
+ "VersionFormat" : "hex",
+ "VersionRaw" : 222,
+ "Icons" : [
+ "computer"
+ ],
+ "Created" : 1614209932
+ }
+ ]
+}
+"""
+
+GET_DEVICES_NO_UPDATES = """{
+ "Devices" : [
+ {
+ "Name" : "ColorHug2",
+ "DeviceId" : "203f56e4e186d078ce76725e708400aafc253aac",
+ "Guid" : [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad",
+ "aa4b4156-9732-55db-9500-bf6388508ee3",
+ "101ee86a-7bea-59fb-9f89-6b6297ceed3b",
+ "2fa8891f-3ece-53a4-adc4-0dd875685f30"
+ ],
+ "Summary" : "An open source display colorimeter",
+ "Plugin" : "colorhug",
+ "Protocol" : "com.hughski.colorhug",
+ "Flags" : [
+ "updatable",
+ "supported",
+ "registered",
+ "self-recovery",
+ "add-counterpart-guids"
+ ],
+ "Vendor" : "Hughski Ltd.",
+ "VendorId" : "USB:0x273F",
+ "Version" : "2.0.7",
+ "VersionFormat" : "triplet",
+ "Icons" : [
+ "colorimeter-colorhug"
+ ],
+ "InstallDuration" : 8,
+ "Created" : 1592916092,
+ "Releases" : [
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.
",
+ "Version" : "2.0.7",
+ "Filename" : "658851e6f27c4d87de19cd66b97b610d100efe09",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "490be5c0b13ca4a3f169bf8bc682ba127b8f7b96"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1482901200,
+ "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on the second half of batch 16 Fix the firmware upgrade process using new versions of fwupd ",
+ "Version" : "2.0.6",
+ "Filename" : "f038b5ca40e6d7c1c0299a9e1dcc129d5f6371b6",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "03c9c14db1894a00035ececcfae192865a710e52"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1450792062,
+ "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on batch 16 Make the self test more sensitive to detect floating pins ",
+ "Version" : "2.0.5",
+ "Filename" : "ae76c6b704b60f9d1d88dc2c8ec8a62d7b2331dc",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "4ee9dfa38df3b810f739d8a19d13da1b3175fb87"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1444059405,
+ "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This unstable release adds the following features:
Add TakeReadingArray to enable panel latency measurements Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration ",
+ "Version" : "2.0.2",
+ "Filename" : "d4b3144daeb2418634f9d464d88d55590bcd9ac7",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "448527af3ce019d03dbb77aaebaa7eb893f1ea20"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 15680,
+ "Created" : 1416675439,
+ "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ }
+ ]
+ },
+ {
+ "Name" : "GP106 [GeForce GTX 1060 6GB]",
+ "DeviceId" : "71b677ca0f1bc2c5b804fa1d59e52064ce589293",
+ "Guid" : [
+ "b080a9ba-fff8-5de0-b641-26f782949f94",
+ "f95bfce3-18e4-58b0-bd81-136457521383"
+ ],
+ "Plugin" : "optionrom",
+ "Flags" : [
+ "internal",
+ "registered",
+ "can-verify",
+ "can-verify-image"
+ ],
+ "Vendor" : "NVIDIA Corporation",
+ "VendorId" : "PCI:0x10DE",
+ "Version" : "a1",
+ "VersionFormat" : "plain",
+ "Created" : 1592899254
+ },
+ {
+ "Name" : "Intel(R) Core™ i5-8400 CPU @ 2.80GHz",
+ "DeviceId" : "4bde70ba4e39b28f9eab1628f9dd6e6244c03027",
+ "Guid" : [
+ "b9a2dd81-159e-5537-a7db-e7101d164d3f"
+ ],
+ "Plugin" : "cpu",
+ "Flags" : [
+ "internal",
+ "registered"
+ ],
+ "Vendor" : "GenuineIntel",
+ "Version" : "0xd6",
+ "VersionFormat" : "hex",
+ "Icons" : [
+ "computer"
+ ],
+ "Created" : 1592899249
+ },
+ {
+ "Name" : "SSDPR-CX400-256",
+ "DeviceId" : "948241a24320627284597ec95079cc1341c90518",
+ "Guid" : [
+ "09fa3842-45bc-5226-a8ec-1668fc61f88f",
+ "57d6b2ff-710d-5cd2-98be-4f6b8b7c5287",
+ "36bebd37-b680-5d56-83a1-6693033d4098"
+ ],
+ "Summary" : "ATA Drive",
+ "Plugin" : "ata",
+ "Protocol" : "org.t13.ata",
+ "Flags" : [
+ "internal",
+ "updatable",
+ "require-ac",
+ "registered",
+ "needs-reboot",
+ "usable-during-update"
+ ],
+ "Vendor" : "Phison",
+ "VendorId" : "ATA:0x1987",
+ "Version" : "SBFM61.3",
+ "VersionFormat" : "plain",
+ "Icons" : [
+ "drive-harddisk"
+ ],
+ "Created" : 1592899254
+ }
+ ]
+}
+"""
+
+
+GET_DEVICES_NO_VERSION = """{
+ "Devices" : [
+ {
+ "Name" : "ColorHug2",
+ "DeviceId" : "203f56e4e186d078ce76725e708400aafc253aac",
+ "Guid" : [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad",
+ "aa4b4156-9732-55db-9500-bf6388508ee3",
+ "101ee86a-7bea-59fb-9f89-6b6297ceed3b",
+ "2fa8891f-3ece-53a4-adc4-0dd875685f30"
+ ],
+ "Summary" : "An open source display colorimeter",
+ "Plugin" : "colorhug",
+ "Protocol" : "com.hughski.colorhug",
+ "Flags" : [
+ "updatable",
+ "supported",
+ "registered",
+ "self-recovery",
+ "add-counterpart-guids"
+ ],
+ "Vendor" : "Hughski Ltd.",
+ "VendorId" : "USB:0x273F",
+ "VersionFormat" : "triplet",
+ "Icons" : [
+ "colorimeter-colorhug"
+ ],
+ "InstallDuration" : 8,
+ "Created" : 1592916092,
+ "Releases" : [
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.
",
+ "Version" : "2.0.7",
+ "Filename" : "658851e6f27c4d87de19cd66b97b610d100efe09",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "490be5c0b13ca4a3f169bf8bc682ba127b8f7b96"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1482901200,
+ "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on the second half of batch 16 Fix the firmware upgrade process using new versions of fwupd ",
+ "Filename" : "f038b5ca40e6d7c1c0299a9e1dcc129d5f6371b6",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "03c9c14db1894a00035ececcfae192865a710e52"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1450792062,
+ "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on batch 16 Make the self test more sensitive to detect floating pins ",
+ "Version" : "2.0.5",
+ "Filename" : "ae76c6b704b60f9d1d88dc2c8ec8a62d7b2331dc",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "4ee9dfa38df3b810f739d8a19d13da1b3175fb87"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1444059405,
+ "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This unstable release adds the following features:
Add TakeReadingArray to enable panel latency measurements Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration ",
+ "Version" : "2.0.2",
+ "Filename" : "d4b3144daeb2418634f9d464d88d55590bcd9ac7",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "448527af3ce019d03dbb77aaebaa7eb893f1ea20"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 15680,
+ "Created" : 1416675439,
+ "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ }
+ ]
+ },
+ {
+ "Name" : "ColorHug2",
+ "DeviceId" : "203f56e4e186d078ce76725e708400aafc253aac",
+ "Guid" : [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad",
+ "aa4b4156-9732-55db-9500-bf6388508ee3",
+ "101ee86a-7bea-59fb-9f89-6b6297ceed3b",
+ "2fa8891f-3ece-53a4-adc4-0dd875685f30"
+ ],
+ "Summary" : "An open source display colorimeter",
+ "Plugin" : "colorhug",
+ "Protocol" : "com.hughski.colorhug",
+ "Flags" : [
+ "updatable",
+ "supported",
+ "registered",
+ "self-recovery",
+ "add-counterpart-guids"
+ ],
+ "Vendor" : "Hughski Ltd.",
+ "Version" : "2.0.6",
+ "VendorId" : "USB:0x273F",
+ "VersionFormat" : "triplet",
+ "Icons" : [
+ "colorimeter-colorhug"
+ ],
+ "InstallDuration" : 8,
+ "Created" : 1592916092,
+ "Releases" : [
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.
",
+ "Version" : "2.0.7",
+ "Filename" : "658851e6f27c4d87de19cd66b97b610d100efe09",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "490be5c0b13ca4a3f169bf8bc682ba127b8f7b96"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1482901200,
+ "Uri" : "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on the second half of batch 16 Fix the firmware upgrade process using new versions of fwupd ",
+ "Version" : "2.0.6",
+ "Filename" : "f038b5ca40e6d7c1c0299a9e1dcc129d5f6371b6",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "03c9c14db1894a00035ececcfae192865a710e52"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1450792062,
+ "Uri" : "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This stable release fixes the following problems:
Fix the swapped LEDs on batch 16 Make the self test more sensitive to detect floating pins ",
+ "Version" : "2.0.5",
+ "Filename" : "ae76c6b704b60f9d1d88dc2c8ec8a62d7b2331dc",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "4ee9dfa38df3b810f739d8a19d13da1b3175fb87"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 16384,
+ "Created" : 1444059405,
+ "Uri" : "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ },
+ {
+ "AppstreamId" : "com.hughski.ColorHug2.firmware",
+ "RemoteId" : "lvfs",
+ "Summary" : "Firmware for the Hughski ColorHug2 Colorimeter",
+ "Description" : "This unstable release adds the following features:
Add TakeReadingArray to enable panel latency measurements Speed up the auto-scaled measurements considerably, using 256ms as the smallest sample duration ",
+ "Version" : "2.0.2",
+ "Filename" : "d4b3144daeb2418634f9d464d88d55590bcd9ac7",
+ "Protocol" : "com.hughski.colorhug",
+ "Checksum" : [
+ "448527af3ce019d03dbb77aaebaa7eb893f1ea20"
+ ],
+ "License" : "GPL-2.0+",
+ "Size" : 15680,
+ "Created" : 1416675439,
+ "Uri" : "https://fwupd.org/downloads/30a121f26c039745aeb5585252d4a9b5386d71cb-hughski-colorhug2-2.0.2.cab",
+ "Homepage" : "http://www.hughski.com/",
+ "SourceUrl" : "https://github.com/hughski/colorhug2-firmware",
+ "Vendor" : "Hughski Limited",
+ "Flags" : [
+ "is-downgrade"
+ ],
+ "InstallDuration" : 8
+ }
+ ]
+ },
+ {
+ "Name" : "GP106 [GeForce GTX 1060 6GB]",
+ "DeviceId" : "71b677ca0f1bc2c5b804fa1d59e52064ce589293",
+ "Guid" : [
+ "b080a9ba-fff8-5de0-b641-26f782949f94",
+ "f95bfce3-18e4-58b0-bd81-136457521383"
+ ],
+ "Plugin" : "optionrom",
+ "Flags" : [
+ "internal",
+ "registered",
+ "can-verify",
+ "can-verify-image"
+ ],
+ "Vendor" : "NVIDIA Corporation",
+ "VendorId" : "PCI:0x10DE",
+ "VersionFormat" : "plain",
+ "Created" : 1592899254
+ },
+ {
+ "Name" : "Intel(R) Core™ i5-8400 CPU @ 2.80GHz",
+ "DeviceId" : "4bde70ba4e39b28f9eab1628f9dd6e6244c03027",
+ "Guid" : [
+ "b9a2dd81-159e-5537-a7db-e7101d164d3f"
+ ],
+ "Plugin" : "cpu",
+ "Flags" : [
+ "internal",
+ "registered"
+ ],
+ "Vendor" : "GenuineIntel",
+ "Version" : "0xd6",
+ "VersionFormat" : "hex",
+ "Icons" : [
+ "computer"
+ ],
+ "Created" : 1592899249
+ },
+ {
+ "Name" : "SSDPR-CX400-256",
+ "DeviceId" : "948241a24320627284597ec95079cc1341c90518",
+ "Guid" : [
+ "09fa3842-45bc-5226-a8ec-1668fc61f88f",
+ "57d6b2ff-710d-5cd2-98be-4f6b8b7c5287",
+ "36bebd37-b680-5d56-83a1-6693033d4098"
+ ],
+ "Summary" : "ATA Drive",
+ "Plugin" : "ata",
+ "Protocol" : "org.t13.ata",
+ "Flags" : [
+ "internal",
+ "updatable",
+ "require-ac",
+ "registered",
+ "needs-reboot",
+ "usable-during-update"
+ ],
+ "Vendor" : "Phison",
+ "VendorId" : "ATA:0x1987",
+ "Version" : "SBFM61.3",
+ "VersionFormat" : "plain",
+ "Icons" : [
+ "drive-harddisk"
+ ],
+ "Created" : 1592899254
+ }
+ ]
+}
+"""
+
+HEADS_XML = """
+
+
+ com.3mdeb.heads.x230.firmware
+ Heads x230 System Update
+ x230 heads system firmware
+
+ x230 heads system firmware
+
+
+ 596c3466-0506-5ca5-a68f-dc34532a93d3
+
+ http://osresearch.net/
+ CC0-1.0
+ GPLv2
+ coreboot
+
+ X-System
+
+
+
+ https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab
+ 1a54e69ca2b58d1218035115d481480eaf4c66e4
+ ba519a7a5d8136c8ade0cf0c775c58f3165f42798ff631c3f57f075897ef1586
+ 76373f1b5a157b6563d3605271472901b03f57f3
+ 9a9c5dbd3faf90ff7a1f4c9be8d71c4db93dd69fa690f8722fec19c5a51aed9e
+
+ Fixes flash-gui issue.
+
+ 12582912
+ 12591670
+
+
+ https://fwupd.org/downloads/1a0f0ad487a40bb27a49db55e256a207a33dac92c5c53761501c9fb89e4fd115-heads_coreboot_x230-v0_2_2.cab
+ 58e85d012ad1d5c6f98e8fe65202b4d6c8a6ec03
+ 94430160d35cf74adf29c7fc1490b44497e1a3f0fff72733efe2982c61c9a772
+ 8e97ce38396e281fcf9a5a248819925a2fa04265
+ a6774661407622f345bf0ac2f113540507f0288bb97bf5dba586059c0653f659
+
+ Lenovo x230 heads system firmware
+
+ 12582912
+ 12591680
+
+
+
+
+"""
diff --git a/fwupd-1.8.6/contrib/qubes/test/logs/firmware.metainfo.xml b/fwupd-1.8.6/contrib/qubes/test/logs/firmware.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fbb384f6160786061ba447a17a80065d8c41041c
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/logs/firmware.metainfo.xml
@@ -0,0 +1,44 @@
+
+
+ com.dell.uefi6180aaaa.firmware
+ Latitude 7390 2-in-1
+ Firmware for the Dell Latitude 7390 2-in-1
+
+ Updating the system firmware improves performance.
+
+
+ 6180aaaa-5529-4bbf-b4fd-65b4f788de5b
+
+ http://support.dell.com/
+ CC0-1.0
+ proprietary
+ Dell Inc.
+
+ X-System
+
+
+ quad
+ dell-bios
+ org.uefi.capsule
+
+
+
+ b03252481573f600c7f530d7a4c24bd62c810412
+ bd866bcd2b5964da4b20d3f57128746efb7afefe648cf7284f2fae399225f1ac
+
+ This stable release fixes the following issues:
+
+ Firmware updates to address the Intel Security Advisories.
+ Enhanced the system firmware auto recovery function when system firmware does not work.
+ Updated the BIOS warning message that is displayed when an AC adapter with low wattage is connected to the system.
+ Updated the Intel CPU Microcode.
+
+
+ 14699068
+
+ CVE-2019-14607
+ CVE-2019-11157
+
+
+
+
diff --git a/fwupd-1.8.6/contrib/qubes/test/logs/get_devices.log b/fwupd-1.8.6/contrib/qubes/test/logs/get_devices.log
new file mode 100644
index 0000000000000000000000000000000000000000..5195522d87c14263f1e1421b36dac97cd3355bd5
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/logs/get_devices.log
@@ -0,0 +1,22 @@
+======================================================================
+Dom0 Devices:
+======================================================================
+ ColorHug2
+======================================================================
+ DeviceId: b0a78eb71f4eeea7df8fb114522556ba8ce22074
+ Guid: ·2082b5e0-7a64-478a-b1b2-e3404fab6dad
+ ·aa4b4156-9732-55db-9500-bf6388508ee3
+ ·101ee86a-7bea-59fb-9f89-6b6297ceed3b
+ ·2fa8891f-3ece-53a4-adc4-0dd875685f30
+ Summary: An open source display colorimeter
+ Plugin: colorhug
+ Protocol: com.hughski.colorhug
+ Flags: ·updatable
+ ·supported
+ ·registered
+ ·self-recovery
+ ·add-counterpart-guids
+ Vendor: Hughski Ltd.
+ VendorId: USB:0x273F
+ Version: 2.0.6
+ Created: 1614224175
diff --git a/fwupd-1.8.6/contrib/qubes/test/logs/get_updates.log b/fwupd-1.8.6/contrib/qubes/test/logs/get_updates.log
new file mode 100644
index 0000000000000000000000000000000000000000..3986f594444d3e56a14962c3045f7cf82ba74f7a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/logs/get_updates.log
@@ -0,0 +1,15 @@
+======================================================
+sys-usb updates:
+======================================================
+Available updates:
+======================================================
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+1. Device: ColorHug2
+ Current firmware version: 2.0.6
+======================================================
+ Firmware update version: 2.0.7
+ URL: https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab
+ SHA256 checksum: 32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda
+ Description: This release fixes prevents the firmware returning an error when the remote SHA1 hash was never sent.
+
+======================================================
diff --git a/fwupd-1.8.6/contrib/qubes/test/logs/help.log b/fwupd-1.8.6/contrib/qubes/test/logs/help.log
new file mode 100644
index 0000000000000000000000000000000000000000..193934e61b823bf18fdcfba3fa999581648611e8
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/logs/help.log
@@ -0,0 +1,25 @@
+======================================================================
+Usage:
+======================================================================
+ Command: qubes-fwupdmgr [OPTION…][FLAG..]
+ Example: qubes-fwupdmgr refresh --whonix --url=
+
+Options:
+======================================================================
+ get-devices: Get all devices that support firmware updates
+ get-updates: Get the list of updates for connected hardware
+ refresh: Refresh metadata from remote server
+ update: Update chosen device to latest firmware version
+ update-heads: Updates heads firmware to the latest version
+ downgrade: Downgrade chosen device to chosen firmware version
+ clean: Delete all cached update files
+
+Flags:
+======================================================================
+ --whonix: Download firmware updates via Tor
+ --device: Specify device for heads update (default - x230)
+ --url: Address of the custom metadata remote server
+
+Help:
+======================================================================
+ -h --help: Show help options
diff --git a/fwupd-1.8.6/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml b/fwupd-1.8.6/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..29cb95e4972cb0c0b000fb9bcfda7363cf8864ff
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/logs/metainfo_name/firmware.metainfo.xml
@@ -0,0 +1,44 @@
+
+
+ com.dell.uefi6180aaaa.firmware
+ Latitude 7390 2-in-1
+ Firmware for the Dell Latitude 7390 2-in-1
+
+ Updating the system firmware improves performance.
+
+
+ 6180aaaa-5529-4bbf-b4fd-65b4f788de5b
+
+ http://support.dell.com/
+ CC0-1.0
+ proprietary
+ Wrong name
+
+ X-System
+
+
+ quad
+ dell-bios
+ org.uefi.capsule
+
+
+
+ b03252481573f600c7f530d7a4c24bd62c810412
+ bd866bcd2b5964da4b20d3f57128746efb7afefe648cf7284f2fae399225f1ac
+
+ This stable release fixes the following issues:
+
+ Firmware updates to address the Intel Security Advisories.
+ Enhanced the system firmware auto recovery function when system firmware does not work.
+ Updated the BIOS warning message that is displayed when an AC adapter with low wattage is connected to the system.
+ Updated the Intel CPU Microcode.
+
+
+ 14699068
+
+ CVE-2019-14607
+ CVE-2019-11157
+
+
+
+
diff --git a/fwupd-1.8.6/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml b/fwupd-1.8.6/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f59ace4ed11c3977273b00b9f59ba2f9f4b37ac8
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/logs/metainfo_version/firmware.metainfo.xml
@@ -0,0 +1,44 @@
+
+
+ com.dell.uefi6180aaaa.firmware
+ Latitude 7390 2-in-1
+ Firmware for the Dell Latitude 7390 2-in-1
+
+ Updating the system firmware improves performance.
+
+
+ 6180aaaa-5529-4bbf-b4fd-65b4f788de5b
+
+ http://support.dell.com/
+ CC0-1.0
+ proprietary
+ Dell Inc.
+
+ X-System
+
+
+ quad
+ dell-bios
+ org.uefi.capsule
+
+
+
+ b03252481573f600c7f530d7a4c24bd62c810412
+ bd866bcd2b5964da4b20d3f57128746efb7afefe648cf7284f2fae399225f1ac
+
+ This stable release fixes the following issues:
+
+ Firmware updates to address the Intel Security Advisories.
+ Enhanced the system firmware auto recovery function when system firmware does not work.
+ Updated the BIOS warning message that is displayed when an AC adapter with low wattage is connected to the system.
+ Updated the Intel CPU Microcode.
+
+
+ 14699068
+
+ CVE-2019-14607
+ CVE-2019-11157
+
+
+
+
diff --git a/fwupd-1.8.6/contrib/qubes/test/test_qubes_fwupd_heads.py b/fwupd-1.8.6/contrib/qubes/test/test_qubes_fwupd_heads.py
new file mode 100644
index 0000000000000000000000000000000000000000..aacc544e27e19bb44c1aa1b1b146b998aa2be616
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/test_qubes_fwupd_heads.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import io
+import os
+import platform
+import shutil
+import imp
+import src.qubes_fwupd_heads as qf_heads
+import sys
+import unittest
+
+from test.fwupd_logs import HEADS_XML
+
+CUSTOM_METADATA = "https://fwupd.org/downloads/firmware-3c81bfdc9db5c8a42c09d38091944bc1a05b27b0.xml.gz"
+QUBES_FWUPDMGR_REPO = "./src/qubes_fwupdmgr.py"
+QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr"
+
+
+class TestQubesFwupdHeads(unittest.TestCase):
+ def setUp(self):
+ if os.path.exists(QUBES_FWUPDMGR_REPO):
+ self.qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_REPO)
+ elif os.path.exists(QUBES_FWUPDMGR_BINDIR):
+ self.qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_BINDIR)
+ self.q = qf_heads.FwupdHeads()
+ self.maxDiff = 2000
+ self.captured_output = io.StringIO()
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_get_hwids(self):
+ self.q._get_hwids()
+ self.assertNotEqual(self.q.dom0_hwids_info, "")
+
+ def test_gather_firmware_version_empty(self):
+ self.q.dom0_hwids_info = ""
+ return_code = self.q._gather_firmware_version()
+ self.assertEqual(return_code, self.qfwupd.EXIT_CODES["NOTHING_TO_DO"])
+
+ def test_gather_firmware_version(self):
+ self.q.dom0_hwids_info = "CBET4000 Heads-v0.2.2-917-g19f0e65"
+ self.q._gather_firmware_version()
+ self.assertEqual(self.q.heads_version, "0.2.2-917-g19f0e65")
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_parse_metadata(self):
+ qmgr = self.qfwupd.QubesFwupdmgr()
+ qmgr.metadata_file = CUSTOM_METADATA.replace(
+ "https://fwupd.org/downloads", self.qfwupd.FWUPD_DOM0_METADATA_DIR
+ )
+ qmgr._download_metadata(metadata_url=CUSTOM_METADATA)
+ self.q._parse_metadata(qmgr.metadata_file)
+ self.assertTrue(self.q.metadata_info)
+
+ def test_check_heads_updates_default_heads(self):
+ self.q.metadata_info = HEADS_XML
+ self.q.heads_version = "heads"
+ return_code = self.q._parse_heads_updates("x230")
+ self.assertEqual(return_code, self.qfwupd.EXIT_CODES["SUCCESS"])
+ self.assertEqual(
+ self.q.heads_update_url,
+ "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab",
+ )
+ self.assertEqual(
+ self.q.heads_update_sha,
+ "ba519a7a5d8136c8ade0cf0c775c58f3165f42798ff631c3f57f075897ef1586",
+ )
+ self.assertEqual(self.q.heads_update_version, "0.2.3")
+
+ def test_check_heads_updates_no_updates(self):
+ self.q.metadata_info = HEADS_XML
+ self.q.heads_version = "0.2.3"
+ return_code = self.q._parse_heads_updates("x230")
+ self.assertEqual(return_code, self.qfwupd.EXIT_CODES["NOTHING_TO_DO"])
+
+ def test_check_heads_updates_lower_version(self):
+ self.q.metadata_info = HEADS_XML
+ self.q.heads_version = "0.2.2"
+ return_code = self.q._parse_heads_updates("x230")
+ self.assertEqual(return_code, self.qfwupd.EXIT_CODES["SUCCESS"])
+ self.assertEqual(
+ self.q.heads_update_url,
+ "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab",
+ )
+ self.assertEqual(
+ self.q.heads_update_sha,
+ "ba519a7a5d8136c8ade0cf0c775c58f3165f42798ff631c3f57f075897ef1586",
+ )
+ self.assertEqual(self.q.heads_update_version, "0.2.3")
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_copy_heads_firmware(self):
+ qmgr = self.qfwupd.QubesFwupdmgr()
+ self.q.heads_update_url = "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab"
+ self.q.heads_update_sha = (
+ "ba519a7a5d8136c8ade0cf0c775c58f3165f42798ff631c3f57f075897ef1586"
+ )
+ self.q.heads_update_version = "0.2.3"
+ qmgr._download_firmware_updates(
+ self.q.heads_update_url, self.q.heads_update_sha
+ )
+ heads_boot_path = os.path.join(
+ qf_heads.HEADS_UPDATES_DIR, self.q.heads_update_version
+ )
+ if os.path.exists(heads_boot_path):
+ shutil.rmtree(heads_boot_path)
+ ret_code = self.q._copy_heads_firmware(qmgr.arch_path)
+ self.assertNotEqual(ret_code, self.qfwupd.EXIT_CODES["NOTHING_TO_DO"])
+ firmware_path = os.path.join(heads_boot_path, "firmware.rom")
+ self.assertTrue(os.path.exists(firmware_path))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/fwupd-1.8.6/contrib/qubes/test/test_qubes_fwupdmgr.py b/fwupd-1.8.6/contrib/qubes/test/test_qubes_fwupdmgr.py
new file mode 100755
index 0000000000000000000000000000000000000000..ec9e42b58c8e461558567fe89993f019f629fa10
--- /dev/null
+++ b/fwupd-1.8.6/contrib/qubes/test/test_qubes_fwupdmgr.py
@@ -0,0 +1,873 @@
+#!/usr/bin/python3
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2021 Norbert Kamiński
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import json
+import unittest
+import os
+import subprocess
+import sys
+import imp
+import io
+import platform
+from packaging.version import Version
+from pathlib import Path
+from test.fwupd_logs import UPDATE_INFO, GET_DEVICES, DMI_DECODE
+from test.fwupd_logs import GET_DEVICES_NO_UPDATES, GET_DEVICES_NO_VERSION
+from unittest.mock import patch
+
+
+QUBES_FWUPDMGR_REPO = "./src/qubes_fwupdmgr.py"
+QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr"
+
+if os.path.exists(QUBES_FWUPDMGR_REPO):
+ qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_REPO)
+elif os.path.exists(QUBES_FWUPDMGR_BINDIR):
+ qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_BINDIR)
+
+FWUPD_DOM0_DIR = "/root/.cache/fwupd"
+FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
+FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted")
+FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log")
+FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata")
+FWUPD_DOM0_METADATA_FILE = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
+FWUPD_DOM0_METADATA_FILE_JCAT = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
+FWUPD_VM_DIR = "/home/user/.cache/fwupd"
+FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
+FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
+FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
+FWUPD_VM_METADATA_FILE_JCAT = os.path.join(
+ FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat"
+)
+REQUIRED_DEV = "Requires device not connected"
+REQUIRED_USBVM = "Requires sys-usb"
+XL_LIST_LOG = "Name ID Mem VCPUs State Time(s)"
+USBVM_N = "sys-usb"
+FWUPDMGR = "/bin/fwupdmgr"
+BIOS_UPDATE_FLAG = os.path.join(FWUPD_DOM0_DIR, "bios_update")
+LVFS_TESTING_DOM0_FLAG = os.path.join(FWUPD_DOM0_DIR, "lvfs_testing")
+LVFS_TESTING_USBVM_FLAG = os.path.join(FWUPD_VM_DIR, "lvfs_testing")
+CUSTOM_METADATA = "https://fwupd.org/downloads/firmware-3c81bfdc9db5c8a42c09d38091944bc1a05b27b0.xml.gz"
+
+
+def check_usbvm():
+ """Checks if sys-usb is running"""
+ if "qubes" not in platform.release():
+ return False
+ q = qfwupd.QubesFwupdmgr()
+ q.check_usbvm()
+ return "sys-usb" in q.output
+
+
+def device_connected_dom0():
+ """Checks if the testing device is connected in dom0"""
+ if "qubes" not in platform.release():
+ return False
+ q = qfwupd.QubesFwupdmgr()
+ q._get_dom0_devices()
+ return "ColorHug2" in q.dom0_devices_info
+
+
+def device_connected_usbvm():
+ """Checks if the testing device is connected in usbvm"""
+ if not check_usbvm():
+ return False
+ q = qfwupd.QubesFwupdmgr()
+ q._validate_usbvm_dirs()
+ if not os.path.exists(FWUPD_DOM0_DIR):
+ q.refresh_metadata()
+ q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ return "ColorHug2" in usbvm_device_info.read()
+
+
+def check_whonix_updatevm():
+ """Checks if the sys-whonix is running"""
+ if "qubes" not in platform.release():
+ return False
+ q = qfwupd.QubesFwupdmgr()
+ q.check_usbvm()
+ return "sys-whonix" in q.output
+
+
+class TestQubesFwupdmgr(unittest.TestCase):
+ def setUp(self):
+ self.q = qfwupd.QubesFwupdmgr()
+ self.maxDiff = 2000
+ self.captured_output = io.StringIO()
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_download_metadata(self):
+ self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.q._download_metadata()
+ self.assertTrue(
+ os.path.exists(FWUPD_DOM0_METADATA_FILE),
+ msg="Metadata update file does not exist",
+ )
+ self.assertTrue(
+ os.path.exists(FWUPD_DOM0_METADATA_FILE_JCAT),
+ msg="Metadata signature does not exist",
+ )
+
+ @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix")
+ def test_download_metadata_whonix(self):
+ self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.q._download_metadata(whonix=True)
+ self.assertTrue(
+ os.path.exists(FWUPD_DOM0_METADATA_FILE),
+ msg="Metadata update file does not exist",
+ )
+ self.assertTrue(
+ os.path.exists(FWUPD_DOM0_METADATA_FILE_JCAT),
+ msg="Metadata signature does not exist",
+ )
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_download_custom_metadata(self):
+ self.q.metadata_file = CUSTOM_METADATA.replace(
+ "https://fwupd.org/downloads", FWUPD_DOM0_METADATA_DIR
+ )
+ self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
+ self.q._download_metadata(metadata_url=CUSTOM_METADATA)
+ self.assertTrue(
+ os.path.exists(self.q.metadata_file),
+ msg="Metadata update file does not exist",
+ )
+ self.assertTrue(
+ os.path.exists(self.q.metadata_file_jcat),
+ msg="Metadata signature does not exist",
+ )
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_refresh_metadata_dom0(self):
+ self.q.refresh_metadata()
+ self.assertEqual(
+ self.q.output,
+ "Successfully refreshed metadata manually\n",
+ msg="Metadata refresh failed.",
+ )
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_refresh_metadata_dom0_custom(self):
+ self.q.refresh_metadata(metadata_url=CUSTOM_METADATA)
+ self.assertEqual(
+ self.q.output,
+ "Successfully refreshed metadata manually\n",
+ msg="Metadata refresh failed.",
+ )
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_refresh_metadata_usbvm(self):
+ self.q.refresh_metadata(usbvm=True)
+ self.assertEqual(
+ self.q.output,
+ "Successfully refreshed metadata manually\n",
+ msg="Metadata refresh failed.",
+ )
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_refresh_metadata_usbvm_custom(self):
+ self.q.refresh_metadata(usbvm=True, metadata_url=CUSTOM_METADATA)
+ self.assertEqual(
+ self.q.output,
+ "Successfully refreshed metadata manually\n",
+ msg="Metadata refresh failed.",
+ )
+
+ @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix")
+ def test_refresh_metadata_whonix(self):
+ self.q.refresh_metadata(whonix=True)
+ self.assertEqual(
+ self.q.output,
+ "Successfully refreshed metadata manually\n",
+ msg="Metadata refresh failed.",
+ )
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_get_dom0_updates(self):
+ self.q._get_dom0_updates()
+ self.assertIn(
+ "Devices", self.q.dom0_updates_info, msg="Getting available updates failed"
+ )
+
+ def test_parse_updates_info(self):
+ self.q._parse_dom0_updates_info(UPDATE_INFO)
+ self.assertEqual(
+ self.q.dom0_updates_list[0]["Name"], "ColorHug2", msg="Wrong device name"
+ )
+ self.assertEqual(
+ self.q.dom0_updates_list[0]["Version"], "2.0.6", msg="Wrong update version"
+ )
+ self.assertEqual(
+ self.q.dom0_updates_list[0]["Releases"][0]["Url"],
+ "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ msg="Wrong update URL",
+ )
+ self.assertEqual(
+ self.q.dom0_updates_list[0]["Releases"][0]["Checksum"],
+ "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
+ msg="Wrong checksum",
+ )
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_download_firmware_updates(self):
+ self.q._download_firmware_updates(
+ "https://fwupd.org/downloads/e5ad222bdbd3d3d48d8613e67c7e0a0e194f"
+ "8cd828e33c554d9f05d933e482c7-hughski-colorhug2-2.0.7.cab",
+ "e5ad222bdbd3d3d48d8613e67c7e0a0e194f8cd828e33c554d9f05d933e482c7",
+ )
+ update_path = os.path.join(
+ FWUPD_DOM0_UPDATES_DIR,
+ "e5ad222bdbd3d3d48d8613e67c7e0a0e194f8cd828e33c554d9f05d933e482c7"
+ "-hughski-colorhug2-2.0.7.cab",
+ )
+ self.assertTrue(os.path.exists(update_path))
+
+ @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix")
+ def test_download_firmware_updates_whonix(self):
+ self.q._download_firmware_updates(
+ "https://fwupd.org/downloads/e5ad222bdbd3d3d48d8613e67c7e0a0e194f"
+ "8cd828e33c554d9f05d933e482c7-hughski-colorhug2-2.0.7.cab",
+ "e5ad222bdbd3d3d48d8613e67c7e0a0e194f8cd828e33c554d9f05d933e482c7",
+ whonix=True,
+ )
+ update_path = os.path.join(
+ FWUPD_DOM0_UPDATES_DIR,
+ "e5ad222bdbd3d3d48d8613e67c7e0a0e194f8cd828e33c554d9f05d933e482c7"
+ "-hughski-colorhug2-2.0.7.cab",
+ )
+ self.assertTrue(os.path.exists(update_path))
+
+ def test_user_input_empty_dict(self):
+ downgrade_dict = {"usbvm": [], "dom0": []}
+ self.assertEqual(self.q._user_input(downgrade_dict), 2)
+
+ def test_user_input_n(self):
+ user_input = ["sth", "n"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q._parse_dom0_updates_info(UPDATE_INFO)
+ downgrade_dict = {
+ "usbvm": self.q.dom0_updates_list,
+ "dom0": self.q.dom0_updates_list,
+ }
+ choice = self.q._user_input(downgrade_dict, usbvm=True)
+ self.assertEqual(choice, 2)
+ user_input = ["sth", "N"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q._parse_dom0_updates_info(UPDATE_INFO)
+ downgrade_dict = {
+ "usbvm": self.q.dom0_updates_list,
+ "dom0": self.q.dom0_updates_list,
+ }
+ choice = self.q._user_input(downgrade_dict, usbvm=True)
+ self.assertEqual(choice, 2)
+
+ def test_user_input_choice(self):
+ user_input = ["6", "1"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q._parse_dom0_updates_info(UPDATE_INFO)
+ updates_dict = {
+ "usbvm": self.q.dom0_updates_list,
+ "dom0": self.q.dom0_updates_list,
+ }
+ key, choice = self.q._user_input(updates_dict)
+ self.assertEqual(key, "dom0")
+ self.assertEqual(choice, 0)
+
+ def test_user_input_choice_usbvm(self):
+ user_input = ["6", "2"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q._parse_dom0_updates_info(UPDATE_INFO)
+ updates_dict = {
+ "usbvm": self.q.dom0_updates_list,
+ "dom0": self.q.dom0_updates_list,
+ }
+ key, choice = self.q._user_input(updates_dict, usbvm=True)
+ self.assertEqual(key, "usbvm")
+ self.assertEqual(choice, 0)
+
+ def test_parse_parameters(self):
+ self.q._parse_dom0_updates_info(UPDATE_INFO)
+ update_dict = {"dom0": self.q.dom0_updates_list}
+ self.q._parse_parameters(update_dict, "dom0", 0)
+ self.assertEqual(
+ self.q.url,
+ "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ )
+ self.assertEqual(
+ self.q.sha,
+ "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
+ )
+ self.assertEqual(self.q.version, "2.0.7")
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_clean_cache_dom0(self):
+ self.q.clean_cache()
+ self.assertFalse(os.path.exists(FWUPD_DOM0_METADATA_DIR))
+ self.assertFalse(os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR))
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_clean_cache_dom0_n_usbvm(self):
+ self.q._validate_usbvm_dirs()
+ self.q.clean_cache(usbvm=True)
+ self.assertFalse(os.path.exists(FWUPD_DOM0_METADATA_DIR))
+ self.assertFalse(os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR))
+ cmd_validate_metadata = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"! [ -d {FWUPD_VM_METADATA_DIR} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_metadata)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Creating metadata directory failed")
+ cmd_validate_udpdate = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"! [ -d {FWUPD_VM_UPDATES_DIR} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_udpdate)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Cleaning update directory failed")
+
+ def test_output_crawler(self):
+ crawler_output = io.StringIO()
+ sys.stdout = crawler_output
+ self.q._output_crawler(json.loads(UPDATE_INFO), 0)
+ with open("test/logs/get_devices.log", "r") as get_devices:
+ self.assertEqual(
+ get_devices.read(), crawler_output.getvalue().strip() + "\n"
+ )
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_get_dom0_devices(self):
+ self.q._get_dom0_devices()
+ self.assertIsNotNone(self.q.dom0_devices_info)
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_get_devices_qubes_dom0(self):
+ get_devices_output = io.StringIO()
+ sys.stdout = get_devices_output
+ self.q.get_devices_qubes()
+ self.assertNotEqual(get_devices_output.getvalue().strip(), "")
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_get_devices_qubes_usbvm(self):
+ get_devices_output = io.StringIO()
+ sys.stdout = get_devices_output
+ self.q.get_devices_qubes(usbvm=True)
+ self.assertNotEqual(get_devices_output.getvalue().strip(), "")
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV)
+ def test_get_updates_qubes_dom0(self):
+ get_updates_output = io.StringIO()
+ sys.stdout = get_updates_output
+ self.q.get_updates_qubes()
+ self.assertNotEqual(get_updates_output.getvalue().strip(), "")
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless(device_connected_usbvm(), REQUIRED_DEV)
+ def test_get_updates_qubes_usbvm(self):
+ get_updates_output = io.StringIO()
+ sys.stdout = get_updates_output
+ self.q.get_updates_qubes(usbvm=True)
+ self.assertNotEqual(get_updates_output.getvalue().strip(), "")
+ sys.stdout = self.captured_output
+
+ def test_help(self):
+ help_output = io.StringIO()
+ sys.stdout = help_output
+ self.q.help()
+ with open("test/logs/help.log", "r") as help_log:
+ self.assertEqual(help_log.read(), help_output.getvalue().strip() + "\n")
+ sys.stdout = self.captured_output
+
+ @patch(
+ "test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi",
+ return_value=DMI_DECODE,
+ )
+ def test_verify_dmi(self, output):
+ self.q.dmi_version = "P.1.0"
+ self.q._verify_dmi("test/logs/", "P1.1")
+
+ @patch(
+ "test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi",
+ return_value=DMI_DECODE,
+ )
+ def test_verify_dmi_wrong_vendor(self, output):
+ with self.assertRaises(ValueError) as wrong_vendor:
+ self.q.dmi_version = "P.1.0"
+ self.q._verify_dmi("test/logs/metainfo_name/", "P1.1")
+ self.assertIn("Wrong firmware provider.", str(wrong_vendor.exception))
+
+ @patch(
+ "test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi",
+ return_value=DMI_DECODE,
+ )
+ def test_verify_dmi_version(self, output):
+ self.q.dmi_version = "P1.0"
+ with self.assertRaises(ValueError) as downgrade:
+ self.q._verify_dmi("test/logs/metainfo_version/", "P0.1")
+ self.assertIn("P0.1 < P1.0 Downgrade not allowed", str(downgrade.exception))
+
+ @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV)
+ def test_downgrade_firmware_dom0(self):
+ old_version = None
+ self.q._get_dom0_devices()
+ downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
+ for number, device in enumerate(downgrades):
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ old_version = device["Version"]
+ break
+ if old_version is None:
+ self.fail("Test device not found")
+ user_input = [str(number + 1), "1"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q.downgrade_firmware()
+ self.q._get_dom0_devices()
+ downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
+ new_version = downgrades[number]["Version"]
+ self.assertGreater(Version(old_version), Version(new_version))
+
+ @unittest.skipUnless(
+ check_whonix_updatevm() and device_connected_usbvm(), REQUIRED_DEV
+ )
+ def test_update_n_downgrade_firmware_whonix(self):
+ old_version = None
+ self.q.clean_cache(usbvm=True)
+ self.q._get_dom0_devices()
+ dom0_downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ downgrades = self.q._parse_downgrades(raw)
+ for number, device in enumerate(downgrades):
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ old_version = device["Version"]
+ break
+ if old_version is None:
+ self.fail("Test device not found")
+ user_input = [str(number + 1 + len(dom0_downgrades)), "1"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q.downgrade_firmware(usbvm=True, whonix=True)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ downgrades = self.q._parse_downgrades(raw)
+ new_version = downgrades[number]["Version"]
+ self.assertGreater(Version(old_version), Version(new_version))
+ old_version = None
+ new_version = None
+ self.q._get_dom0_updates()
+ self.q._parse_dom0_updates_info(self.q.dom0_updates_info)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ self.q._parse_usbvm_updates(raw)
+ for number, device in enumerate(self.q.usbvm_updates_list):
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ old_version = device["Version"]
+ break
+ if old_version is None:
+ self.fail("Test device not found")
+ user_input = [str(number + 1 + len(self.q.dom0_updates_list)), "1"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q.update_firmware(usbvm=True, whonix=True)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ usbvm_devices_info_dict = json.loads(raw)
+ for device in usbvm_devices_info_dict["Devices"]:
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ new_version = device["Version"]
+ break
+ if new_version is None:
+ self.fail("Test device not found")
+ self.assertLess(Version(old_version), Version(new_version))
+
+ @unittest.skipUnless(device_connected_usbvm(), REQUIRED_DEV)
+ def test_downgrade_firmware_usbvm(self):
+ old_version = None
+ self.q._get_dom0_devices()
+ dom0_downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ downgrades = self.q._parse_downgrades(raw)
+ for number, device in enumerate(downgrades):
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ old_version = device["Version"]
+ break
+ if old_version is None:
+ self.fail("Test device not found")
+ user_input = [str(number + 1 + len(dom0_downgrades)), "1"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q.downgrade_firmware(usbvm=True)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ downgrades = self.q._parse_downgrades(raw)
+ new_version = downgrades[number]["Version"]
+ self.assertGreater(Version(old_version), Version(new_version))
+
+ def test_parse_downgrades(self):
+ downgrades = self.q._parse_downgrades(GET_DEVICES)
+ self.assertEqual(downgrades[0]["Name"], "ColorHug2")
+ self.assertEqual(downgrades[0]["Version"], "2.0.6")
+ self.assertEqual(downgrades[0]["Releases"][0]["Version"], "2.0.5")
+ self.assertEqual(
+ downgrades[0]["Releases"][0]["Url"],
+ "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ )
+ self.assertEqual(
+ downgrades[0]["Releases"][0]["Checksum"],
+ "8cd379eb2e1467e4fda92c20650306dc7e598b1d421841bbe19d9ed6ea01e3ee",
+ )
+
+ def test_parse_downgrades_no_version(self):
+ downgrades = self.q._parse_downgrades(GET_DEVICES_NO_VERSION)
+ self.assertEqual(downgrades[0]["Name"], "ColorHug2")
+ self.assertEqual(downgrades[0]["Version"], "2.0.6")
+ self.assertEqual(downgrades[0]["Releases"][0]["Version"], "2.0.5")
+ self.assertEqual(
+ downgrades[0]["Releases"][0]["Url"],
+ "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
+ )
+ self.assertEqual(
+ downgrades[0]["Releases"][0]["Checksum"],
+ "4ee9dfa38df3b810f739d8a19d13da1b3175fb87",
+ )
+
+ def test_user_input_downgrade_usbvm(self):
+ user_input = ["2", "6", "sth", "2.2.1", "", " ", "\0", "2"]
+ with patch("builtins.input", side_effect=user_input):
+ downgrade_list = self.q._parse_downgrades(GET_DEVICES)
+ downgrade_dict = {"usbvm": downgrade_list, "dom0": downgrade_list}
+ key, device_choice, downgrade_choice = self.q._user_input(
+ downgrade_dict, downgrade=True, usbvm=True
+ )
+ self.assertEqual(key, "usbvm")
+ self.assertEqual(device_choice, 0)
+ self.assertEqual(downgrade_choice, 1)
+
+ def test_user_input_downgrade_dom0(self):
+ user_input = ["1", "6", "sth", "2.2.1", "", " ", "\0", "2"]
+ with patch("builtins.input", side_effect=user_input):
+ downgrade_list = self.q._parse_downgrades(GET_DEVICES)
+ downgrade_dict = {"dom0": downgrade_list}
+ key, device_choice, downgrade_choice = self.q._user_input(
+ downgrade_dict, downgrade=True
+ )
+ self.assertEqual(key, "dom0")
+ self.assertEqual(device_choice, 0)
+ self.assertEqual(downgrade_choice, 1)
+
+ def test_user_input_downgrade_N(self):
+ user_input = ["N"]
+ with patch("builtins.input", side_effect=user_input):
+ downgrade_list = self.q._parse_downgrades(GET_DEVICES)
+ downgrade_dict = {"usbvm": downgrade_list, "dom0": downgrade_list}
+ N_choice = self.q._user_input(downgrade_dict, downgrade=True, usbvm=True)
+ self.assertEqual(N_choice, 2)
+
+ @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV)
+ def test_update_firmware_dom0(self):
+ old_version = None
+ new_version = None
+ self.q._get_dom0_updates()
+ self.q._parse_dom0_updates_info(self.q.dom0_updates_info)
+ for number, device in enumerate(self.q.dom0_updates_list):
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ old_version = device["Version"]
+ break
+ if old_version is None:
+ self.fail("Test device not found")
+ user_input = [str(number + 1)]
+ with patch("builtins.input", side_effect=user_input):
+ self.q.update_firmware()
+ self.q._get_dom0_devices()
+ dom0_devices_info_dict = json.loads(self.q.dom0_devices_info)
+ for device in dom0_devices_info_dict["Devices"]:
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ new_version = device["Version"]
+ break
+ if new_version is None:
+ self.fail("Test device not found")
+ self.assertLess(Version(old_version), Version(new_version))
+
+ @unittest.skipUnless(device_connected_usbvm(), REQUIRED_DEV)
+ def test_update_firmware_usbvm(self):
+ old_version = None
+ new_version = None
+ self.q._get_dom0_updates()
+ self.q._parse_dom0_updates_info(self.q.dom0_updates_info)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ self.q._parse_usbvm_updates(raw)
+ for number, device in enumerate(self.q.usbvm_updates_list):
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ old_version = device["Version"]
+ break
+ if old_version is None:
+ self.fail("Test device not found")
+ user_input = [str(number + 1 + len(self.q.dom0_updates_list)), "1"]
+ with patch("builtins.input", side_effect=user_input):
+ self.q.update_firmware(usbvm=True)
+ self.q._get_usbvm_devices()
+ with open(FWUPD_VM_LOG) as usbvm_device_info:
+ raw = usbvm_device_info.read()
+ usbvm_devices_info_dict = json.loads(raw)
+ for device in usbvm_devices_info_dict["Devices"]:
+ if "Name" not in device:
+ continue
+ if device["Name"] == "ColorHug2":
+ new_version = device["Version"]
+ break
+ if new_version is None:
+ self.fail("Test device not found")
+ self.assertLess(Version(old_version), Version(new_version))
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_get_usbvm_devices(self):
+ self.q._get_usbvm_devices()
+ self.assertTrue(os.path.exists(FWUPD_VM_LOG))
+
+ def test_parse_usbvm_updates(self):
+ self.q._parse_usbvm_updates(GET_DEVICES)
+ self.assertEqual(self.q.usbvm_updates_list[0]["Name"], "ColorHug2")
+ self.assertEqual(self.q.usbvm_updates_list[0]["Version"], "2.0.6")
+ self.assertListEqual(
+ self.q.usbvm_updates_list[0]["Releases"],
+ [
+ {
+ "Checksum": "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
+ "Description": "This release fixes prevents the firmware returning an "
+ "error when the remote SHA1 hash was never sent.
",
+ "Url": "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
+ "Version": "2.0.7",
+ }
+ ],
+ )
+
+ def test_parse_usbvm_updates_no_updates_available(self):
+ self.q._parse_usbvm_updates(GET_DEVICES_NO_UPDATES)
+ self.assertListEqual(self.q.usbvm_updates_list, [])
+
+ def test_updates_crawler(self):
+ crawler_output = io.StringIO()
+ sys.stdout = crawler_output
+ self.q._parse_usbvm_updates(GET_DEVICES)
+ self.q._updates_crawler(self.q.usbvm_updates_list, usbvm=True)
+ with open("test/logs/get_updates.log", "r") as getupdates:
+ self.assertEqual(
+ getupdates.read(), crawler_output.getvalue().strip() + "\n"
+ )
+ sys.stdout = self.captured_output
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_validate_usbvm_dirs(self):
+ self.q._validate_usbvm_dirs()
+ cmd_validate_metadata = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"[ -d {FWUPD_VM_METADATA_DIR} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_metadata)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Creating metadata directory failed")
+ cmd_validate_udpdate = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"[ -d {FWUPD_VM_UPDATES_DIR} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_udpdate)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Creating update directory failed")
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_copy_usbvm_metadata(self):
+ self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
+ self.q._download_metadata()
+ self.q._validate_usbvm_dirs()
+ self.q._copy_usbvm_metadata()
+ cmd_validate_metadata_file = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"[ -f {FWUPD_VM_METADATA_FILE} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_metadata_file)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Metadata file does not exist")
+ cmd_validate_metadata_jcat = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"[ -f {FWUPD_VM_METADATA_FILE_JCAT} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_metadata_jcat)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Metadata jcat signature does not exist")
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_enable_lvfs_testing_dom0(self):
+ if os.path.exists(LVFS_TESTING_DOM0_FLAG):
+ os.remove(LVFS_TESTING_DOM0_FLAG)
+ self.q._enable_lvfs_testing_dom0()
+ self.assertTrue(os.path.exists(LVFS_TESTING_DOM0_FLAG))
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_enable_lvfs_testing_usbvm(self):
+ cmd_validate_flag = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ (
+ "script --quiet --return --command "
+ f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"'
+ ),
+ ]
+ cmd_rm_flag = [
+ "qvm-run",
+ "--pass-io",
+ USBVM_N,
+ ("script --quiet --return --command " f'"rm {LVFS_TESTING_USBVM_FLAG}"'),
+ ]
+ flag = subprocess.Popen(cmd_validate_flag)
+ flag.wait()
+ if flag.returncode == 0:
+ rm_flag = subprocess.Popen(cmd_rm_flag)
+ rm_flag.wait()
+ if rm_flag.returncode != 0:
+ raise Exception("Removing lvfs-testing flag failed!!")
+ self.q._enable_lvfs_testing_usbvm(usbvm=True)
+ flag = subprocess.Popen(cmd_validate_flag)
+ flag.wait()
+ self.assertEqual(flag.returncode, 0)
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_validate_usbvm_metadata(self):
+ self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
+ self.q._download_metadata()
+ self.q._validate_usbvm_dirs()
+ self.q._copy_usbvm_metadata()
+ self.q._validate_usbvm_metadata()
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_refresh_usbvm_metadata(self):
+ self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
+ self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
+ self.q.lvfs = "lvfs"
+ self.q._download_metadata()
+ self.q._validate_usbvm_dirs()
+ self.q._copy_usbvm_metadata()
+ self.q._validate_usbvm_metadata()
+ self.q._refresh_usbvm_metadata()
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_clean_usbvm(self):
+ self.q._validate_usbvm_dirs()
+ self.q._clean_usbvm()
+ cmd_validate_metadata = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"! [ -d {FWUPD_VM_METADATA_DIR} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_metadata)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Cleaning metadata directory failed")
+ cmd_validate_udpdate = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ f"! [ -d {FWUPD_VM_METADATA_DIR} ]",
+ ]
+ p = subprocess.Popen(cmd_validate_udpdate)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Cleaning update directory failed")
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_validate_usbvm_archive(self):
+ url = (
+ "https://fwupd.org/downloads/e5ad222bdbd3d3d48d8613e67c7e0a0e1"
+ "94f8cd828e33c554d9f05d933e482c7-hughski-colorhug2-2.0.7.cab"
+ )
+ sha = "e5ad222bdbd3d3d48d8613e67c7e0a0e194f8cd828e33c554d9f05d933e482c7"
+ name = url.replace("https://fwupd.org/downloads/", "")
+ self.q._clean_usbvm()
+ self.q._validate_usbvm_dirs()
+ self.q._download_firmware_updates(url, sha)
+ self.q._copy_firmware_updates(name)
+ self.q._validate_usbvm_archive(name, sha)
+ cmd_validate_udpdate = [
+ "qvm-run",
+ "--pass-io",
+ "sys-usb",
+ "[ -f %s ]" % os.path.join(FWUPD_VM_UPDATES_DIR, name),
+ ]
+ p = subprocess.Popen(cmd_validate_udpdate)
+ p.wait()
+ self.assertEqual(p.returncode, 0, msg="Archive validation failed")
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_check_usbvm(self):
+ self.q.check_usbvm()
+ self.assertIn(XL_LIST_LOG, self.q.output)
+
+ @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
+ def test_bios_refresh_metadata(self):
+ sys_usb = self.q.check_usbvm()
+ Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True)
+ self.q.refresh_metadata_after_bios_update(usbvm=sys_usb)
+ self.assertEqual(
+ self.q.output,
+ "Successfully refreshed metadata manually\n",
+ msg="Metadata refresh failed.",
+ )
+
+ @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
+ def test_trusted_cleanup(self):
+ trusted_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, "trusted.cab")
+ if not os.path.exists(trusted_path):
+ Path(FWUPD_DOM0_UPDATES_DIR).mkdir(exist_ok=True)
+ Path(trusted_path).touch(mode=0o644, exist_ok=True)
+ os.mkdir(trusted_path.replace(".cab", ""))
+ self.q.trusted_cleanup(usbvm=True)
+ self.assertFalse(os.path.exists(trusted_path))
+ self.assertFalse(os.path.exists(trusted_path.replace(".cab", "")))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/fwupd-1.8.6/contrib/reformat-code.py b/fwupd-1.8.6/contrib/reformat-code.py
new file mode 100755
index 0000000000000000000000000000000000000000..65a4ac4ac7c3fc8f66c6ec177a0529a01d18f08b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/reformat-code.py
@@ -0,0 +1,90 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2017 Dell Inc.
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+import os
+import sys
+import subprocess
+import argparse
+
+CLANG_DIFF_FORMATTERS = [
+ "clang-format-diff-11",
+ "clang-format-diff-13",
+ "clang-format-diff",
+]
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Reformat C code to match project style",
+ epilog="Call with no argument to reformat uncommitted code.",
+ )
+ parser.add_argument(
+ "commit", nargs="*", default="", help="Reformat all changes since this commit"
+ )
+ parser.add_argument(
+ "--debug", action="store_true", help="Display all launched commands"
+ )
+ return parser.parse_args()
+
+
+def select_clang_version(formatters):
+ for formatter in formatters:
+ try:
+ ret = subprocess.check_call(
+ [formatter, "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ if ret == 0:
+ return formatter
+ except FileNotFoundError:
+ continue
+ print("No clang formatter installed")
+ sys.exit(1)
+
+
+## Entry Point ##
+if __name__ == "__main__":
+ args = parse_args()
+ base = os.getenv("GITHUB_BASE_REF")
+ if base:
+ base = "origin/%s" % base
+ else:
+ if args.commit:
+ base = args.commit[0]
+ else:
+ base = "HEAD"
+ cmd = ["git", "describe", base]
+ if args.debug:
+ print(cmd)
+ ret = subprocess.run(cmd, capture_output=True)
+ if ret.returncode:
+ if args.debug:
+ print(ret.stderr)
+ base = "HEAD"
+ print("Reformatting code against %s" % base)
+ formatter = select_clang_version(CLANG_DIFF_FORMATTERS)
+ cmd = ["git", "diff", "-U0", base]
+ if args.debug:
+ print(cmd)
+ ret = subprocess.run(cmd, capture_output=True, text=True)
+ if ret.returncode:
+ print("Failed to run %s\n%s" % (cmd, ret.stderr.strip()))
+ sys.exit(1)
+ cmd = [formatter, "-p1"]
+ if args.debug:
+ print(cmd)
+ ret = subprocess.run(cmd, input=ret.stdout, capture_output=True, text=True)
+ if ret.returncode:
+ print("Failed to run %s\n%s" % (cmd, ret.stderr.strip()))
+ sys.exit(1)
+ cmd = ["patch", "-p0"]
+ if args.debug:
+ print(cmd)
+ ret = subprocess.run(cmd, input=ret.stdout, capture_output=True, text=True)
+ if ret.returncode:
+ print("Failed to run %s\n%s" % (cmd, ret.stderr.strip()))
+ sys.exit(1)
+ sys.exit(0)
diff --git a/fwupd-1.8.6/contrib/run-tests.sh b/fwupd-1.8.6/contrib/run-tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9a22092231bc265e1b9edd57bd8eede1ddf6b5be
--- /dev/null
+++ b/fwupd-1.8.6/contrib/run-tests.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+meson build && ninja -C build test
diff --git a/fwupd-1.8.6/contrib/setup b/fwupd-1.8.6/contrib/setup
new file mode 100755
index 0000000000000000000000000000000000000000..71fb82a8c03a19a66aa2ed3c0419ef393c3a6a3d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/setup
@@ -0,0 +1,184 @@
+#!/bin/bash -e
+# Setup the repository and local system for development
+
+cd "$(dirname "$0")/.."
+
+HELPER=./contrib/ci/fwupd_setup_helpers.py
+HELPER_ARGS="-y"
+
+rename_branch()
+{
+ OLD=master
+ NEW=main
+ if git log $OLD >/dev/null 2>&1 &&
+ git remote get-url origin 2>&1 | grep fwupd/fwupd.git >/dev/null 2>&1; then
+ read -p "Rename existing $OLD branch to $NEW? (y/N) " question
+ if [ "$question" = "y" ]; then
+ git branch -m $OLD $NEW
+ git fetch origin
+ git branch -u origin/$NEW $NEW
+ git remote set-head origin -a
+ fi
+ fi
+}
+
+detect_selinux()
+{
+ SELINUX="0"
+ if which getenforce &> /dev/null; then
+ if getenforce | grep -i "enforcing" >/dev/null; then
+ SELINUX="1"
+ fi
+ fi
+}
+
+setup_deps()
+{
+ read -p "Install build dependencies? (y/N) " question
+ if [ "$question" = "y" ]; then
+ $(which sudo) python3 $HELPER install-dependencies $HELPER_ARGS -y
+ fi
+}
+
+setup_run_dev()
+{
+ if [ "$SELINUX" -eq "1" ]; then
+ echo "SELinux is enabled, you won't be able to run the daemon from default prefix /usr/local"
+ return
+ fi
+ read -p "Set up dbus activated daemon and PolicyKit actions from /usr/local? (y/N) " question
+ if [ "$question" = "y" ]; then
+ ./contrib/prepare-system /usr/local install
+ fi
+}
+
+setup_unsafe_polkit_rules()
+{
+ read -p "Install developer-friendly **unsafe** PolicyKit rules into /etc/polkit-1/rules.d? (y/N) " question
+ if [ "$question" = "y" ]; then
+ sudo mkdir -p /etc/polkit-1/rules.d
+ sudo cp ./policy/org.freedesktop.fwupd-unsafe.rules /etc/polkit-1/rules.d/
+ fi
+}
+
+setup_vscode()
+{
+ # Add default vscode settings if not existing
+ SETTINGS_FILE=./.vscode/settings.json
+ SETTINGS_TEMPLATE_FILE=./contrib/vscode/settings.json
+ if [ ! -f "$SETTINGS_FILE" ]; then
+ mkdir ./.vscode
+ echo "Copy $SETTINGS_TEMPLATE_FILE to $SETTINGS_FILE."
+ cp "$SETTINGS_TEMPLATE_FILE" "$SETTINGS_FILE"
+ fi
+}
+
+setup_git()
+{
+ echo "Configuring git environment"
+ git config include.path ../.gitconfig
+}
+
+install_pip()
+{
+ package=$1
+ args=$2
+ if ! python3 -m pip install $package $args; then
+ $(which sudo) python3 $HELPER install-pip $HELPER_ARGS -y
+ fi
+ #try once more
+ python3 -m pip install $package
+}
+
+setup_precommit()
+{
+ echo "Configuring pre-commit hooks"
+ python3 -m venv venv
+ source venv/bin/activate
+
+ install_pip pre-commit
+ pre-commit install
+}
+
+setup_prepush()
+{
+ read -p "Run tests locally before pushing to remote branches? THIS WILL SLOW DOWN EVERY PUSH but reduce the risk of failing CI. (y/N) " question
+ if [ "$question" = "y" ]; then
+ pre-commit install -t pre-push
+ else
+ pre-commit uninstall -t pre-push
+ fi
+}
+
+check_markdown()
+{
+ python3 $HELPER test-markdown
+}
+
+check_meson()
+{
+ python3 $HELPER test-meson
+}
+
+detect_os()
+{
+ for i in "$@"; do
+ case $i in
+ --os=*)
+ OS="${i#*=}"
+ shift
+ ;;
+ --debug)
+ DEBUG=1
+ shift
+ ;;
+ *)
+ ;;
+ esac
+ done
+ if [ -z $OS ]; then
+ OS=$(python3 $HELPER detect-profile)
+ if [ -z "$OS" ]; then
+ install_pip distro
+ OS=$(python3 $HELPER detect-profile)
+ fi
+ echo "Using OS profile $OS to setup"
+ fi
+ if [ -n "$OS" ];then
+ HELPER_ARGS="$HELPER_ARGS --os $OS"
+ fi
+ if [ -n "$DEBUG" ]; then
+ set -x
+ HELPER_ARGS="$HELPER_ARGS --debug"
+ fi
+}
+
+#needed for arguments for some commands
+detect_os "$@"
+
+detect_selinux
+
+#if interactive install build deps and prepare environment
+if [ -t 2 ]; then
+ case $OS in
+ debian|ubuntu|arch|fedora)
+ setup_deps
+ setup_run_dev
+ ;;
+ void)
+ setup_deps
+ ;;
+ esac
+ setup_unsafe_polkit_rules
+ rename_branch
+fi
+check_markdown
+setup_vscode
+setup_git
+check_meson
+setup_precommit
+
+#needs to be after pre-commit is sourced
+if [ -t 2 ]; then
+ setup_prepush
+fi
diff --git a/fwupd-1.8.6/contrib/snap/README.md b/fwupd-1.8.6/contrib/snap/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..eb2cd9dc115c9932ef70a6544188174127143a69
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/README.md
@@ -0,0 +1,32 @@
+# 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:
+
+```shell
+# snapcraft cleanbuild
+```
+
+## Installing
+
+A "classic" snap is produced, and locally built snaps can be installed like this:
+
+```shell
+# 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 --git a/fwupd-1.8.6/contrib/snap/activate-shutdown/Makefile b/fwupd-1.8.6/contrib/snap/activate-shutdown/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a219d193d56072988c7826480b7b70904fb1b343
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/activate-shutdown/Makefile
@@ -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 --git a/fwupd-1.8.6/contrib/snap/activate-shutdown/fwupd-activate.service b/fwupd-1.8.6/contrib/snap/activate-shutdown/fwupd-activate.service
new file mode 100644
index 0000000000000000000000000000000000000000..79739bebcd256fea32c8460481eda3ecd3bb3bc9
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/activate-shutdown/fwupd-activate.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Activate fwupd updates
+After=snapd.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+ExecStop=/snap/bin/fwupd.fwupdtool activate
+SuccessExitStatus=0 2
+
+[Install]
+WantedBy=multi-user.target
diff --git a/fwupd-1.8.6/contrib/snap/dbxtool.wrapper b/fwupd-1.8.6/contrib/snap/dbxtool.wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..d29ab99015d68f24b7f185fd72b65779821684d4
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/dbxtool.wrapper
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec "$SNAP/fwupd-command" $SNAP/bin/dbxtool $@
diff --git a/fwupd-1.8.6/contrib/snap/dfu-tool.wrapper b/fwupd-1.8.6/contrib/snap/dfu-tool.wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..0b20a913a9f1b172f8c3e54035671c87e90cae8a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/dfu-tool.wrapper
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec "$SNAP/fwupd-command" $SNAP/bin/dfu-tool $@
diff --git a/fwupd-1.8.6/contrib/snap/fix-bash-completion/Makefile b/fwupd-1.8.6/contrib/snap/fix-bash-completion/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..add3629496c44e9d508110ff5ed43887ddc26469
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fix-bash-completion/Makefile
@@ -0,0 +1,11 @@
+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,; \
+ s,\(command.*\)\(fwupdagent\),\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 --git a/fwupd-1.8.6/contrib/snap/fwup-efi-signed/Makefile b/fwupd-1.8.6/contrib/snap/fwup-efi-signed/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f72ae7d9e07b03838da7046dbf7b5d328e3036c4
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwup-efi-signed/Makefile
@@ -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 --git a/fwupd-1.8.6/contrib/snap/fwup-efi-signed/download-fwupd b/fwupd-1.8.6/contrib/snap/fwup-efi-signed/download-fwupd
new file mode 100755
index 0000000000000000000000000000000000000000..5717ddc975d20c57f04d248505e56a6b7cc1a8c1
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwup-efi-signed/download-fwupd
@@ -0,0 +1,35 @@
+#! /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 --git a/fwupd-1.8.6/contrib/snap/fwupd-command b/fwupd-1.8.6/contrib/snap/fwupd-command
new file mode 100755
index 0000000000000000000000000000000000000000..8afd87a442b5c37ba14812c275de6abe09565943
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwupd-command
@@ -0,0 +1,42 @@
+#!/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" ] && [ -d "$SNAP/etc" ] && cp -R "$SNAP/etc" "$SNAP_USER_DATA"
+[ ! -d "$SNAP_USER_DATA/var" ] && [ -d "$SNAP/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
+ # shellcheck source=/dev/null
+ . $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 --git a/fwupd-1.8.6/contrib/snap/fwupd.wrapper b/fwupd-1.8.6/contrib/snap/fwupd.wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..3ad73086b15175790fe74163a05f713c55a82340
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwupd.wrapper
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec "$SNAP/fwupd-command" $SNAP/libexec/fwupd/fwupd $@
diff --git a/fwupd-1.8.6/contrib/snap/fwupdagent.wrapper b/fwupd-1.8.6/contrib/snap/fwupdagent.wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..303a799d139650a6009c3f5ef376edfac6b60b81
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwupdagent.wrapper
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec "$SNAP/fwupd-command" $SNAP/bin/fwupdagent $@
diff --git a/fwupd-1.8.6/contrib/snap/fwupdmgr.wrapper b/fwupd-1.8.6/contrib/snap/fwupdmgr.wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..a7488263e9323209e2e66a48ad4f02f6c45bba3a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwupdmgr.wrapper
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec "$SNAP/fwupd-command" $SNAP/bin/fwupdmgr $@
diff --git a/fwupd-1.8.6/contrib/snap/fwupdtool.wrapper b/fwupd-1.8.6/contrib/snap/fwupdtool.wrapper
new file mode 100755
index 0000000000000000000000000000000000000000..4006c6aef9b40e4abe0d2d757e2f5172bb594d8b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/fwupdtool.wrapper
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec "$SNAP/fwupd-command" $SNAP/bin/fwupdtool $@
diff --git a/fwupd-1.8.6/contrib/snap/libefivar-fixpkgconfig/Makefile b/fwupd-1.8.6/contrib/snap/libefivar-fixpkgconfig/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..614459e4e0f09da388dda8c2dbbd2498a12c6950
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/libefivar-fixpkgconfig/Makefile
@@ -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 --git a/fwupd-1.8.6/contrib/snap/update-mime/Makefile b/fwupd-1.8.6/contrib/snap/update-mime/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1b07f726d57b06b6812bd6327875ca7495f4668d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/snap/update-mime/Makefile
@@ -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 --git a/fwupd-1.8.6/contrib/standalone-installer/README.md b/fwupd-1.8.6/contrib/standalone-installer/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..04a6eb9ccd4cc68c684b5006a169fdb48b38cf49
--- /dev/null
+++ b/fwupd-1.8.6/contrib/standalone-installer/README.md
@@ -0,0 +1,10 @@
+# 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:
+
+```shell
+./make.py --help
+```
diff --git a/fwupd-1.8.6/contrib/standalone-installer/assets/header.py b/fwupd-1.8.6/contrib/standalone-installer/assets/header.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f18ccd5768eff2246fb9f394f99aec1f275dd9b
--- /dev/null
+++ b/fwupd-1.8.6/contrib/standalone-installer/assets/header.py
@@ -0,0 +1,369 @@
+#!/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(
+ "Using existing fwupd version %s already installed on system."
+ % version.version
+ )
+ 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 True:
+ res = input("Remove now (Y/N)? ")
+ if res.lower() == "n":
+ res = False
+ break
+ if res.lower() == "y":
+ res = True
+ break
+ if res:
+ pkg.mark_delete()
+ res = cache.commit()
+ if not res:
+ raise Exception("Need to remove packaged version")
+ return True
+
+
+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 not 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:
+ 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 --git a/fwupd-1.8.6/contrib/standalone-installer/make.py b/fwupd-1.8.6/contrib/standalone-installer/make.py
new file mode 100755
index 0000000000000000000000000000000000000000..93a01c9806a12d19506c43cbe1b479bd9d8332c7
--- /dev/null
+++ b/fwupd-1.8.6/contrib/standalone-installer/make.py
@@ -0,0 +1,173 @@
+#!/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 --git a/fwupd-1.8.6/contrib/vscode/README.md b/fwupd-1.8.6/contrib/vscode/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ce3cee7c177ee1efce5d522cc304d68153d96e91
--- /dev/null
+++ b/fwupd-1.8.6/contrib/vscode/README.md
@@ -0,0 +1,46 @@
+# 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:
+
+```shell
+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 --git a/fwupd-1.8.6/contrib/vscode/build.sh b/fwupd-1.8.6/contrib/vscode/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..de332ba7d256acc5350b725e15ce6fdf8751351d
--- /dev/null
+++ b/fwupd-1.8.6/contrib/vscode/build.sh
@@ -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
+sudo rm -rf build ${ROOT}/dist
+meson build --prefix=${ROOT}/dist -Dsystemd=disabled -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#,bin/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 --git a/fwupd-1.8.6/contrib/vscode/launch.json b/fwupd-1.8.6/contrib/vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..ebb75559660ee5321c32336b9bec81a9558c253a
--- /dev/null
+++ b/fwupd-1.8.6/contrib/vscode/launch.json
@@ -0,0 +1,65 @@
+{
+ "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 --git a/fwupd-1.8.6/contrib/vscode/launcher.sh b/fwupd-1.8.6/contrib/vscode/launcher.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8cea6bdce52993969a7882858509dc427cac7924
--- /dev/null
+++ b/fwupd-1.8.6/contrib/vscode/launcher.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+gcc=$(gcc -dumpmachine)
+export ROOT=#ROOT#
+export FWUPD_LOCALSTATEDIR=${ROOT}/dist
+export FWUPD_SYSCONFDIR=${ROOT}/dist/etc
+export LD_LIBRARY_PATH=${ROOT}/dist/lib/${gcc}
+if [ -n "${DEBUG}" ]; then
+ DEBUG="gdbserver localhost:9091"
+fi
+${DEBUG} ${ROOT}/dist/#EXECUTABLE# "$@"
diff --git a/fwupd-1.8.6/contrib/vscode/settings.json b/fwupd-1.8.6/contrib/vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..2d79621558a9d8d8d938fae42861ff9f9201863f
--- /dev/null
+++ b/fwupd-1.8.6/contrib/vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "editor.tabSize": 8,
+ "mesonbuild.buildFolder": "build"
+}
diff --git a/fwupd-1.8.6/data/90-fwupd-devices.rules b/fwupd-1.8.6/data/90-fwupd-devices.rules
new file mode 100644
index 0000000000000000000000000000000000000000..2bc9efc49771d19455e559a931c93ebd43f0be0a
--- /dev/null
+++ b/fwupd-1.8.6/data/90-fwupd-devices.rules
@@ -0,0 +1,8 @@
+########################################################################
+# Copyright (C) 2015 Richard Hughes
+#
+# SPDX-License-Identifier: LGPL-2.1+
+#
+
+# NVMe hardware
+SUBSYSTEM=="nvme", ENV{ID_VENDOR_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=pci"
diff --git a/fwupd-1.8.6/data/bash-completion/fwupdagent b/fwupd-1.8.6/data/bash-completion/fwupdagent
new file mode 100644
index 0000000000000000000000000000000000000000..448d94b08e5e6238626687b903b877eddce9975e
--- /dev/null
+++ b/fwupd-1.8.6/data/bash-completion/fwupdagent
@@ -0,0 +1,40 @@
+_fwupdagent_cmd_list=(
+ 'get-devices'
+ 'get-updates'
+ 'get-upgrades'
+ 'security'
+)
+
+_fwupdagent_opts=(
+ '--verbose'
+)
+
+_show_modifiers()
+{
+ COMPREPLY+=( $(compgen -W '${_fwupdagent_opts[@]}' -- "$cur") )
+}
+
+_fwupdagent()
+{
+ local cur prev command arg args
+ COMPREPLY=()
+ _get_comp_words_by_ref cur prev
+ _get_first_arg
+ _count_args
+
+ case $arg in
+ *)
+ #find first command
+ if [[ "$args" = "1" ]]; then
+ COMPREPLY=( $(compgen -W '${_fwupdagent_cmd_list[@]}' -- "$cur") )
+ fi
+ ;;
+ esac
+
+ #modifiers
+ _show_modifiers
+
+ return 0
+}
+
+complete -F _fwupdagent fwupdagent
diff --git a/fwupd-1.8.6/data/bash-completion/fwupdmgr b/fwupd-1.8.6/data/bash-completion/fwupdmgr
new file mode 100644
index 0000000000000000000000000000000000000000..95646cf3787662cd02b4623cc1ea7f54ed81ab31
--- /dev/null
+++ b/fwupd-1.8.6/data/bash-completion/fwupdmgr
@@ -0,0 +1,280 @@
+_fwupdmgr_cmd_list=(
+ 'activate'
+ 'block-firmware'
+ 'clear-results'
+ 'disable-remote'
+ 'device-test'
+ 'downgrade'
+ 'download'
+ 'enable-remote'
+ 'get-approved-firmware'
+ 'get-bios-setting'
+ 'get-blocked-firmware'
+ 'get-details'
+ 'get-devices'
+ 'get-history'
+ 'get-releases'
+ 'get-remotes'
+ 'get-results'
+ 'get-topology'
+ 'get-updates'
+ 'get-upgrades'
+ 'get-plugins'
+ 'install'
+ 'local-install'
+ 'modify-config'
+ 'modify-remote'
+ 'reinstall'
+ 'refresh'
+ 'report-history'
+ 'security'
+ 'set-approved-firmware'
+ 'set-bios-setting'
+ 'switch-branch'
+ 'sync-bkc'
+ 'unlock'
+ 'unblock-firmware'
+ 'update'
+ 'upgrade'
+ 'verify'
+ 'verify-update'
+ '--version'
+)
+
+_fwupdmgr_opts=(
+ '--verbose'
+ '--offline'
+ '--allow-reinstall'
+ '--allow-older'
+ '--allow-branch-switch'
+ '--force'
+ '--assume-yes'
+ '--no-history'
+ '--no-unreported-check'
+ '--no-metadata-check'
+ '--no-reboot-check'
+ '--no-safety-check'
+ '--no-remote-check'
+ '--show-all'
+ '--sign'
+ '--filter'
+ '--disable-ssl-strict'
+ '--ipfs'
+ '--json'
+)
+
+bios_get_opts=(
+ '--no-authenticate'
+ '--json'
+ '--verbose'
+)
+
+bios_set_opts=(
+ '--no-reboot-check'
+ '--json'
+ '--verbose'
+)
+
+_show_file_in_dir()
+{
+ local files
+ files="$(ls 2>/dev/null)"
+ COMPREPLY+=( $(compgen -W "${files}" -- "$cur") )
+}
+
+_show_bios_get_modifiers()
+{
+ COMPREPLY+=( $(compgen -W '${bios_get_opts[@]}' -- "$cur") )
+}
+
+_show_bios_set_modifiers()
+{
+ COMPREPLY+=( $(compgen -W '${bios_set_opts[@]}' -- "$cur") )
+}
+
+_show_filters()
+{
+ local flags
+ flags="$(command fwupdtool get-device-flags 2>/dev/null)"
+ COMPREPLY+=( $(compgen -W "${flags}" -- "$cur") )
+}
+
+_show_modifiers()
+{
+ COMPREPLY+=( $(compgen -W '${_fwupdmgr_opts[@]}' -- "$cur") )
+}
+
+_show_bios_settings()
+{
+ if ! command -v jq &> /dev/null; then
+ return 0
+ fi
+ local attr
+ attr="$(command fwupdmgr get-bios-setting --json --no-authenticate 2>/dev/null | jq '.BiosSettings | .[] | .Name')"
+ COMPREPLY+=( $(compgen -W "${attr}" -- "$cur") )
+}
+
+_show_bios_settings_possible()
+{
+ if ! command -v jq &> /dev/null; then
+ return 0
+ fi
+ local attr
+ attr="$(command fwupdmgr get-bios-setting "$1" --json --no-authenticate 2>/dev/null | jq '.BiosSettings | .[] | .BiosSettingPossibleValues | .[]')"
+ COMPREPLY+=( $(compgen -W "${attr}" -- "$cur") )
+}
+
+_show_device_ids()
+{
+ if ! command -v jq &> /dev/null; then
+ return 0
+ fi
+ local description
+ description="$(command fwupdmgr get-devices --json 2>/dev/null | jq '.Devices | .[] | .DeviceId')"
+ COMPREPLY+=( $(compgen -W "${description}" -- "$cur") )
+}
+
+_show_release_versions()
+{
+ if ! command -v jq &> /dev/null; then
+ return 0
+ fi
+ local description
+ description="$(command fwupdmgr get-releases "$1" --json 2>/dev/null | jq '.Releases[].Version')"
+ COMPREPLY+=( $(compgen -W "${description}" -- "$cur") )
+}
+
+_show_remotes()
+{
+ local remotes
+ remotes="$(command fwupdmgr get-remotes | command awk '/Remote ID/ { print $4 }')"
+ COMPREPLY+=( $(compgen -W "${remotes}" -- "$cur") )
+}
+
+_fwupdmgr()
+{
+ local cur prev command arg args
+ COMPREPLY=()
+ _get_comp_words_by_ref cur prev
+ _get_first_arg
+ _count_args
+
+ case $prev in
+ --filter)
+ _show_filters
+ return 0
+ ;;
+ esac
+
+ case $arg in
+ activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates|switch-branch|update|upgrade)
+ #device ID
+ if [[ "$args" = "2" ]]; then
+ _show_device_ids
+ fi
+ ;;
+ get-bios-settings|get-bios-setting)
+ #bios settings (no limit)
+ _show_bios_settings
+ _show_bios_get_modifiers
+ return 0
+ ;;
+ set-bios-setting)
+ if [[ "$prev" = "--json" ]]; then
+ _show_file_in_dir "$prev"
+ return 0
+ fi
+ count=$(($((args)) % 2))
+ #allow setting a single bios setting at a time
+ if [[ $count == 0 ]]; then
+ _show_bios_settings
+ fi
+ #possible values (only works for enumeration though)
+ if [[ $count == 1 ]]; then
+ _show_bios_settings_possible "$prev"
+ return 0
+ fi
+ _show_bios_set_modifiers
+ return 0
+ ;;
+ get-details)
+ #find files
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ fi
+ ;;
+ device-test)
+ #find files
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ fi
+ ;;
+ install)
+ #device ID
+ if [[ "$args" = "2" ]]; then
+ _show_device_ids
+ #version
+ elif [[ "$args" = "3" ]]; then
+ _show_release_versions "$prev"
+ fi
+ ;;
+ local-install)
+ #find files
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ #device ID or modifiers
+ elif [[ "$args" = "3" ]]; then
+ _show_device_ids
+ _show_modifiers
+ fi
+ ;;
+ modify-remote)
+ #find remotes
+ if [[ "$args" = "2" ]]; then
+ _show_remotes
+ #add key
+ elif [[ "$args" = "3" ]]; then
+ 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") )
+ fi
+ ;;
+ enable-remote)
+ #find remotes
+ if [[ "$args" = "2" ]]; then
+ _show_remotes
+ fi
+ ;;
+ disable-remote)
+ #find remotes
+ if [[ "$args" = "2" ]]; then
+ _show_remotes
+ fi
+ ;;
+ refresh)
+ #find first file
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ #find second file
+ elif [[ "$args" = "3" ]]; then
+ _filedir
+ #find remote ID
+ elif [[ "$args" = "4" ]]; then
+ _show_remotes
+ fi
+ ;;
+ *)
+ #find first command
+ if [[ "$args" = "1" ]]; then
+ COMPREPLY=( $(compgen -W '${_fwupdmgr_cmd_list[@]}' -- "$cur") )
+ fi
+ ;;
+ esac
+
+ #modifiers
+ _show_modifiers
+
+ return 0
+}
+
+complete -F _fwupdmgr fwupdmgr
diff --git a/fwupd-1.8.6/data/bash-completion/fwupdtool b/fwupd-1.8.6/data/bash-completion/fwupdtool
new file mode 100644
index 0000000000000000000000000000000000000000..071d7384c2d1bb6d9247547569b170059e6ccc43
--- /dev/null
+++ b/fwupd-1.8.6/data/bash-completion/fwupdtool
@@ -0,0 +1,180 @@
+_fwupdtool_cmd_list=(
+ 'activate'
+ 'build-firmware'
+ 'clear-history'
+ 'esp-list'
+ 'esp-mount'
+ 'esp-unmount'
+ 'firmware-build'
+ 'firmware-convert'
+ 'firmware-export'
+ 'firmware-extract'
+ 'firmware-parse'
+ 'firmware-sign'
+ 'firmware-patch'
+ 'get-bios-setting'
+ 'get-updates'
+ 'get-upgrades'
+ 'get-details'
+ 'get-firmware-types'
+ 'get-device-flags'
+ 'get-devices'
+ 'get-history'
+ 'get-plugins'
+ 'get-remotes'
+ 'get-topology'
+ 'hwids'
+ 'update'
+ 'upgrade'
+ 'install'
+ 'install-blob'
+ 'monitor'
+ 'reinstall'
+ 'security'
+ 'set-bios-setting'
+ 'switch-branch'
+ 'self-sign'
+ 'smbios-dump'
+ 'attach'
+ 'detach'
+ 'firmware-dump'
+ 'firmware-read'
+ 'refresh'
+ 'verify-update'
+ 'watch'
+ 'unbind-driver'
+ 'bind-driver'
+ 'export-hwids'
+)
+
+_fwupdtool_opts=(
+ '--verbose'
+ '--allow-reinstall'
+ '--allow-older'
+ '--force'
+ '--show-all'
+ '--plugins'
+ '--prepare'
+ '--cleanup'
+ '--filter'
+ '--method'
+ '--disable-ssl-strict'
+ '--no-safety-check'
+ '--ignore-checksum'
+ '--ignore-vid-pid'
+ '--save-backends'
+)
+
+_show_filters()
+{
+ local flags
+ flags="$(command fwupdtool get-device-flags 2>/dev/null)"
+ COMPREPLY+=( $(compgen -W "${flags}" -- "$cur") )
+}
+
+_show_firmware_types()
+{
+ local firmware_types
+ firmware_types="$(command fwupdtool get-firmware-types 2>/dev/null)"
+ COMPREPLY+=( $(compgen -W "${firmware_types}" -- "$cur") )
+}
+
+_show_device_ids()
+{
+ if ! command -v jq &> /dev/null; then
+ return 0
+ fi
+ local description
+ description="$(command jq '.Devices | .[] | .DeviceId' @localstatedir@/cache/fwupd/devices.json 2>/dev/null)"
+ COMPREPLY+=( $(compgen -W "${description}" -- "$cur") )
+}
+
+_show_plugins()
+{
+ if ! command -v jq &> /dev/null; then
+ return 0
+ fi
+ local plugins
+ plugins="$(command fwupdtool get-plugins --json 2>/dev/null | jq '.Plugins | .[] | .Name')"
+ COMPREPLY+=( $(compgen -W "${plugins}" -- "$cur") )
+}
+
+_show_modifiers()
+{
+ COMPREPLY+=( $(compgen -W '${_fwupdtool_opts[@]}' -- "$cur") )
+}
+
+_fwupdtool()
+{
+ local cur prev command arg args
+ COMPREPLY=()
+ _get_comp_words_by_ref cur prev
+ _get_first_arg
+ _count_args
+
+ case $prev in
+ --plugins)
+ _show_plugins
+ return 0
+ ;;
+ --filter)
+ _show_filters
+ return 0
+ ;;
+ esac
+
+ case $arg in
+ get-details|install|install-blob|firmware-dump|firmware-read)
+ #find files
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ #device ID
+ elif [[ "$args" = "3" ]]; then
+ _show_device_ids
+ fi
+ ;;
+ attach|detach|activate|verify-update|reinstall|get-updates)
+ #device ID
+ if [[ "$args" = "2" ]]; then
+ _show_device_ids
+ fi
+ ;;
+ firmware-parse|firmware-patch)
+ #find files
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ #firmware_type
+ elif [[ "$args" = "3" ]]; then
+ _show_firmware_types
+ fi
+ ;;
+ firmware-convert)
+ #file in
+ if [[ "$args" = "2" ]]; then
+ _filedir
+ #file out
+ elif [[ "$args" = "3" ]]; then
+ _filedir
+ #firmware_type in
+ elif [[ "$args" = "4" ]]; then
+ _show_firmware_types
+ #firmware_type out
+ elif [[ "$args" = "5" ]]; then
+ _show_firmware_types
+ fi
+ ;;
+ *)
+ #find first command
+ if [[ "$args" = "1" ]]; then
+ COMPREPLY=( $(compgen -W '${_fwupdtool_cmd_list[@]}' -- "$cur") )
+ fi
+ ;;
+ esac
+
+ #modifiers
+ _show_modifiers
+
+ return 0
+}
+
+complete -F _fwupdtool fwupdtool
diff --git a/fwupd-1.8.6/data/bash-completion/meson.build b/fwupd-1.8.6/data/bash-completion/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..815b7bf70b6b47a0dbc80e9c0c20aebc4f8c2d11
--- /dev/null
+++ b/fwupd-1.8.6/data/bash-completion/meson.build
@@ -0,0 +1,23 @@
+if bashcomp.found()
+ completions_dir = bashcomp.get_variable(pkgconfig: 'completionsdir',
+ pkgconfig_define: bashcomp.version().version_compare('>= 2.10') ? ['datadir', datadir] : ['prefix', prefix],
+ )
+
+ con = configuration_data()
+ con.set('localstatedir', localstatedir)
+
+ configure_file(
+ input: 'fwupdtool',
+ output: 'fwupdtool',
+ configuration: con,
+ install: true,
+ install_dir: completions_dir,
+ )
+
+ if build_daemon
+ install_data(['fwupdagent', 'fwupdmgr'],
+ install_dir: completions_dir,
+ )
+ endif # build_daemon
+
+endif # bashcomp.found()
diff --git a/fwupd-1.8.6/data/bios-settings.d/README.md b/fwupd-1.8.6/data/bios-settings.d/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0d9fba88a79f8e833a1d4a2d2207463f432e0802
--- /dev/null
+++ b/fwupd-1.8.6/data/bios-settings.d/README.md
@@ -0,0 +1,25 @@
+# BIOS Settings
+
+On supported machines fwupd can enforce BIOS settings policy so that a user's desired settings are configured at bootup
+and prevent fwupd clients from changing them.
+
+## JSON policies
+
+A policy file can be created using `fwupdmgr`. First determine what settings you want to enforce by running:
+
+```shell
+# fwupdmgr get-bios-settings
+```
+
+After you have identified settings, create a JSON payload by listing them on the command line. Any number of attributes can
+be listed.
+For example for the BIOS setting `WindowsUEFIFirmwareUpdate` you would create a policy file like this:
+
+```shell
+# fwupdmgr get-bios-settings --json WindowsUEFIFirmwareUpdate > ~/foo.json
+```
+
+Now examine `~/foo.json` and modify the `BiosSettingCurrentValue` key to your desired value.
+
+Lastly place this policy file into `/etc/fwupd/bios-settings.d`. Any number of policies is supported, and they will be examined
+in alphabetical order. The next time that fwupd is started it will load this policy and ensure that no fwupd clients change it.
diff --git a/fwupd-1.8.6/data/bios-settings.d/meson.build b/fwupd-1.8.6/data/bios-settings.d/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..b0ff5b10689ccbc39d0f357397d6a051c02bc6c6
--- /dev/null
+++ b/fwupd-1.8.6/data/bios-settings.d/meson.build
@@ -0,0 +1,5 @@
+if build_standalone and host_machine.system() == 'linux'
+install_data('README.md',
+ install_dir: join_paths(sysconfdir, 'fwupd', 'bios-settings.d')
+)
+endif
diff --git a/fwupd-1.8.6/data/cfi.quirk b/fwupd-1.8.6/data/cfi.quirk
new file mode 100644
index 0000000000000000000000000000000000000000..8a397981ed16a31d197bb42bfaee939dbb9744a7
--- /dev/null
+++ b/fwupd-1.8.6/data/cfi.quirk
@@ -0,0 +1,194 @@
+# No Manufacturer
+[CFI\FLASHID_0020]
+Name = M25PxxA/xx
+CfiDeviceCmdChipErase = 0xC7
+CfiDeviceCmdSectorErase = 0x00
+[CFI\FLASHID_00BF]
+Name = PCT/SST25VFxxx/xxxA
+CfiDeviceCmdReadId = 0x90
+CfiDeviceCmdChipErase = 0x60
+CfiDeviceCmdSectorErase = 0x20
+[CFI\FLASHID_009D]
+Name = PM25LDxxx
+CfiDeviceCmdReadId = 0x90
+CfiDeviceCmdChipErase = 0xC7
+CfiDeviceCmdSectorErase = 0xD7
+[CFI\FLASHID_009D]
+Name = PM25LVxxx
+CfiDeviceCmdReadId = 0xAB
+CfiDeviceCmdChipErase = 0xC7
+CfiDeviceCmdSectorErase = 0xD7
+[CFI\FLASHID_00EF]
+Name = W25XxxBV/W25XxxCL
+CfiDeviceCmdChipErase = 0xC7
+CfiDeviceCmdSectorErase = 0x20
+
+# Fujitsu
+[CFI\FLASHID_04]
+Vendor = Fujitsu
+
+# Atmel
+[CFI\FLASHID_1F]
+Vendor = Atmel
+[CFI\FLASHID_1F65]
+Name = AT25F512A/B
+CfiDeviceCmdReadId = 0x15
+CfiDeviceCmdChipErase = 0x62
+CfiDeviceCmdSectorErase = 0x00
+FirmwareSizeMax = 0x10000
+
+# EON
+[CFI\FLASHID_1C]
+Vendor = EON
+[CFI\FLASHID_1C31]
+Name = EN25Fxx
+CfiDeviceCmdChipErase = 0x60
+CfiDeviceCmdSectorErase = 0x20
+
+# ST
+[CFI\FLASHID_20]
+Vendor = ST
+
+# Catalyst
+[CFI\FLASHID_31]
+Vendor = Catalyst
+
+# AMIC
+[CFI\FLASHID_37]
+Vendor = AMIC
+[CFI\FLASHID_3730]
+Name = A25Lxxx
+CfiDeviceCmdChipErase = 0xc7
+CfiDeviceCmdSectorErase = 0x20
+
+# SyncMOS
+[CFI\FLASHID_40]
+Vendor = SyncMOS
+
+# ESI
+[CFI\FLASHID_4A]
+Vendor = ESI
+
+# Alliance
+[CFI\FLASHID_52]
+Vendor = Alliance
+
+# Tenx
+[CFI\FLASHID_5E]
+Vendor = Tenx
+
+# Sanyo
+[CFI\FLASHID_62]
+Vendor = Sanyo
+
+# AMIC
+[CFI\FLASHID_7F]
+Vendor = AMIC
+[CFI\FLASHID_7F9D21]
+Name = A49LF040A
+FirmwareSizeMax = 0x20000
+
+[CFI\FLASHID_89]
+Vendor = Intel
+
+# Elite
+[CFI\FLASHID_8C]
+Vendor = Elite
+
+# Texas Instruments
+[CFI\FLASHID_97]
+Vendor = Texas Instruments
+
+# PMC
+[CFI\FLASHID_9D]
+Vendor = PMC
+
+# Fudan
+[CFI\FLASHID_A1]
+Vendor = Fudan
+[CFI\FLASHID_A131]
+Name = FM25xxx
+CfiDeviceBlockSize = 0x10000
+CfiDeviceSectorSize = 0x1000
+CfiDevicePageSize = 0x100
+CfiDeviceCmdBlockErase = 0xd8
+[CFI\FLASHID_A13110]
+Name = FM25W04
+FirmwareSizeMax = 0x80000
+[CFI\FLASHID_A13111]
+Name = FM25F01
+FirmwareSizeMax = 0x20000
+
+# Hyundai
+[CFI\FLASHID_AD]
+Vendor = Hyundai
+
+# Sharp
+[CFI\FLASHID_B0]
+Vendor = Sharp
+
+# SST
+[CFI\FLASHID_BF]
+Vendor = SST
+
+# Macronix
+[CFI\FLASHID_C2]
+Vendor = Macronix
+[CFI\FLASHID_C220]
+Name = MX25Lxxx/xxxC/xxxE
+CfiDeviceCmdChipErase = 0x60
+CfiDeviceCmdSectorErase = 0x20
+CfiDeviceCmdBlockErase = 0xd8
+CfiDeviceBlockSize = 0x10000
+CfiDeviceSectorSize = 0x1000
+CfiDevicePageSize = 0x100
+[CFI\FLASHID_C22012]
+Name = MX25V2033F
+FirmwareSizeMax = 0x40000
+[CFI\FLASHID_C22016]
+Name = MX25L3236F
+FirmwareSizeMax = 0x400000
+[CFI\FLASHID_C222]
+Name = MX25Lxxx1E
+CfiDeviceCmdChipErase = 0x60
+CfiDeviceCmdSectorErase = 0x20
+
+# GigaDevice
+[CFI\FLASHID_C8]
+Vendor = GigaDevice
+[CFI\FLASHID_C840]
+Name = GD25Qxxx
+CfiDeviceCmdChipErase = 0xC7
+CfiDeviceCmdSectorErase = 0x20
+CfiDeviceCmdBlockErase = 0xd8
+CfiDeviceBlockSize = 0x10000
+CfiDeviceSectorSize = 0x1000
+CfiDevicePageSize = 0x100
+[CFI\FLASHID_C84012]
+Name = GD25Q20C
+FirmwareSizeMax = 0x40000
+[CFI\FLASHID_C84016]
+Name = GD25Q32C
+FirmwareSizeMax = 0x400000
+
+# Nantronics
+[CFI\FLASHID_D5]
+Vendor = Nantronics
+
+# Winbond
+[CFI\FLASHID_DA]
+Vendor = Winbond
+
+# Winbond (ex Nexcom)
+[CFI\FLASHID_EF]
+Vendor = Winbond
+[CFI\FLASHID_EF3010]
+Name = W25X05CL
+FirmwareSizeMax = 0x10000
+[CFI\FLASHID_EF4018]
+Name = W25Q128
+FirmwareSizeMax = 0x1000000
+
+# Fidelix
+[CFI\FLASHID_F8]
+Vendor = Fidelix
diff --git a/fwupd-1.8.6/data/daemon.conf b/fwupd-1.8.6/data/daemon.conf
new file mode 100644
index 0000000000000000000000000000000000000000..5066ce1c26c0bb405f8b0f87e1c82f6cf99a8b53
--- /dev/null
+++ b/fwupd-1.8.6/data/daemon.conf
@@ -0,0 +1,74 @@
+[fwupd]
+
+# Allow blocking specific devices by their GUID
+# Uses semicolons as delimiter
+DisabledDevices=
+
+# Allow blocking specific plugins
+# Uses semicolons as delimiter
+DisabledPlugins=test;test_ble
+
+# 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=
+
+# Update the message of the day (MOTD) on device and metadata changes
+UpdateMotd=true
+
+# For some plugins, enumerate only devices supported by metadata
+EnumerateAllDevices=false
+
+# A list of firmware checksums that has been approved by the site admin
+# If unset, all firmware is approved
+ApprovedFirmware=
+
+# Allow blocking specific devices by their checksum, either SHA1 or SHA256
+# Uses semicolons as delimiter
+BlockedFirmware=
+
+# Allowed URI schemes in the preference order; failed downloads from the first
+# scheme will be retried with the next in order until no choices remain.
+#
+# If unset or no schemes are listed, the default will be: file,https,http,ipfs
+UriSchemes=
+
+# Ignore power levels of devices when running updates
+IgnorePower=false
+
+# Only support installing firmware signed with a trusted key
+OnlyTrusted=true
+
+# Show private data like device serial numbers and instance IDs to clients
+ShowDevicePrivate=true
+
+# UIDs that should marked as trusted
+TrustedUids=
+
+# A host best known configuration is used when using `fwupdmgr sync` which can
+# downgrade firmware to factory versions or upgrade firmware to a supported
+# config level. e.g. `vendor-factory-2021q1`
+HostBkc=
+
+# The EFI system partition (ESP) path used if UDisks is not available
+# or if this partition is not mounted at /boot/efi, /boot, or /efi
+#EspLocation=
+
+# these are only required when the SMBIOS or Device Tree data is invalid or missing
+#Manufacturer=
+#ProductName=
+#ProductSku=
+#Family=
+#EnclosureKind=
+#BaseboardProduct=
+#BaseboardManufacturer=
diff --git a/fwupd-1.8.6/data/device-tests/8bitdo-nes30pro.json b/fwupd-1.8.6/data/device-tests/8bitdo-nes30pro.json
new file mode 100644
index 0000000000000000000000000000000000000000..fe198100f2933139248fae687b0e29e78786f388
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/8bitdo-nes30pro.json
@@ -0,0 +1,17 @@
+{
+ "name": "8BitDo NES30Pro",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/1cb9a0277f536ecd81ca1cea6fd80d60cdbbdcd8-8Bitdo-SFC30PRO_NES30PRO-4.01.cab",
+ "components": [
+ {
+ "version": "4.01",
+ "guids": [
+ "c6566b1b-0c6e-5d2e-9376-78c23ab57bf2"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/8bitdo-sf30pro.json b/fwupd-1.8.6/data/device-tests/8bitdo-sf30pro.json
new file mode 100644
index 0000000000000000000000000000000000000000..3969d55a4ada855422c778ebd4d2ad24f5c9be84
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/8bitdo-sf30pro.json
@@ -0,0 +1,17 @@
+{
+ "name": "8BitDo SF30Pro",
+ "interactive": true,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/3d3a65ee2e8581647fb09d752fa7e21ee1566481-8Bitdo-SF30_Pro-SN30_Pro-1.26.cab",
+ "components": [
+ {
+ "version": "1.26",
+ "guids": [
+ "269b3121-097b-50d8-b9ba-d1f64f9cd241"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/8bitdo-sfc30.json b/fwupd-1.8.6/data/device-tests/8bitdo-sfc30.json
new file mode 100644
index 0000000000000000000000000000000000000000..edff91d5cc791f830562907afe0f3195d041ccf6
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/8bitdo-sfc30.json
@@ -0,0 +1,17 @@
+{
+ "name": "8BitDo SFC30",
+ "interactive": true,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/fe066b57c69265f4cce8a999a5f8ab90d1c13b24-8Bitdo-SFC30_NES30_SFC30_SNES30-4.01.cab",
+ "components": [
+ {
+ "version": "4.01",
+ "guids": [
+ "a7fcfbaf-e9e8-59f4-920d-7691dc6c8699"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/aiaiai-h05.json b/fwupd-1.8.6/data/device-tests/aiaiai-h05.json
new file mode 100644
index 0000000000000000000000000000000000000000..a32272b4b8e615e45a3f51a224a036b84bc2aea3
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/aiaiai-h05.json
@@ -0,0 +1,18 @@
+{
+ "name": "AIAIAI H05",
+ "interactive": true,
+ "runtime": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/84279d6bab52262080531acac701523604f3e649-AIAIAI-H05-1.6.cab",
+ "components": [
+ {
+ "version": "1.6",
+ "guids": [
+ "7e8318e1-27ae-55e4-a7a7-a35eff60e9bf"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/bizlink-no-sku-vli.json b/fwupd-1.8.6/data/device-tests/bizlink-no-sku-vli.json
new file mode 100644
index 0000000000000000000000000000000000000000..376926664930b7efa5d5bc9f2bbbe965f0b0d86a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/bizlink-no-sku-vli.json
@@ -0,0 +1,44 @@
+{
+ "name": "BizLink Cayenne Hub [VL822+VL103]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/e0d6f62140663744f114d59b1ec48dd3e4743006bb06d0643efe178b8bdb2a04-BizLink-Cayenne_New.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "106.83",
+ "guids": [
+ "a0eff862-6b0b-5571-91ec-a0c4bb25b539"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "138.2.5.18",
+ "guids": [
+ "a7927038-e2df-5209-88db-2e28bcd3cf8e"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/baf2f1a78334b7722d913ffa468240f728a09d91d0d2f755ff5515d4fed111c1-BizLink-Cayenne_Old.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "06.83",
+ "guids": [
+ "a0eff862-6b0b-5571-91ec-a0c4bb25b539"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "122.2.5.18",
+ "guids": [
+ "a7927038-e2df-5209-88db-2e28bcd3cf8e"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/corsair-katar-pro-xt.json b/fwupd-1.8.6/data/device-tests/corsair-katar-pro-xt.json
new file mode 100644
index 0000000000000000000000000000000000000000..52a334f490ca4d070df52226b96ff5676e1bc097
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/corsair-katar-pro-xt.json
@@ -0,0 +1,30 @@
+{
+ "name": "Corsair KATAR PRO XT Gaming Mouse",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/3bfde46a20bffd123ea4efd8eb7b59fb50d473ec9176735538e139a4e6b6e12c-corsair-bora-1.6.25.cab",
+ "components": [
+ {
+ "version": "1.6.25",
+ "protocol": "com.corsair.bp",
+ "guids": [
+ "b7b0728e-94e9-5ad5-999f-c6a359a9ddd4"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/7598356dbb3c40f16bc4cd314497ad0b983303e52311f95afc1d9aa8661a154d-corsair-bora-1.6.26.cab",
+ "components": [
+ {
+ "version": "1.6.26",
+ "protocol": "com.corsair.bp",
+ "guids": [
+ "b7b0728e-94e9-5ad5-999f-c6a359a9ddd4"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/corsair-sabre-pro.json b/fwupd-1.8.6/data/device-tests/corsair-sabre-pro.json
new file mode 100644
index 0000000000000000000000000000000000000000..67325e3995f298b51199052c78b6b4b9981d0106
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/corsair-sabre-pro.json
@@ -0,0 +1,30 @@
+{
+ "name": "Corsair SABRE PRO Gaming Mouse",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/c5d729ea474b0c380641a5a86f05796dad6e74888b3eb207237f18fab9da8157-corsair-tongs-1.15.24.cab",
+ "components": [
+ {
+ "version": "1.15.24",
+ "protocol": "com.corsair.bp",
+ "guids": [
+ "9896f0c3-6682-5392-80f6-0ba462918645"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/5adc54e39596b5b941339d247ac01f6a40377bc58e6b1b87c49d60c8a7509f4e-corsair-tongs-1.15.25.cab",
+ "components": [
+ {
+ "version": "1.15.25",
+ "protocol": "com.corsair.bp",
+ "guids": [
+ "9896f0c3-6682-5392-80f6-0ba462918645"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/corsair-sabre-rgb-pro.json b/fwupd-1.8.6/data/device-tests/corsair-sabre-rgb-pro.json
new file mode 100644
index 0000000000000000000000000000000000000000..1a69c160d9968c71d0f9e5052284057173f58a4b
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/corsair-sabre-rgb-pro.json
@@ -0,0 +1,30 @@
+{
+ "name": "Corsair SABRE RGB PRO Gaming Mouse",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/6a765b6f9cdd2ac91c43b0d6e6e0d256e1c575dae6da2e287d603a1d8e9c5b49-corsair-vise-1.15.29.cab",
+ "components": [
+ {
+ "version": "1.15.29",
+ "protocol": "com.corsair.bp",
+ "guids": [
+ "7eb05392-a5e0-529a-991b-1910a4bce8cf"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/ad9aef845359ba6c8425329df68ff92e299588af334be2bc867e3b6e690c4279-corsair-vise-1.15.30.cab",
+ "components": [
+ {
+ "version": "1.15.30",
+ "protocol": "com.corsair.bp",
+ "guids": [
+ "7eb05392-a5e0-529a-991b-1910a4bce8cf"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/dell-kh08p.json b/fwupd-1.8.6/data/device-tests/dell-kh08p.json
new file mode 100644
index 0000000000000000000000000000000000000000..310a9f5bc8f35665a795bcc08ba9782429dfb64a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/dell-kh08p.json
@@ -0,0 +1,28 @@
+{
+ "name": "Dell KH08P [BCM5719]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/6cf165037a381eb29c183319e031def6b87e3ce955781ecf73f28751a1365db2-kh08p-bcm5719-0.4.62.cab",
+ "components": [
+ {
+ "version": "0.4.62",
+ "guids": [
+ "ec5b8a9e-973b-58cc-935b-8322fabaebe9"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/c786be1c525ad062c5af8983474a9412f83f5251efb767fe9cb414a3a124b8ce-kh08p-bcm5719-0.4.64.cab",
+ "components": [
+ {
+ "version": "0.4.64",
+ "guids": [
+ "ec5b8a9e-973b-58cc-935b-8322fabaebe9"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/dell-wd19tb.json b/fwupd-1.8.6/data/device-tests/dell-wd19tb.json
new file mode 100644
index 0000000000000000000000000000000000000000..1f5db67ac7bb3a30899ae508ae591df56ff7561a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/dell-wd19tb.json
@@ -0,0 +1,53 @@
+{
+ "name": "Dell WD19TB Dock",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/c05bacfd8f73f30812559f14245b92a069c680caf300e961c78e00c985efe3e0-WD19FirmwareUpdateLinux_01.00.14.cab",
+ "components": [
+ {
+ "name": "ec",
+ "version": "01.00.00.04",
+ "guids": [
+ "cd357cf1-40b2-5d87-b8df-bb2dd82774aa"
+ ]
+ },
+ {
+ "name": "mst",
+ "version": "05.04.03",
+ "guids": [
+ "89fec0b6-6b76-5008-b82c-5e5c6c164007"
+ ]
+ },
+ {
+ "name": "pkg",
+ "version": "01.00.14.01",
+ "guids": [
+ "8ceeeffd-51b6-580c-9b75-69143227aff8"
+ ]
+ },
+ {
+ "name": "tbt",
+ "version": "43.00",
+ "guids": [
+ "c94770ca-1773-592c-b20a-e87243bc7cd0"
+ ]
+ },
+ {
+ "name": "usb1",
+ "version": "01.21",
+ "guids": [
+ "ac5b774c-b49d-566b-9255-85f0f7f8a4ed"
+ ]
+ },
+ {
+ "name": "usb2",
+ "version": "01.47",
+ "guids": [
+ "568ffa1e-a0db-5287-9ea3-872b60f7730b"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/fwupd-a3bu-xplained.json b/fwupd-1.8.6/data/device-tests/fwupd-a3bu-xplained.json
new file mode 100644
index 0000000000000000000000000000000000000000..9ffb0cae1d811eeb600951a9220fdc0cea7fa53a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/fwupd-a3bu-xplained.json
@@ -0,0 +1,28 @@
+{
+ "name": "LVFS A3BU XPLAINED",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/f5bbeaba1037dce31dd12f349e8148ae35f98b61-a3bu-xplained123.cab",
+ "components": [
+ {
+ "version": "1.23",
+ "guids": [
+ "80478b9a-3643-5e47-ab0f-ed28abe1019d"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/24d838541efe0340bf67e1cc5a9b95526e4d3702-a3bu-xplained124.cab",
+ "components": [
+ {
+ "version": "1.24",
+ "guids": [
+ "80478b9a-3643-5e47-ab0f-ed28abe1019d"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/fwupd-at90usbkey.json b/fwupd-1.8.6/data/device-tests/fwupd-at90usbkey.json
new file mode 100644
index 0000000000000000000000000000000000000000..f0363b5d2a1dacdb13e5c4432f6edff46c4e492a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/fwupd-at90usbkey.json
@@ -0,0 +1,28 @@
+{
+ "name": "LVFS AT90USBKEY",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/b6bef375597e848971f230cf992c9740f7bf5b92-at90usbkey123.cab",
+ "components": [
+ {
+ "version": "1.23",
+ "guids": [
+ "c1874c52-5f6a-5864-926d-ea84bcdc82ea"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/47807fd4a94a4d5514ac6bf7a73038e00ed63225-at90usbkey124.cab",
+ "components": [
+ {
+ "version": "1.24",
+ "guids": [
+ "c1874c52-5f6a-5864-926d-ea84bcdc82ea"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/google-servo-micro.json b/fwupd-1.8.6/data/device-tests/google-servo-micro.json
new file mode 100644
index 0000000000000000000000000000000000000000..adc77aafd00884063c126e027a67628f0a8cc61c
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/google-servo-micro.json
@@ -0,0 +1,28 @@
+{
+ "name": "Google Servo Micro",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/3c3123b6eaa89d5469553b301210a9e4cb06efa98a1cb7c6847a1d10bb0a0c4b-servo_micro_v2.4.0.cab",
+ "components": [
+ {
+ "version": "2.4.0",
+ "guids": [
+ "13564257-c649-586d-b4e4-4f048d480f36"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/1dc362734f138e71fa838ac5503491d297715d7e9bccc0424a62c4a5c68526cc-servo_micro_v2.4.17.cab",
+ "components": [
+ {
+ "version": "2.4.17",
+ "guids": [
+ "13564257-c649-586d-b4e4-4f048d480f36"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/hp-dock-g5.json b/fwupd-1.8.6/data/device-tests/hp-dock-g5.json
new file mode 100644
index 0000000000000000000000000000000000000000..7b4acb8802858315060971b30b59533ac7e14eea
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/hp-dock-g5.json
@@ -0,0 +1,28 @@
+{
+ "name": "HP USB-C Dock G5",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/eb866447bb755c00e748cce14918dcbfaec0ec123237daefce5876c769c2bf92-HP-USBC_DOCK_G5-V1.0.11.0.cab",
+ "components": [
+ {
+ "version": "1.0.11.0",
+ "guids": [
+ "9434f89a-3351-536d-a281-f70203326833"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/c15a0df7386812781d1f376fe54729e64f69b2a8a6c4b580914d4f6740e4fcc3-HP-USBC_DOCK_G5-V1.0.13.0.cab",
+ "components": [
+ {
+ "version": "1.0.13.0",
+ "guids": [
+ "9434f89a-3351-536d-a281-f70203326833"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/hughski-colorhug-plus.json b/fwupd-1.8.6/data/device-tests/hughski-colorhug-plus.json
new file mode 100644
index 0000000000000000000000000000000000000000..e5313a3983b76daa04768711ac15e76649b9ddd9
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/hughski-colorhug-plus.json
@@ -0,0 +1,30 @@
+{
+ "name": "Hughski ColorHug Plus",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/5cbff92158331aeb10008ca36fa918a9637dde7bfe31de3e0523d14090be8977-fakedevice01_dfu.cab",
+ "components": [
+ {
+ "version": "0.1",
+ "guids": [
+ "dfbaaded-754b-5214-a5f2-46aa3331e8ce",
+ "f5b42624-ff57-5073-ba09-b7c9c04241be"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/8bc3afd07a0af3baaab8b19893791dd3972e8305-fakedevice02_dfu.cab",
+ "components": [
+ {
+ "version": "0.2",
+ "guids": [
+ "dfbaaded-754b-5214-a5f2-46aa3331e8ce",
+ "f5b42624-ff57-5073-ba09-b7c9c04241be"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/hughski-colorhug.json b/fwupd-1.8.6/data/device-tests/hughski-colorhug.json
new file mode 100644
index 0000000000000000000000000000000000000000..96fef5e0e9b26d9c3d3b5de6a405c2461772824b
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/hughski-colorhug.json
@@ -0,0 +1,28 @@
+{
+ "name": "Hughski ColorHug",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/9a4e77009da7d3b5f15a1388afeb9e5d41a5a8ae-hughski-colorhug2-1.2.5.cab",
+ "components": [
+ {
+ "version": "1.2.5",
+ "guids": [
+ "40338ceb-b966-4eae-adae-9c32edfcc484"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/2a066c8a1bfbd99f161c867b4dbe7e51ac36fc2b16ef37b11d18419874fbcb6c-hughski-colorhug-1.2.6.cab",
+ "components": [
+ {
+ "version": "1.2.6",
+ "guids": [
+ "40338ceb-b966-4eae-adae-9c32edfcc484"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/hughski-colorhug2.json b/fwupd-1.8.6/data/device-tests/hughski-colorhug2.json
new file mode 100644
index 0000000000000000000000000000000000000000..7c0e1db06cd39f770c90aacd58d80c207fd08dd7
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/hughski-colorhug2.json
@@ -0,0 +1,28 @@
+{
+ "name": "Hughski ColorHug2",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/170f2c19f17b7819644d3fcc7617621cc3350a04-hughski-colorhug2-2.0.6.cab",
+ "components": [
+ {
+ "version": "2.0.6",
+ "guids": [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/e5ad222bdbd3d3d48d8613e67c7e0a0e194f8cd828e33c554d9f05d933e482c7-hughski-colorhug2-2.0.7.cab",
+ "components": [
+ {
+ "version": "2.0.7",
+ "guids": [
+ "2082b5e0-7a64-478a-b1b2-e3404fab6dad"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/hyper-no-sku-vli.json b/fwupd-1.8.6/data/device-tests/hyper-no-sku-vli.json
new file mode 100644
index 0000000000000000000000000000000000000000..20675fb2be5f7fa6775b351a8def184bb23c9b14
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/hyper-no-sku-vli.json
@@ -0,0 +1,44 @@
+{
+ "name": "Hyper USB-C Hub [VL817+VL103]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/ecfebc47d63a5319e35da39bd6124b80e90138a208bc9134c9d1b256b232a704-Hyper-USB-C_Hub.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "90.83",
+ "guids": [
+ "a476b1bb-9f8e-5ad4-a0ed-afadb52334fc"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "154.36.9.55",
+ "guids": [
+ "0a120f99-b0f4-52af-9af9-e13155634370"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/1694cceda16068b24d7627caace4bd373ecae73aca891f610dec0fe5a4d1207c-Hyper-USB-C_Hub_Old.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "80.83",
+ "guids": [
+ "a476b1bb-9f8e-5ad4-a0ed-afadb52334fc"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "138.36.9.55",
+ "guids": [
+ "0a120f99-b0f4-52af-9af9-e13155634370"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/jabra-speak-410.json b/fwupd-1.8.6/data/device-tests/jabra-speak-410.json
new file mode 100644
index 0000000000000000000000000000000000000000..522e8a103d40f49acc91473ced7a6d248c5333db
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/jabra-speak-410.json
@@ -0,0 +1,28 @@
+{
+ "name": "Jabra Speak 410",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/eab97d7e745e372e435dbd76404c3929730ac082-Jabra-SPEAK_410-1.8.cab",
+ "components": [
+ {
+ "version": "1.8",
+ "guids": [
+ "1764c519-4723-5514-baf9-3b42970de487"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/50a03efc5df333a948e159854ea40e1a3786c34c-Jabra-SPEAK_410-1.11.cab",
+ "components": [
+ {
+ "version": "1.11",
+ "guids": [
+ "1764c519-4723-5514-baf9-3b42970de487"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/jabra-speak-510.json b/fwupd-1.8.6/data/device-tests/jabra-speak-510.json
new file mode 100644
index 0000000000000000000000000000000000000000..c3b7bdbf1849ca76feefb757757a26e73b978de8
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/jabra-speak-510.json
@@ -0,0 +1,28 @@
+{
+ "name": "Jabra Speak 510",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/45f88c50e79cfd30b6599df463463578d52f2fe9-Jabra-SPEAK_510-2.10.cab",
+ "components": [
+ {
+ "version": "2.10",
+ "guids": [
+ "443b9b32-7603-5c3a-bb30-291a7d8d6dbd"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/c0523a98ef72508b5c7ddd687418b915ad5f4eb9-Jabra-SPEAK_510-2.14.cab",
+ "components": [
+ {
+ "version": "2.14",
+ "guids": [
+ "443b9b32-7603-5c3a-bb30-291a7d8d6dbd"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/jabra-speak-710.json b/fwupd-1.8.6/data/device-tests/jabra-speak-710.json
new file mode 100644
index 0000000000000000000000000000000000000000..a985179f15fabb0d42cac1897a3a6a8daf19a4c7
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/jabra-speak-710.json
@@ -0,0 +1,28 @@
+{
+ "name": "Jabra Speak 710",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/d2910cdbc45cf172767d05e60d9e39a07a10d242-Jabra-SPEAK_710-1.10.cab",
+ "components": [
+ {
+ "version": "1.10",
+ "guids": [
+ "0c503ad9-4969-5668-81e5-a3748682fc16"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/a5c627ae42de4e5c3ae3df28977f480624f96f66-Jabra-SPEAK_710-1.28.cab",
+ "components": [
+ {
+ "version": "1.28",
+ "guids": [
+ "0c503ad9-4969-5668-81e5-a3748682fc16"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/lenovo-03x7168.json b/fwupd-1.8.6/data/device-tests/lenovo-03x7168.json
new file mode 100644
index 0000000000000000000000000000000000000000..ef95fa4f721d3e9262cf73e56822134470cd40e8
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/lenovo-03x7168.json
@@ -0,0 +1,28 @@
+{
+ "name": "Lenovo USB-C to HDMI (with power) [VL100]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/9ef0bb237baf8043f3ff16db5a8dd23bfd63fc24ea0eca2a6af3285792aa283b-Lenovo-USB-C_to_HDMI.cab",
+ "components": [
+ {
+ "version": "130.4.22.1",
+ "guids": [
+ "eca16353-163f-570b-9e0a-8329045fdcff"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/5b06a36aa0f2b99fc33f43a26a553d95c2d8ac46a7f5a2e45a840570456fe29b-Lenovo-USB-C_to_HDMI.cab",
+ "components": [
+ {
+ "version": "130.4.23.1",
+ "guids": [
+ "eca16353-163f-570b-9e0a-8329045fdcff"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/lenovo-03x7605.json b/fwupd-1.8.6/data/device-tests/lenovo-03x7605.json
new file mode 100644
index 0000000000000000000000000000000000000000..f2488696e39a490d170cf741e073f5fa8b83e9c2
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/lenovo-03x7605.json
@@ -0,0 +1,28 @@
+{
+ "name": "Lenovo USB-C to HDMI (no power) [VL103]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/61b393d8e27503746bae9a16dccf54929b9f1a0d1b5106334933a7313596c00c-Lenovo-USB-C_to_HDMI.cab",
+ "components": [
+ {
+ "version": "153.84.6.1",
+ "guids": [
+ "d0909dd3-d140-5da8-85fd-4aa5b2dcee5d"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/8be7eea7db239766cf92adf2145138c9929fd953d6d36e39d60c9dd6425638de-Lenovo-USB-C_to_HDMI.cab",
+ "components": [
+ {
+ "version": "153.84.7.1",
+ "guids": [
+ "d0909dd3-d140-5da8-85fd-4aa5b2dcee5d"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/lenovo-03x7608-vli.json b/fwupd-1.8.6/data/device-tests/lenovo-03x7608-vli.json
new file mode 100644
index 0000000000000000000000000000000000000000..660d7cd53342fc207d968257e9fb68740c476e2e
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/lenovo-03x7608-vli.json
@@ -0,0 +1,25 @@
+{
+ "name": "Lenovo Travel Hub Gen2 [VL817]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/ebfda3c96543d6d7ad97a972344f4d34a14549c535095bfbb1860115a88e6ff6-Lenovo-TravalHub-2020-12-11-153442.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "4.74",
+ "guids": [
+ "3fc55e47-f57a-55bd-9f41-ac60280bd689"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "138.04.72.18",
+ "guids": [
+ "3ae6610b-5c33-5714-96e3-05735eb9b2a5"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/lenovo-03x7609-cxaudio.json b/fwupd-1.8.6/data/device-tests/lenovo-03x7609-cxaudio.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d6828fc0d6cd1c068ecc45be21f1914b7049e4b
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/lenovo-03x7609-cxaudio.json
@@ -0,0 +1,19 @@
+{
+ "name": "Lenovo USB-C Dock Gen2 (CXAUDIO)",
+ "interactive": false,
+ "repeat": 2,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/2e0bf8aaf9c63ca11cfe3444d032277c21ec0d678e5963123a8b33e5dcd37d99-Lenovo-ThinkPad-USBCGen2Dock-Firmware-49-0E-14.cab",
+ "components": [
+ {
+ "name": "cxaudio",
+ "version": "49-0E-14",
+ "guids": [
+ "dbb8d54c-42e6-5215-b7ac-1df16872bb06"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/lenovo-40au0065-vli.json b/fwupd-1.8.6/data/device-tests/lenovo-40au0065-vli.json
new file mode 100644
index 0000000000000000000000000000000000000000..5395729bf8864ff15db87ab4593100b0aed0fd80
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/lenovo-40au0065-vli.json
@@ -0,0 +1,58 @@
+{
+ "name": "Lenovo USB-C Mini Dock",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/3b183e21869e4fce8bc81b3357de2fd1ee47b35e272e26169ebaee88faa39e03-Lenovo-Mini_Dock_New.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "4.154",
+ "guids": [
+ "f281c1df-c3d5-5f8a-984d-e9548ffc95fe"
+ ]
+ },
+ {
+ "name": "tier2",
+ "version": "4.43",
+ "guids": [
+ "d636c717-44c4-5fcf-9d7f-b96f9c5f6608"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "138.4.24.38",
+ "guids": [
+ "3ae6610b-5c33-5714-96e3-05735eb9b2a5"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/f55a307af1dc66d46bc12460ced828b31b2ee2a78c1d58d4f474958c2c6d134e-Lenovo-Mini_Dock_Old.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "4.94",
+ "guids": [
+ "f281c1df-c3d5-5f8a-984d-e9548ffc95fe"
+ ]
+ },
+ {
+ "name": "tier2",
+ "version": "4.33",
+ "guids": [
+ "d636c717-44c4-5fcf-9d7f-b96f9c5f6608"
+ ]
+ },
+ {
+ "name": "tier3",
+ "version": "138.4.23.38",
+ "guids": [
+ "3ae6610b-5c33-5714-96e3-05735eb9b2a5"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/lenovo-GX90T33021-vli.json b/fwupd-1.8.6/data/device-tests/lenovo-GX90T33021-vli.json
new file mode 100644
index 0000000000000000000000000000000000000000..7e7f43600a61fd72804826b02c1ecc66b855ec65
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/lenovo-GX90T33021-vli.json
@@ -0,0 +1,30 @@
+{
+ "name": "Lenovo Travel Hub 1in3 [VL211]",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/2004603b40bd529d85c2fcfcf9d50d77b47229e6564ef0ea9c03633bdccff94d-Lenovo-Travel_Hub_1in3_New.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "44.33",
+ "guids": [
+ "7636b85e-d79f-5d30-a329-458957958b88"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/5fb4f4dce233626558806c2b7474d3b5ed4f500f6013aa3b376a54322642d449-Lenovo-Travel_Hub_1in3_Old.cab",
+ "components": [
+ {
+ "name": "tier1",
+ "version": "04.33",
+ "guids": [
+ "7636b85e-d79f-5d30-a329-458957958b88"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-bolt-receiver.json b/fwupd-1.8.6/data/device-tests/logitech-bolt-receiver.json
new file mode 100644
index 0000000000000000000000000000000000000000..2bf161e14a235b2ecd4278558a01e07dd3d24684
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-bolt-receiver.json
@@ -0,0 +1,42 @@
+{
+ "name": "Logitech Bolt receiver",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/003dcc6c2c5437ab093e0c5c5fc1c4e5ab6274d3060505fe0ef843fd13e7200c-Logitech-MPR05-MPR05.00_B0008.cab",
+ "components": [
+ {
+ "version": "MPR05.00_B0008",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "af1404c4-f038-5b3e-92b0-09bf4aa84f1c"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/c35ade1237da4e1ff90d031cc2b2218c32ee53c01b92b014aae2d2226aed2e35-Logitech-MPR05-MPR05.00_B0009.cab",
+ "components": [
+ {
+ "version": "MPR05.00_B0009",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "af1404c4-f038-5b3e-92b0-09bf4aa84f1c"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/f1e3ba268ae4e1d3c029392d4f203a976970b162521296a2e9a9a31f314c0c46-Logitech-MPR05-MPR05.01_B0010.cab",
+ "components": [
+ {
+ "version": "MPR05.01_B0010",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "af1404c4-f038-5b3e-92b0-09bf4aa84f1c"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-k780.json b/fwupd-1.8.6/data/device-tests/logitech-k780.json
new file mode 100644
index 0000000000000000000000000000000000000000..a360f858fa70a41ac4a4158e04e93f47fa7727fa
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-k780.json
@@ -0,0 +1,28 @@
+{
+ "name": "Logitech K780",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/454f1034f5efeb531163d90852ef33afd3fafeeb-Logitech-K780-MPK01.02_B0021.cab",
+ "components": [
+ {
+ "version": "MPK01.02_B0021",
+ "guids": [
+ "3932ba15-2bbe-5bbb-817e-6c74e7088509"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/b0dffe84c6d3681e7ae5f27509781bc1cf924dd7-Logitech-K780-MPK01.03_B0024.cab",
+ "components": [
+ {
+ "version": "MPK01.03_B0024",
+ "guids": [
+ "3932ba15-2bbe-5bbb-817e-6c74e7088509"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-m650.json b/fwupd-1.8.6/data/device-tests/logitech-m650.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c19830ed301abe00f2642cf9f6122ff97db832a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-m650.json
@@ -0,0 +1,30 @@
+{
+ "name": "Logitech M650",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/6531c7a26d54f9dacbc24f81e8b26e37dd630fe22a417cd2ce6e13ea3b6fd105-Logitech-RBM16-RBM16.00_B0009.cab",
+ "components": [
+ {
+ "version": "RBM16.00_B0009",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "bb3fe644-ed3c-55a4-a506-191e65974b04"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/422d8c719d859b4ef321d95aa9e21f8d0d899ac924b9ca3ed76b1d745224e8e4-Logitech-RBM16-RBM16.00_B0010.cab",
+ "components": [
+ {
+ "version": "RBM16.00_B0010",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "bb3fe644-ed3c-55a4-a506-191e65974b04"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-m750.json b/fwupd-1.8.6/data/device-tests/logitech-m750.json
new file mode 100644
index 0000000000000000000000000000000000000000..a5cd35373ccb4a0912e4aa56e07f8b9548693d0b
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-m750.json
@@ -0,0 +1,17 @@
+{
+ "name": "Logitech M750",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/597a12cca95b9dcf19e82e5add970a45bf658de8c82dc329cc271a6c50d68752-Logitech-RBM18-RBM18.00_B0010.cab",
+ "components": [
+ {
+ "version": "RBM18.00_B0010",
+ "guids": [
+ "b0904956-9081-5ce4-9490-bee057a2d577"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-mr0077.json b/fwupd-1.8.6/data/device-tests/logitech-mr0077.json
new file mode 100644
index 0000000000000000000000000000000000000000..4518c08f3182fae6750dec291beddefb81f0f598
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-mr0077.json
@@ -0,0 +1,30 @@
+{
+ "name": "Logitech MR0077",
+ "interactive": true,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/7b86a6cb5747607f38e78259734dcf0d1afc02d2116b7386ac00c15e70eece72-Logitech-RBM14-RBM14_00_B0007.cab",
+ "components": [
+ {
+ "version": "RBM14.00_B0007",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "b2b50d12-c3df-5980-b5e9-6cc6c34b3037"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/1cec33151e0f206df9b353a56e318adebb9a9ba9f330b452336eef169f5b1f3c-Logitech-RBM14-RBM14_00_B0008.cab",
+ "components": [
+ {
+ "version": "RBM14.00_B0008",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "b2b50d12-c3df-5980-b5e9-6cc6c34b3037"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-rqr12-signed.json b/fwupd-1.8.6/data/device-tests/logitech-rqr12-signed.json
new file mode 100644
index 0000000000000000000000000000000000000000..d568697e8b99cc6b1ce0dc78abc9e10ce4047973
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-rqr12-signed.json
@@ -0,0 +1,19 @@
+{
+ "name": "Logitech Unifying Receiver (RQR12 SIGNED)",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/2443cef8b1dae48751d3c60dab22210733e57036-Logitech-Unifying-RQR12.11_B0032.cab",
+ "components": [
+ {
+ "version": "RQR12.11_B0032",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "9d131a0c-a606-580f-8eda-80587250b8d6",
+ "d637baf7-3ab5-502a-8169-2545302e44e2"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-rqr12.json b/fwupd-1.8.6/data/device-tests/logitech-rqr12.json
new file mode 100644
index 0000000000000000000000000000000000000000..b51b49b75c1c6cc1bd25064427ecd0060c71e523
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-rqr12.json
@@ -0,0 +1,30 @@
+{
+ "name": "Logitech Unifying Receiver (RQR12)",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/6e5ab5961ec4c577bff198ebb465106e979cf686-Logitech-Unifying-RQR12.05_B0028.cab",
+ "components": [
+ {
+ "version": "RQR12.05_B0028",
+ "protocol": "com.logitech.unifying",
+ "guids": [
+ "9d131a0c-a606-580f-8eda-80587250b8d6"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/938fec082652c603a1cdafde7cd25d76baadc70d-Logitech-Unifying-RQR12.07_B0029.cab",
+ "components": [
+ {
+ "version": "RQR12.07_B0029",
+ "protocol": "com.logitech.unifying",
+ "guids": [
+ "9d131a0c-a606-580f-8eda-80587250b8d6"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-rqr24-signed.json b/fwupd-1.8.6/data/device-tests/logitech-rqr24-signed.json
new file mode 100644
index 0000000000000000000000000000000000000000..9f1b3794a328cb0f390b1be6bf12235060748a40
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-rqr24-signed.json
@@ -0,0 +1,21 @@
+{
+ "name": "Logitech Unifying Receiver (RQR24 SIGNED)",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/b30e729cc544c711a6ad947cef9ce6614b394a7b-Logitech-Unifying-RQR24.11_B0036.cab",
+ "components": [
+ {
+ "version": "RQR24.11_B0036",
+ "protocol": "com.logitech.unifyingsigned",
+ "guids": [
+ "cc4cbfa9-bf9d-540b-b92b-172ce31013c1",
+ "87fd7145-3913-50c8-bfcb-86f85006d7d1",
+ "111c9951-f819-5c48-93ef-205a8f8b96c1",
+ "40410bd7-57eb-5c82-9eac-abf893861221"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/logitech-rqr24.json b/fwupd-1.8.6/data/device-tests/logitech-rqr24.json
new file mode 100644
index 0000000000000000000000000000000000000000..94f9cc0d255f31cff67c6d39b844b32a228c8b40
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/logitech-rqr24.json
@@ -0,0 +1,30 @@
+{
+ "name": "Logitech Unifying Receiver (RQR24)",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/82b90b2614a9a4d0aced1ab8a4a99e228c95585c-Logitech-Unifying-RQ024.03_B0027.cab",
+ "components": [
+ {
+ "version": "RQR24.03_B0027",
+ "protocol": "com.logitech.unifying",
+ "guids": [
+ "cc4cbfa9-bf9d-540b-b92b-172ce31013c1"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/4511b9b0d123bdbe8a2007233318ab215a59dfe6-Logitech-Unifying-RQR24.05_B0029.cab",
+ "components": [
+ {
+ "version": "RQR24.05_B0029",
+ "protocol": "com.logitech.unifying",
+ "guids": [
+ "cc4cbfa9-bf9d-540b-b92b-172ce31013c1"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/meson.build b/fwupd-1.8.6/data/device-tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..beb51e84b39cf12f743e7c2c9bf402a00a1f7a06
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/meson.build
@@ -0,0 +1,47 @@
+install_data([
+ '8bitdo-nes30pro.json',
+ '8bitdo-sf30pro.json',
+ '8bitdo-sfc30.json',
+ 'aiaiai-h05.json',
+ 'bizlink-no-sku-vli.json',
+ 'corsair-katar-pro-xt.json',
+ 'corsair-sabre-pro.json',
+ 'corsair-sabre-rgb-pro.json',
+ 'dell-kh08p.json',
+ 'dell-wd19tb.json',
+ 'fwupd-a3bu-xplained.json',
+ 'fwupd-at90usbkey.json',
+ 'hp-dock-g5.json',
+ 'hughski-colorhug2.json',
+ 'hughski-colorhug.json',
+ 'hughski-colorhug-plus.json',
+ 'hyper-no-sku-vli.json',
+ 'jabra-speak-410.json',
+ 'jabra-speak-510.json',
+ 'jabra-speak-710.json',
+ 'lenovo-03x7168.json',
+ 'lenovo-03x7605.json',
+ 'lenovo-03x7608-vli.json',
+ 'lenovo-03x7609-cxaudio.json',
+ 'lenovo-40au0065-vli.json',
+ 'lenovo-GX90T33021-vli.json',
+ 'logitech-bolt-receiver.json',
+ 'logitech-k780.json',
+ 'logitech-m650.json',
+ 'logitech-m750.json',
+ 'logitech-mr0077.json',
+ 'logitech-rqr12.json',
+ 'logitech-rqr12-signed.json',
+ 'logitech-rqr24.json',
+ 'logitech-rqr24-signed.json',
+ 'nordic-hid-nrf52840-mcuboot.json',
+ 'realtek-rts5423.json',
+ 'realtek-rts5855.json',
+ 'synaptics-prometheus.json',
+ 'system76-thelio.json',
+ 'ugreen-cm260.json',
+ 'wacom-intuos-bt-m.json',
+ 'wacom-intuos-bt-s.json',
+ ],
+ install_dir: join_paths(datadir, 'fwupd', 'device-tests'),
+)
diff --git a/fwupd-1.8.6/data/device-tests/nordic-hid-nrf52840-mcuboot.json b/fwupd-1.8.6/data/device-tests/nordic-hid-nrf52840-mcuboot.json
new file mode 100644
index 0000000000000000000000000000000000000000..4ca02e307084020314f10cca8a9b1bc0ea10d6be
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/nordic-hid-nrf52840-mcuboot.json
@@ -0,0 +1,28 @@
+{
+ "name": "nRF52840 DK (nRF52 Desktop) MCUBoot variant",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/904ff137256218bc617661bb4fc2bfddad19522c7e54773d1fd0290b54adfcee-nordic-nrf52840dk-mcuboot-0.0.0_2.cab",
+ "components": [
+ {
+ "version": "0.0.0.2",
+ "guids": [
+ "43b38427-fdf5-5400-a23c-f3eb7ea00e7c"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/2eb21f9439f0c4928c14548ff5c5c73ad6590d23fa704c58c4afa88168bcea90-nordic-nrf52840dk-mcuboot-0.0.0_3.cab",
+ "components": [
+ {
+ "version": "0.0.0.3",
+ "guids": [
+ "43b38427-fdf5-5400-a23c-f3eb7ea00e7c"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/realtek-rts5423.json b/fwupd-1.8.6/data/device-tests/realtek-rts5423.json
new file mode 100644
index 0000000000000000000000000000000000000000..8a753d6dc74bc4dfebc604f5743cec4f5bbfa33f
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/realtek-rts5423.json
@@ -0,0 +1,28 @@
+{
+ "name": "Realtek 4-Port USB Hub",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/460a18d93f5d6118908d8437009ebbd6eceb3c6a0cdfbaf31f8a96df008564da-Realtek-RTS5423-1.56.cab",
+ "components": [
+ {
+ "version": "1.56",
+ "guids": [
+ "b2d2fae3-1546-5d16-a9af-ac117a255a91"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/659e721b0efbe2dfc003d3d30ea5b771c00113cc9a162333ee5a8918c4515f69-Realtek-RTS5423-1.57.cab",
+ "components": [
+ {
+ "version": "1.57",
+ "guids": [
+ "b2d2fae3-1546-5d16-a9af-ac117a255a91"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/realtek-rts5855.json b/fwupd-1.8.6/data/device-tests/realtek-rts5855.json
new file mode 100644
index 0000000000000000000000000000000000000000..c19ff22b1bd0d66455832fb86aba13603a0cef40
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/realtek-rts5855.json
@@ -0,0 +1,28 @@
+{
+ "name": "Realtek RTS5855 Webcam",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/ff989c4b71c92a4a217dfb2f82c1c87691b8eb31-rts5855_v0.4.cab",
+ "components": [
+ {
+ "version": "0.4",
+ "guids": [
+ "9829f051-47f5-55e7-87dc-a49cf55602e2"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/ed5c411d6b74c363209f408f87618fa5c31b50ab-v0.3.cab",
+ "components": [
+ {
+ "version": "0.3",
+ "guids": [
+ "9829f051-47f5-55e7-87dc-a49cf55602e2"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/steelseries-aerox-3-wireless.json b/fwupd-1.8.6/data/device-tests/steelseries-aerox-3-wireless.json
new file mode 100644
index 0000000000000000000000000000000000000000..6f713a4ec33a4e69f918e92168d1c845ba7b9a1a
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/steelseries-aerox-3-wireless.json
@@ -0,0 +1,56 @@
+{
+ "name": "Steelseries Aerox 3 Wireless",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/dee6986d0faf769bf57869ee2b61118c8142e4a0017dbfc3bb0da24fb6dcfb06-SteelSeries_Aerox_3_Wireless_Dongle_1.2.17.cab",
+ "components": [
+ {
+ "version": "1.2.17",
+ "guids": [
+ "291b0582-8d08-5714-88db-986911c744d9",
+ "df0cb7f0-be88-532f-87f9-65662da376b9"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/35883a1f60f9a171451ccd8ca9e3d89cfaedd99cc1325410465e30d180bcb47a-SteelSeries_Aerox_3_Wireless_Mouse_1.8.1.cab",
+ "components": [
+ {
+ "version": "1.8.1",
+ "guids": [
+ "541b2713-d367-5240-a443-bed07f09ffbf",
+ "4f3fac7c-981b-58cc-bb58-8a3b90f31c9c",
+ "ac7d7cbb-7ef5-5466-ab3d-e70ced97ee61"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/fb8e8253a6c4426233ff88a58ae9323f1a7b9002fe6f68541c2e886cded04d38-SteelSeries_Aerox_3_Wireless_Dongle_1.3.1.cab",
+ "components": [
+ {
+ "version": "1.3.1",
+ "guids": [
+ "291b0582-8d08-5714-88db-986911c744d9",
+ "df0cb7f0-be88-532f-87f9-65662da376b9"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/60627b15b7c1499fcd6a882ef02743f358812fcfc9ed3d1b200f55b91c554796-SteelSeries_Aerox_3_Wireless_Mouse_1.9.3.cab",
+ "components": [
+ {
+ "version": "1.9.3",
+ "guids": [
+ "541b2713-d367-5240-a443-bed07f09ffbf",
+ "4f3fac7c-981b-58cc-bb58-8a3b90f31c9c",
+ "ac7d7cbb-7ef5-5466-ab3d-e70ced97ee61"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/steelseries-rival-3-wireless.json b/fwupd-1.8.6/data/device-tests/steelseries-rival-3-wireless.json
new file mode 100644
index 0000000000000000000000000000000000000000..f51bc71997328852dfb7b1e9ae22e7eb582c5966
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/steelseries-rival-3-wireless.json
@@ -0,0 +1,28 @@
+{
+ "name": "Steelseries Rival 3 Wireless",
+ "interactive": true,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/fe3775d33b41898e69f06698ed03779a158d99b9716a9b1c0ee7e3051ab857c3-SteelSeries_Rival_3_Wireless_1.0.cab",
+ "components": [
+ {
+ "version": "1.0",
+ "guids": [
+ "73e6daa7-d5a1-567d-a0ff-01514f8498b1"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/30c6979b393fee0bbf27695fa1b36c1fa8ac276c7744a8e3845a859e79fb0c94-SteelSeries_Rival_3_Wireless_1.4.cab",
+ "components": [
+ {
+ "version": "1.4",
+ "guids": [
+ "73e6daa7-d5a1-567d-a0ff-01514f8498b1"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/synaptics-prometheus.json b/fwupd-1.8.6/data/device-tests/synaptics-prometheus.json
new file mode 100644
index 0000000000000000000000000000000000000000..d0573d151eae2426a8a0947710d8b7c7c87d286d
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/synaptics-prometheus.json
@@ -0,0 +1,17 @@
+{
+ "name": "Prometheus Fingerprint Reader",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/7c260a13ea6df444f7a1fa8fa2bf431876a8c7203b6aeac371564aad30756ff1-Synaptics-Prometheus-10.01.3121519.cab",
+ "components": [
+ {
+ "version": "10.01.3121519",
+ "guids": [
+ "8088f861-6318-5b1e-9ce4-fbddbedb09ac"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/system76-thelio.json b/fwupd-1.8.6/data/device-tests/system76-thelio.json
new file mode 100644
index 0000000000000000000000000000000000000000..63849317f529cee00e3df5b7e6d10a721faa456c
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/system76-thelio.json
@@ -0,0 +1,42 @@
+{
+ "name": "System76 Thelio Io",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/ed423e586cdd35d41f0dd708ea8e5b5b97c54d48eef7e23a02d9a088b231b3fd-thelio-io_0.0.0.cab",
+ "components": [
+ {
+ "version": "0.0.0",
+ "protocol": "org.usb.dfu",
+ "guids": [
+ "fdac0b40-51c6-591b-a049-e9cfc05e9271"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/1be9bcfa7b5f0db2bca927505f82d8829be5882ca295e33af492d0e1fdacc162-thelio-io_1.0.0.cab",
+ "components": [
+ {
+ "version": "1.0.0",
+ "protocol": "org.usb.dfu",
+ "guids": [
+ "fdac0b40-51c6-591b-a049-e9cfc05e9271"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/63d4a480162b729fc57ff7c92c1e2254540f43d6-thelio-io_1.0.2.cab",
+ "components": [
+ {
+ "version": "1.0.2",
+ "protocol": "org.usb.dfu",
+ "guids": [
+ "fdac0b40-51c6-591b-a049-e9cfc05e9271"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/ugreen-cm260.json b/fwupd-1.8.6/data/device-tests/ugreen-cm260.json
new file mode 100644
index 0000000000000000000000000000000000000000..28e35ad9e1106ab9b5d1a793502545be62eea443
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/ugreen-cm260.json
@@ -0,0 +1,28 @@
+{
+ "name": "Ugreen CM260",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/53cd390673287a99e5d4cc4cf30b5fade0f5e708fe0b1bd424bf36467642d76c-Ugreen-CM260-7.2.1.0.cab",
+ "components": [
+ {
+ "version": "7.2.1.0",
+ "guids": [
+ "7afc5bff-be55-5e95-81ca-584f13207b1d"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/eec2c6216fa86077504587633fc8d018a366a1cfe3df8dd9c575c2e8ef0ef423-Ugreen-CM260-7.2.2.0.cab",
+ "components": [
+ {
+ "version": "7.2.1.0",
+ "guids": [
+ "7afc5bff-be55-5e95-81ca-584f13207b1d"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/wacom-intuos-bt-m.json b/fwupd-1.8.6/data/device-tests/wacom-intuos-bt-m.json
new file mode 100644
index 0000000000000000000000000000000000000000..bcf88e65322a6827a98b5acb1877fc5efe1573e3
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/wacom-intuos-bt-m.json
@@ -0,0 +1,30 @@
+{
+ "name": "Wacom Intuos BT-M",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/d16b682de56c42b134f1e5af7f9926c62dc246df851648e49aa1d1d0e5b38532-Wacom-Intuos_BT-M_MainFW-1.66.cab",
+ "components": [
+ {
+ "name": "main",
+ "version": "1.66",
+ "guids": [
+ "edf56833-dbe5-56ca-a651-734b01bb02ba"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/1ee4f3dc9fd08acd4c6bc833b25e7061f85ddd40122148d66940cd3ddd748920-Wacom-Intuos_BT-M_BluetoothFW-1.12.cab",
+ "components": [
+ {
+ "name": "bluetooth",
+ "version": "1.12",
+ "guids": [
+ "230fb992-35c7-56b1-8236-7f5674a04153"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/device-tests/wacom-intuos-bt-s.json b/fwupd-1.8.6/data/device-tests/wacom-intuos-bt-s.json
new file mode 100644
index 0000000000000000000000000000000000000000..97ee8153b4b12d63d270ecabfd1b907722750b1f
--- /dev/null
+++ b/fwupd-1.8.6/data/device-tests/wacom-intuos-bt-s.json
@@ -0,0 +1,44 @@
+{
+ "name": "Wacom Intuos BT-S",
+ "interactive": false,
+ "steps": [
+ {
+ "url": "https://fwupd.org/downloads/0d9314e86d28f78f5dc37d71c5cc5205b681334fe64b28f1ec95b5eedc6e1ea6-Wacom-CTL-4100WL-1.10.cab",
+ "components": [
+ {
+ "name": "bluetooth",
+ "version": "1.12",
+ "guids": [
+ "e317b626-4c1d-5892-8b4c-aafec894a4c9"
+ ]
+ },
+ {
+ "name": "main",
+ "version": "1.10",
+ "guids": [
+ "dc80ba55-c5f7-5195-b6f4-23c2940bcaec"
+ ]
+ }
+ ]
+ },
+ {
+ "url": "https://fwupd.org/downloads/cfec6515263c0d358d40d7b8fb6472214015225210dfa2db8dd307e896f03dcf-Wacom-CTL-4100WL-1.11.cab",
+ "components": [
+ {
+ "name": "bluetooth",
+ "version": "1.12",
+ "guids": [
+ "e317b626-4c1d-5892-8b4c-aafec894a4c9"
+ ]
+ },
+ {
+ "name": "main",
+ "version": "1.11",
+ "guids": [
+ "dc80ba55-c5f7-5195-b6f4-23c2940bcaec"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/fwupd-1.8.6/data/fish-completion/fwupdmgr.fish b/fwupd-1.8.6/data/fish-completion/fwupdmgr.fish
new file mode 100644
index 0000000000000000000000000000000000000000..e2746ac15b05c97d39466e16bcdb3591fac0ae7c
--- /dev/null
+++ b/fwupd-1.8.6/data/fish-completion/fwupdmgr.fish
@@ -0,0 +1,80 @@
+function __fish_fwupdmgr_devices --description 'Get device IDs used by fwupdmgr'
+ set -l ids (fwupdmgr get-devices | string replace -f -r '.*Device ID:\s*(.*)' '$1')
+ set -l names (fwupdmgr get-devices | string replace -f -r '.*─(.*):$' '$1')
+ for i in (seq (count $ids))
+ echo -e "$ids[$i]\t$names[$i]"
+ end
+end
+
+function __fish_fwupdmgr_remotes --description 'Get remote IDs used by fwupdmgr'
+ fwupdmgr get-remotes | string replace -f -r '.*Remote ID:\s*(.*)' '$1'
+end
+
+
+# complete options
+complete -c fwupdmgr -s h -l help -d 'Show help options'
+complete -c fwupdmgr -s v -l verbose -d 'Show extra debugging information'
+complete -c fwupdmgr -l version -d 'Show client and daemon versions'
+complete -c fwupdmgr -l offline -d 'Schedule installation for next reboot when possible'
+complete -c fwupdmgr -l allow-reinstall -d 'Allow reinstalling existing firmware versions'
+complete -c fwupdmgr -l allow-older -d 'Allow downgrading firmware versions'
+complete -c fwupdmgr -l allow-branch-switch -d 'Allow switching firmware branch'
+complete -c fwupdmgr -l force -d 'Force the action by relaxing some runtime checks'
+complete -c fwupdmgr -s y -l assume-yes -d 'Answer yes to all questions'
+complete -c fwupdmgr -l sign -d 'Sign the uploaded data with the client certificate'
+complete -c fwupdmgr -l no-unreported-check -d 'Do not check for unreported history'
+complete -c fwupdmgr -l no-metadata-check -d 'Do not check for old metadata'
+complete -c fwupdmgr -l no-reboot-check -d 'Do not check or prompt for reboot after update'
+complete -c fwupdmgr -l no-safety-check -d 'Do not perform device safety checks'
+complete -c fwupdmgr -l no-history -d 'Do not write to the history database'
+complete -c fwupdmgr -l show-all -d 'Show all results'
+complete -c fwupdmgr -l disable-ssl-strict -d 'Ignore SSL strict checks when downloading'
+complete -c fwupdmgr -l ipfs -d 'Use IPFS when downloading files'
+complete -c fwupdmgr -l filter -d 'Filter with a set of device flags'
+
+# complete subcommands
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a activate -d 'Activate devices'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a block-firmware -d 'Blocks a specific firmware from being installed'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a clear-results -d 'Clears the results from the last update'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a disable-remote -d 'Disables a given remote'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a downgrade -d 'Downgrades the firmware on a device'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a enable-remote -d 'Enables a given remote'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-approved-firmware -d 'Gets the list of approved firmware'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-blocked-firmware -d 'Gets the list of blocked firmware'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-bios-setting -d 'Retrieve BIOS setting'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-details -d 'Gets details about a firmware file'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-devices -d 'Get all devices that support firmware updates'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-history -d 'Show history of firmware updates'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-releases -d 'Gets the releases for a device'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-remotes -d 'Gets the configured remotes'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-results -d 'Gets the results from the last update'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a get-updates -d 'Gets the list of updates for connected hardware'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a install -d 'Install a firmware file on this hardware'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-config -d 'Modifies a daemon configuration value'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a modify-remote -d 'Modifies a given remote'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a refresh -d 'Refresh metadata from remote server'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a report-history -d 'Share firmware history with the developers'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-bios-setting -d 'Set a BIOS setting'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a security -d 'Gets the host security attributes'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unblock-firmware -d 'Unblocks a specific firmware from being installed'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unlock -d 'Unlocks the device for firmware access'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a update -d 'Updates all firmware to latest versions available'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptographic hash matches firmware'
+complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify-update -d 'Update the stored cryptographic hash with current ROM contents'
+
+# commands exclusively consuming device IDs
+set -l deviceid_consumers activate clear-results downgrade get-releases get-results get-updates reinstall switch-branch unlock update verify verify-update
+# complete device IDs
+complete -c fwupdmgr -n "__fish_seen_subcommand_from $deviceid_consumers" -x -a "(__fish_fwupdmgr_devices)"
+# complete files and device IDs
+complete -c fwupdmgr -n "__fish_seen_subcommand_from install" -r -a "(__fish_fwupdmgr_devices)"
+
+# commands exclusively consuming remote IDs
+set -l remoteid_consumers disable-remote enable-remote modify-remote
+# complete remote IDs
+complete -c fwupdmgr -n "__fish_seen_subcommand_from $remoteid_consumers" -x -a "(__fish_fwupdmgr_remotes)"
+# complete files and remote IDs
+complete -c fwupdmgr -n "__fish_seen_subcommand_from refresh" -r -a "(__fish_fwupdmgr_remotes)"
diff --git a/fwupd-1.8.6/data/fish-completion/meson.build b/fwupd-1.8.6/data/fish-completion/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..5cce15e4d51b58ee822903325ddabd6f9966d2ab
--- /dev/null
+++ b/fwupd-1.8.6/data/fish-completion/meson.build
@@ -0,0 +1,3 @@
+install_data(['fwupdmgr.fish'],
+ install_dir: join_paths(datadir, 'fish', 'vendor_completions.d'),
+)
diff --git a/fwupd-1.8.6/data/fwupd-offline-update.service.in b/fwupd-1.8.6/data/fwupd-offline-update.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..ee44b6581f22f8d5e5b62236cb677059415fa500
--- /dev/null
+++ b/fwupd-1.8.6/data/fwupd-offline-update.service.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=Updates device firmware whilst offline
+Documentation=man:fwupdmgr
+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]
+Type=oneshot
+ExecStart=@libexecdir@/fwupd/fwupdoffline
+FailureAction=reboot
diff --git a/fwupd-1.8.6/data/fwupd.ico b/fwupd-1.8.6/data/fwupd.ico
new file mode 100644
index 0000000000000000000000000000000000000000..d92df08b6513a8699a72892c9d1d1f7f2c9dfda3
Binary files /dev/null and b/fwupd-1.8.6/data/fwupd.ico differ
diff --git a/fwupd-1.8.6/data/fwupd.service.in b/fwupd-1.8.6/data/fwupd.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..0095c5b5aacb3cc92c1b4a472ed755fa0784ffce
--- /dev/null
+++ b/fwupd-1.8.6/data/fwupd.service.in
@@ -0,0 +1,19 @@
+[Unit]
+Description=Firmware update daemon
+Documentation=https://fwupd.org/
+After=dbus.service
+Before=display-manager.service
+ConditionVirtualization=!container
+
+[Service]
+Type=dbus
+TimeoutSec=180
+RuntimeDirectory=@motd_dir@
+RuntimeDirectoryPreserve=yes
+BusName=org.freedesktop.fwupd
+ExecStart=@libexecdir@/fwupd/fwupd
+PrivateTmp=yes
+ProtectHome=yes
+ProtectSystem=full
+SystemCallFilter=~@mount
+@dynamic_options@
diff --git a/fwupd-1.8.6/data/fwupd.shutdown.in b/fwupd-1.8.6/data/fwupd.shutdown.in
new file mode 100755
index 0000000000000000000000000000000000000000..0a27b7680567fa8bc9c1599da5fff62c95c451c3
--- /dev/null
+++ b/fwupd-1.8.6/data/fwupd.shutdown.in
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# no history database exists
+[ -f @localstatedir@/lib/fwupd/pending.db ] || exit 0
+
+# activate firmware when we have a read-only filesysten
+if ! @bindir@/fwupdtool activate; then
+ ret=$?
+ [ "$ret" -eq "2" ] && exit 0
+ exit $ret
+fi
diff --git a/fwupd-1.8.6/data/installed-tests/README.md b/fwupd-1.8.6/data/installed-tests/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c7fb4641501bc0da05d762cd370416a957b78531
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/README.md
@@ -0,0 +1,83 @@
+# 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 `DisabledPlugins`
+
+ ```shell
+ # sed "s,^Enabled=false,Enabled=true," -i /etc/fwupd/remotes.d/fwupd-tests.conf
+ ```
+
+2. Enable the `fwupd-tests` remote for local CAB files.
+
+ ```shell
+ # 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.
+
+```text
+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.
+
+```shell
+$ 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`.
+
+```shell
+$ 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 --git a/fwupd-1.8.6/data/installed-tests/fakedevice123.bin b/fwupd-1.8.6/data/installed-tests/fakedevice123.bin
new file mode 100644
index 0000000000000000000000000000000000000000..885b0f234903bada1fe2c9e1ba5f21c18207c9f7
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fakedevice123.bin
@@ -0,0 +1 @@
+0x1020003
diff --git a/fwupd-1.8.6/data/installed-tests/fakedevice123.bin.asc b/fwupd-1.8.6/data/installed-tests/fakedevice123.bin.asc
new file mode 100644
index 0000000000000000000000000000000000000000..ed6d9b858de3fff8a2b2f286877d237090ceb5fd
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fakedevice123.bin.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+iQEcBAABAgAGBQJfey1HAAoJEEim2A5FOLrCn2MIAK6BnVojGYSwHVpZm58b05Xs
+rNqozg5pvfDfB0Bde1S0T/4TlDEnJNUku0Gz5IFNbR3ENT5VnJgBkE5xa8Rmv6cy
+Gm30CmX+UE1E8qK4BVhUdbNN8bEmeMtzUMK2KfpwMXlIqcpSjpln76PQIxMHj+3P
+600bkcppkLEKhiOo+THNhiHxPYJ+wjSSPm3paeMmUuApIvP4YFH8uQ5qkKLdLDVI
+V5QOx3O5P3avmHu936GILG9EwV3TkR1eNOe33OqtrGvpoMTcsxUF0Wc/qmUD066d
+c9hkTe01paQoN0HW/RMgrIaMnLFwK2mBcwySOo6TU9MIyQfDmLGN3u12nCrmRH8=
+=Rq70
+-----END PGP SIGNATURE-----
diff --git a/fwupd-1.8.6/data/installed-tests/fakedevice123.metainfo.xml b/fwupd-1.8.6/data/installed-tests/fakedevice123.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..52c9c71f44777a004095b86ec2eb0a4229fd11d8
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fakedevice123.metainfo.xml
@@ -0,0 +1,28 @@
+
+
+
+ org.fwupd.fakedevice.firmware
+ FakeDevice
+ Firmware for the ACME Corp Integrated Webcam
+
+
+ Updating the firmware on your webcam device improves performance and
+ adds new features.
+
+
+
+ b585990a-003e-5270-89d5-3705a17f9a43
+
+ http://www.acme.com/
+ CC0-1.0
+ GPL-2.0+
+ ACME Corp
+
+
+
+
+ Fixes a bug with the flux capacitor to avoid year 2038 overflow.
+
+
+
+
diff --git a/fwupd-1.8.6/data/installed-tests/fakedevice124.bin b/fwupd-1.8.6/data/installed-tests/fakedevice124.bin
new file mode 100644
index 0000000000000000000000000000000000000000..f1b2c68db4d7df957abefa64862c4a09101e6ebc
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fakedevice124.bin
@@ -0,0 +1 @@
+0x1020004
diff --git a/fwupd-1.8.6/data/installed-tests/fakedevice124.bin.asc b/fwupd-1.8.6/data/installed-tests/fakedevice124.bin.asc
new file mode 100644
index 0000000000000000000000000000000000000000..2b2192170e3816c4a4b985b14098fdfa2491b1c8
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fakedevice124.bin.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+iQEcBAABAgAGBQJfey2FAAoJEEim2A5FOLrCl88IAKCggwAz3qBrBfrc91sYHCq5
+OthMyftOUTQ4JpfISY38k20pwFEhsSHKdKAYDKEVO2jopw+Cr9oTyFycWK20R2lz
+tUn4e1EF8zQ29OLxGbvgGlP5/4vPJ2Cv5ujkub6LtNBrOMkNJ6+bB6G8nJZRTElU
+e3wi9+E9oKPBgP40A/y79pzPiFMxXl1piYjU3JNeofd3nbtmyRqb6VAs9exQ94+p
+CMWWZaJ9igxSAsQiE/NxZpO8qgG3KEmsW7yXRiaIe6xHxb49+JQdjxqS8Oc/C9sX
+FSiVHDPzlUegZtcRWZy2zeSNTqmu8vzNSei0xEaLCaQ6PO+pQibxS2VZI/jDLdQ=
+=Gha4
+-----END PGP SIGNATURE-----
diff --git a/fwupd-1.8.6/data/installed-tests/fakedevice124.metainfo.xml b/fwupd-1.8.6/data/installed-tests/fakedevice124.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6b67f36cd37d0861835fdf21bdd8c3abc9e04413
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fakedevice124.metainfo.xml
@@ -0,0 +1,28 @@
+
+
+
+ org.fwupd.fakedevice.firmware
+ FakeDevice
+ Firmware for the ACME Corp Integrated Webcam
+
+
+ Updating the firmware on your webcam device improves performance and
+ adds new features.
+
+
+
+ b585990a-003e-5270-89d5-3705a17f9a43
+
+ http://www.acme.com/
+ CC0-1.0
+ GPL-2.0+
+ ACME Corp
+
+
+
+
+ Fixes another bug with the flux capacitor to prevent time going backwards.
+
+
+
+
diff --git a/fwupd-1.8.6/data/installed-tests/fwupd-tests.xml b/fwupd-1.8.6/data/installed-tests/fwupd-tests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c24bb31695c4532cfc80e889284b418059bad56b
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupd-tests.xml
@@ -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 --git a/fwupd-1.8.6/data/installed-tests/fwupd.sh b/fwupd-1.8.6/data/installed-tests/fwupd.sh
new file mode 100755
index 0000000000000000000000000000000000000000..320ded0d522ce55d5868c62ab47ee5b5b3ac4052
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupd.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+exec 2>&1
+dirname=`dirname $0`
+
+run_test()
+{
+ if [ -f $dirname/$1 ]; then
+ $dirname/$1
+ rc=$?; if [ $rc != 0 ]; then exit $rc; fi
+ fi
+}
+
+run_test acpi-dmar-self-test
+run_test acpi-facp-self-test
+run_test acpi-phat-self-test
+run_test ata-self-test
+run_test nitrokey-self-test
+run_test linux-swap-self-test
+run_test nvme-self-test
+run_test wacom-usb-self-test
+run_test redfish-self-test
+run_test optionrom-self-test
+run_test vli-self-test
+run_test uefi-dbx-self-test
+run_test synaptics-prometheus-self-test
+run_test dfu-self-test
+run_test mtd-self-test
+
+# success!
+exit 0
diff --git a/fwupd-1.8.6/data/installed-tests/fwupd.test.in b/fwupd-1.8.6/data/installed-tests/fwupd.test.in
new file mode 100644
index 0000000000000000000000000000000000000000..b33c85f3b55c5a348d4199eba728268c8f17bc2a
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupd.test.in
@@ -0,0 +1,3 @@
+[Test]
+Type=session
+Exec=sh -c "G_TEST_SRCDIR=@installedtestsdatadir@ G_TEST_BUILDDIR=@installedtestsdatadir@ @installedtestsbindir@/fwupd.sh"
diff --git a/fwupd-1.8.6/data/installed-tests/fwupdmgr-p2p.sh b/fwupd-1.8.6/data/installed-tests/fwupdmgr-p2p.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0fa734fd626c90934a7e03657de9e5b8bfb4e6ae
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupdmgr-p2p.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+set -e
+
+exec 2>&1
+
+# only run as root, possibly only in CI
+if [ "$(id -u)" -ne 0 ]; then exit 0; fi
+
+# ---
+echo "Starting P2P daemon..."
+export FWUPD_DBUS_SOCKET="/run/fwupd.sock"
+rm -rf ${FWUPD_DBUS_SOCKET}
+@libexecdir@/fwupd/fwupd --verbose --timed-exit --no-timestamp &
+while [ ! -e ${FWUPD_DBUS_SOCKET} ]; do sleep 1; done
+
+# ---
+echo "Starting P2P client..."
+fwupdmgr get-devices --json
+rc=$?; if [ $rc != 0 ]; then exit $rc; fi
+
+# ---
+echo "Shutting down P2P daemon..."
+gdbus call --system --dest org.freedesktop.fwupd --object-path / --method org.freedesktop.fwupd.Quit
+
+# success!
+exit 0
diff --git a/fwupd-1.8.6/data/installed-tests/fwupdmgr-p2p.test.in b/fwupd-1.8.6/data/installed-tests/fwupdmgr-p2p.test.in
new file mode 100644
index 0000000000000000000000000000000000000000..63fb215e59ca88af4fbcf906776f87a35c99c602
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupdmgr-p2p.test.in
@@ -0,0 +1,3 @@
+[Test]
+Type=session
+Exec=sh -c "@installedtestsdir@/fwupdmgr-p2p.sh"
diff --git a/fwupd-1.8.6/data/installed-tests/fwupdmgr.sh b/fwupd-1.8.6/data/installed-tests/fwupdmgr.sh
new file mode 100755
index 0000000000000000000000000000000000000000..3d65395ec93fa343e6eccad80d838e07d3327cd8
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupdmgr.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+exec 2>&1
+device=08d460be0f1f9f128413f816022a6439e0078018
+
+error()
+{
+ rc=$1
+ journalctl -u fwupd -b || true
+ exit $rc
+}
+
+# ---
+echo "Getting the list of remotes..."
+fwupdmgr get-remotes
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Enabling fwupd-tests remote..."
+fwupdmgr enable-remote fwupd-tests
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Update the device hash database..."
+fwupdmgr verify-update $device
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Getting devices (should be one)..."
+fwupdmgr get-devices --no-unreported-check
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Testing the verification of firmware..."
+fwupdmgr verify $device
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Getting updates (should be one)..."
+fwupdmgr --no-unreported-check --no-metadata-check get-updates
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Installing test firmware..."
+fwupdmgr update $device -y
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Getting updates (should be none)..."
+fwupdmgr --no-unreported-check --no-metadata-check get-updates
+rc=$?; if [ $rc != 2 ]; then error $rc; fi
+
+# ---
+echo "Testing the verification of firmware (again)..."
+fwupdmgr verify $device
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+if [ -z "$CI_NETWORK" ]; then
+ echo "Skipping remaining tests due to CI_NETWORK not being set"
+ exit 0
+fi
+
+# ---
+echo "Downgrading to older release (requires network access)"
+fwupdmgr downgrade $device -y
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Downgrading to older release (should be none)"
+fwupdmgr downgrade $device
+rc=$?; if [ $rc != 2 ]; then error $rc; fi
+
+# ---
+echo "Updating all devices to latest release (requires network access)"
+fwupdmgr --no-unreported-check --no-metadata-check --no-reboot-check update -y
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# ---
+echo "Getting updates (should be none)..."
+fwupdmgr --no-unreported-check --no-metadata-check get-updates
+rc=$?; if [ $rc != 2 ]; then error $rc; fi
+
+# ---
+echo "Refreshing from the LVFS (requires network access)..."
+fwupdmgr refresh
+rc=$?; if [ $rc != 0 ]; then error $rc; fi
+
+# success!
+exit 0
diff --git a/fwupd-1.8.6/data/installed-tests/fwupdmgr.test.in b/fwupd-1.8.6/data/installed-tests/fwupdmgr.test.in
new file mode 100644
index 0000000000000000000000000000000000000000..20c4347082a17dceeef50419343baa5fa9bf8f77
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/fwupdmgr.test.in
@@ -0,0 +1,3 @@
+[Test]
+Type=session
+Exec=sh -c "@installedtestsdir@/fwupdmgr.sh"
diff --git a/fwupd-1.8.6/data/installed-tests/meson.build b/fwupd-1.8.6/data/installed-tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..be3d5c6d9f9db68a16015dc94e944ee175f644aa
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/meson.build
@@ -0,0 +1,87 @@
+con2 = configuration_data()
+con2.set('installedtestsdir', installed_test_datadir)
+con2.set('installedtestsbindir', installed_test_bindir)
+con2.set('installedtestsdatadir', installed_test_datadir)
+con2.set('bindir', bindir)
+con2.set('libexecdir', libexecdir)
+
+configure_file(
+ input: 'fwupdmgr.test.in',
+ output: 'fwupdmgr.test',
+ configuration: con2,
+ install: true,
+ install_dir: installed_test_datadir,
+)
+
+configure_file(
+ input: 'fwupdmgr-p2p.test.in',
+ output: 'fwupdmgr-p2p.test',
+ configuration: con2,
+ install: true,
+ install_dir: installed_test_datadir,
+)
+
+configure_file(
+ input: 'fwupd.test.in',
+ output: 'fwupd.test',
+ configuration: con2,
+ install: true,
+ install_dir: installed_test_datadir,
+)
+
+configure_file(
+ input: 'fwupdmgr-p2p.sh',
+ output: 'fwupdmgr-p2p.sh',
+ configuration: con2,
+ install: true,
+ install_dir: installed_test_datadir,
+)
+
+install_data([
+ 'fwupdmgr.sh',
+ 'fwupd-tests.xml',
+ ],
+ install_dir: installed_test_datadir,
+)
+
+install_data([
+ 'fwupd.sh',
+ ],
+ install_dir: installed_test_bindir,
+)
+
+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: installed_test_datadir,
+)
+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: installed_test_datadir,
+)
+
+# 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 --git a/fwupd-1.8.6/data/installed-tests/remote.conf.in b/fwupd-1.8.6/data/installed-tests/remote.conf.in
new file mode 100644
index 0000000000000000000000000000000000000000..dca038b3712e200bc073dd641d20d200ddb75cd7
--- /dev/null
+++ b/fwupd-1.8.6/data/installed-tests/remote.conf.in
@@ -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 --git a/fwupd-1.8.6/data/meson.build b/fwupd-1.8.6/data/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..865b20e26113c8eae888cda5fa94c84513756e2d
--- /dev/null
+++ b/fwupd-1.8.6/data/meson.build
@@ -0,0 +1,148 @@
+subdir('bios-settings.d')
+subdir('pki')
+subdir('remotes.d')
+
+if get_option('bash_completion')
+ subdir('bash-completion')
+endif
+
+if get_option('fish_completion')
+ subdir('fish-completion')
+endif
+
+if get_option('tests')
+subdir('device-tests')
+endif
+
+if build_daemon
+subdir('motd')
+endif
+
+if get_option('tests')
+ if build_daemon
+ subdir('installed-tests')
+ endif
+endif
+
+if build_standalone
+ install_data(['daemon.conf'],
+ install_dir: join_paths(sysconfdir, 'fwupd')
+ )
+ plugin_quirks += files([
+ 'power.quirk',
+ 'cfi.quirk',
+ ])
+endif
+
+if get_option('metainfo')
+ custom_target('metainfo',
+ input: 'org.freedesktop.fwupd.metainfo.xml',
+ output: 'org.freedesktop.fwupd.metainfo.xml',
+ command: [
+ python3,
+ join_paths(meson.project_source_root(), 'contrib', 'generate-metainfo.py'),
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ install: true,
+ install_dir: join_paths(datadir, 'metainfo'),
+ )
+ install_data(['org.freedesktop.fwupd.svg'],
+ install_dir: join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps')
+ )
+endif
+
+if build_daemon
+ install_data(['org.freedesktop.fwupd.conf'],
+ install_dir: join_paths(datadir, 'dbus-1', 'system.d')
+ )
+
+ if gudev.found()
+ install_data(['90-fwupd-devices.rules'],
+ install_dir: join_paths(udevdir, 'rules.d')
+ )
+ endif
+
+ if libsystemd.found()
+ con2 = configuration_data()
+ con2.set('libexecdir', libexecdir)
+ con2.set('bindir', bindir)
+ con2.set('datadir', datadir)
+ con2.set('localstatedir', localstatedir)
+ rw_directories = []
+ if not get_option('plugin_uefi_capsule').disabled()
+ rw_directories += ['-/boot/efi', '-/efi/EFI', '-/boot/EFI', '-/boot/grub']
+ 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
+ #pull configuration/cache/state from /etc and /var only if prefix is /usr
+ if get_option('prefix') == '/usr'
+ dynamic_options += 'ConfigurationDirectory=fwupd'
+ dynamic_options += 'StateDirectory=fwupd'
+ dynamic_options += 'CacheDirectory=fwupd'
+ endif
+ if not get_option('plugin_redfish').disabled()
+ dynamic_options += 'RestrictAddressFamilies=AF_NETLINK AF_UNIX AF_INET AF_INET6'
+ else
+ dynamic_options += 'RestrictAddressFamilies=AF_NETLINK AF_UNIX'
+ endif
+ con2.set('dynamic_options', '\n'.join(dynamic_options))
+ con2.set('motd_dir', motd_dir)
+
+ # replace @bindir@
+ if offline.allowed()
+ configure_file(
+ input: 'fwupd-offline-update.service.in',
+ output: 'fwupd-offline-update.service',
+ configuration: con2,
+ install: true,
+ install_dir: systemdunitdir,
+ )
+ endif
+
+ # replace @dynamic_options@
+ configure_file(
+ input: 'fwupd.service.in',
+ output: 'fwupd.service',
+ configuration: con2,
+ install: true,
+ install_dir: systemdunitdir,
+ )
+
+ # for activation
+ configure_file(
+ input: 'fwupd.shutdown.in',
+ output: 'fwupd.shutdown',
+ configuration: con2,
+ install: true,
+ install_dir: systemd_shutdown_dir,
+ )
+ endif
+
+ if libsystemd.found() or elogind.found()
+ 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
+endif
diff --git a/fwupd-1.8.6/data/motd/85-fwupd.motd.in b/fwupd-1.8.6/data/motd/85-fwupd.motd.in
new file mode 100755
index 0000000000000000000000000000000000000000..450d5c7178afe72457bfa85f59e7b4618b2dbe1e
--- /dev/null
+++ b/fwupd-1.8.6/data/motd/85-fwupd.motd.in
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+if [ -f @motd_fullpath@ ]; then
+ cat @motd_fullpath@
+fi
diff --git a/fwupd-1.8.6/data/motd/README.md b/fwupd-1.8.6/data/motd/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5bf48d3fff2d6c2ee3cf6dc425058d0ebd0bc852
--- /dev/null
+++ b/fwupd-1.8.6/data/motd/README.md
@@ -0,0 +1,21 @@
+# Message of the day integration
+
+Message on the day integration is used to display the availability of updates when connecting to a remote console.
+
+It has two elements:
+
+* Automatic firmware metadata refresh
+* Message of the day display
+
+## Automatic firmware metadata refresh
+
+This uses a systemd timer to run on a regular cadence.
+To enable this, run
+
+```shell
+# systemctl enable fwupd-refresh.timer
+```
+
+## Motd display
+
+Motd display is dependent upon the availability of the update-motd snippet consumption service such as pam_motd.
diff --git a/fwupd-1.8.6/data/motd/fwupd-refresh.preset b/fwupd-1.8.6/data/motd/fwupd-refresh.preset
new file mode 100644
index 0000000000000000000000000000000000000000..2aab2d26e44cfc2374903ed6b8b4c5936a0a9d5b
--- /dev/null
+++ b/fwupd-1.8.6/data/motd/fwupd-refresh.preset
@@ -0,0 +1,2 @@
+disable fwupd-refresh.service
+disable fwupd-refresh.timer
diff --git a/fwupd-1.8.6/data/motd/fwupd-refresh.service.in b/fwupd-1.8.6/data/motd/fwupd-refresh.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..d217450e83398cc3d365f9ac0262595e20f1b9a5
--- /dev/null
+++ b/fwupd-1.8.6/data/motd/fwupd-refresh.service.in
@@ -0,0 +1,17 @@
+[Unit]
+Description=Refresh fwupd metadata and update motd
+Documentation=man:fwupdmgr(1)
+After=network-online.target
+
+[Service]
+Type=oneshot
+CacheDirectory=fwupdmgr
+StandardError=null
+@user@
+RestrictAddressFamilies=AF_NETLINK AF_UNIX AF_INET AF_INET6
+SystemCallFilter=~@mount
+ProtectKernelModules=yes
+ProtectControlGroups=yes
+RestrictRealtime=yes
+SuccessExitStatus=2
+ExecStart=@bindir@/fwupdmgr refresh
diff --git a/fwupd-1.8.6/data/motd/fwupd-refresh.timer b/fwupd-1.8.6/data/motd/fwupd-refresh.timer
new file mode 100644
index 0000000000000000000000000000000000000000..c72e05a7311bbb78a824ff4b519b82fd1c0d73d9
--- /dev/null
+++ b/fwupd-1.8.6/data/motd/fwupd-refresh.timer
@@ -0,0 +1,11 @@
+[Unit]
+Description=Refresh fwupd metadata regularly
+ConditionVirtualization=!container
+
+[Timer]
+OnCalendar=*-*-* 6,18:00
+RandomizedDelaySec=12h
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/fwupd-1.8.6/data/motd/meson.build b/fwupd-1.8.6/data/motd/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..d817c010da3b65d6b7cf5c72602dc01b4a921429
--- /dev/null
+++ b/fwupd-1.8.6/data/motd/meson.build
@@ -0,0 +1,45 @@
+
+if libsystemd.found()
+ install_data(['fwupd-refresh.timer'],
+ install_dir: systemdunitdir)
+ install_data(['fwupd-refresh.preset'],
+ install_dir: systemdsystempresetdir)
+ motd_fullpath = join_paths ('/run', motd_dir, motd_file)
+else
+ motd_fullpath = join_paths (localstatedir, motd_dir, motd_file)
+endif
+
+con2 = configuration_data()
+con2.set('bindir', bindir)
+con2.set('motd_fullpath', motd_fullpath)
+
+if libsystemd.found()
+ if get_option('systemd_unit_user') == ''
+ con2.set('user', 'DynamicUser=yes')
+ else
+ dynamic_options = [
+ 'ProtectSystem=strict',
+ 'ProtectHome=read-only',
+ 'User=' + get_option('systemd_unit_user')
+ ]
+ con2.set('user','\n'.join(dynamic_options))
+ endif
+
+ configure_file(
+ input: 'fwupd-refresh.service.in',
+ output: 'fwupd-refresh.service',
+ configuration: con2,
+ install: true,
+ install_dir: systemdunitdir,
+ )
+endif
+
+# This file is only used in Ubuntu, which chooses to use update-motd instead
+# of sourcing /run/motd.d/*
+# See https://bugs.launchpad.net/ubuntu/+source/pam/+bug/399071
+configure_file(
+ input: '85-fwupd.motd.in',
+ output: motd_file,
+ configuration: con2,
+ install: false,
+)
diff --git a/fwupd-1.8.6/data/org.freedesktop.fwupd.conf b/fwupd-1.8.6/data/org.freedesktop.fwupd.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7267fa987d37e478b7b31cc4a6990fb353339268
--- /dev/null
+++ b/fwupd-1.8.6/data/org.freedesktop.fwupd.conf
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fwupd-1.8.6/data/org.freedesktop.fwupd.metainfo.xml b/fwupd-1.8.6/data/org.freedesktop.fwupd.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fa573d90f17a78ef42e17a050a5d332c33788e72
--- /dev/null
+++ b/fwupd-1.8.6/data/org.freedesktop.fwupd.metainfo.xml
@@ -0,0 +1,2529 @@
+
+
+
+ org.freedesktop.fwupd
+ CC0-1.0
+ LGPL-2.0+
+ fwupd
+ Update device firmware on Linux
+
+
+ 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.
+
+
+ The fwupd process is a system 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.
+
+
+ https://github.com/fwupd/fwupd/issues
+ https://fwupd.org/
+ https://www.transifex.com/freedesktop/fwupd/
+ richard_at_hughsie.com
+ fwupd
+
+ moderate
+
+
+ fwupdmgr
+ fwupdtool
+
+
+
+
+
+ This release adds the following features:
+
+
+ Reduce the installed package size by more than 30%
+ Translate more interactive messages
+
+ This release fixes the following bugs:
+
+ Allow disabling a DFU device when required
+ Fix a regression when getting the i2c bus number
+ Fix a small memory leak when reloading the parade-lspcon device
+ Fix installing the dbx update when using fwupdtool
+ Improve writing CoSWID and uSWID metadata
+ Only include the last 5 releases in the installed metainfo file
+ Only request the BOS descriptor for newer libgusb versions
+ Prevent high memory usage when loading corrupt SREC files
+ Try harder when trying to find the default ESP volume
+ Use a higher compression preset for the UEFI splash images
+
+ This release adds support for the following hardware:
+
+ Focaltech touchpads
+ FPC fingerprint readers
+ Supermicro machines using Redfish
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a new android-boot plugin to update specific block devices
+ Add new plugin to display SMU firmware version on AMD APU/CPU
+ Add support for platform capability descriptors so devices can set quirks
+ Move the generic Intel Goshen Ridge code out to a new plugin
+
+ This release fixes the following bugs:
+
+ Allow specifying the ESP when applying the dbx update
+ Always check the BDP partitions when getting all the possible ESPs
+ Correctly update Wacom AES devices
+ Disable changing sleep mode on Ryzen 6000 systems
+ Do not show the 'may not be usable while updating' message for DBX updates
+ Expose Pine64 PinePhone Pro MTD as Tow-Boot
+ Fix a critical warning when issuing Secure Boot modem AT commands
+ Fix a fuzzing crash when parsing malicious FDT data
+ Fix aligning up addresses greater than 4GB
+ Fix a possible crash when dumping VBE firmware
+ Fix a possible critical warning when parsing cabinet archives
+ Fix a regression when parsing pixart-rf firmware
+ Fix a small memory leak when parsing UF2 files
+ Fix checking for invalid depth requirements
+ Fix parsing the coSWID firmware ID when encoded as a UUID
+ Fix parsing uSWID uncompressed metadata
+ Fix uploading to DFU-CSR devices
+ Limit the archive size to 25% of the RAM, or 4G
+ Load coSWID metadata from a uSWID MTD block device
+ Never save the Redfish auto-generated password to a user-readable file
+ Only create users using IPMI when we know it's going to work
+ Write all the CCGX metadata block as intended
+
+ This release adds support for the following hardware:
+
+ Corsair SABRE RGB PRO Gaming mouse
+ More Sonix CAM devices
+ More Intel Goshen Ridge USB-4 docks
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a translated title and long description for HSI security attributes
+ Add support for loading a machine-default BIOS settings policy
+ Add support for reading and writing BIOS settings
+ Allow loading BIOS settings for host emulation
+ Prompt users to fix some BIOS configuration issues
+
+ This release fixes the following bugs:
+
+ Actually show provided AppStream security issues
+ Add Quectel secure boot status AT commands
+ Correctly detect CET IBT
+ Do not assert when running with no plugins
+ Do not require UEFI capsule updates for checking TPM PCR0
+ Do not show HSI events where we changed the spec result value
+ Fix applying the latest DBX update
+ Include vfat in the list of possible BDP partition types
+ Install all devices with the same composite id in fwupdtool
+ Only fail the kernel HSI test for specific taint reasons
+ Only show changed events in fwupdmgr security
+ Update vulnerable CMSE versions from CSMEVDT data
+
+ This release adds support for the following hardware:
+
+ Elan non-HID touchpads
+ Google Prism
+ LabTop Mk III
+ ThinkPad Thunderbolt 4 Dock
+ ThinkPad Universal Smart Dock
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add resolution flags to each security attribute failures for the user
+ Allow loading in emulated host profiles for debugging
+ Check if Intel TME has been disabled by the firmware or platform
+ Wait for the system to acquiesce after doing each update
+
+ This release fixes the following bugs:
+
+ Do not use CoD even when advertized on non-aarch64 platforms
+ Fix a crash when updating the Logitech Bolt radio device
+ Fix a critical warning when parsing an invalid PHAT record
+ Fix a critical warning when parsing invalid FDT firmware
+ Fix fwupdmgr security when plugins are added to the blocklist
+ Fix parsing SMBIOS data to correct the device hardware IDs
+ Fix uploading signed reports by sending the correct checksum
+ Use the correct protocol attribute name when exporting to JSON
+
+ This release adds support for the following hardware:
+
+ Additional Startech devices
+ Additional Elan fingerprint readers
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add startup profiling which allowed us to speed up daemon startup considerably
+ Add support for OptionROM, CPD and FPT firmware formats for future hardware
+ Add the HostVendor to the D-Bus interface
+ Break some internal ABI and add a conversion helper for out-of-tree plugins
+ Optionally build the quirk files into the daemon binary to reduce installed size
+
+ This release fixes the following bugs:
+
+ Allow front-end clients to read the percentage property
+ Allow more quirk entries to add multiple items
+ Allow to force install Genesys firmware even if the public-key does not match
+ Allow UFS disks to define the signed status in metadata
+ Autoconnect the Redfish network device when rebooting the BMC
+ Copy the instance ID strings when incorporating devices
+ Do not generate a capsule header for the FMP GUID
+ Ensure more firmware formats can round-trip to and from XML
+ Fix a regression for devices using the Atmel FLIP Bootloader
+ Fix running fwupdtool security with a user-specified plugin allowlist
+ Handle ENOTTY with the correct error code for ioctl calls
+ Increase the self tests coverage substantially
+ Modernize the AMT plugin and split out common MEI functionality
+ Only move the logitech-bulkcontroller progressbar forwards when writing
+ Set the device ID on the FwupdRequest to allow better UX
+ Show the get-details output when the device requirements fail
+ Simply quirk matching for i2c devices to speed up daemon startup
+ Support SHA256 fastboot hashes if specified
+ Use force-detach to bypass the DFU streaming check for camera devices
+ Use the SCSI target to correctly set the physical ID
+ Wait for the System76 launch device to re-enumerate if already unlocked
+
+ This release adds support for the following hardware:
+
+ Corsair HARPOON RGB Wireless mouse
+ U-Boot devices writing simple FIT images
+ Genesys M27fd AIM101
+ More PixArt wireless devices
+ More Steelseries HID, Sonic and Fizz devices
+ System76 launch_2
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add archive writing support for devices with composite firmware
+ Add a way to read device composite firmware in fwupdtool
+ Allow clients to opt-in to showing updates with user-solvable problems
+ Allow the device to pause polling when writing firmware
+ Export the system and device battery levels on the D-Bus interface
+ Log errors and warnings to the win32 eventlog when required
+ Add X-UsbReceiver as an update category with icon usb-receiver
+
+ This release fixes the following bugs:
+
+ Accurately return the last-set status to client tools
+ Allow dumping flashrom firmware using fwupdtool
+ Allow specifying a non-file D-Bus transport
+ Allow to request post actions from fwupdtool
+ Always be arch-explicit when installing OS deps
+ Be more resilient when restarting the Redfish BMC
+ Do not mark all Redfish updates as UPDATABLE
+ Do not use 'dongle' to describe USB receiver hardware
+ Download in-process when using fwupdtool
+ Fix a critical warning on failed modem update
+ Fix regression when probing PS175 devices
+ Hardcode the Redfish filedata name to firmware.bin
+ Set the Bluetooth version if REV has been set
+ Switch the Windows installer from NSIS to MSI
+ Use StartServiceCtrlDispatcherA for the daemon on Windows
+ Use the native certificate store on Windows
+
+ This release adds support for the following hardware:
+
+ Corsair KATAR PRO XT, SABRE PRO and KATAR PRO Wireless
+ HP Thunderbolt Dock G4
+ Lenovo ThinkPad Universal USB-C Dock
+ More PixArt wireless devices
+ More SunplusIT USB cameras
+ Some UFS devices
+ Steelseries Aerox 3 Wireless and Rival 3 Wireless
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a new attribute for CPUs supported by HSI
+ Add coSWID and uSWID parsers to libfwupdplugin for initial SBoM support
+ Add new HSI attributes for the AMD PSP and various other system protections
+ Add the runtime fwupd-efi version as a firmware requirement
+ Allow 'fwupdmgr install' to install a specified firmware version
+ Allow overriding the detected machine type for debugging and development
+ Restart the BMC after installing BCM updates
+ Show the device serial number and instance IDs by default
+ Support dumping the MTD image to a firmware blob
+ Take a device inhibit when updating a device
+ Use the CFI manufacturer ID to set the vendor
+ Use the correct icon automatically for more hardware
+
+ This release fixes the following bugs:
+
+ Add signed-payload metadata for more devices
+ Allow Capsule-on-Disk to work in more cases
+ Allow quirking the detected flashrom flash size
+ Check for os-release on FWUPD_SYSCONFDIR
+ Check the alignment when parsing raw firmware
+ Check the update protocol exists when checking requirements
+ Convert the build system to use meson tristate features
+ Correctly probe USB-2 hubs with more than 7 ports
+ Do not add the Windows compatibility ID to capsule devices
+ Do not allow the DBX update for specific motherboards
+ Do not expect KernelCmdline on Windows
+ Do not export USB4 host controllers as updatable if they don't have unique GUIDs
+ Do not fallback to audio-card and use a more suitable icon for USB hubs
+ Do not hardcode the libexecdir to /usr/libexec
+ Do not leak child processes when canceling
+ Do not show unconnected or unreachable devices in the client tools
+ Do not throw away the TPM eventlog when uploading to the LVFS
+ Do not use /var/run for the socket
+ Export the version_lowest_raw value correctly
+ Fix build for MacOS and add to the CI matrix
+ Fix eventlog replay for Intel TXT machines
+ Fix several small memory leaks
+ Fix writing large mtd images than 10kb
+ Ignore MTD devices that report EPERM on open
+ Mark the ME region device locked if it is read only
+ Never send the DeviceChanged signal with old data
+ Only show the CLI time remaining for predictable status phases
+ Respect the NO_COLOR env variable
+ Return the correct error when there is no GPIO device to open
+ Support the new UPower PENDING device states
+
+ This release adds support for the following hardware:
+
+ CH341A SPI programmer
+ Corsair Sabre RGB PRO and Slipstream USB receiver
+ Genesys GL3521 and GL3590 hubs
+ Google Servo Dock
+ Logitech M550, M650 and K650
+ More ELAN fingerprint readers
+ More integrated Wacom panels
+ More NovaCustom machines
+ More StaLabs StarLite machines
+ More Tuxedo laptops
+ Quectel EM05
+ FlatFrog devices
+ System76 launch_lite_1
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a flag for UEFI devices that never want a capsule header auto-added
+ Add a flag to indicate the device has a signed or unsigned payload
+ Add a plugin to set a GPIO pin for the duration of an update
+ Add a simple plugin to enumerate (but not update) SCSI hardware
+ Add two more instance IDs to the MTD devices
+ Add X-BaseboardManagementController as an update category
+ Allow assigning issues to devices for known high priority problems
+ Parse the MTD firmware version using the defined GType
+
+ This release fixes the following bugs:
+
+ Check the IFD sections have non-zero data length to fix a critical warning
+ Modify the AT retry behavior to fix getting the firmware branch
+ Do not run fwupd-refresh automatically in containers
+ Do not show a warning if the TPM eventlog does not exist
+ Do not show TSS2 warning messages by default
+ Fix a critical warning when loading an empty TPM eventlog item
+ Fix a logic error when adding the community warning in fwupdmgr
+ Fix loading flashrom devices in coreboot mode
+ Fix the error handling when updating USB4 retimers
+ Show the user when devices are not updatable due to inhibits
+ Skip probing the Dell DA300 device to avoid a warning
+ Try harder to convert to a version into a correct semver
+ Use multiple checksums when there are no provided artifacts
+
+ This release adds support for the following hardware:
+
+ HP M2xfd monitors
+ Star Lite Mk III
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a flag to indicate the firmware is not provided by the vendor
+ Add support for showing dependency versions in JSON format
+ Allow fwupd to operate in socket mode without a D-Bus daemon
+ Allow marking a device as End-of-Life by the OEM vendor
+ Allow specifying the machine Best Known Configuration locally
+ Fall back to the ARM Device Tree 'compatible' data when required
+
+ This release fixes the following bugs:
+
+ Be more robust by retrying IPMI transactions on servers
+ Change the expired Redfish password when required
+ Fix a ModemManager segfault on startup for some MBIM-QDU devices
+ Fix a possible dell-dock segfault at startup
+ Fix compiling with new versions of efivar
+ Fix the Nordic bootloader type detection
+ Fix USB4 retimer enumeration
+ Get the SMBIOS table and host machine ID when running on Windows
+ Show results when calling get-details if failing requirements
+ Uninhibit the modem using ModemManager after upgrade
+
+ This release adds support for the following hardware:
+
+ Future Analogix devices
+ NovaCustom NV4x
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add firmware branch support for ModemManager devices
+ Allow firmware engineers to patch files at known offsets
+ Show why more devices are not marked as updatable
+
+ This release fixes the following bugs:
+
+ Allow fwupdtool to be run as the non-root user in more cases
+ Assign the Logitech bulkcontroller update interface correctly
+ Do not allow UEFI updates when the laptop lid is closed
+ Do not autoload ipmi-si to avoid warning on non-server hardware
+ Do not show a critical warning for a weird TPM event log
+ Fix waiting for USB devices when using Windows
+ Ignore non-PCI NVMe devices
+
+ This release adds support for the following hardware:
+
+ HP USB-C G2 Dock
+ Many UF2 devices, experimentally
+ More PixArt devices
+ Nordic HID devices using MCUBoot
+ Quectel EG25-G LTE Modem
+ ThinkPad Thunderbolt 4 Dock
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a sync-bkc subcommand to ensure a known set of firmware versions
+ Add FuArchiveFirmware for plugins that use archives as firmware files
+ Add quirkable page and sector size properties to FuCfiDevice
+ Make Upower and powerd support optional
+
+ This release fixes the following bugs:
+
+ Add some sanity checks to the elanfp firmware parser
+ Add the CFI JEDEC instance ID if using the vendor-extended version
+ Check the value range when parsing the quirk keys
+ Do not wait for a USB runtime if will-disappear is set
+ Enable the MOTD integration when using pam_motd
+ Fix DFU regression when merging the FuProgress work
+ Fix running the tests when fwupd is not installed
+ Fix the GLib error message when inotify max_user_instances is too low
+ Fix VLI VL820Q7 detection to fix flashing of the Lenovo TBT3 dock
+ Ignore a USB error for STM32 attach when the device goes away
+ Make the HSI tests optional for embedded targets
+ Make the plugin startup order deterministic
+ Set Thunderbolt ports offline on host controller
+ Use endian-safe version functions when enumerating Logitech hardware
+ Use lowercase flag names in intel-spi to prevent a runtime warning
+ Wait for the System76 Launch device to come back from DFU mode
+
+ This release adds support for the following hardware:
+
+ Most Nordic Semiconductor nRF Secure devices
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a new HSI check that PCR registers 0-7 are not empty
+ Add several compile flags to reduce the install size by over 300Kb
+ Allow overriding HwId data from the daemon.conf config file
+ Allow overriding the firmware GType from a quirk file
+ Export the component release ID over DBus
+ Remove support for the SoloKey and ChaosKey devices
+ Show a daemon warning if quirk flags are malformed
+ Speed up the daemon startup by ~40% by doing less at startup
+
+ This release fixes the following bugs:
+
+ Be case insensitive when fixing the device model
+ Fix a critial warning in ccgx found by the fuzzer
+ Fix a DFU crash if the attach failed due to a hardware fault
+ Fix a Redfish crash when specifying a URL without a port
+ Fix CLI downloads when using fwupdmgr --ipfs
+ Fix critical warning when /etc/machine-id does not exist
+ Inhibit thunderbolt devices to correctly use UPDATABLE_HIDDEN
+ Set SSL_VERIFYHOST=0 when using Redfish to fix OpenBMC auth
+ Skip UEFI devices that fail coldplug
+
+ This release adds support for the following hardware:
+
+ All exported MTD block devices
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Allow specifying 'fwupdmgr device-test foo --json' for unattended testing
+ Allow using a filename when using set-approved-firmware
+ Inhibit ModemManager device in mbim-qdu
+ Share the Common Flash Memory Interface quirks between plugins
+ Show changes in HSI attributes when using 'fwupdmgr security'
+ Show the user a warning if updating may affect full-disk-encryption
+ Show translated firmware release notes when provided
+ Support loading remotes from /var/lib/fwupd/remotes.d
+
+ This release fixes the following bugs:
+
+ Fix a CCGX regression when loading firmware
+ Fix a potential crash when dumping Parade devices
+ Fix build error when sys/io.h is not available
+ Fix building the Synaptics RMI self tests on s390x
+ Fix the CSME CVE detection for new generations
+ Handle EPERM when running the self tests on systems with IPMI
+ Mark as SUPPORTED even if on battery power
+ Only save the HSI attributes to the database if different
+ Raise the client timeout value from 25 seconds to fix Redfish startup
+ Redirect the old HSI links to the correct place
+ Relax the ITE SuperIO signature checks for new hardware support
+ Set device time and timezone for logitech bulkcontroller devices
+ Set the verfmt of the returned device when the daemon device is unset
+
+ This release adds support for the following hardware:
+
+ Dell Atomic Dock
+ HP Thunderbolt Dock G4
+ More PixArt devices
+ Steelseries Stratus
+ Wacom 3rd-gen Intuos BT
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add FuCfuPayload and FuCfuOffer for future usage
+ Add support for an 'unreachable' device flag
+ Add support for Logitech devices supporting the Unified Battery feature
+ Allow adding GUIDs to each HSI security attribute
+ Allow installing the LVFS remote, but with it disabled by default
+ Convert security attributes to JSON and write then to the database
+ Convert the device test script to a fwupdmgr subcommand
+ Create Redfish user accounts automatically using IPMI
+ Use an interactive request to restart some Logitech DFU devices
+
+ This release fixes the following bugs:
+
+ Abort on invalid SREC files early to avoid a fuzzing timeout
+ Allow using interrupt transfers for HID devices
+ Allow waiting for multiple devices to replug
+ Fix a critical warning on a Unifying flash failure
+ Fix a regression in flashing the Dell dock
+ Fix Thunderbolt host controller probing
+ Forcefully set checksums found in cabinet files to lowercase
+ Force UX-capsule over full size BGRT
+ Make the SuperIO ports and timeouts specific to the DMI model
+ Only probe SynapticsMST devices that have opted-in
+ Remove support for --ignore-power as it did not work for UEFI firmware
+ Reset the CMOS as required when changing system firmware branch
+ Restart the daemon if any of the the plugin config files are modified
+ Show HSiLevel=0 attributes in JSON security output
+ Update the child composite ID if the parent changes
+ Use a per-device global percentage completion
+ Write the BMP image upside down to avoid using a negative bitmap height
+
+ This release adds support for the following hardware:
+
+ A huge number of Synaptics CAPE devices
+ Elan fingerprint readers
+ Logitech Bolt peripherals, receivers and radio hardware
+ Logitech devices supporting the bulk controller protocol
+ More supported PixArt devices
+ More supported StarBook coreboot devices
+ Union Point SPI hardware
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add a plugin to check Lenovo firmware settings
+ Add initial support for the powerd daemon
+ Add support for CapsuleOnDisk
+ Add support for installing UEFI updates from GRUB
+ Add support for soft-requirements that can be ignored with --force
+ Allow devices to only accept version upgrades
+ Allow discovery of Redfish BMCs specified by VID-PID or MAC
+ Allow the daemon to request interactive action from the end user
+ Automatically connect the BMC network interface at startup
+ Show the build timestamp if set on the device
+ Show the user how to switch out of Wacom tablet Android-mode
+
+ This release fixes the following bugs:
+
+ Add the alternate vendor name into the 8BitDo allowlist
+ Allow multiple devices to set WAIT_FOR_REPLUG
+ Allow the client to watch for more property changes
+ Always ensure the SuperIO version string is NUL terminated
+ Automatically clear the update error as required
+ Disable all UX capsules for Lenovo hardware
+ Do not assume the metainfo file is NUL-terminated
+ Do not save invalid files on LVFS server error
+ Fix a VLI regression in enumerating the PD device
+ Fix a VLI regression when installing VL820Q7 firmware
+ Fix enumeration of the Synaptics Prometheus config child
+ Fix parsing Redfish USB/PCI network VID/PIDs
+ Fix the fwupdmgr progressbar spinner to actually work
+ Fix version number for legacy Wacom Bluetooth modules
+ Ignore virtual M.2 ATA devices
+ Preserve NEEDS_REBOOT on successful update
+ Prevent a corrupt PHAT table from allocating lots of memory
+ Read the Redfish SMBIOS table when required
+ Remove the vendor string from the device name where required
+ Save the update state to the database correctly all of the time
+ Switch from sysctl to ioctl for ESRT on FreeBSD
+ Try reading from /sys/class/dmi if SMBIOS direct access fails
+ Watch for children added or removed after setup has been completed
+ Work around a XCC-ism on Lenovo hardware
+
+ This release adds support for the following hardware:
+
+ ModemManager devices supporting Firehose or MBIM QDU
+ More models of RTS54HUB
+ More Poly DFU devices
+ Parade LSPCON
+ PixArt receiver and wireless hardware
+ Realtek MST with RTD2142
+ SuperIO IT5570
+ USB4 Dell dock
+
+
+
+
+
+
+ This release adds the following features:
+
+
+ Add FreeBSD UEFI Capsule support
+ Add generic ModemManager support for PCI based modems
+ Add initial support for USB4 module in the Dell dock
+ Add support for sibling requirements
+ Add support for the ACPI PHAT table
+ Allow building the documentation with gi-docgen and gtk-doc
+ Support binary artifact resources in cabinet archives
+ Use GProxyResolver to get the system proxy setting for a given URL
+
+ This release fixes the following bugs:
+
+ Ask the user to confirm all CLI actions
+ Check the versions of libfwupd and libfwupdplugin at startup
+ Do not prevent firmware updates on desktop hardware
+ Do not show an invalid DFU warning on attach
+ Fail parsing if wacom firmware sections are not in sorted order
+ Fall back to binary files when flashing STM32 hardware
+ Fix a critical warning when downloading files
+ Fix a possible critical warning due to a bug in type casting
+ Fix a regression in updating the WD19TB dock
+ Fix GUID generation on pixart hardware
+ Fix the VLI i2c device enumeration, e.g. MSP430
+ Follow HTTP 3XX redirects when downloading files
+ Force the device locker to close() an aborted open()
+ Handle bsdisks' UDisks2 implementation on FreeBSD
+ Only lock fwupdtool when loading the engine
+ Read current Wacom firmware index before finding image to write
+ Support all hash types when loading cabinet archives
+ Support mirroring the detach and update images
+ Switch lock directory from /var/run to /run/lock
+
+ This release adds support for the following hardware:
+
+ Minibons devices
+ More 8BitDo hardware
+ More Synaptics Prometheus hardware
+ RTD21xx devices in background mode
+ Some Kingston SSD and NVMe hardware
+
+
+
+
+
+
+ This is the first release of the 1.6.x series, and since 1.5.x
+ some internal plugin API has been changed and removed.
+ Although we've tested this release on all the hardware we have
+ regression tests for, bugs may have crept in; please report failures
+ to the issue tracker as required.
+
+
+ There are several new plugins adding support for new hardware
+ and a lot of code has been migrated to the new plugin API.
+ The public libfwupd API also has some trivial additions, although no
+ action is required.
+
+
+ This release adds the following features:
+
+
+ Add a composite ID that is used to identify dock device components
+ Add an Intel Flash Descriptor parser
+ Add API to allow the device to report its own battery level
+ Add API to recount why the the device is non-updatable
+ Add lspcon-i2c-spi programmer support
+ Add more hardware support to the pixart-rf plugin
+ Add some more new category types for firmware to use
+ Add support for downloading the SPI image from the Intel eSPI device
+ Add support for some Analogix hardware
+ Add support for writing SREC firmware
+ Add the firmware-sign command to fwupdtool to allow resigning archives
+ Split UEFI EFI binary into a subproject
+ Use an OFD or Unix lock to prevent more than one fwupdtool process
+
+ This release fixes the following bugs:
+
+ Actually write the bcm57xx stage1 version into the file
+ Add option to disable the UEFI capsule splash screen generation
+ Avoid use-after-free when specifying the VID/PID in dfu-tool
+ Cancel the GDBusObjectManager operation to fix a potential crash
+ Check PixArt firmware compatibility with hardware before flashing
+ Do not check for native dependencies as target dependencies
+ Do not use help2man to build manual pages
+ Fix a crash when shutting down the daemon
+ Fix build on musl
+ Fix build when using BSD
+ Fix /etc/os-release ID_LIKE field parsing
+ Force the synaptics-rmi hardware into IEP mode as required
+ Never allow D-Bus replacement when a firmware update is in operation
+ Offer the user to refresh the remote after enabling
+ Remove unused, unsafe and deprecated functions from libfwupdplugin
+ Simplify asking the user about reviews
+ Write BMP data directly without using PIL
+ Write synaptics-rmi files with valid checksum data
+
+
+
+
+
+ This release adds the following features:
+
+ Add initial support for Bluez bluetooth devices
+ Add more supported pixart devices
+ Add support for the RTD21xx HDMI converter
+
+ This release fixes the following bugs:
+
+ Convert MBR types to GPT GUIDs to help find the ESP
+ Do not allow updating a synaptics-mst device with no customer ID
+ Drop unused heap pages after startup has completed
+ Ensure SBAT metadata is added correctly
+ Move the plugin build logic to the plugins themselves
+ Only allow verify-update for plugins that support CAN_VERIFY
+
+
+
+
+
+ This release adds the following features:
+
+ Add SBAT metadata to the fwupd EFI binary
+ Add support for GD32VF103 as found in the Longan Nano
+ Add support for RMI PS2 devices
+ Add support for the System76 Keyboard
+ Allow downloading firmware from IPFS
+ Install the UX data into a single .tar.xz file
+
+ This release fixes the following bugs:
+
+ Add support for the Starlabs LabTop L4
+ Allow using an external ESP again
+ Ask the user to reboot when required if downgrading
+ Be more paranoid when parsing ASCII buffers and devices
+ Check if the fwupd BootXXXX entry exists on failure
+ Clear the pending flag if restarting the system
+ Do not allow flashing using flashrom if BLE is enabled
+ Do not allow Lenovo hardware to install multiple capsules
+ Do not parse the OptionROM image
+ Do not show Unknown [***] for every client connection
+ Fix dnload wBlockNum wraparound for ST devices
+ Fix OOM when using large ArchiveSizeMax values
+ Fix several crashes spotted by AddressSanitizer
+ Fix several places where the Goodix MOC plugin could crash
+ Include the PCR0 to the report metadata
+ Report the lockdown status from UEFI and SuperIO plugins
+ Show a console warning if the system clock is not set
+
+
+
+
+
+ This release adds the following features:
+
+ Add a plugin to update PixArt RF devices
+ Add new hardware to use the elantp and rts54hid plugins
+ Allow specifying more than one VendorID for a device
+ Detect the AMD TSME encryption state for HSI-4
+ Detect the AMI PK test key is not installed for HSI-1
+
+ This release fixes the following bugs:
+
+ Fix flashing a fingerprint reader that is in use
+ Fix several critical warnings when parsing invalid firmware
+ Fix updating DFU devices that use DNLOAD_BUSY
+ Ignore the legacy UEFI OVMF dummy GUID
+ Make libfwupd more thread safe to fix a crash in gnome-software
+ Never show unprintable chars from invalid firmware in the logs
+
+
+
+
+
+ This release adds the following features:
+
+ Add Maple Ridge Thunderbolt firmware parsing support
+ Add --no-remote-check to ignore checking for download remotes
+ Allow creating FMAP and Synaptics firmware using builder.xml
+ Build a test harness that uses honggfuzz to fuzz firmware
+
+ This release fixes the following bugs:
+
+ Allow using fwupdtool as non-root for firmware commands
+ Do not trust the Block.HintSystem boolean for ESP filtering
+ Fix a memory leak when parsing Synaptics firmware
+ Fix a possible crash when reading the Goodix MOC USB request
+ Fix crashes when parsing invalid FMAP, DMC, Solokey and Synaptics images
+
+
+
+
+
+ This release adds the following features:
+
+ Allow setting the GMainContext when used for sync methods
+ Export the driver name from FuUdevDevice
+
+ This release fixes the following bugs:
+
+ Add a UEFI quirk for Star Labs Lite Mk III
+ Add the device firmware ID for serio class hardware
+ Allow the client to send legacy PKCS7 and GPG signatures
+ Do not use accidentally depend on new meson versions
+ Fix a possible critical warning due to missing retval
+ Fix the endianness for the CRC check in bcm57xx
+ Lower the CURL version required to fix RHEL
+ Make sure the correct interface number is used for QMI
+ Mark more user-visible strings as translatable
+ Restrict loading component types of firmware
+ Validate ModemManager firmware update method combinations
+
+
+
+
+
+ This release adds the following features:
+
+ Add a flag to indicate if packages are supported
+ Add a plugin for the Pinebook Pro laptop
+ Allow components to set the icon from the metadata
+ Switch from libsoup to libcurl for downloading data
+
+ This release fixes the following bugs:
+
+ Fall back to FAT32 internal partitions for detecting ESP
+ Fix detection of ColorHug version on older firmware versions
+ Fix reading BCM57XX vendor and device ids from firmware
+ Fix replugging the MSP430 device
+ Fix sync method when called from threads without a context
+ Ignore an invalid vendor-id when adding releases for display
+ Improve synaptics-mst reliability when writing data
+ Install modules-load configs in the correct directory
+ Notify the service manager when idle-quitting
+ Only download the remote metadata as required
+ Remove HSI update and attestation suffixes
+ Restore recognizing GPG and PKCS7 signature types in libfwupd
+ Set the SMBIOS chassis type to portable if a DT battery exists
+
+
+
+
+
+ This release adds the following features:
+
+ Include the amount of NVRAM size in use in the LVFS failure report
+
+ This release fixes the following bugs:
+
+ Delete unused EFI variables when deploying firmware
+ Fix probe warning for the Logitech Unifying device
+ Make bcm57xx hotplug more reliable
+ Recognize authorized thunderbolt value of 2
+ Remove the duplicate parent-child data in FwupdDevice and FuDevice
+ Show a less scary fwupdate output for devices without info
+ Show a link to discover more information about a specific plugin failure
+ Use a different Device ID for the OptionROM devices
+ Use UDisks to find out if swap devices are encrypted
+
+
+
+
+
+ This release adds the following features:
+
+ Add a compatible re-implementation of the rhboot dbxtool
+ Add async versions of the library for GUI tools
+ Add commands for interacting with the ESP to fwupdtool
+ Add firmware-extract subcommand to fwupdtool
+ Add FwupdPlugin so we can convey enumerated system errors to the end user
+ Add plugin for Goodix fingerprint sensors
+ Add plugin that can update the BCM5719 network adapter
+ Add plugin to update Elan Touchpads using HID
+ Add support for a delayed activation flow for Thunderbolt
+ Add support for ChromeOS Quiche and Gingerbread
+ Add support for Hyper hardware
+ Add support for the Host Security ID
+ Add support for ThunderBolt retimers
+ Add switch-branch command to fwupdtool and fwupdmgr
+ Allow blocking specific firmware releases by checksum
+ Allow constructing a firmware with multiple images
+ Allow firmware to require specific features from front-end clients
+ Allow updating the dbx using the LVFS, validating it is safe to apply
+ Include the HSI results and attributes in the uploaded report
+ Support loading DMI data from DT systems
+ Support LVFS::UpdateImage for GUI clients
+
+ This release fixes the following bugs:
+
+ Allow compiling the daemon without polkit support
+ Always look at all TPM eventlog supported algorithms
+ Change all instances of master/slave to initiator/target
+ Correctly order devices when using logical parents
+ Do not dedupe NVMe or VLI PD devices
+ Do not expose the VLI shared-SPI devices on the USB2 recovery device
+ Do not fix up the version on post-update mismatch
+ Download the metadata first when using 'fwupdtool refresh'
+ Drop efivar dependency
+ Drop support for ThunderBolt force power due to hardware issues
+ Fix setting BootNext correctly when multiple updates are scheduled
+ Fix the topology of the audio device on the Lenovo TR dock
+ Make return code different for get-updates with no updates
+ Make specific authorizations also imply others
+ Make TPM support more optional
+ Parse the HEX version before comparing for equality
+ Prevent dell-dock updates to occur via synaptics-mst plugin
+ Record the UEFI failure in more cases
+ Retry the HID SetReport to fix flashing the TB3 dock
+ Show an error when a plugin is missing dependencies
+ Use libxmlb bound parameters to speed up the device verification
+ Use pkttyagent to request user passwords if running without GUI
+ Use the JCat file to select the metadata file
+
+
+
+
+
+ This release adds the following features:
+
+ Allow adding a device 'proxy' device that can do actions on it
+ Allow specifying the device on the command line by GUID
+
+ This release fixes the following bugs:
+
+ Add a device quirk that forces an explicit device-id match
+ Allow a device to set the logical or physical ID during ->setup()
+ Correctly format firmware version of Dynabook X30 and X40
+ Do not show safe mode errors for USB4 host controllers
+ Do not show the USB 2 VLI recovery devices for USB 3 hubs
+ Fix the correct DeviceID set by GetDetails
+ Make the EP963X plugin actually work on real hardware
+ Make the tss2-esys dep conditional for RHEL 8
+ Only update the FW2 partition of the ThinkPad USB-C Dock Gen2
+ Prefer to update the child device first if the order is unspecified
+ Refresh device name and format before setting supported flag
+ Reset the progressbar time estimate if the percentage is invalid
+ Set the CCGX device name and summary from quirk files
+ Wait for the cxaudio device to reboot after writing firmware
+
+
+
+
+
+ This release adds the following features:
+
+ Add 'firmware-convert' subcommand to fwupdtool
+ Add fu_device_retry() API
+ Add FuHidDevice abstraction
+ Add plugin for CPU microcode
+ Add plugin for Cypress CCGX hardware
+ Add plugin for EP963x hardware
+ Add 'reinstall' command to fu-tool
+ Allow server metadata to set the device name and version format
+ Export the device state as part of the D-Bus interface
+ Export the release creation time and urgency
+ Introduce a new VersionFormat of 'hex'
+ Use Jcat files in firmware archives and for metadata
+
+ This release fixes the following bugs:
+
+ Actually reload the DFU device after upgrade has completed
+ Add a lot of missing metadata about wacom-usb devices
+ Add a way to set the device timeout from a quirk
+ Add STM32F745 DfuSe version quirk
+ Allow waiting for the parent device when replugging
+ Always check for 'PLAIN' when doing vercmp() operations
+ Apply version format to releases and devices at same time
+ Check the firmware requirements before adding 'SUPPORTED'
+ Correctly attach VL103 after a firmware update
+ Do not allow devices that have no vendor ID to be 'UPDATABLE'
+ Do not conditionalize attach() and detach() on 'IS_BOOTLOADER'
+ Do not use shim for non-secure boot configurations
+ Fix a crash when removing device parents
+ Fix a difficult-to-trigger daemon hang when replugging devices
+ Fix a runtime error when detaching MSP430
+ Fix CounterpartGuid when there is more than one supported device
+ Fix reporting Synaptics cxaudio version number
+ Load the signature to get the aliased CDN-safe version of the metadata
+ Never add USB hub devices that are not upgradable
+ Only auto-add counterpart GUIDs when required
+ Parse the CSR firmware as a DFU file
+ Set the protocol when updating logitech HID++ devices
+ When TPM PCR0 measurements fail, query if secure boot is available and enabled
+
+
+
+
+
+ This release adds the following features:
+
+ Added completion script for fish shell
+ Inihbit all power management actions using logind when updating
+
+ This release fixes the following bugs:
+
+ Always check for PLAIN when doing vercmp() operations
+ Always return AppStream markup for remote agreements
+ Apply UEFI capsule update even with single valid capsule
+ Check the device protocol before de-duping devices
+ Copy the version and format from donor device in get-details
+ Correctly append the release to devices in `fwupdtool get-details`
+ Decrease minimum battery requirement to 10%
+ Discard the reason upgrades aren't available
+ Do not fail loading in /etc/machine-id is not available
+ Fix a critical warning when installing some firmware
+ For the `get-details` command make sure to always show devices
+ Set the MSP430 version format to pair
+ Switch off the ATA verbose logging by default
+ Use unknown for version format by default on get-details
+
+
+
+
+
+ This release adds the following features:
+
+ Add an extra instance ID to disambiguate USB hubs
+ Add a plugin to update PD controllers by Fresco Logic
+ Replay the TPM event log to get the PCRx values
+
+ This release fixes the following bugs:
+
+ Fix updating Synaptics MST devics with no PCI parent
+ Correctly reset VL100 PD devices
+ Do not rewrite BootOrder in the EFI helper
+ Do not use vercmp when the device version format is plain
+ Fix firmware regression in the EFI capsule helper
+ Ignore Unifying detach failures
+ Make the cxaudio version match that of the existing Windows tools
+ Set up more parent devices for various Lenovo USB hubs
+ Support the new gnuefi file locations
+ Use the correct command to get the VLI device firmware version
+
+
+
+
+
+ This release adds the following features:
+
+ Add 'get-remotes' and 'refresh' to fwupdtool
+ Add support for standalone VIA PD devices
+ Allow applying all releases to get to a target version
+ Discourage command line metadata refreshes more than once per day
+ Generate a win32 setup binary
+ Get the list of updates in JSON format from fwupdagent
+ Move MOTD population into the daemon
+ Shut down automatically when there is system memory pressure
+
+ This release fixes the following bugs:
+
+ Correctly delete UEFI variables
+ Correctly import PKCS-7 remote metadata
+ Disable the battery percentage checks if UPower is unavailable
+ Do not always get the vendor ID for udev devices using the parent
+ Fix display of UTF-8 characters on Windows
+ Show the device parent if there is an interesting child
+ Use a different protocol ID for VIA i2c devices
+ Use the correct timeout for Logitech IO channel writes
+
+
+
+
+
+ This release adds the following features:
+
+ Add a new plugin that can parse the TPM event log
+ Add a new plugin that exposes the TPM device firmware version
+ Allow building on Windows with MinGW
+ Enforce that device protocol matches the metadata value
+ Export the device protocol and raw device version to the client --verbose output
+
+ This release fixes the following bugs:
+
+ Add a dell-bios version format to match what is shown on the vendor website
+ Allow incremental version major and minor number for Synaptics Prometheus devices
+ Clarify error messages when no upgrades are available
+ Correct the default prompt for reboot/shutdown
+ Do not expose bootloader version errors to users
+ Fix the quirk for the legacy VIA 813 usbhub chip
+ Hardcode the vendor ID for Dell dock hardware
+ Only check the vendor ID if the device has one set
+ Return exit status success if there is no firmware to be updated
+ Set the correct vendor eMMC ID prefix
+ Use the baseboard vendor as the superio vendor ID
+ Use the BIOS vendor as the coreboot and flashrom vendor ID
+
+
+
+
+
+ This release adds the following features:
+
+ Convert libfwupdprivate to a shared library libfwupdplugin
+ Create a REV_00 instance ID as this may be what the vendor needs to target
+
+ This release fixes the following bugs:
+
+ Improve coreboot version detection
+ Invert default behavior to be safer for reboot and shutdown prompts
+ Reload the Synaptics prometheus device version after update
+ Use the correct unlocker when using GRWLock
+ Whitelist VIA USB hub PD and I²C devices
+
+
+
+
+
+ This release adds the following features:
+
+ Add a new property Interactive to the daemon
+ Add a new script for installing a Dell BIOS from an EXE file
+ Add support for Foxconn T77W968 and DW5821e eSIM
+ Add support for matching firmware requirements on device parents
+ Add support for writing VIA PD and I2C devices
+ Add versions formats for the Microsoft Surface devices
+
+ This release fixes the following bugs:
+
+ Allows confined snaps to activate fwupd via D-Bus
+ Correct Wacom panel HWID support
+ Don't assume all udev devices have device_file
+ Dynamically determine release version
+ Fall back to `ID_LIKE` when the path for `ID` doesn't exist
+ Fix a fastboot regression when updating modem firmware
+ Fix regression when coldplugging superio devices
+ Fix the linking of the UEFI update binary
+ Fix the vendor id of hidraw devices
+ Make loading USB device strings non-fatal
+ Reject invalid Synaptics MST chip IDs
+ Skip cleanup after device is done updating if required
+
+
+
+
+
+ This release adds the following features:
+
+ Add a plugin for systems running coreboot
+ Add a plugin to update eMMC devices
+ Add a plugin to update Synaptics RMI4 devices
+ Add a plugin to update VIA USB hub hardware
+ Add some success messages when CLI tasks have completed
+ Add support for automatically uploading reports
+ Add support for `fwupdmgr reinstall`
+ Allow fwupdtool to dump details of common firmware formats
+ Use XMLb to query quirks to reduce the RSS when running
+
+ This release fixes the following bugs:
+
+ Add several quirks for Realtek webcams
+ Add support for the 8bitdo SN30Pro+
+ Add support for the ThinkPad USB-C Dock Gen2 audio device
+ Always report the update-error correctly for multiple updates
+ Create a unique GUID for the Thunderbolt controller path
+ Fix a regression for Wacom EMR devices
+ Move the Jabra-specific detach out into its own plugin
+ Recognize new 'generation' Thunderbolt sysfs attribute for USB4
+ Reduce more boilerplate in plugins, modernizing where required
+ Remove unused DFU functionality
+ Rework ESP path detection and lifecycle to auto-unmount when required
+ Show a useful error for Logitech devices that cannot self-reset
+ Use correct method for stopping systemd units
+ Use device safety flags to show prompts before installing updates
+ Use `genpeimg` to mark ASLR and DP/NX on EFI binary
+ Use will-disappear flag for 8bitdo SF30/SN30 controllers
+
+
+
+
+
+ This release adds the following features:
+
+ Add a plugin to detach the Thelio IO board
+ Add a plugin to update Conexant audio devices
+ Support issues in AppStream metadata
+
+ This release fixes the following bugs:
+
+ Align the key values to the text width not the number of bytes
+ Display more helpful historical device information
+ Do not ask the user to upload a report if ReportURI is not set
+ Do not crash when starting tpm2-abrmd
+ Ensure HID++ v2.0 peripheral devices get added
+ Fall back to /var/lib/dbus/machine-id when required
+ Include all GUIDs when uploading a report
+ Move D-Bus conf file to datadir/dbus-1/system.d
+ Update device_modified in sql database during updates
+
+
+
+
+
+ This release adds the following features:
+
+ Add support for the Minnowboard Turbot
+ Add support for the SoloKey Secure
+ Add support for thunderbolt kernel safety checks
+ Add support to integrate into the motd
+ Allow filtering devices when using the command line tools
+ Allow setting custom flags when using fwupdate
+ Allow specifying a firmware GUID to check any version exists
+ Include the kernel release as a runtime version
+ Print devices, remotes, releases using a tree
+ Publish docs to fwupd.github.io using CircleCI
+
+ This release fixes the following bugs:
+
+ Add aliases for get-upgrades and upgrade
+ Allow disabling SSL strict mode for broken corporate proxies
+ Be more accepting when trying to recover a failed database migration
+ Do not segfault when trying to quit the downgrade selection
+ Fix a possible crash when stopping the fwupd service
+ Fix incomplete hex file parsing in unifying plugin
+ Fix thunderbolt logic to work properly with ICL thunderbolt controller
+ Never show AppStream markup on the console
+ Never use memcpy() in a possibly unsafe way
+ Only write the new UEFI device path if different than before
+ Partially rewrite the Synapticsmst plugin to support more hardware
+ Reload metadata store when configuration changes
+ Use environment variables for systemd managed directories
+ Use tpm2-tss library to read PCR values
+
+
+
+
+
+ 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 required 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:
+
+ Blocklist 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 an external power source
+ 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 blocklist 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 blocklist 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 blocklist
+ 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 --git a/fwupd-1.8.6/data/org.freedesktop.fwupd.service.in b/fwupd-1.8.6/data/org.freedesktop.fwupd.service.in
new file mode 100644
index 0000000000000000000000000000000000000000..53f5171093fd64ca038599fa1f2a0ac877e1fe57
--- /dev/null
+++ b/fwupd-1.8.6/data/org.freedesktop.fwupd.service.in
@@ -0,0 +1,7 @@
+[D-BUS Service]
+Name=org.freedesktop.fwupd
+Documentation=https://fwupd.org/
+Exec=@libexecdir@/fwupd/fwupd
+User=root
+SystemdService=fwupd.service
+AssumedAppArmorLabel=unconfined
diff --git a/fwupd-1.8.6/data/org.freedesktop.fwupd.svg b/fwupd-1.8.6/data/org.freedesktop.fwupd.svg
new file mode 100644
index 0000000000000000000000000000000000000000..82a4b4b50721608d6f7fc70da609ca43bd14114d
--- /dev/null
+++ b/fwupd-1.8.6/data/org.freedesktop.fwupd.svg
@@ -0,0 +1,209 @@
+
+
+
+ Adwaita Icon Template
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+ GNOME Design Team
+
+
+
+
+ Adwaita Icon Template
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ fwupd
+ firmware updater
+
diff --git a/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Foundation-Firmware b/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Foundation-Firmware
new file mode 100644
index 0000000000000000000000000000000000000000..e03bf682cd19c09f7655b7f12fbaf246b7738bbc
--- /dev/null
+++ b/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Foundation-Firmware
@@ -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 --git a/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Foundation-Metadata b/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Foundation-Metadata
new file mode 100644
index 0000000000000000000000000000000000000000..9ecdb0d08240ced9e96b4f507b2f09e43ee8c177
--- /dev/null
+++ b/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Foundation-Metadata
@@ -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 --git a/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Vendor-Firmware-Service b/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Vendor-Firmware-Service
new file mode 100644
index 0000000000000000000000000000000000000000..dda1c3f4795f0aada2800741a8accd6574a13aeb
--- /dev/null
+++ b/fwupd-1.8.6/data/pki/GPG-KEY-Linux-Vendor-Firmware-Service
@@ -0,0 +1,19 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mQENBFWt/98BCADZ4+lUHSp4OMlzVf4HlJNLJ7Ks5QxGwL/hy2wChoNLuA/j4GNM
+9mBZutKynYmphD0Mi4XjXn7JNXyuJa8Qutz98/Iyhsjq4LeiL9ayaKMXT+3pKlTm
+Gd/Fzo3QEOqTJ5s2RamrfwFIVuvwoj+rNmzj5fUCgoDOZeqVl6gxb7ZPzL8sWTOU
+iLeGMSzZBGE0ioJ82PZzsHelrrObDP1mMre1jQ6zxLlnYUlLvtJpydAfeBxU+6yL
+fgPeoFeuCE6JIszyWuyAgpBpYSGgj1bpt9Sxc2+MoZ0BjDzoijZqt4O48gYuEaLf
+iqYzQybe1JF0McO4C0dmjdKQz2qm0XrQyNhVABEBAAG0LkxpbnV4IFZlbmRvciBG
+aXJtd2FyZSBTZXJ2aWNlIDxzaWduQGZ3dXBkLm9yZz6JATcEEwEIACEFAlWt/98C
+GwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQSKbYDkU4usJjjQgAzmTcA8qH
+s+1kieEZvsUzH4wun2Hlz7R5FRc/7BijgIQAA9TTrJnwbJmEBzEvHv7FKQLiBN3a
+0lQIZgahmcUt1qm6VW94VAio+SDCdqTx73wUsgM3t9sAwKxkEdJQQoO8PqYHV3uK
+rq0t2YjXglIBHRDiJlOTAR3if37OCDKCcHOOODqYrsN7wNleez+ulkDyP7C7ZTbm
+/A7Xec73t2OQUnejU0uvRvc7VSnQDRFBHA9TPiBhbruMw+ZX+z/wfPd7x2RCqoOE
+vHh+QofE41Ya2QOkT96fAKfcJ+gvIbmwp3w7h+Hus1h3xDrykCG9cCxuH0HxooVI
+XL3IlFx/6OUpBA==
+=6Dz2
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/fwupd-1.8.6/data/pki/LVFS-CA.pem b/fwupd-1.8.6/data/pki/LVFS-CA.pem
new file mode 100644
index 0000000000000000000000000000000000000000..560c037b487cde0a2842203158894317d30f0033
--- /dev/null
+++ b/fwupd-1.8.6/data/pki/LVFS-CA.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqjCCAxKgAwIBAgIBATANBgkqhkiG9w0BAQsFADA6MRAwDgYDVQQDEwdMVkZT
+IENBMSYwJAYDVQQKEx1MaW51eCBWZW5kb3IgRmlybXdhcmUgUHJvamVjdDAeFw0x
+NzA4MDEwMDAwMDBaFw00NzA4MDEwMDAwMDBaMDoxEDAOBgNVBAMTB0xWRlMgQ0Ex
+JjAkBgNVBAoTHUxpbnV4IFZlbmRvciBGaXJtd2FyZSBQcm9qZWN0MIIBojANBgkq
+hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAtfUXH3NwDJzWyhkPyPcFI899+tPZ/SMp
+OkDtRr9dJjgQkSO9jKCue4DVq8Bd9RcL76F7XnEKG0LiuKnr+D7+x86TtDAPCbkP
+WAS7fAaetLtiNFU96cokhjeALB3hyamkMQnCw+5Ov+sHJfGI9Bor9UaIIbIB4r8v
+oU1WpE7N6Ix2qsS5b88+Z6EIV6CX8RbciOC/TfyYVnpF1cd4l7LH7TtL+ERpsPwv
+rk0JgVoRzG3BT5yYfuxHIe4H4Axh95tW9i6urzyQkXRz14twwwcEDvl5ALrBLNJJ
+8EDz9oR8HBPbxbd4i2dBfziY7TW4o/VgZKTGWA39JfwWNc5RxaYzBhBmg5nRcVFs
+E7PlovhyFH/0RNm/3E6vZQCeM+FNps0ovVq8Yqg8whL/yZ0iNlavCGTWhaxisVHG
+7mQopV4jZlafxvrcBFzK8RPe8Gi04FFn4ugZtJnOuMel+AiADhgtWZCENiyWV+V7
+WF1SFF4HaHuS8qqna/p9lrpVq6TBr0WRAgMBAAGjgbowgbcwEgYDVR0TAQH/BAgw
+BgEB/wIBATAwBgNVHREEKTAnhhVodHRwOi8vd3d3LmZ3dXBkLm9yZy+BDnNpZ25A
+Znd1cGQub3JnMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA8GA1UdDwEB/wQFAwMHBgAw
+HQYDVR0OBBYEFLGN6uQjp34JjrXuMeBq3Z40N2WsMCoGA1UdHwQjMCEwH6AdoBuG
+GWh0dHA6Ly93d3cuZnd1cGQub3JnL3BraS8wDQYJKoZIhvcNAQELBQADggGBABNK
+mC4AcqsBCVRGpwJeUymh5G6uUpzkoEDw+y9TEoWzfldV0epU7ruqI2p8B8YshDK6
++D4CFmCnW8cc+Jb6jrJ2ZcjUqWE/c+uwZhwsUHNdk6ummPPKfMhRSbduk1ngdQe5
+meIgWGkoCfJ48GUAVVD6MlrMTNFsot1GN9x3ALMqhSU49+X43yikcc9WY2F8JOY8
+xYpGpgUQV1hBSPOGK4XhgztpFLqw0GxJiLrOfKjtJwSTkxGCpPi2dLS0huk/mreT
+NAQ5FnMLkoqfR1RGga3tiP5w13gqDBV7a6MYMdmMfAAZhfRtlDu6SiAmjEmlSkOK
+PNhdoCNVDQLQpGaKZUI5hjMfR90U8Cm/6e0ondwjV4J6f4CS4wkQ5zzITGWptagE
+01tpgTXf7TLaFGtzR8cl8XgV+UO3T4DQjEQkXUaS7n72ZCGv/s4LraLunhBrVHSq
+glEXpU/V/JNptgArIiRFZOrto52cUnnlNEfgqIzAHv/LMFRIkMo8ZMGTgScFrA==
+-----END CERTIFICATE-----
diff --git a/fwupd-1.8.6/data/pki/meson.build b/fwupd-1.8.6/data/pki/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..3649fecea164d7cd235c76ad9f052bfcc07f7ef7
--- /dev/null
+++ b/fwupd-1.8.6/data/pki/meson.build
@@ -0,0 +1,36 @@
+# only install files that are going to be used
+if libjcat.type_name() != 'internal' and libjcat.version().version_compare('>= 0.1.9')
+ supported_gpg = libjcat.get_variable(pkgconfig: 'supported_gpg') == '1'
+ supported_pkcs7 = libjcat.get_variable(pkgconfig: 'supported_pkcs7') == '1'
+else
+ supported_gpg = host_machine.system() != 'windows'
+ supported_pkcs7 = true
+endif
+
+if supported_gpg
+install_data([
+ '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')
+)
+endif
+
+if supported_pkcs7
+install_data([
+ 'LVFS-CA.pem',
+ ],
+ install_dir: join_paths(sysconfdir, 'pki', 'fwupd')
+)
+install_data([
+ 'LVFS-CA.pem',
+ ],
+ install_dir: join_paths(sysconfdir, 'pki', 'fwupd-metadata')
+)
+endif
diff --git a/fwupd-1.8.6/data/power.quirk b/fwupd-1.8.6/data/power.quirk
new file mode 100644
index 0000000000000000000000000000000000000000..bfddd35e63ede711696626af3de1329b3bb6ff2c
--- /dev/null
+++ b/fwupd-1.8.6/data/power.quirk
@@ -0,0 +1,10 @@
+#This file provides manufacturer specified minimum battery thresholds
+
+[LENOVO]
+BatteryThreshold = 25
+
+[Star Labs]
+BatteryThreshold = 30
+
+[HP]
+BatteryThreshold = 50
diff --git a/fwupd-1.8.6/data/remotes.d/README.md b/fwupd-1.8.6/data/remotes.d/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d289124c7c046eb7d6b7ceb2e8994cc4b2575861
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/README.md
@@ -0,0 +1,81 @@
+# Remotes
+
+## Vendor Firmware
+
+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.gz`
+
+The metadata should be of the form:
+
+
+
+
+ FIXME.firmware
+ FIXME
+ FIXME
+ FIXME
+ FIXME
+ FIXME
+ http://FIXME
+
+
+ 86406
+ firmware/FIXME.cab
+ 96a92915c9ebaf3dd232cfc7dcc41c1c6f942877
+ FIXME.
+
+
+
+ FIXME
+
+
+
+
+Ideally, the metadata and firmware should be signed by either GPG or a PKCS7
+certificate. If this is the case also change `Keyring=gpg` or `Keyring=pkcs7`
+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-directory.conf` 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 upstream 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.
+
+For mirroring the LVFS content to a new CDN, you could use:
+
+ [fwupd Remote]
+ Enabled=true
+ Type=download
+ Keyring=gpg
+ MetadataURI=https://my.new.cdn/mirror/firmware.xml.gz
+ FirmwareBaseURI=https://my.new.cdn/mirror
+
+New instances of the LVFS can actually output a relative URL for firmware files,
+e.g. `bar.cab ` and when downloading the `MetadataURI` name
+and path prefix is used in this case.
+This is not enabled for the "upstream" LVFS instance as versions of fwupd older
+than 1.0.3 are unable to automatically use the `MetadataURI` value for firmware
+downloads.
diff --git a/fwupd-1.8.6/data/remotes.d/lvfs-testing.conf b/fwupd-1.8.6/data/remotes.d/lvfs-testing.conf
new file mode 100644
index 0000000000000000000000000000000000000000..42575498f44c44d9240430868889d113de9697cb
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/lvfs-testing.conf
@@ -0,0 +1,12 @@
+[fwupd Remote]
+
+# this remote provides metadata and firmware marked as 'testing' from the LVFS
+Enabled=false
+Title=Linux Vendor Firmware Service (testing)
+MetadataURI=https://cdn.fwupd.org/downloads/firmware-testing.xml.gz
+ReportURI=https://fwupd.org/lvfs/firmware/report
+#Username=
+#Password=
+OrderBefore=lvfs,fwupd
+AutomaticReports=false
+ApprovalRequired=false
diff --git a/fwupd-1.8.6/data/remotes.d/lvfs-testing.metainfo.xml b/fwupd-1.8.6/data/remotes.d/lvfs-testing.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e36aab775fe90023b985e23d1c5c108f736d00f
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/lvfs-testing.metainfo.xml
@@ -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 --git a/fwupd-1.8.6/data/remotes.d/lvfs.conf b/fwupd-1.8.6/data/remotes.d/lvfs.conf
new file mode 100644
index 0000000000000000000000000000000000000000..f425ce55830ea07780b47fc2cefe56edd6520022
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/lvfs.conf
@@ -0,0 +1,12 @@
+[fwupd Remote]
+
+# this remote provides metadata and firmware marked as 'stable' from the LVFS
+Enabled=@enabled@
+Title=Linux Vendor Firmware Service
+MetadataURI=https://cdn.fwupd.org/downloads/firmware.xml.gz
+ReportURI=https://fwupd.org/lvfs/firmware/report
+SecurityReportURI=https://fwupd.org/lvfs/hsireports/upload
+OrderBefore=fwupd
+AutomaticReports=false
+AutomaticSecurityReports=false
+ApprovalRequired=false
diff --git a/fwupd-1.8.6/data/remotes.d/lvfs.metainfo.xml b/fwupd-1.8.6/data/remotes.d/lvfs.metainfo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d9565ddd11a78b5da9fbe1202c94a7375c5fa507
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/lvfs.metainfo.xml
@@ -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 --git a/fwupd-1.8.6/data/remotes.d/meson.build b/fwupd-1.8.6/data/remotes.d/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..1d1698a7eb6e9ddd82fe8d1a3b1778b7bb677092
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/meson.build
@@ -0,0 +1,60 @@
+if build_standalone and get_option('lvfs') != 'false'
+ install_data([
+ 'lvfs-testing.conf',
+ ],
+ install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d')
+ )
+ con3 = configuration_data()
+ if get_option('lvfs') == 'disabled'
+ con3.set('enabled', 'false')
+ else
+ con3.set('enabled', 'true')
+ endif
+ configure_file(
+ input: 'lvfs.conf',
+ output: 'lvfs.conf',
+ configuration: con3,
+ install: true,
+ 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.project_source_root(), 'po'),
+ data_dirs: join_paths(meson.project_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.project_source_root(), 'po'),
+ data_dirs: join_paths(meson.project_source_root(), 'po'),
+ install: true,
+ install_dir: join_paths(get_option('datadir'), 'fwupd', 'metainfo')
+ )
+endif
+
+install_data('README.md',
+ install_dir: join_paths(datadir, 'fwupd', 'remotes.d', 'vendor', 'firmware')
+)
+
+# replace @datadir@
+con2 = configuration_data()
+con2.set('datadir', datadir)
+configure_file(
+ input: 'vendor.conf',
+ output: 'vendor.conf',
+ configuration: con2,
+ install: true,
+ install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'),
+)
+configure_file(
+ input: 'vendor-directory.conf',
+ output: 'vendor-directory.conf',
+ configuration: con2,
+ install: true,
+ install_dir: join_paths(sysconfdir, 'fwupd', 'remotes.d'),
+)
diff --git a/fwupd-1.8.6/data/remotes.d/vendor-directory.conf b/fwupd-1.8.6/data/remotes.d/vendor-directory.conf
new file mode 100644
index 0000000000000000000000000000000000000000..3885159d8f517a8d84b90e23084595f121922579
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/vendor-directory.conf
@@ -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 --git a/fwupd-1.8.6/data/remotes.d/vendor.conf b/fwupd-1.8.6/data/remotes.d/vendor.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a69d1bfa00e3feb7f1466d67ac74b536f5ea4602
--- /dev/null
+++ b/fwupd-1.8.6/data/remotes.d/vendor.conf
@@ -0,0 +1,8 @@
+[fwupd Remote]
+# this remote provides metadata shipped by the OS vendor and can be found in
+# @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 --git a/fwupd-1.8.6/docs/architecture-plan.svg b/fwupd-1.8.6/docs/architecture-plan.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7dc2f7e0f18dd3d85403489cb50b953bc96ba5b5
--- /dev/null
+++ b/fwupd-1.8.6/docs/architecture-plan.svg
@@ -0,0 +1,1354 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+ fwupd
+
+ Bluetooth (bluez)
+
+ Keyboard
+
+ custom plugins
+
+ udev, sysfs, ESRT
+
+ systemd
+
+ pending.db
+
+
+
+
+
+
+ internet
+ system
+
+
+ IPFS
+
+ CDN
+ sqlite
+ gnome-software fwupdmgr
+
+
+
+ Mouse
+
+
+ SAS / RAID
+
+
+ BMC
+
+
+ UpdateMetadata()
+ GetDevices()
+
+ IPMI & Redfish
+
+ only metadata
+ manual user opt-in
+ firmware
+
+
+ AppStream XML
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LVFS
+
+
+
+
+ session
+ embargoed metadata
+
+
+
+
+
+
+
diff --git a/fwupd-1.8.6/docs/bios-settings.md b/fwupd-1.8.6/docs/bios-settings.md
new file mode 100644
index 0000000000000000000000000000000000000000..03d161d14fe4fcfde302d7c9749856fbe730c80f
--- /dev/null
+++ b/fwupd-1.8.6/docs/bios-settings.md
@@ -0,0 +1,183 @@
+---
+title: BIOS Settings API
+---
+
+fwupd 1.8.4 and later include the ability to modify BIOS settings on systems that support the Linux kernel's [firmware-attributes API](https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-firmware-attributes).
+
+Drivers included with the Linux kernel on supported machines will advertise all BIOS settings that the OS can change. The fwupd daemon uses this API create an abstraction that fwupd clients can use to offer BIOS settings to change to end users.
+
+## Interactive command line usage
+
+Both `fwupdmgr` and `fwupdtool` have support for the fwupd BIOS settings API both for interactive use.
+Using `fwupdgmr` will require PolicyKit authentication as only authorized users can view the current BIOS settings.
+Using `fwupdtool` will require running the tool as root, as `fwupdtool` only works as root.
+
+### Getting available BIOS settings
+
+To fetch available BIOS settings for a machine:
+
+```shell
+# fwupdmgr get-bios-setting
+```
+
+This will provide a listing of all available settings. If you would like to just see a subset of attributes, you can list them space delimited on the command line. For example:
+
+```shell
+$ fwupdmgr get-bios-setting WindowsUEFIFirmwareUpdate MmioAbove4GLimit
+Authenticating… [ - ]
+WindowsUEFIFirmwareUpdate:
+ Setting type: Enumeration
+ Current Value: Enable
+ Description: BIOS updates delivered via LVFS or Windows Update
+ Read Only: False
+ Possible Values:
+ 0: Disable
+ 1: Enable
+
+
+MmioAbove4GLimit:
+ Setting type: Enumeration
+ Current Value: Auto
+ Description: MmioAbove4GLimit
+ Read Only: False
+ Possible Values:
+ 0: Auto
+ 1: 40
+ 2: 42
+ 3: 44
+ 4: 46
+ 5: 48
+```
+
+When using BASH as your shell, bash-completion can be used to discover BIOS settings. In the above example, those settings could be found from this series of tab actions:
+
+```shell
+$ sudo fwupdmgr get-bios-setting W
+WakeonLAN WakeUponAlarm WindowsUEFIFirmwareUpdate
+130 $ sudo fwupdmgr get-bios-setting WindowsUEFIFirmwareUpdate
+Display all 131 possibilities? (y or n)
+AbsolutePersistenceModule CStateSupport M2Slot2Port PCIeSlot3Bifurcation PXEIPV6NetworkStack SetStrongPassword
+AccessSecuritySettings DASHSupport MaxPasswordAttempts PCIeSlot3DLFSupport QuadM2PCIeCardFanControl SmartUSBProtection
+AfterPowerLoss DataScrambling MCRUSBHeader PCIeSlot3LinkSpeed RealtimeDIAG SMT
+AlarmDate(MM\DD\YYYY) DeviceGuard MediaCardReader PCIeSlot3Port RearAudioController SRIOVSupport
+AlarmDayofWeek DevicePowerupDelay MmioAbove4GLimit PCIeSlot4Bifurcation RearUSBPorts StartupSequence
+AlarmTime(HH:MM:SS) DeviceResetTimeout --no-authenticate PCIeSlot4DLFSupport RemoteSetSMP USBChargingPortInS4S5
+AllowJumperClearSVP DIAG7SegMode NUMA PCIeSlot4LinkSpeed RequireHDPonSystemBoot USBPortAccess
+AMDMemoryGuard EnhancedPowerSavingMode NVMeRAIDMode PCIeSlot4Port RequireSVPwhenFlashing USBTransferTimeout
+AMDSecureVirtualMachine ErrorBootSequence OnboardEthernetController PCIeSlot5Bifurcation SATAController UserDefinedAlarmFriday
+ASPMSupport FanControlStepping OptionKeysDisplay PCIeSlot5DLFSupport SATADrive1 UserDefinedAlarmMonday
+AutomaticBootSequence FrontUSBPorts PasswordChangeTime PCIeSlot5LinkSpeed SATADrive2 UserDefinedAlarmSaturday
+BIOSPasswordAtBootDeviceList HardDiskPre-delay PasswordCountExceededError PCIeSlot5Port SATADrive3 UserDefinedAlarmSunday
+BIOSPasswordAtReboot InternalUSB2Port PatroScrub PCIeSlot6Bifurcation SATADrive4 UserDefinedAlarmThursday
+BIOSPasswordAtSystemBoot InternalUSB3Port PatroScrubInterval PCIeSlot6DLFSupport SATADrive5 UserDefinedAlarmTime
+BootUpNumLockStatus IOMMU PCIeSlot1Bifurcation PCIeSlot6LinkSpeed SATADrive6 UserDefinedAlarmTuesday
+CardLocation --json PCIeSlot1DLFSupport PCIeSlot6Port SATADrive6HotPlugSupport UserDefinedAlarmWednesday
+ClearDIAGLog KeyboardLayout PCIeSlot1LinkSpeed pending_reboot SecureBoot --verbose
+ConfigurationChangeDetection M2Slot1DLFSupport PCIeSlot1Port PhysicalPresenceforClear SecureRollBackPrevention WakeonLAN
+ConfigureSATAas M2Slot1LinkSpeed PCIeSlot2Bifurcation POPChangeablebyUser SecurityChip WakeUponAlarm
+CoverTamperDetected M2Slot1Port PCIeSlot2DLFSupport PostPackageRepair SelectActiveVideo WindowsUEFIFirmwareUpdate
+CPBMode M2Slot2DLFSupport PCIeSlot2LinkSpeed PrimaryBootSequence SerialPort1Address XHCIHandoff
+CPUC6Report M2Slot2LinkSpeed PCIeSlot2Port PXEIPV4NetworkStack SetMinimumLength
+130 $ fwupdmgr get-bios-setting WindowsUEFIFirmwareUpdate MmioAbove4GLimit
+```
+
+### Setting BIOS settings
+
+To set one or more BIOS settings for a machine:
+
+```shell
+# fwupdmgr set-bios-setting SETTING VALUE
+```
+
+For supported attributes, `fwupdmgr` will also use tab completion in BASH for filling out a value.
+For example to enable an enumeration attribute:
+
+```shell
+$ sudo fwupdmgr set-bios-setting W
+WakeonLAN WakeUponAlarm WindowsUEFIFirmwareUpdate
+130 $ sudo fwupdmgr set-bios-setting WindowsUEFIFirmwareUpdate
+Disable Enable
+130 $ sudo fwupdmgr set-bios-setting WindowsUEFIFirmwareUpdate Enable
+```
+
+After setting an attribute you may be prompted to reboot as most settings will require a reboot to take effect.
+
+```shell
+$ fwupdmgr set-bios-setting WakeonLAN Primary
+Authenticating… [ - ]
+Set BIOS setting 'WakeonLAN' using 'Primary'.
+
+An update requires a reboot to complete. Restart now? [y|N]:
+```
+
+If you would like to program multiple attributes, list them in pairs of the name of the attribute followed by the desired value.
+
+## Programmatic command line usage
+
+`fwupdmgr` offers support for the fwupd BIOS settings API programmatically as well for use in scripts. To use the programmatic API you will add the `--json` argument to your calls. The output or input will then be expected to be JSON payloads.
+
+### Fetching BIOS settings programmatically
+
+Below is an example of fetching the `WakeonLAN` setting.
+
+```shell
+# fwupdmgr get-bios-setting WakeonLAN --json
+{
+ "BiosSettings" : [
+ {
+ "Name" : "WakeonLAN",
+ "Description" : "WakeonLAN",
+ "Filename" : "/sys/class/firmware-attributes/thinklmi/attributes/WakeonLAN",
+ "BiosSettingId" : "com.thinklmi.WakeonLAN",
+ "BiosSettingCurrentValue" : "Primary",
+ "BiosSettingReadOnly" : "false",
+ "BiosSettingType" : 1,
+ "BiosSettingPossibleValues" : [
+ "Primary",
+ "Automatic",
+ "Disable"
+ ]
+ }
+ ]
+}
+```
+
+Similar to the interactive usage, if no parameters are provided all settings are fetched, and if desired multiple settings can be listed on the command line.
+
+Error messages won't be emitted, you'll have to rely on the return code to tell if this was successful.
+*NOTE:* To debug errors, use the `--verbose` argument to see messages related to the error.
+
+### Setting BIOS settings programmatically
+
+To set BIOS settings, a JSON payload will need to be crafted in advance. The path to this payload is used as an argument.
+
+```shell
+# fwupdmgr set-bios-setting ~/foo.json --json
+```
+
+An important return code to know for programmatic usage is that *2* means nothing was done because all settings are already programmed. This message will also be emitted.
+*NOTE:* To debug errors, use the `--verbose` argument to see messages related to the error.
+
+## Firmware setting policies
+
+`fwupd` has the ability to enforce the BIOS settings policy of a system administrator. To use this feature, create a json payload using `fwupdmgr get-bios-setting --json` that reflects the settings you would like to see enforced.
+
+Then copy this payload into `/etc/fwupd/bios-settings.d` with a filename ending in `.json`. The next time that the fwupd daemon is started (such as a system bootup) it will ensure that all BIOS settings are programed to your desired values. It will also mark those settings as read-only so no fwupd clients will be able to modify them.
+
+This *does not* stop the kernel firmware-attributes API from working. So a determined user with appropriate permissions would be able to modify settings from the kernel API directly, but they would be changed again on fwupd daemon startup.
+
+## Settings types
+
+The Linux kernel will offer the following types of BIOS settings:
+
+* Enumeration: The setting will only accept a limiited list of possible values
+* Integer: The setting will will accept a limited range of integer values
+* String: The setting will accept a limited length UTF-8 string
+
+All of those setting types are accepted by fwupd. It is expected that drivers or firmware will validate the input, but where possible fwupd will do validation of the input to give better error messages and avoid failures.
+
+fwupd will also do a mapping where it can accept multiple cases or synonyms for words that are obviously positive or negative. So for example if the setting expects `Enabled` but the user passes `tRUE` fwupd will map this into `Enabled` before sending it to the driver and the driver sending it to the firmware.
+
+## libfwupd
+
+`fwupdmgr` internally uses `FwupdClient` to manage BIOS settings. Any other clients that are interested in managing BIOS settings can use this library as well. A sample python application is included in the `contrib/` directory in the fwupd source tree.
diff --git a/fwupd-1.8.6/docs/ds20.md b/fwupd-1.8.6/docs/ds20.md
new file mode 100644
index 0000000000000000000000000000000000000000..a010c478cc27d4228d21c73d72177b82e3356497
--- /dev/null
+++ b/fwupd-1.8.6/docs/ds20.md
@@ -0,0 +1,135 @@
+# fwupd BOS DS20 Specification
+
+## Introduction
+
+When `fwupd` starts it enumerates all PCI and USB hardware and generates *Instance IDs* based on the reported vendor and product so that it can match the device to a plugin.
+The plugin knows how to communicate with the device (for instance using vendor-specific USB control transfers) and also knows how to parse the firmware and deliver it to the device.
+
+Before a vendor can ship a firmware on the LVFS to a machine using Linux (or ChromeOS) the fwupd package often must be updated so that it knows what plugin to use for that specific device.
+At this point other overridden [quirk data](https://fwupd.github.io/libfwupdplugin/class.Quirks.html) can also be set. For instance, the icon, long summary or even per-plugin flags that change device behavior.
+For example `colorhug.quirk`:
+
+ [USB\VID_273F&PID_1001]
+ Plugin = colorhug
+ Flags = self-recovery
+ Icon = colorimeter-colorhug
+
+Updating the fwupd binary package might take anywhere from a few weeks to several years due to various Linux distribution policies.
+Clearly this isn't good when the majority of firmware updates are distributed to address security issues.
+
+One suggestion would be to put this quirk information into the existing update metadata provided by the configured remote, but this has several problems:
+
+* The daemon needs to *enumerate* hardware that does not have updates on the main LVFS remote.
+* A *lot* of machines using fwupd have never connected to the internet and we still want to enumerate hardware for audit and verification purposes.
+* Re-enumerating all physical hardware (to get the latest quirks) when updating the metadata is not straightforward.
+* The VID/PID is not necessarily the information that the plugin matches to assign the firmware stream, and so this would have to be a separate facet of metadata -- which may have to include quirks too.
+
+Matching devices to plugins should be thought of as *orthogonal* to matching firmware to devices.
+To simplify deployment it should be possible to allow the device itself to specify the plugin to use and optionally additional quirk data.
+
+## Specification
+
+Devices that implement a fwupd BOS DS20 descriptor can be updated without always needing to update the runtime version of fwupd for updated quirk entries, assuming the device is updatable by the existing vendor plugin.
+
+USB devices can create a new platform device capability BOS *“Binary Object Store”* descriptor with `bDevCapabilityType=0x05` and a fwupd-specific UUID, specifically `010aec63-f574-52cd-9dda-2852550d94f0`.
+This UUID is generated type-5 SHA-1 hash of the word `fwupd` using a DNS namespace.
+Using this custom UUID will ensure that Microsoft Windows does not try to parse the capability descriptor as a *Microsoft OS 2.0 descriptor set*.
+
+## Implementation
+
+Create a BOS DS20 descriptor such as:
+
+ 1C 10 05 00 63 ec 0a 01 74 f5 cd 52 9d da 28 52 55 0d 94 f0 05 08 01 00 20 00 2a 00
+ ├┘ ├┘ ├┘ ├┘ └─────────────┬───────────────────────────────┘ └─┬───────┘ └─┬─┘ ├┘ ├┘
+ │ │ │ │ └─PlatformCapabilityUUID │ wLength─┘ │ │
+ │ │ │ └─bReserved dwVersion─┘ bVendorCode─┘ │
+ │ │ └────bDevCapability bAltEnumCmd────┘
+ │ └───────bDescriptorType
+ └──────────bLength
+
+The `dwVersion` encoded here is fwupd `1.8.5`, which is also the first version that supports BOS DS20 descriptors.
+
+The BOS descriptors are sorted by the requester and can appear in any order.
+The descriptor with the highest `dwVersion` that is not newer than the current running daemon version is used.
+This means that `dwVersion` is effectively the minimum version of fwupd that should read the descriptor.
+This allows devices to set different quirks depending on the fwupd version, although in practice this should not be required.
+A suitable bVendorCode should be chosen that is not used for existing device operation.
+
+* The `dwVersion` parameter **must** be larger than `0x00010805`, i.e. 1.8.5.
+* The `bAltEnumCmd` parameter **must** be zero.
+* The `PlatformCapabilityUUID` **must** be `010aec63-f574-52cd-9dda-2852550d94f0`.
+
+Then allow the device to reply to a USB control request with the following parameters:
+
+ transfer-direction: device-to-host
+ request-type: vendor
+ recipient: device
+ bRequest: {value of bVendorCode in the BOS descriptor}
+ wValue: 0x00
+ wIndex: 0x07
+ wLength: {value of wLength in the BOS descriptor}
+
+The device should return something like:
+
+ 50 6c 75 67 69 6e 3d 64 66 75 0a 49 63 6f 6e 3d 63 6f 6d 70 75 74 65 72 0a 00 00 00 00 00 00 00
+
+...which is the UTF-8 quirk data, e.g.
+
+ Plugin=dfu
+ Icon=computer
+
+The UTF-8 quirk data must **not** contain Windows *CRLF-style* line endings.
+
+## Workflow
+
+To generate the fwupd DS20 descriptor save a file such as `fw-ds20.builder.xml`:
+
+
+ 42
+ 32
+
+
+Then run `fwupdtool firmware-build fw-ds20.builder.xml fw-ds20.bin`.
+
+To generate the control transfer response, save a file such as `fw-ds20.quirk`:
+
+ [USB\VID_273F&PID_1004]
+ Plugin = dfu
+ Icon = computer
+
+Then run `contrib/generate-ds20.py fw-ds20.quirk --bufsz 32`.
+The maximum buffer size is typically hardcoded for the device and may be specified in a microcontroller datasheet.
+
+## Prior Art
+
+### Hardcoded Class & Subclass
+
+The fwupd project already support two plugins that use the USB class code, rather than the exact instance ID with the VID/PID.
+For example, this DFU entry means *“match any USB device with class 0xFE (application specific) and subclass 0x01”*:
+
+ [USB\CLASS_FE&SUBCLASS_01]
+ Plugin = dfu
+
+These kind of devices do not need any device to plugin mapping (although, they still might need a quirk if they are non-complaint in some way, for example needing `Flags = detach-for-attach`) – but in the most cases they just work.
+
+The same can be done for Fastboot devices, matching class `0xFF` (vendor specific), subclass `0x42` and protocol `0x03`, although there is the same caveat for non-compliant devices that need quirk entries like `FastbootOperationDelay = 250`:
+
+ [USB\CLASS_FF&SUBCLASS_42&PROT_03]
+ Plugin = fastboot
+
+#### Microsoft OS Descriptors 1.0
+
+The [Microsoft OS Descriptors 1.0 Specification](https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-1-0-descriptors-specification) defines a device-specific variable-length metadata block of `CompatibleID`:`SubCompatibleID` on a string index of `0xEE` where the `CompatibleID` and `SubCompatibleID` are also both hardcoded at 8 bytes.
+
+Using `FWUPDPLU` or `FWUPDFLA` as the `CompatibleID` would be acceptable, but we could not fit the plugin name (e.g. `logitech-bulkcontroller`) or the GUID (16 bytes) in an 8 byte `SubCompatibleID`.
+Some non-compliant devices also hang and stop working when probing this specific string index.
+
+#### Microsoft OS Descriptors 2.0
+
+The [Microsoft OS Descriptors 2.0 Specification](https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-2-0-descriptors-specification) is more useful as it defines a new device capability that can return a variable length vendor-defined section of data, using a UUID as a key.
+Using the `BOS` *“Binary Object Store”* descriptor is only available for devices using USB specification version 2.1 and newer.
+The BOS descriptor is used for Wireless USB details, USB 2.0 extensions, SuperSpeed USB connection details and a Container ID.
+
+The BOS descriptor does give the OS the ability to parse the platform capability, which is `bDevCapabilityType=0x05`. For UUID `D8DD60DF-4589-4CC7-9CD2-659D9E648A9F` this is identified as a structured blob of data Microsoft Windows uses for the suspend mode of the device.
+
+Creating a new `bDevCapabilityType` would allow vendors to store a binary blob (e.g. `Plugin=foobarbaz\nFlags=QuirkValueHere\n`) but that would be out-of-specification and difficult to implement.
diff --git a/fwupd-1.8.6/docs/env.md b/fwupd-1.8.6/docs/env.md
new file mode 100644
index 0000000000000000000000000000000000000000..10d50b0fa42237ac11782dac6066d6eeb05c9ed2
--- /dev/null
+++ b/fwupd-1.8.6/docs/env.md
@@ -0,0 +1,96 @@
+---
+title: Environment Variables
+---
+
+When running fwupd reads some variables from your environment and changes some
+behavior. This might be useful for debugging, or to make fwupd run somewhere
+with a non-standard filesystem layout.
+
+## fwupdmgr and fwupdtool
+
+* `DISABLE_SSL_STRICT` disables strict SSL certificate checking, which may make
+ downloading files work when using some antisocial corporate firewalls.
+* `FWUPD_CURL_VERBOSE` shows more information when downloading files
+* `FWUPD_DEVICE_TESTS_BASE_URI` sets the base URI when downloading firmware for the device-tests
+* `FWUPD_SUPPORTED` overrides the `-Dsupported_build` meson option at runtime
+* `FWUPD_VERBOSE` is set when running `--verbose`
+* `FWUPD_BACKEND_VERBOSE` can be used to show detailed plugin and backend debugging
+* `FWUPD_XMLB_VERBOSE` can be set to show Xmlb silo regeneration and quirk matches
+* `FWUPD_DBUS_SOCKET` is used to set the socket filename if running without a dbus-daemon
+* `FWUPD_DOWNLOAD_VERBOSE` can be used to show wget or curl output
+* `FWUPD_PROFILE` can be used to set the profile traceback threshold value in ms
+* `FWUPD_FUZZER_RUNNING` if the firmware format is being fuzzed
+* standard glibc variables like `LANG` are also honored for CLI tools that are translated
+* libcurl respects the session proxy, e.g. `http_proxy`, `all_proxy`, `sftp_proxy` and `no_proxy`
+
+## daemon
+
+* `FWUPD_MACHINE_KIND` can be used to override the detected machine type, e.g. `physical`, `virtual`, or `container`
+* `FWUPD_HOST_EMULATE` can be used to load test data from `/usr/share/fwupd/host-emulate.d`, e.g. `thinkpad-p1-no-iommu.json.gz`
+
+## Self Tests
+
+* `CI_NETWORK` if CI is running with network access
+* `TPM_SERVER_RUNNING` if an emulated TPM is running
+
+## Shared libfwupdplugin
+
+* `FU_HID_DEVICE_VERBOSE` shows HID traffic
+* `FU_SREC_FIRMWARE_VERBOSE` shows more information about parsing
+* `FU_UDEV_DEVICE_DEBUG` shows more information about UDEV devices, including parents
+* `FU_USB_DEVICE_DEBUG` shows more information about USB devices
+* `FU_MEI_DEVICE_DEBUG` shows MEI reads and writes
+* `FWUPD_DEVICE_LIST_VERBOSE` display devices being added and removed from the list
+* `FWUPD_PROBE_VERBOSE` dump the detected devices to the console, even if not supported by fwupd
+* `FWUPD_BIOS_SETTING_VERBOSE` be verbose while parsing BIOS settings
+
+## Plugins
+
+Most plugins read a plugin-specific runtime key to increase verbosity more than the usual `VERBOSE`.
+This can be also used when using fwupdtool e.g. using `--plugin-verbose=dell` will set the
+environment variable of `FWUPD_DELL_VERBOSE` automatically.
+
+Other variables, include:
+
+* `FWUPD_DELL_FAKE_SMBIOS` if set, use fake SMBIOS information for tests
+* `FWUPD_FORCE_TPM2` ignores a TPM 1.2 device detected in the TPM self tests
+* `FWUPD_PLUGIN_TEST` used by the test plugin to pass data out-of-band to the loader
+* `FWUPD_REDFISH_SELF_TEST` if set, do destructive tests on the actual device BMC
+* `FWUPD_REDFISH_SMBIOS_DATA` use this filename to emulate a specific SMBIOS blob
+* `FWUPD_SOLOKEY_EMULATE` emulates a fake device for testing
+* `FWUPD_SUPERIO_DISABLE_MIRROR` disables the e-flash fixup to get byte-accurate hardware dumps
+* `FWUPD_SUPERIO_RECOVER` allow recovery of a corrupted SuperIO by hardcoding the device size
+* `FWUPD_TEST_PLUGIN_XML` used by the test plugin to load XML state out-of-band before startup
+* `FWUPD_UEFI_CAPSULE_RECREATE_COD_DATA` if set, write the files in the example COD tree in srcdir
+* `FWUPD_UEFI_TEST` used by the UEFI plugins to disable specific sanity checks during self tests
+* `FWUPD_WAC_EMULATE` emulates a fake device for testing
+
+## File system overrides
+
+These are not fully documented here, see
+for details.
+
+* `CACHE_DIRECTORY`
+* `CONFIGURATION_DIRECTORY`
+* `FWUPD_ACPITABLESDIR`
+* `FWUPD_DATADIR`
+* `FWUPD_DATADIR_QUIRKS`
+* `FWUPD_EFIAPPDIR`
+* `FWUPD_FIRMWARESEARCH`
+* `FWUPD_LIBDIR_PKG`
+* `FWUPD_LOCALSTATEDIR`
+* `FWUPD_LOCALSTATEDIR_QUIRKS`
+* `FWUPD_OFFLINE_TRIGGER`
+* `FWUPD_PROCFS`
+* `FWUPD_SYSCONFDIR`
+* `FWUPD_SYSFSDRIVERDIR`
+* `FWUPD_SYSFSFWATTRIBDIR`
+* `FWUPD_SYSFSFWDIR`
+* `FWUPD_SYSFSSECURITYDIR`
+* `FWUPD_SYSFSTPMDIR`
+* `FWUPD_UEFI_ESP_PATH`
+* `HOME`
+* `RUNTIME_DIRECTORY`
+* `SNAP`
+* `SNAP_USER_DATA`
+* `STATE_DIRECTORY`
diff --git a/fwupd-1.8.6/docs/fwupd.toml.in b/fwupd-1.8.6/docs/fwupd.toml.in
new file mode 100644
index 0000000000000000000000000000000000000000..fef8d43b6ca346048b939b0ead68225cdab31dd9
--- /dev/null
+++ b/fwupd-1.8.6/docs/fwupd.toml.in
@@ -0,0 +1,65 @@
+[library]
+version = "@version@"
+browse_url = "https://github.com/fwupd/fwupd"
+repository_url = "https://github.com/fwupd/fwupd.git"
+website_url = "https://www.fwupd.org"
+authors = "fwupd Development Team"
+logo_url = "org.freedesktop.fwupd.svg"
+license = "LGPL-2.1-or-later"
+description = "Functionality exported by libfwupd for client applications"
+dependencies = [
+ "GObject-2.0",
+ "Gio-2.0",
+ "Json-1.0"
+]
+devhelp = true
+search_index = true
+
+ [dependencies."GObject-2.0"]
+ name = "GObject"
+ description = "The base type system library"
+ docs_url = "https://docs.gtk.org/gobject/"
+
+ [dependencies."Gio-2.0"]
+ name = "Gio"
+ description = "A modern, easy-to-use VFS API"
+ docs_url = "https://docs.gtk.org/gio/"
+
+ [dependencies."Json-1.0"]
+ name = "Json"
+ description = "API for efficient parsing and writing of JSON (JavaScript Object Notation) streams"
+ docs_url = "https://gnome.pages.gitlab.gnome.org/json-glib/"
+
+[theme]
+name = "basic"
+show_index_summary = true
+show_class_hierarchy = true
+
+[source-location]
+base_url = "https://github.com/fwupd/fwupd/blob/@version@/"
+
+[extra]
+content_images = [
+ "../data/org.freedesktop.fwupd.svg",
+]
+urlmap_file = "urlmap_fwupd.js"
+
+[[object]]
+name = "build_user_agent_system"
+hidden = true
+
+[[object]]
+name = "hash_kv_to_variant"
+hidden = true
+
+[[object]]
+name = "variant_to_hash_kv"
+hidden = true
+
+[[object]]
+name = "input_stream_read_bytes_async"
+hidden = true
+
+[[object]]
+name = "input_stream_read_bytes_finish"
+hidden = true
diff --git a/fwupd-1.8.6/docs/fwupdplugin.toml.in b/fwupd-1.8.6/docs/fwupdplugin.toml.in
new file mode 100644
index 0000000000000000000000000000000000000000..32a5ef5c0ca6b4aa96b70dd71336cfb39c3bd079
--- /dev/null
+++ b/fwupd-1.8.6/docs/fwupdplugin.toml.in
@@ -0,0 +1,93 @@
+[library]
+version = "@version@"
+browse_url = "https://github.com/fwupd/fwupd"
+repository_url = "https://github.com/fwupd/fwupd.git"
+website_url = "https://www.fwupd.org"
+authors = "fwupd Development Team"
+logo_url = "org.freedesktop.fwupd.svg"
+license = "LGPL-2.1-or-later"
+description = "Functionality available to fwupd plugins"
+dependencies = [
+ "GObject-2.0",
+ "Gio-2.0",
+ "Fwupd-2.0",
+ "Xmlb-2.0",
+ "GUsb-1.0"
+]
+devhelp = true
+search_index = true
+
+ [dependencies."GObject-2.0"]
+ name = "GObject"
+ description = "The base type system library"
+ docs_url = "https://developer.gnome.org/gobject/stable/"
+
+ [dependencies."Gio-2.0"]
+ name = "Gio"
+ description = "A modern, easy-to-use VFS API"
+ docs_url = "https://developer.gnome.org/gio/stable/"
+
+ [dependencies."Fwupd-2.0"]
+ name = "Fwupd"
+ description = "Firmware update daemon client library"
+ docs_url = "../libfwupd/index.html"
+
+[theme]
+name = "basic"
+show_index_summary = true
+show_class_hierarchy = true
+
+[source-location]
+base_url = "https://github.com/fwupd/fwupd/blob/@version@/"
+
+[extra]
+content_files = [
+ "env.md",
+ "tutorial.md",
+ "hsi.md",
+ "ds20.md",
+ "bios-settings.md",
+]
+content_images = [
+ "architecture-plan.svg",
+ "../data/org.freedesktop.fwupd.svg",
+]
+urlmap_file = "urlmap_fwupdplugin.js"
+
+[[object]]
+name = "Device"
+
+ [[object.method]]
+ name = "incorporate_from_component"
+ hidden = true
+
+[[object]]
+name = "Cabinet"
+
+ [[object.method]]
+ name = "set_jcat_context"
+ hidden = true
+
+ [[object.method]]
+ name = "get_silo"
+ hidden = true
+
+[[object.function]]
+name = "common_cab_build_silo"
+hidden = true
+
+[[object]]
+name = "Fmap"
+hidden = true
+
+[[object]]
+name = "FmapArea"
+hidden = true
+
+[[object]]
+name = "IhexFirmwareRecord"
+hidden = true
+
+[[object]]
+name = "SrecFirmwareRecord"
+hidden = true
diff --git a/fwupd-1.8.6/docs/hsi.html b/fwupd-1.8.6/docs/hsi.html
new file mode 100644
index 0000000000000000000000000000000000000000..76e6306ac8a362d48b33079c236de27f8cba4669
--- /dev/null
+++ b/fwupd-1.8.6/docs/hsi.html
@@ -0,0 +1,13 @@
+
+
+Redirecting to https://fwupd.github.io/libfwupdplugin/hsi.html
+
+
+
+
+
diff --git a/fwupd-1.8.6/docs/hsi.md b/fwupd-1.8.6/docs/hsi.md
new file mode 100644
index 0000000000000000000000000000000000000000..e097f5dd1eaa3ed0912a77238902c4c61a1c4c14
--- /dev/null
+++ b/fwupd-1.8.6/docs/hsi.md
@@ -0,0 +1,837 @@
+---
+title: Host Security ID Specification
+---
+
+**WARNING:
+This specification is still in active development: it is incomplete, subject to change, and may have errors; use this at your own risk.
+It is based on publicly available information.**
+
+Authors:
+
+- Richard Hughes
+- Mario Limonciello
+- Alex Bazhaniuk
+- Alex Matrosov
+
+---
+
+## Introduction
+
+Not all system vendors prioritize building a secure platform.
+The truth is that **security costs money**.
+Vendors have to choose between saving a few cents on a bill-of-materials by sharing a SPI chip, or correctly implementing BootGuard.
+Discovering security vulnerabilities often takes an external researcher filing a disclosure.
+These disclosures are often technical in nature and difficult for an average consumer to decipher.
+
+The Linux Vendor Firmware Service (LVFS) could provide some **easy-to-understand** information to people buying hardware.
+The service already knows a huge amount of information about machines from signed reports uploaded to the LVFS and from analyzing firmware binaries.
+However this information alone does not explain firmware security to the user in a way they can actually interpret.
+
+### Other Tools
+
+Traditionally, figuring out the true security of your hardware and firmware requires sifting through the marketing documentation provided by the OEM and in many cases just "trusting" they did it right.
+Tools such as Chipsec can check the hardware configuration, but they do not work out of the box and use technical jargon that an average user cannot interpret.
+Unfortunately, running a tool like Chipsec requires that you actively turn off some security layers such as UEFI Secure Boot, and allow 3rd party unsigned kernel modules to be loaded.
+
+
+
+## [Verifying Host Firmware Security](#verifying)
+
+To start out some core protections must be assigned a relative
+importance.
+Then an evaluation must be done to determine how each vendor is conforming to the model.
+For instance, a user might say that for home use any hardware the bare minimum security level (`HSI:1`) is *good enough*.
+For a work laptop the company IT department might restrict the choice of models to anything meeting the criteria of level `HSI:2` or above.
+A journalist or a security researcher would only buy level `HSI:3` and above.
+The reality is that `HSI:4` is going to be more expensive than some unbranded hardware that is rated `HSI:0`.
+
+To be trusted, this rating information should be distributed in a centralized agnostic database such as the LVFS.
+
+Of course, tools need to detect implementation errors, and to verify that the model that is measured does indeed match the HSI level advertised by the LVFS.
+Some existing compliance solutions place the burden on the OEM to define what firmware security has been implemented, which is easy to get wrong and in some cases impossible to verify.
+
+For this reason HSI will only measure security protections that can be verified by the end user without requiring any extra hardware to be connected, additional software to be installed, or disabling any existing security layers to measure.
+
+The HSI specification is primarily designed for laptop and desktop hardware, although some tests *may* still make sense on server or embedded hardware.
+It is not expected that non-consumer hardware will publish an HSI number.
+
+
+
+## [Runtime Behavior](#runtime-behaviour)
+
+Orthogonal to the security features provided by the firmware there are other security considerations related to the firmware which may require internet access to discover or that runtime OS changes directly affect the security of the firmware.
+It would not make sense to have *have updates on the LVFS* as a requirement for a specific security level as this would mean offline the platform might be a higher level initially but as soon as it is brought online it is downgraded which would be really confusing to users.
+The *core* security level will not change at Operating System runtime, but the suffix may.
+
+**More information**
+Additional information about specific bugs and debugging steps are available on the [fwupd wiki](https://github.com/fwupd/fwupd/wiki/Host-security-ID-runtime-issues).
+
+
+
+### [HSI:0 (Insecure State)](#hsi-level0)
+
+Limited firmware protection.
+
+The lowest security level with little or no detected firmware protections.
+This is the default security level if no tests can be run or some tests in the next security level have failed.
+
+
+
+### [HSI:1 (Critical State)](#hsi-level1)
+
+Basic protection but any failure would lead to a critical security impact.
+
+This security level corresponds to the most basic of security protections considered essential by security professionals.
+Any failures at this level would have critical security impact and could likely be used to compromise the system firmware without physical access.
+
+
+
+### [HSI:2 (Risky State)](#hsi-level2)
+
+The failure is only happened by the theoretical exploit in the lab.
+
+This security level corresponds to firmware security issues that pose a theoretical concern or where any exploit would be difficult or impractical to use.
+At this level various technologies may be employed to protect the boot process from modification by an attacker with local access to the machine.
+
+
+
+### [HSI:3 (Protected State)](#hsi-level3)
+
+The system firmware only has few minor issues which do not affect the security status.
+
+This security level corresponds to out-of-band protection of the system firmware perhaps including recovery.
+
+
+
+### [HSI:4 (Secure State)](#hsi-level4)
+
+The system is in a robust secure state.
+
+The system is corresponding several kind of encryption and execution protection for the system firmware.
+
+
+
+### [HSI:5 (Secure Proven State)](#hsi-level5)
+
+This security level corresponds to out-of-band attestation of the system firmware.
+There are currently no tests implemented for HSI:5 and so this security level cannot yet be obtained.
+
+
+
+### [HSI Runtime Suffix `!`](#runtime-bang)
+
+A runtime security issue detected.
+
+- UEFI [Secure Boot](https://wiki.ubuntu.com/UEFI/SecureBoot) has been turned off. *[v1.5.0]*
+
+- The kernel is [tainted](https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html) due to a non-free module or critical firmware issue. *[v1.5.0]*
+
+- The kernel is not [locked down](https://mjg59.dreamwidth.org/50577.html). *[v1.5.0]*
+
+- Unencrypted [swap partition](https://wiki.archlinux.org/index.php/Dm-crypt/Swap_encryption). *[v1.5.0]*
+
+- The installed fwupd is running with [custom or modified plugins](https://github.com/fwupd/fwupd/tree/main/plugins). *[v1.5.0]*
+
+
+
+## [Low Security Level](#low-security-level)
+
+A safe baseline for security should be HSI-1. If your system isn't at least meeting this criteria, you should adjust firmware setup options, contact your manufacturer or replace the hardware.
+
+The command line tool `fwupdmgr security` included with fwupd 1.8.4 or later will make individual recommendations on what you can do for individual test failures. GUI tools built against `libfwupd` 1.8.4 or later may also make these recommendation as well.
+
+
+
+## [Not enough information](#not-enough-info)
+
+HSI calculations require that the SOC, firmware, and kernel provide enough data to the fwupd daemon about the state of the system. If any HSI test that runs on the system declares it's *missing data* then the client will show a message like this:
+
+**Not enough data was provided to make an HSI calculation.**
+
+The HSI level will also be set to `INVALID` indicating this.
+
+
+
+## [Tests included in fwupd](#tests)
+
+The set of tests is currently x86 UEFI-centric, but will be expanded in the future for various ARM or RISC-V firmware protections as required.
+Where the requirement is architecture or processor specific it has been noted.
+
+
+
+### [UEFI SecureBoot](#org.fwupd.hsi.Uefi.SecureBoot)
+
+UEFI Secure boot is a verification mechanism for ensuring that code launched by firmware is trusted.
+
+Secure Boot requires that each binary loaded at boot is validated against trusted certificates.
+
+**Impact:** When Secure Boot is not enabled any EFI binary can be run at startup, which gives the attacker full access to your hardware.
+
+**Possible results:**
+
+- `not-found`: support has not been detected
+- `not-enabled`: detected, but has been turned off
+- `enabled`: supported and enabled
+
+To meet HSI-1 on UEFI systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**Resolution:**
+
+Turn off CSM boot and enable Secure Boot in the BIOS setup.
+
+**References:**
+
+- [Ubuntu SecureBoot Wiki Page](https://wiki.ubuntu.com/UEFI/SecureBoot)
+
+
+
+### [UEFI PK](#org.fwupd.hsi.Uefi.Pk)
+
+UEFI defines a platform key for the system.
+This should not be a test key, e.g. `DO NOT TRUST - AMI Test PK`
+
+**Impact:** It is possible to sign an EFI binary with the test platform key, which invalidates the Secure Boot trust chain.
+It effectively gives the local attacker full access to your hardware.
+
+**Possible results:**
+
+- `valid`: valid key
+- `not-valid`: an invalid key has been enrolled
+
+To meet HSI-1 on UEFI systems that run this test, the result must be `valid`. *[v1.5.0]*
+
+**References:**
+
+- [Ubuntu SecureBoot Wiki Page](https://wiki.ubuntu.com/UEFI/SecureBoot/Testing)
+
+
+
+### [BIOS Write Enable (BWE)](#org.fwupd.hsi.Spi.Bioswe)
+
+Intel hardware provides this mechanism to protect the SPI ROM chip located on the motherboard from being overwritten by the operating
+system. The `BIOSWE` bit must be unset otherwise userspace can write to the SPI chip.
+
+**Impact:** The system firmware can be written from userspace.
+This gives any attacker with root access a method to write persistent executable code to the firmware, which survives even a full disk wipe and OS reinstall.
+
+**Possible results:**
+
+- `not-found`: the SPI device was not found
+- `not-enabled`: write enable is disabled
+- `enabled`: write enable is enabled
+
+To meet HSI-1 on systems that run this test, the result must be `not-enabled`. *[v1.5.0]*
+
+**References:**
+
+- [Intel C200 Datasheet](https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/6-chipset-c200-chipset-datasheet.pdf)
+
+
+
+### [BIOS Lock Enable (BLE)](#org.fwupd.hsi.Spi.Ble)
+
+If the lock bit is set then System Management Interrupts (SMIs) are raised when setting BIOS Write Enable.
+The `BLE` bit must be enabled in the PCH otherwise `BIOSWE` can easily be unset.
+
+**Impact:** The system firmware can be written from userspace.
+This gives any attacker with root access a method to write persistent executable code to the firmware, which survives even a full disk wipe and OS reinstall.
+
+**Possible results:**
+
+- `enabled`: the register is locked
+- `not-enabled`: the register is not locked
+
+To meet HSI-1 on systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**References:**
+
+- [Intel C200 Datasheet](https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/6-chipset-c200-chipset-datasheet.pdf)
+
+
+
+### [SMM Bios Write Protect (SMM\_BWP)](#org.fwupd.hsi.Spi.SmmBwp)
+
+This bit set defines when the BIOS region can be written by the host.
+The `SMM_BWP` bit must be set to make the BIOS region non-writable unless all processors are in system management mode.
+
+**Impact:** The system firmware can be written from userspace by exploiting a race condition in checking `BLE`.
+This gives any attacker with root access a method to write persistent executable code to the firmware, which survives even a full disk wipe and OS reinstall.
+
+**Possible results:**
+
+- `locked`: the region is locked
+- `not-locked`: the region is not locked
+
+To meet HSI-1 on systems that run this test, the result must be `locked`. *[v1.5.0]*
+
+**References:**
+
+- [Intel C200 Datasheet](https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/6-chipset-c200-chipset-datasheet.pdf)
+
+
+
+### [Read-only SPI Descriptor](#org.fwupd.hsi.Spi.Descriptor)
+
+The SPI descriptor must always be read only from all other regions.
+Additionally on Intel architectures the FLOCKDN register must be set to prevent configuration registers in the SPI BAR from being changed.
+
+**Impact:** The system firmware can be written from userspace by changing the protected region.
+This gives any attacker with root access a method to write persistent executable code to the firmware, which survives even a full disk wipe and OS reinstall.
+
+**Possible results:**
+
+- `not-valid`: any region can write to the flash descriptor
+- `locked`: the SPI BAR is locked and read only from all regions
+- `not-locked`: the SPI BAR is not locked
+
+To meet HSI-1 on systems that run this test, the result must be `locked`. *[v1.6.0]*
+
+
+
+### [TPM 2.0 Present](#org.fwupd.hsi.Tpm.Version20)
+
+A TPM securely stores platform specific secrets that can only be divulged to trusted consumers in a secure environment.
+
+**Impact:** The PCR registers will not be available for use by the bootloader and kernel.
+This means userspace cannot either encrypt disks to the specific machine, and also can't know if the system firmware was externally modified.
+
+**Possible results:**
+
+- `found`: device found in v2 mode
+- `not-found`: no device found
+- `not-enabled`: not in v2 mode
+
+To meet HSI-1 on systems that run this test, the result must be `found`. *[v1.5.0]*
+
+**References:**
+
+- [TPM Wikipedia Page](https://en.wikipedia.org/wiki/Trusted_Platform_Module)
+
+
+
+### [ME not in manufacturing mode](#org.fwupd.hsi.Mei.ManufacturingMode)
+
+There have been some unfortunate cases of the ME being distributed in manufacturing mode.
+In manufacturing mode many features from the ME can be interacted with that decrease the platform's security.
+
+**Impact:** If the ME is in manufacturing mode then any user with root access can provision the ME engine with new keys.
+This gives them full access to the system even when the system is powered off.
+
+**Possible results:**
+
+- `locked`: device has had manufacturing mode disabled
+- `not-locked`: device is in manufacturing mode
+
+To meet HSI-1 on systems that run this test, the result must be `locked`. *[v1.5.0]*
+
+**References:**
+
+- [ME Manufacturing Mode: obscured dangers](https://malware.news/t/intel-me-manufacturing-mode-obscured-dangers-and-their-relationship-to-apple-macbook-vulnerability-cve-2018-4251/23214)
+- [Intel security advisory SA-00086](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00086.html)
+
+
+
+### [ME Flash Descriptor Override](#org.fwupd.hsi.Mei.OverrideStrap)
+
+The Flash Descriptor Security Override Strap is not accessible to end users on consumer boards and Intel stresses that this is for debugging
+only.
+
+**Impact:** The system firmware can be written from userspace by changing the protected region.
+This gives any attacker with root access a method to write persistent executable code to the firmware, which survives even a full disk wipe and OS reinstall.
+
+**Possible results:**
+
+- `locked`: device in in normal runtime mode
+- `not-locked`: device is in debugging mode
+
+To meet HSI-1 on systems that run this test, the result must be `locked`. *[v1.5.0]*
+
+**References:**
+
+- [Chromium documentation for Intel ME](https://chromium.googlesource.com/chromiumos/third_party/flashrom/+/master/Documentation/mysteries_intel.txt)
+
+
+
+### [CSME Version](#org.fwupd.hsi.Mei.Version)
+
+Converged Security and Manageability Engine is a standalone management module that can manage and control some local devices without the host CPU involvement.
+The CSME lives in the PCH and can only be updated by the OEM vendor.
+The version of the CSME module can be checked to detect the most common and serious vulnerabilities: CVE-2017-5705, CVE-2017-5708, CVE-2017-5711, CVE-2017-5712, CVE-2017-5711, CVE-2017-5712, CVE-2017-5706, CVE-2017-5709, CVE-2017-5707 or CVE-2017-5710.
+
+**Impact:** Using any one of the critical vulnerabilities, a remote attacker can take full control of the system and all connected devices, even when the system is powered off.
+
+**Possible results:**
+
+- `valid`: is not affected by the most critical CVEs
+- `not-valid`: affected by one of the below CVEs
+
+To meet HSI-1 on systems that run this test, the result must be `valid`. *[v1.5.0]*
+
+**References:**
+
+- [Intel CSME Security Review Cumulative Update](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00086.html)
+
+
+
+
+### [Intel DCI](#org.fwupd.hsi.PlatformDebugEnabled)
+
+Newer Intel CPUs support debugging over USB3 via a proprietary Direct Connection Interface (DCI) with the use of off-the-shelf hardware.
+
+**Impact:** Using DCI an attacker with physical access to the computer has full access to all registers and memory in the system, and is able to make changes.
+This makes privilege escalation from user to root possible, and also modifying SMM makes it possible to write to system firmware for a persistent backdoor.
+
+**Possible results:**
+
+- `enabled`: debugging is currently enabled
+- `not-enabled`: debugging is not currently enabled
+
+To meet HSI-1 on systems that run this test, the result must be `not-enabled`. *[v1.5.0]*
+
+Note: this attribute was previously known as org.fwupd.hsi.IntelDci.Enabled in 1.5.0, but was renamed in 1.8.0 to support other vendors.
+
+**References:**
+
+- [Intel Direct Connect Interface](https://www.intel.co.uk/content/www/uk/en/support/articles/000029393/processors.html)
+- [Chipsec 4xxlp register definitions](https://github.com/chipsec/chipsec/blob/master/chipsec/cfg/8086/pch_4xxlp.xml#L270)
+- [RISC-V EDK PCH register definitions](https://github.com/riscv/riscv-edk2-platforms/blob/85a50de1b459d1d6644a402081120770aa6dd8c7/Silicon/Intel/CoffeelakeSiliconPkg/Pch/Include/Register/PchRegsDci.h)
+
+
+
+### [Part is fused](#org.fwupd.hsi.PlatformFused)
+
+When fuses are blown in parts from some manufacturers the hardware will enforce protections against
+tampering or accessing of certain registers.
+
+**Impact:** If using an unfused part, the platform's overall security will be decreased.
+
+**Possible results:**
+
+- `locked`: device is fused
+- `not-locked`: device is not fused
+
+To meet HSI-1 on systems that run this test, the result must be `locked`. *[v1.8.0]*
+
+
+
+
+### [Part is debug locked](#org.fwupd.hsi.PlatformDebugLocked)
+
+Some devices support a concept of whether a part has been unlocked for debugging using proprietary hardware. Such parts allow access to registers that are typically restricted when parts are fused.
+On Intel systems access to this interface is done via a proprietary Direct Connection Interface (DCI).
+
+**Impact:** If using a debug unlocked part, the platform's overall security will be decreased as an attacker may have elevated access to registers and memory within the system and can potentially enable persistent backdoors.
+
+**Possible results:**
+
+- `locked`: device is locked
+- `not-locked`: device is not not locked
+
+To meet HSI-2 on systems that run this test, the result must be `locked`. *[v1.8.0]*
+
+Note: this attribute was previously known as org.fwupd.hsi.IntelDci.Locked in 1.5.0, but was renamed in 1.8.0 to support other vendors.
+
+**References:**
+
+- [Intel Direct Connect Interface](https://www.intel.co.uk/content/www/uk/en/support/articles/000029393/processors.html)
+
+
+
+### [Empty PCR in TPM](#org.fwupd.hsi.Tpm.EmptyPcr)
+
+The system firmware is responsible for measuring values about its boot stage in PCRs 0 through 7.
+Some firmwares have bugs that prevent them from measuring some of those values, breaking the fundamental assumption of the Measured Boot chain-of-trust.
+
+**Impact:** A local attacker could measure fake values into the empty PCR, corresponding to a firmware and OS that do not match the ones actually loaded.
+This allows hiding a compromised boot chain or fooling a remote-attestation server into believing that a different kernel is running.
+
+**Possible results:**
+
+- `valid`: all correct
+- `not-valid`: at least one empty checksum has been found
+- `not-found`: no TPM hardware could be found
+
+To meet HSI-1 on systems that run this test, all PCRs from 0 to 7 in all banks must have non-empty measurements *[v1.7.2]*
+
+**References:**
+
+- [CVE-2021-42299: TPM Carte Blanche](https://github.com/google/security-research/blob/master/pocs/bios/tpm-carte-blanche/writeup.md)
+
+
+
+### [PCR0 TPM Event Log Reconstruction](#org.fwupd.hsi.Tpm.ReconstructionPcr0)
+
+The TPM event log records which events are registered for the PCR0 hash.
+When reconstructed the event log values should always match the TPM PCR0.
+If extra events are included in the event log, or some are missing, the reconstitution will fail.
+
+**Impact:** This is not a vulnerability per-se, but it shows that the system firmware checksum cannot be verified as the PCR result has been calculated incorrectly.
+
+**Possible results:**
+
+- `valid`: all correct
+- `not-valid`: could not reconstitute the hash value
+- `not-found`: no TPM hardware could be found
+
+To meet HSI-2 on systems that run this test, the result must be `valid`. *[v1.5.0]*
+
+**More information**
+Additional information about specific bugs and debugging steps are available on the [fwupd wiki](https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction).
+
+**References:**
+
+- [Linux Kernel TPM Documentation](https://www.kernel.org/doc/html/latest/security/tpm/tpm_event_log.html)
+
+
+
+
+### [Pre-boot DMA protection](#org.fwupd.hsi.PrebootDma)
+
+The IOMMU on modern systems is used to mitigate against DMA attacks.
+All I/O for devices capable of DMA is mapped into a private virtual memory region.
+On Intel systems the ACPI DMAR table indicated the system is configured with pre-boot DMA protection which eliminates some firmware attacks.
+On AMD systems the ACPI IVRS table indicates the same.
+
+**Impact:** The IOMMU may is disabled at boot.
+An attacker could connect a malicious peripheral using ThunderBolt and reboot the machine, which would allow the attacker to modify the system memory.
+This would allow subverting the Secure Boot protection, and also invalidate any system attestation.
+
+**Possible results:**
+
+- `enabled`: detected correctly
+- `not-valid`: could not determine state
+- `not-enabled`: was not enabled
+
+To meet HSI-3 on systems that run this test, the result must be `enabled`. *[v1.8.0]*
+
+Note: a previous version of this attribute existed in 1.5.0 but was only for Intel systems.
+It was renamed in 1.8.0 to support other vendors.
+
+**References:**
+
+- [IOMMU Wikipedia Page](https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit)
+- [AMD IVRS Specification](https://www.amd.com/system/files/TechDocs/48882_IOMMU.pdf)
+
+
+
+
+### [Intel BootGuard: Enabled](#org.fwupd.hsi.IntelBootguard.Enabled)
+
+BootGuard is a processor feature that prevents the machine from running firmware images not released by the system manufacturer.
+It forms a root-of-trust by fusing in cryptographic keys into the processor itself that are used to verify the Authenticated Code Modules found in the SPI flash.
+
+**Impact:** When BootGuard is not set up correctly then the chain-of-trust between the CPU and the bootloader can not be verified.
+This would allow subverting the Secure Boot protection which gives the attacker full access to your hardware.
+
+**Possible results:**
+
+- `enabled`: detected and enabled
+- `not-enabled`: not detected, or detected but not enabled
+
+To meet HSI-2 on systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**References:**
+
+- [Coreboot documentation](https://github.com/coreboot/coreboot/blob/master/src/soc/intel/jasperlake/include/soc/me.h)
+
+
+
+### [Intel BootGuard: Verified](#org.fwupd.hsi.IntelBootguard.Verified)
+
+BootGuard is a processor feature that prevents the machine from running firmware images not released by the system manufacturer.
+It forms a root-of-trust by fusing in cryptographic keys into the processor itself that are used to verify the Authenticated Code Modules found in the SPI flash.
+
+**Impact:** When BootGuard is not set up correctly then the chain-of-trust between the CPU and the bootloader can not be verified.
+This would allow subverting the Secure Boot protection which gives the attacker full access to your hardware.
+
+**Possible results:**
+
+- `success`: verified boot chain
+- `not-valid`: boot is not verified
+
+To meet HSI-2 on systems that run this test, the result must be `success`. *[v1.5.0]*
+
+
+
+### [Intel BootGuard: ACM](#org.fwupd.hsi.IntelBootguard.Acm)
+
+BootGuard is a processor feature that prevents the machine from running firmware images not released by the system manufacturer.
+It forms a root-of-trust by fusing in cryptographic keys into the processor itself that are used to verify the Authenticated Code Modules found in the SPI flash.
+
+**Impact:** When BootGuard is not set up correctly then the chain-of-trust between the CPU and the bootloader can not be verified.
+This would allow subverting the Secure Boot protection which gives the attacker full access to your hardware.
+
+**Possible results:**
+
+- `valid`: ACM protected
+- `not-valid`: boot is not verified
+
+To meet HSI-2 on systems that run this test, the result must be `valid`. *[v1.5.0]*
+
+
+
+### [Intel BootGuard: Policy](#org.fwupd.hsi.IntelBootguard.Policy)
+
+BootGuard is a processor feature that prevents the machine from running firmware images not released by the system manufacturer.
+It forms a root-of-trust by fusing in cryptographic keys into the processor itself that are used to verify the Authenticated Code Modules found in the SPI flash.
+
+**Impact:** The attacker can invalidate the chain of trust (subverting Secure Boot), and the user would get just a console warning and then continue to boot.
+
+**Possible results:**
+
+- `valid`: error enforce policy is set to shutdown
+- `not-valid`: policy is invalid
+
+To meet HSI-3 on systems that run this test, the result must be `valid`. *[v1.5.0]*
+
+
+
+### [Intel BootGuard: OTP](#org.fwupd.hsi.IntelBootguard.Otp)
+
+BootGuard is a processor feature that prevents the machine from running firmware images not released by the system manufacturer.
+It forms a root-of-trust by fusing in cryptographic keys into the processor itself that are used to verify the Authenticated Code Modules found in the SPI flash.
+
+**Impact:** When BootGuard is not set up correctly then the chain-of-trust between the CPU and the bootloader can not be verified.
+This would allow subverting the Secure Boot protection which gives the attacker full access to your hardware.
+
+**Possible results:**
+
+- `valid`: SOC is locked
+- `not-valid`: SOC is not locked
+
+To meet HSI-2 on systems that run this test, the result must be `valid`. *[v1.5.0]*
+
+
+
+### [Suspend to RAM disabled](#org.fwupd.hsi.SuspendToRam)
+
+Suspend to Ram (S3) keeps the raw contents of the DRAM refreshed when the system is asleep.
+This means that the memory modules can be physically removed and the contents recovered, or a cold boot attack can be performed with a USB device.
+The firmware should be configured to prefer using suspend to idle instead of suspend to ram or to not offer suspend to RAM.
+
+**Impact:** An attacker with physical access to a system can obtain the un-encrypted contents of the RAM by suspending the machine, removing the DIMM and inserting it into another machine with modified DRAM controller before the memory contents decay.
+
+**Possible results:**
+
+- `enabled`: sleep enabled
+- `not-enabled`: suspend-to-ram being used
+- `not-valid`: could not determine the default
+
+To meet HSI-3 on systems that run this test, the result must be `not-enabled`. *[v1.5.0]*
+
+**References:**
+
+- [Cold Boot Attack Wikipedia Page](https://en.wikipedia.org/wiki/Cold_boot_attack)
+
+
+
+### [Intel CET: Available](#org.fwupd.hsi.IntelCet.Enabled)
+
+Control enforcement technology is available on new Intel platforms and prevents exploits from hijacking the control-flow transfer instructions for both forward-edge (indirect call/jmp) and back-edge transfer (ret).
+
+**Impact:** A local or physical attacker with an existing unrelated vulnerability can use a reliable and well-known method to run arbitrary code.
+
+**Possible results:**
+
+- `enabled`: feature enabled by the platform
+- `not-supported`: not supported
+
+To meet HSI-3 on systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**References:**
+
+- [Intel CET Technology Preview](https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf)
+
+
+
+### [Intel CET: Active](#org.fwupd.hsi.IntelCet.Active)
+
+Control enforcement technology is available on new Intel platforms and prevents exploits from hijacking the control-flow transfer instructions for both forward-edge (indirect call/jmp) and back-edge transfer (ret).
+
+**Impact:** A local or physical attacker with an existing unrelated vulnerability can use a ROP gadget to run arbitrary code.
+
+**Possible results:**
+
+- `supported`: being used
+- `not-supported`: not being used by the host
+
+To meet HSI-3 on systems that run this test, the result must be `supported`. *[v1.5.0]*
+
+**References:**
+
+- [Intel CET Technology Preview](https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf)
+
+
+
+### [DRAM memory encryption](#org.fwupd.hsi.EncryptedRam)
+
+TME (Intel) or SME (AMD) is used by the hardware on supported SOCs to encrypt all data on external memory buses.
+It mitigates against an attacker being able to capture memory data while the system is running or to capture memory by removing a DRAM chip.
+
+This encryption may be activated by either transparently via firmware configuration or by code running in the Linux kernel.
+
+**Impact:** A local attacker can either extract unencrypted content by attaching debug probes on the DIMM modules, or by removing them and inserting them into a computer with a modified DRAM controller.
+
+**Possible results:**
+
+- `encrypted`: detected and enabled
+- `not-encrypted`: detected but disabled
+- `not-supported`: not available
+
+To meet HSI-4 on systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**References:**
+
+- [Intel TME Press Release](https://software.intel.com/content/www/us/en/develop/blogs/intel-releases-new-technology-specification-for-memory-encryption.html)
+- [WikiChip SME Overview](https://en.wikichip.org/wiki/x86/sme)
+
+
+
+### [AMD Rollback protection](#org.fwupd.hsi.Amd.RollbackProtection)
+
+AMD SOCs include the ability to prevent a rollback attack by a rollback protection feature on the firmware. This feature prevents an attacker from loading an older
+firmware onto the part after a security vulnerability has been fixed.
+
+**Impact:** SOCs without this feature may be attacked by an attacker installing an older firmware that takes advantage of a well-known vulnerability.
+
+**Possible results:**
+
+- `enabled`: rollback protection enabled
+- `not-enabled`: rollback protection disabled
+
+To meet HSI-1 on AMD systems that run this test, the result must be `enabled`. *[v1.8.0]*
+
+**References:**
+
+- [Rollback protection](https://www.psacertified.org/blog/anti-rollback-explained/)
+
+
+
+### [AMD SPI Write protections](#org.fwupd.hsi.Amd.SpiWriteProtection)
+
+SOCs may enforce control of the SPI bus to prevent writes other than by verified entities.
+
+**Impact:** SOCs without this feature may be attacked by an attacker modifying the SPI.
+
+**Possible results:**
+
+- `enabled`: spi protections enabled
+- `not-enabled`: spi protections disabled
+
+To meet HSI-2 on systems that run this test, the result must be `enabled`. *[v1.8.0]*
+
+
+
+### [AMD SPI Replay protections](#org.fwupd.hsi.Amd.SpiReplayProtection)
+
+SOCs may include support for replay-protected monotonic counters to prevent replay attacks.
+
+**Impact:** SOCs without this feature may be attacked by an attacker modifying the SPI.
+
+**Possible results:**
+
+- `enabled`: spi protections enabled
+- `not-enabled`: spi protections disabled
+
+To meet HSI-3 on systems that run this test, the result must be `enabled`. *[v1.8.0]*
+
+
+
+### [Supervisor Mode Access Prevention](#org.fwupd.hsi.IntelSmap)
+
+Without Supervisor Mode Access Prevention, the supervisor code usually has full read and write access to user-space memory mappings.
+This can make exploits easier to write, as it allows the kernel to access user-space memory when it did not intend to.
+
+**Impact:** A local or remote attacker can use a simple exploit to modify the contents of kernel memory which can lead to privilege escalation.
+
+**Possible results:**
+
+- `enabled`: features are detected and enabled
+- `not-supported`: not enabled
+
+To meet HSI-4 on systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**References:**
+
+- [SMAP Wikipedia Page](https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention)
+
+
+
+### [Kernel DMA protection](#org.fwupd.hsi.Iommu)
+
+The IOMMU on modern systems is used to mitigate against DMA attacks.
+All I/O for devices capable of DMA is mapped into a private virtual memory region.
+Common implementations are Intel VT-d and AMD-Vi.
+
+**Impact:** An attacker with inexpensive PCIe development hardware can write to system RAM from the ThunderBolt or Firewire ports which can lead to privilege escalation.
+
+**Possible results:**
+
+- `enabled`: hardware detected and enabled
+- `not-found`: hardware was not detected
+
+To meet HSI-2 on systems that run this test, the result must be `enabled`. *[v1.5.0]*
+
+**Resolution:** If available, turn on IOMMU in the system BIOS. You may also have to use additional kernel boot parameters, for example `intel_iommu=on iommu=pt`.
+
+**References:**
+
+- [IOMMU Wikipedia Page](https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit)
+
+
+
+### [Suspend-to-Idle](#org.fwupd.hsi.SuspendToIdle)
+
+The platform should be set up with Suspend-to-Idle as the default S3 sleep state.
+
+**Impact:** A local attacker could overwrite the S3 resume script to modify system RAM which can lead to privilege escalation.
+
+**Possible results:**
+
+- `enabled`: deep sleep enabled
+- `not-enabled`: suspend-to-idle being used
+- `not-valid`: could not determine the default
+
+To meet HSI-3 on systems that run this test, the result must be `not-enabled`. *[v1.5.0]*
+
+
+
+## [Conclusion](#conclusions)
+
+Any system with a Host Security ID of `0` can easily be modified from userspace.
+PCs with confidential documents should have a `HSI:3` or higher level of protection.
+In a graphical tool that would show details about the computer (such as GNOME Control Center's details tab) the OS could display a field indicating Host Security ID.
+The ID should be shown with an alert color if the security is not at least `HSI:1` or the suffix is `!`.
+
+On Linux `fwupd` is used to enumerate and update firmware.
+It exports a property `HostSecurityId` and a `GetHostSecurityAttrs()` method.
+The attributes are supposed to represent the *system as a whole* but individual (internal) devices are able to make a claim that they worsened the state of the security of the system.
+Certain attributes can "obsolete" other attributes.
+An example is BIOSGuard will set obsoletes to `org.intel.prx`.
+
+A plugin method gets called on each plugin which adds attributes directly from the hardware or kernel.
+Several attributes may be dependent upon the kernel performing measurements and it will take time for these to be upstreamed.
+In some cases security level measurements will only be possible on systems with a newer kernel.
+
+The long term goal is to increase the `HSI:x` level of systems being sold to consumers.
+By making some of the `HSI:x` attributes part of the LVFS uploaded report we can allow users to compare vendors and models before purchasing hardware.
+
+
+
+## [Intentional Omissions](#ommissions)
+
+### Intel SGX
+
+This is not widely used as it has several high severity security issues.
+
+### Intel MPX
+
+MPX support was removed from GCC and the Linux kernel in 2019 and it is now considered obsolete.
+
+## Further Work
+
+More internal and external devices should be factored into the security equation.
+For now the focus for further tests should be around internal device firmware as it is what can be most directly controlled by fwupd and the hardware manufacturer.
+
+Security conscious manufacturers are actively participating in the development of future initiatives in the Trusted Computing Group (TCG).
+As those become ratified standards that are available in hardware, there are opportunities for synergy with this specification.
diff --git a/fwupd-1.8.6/docs/index.html b/fwupd-1.8.6/docs/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..3e58e7a2ebe0ad3e76c1f83623d3c8c348ad0deb
--- /dev/null
+++ b/fwupd-1.8.6/docs/index.html
@@ -0,0 +1,80 @@
+
+
+
+ fwupd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fwupd-1.8.6/docs/meson.build b/fwupd-1.8.6/docs/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..75dd9a3d7b4b840677299298749f8457fa82fbf9
--- /dev/null
+++ b/fwupd-1.8.6/docs/meson.build
@@ -0,0 +1,91 @@
+if gidocgen_dep.found() and docs_python_deps.allowed() and gidocgen_app.found() and introspection.allowed()
+ toml_conf = configuration_data()
+ docgen_version = source_version
+ if git.found() and source_version != fwupd_version
+ docgen_version = run_command(git, 'branch', '--show-current').stdout().strip()
+ endif
+ toml_conf.set('version', docgen_version)
+
+ fwupd_toml = configure_file(
+ input: 'fwupd.toml.in',
+ output: 'fwupd.toml',
+ configuration: toml_conf
+ )
+
+ fwupdplugin_toml = configure_file(
+ input: 'fwupdplugin.toml.in',
+ output: 'fwupdplugin.toml',
+ configuration: toml_conf
+ )
+
+ custom_target('doc-fwupd',
+ input: [
+ fwupd_toml,
+ fwupd_gir[0],
+ ],
+ output: 'libfwupd',
+ command: [
+ gidocgen_app,
+ 'generate',
+ '--quiet',
+ '--add-include-path=@0@'.format(meson.current_build_dir() / '../libfwupd'),
+ '--config=@INPUT0@',
+ '--output-dir=@OUTPUT@',
+ '--no-namespace-dir',
+ '--content-dir=@0@'.format(meson.current_source_dir()),
+ '@INPUT1@',
+ ],
+ depends: [
+ fwupd_gir[0],
+ ],
+ build_by_default: true,
+ install: true,
+ install_dir: join_paths(datadir, 'doc'),
+ )
+
+ custom_target('doc-fwupdplugin',
+ input: [
+ fwupdplugin_toml,
+ fwupdplugin_gir[0],
+ ],
+ output: 'libfwupdplugin',
+ command: [
+ gidocgen_app,
+ 'generate',
+ '--quiet',
+ '--add-include-path=@0@'.format(meson.current_build_dir() / '../libfwupd'),
+ '--add-include-path=@0@'.format(meson.current_build_dir() / '../libfwupdplugin'),
+ '--config=@INPUT0@',
+ '--output-dir=@OUTPUT@',
+ '--no-namespace-dir',
+ '--content-dir=@0@'.format(meson.current_source_dir()),
+ '@INPUT1@',
+ ],
+ depends: [
+ fwupdplugin_gir[0],
+ ],
+ build_by_default: true,
+ install: true,
+ install_dir: join_paths(datadir, 'doc'),
+ )
+ if hsi
+ install_data(['index.html', 'hsi.html'],
+ install_dir : join_paths(datadir, 'doc', 'fwupd')
+ )
+ endif
+ install_data(['urlmap_fwupd.js'],
+ install_dir: join_paths(datadir, 'doc', 'libfwupd')
+ )
+ install_data(['urlmap_fwupdplugin.js'],
+ install_dir: join_paths(datadir, 'doc', 'libfwupdplugin')
+ )
+ #make devhelp work
+ install_symlink('libfwupd',
+ install_dir: join_paths(datadir, 'doc', 'fwupd'),
+ pointing_to: join_paths('..', 'libfwupd'),
+ )
+ install_symlink('libfwupdplugin',
+ install_dir: join_paths(datadir, 'doc', 'fwupd'),
+ pointing_to: join_paths('..', 'libfwupdplugin'),
+ )
+endif
diff --git a/fwupd-1.8.6/docs/tutorial.md b/fwupd-1.8.6/docs/tutorial.md
new file mode 100644
index 0000000000000000000000000000000000000000..aba4cd42eae7c08a2191ab3e2d61fc7b47e23381
--- /dev/null
+++ b/fwupd-1.8.6/docs/tutorial.md
@@ -0,0 +1,827 @@
+---
+title: Plugin Tutorial
+---
+
+## Introduction
+
+At the heart of fwupd are plugins that gets run at startup, when devices
+get hotplugged and when updates are done.
+The idea is we have lots of small plugins that each do one thing, and are
+ordered by dependencies against each other at runtime.
+Using plugins we can add support for new hardware or new policies without making
+big changes all over the source tree.
+
+There are broadly 3 types of plugin methods:
+
+- **Mechanism**: Upload binary data into a specific hardware device.
+- **Policy**: Control the system when updates are happening, e.g. preventing the
+ user from powering-off.
+- **Helpers**: Providing more metadata about devices, for instance handling device quirks.
+
+A plugin only needs to define the vfuncs that are required, and the plugin name
+is taken automatically from the GType.
+
+ /* fu-foo-plugin.h
+ *
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+ #pragma once
+
+ #include
+
+ G_DECLARE_FINAL_TYPE(FuFooPlugin, fu_foo_plugin, FU, FOO_PLUGIN, FuPlugin)
+
+ /* fu-foo-plugin.c
+ *
+ * Copyright (C) Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+ #include "config.h"
+
+ #include "fu-foo-plugin.h"
+
+ struct _FuFooPlugin {
+ FuPlugin parent_instance;
+ gpointer proxy;
+ };
+
+ G_DEFINE_TYPE(FuFooPlugin, fu_foo_plugin, FU_TYPE_PLUGIN)
+
+ static gboolean
+ fu_foo_plugin_startup(FuPlugin *plugin, FuProgress *progress, GError **error)
+ {
+ FuPluginData *data = fu_plugin_get_data(plugin);
+ self->proxy = create_proxy();
+ if(self->proxy == NULL) {
+ g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED,
+ "failed to create proxy");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ static void
+ fu_foo_plugin_init(FuFooPlugin *self)
+ {
+ }
+
+ static void
+ fu_foo_constructed(GObject *obj)
+ {
+ FuPlugin *plugin = FU_PLUGIN(obj);
+ FuContext *ctx = fu_plugin_get_context(plugin);
+ fu_plugin_add_rule(plugin, FU_PLUGIN_RULE_RUN_BEFORE, "dfu");
+ }
+
+ static void
+ fu_foo_finalize(GObject *obj)
+ {
+ FuFooPlugin *self = FU_FOO_PLUGIN(obj);
+ destroy_proxy(self->proxy);
+ G_OBJECT_CLASS(fu_foo_plugin_parent_class)->finalize(obj);
+ }
+
+ static void
+ fu_foo_plugin_class_init(FuFooPluginClass *klass)
+ {
+ FuPluginClass *plugin_class = FU_PLUGIN_CLASS(klass);
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->constructed = fu_foo_constructed;
+ object_class->finalize = fu_foo_finalize;
+ plugin_class->startup = fu_foo_plugin_startup;
+ }
+
+We have to define when our plugin is run in reference to other plugins, in this
+case, making sure we run before the `dfu` plugin.
+
+For most plugins it does not matter in what order they are run and this
+information is not required.
+
+## 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.
+The example here is all hardcoded, and a true plugin would have to
+derive the details about the `FuDevice` from the hardware, for example reading
+data from `sysfs` or `/dev`.
+
+ static gboolean
+ fu_foo_plugin_coldplug(FuPlugin *plugin, FuProgress *progress, GError **error)
+ {
+ g_autoptr(FuDevice) dev = NULL;
+ fu_device_set_id(dev, "dummy-1:2:3");
+ fu_device_add_guid(dev, "2d47f29b-83a2-4f31-a2e8-63474f4d4c2e");
+ fu_device_set_version(dev, "1.2.3");
+ fu_device_get_version_lowest(dev, "1.2.2");
+ fu_device_get_version_bootloader(dev, "0.1.2");
+ fu_device_add_icon(dev, "computer");
+ fu_device_add_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE);
+ fu_plugin_device_add(plugin, dev);
+ return TRUE;
+ }
+
+ static void
+ fu_foo_plugin_class_init(FuFooPluginClass *klass)
+ {
+ …
+ plugin_class->coldplug = fu_foo_plugin_coldplug;
+ …
+ }
+
+This shows a lot of the plugin architecture in action.
+Some notable points:
+
+- The device ID (`dummy-1:2:3`) has to be unique on the system between all
+plugins, so including the plugin name as a prefix is probably a good idea.
+
+- The GUID value can be generated automatically using
+`fu_device_add_guid(dev,"some-identifier")` but is quoted here explicitly. The
+GUID value has to match the `provides` value in the `.metainfo.xml` file for the
+firmware update to succeed.
+
+- Setting a display name and an icon is a good idea in case the GUI software
+needs to display the device to the user. Icons can be specified using a full
+path, although icon theme names should be preferred for most devices.
+
+- The `FWUPD_DEVICE_FLAG_UPDATABLE` flag tells the client code that the device
+is in a state where it can be updated. If the device needs to be in a special
+mode (e.g. a bootloader) then the `FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER` flag can
+also be used. If the update should only be allowed when there is AC power
+available to the computer (i.e. not on battery) then
+`FWUPD_DEVICE_FLAG_REQUIRE_AC` should be used as well. There are other flags and
+the API documentation should be used when choosing what flags to use for each
+kind of device.
+
+- Setting the lowest allows client software to refuse downgrading the device to
+specific versions.
+This is required in case the upgrade migrates some kind of data-store so as to
+be incompatible with previous versions.
+Similarly, setting the version of the bootloader (if known) allows the firmware
+to depend on a specific bootloader version, for instance allowing signed
+firmware to only be installable on hardware with a bootloader new enough to
+deploy it.
+
+## Mechanism Plugins
+
+Although it would be a wonderful world if we could update all hardware using a
+standard shared protocol this is not the universe we live in.
+Using a mechanism like DFU or UpdateCapsule means that fwupd will just work
+without requiring any special code, but for the real world we need
+to support vendor-specific update protocols with layers of backwards compatibility.
+
+When a plugin has created a device that is `FWUPD_DEVICE_FLAG_UPDATABLE` we can
+ask the daemon to update the device with a suitable `.cab` file.
+When this is done the daemon checks the update for compatibility with the device,
+and then calls the vfuncs to update the device.
+
+ static gboolean
+ fu_foo_plugin_write_firmware(FuPlugin *plugin,
+ FuDevice *dev,
+ GBytes *blob_fw,
+ FuProgress *progress,
+ FwupdInstallFlags flags,
+ GError **error)
+ {
+ gsize sz = 0;
+ guint8 *buf = g_bytes_get_data(blob_fw, &sz);
+ /* write 'buf' of size 'sz' to the hardware */
+ return TRUE;
+ }
+
+ static void
+ fu_foo_plugin_class_init(FuFooPluginClass *klass)
+ {
+ …
+ plugin_class->write_firmware = fu_foo_plugin_write_firmware;
+ …
+ }
+
+It's important to note that the `blob_fw` is the binary firmware file
+(e.g. `.dfu`) and **not** the `.cab` binary data.
+
+If `FWUPD_INSTALL_FLAG_FORCE` is used then the usual checks done by the flashing
+process can be relaxed (e.g. checking for quirks), but please don't brick the
+users hardware even if they ask you to.
+
+## Policy Helpers
+
+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 threshold, or it could be as complicated as ensuring a vendor-specific
+GPIO is asserted when specific types of hardware are updated.
+
+ static gboolean
+ fu_foo_plugin_prepare(FuPlugin *plugin, FuDevice *device, GError **error)
+ {
+ if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_REQUIRE_AC && !on_ac_power()) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_AC_POWER_REQUIRED,
+ "Cannot install update "
+ "when not on AC power");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ static gboolean
+ fu_foo_plugin_cleanup(FuPlugin *plugin, FuDevice *device, GError **error)
+ {
+ return g_file_set_contents("/var/lib/fwupd/something",
+ fu_device_get_id(device), -1, error);
+ }
+
+ static void
+ fu_foo_plugin_class_init(FuFooPluginClass *klass)
+ {
+ …
+ plugin_class->prepare = fu_foo_plugin_prepare;
+ plugin_class->cleanup = fu_foo_plugin_cleanup;
+ …
+ }
+
+## Detaching to bootloader mode
+
+Some hardware can only be updated in a special bootloader mode, which 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.
+
+Before the device update is performed the fwupd daemon runs an optional
+`update_detach()` vfunc which switches the device to bootloader mode.
+
+After the update (or if the update fails) an the daemon runs an optional
+`update_attach()` vfunc which should switch the hardware back to runtime mode.
+Finally an optional `update_reload()` vfunc is run to get the new firmware
+version from the hardware.
+
+The optional vfuncs are **only** run on the plugin currently registered to
+handle the device ID, although the registered plugin can change during the
+attach and detach phases.
+
+ static gboolean
+ fu_foo_plugin_detach(FuPlugin *plugin, FuDevice *device, FuProgress *progress, GError **error)
+ {
+ if (hardware_in_bootloader)
+ return TRUE;
+ return _device_detach(device, progress, error);
+ }
+
+ static gboolean
+ fu_foo_plugin_attach(FuPlugin *plugin, FuDevice *device, FuProgress *progress, GError **error)
+ {
+ if (!hardware_in_bootloader)
+ return TRUE;
+ return _device_attach(device, progress, error);
+ }
+
+ static gboolean
+ fu_foo_plugin_reload(FuPlugin *plugin, FuDevice *device, GError **error)
+ {
+ g_autofree gchar *version = _get_version(plugin, device, error);
+ if (version == NULL)
+ return FALSE;
+ fu_device_set_version(device, version);
+ return TRUE;
+ }
+
+ static void
+ fu_foo_plugin_class_init(FuFooPluginClass *klass)
+ {
+ …
+ plugin_class->detach = fu_foo_plugin_detach;
+ plugin_class->attach = fu_foo_plugin_attach;
+ plugin_class->reload = fu_foo_plugin_reload;
+ …
+ }
+
+## The Plugin Object Cache
+
+The fwupd daemon provides a per-plugin cache which allows objects to be added,
+removed and queried using a specified key.
+Objects added to the cache must be `GObject`s to enable the cache objects to be
+properly refcounted.
+
+## Debugging a Plugin
+
+If the fwupd daemon is started with `--plugin-verbose=$plugin` then the
+environment variable `FWUPD_$PLUGIN_VERBOSE` is set process-wide.
+This allows plugins to detect when they should output detailed debugging
+information that would normally be too verbose to keep in the journal.
+For example, using `--plugin-verbose=logitech_hidpp` would set
+`FWUPD_LOGITECH_HID_VERBOSE=1`.
+
+## Using existing code to develop a plugin
+
+It is not usually possible to share a plugin codebase with firmware update
+programs designed for other operating systems.
+
+Matching the same rationale as the Linux kernel, trying to use one code base
+between projects with a compatibility shim layer in-between is real headache to
+maintain.
+
+The general consensus is that trying to use a abstraction layer for hardware is
+a very bad idea as you're not able to take advantage of the platform specific
+helpers -- for instance quirk files and the custom GType device creation.
+
+The time the vendor saves by creating a shim layer and importing existing source
+code into fwupd will be overtaken 100x by upstream maintenance costs longer term,
+which isn't fair.
+
+In a similar way, using C++ rather than GObject C means expanding the test matrix
+to include clang in C++ mode and GNU g++ too.
+It's also doubled the runtime requirements to now include both the C standard library
+as well as the C++ standard library and increases the dependency surface.
+
+Most rewritten fwupd plugins at up to x10 smaller than the standalone code as they
+can take advantage of helpers provided by fwupd rather than re-implementing error
+handling, device quirking and data chunking.
+
+## General guidelines for plugin developers
+
+### General considerations
+
+When adding support for a new device in fwupd some things need to be
+evaluated beforehand:
+
+- how the hardware is discovered, identified and polled.
+- how to communicate with the device (USB? file open/read/write?)
+- does the device need to be switched to bootloader mode to make it
+ upgradable?
+- about the format of the firmware files, do they follow any standard?
+ are they already supported in fwupd?
+- about the update protocol, is it already supported in fwupd?
+- Is the device composed of multiple different devices? Are those
+ devices enumerated and programmed independently or are they accessed
+ and flashed through a "root" device?
+
+In most cases, even if the features you need aren't implemented yet,
+there's already a plugin that does something similar and can be used as
+an example, so it's always a good idea to read the code of the existing
+plugins to understand how they work and how to write a new one, as no
+documentation will be as complete and updated as the code
+itself. Besides, the mechanisms implemented in the plugin collection are
+very diverse and the best way of knowing what can be done is to check
+what is already been done.
+
+### Leveraging existing fwupd code
+
+Depending on how much of the key items for the device update (firmware
+format, update protocol, transport layer) are already supported in
+fwupd, the work needed to add support for a new device can range from
+editing a quirk file to having to fully implement new device and
+firmware types, although in most cases fwupd already implements helper
+code that can be extended.
+
+#### If the firmware format, update protocol and device communication are already supported
+
+This is the simplest case, where an existing plugin fully implements the
+update process for the new device and we only have to let fwupd know
+that that plugin should be used for our device. In this case the only
+thing to do is to edit the plugin quirk file and add the device
+identifier in the format expected by the plugin together with any
+required options for it (at least a "Plugin" key to declare that this is
+the plugin to use for this device). Example:
+
+
+#### If the device type is not supported
+
+Then we have to take a look at the existing device types and check if
+there's any of them that have similarities and which can be partially
+reused or extended for our device. If the device type is derivable and
+it can support our new device by implementing the proper vfuncs, then we
+can simply subclass it and add the required functionalities. If not,
+we'll need to study what is the best way to reuse it for our needs.
+
+If a plugin already implements most of the things we need besides the
+device type, we can add our new device type to that plugin. Otherwise we
+should create a plugin that will hold the new device type.
+
+The core fwupd code contains some basic device types (such as
+[FuUdevDevice](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-udev-device.c), [FuUsbDevice](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-usb-device.c), [FuBluezDevice](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-bluez-device.c)) that can be used as a base
+type for most devices in case we have to implement our own device
+access, identification and communication from scratch.
+
+If the device is natively visible by the OS, most of the time fwupd can
+detect the device connection and disconnection by listening to udev
+events, but a supported device may also be not directly accessible from
+the OS -- for example, a composite device that contains an updatable chip
+that's connected through I2C to a USB hub that acts as an interface. In
+that case, the device discovery and enumeration must be programmed by
+the developer, but the same device identification and management
+mechanisms apply in all cases. See the "Creating a new device type" and
+"Device identification" below for more details.
+
+#### If the firmware type is not supported
+
+Same as with the new device type, there could be an existing firmware
+type that can be used as a base type for our new type, so first of all
+we should look for firmware types that are similar to the one we're
+using. Then, choosing where to define the new type depends on whether
+there's already a plugin that implements most of the functionalities we
+need or not.
+
+### Example: extending a firmware type
+
+Our firmware files are Intel HEX files that have optional
+vendor-specific sections at fixed addresses, this is not supported by
+any firmware type in fwupd out of the box but the [FuIhexFirmare](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-ihex-firmware.c) class
+parses and models a standard Intel HEX file, so we can create a subclass
+of it for our firmware type and override the parse method so that it
+calls the method from the parent class, which would parse the file, and
+then we can get the data with `fu_firmware_get_bytes()` and do the rest of
+the custom parsing. Example:
+
+
+### Example: extending a device type
+
+Communication with our new device is carried out by doing
+read/write/ioctl operations on a device file, but using a custom
+protocol that is not supported in fwupd.
+
+For this type of device we can create a new type derived from
+`FuUdevDevice`, which takes care of discovering this type of devices,
+possibly using a vendor-specific protocol, as well as of opening,
+reading and writing device files, so we would only have to implement the
+protocol on top of those primitives. (Example:
+`fu_logitech_hidpp_runtime_bolt_poll_peripherals()` in
+)
+The process would be similar if our device was handled by a different
+backend (USB or BlueZ).
+
+### Creating a new plugin
+
+The bare minimum a plugin should have is a `constructed` function that
+defines the plugin characteristics such as the device type and firmware
+type handled by it, the build hash and any plugin-specific quirk keys
+that can be used for the plugin.
+
+ static void
+ fu_foo_plugin_constructed(GObject *obj)
+ {
+ FuPlugin *plugin = FU_PLUGIN(obj);
+ FuContext *ctx = fu_plugin_get_context(plugin);
+ fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_MOUSE);
+ fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_GAMEPAD);
+ }
+
+ static void
+ fu_foo_plugin_class_init(FuFooPluginClass *klass)
+ {
+ plugin_class->init = fu_foo_plugin_constructed;
+ }
+
+### Creating a new device type
+
+Besides defining its attributes as a data type, a device type should
+implement at least the usual `init`, `finalize` and `class_init` functions,
+and then, depending on its parent type, which methods it overrides and
+what it does, it must implement a set of device methods. These are some
+of them, the complete list is in [libfwupdplugin/fu-device.h](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.h).
+
+#### to_string
+
+Called whenever fwupd needs a human-readable representation of the
+device.
+
+#### probe
+
+The `probe` method is called the first time a device is opened, before
+actually opening it. The generic probe methods implemented in the base
+device types (such as USB/udev) take care of basic device identification
+and setting the non-specific parameters that don't need the device to be
+opened or the interface claimed (vendor id, product id, guids, etc.).
+
+The device-specific probe method should start by calling the generic
+method upwards in the class tree and then do any other specific setup
+such as setting the appropriate device flags.
+
+#### open
+
+Depending on the type of device, opening it means different things. For
+instance, opening a udev device means opening its device file.
+
+If there's no interface-specific `open` method, then opening a device
+simply calls the `probe()` and `setup()` methods (the `open()` method would be
+called in between if it exists).
+
+#### setup
+
+Sets parameters on the device object that require the device to be open
+and have the interface claimed. USB/udev generic devices don't implement
+this method, this is normally implemented for each different plugin
+device type if needed.
+
+#### prepare
+
+If implemented, this takes care of decompressing or parsing the firmware
+data. For example, to check if the firmware is valid, if it's suitable
+for the device, etc.
+
+It takes a stream of bytes (`GBytes`) as a parameter, representing the
+raw binary firmware data.
+
+It should create the firmware object and call the appropriate method to
+load the firmware. Otherwise, if it's not implemented for the specific
+device type, the generic implementation in
+[libfwupdplugin/fu-device.c](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.c):`fu_device_prepare_firmware()`
+creates a firmware object loaded with a provided image.
+
+#### detach
+
+Implemented if the device needs to be put in bootloader mode before
+updating, this does all the necessary operations to put the device in
+that mode. fwupd can handle the case where a device needs to be
+disconnected to do the mode switch if the device has the
+`FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG` flag.
+
+#### attach
+
+The inverse of `detach()`, to configure the device back to application mode.
+
+#### reload
+
+If implemented, this is called after the device update if it needs to
+perform any kind of post-update operation.
+
+#### write_firmware
+
+Writes a firmware passed as a raw byte stream. The firmware parsing and
+processing is done by the firmware object, so that when this method gets
+the blob it simply has to write it to the device in the appropriate way
+following the device update protocol.
+
+#### read_firmware
+
+Reads the firmware data from the device without any device-specific
+configuration or serial numbers. This is meant to retrieve the current
+firmware contents for verification purposes. The data read can then be
+output to a binary blob using `fu_firmware_write()`.
+
+#### set_progress
+
+Informs the daemon of the expected duration percentages for the different
+phases of update. The daemon runs the `->detach()`, `->write_firmware()`,
+`->attach()` and `->reload()` phases as part of the engine during the firmware
+update (rather than being done by plugin-specific code) and so this vfunc
+informs the daemon how to scale the progress output accordingly.
+
+For instance, if your update takes 2 seconds to detach into bootloader mode,
+10 seconds to write the firmware, 7 seconds to attach back into runtime mode
+(which includes the time required for USB enumeration) and then 1 second to
+read the new firmware version you would use:
+
+ fu_progress_set_id(progress, G_STRLOC);
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 10, "detach");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 45, "write");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 40, "attach");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 5, "reload");
+
+If however your device does not require `->detach()` or `->attach()`, and
+`->reload()` is instantaneous, you still however need to include 4 steps:
+
+ fu_progress_set_id(progress, G_STRLOC);
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 0, "detach");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 100, "write");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 0, "attach");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0, "reload");
+
+If the device has multiple phases that occur when actually in the write phase
+then it is perfectly okay to split up the `FuProgress` steps in the
+`->write_firmware()` vfunc further. For instance:
+
+ fu_progress_set_id(progress, G_STRLOC);
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 5, "wait-for-idle");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 90, "write");
+ fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 5, "reset");
+
+It should be noted that actions that are required to be done *before* the update
+should be added as a `->prepare()` vfunc, and those to be done after in the `->cleanup()`
+as the daemon will then recover the hardware if the update fails. For instance,
+putting the device back into a *normal runtime power saving* state should always
+be done during cleanup.
+
+### Creating a new firmware type
+
+The same way a device type implements some methods to complete its
+functionality and override certain behaviors, there's a set of firmware
+methods that a firmware class can (or must) implement:
+
+#### parse
+
+If implemented, it parses the firmware file passed as a byte
+sequence. If the firmware to be used contains a custom header, a
+specific structured format or multiple images embedded, this method
+should take care of processing the format and appropriately populating
+the `FuFirmware` object passed as a parameter. If not implemented, the
+whole data blob is taken as is.
+
+#### write
+
+Returns a `FuFirmware` object as a byte sequence. This can be used to
+output a firmware read with `fu_device_read_firmware()` as a binary
+blob.
+
+#### export
+
+Converts a `FuFirmware` object to an xml representation. If not
+implemented, the default implementation generates an xml representation
+containing only generic attributes and, optionally, the firmware data as
+well as the representation of children firmware nodes.
+
+When testing the implementation of a new firmware type, this is useful
+to show if the parsing and processing of the firmware are correct and
+can be checked with:
+
+ fwupdtool firmware-parse --plugins
+
+#### tokenize
+
+If implemented it tokenizes a firmware, breaking it into records.
+
+#### build
+
+This is the reverse of `export()`, it builds a `FuFirmware` object from
+an xml representation.
+
+#### get_checksum
+
+The default implementation returns a checksum of the payload data of a
+`FuFirmware` object. Subclass it only if the checksum of your firmware
+needs to be computed differently.
+
+### Device identification
+
+A device is identified in fwupd by its physical and logical ids. A
+physical id represents the electrical connection of the device to the
+system and many devices can have the same physical id. For example,
+`PCI_SLOT_NAME=0000:3e:00:0` (see
+[libfwupdplugin/fu-udev-device.c](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-udev-device.c):`fu_udev_device_set_physical_id()` for
+examples) . The logical id is used to disambiguate devices with the same
+physical id. Together they identify a device uniquely. There are many
+examples of this in the existing plugins, such as
+`fu_pxi_receiver_device_add_peripherals()` in
+
+
+Besides that, each device type will have a unique instance id, which is
+a string representing the device subsystem, vendor, model and revision
+(specific details depend on the device type). This should identify a
+device type in the system, that is, a particular device type, model and
+revision by a specific vendor will have a defined instance id and two of
+the same device will have the same instance id (see
+[libfwupdplugin/fu-udev-device.c](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-udev-device.c):`fu_udev_device_probe()`
+for examples).
+
+One or more GUIDs are generated for a device from its identifying
+attributes, these GUIDs are then used to match a firmware metadata
+against a specific device type. See the implementation of the many
+`probe()` methods for examples.
+
+### Support for BLE devices
+
+BLE support in fwupd on Linux is provided by BlueZ. If the device
+implements the standard HID-over-GATT BLE profile, then communication
+with the device can be done through the [hidraw
+interface](https://www.kernel.org/doc/html/latest/hid/hidraw.html). If
+the device implements a custom BLE profile instead, then it will have to
+be managed by the `FuBluezBackend`, which uses the BlueZ DBus interface
+to communicate with the devices. The `FuBluezDevice` type implements
+device enumeration as well as the basic primitives to read and write BLE
+characteristics, and can be used as the base type for a more specific
+BLE device.
+
+### Battery checks
+
+If the device can be updated wirelessly or if the update process doesn't
+rely on an external power supply, the vendor might define a minimum
+operative battery level to guarantee a correct update. fwupd provides a
+simple API to define these requirements per-device.
+
+[fu_device_set_battery_threshold()](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.c)
+can be used to define the minimum battery level required to allow a
+firmware update on a device (10% by default). If the battery level is
+below that threshold, fwupd will inhibit the device to prevent the user
+from starting a firmware update. Then, the battery level of a device can
+be queried and then set with
+[fu_device_set_battery_level()](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.c).
+
+## Howtos
+
+### How to create a child device
+
+fwupd devices can be hierarchically ordered to model dependent and
+composite devices such as docking stations composed of multiple
+updatable chips. When writing support for a new composite device the
+parent device should, at some point, poll the devices that "hang" from
+it and register them in fwupd. The process of polling and identifying a
+child device is totally vendor and device-specific, although the main
+requirement for it is that the child device is properly identified
+(having physical/logical and instance ids). Then,
+[fu_device_add_child()](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.c)
+can be used to add a new child device to an existing one. See
+`fu_logitech_hidpp_runtime_bolt_poll_peripherals()` in
+
+for an example.
+
+Note that when deploying and installing a firmware set for a composite
+device, there might be firmware dependencies between parent and child
+devices that require a specific update ordering (for instance, child
+devices first, then the parent). This can be modeled by setting an
+appropriate firmware priority in the firmware metainfo or by setting the
+`FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST` device flag.
+
+### How to add a delay
+
+In certain scenarios you may need to introduce small controlled delays
+in the plugin code, for instance, to comply with a communications
+protocol or to wait for the device to be ready after a particular
+operation. In this case you can insert a delay in microseconds with
+`g_usleep` or a delay in seconds that shows a progress bar with
+`fu_device_sleep_with_progress`. Note that, in both cases, this will
+stop the application main loop during the wait, so use it only when
+necessary.
+
+### How to define private flags
+
+Besides the regular flags and internal flags that any device can have, a
+device can define private flags for specific uses. These can be enabled
+in the code as well as in quirk files, just as the rest of flags. To
+define a private flag:
+
+1. Define the flag value. This is normally defined as a macro that
+ expands to a binary flag, for example: `#define MY_PRIVATE_FLAG (1 <<
+ 2)`. Note that this will be part of the ABI, so it must be versioned
+1. Call `fu_device_register_private_flag` in the device init function
+ and assign a string identifier to the flag:
+ `fu_device_register_private_flag (FU_DEVICE (self), MY_PRIVATE_FLAG,
+ "myflag");`
+
+You can then add it to the device programmatically with
+`fu_device_add_private_flag`, remove it with `fu_device_remove_private_flag`
+and query it with `fu_device_has_private_flag`. In a quirk file, you can
+add the flag identifier to the Flags attribute of a device (eg. `Flags =
+myflag,is-bootloader`)
+
+### How to make fwupd wait for a device replug
+
+Certain devices require a disconnection and reconnection to start the
+update process. A common example are devices that have two booting
+modes: application or runtime mode, and bootloader mode, where the
+runtime mode is the normal operation mode and the bootloader mode is
+exclusively used to update the device firmware. It's common for these
+devices to require some operation from fwupd to switch the booting mode
+and then to need a reset to enter bootloader mode. Often, the device is
+enumerated differently in both modes, so fwupd needs to know that the
+same device will be identified differently depending on the boot mode.
+
+The common way to do this is to add the
+`FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG` flag in the device before its detach
+method returns. This will make fwupd wait for a predetermined amount of
+time for the device to be detected again. Then, to inform fwupd about
+the two identities of the same device, the `CounterpartGuid` key can be
+used in a device entry to match it with another defined device (example:
+).
+
+### Inhibiting a device
+
+If a device becomes unsuitable for an update for whatever reason (see
+"Battery checks" above for an example), a plugin can temporarily disable
+firmware updates on it by calling [fu_device_inhibit()](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.c). The device will
+still be listed as present by `fwupdmgr get-devices`, but fwupd won't
+allow firmware updates on it. Device inhibition can be disabled with
+[fu_device_uninhibit()](https://github.com/fwupd/fwupd/blob/main/libfwupdplugin/fu-device.c).
+
+Note that there might be multiple inhibits on a specific device, the
+device will only be updatable when all of them are removed.
+
+## Debugging tips
+
+The most important rule when debugging is using the `--verbose` flag
+when running fwupd or fwupdtool. Besides that, there are many
+environment variables that allow some debug traces to be printed
+conditionally, for example: `FWUPD_PROBE_VERBOSE`,
+`FU_HID_DEVICE_VERBOSE`, `FWUPD_DEVICE_LIST_VERBOSE` and many other
+plugin-specific envvars.
+
+### Adding debug messages
+
+The usual way to print a debug message is using the `g_debug` macro. Each
+relevant module will define its own `G_LOG_DOMAIN` to tag the debug traces
+accordingly. See
+ and
+ for more
+information.
+
+### Inspecting raw binary data
+
+The `fu_dump_full` and `fu_dump_raw` functions implement the
+printing of a binary buffer to the console as a stream of bytes in
+hexadecimal. See `libfwupdplugin/fu-common.c` for their definitions, you
+can find many examples of how to use them in the plugins code.
diff --git a/fwupd-1.8.6/docs/urlmap_fwupd.js b/fwupd-1.8.6/docs/urlmap_fwupd.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e7f2cb321da36d3b75124a47dcdc17b6ec53bad
--- /dev/null
+++ b/fwupd-1.8.6/docs/urlmap_fwupd.js
@@ -0,0 +1,4 @@
+baseURLs = [
+ [ 'Gio', 'https://people.gnome.org/~ebassi/docs/_build/Gio/' ],
+ [ 'GObject', 'https://people.gnome.org/~ebassi/docs/_build/GObject/' ],
+]
diff --git a/fwupd-1.8.6/docs/urlmap_fwupdplugin.js b/fwupd-1.8.6/docs/urlmap_fwupdplugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..a41bcdb879366a01c1142d0ab5346eb698741f01
--- /dev/null
+++ b/fwupd-1.8.6/docs/urlmap_fwupdplugin.js
@@ -0,0 +1,5 @@
+baseURLs = [
+ [ 'Gio', 'https://people.gnome.org/~ebassi/docs/_build/Gio/' ],
+ [ 'GObject', 'https://people.gnome.org/~ebassi/docs/_build/GObject/' ],
+ [ 'Fwupd', '../libfwupd/' ],
+]
diff --git a/fwupd-1.8.6/libfwupd/README.md b/fwupd-1.8.6/libfwupd/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..de31bfa4e4844caf28fdaf7ad9b7ac056c43c06a
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/README.md
@@ -0,0 +1,31 @@
+# libfwupd
+
+## Planned API/ABI changes for next release
+
+* Typedef `FwupdFeatureFlags` to `guint64` so it's the same size on all platforms
+* Remove the `soup-session` fallback property in `FwupdClient`.
+* Remove fwupd_device_set_vendor_id() and fwupd_device_get_vendor_id()
+* Remove the deprecated flags like `FWUPD_DEVICE_FLAG_MD_SET_ICON`
+* Remove `fwupd_release_get_uri()` and `fwupd_release_set_uri()`
+* Rename `fwupd_client_install_release2_async()` to `fwupd_client_install_release_async()`
+* Remove fwupd_device_set_protocol() and fwupd_device_get_protocol()
+* Remove deprecated install flag `FWUPD_INSTALL_FLAG_IGNORE_POWER`
+
+## Migration from Version 0.9.x
+
+* Rename FU_DEVICE_FLAG -> FWUPD_DEVICE_FLAG
+* Rename FWUPD_DEVICE_FLAG_ALLOW_ONLINE -> FWUPD_DEVICE_FLAG_UPDATABLE
+* Rename FWUPD_DEVICE_FLAG_ALLOW_OFFLINE -> FWUPD_DEVICE_FLAG_ONLY_OFFLINE
+* Rename fwupd_client_get_devices_simple -> fwupd_client_get_devices
+* Rename fwupd_client_get_details_local -> fwupd_client_get_details
+* Rename fwupd_client_update_metadata_with_id -> fwupd_client_update_metadata
+* Rename fwupd_remote_get_uri -> fwupd_remote_get_metadata_uri
+* Rename fwupd_remote_get_uri_asc -> fwupd_remote_get_metadata_uri_sig
+* Rename fwupd_remote_build_uri -> fwupd_remote_build_firmware_uri
+* Switch FWUPD_RESULT_KEY_DEVICE_CHECKSUM_KIND to fwupd_checksum_guess_kind()
+* Rename fwupd_result_update_*() to fwupd_release_*()
+* Rename fwupd_result_*() to fwupd_device_*()
+* Convert FwupdResult to FwupdDevice in all callbacks
+* Rename fwupd_device_*_provider -> fwupd_device_*_plugin
+* Convert hash types sa{sv} -> a{sv}
+* Convert fwupd_client_get_updates() -> fwupd_client_get_upgrades()
diff --git a/fwupd-1.8.6/libfwupd/fwupd-bios-setting-private.h b/fwupd-1.8.6/libfwupd/fwupd-bios-setting-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..741b0eae0eb439087c87dedd0fb23a0146824ce2
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-bios-setting-private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include
+
+#include "fwupd-bios-setting.h"
+
+#pragma once
+
+GVariant *
+fwupd_bios_setting_to_variant(FwupdBiosSetting *self, gboolean trusted);
+void
+fwupd_bios_setting_to_json(FwupdBiosSetting *self, JsonBuilder *builder);
+gboolean
+fwupd_bios_setting_from_json(FwupdBiosSetting *self, JsonNode *json_node, GError **error);
diff --git a/fwupd-1.8.6/libfwupd/fwupd-bios-setting.c b/fwupd-1.8.6/libfwupd/fwupd-bios-setting.c
new file mode 100644
index 0000000000000000000000000000000000000000..26716f20535de2bc4b42249bf4926de11692ffe8
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-bios-setting.c
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (C) 2022 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fwupd-bios-setting-private.h"
+#include "fwupd-common-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-error.h"
+
+/**
+ * FwupdBiosSetting:
+ *
+ * A BIOS setting that represents a setting in the firmware.
+ */
+
+static void
+fwupd_bios_setting_finalize(GObject *object);
+
+typedef struct {
+ FwupdBiosSettingKind kind;
+ gchar *id;
+ gchar *name;
+ gchar *description;
+ gchar *path;
+ gchar *current_value;
+ guint64 lower_bound;
+ guint64 upper_bound;
+ guint64 scalar_increment;
+ gboolean read_only;
+ GPtrArray *possible_values;
+} FwupdBiosSettingPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdBiosSetting, fwupd_bios_setting, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_bios_setting_get_instance_private(o))
+
+/**
+ * fwupd_bios_setting_get_id
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the unique attribute identifier for this attribute/driver
+ *
+ * Returns: attribute ID if set otherwise NULL
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_bios_setting_get_id(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ return priv->id;
+}
+
+/**
+ * fwupd_bios_setting_set_id
+ * @self: a #FwupdBiosSetting
+ *
+ * Sets the unique attribute identifier for this attribute
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_id(FwupdBiosSetting *self, const gchar *id)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->id, id) == 0)
+ return;
+
+ g_free(priv->id);
+ priv->id = g_strdup(id);
+}
+
+/**
+ * fwupd_bios_setting_get_read_only:
+ * @self: a #FwupdBiosSetting
+ *
+ * Determines if a BIOS setting is read only
+ *
+ * Returns: gboolean
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fwupd_bios_setting_get_read_only(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), FALSE);
+ return priv->read_only;
+}
+
+/**
+ * fwupd_bios_setting_set_read_only:
+ * @self: a #FwupdBiosSetting
+ *
+ * Configures whether an attribute is read only
+ * maximum length for string attributes.
+ *
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_read_only(FwupdBiosSetting *self, gboolean val)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ priv->read_only = val;
+}
+
+/**
+ * fwupd_bios_setting_get_lower_bound:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the lower bound for integer attributes or
+ * minimum length for string attributes.
+ *
+ * Returns: guint64
+ *
+ * Since: 1.8.4
+ **/
+guint64
+fwupd_bios_setting_get_lower_bound(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), 0);
+ return priv->lower_bound;
+}
+
+/**
+ * fwupd_bios_setting_get_upper_bound:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the upper bound for integer attributes or
+ * maximum length for string attributes.
+ *
+ * Returns: guint64
+ *
+ * Since: 1.8.4
+ **/
+guint64
+fwupd_bios_setting_get_upper_bound(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), 0);
+ return priv->upper_bound;
+}
+
+/**
+ * fwupd_bios_setting_get_scalar_increment:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the scalar increment used for integer attributes.
+ *
+ * Returns: guint64
+ *
+ * Since: 1.8.4
+ **/
+guint64
+fwupd_bios_setting_get_scalar_increment(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), 0);
+ return priv->scalar_increment;
+}
+
+/**
+ * fwupd_bios_setting_set_upper_bound:
+ * @self: a #FwupdBiosSetting
+ * @val: a guint64 value to set bound to
+ *
+ * Sets the upper bound used for BIOS integer attributes or max
+ * length for string attributes.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_upper_bound(FwupdBiosSetting *self, guint64 val)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ priv->upper_bound = val;
+}
+
+/**
+ * fwupd_bios_setting_set_lower_bound:
+ * @self: a #FwupdBiosSetting
+ * @val: a guint64 value to set bound to
+ *
+ * Sets the lower bound used for BIOS integer attributes or max
+ * length for string attributes.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_lower_bound(FwupdBiosSetting *self, guint64 val)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ priv->lower_bound = val;
+}
+
+/**
+ * fwupd_bios_setting_set_scalar_increment:
+ * @self: a #FwupdBiosSetting
+ * @val: a guint64 value to set increment to
+ *
+ * Sets the scalar increment used for BIOS integer attributes.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_scalar_increment(FwupdBiosSetting *self, guint64 val)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ priv->scalar_increment = val;
+}
+
+/**
+ * fwupd_bios_setting_get_kind:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the BIOS setting type used by the kernel interface.
+ *
+ * Returns: the bios setting type, or %FWUPD_BIOS_SETTING_KIND_UNKNOWN if unset.
+ *
+ * Since: 1.8.4
+ **/
+FwupdBiosSettingKind
+fwupd_bios_setting_get_kind(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), 0);
+ return priv->kind;
+}
+
+/**
+ * fwupd_bios_setting_set_kind:
+ * @self: a #FwupdBiosSetting
+ * @type: a bios setting type, e.g. %FWUPD_BIOS_SETTING_KIND_ENUMERATION
+ *
+ * Sets the BIOS setting type used by the kernel interface.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_kind(FwupdBiosSetting *self, FwupdBiosSettingKind type)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ priv->kind = type;
+}
+
+/**
+ * fwupd_bios_setting_set_name:
+ * @self: a #FwupdBiosSetting
+ * @name: (nullable): the attribute name
+ *
+ * Sets the attribute name provided by a kernel driver.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_name(FwupdBiosSetting *self, const gchar *name)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->name, name) == 0)
+ return;
+
+ g_free(priv->name);
+ priv->name = g_strdup(name);
+}
+
+/**
+ * fwupd_bios_setting_set_path:
+ * @self: a #FwupdBiosSetting
+ * @path: (nullable): the path the driver providing the attribute uses
+ *
+ * Sets path to the attribute.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_path(FwupdBiosSetting *self, const gchar *path)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->path, path) == 0)
+ return;
+
+ g_free(priv->path);
+ priv->path = g_strdup(path);
+}
+
+/**
+ * fwupd_bios_setting_set_description:
+ * @self: a #FwupdBiosSetting
+ * @description: (nullable): the attribute description
+ *
+ * Sets the attribute description.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_description(FwupdBiosSetting *self, const gchar *description)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->description, description) == 0)
+ return;
+
+ g_free(priv->description);
+ priv->description = g_strdup(description);
+}
+
+/* determine if key is supposed to be positive */
+static gboolean
+fu_bios_setting_key_is_positive(const gchar *key)
+{
+ if (g_strrstr(key, "enable"))
+ return TRUE;
+ if (g_strcmp0(key, "true") == 0)
+ return TRUE;
+ if (g_strcmp0(key, "1") == 0)
+ return TRUE;
+ if (g_strcmp0(key, "on") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+/* determine if key is supposed to be negative */
+static gboolean
+fu_bios_setting_key_is_negative(const gchar *key)
+{
+ if (g_strrstr(key, "disable"))
+ return TRUE;
+ if (g_strcmp0(key, "false") == 0)
+ return TRUE;
+ if (g_strcmp0(key, "0") == 0)
+ return TRUE;
+ if (g_strcmp0(key, "off") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * fwupd_bios_setting_map_possible_value:
+ * @self: a #FwupdBiosSetting
+ * @key: the string to try to map
+ * @error: (nullable): optional return location for an error
+ *
+ * Attempts to map a user provided string into strings that a #FwupdBiosSetting can
+ * support. The following heuristics are used:
+ * - Ignore case sensitivity
+ * - Map obviously "positive" phrases into a value that turns on the #FwupdBiosSetting
+ * - Map obviously "negative" phrases into a value that turns off the #FwupdBiosSetting
+ *
+ * Returns: (transfer none): the possible value that maps or NULL if none if found
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_bios_setting_map_possible_value(FwupdBiosSetting *self, const gchar *key, GError **error)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ gboolean positive_key = FALSE;
+ gboolean negative_key = FALSE;
+ g_autofree gchar *lower_key = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ g_return_val_if_fail(priv->kind == FWUPD_BIOS_SETTING_KIND_ENUMERATION, NULL);
+
+ if (priv->possible_values->len == 0) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "%s doesn't contain any possible values",
+ priv->name);
+ return NULL;
+ }
+
+ lower_key = g_utf8_strdown(key, -1);
+ positive_key = fu_bios_setting_key_is_positive(lower_key);
+ negative_key = fu_bios_setting_key_is_negative(lower_key);
+ for (guint i = 0; i < priv->possible_values->len; i++) {
+ const gchar *possible = g_ptr_array_index(priv->possible_values, i);
+ g_autofree gchar *lower_possible = g_utf8_strdown(possible, -1);
+ gboolean positive_possible;
+ gboolean negative_possible;
+
+ /* perfect match */
+ if (g_strcmp0(lower_possible, lower_key) == 0)
+ return possible;
+ /* fuzzy match */
+ positive_possible = fu_bios_setting_key_is_positive(lower_possible);
+ negative_possible = fu_bios_setting_key_is_negative(lower_possible);
+ if ((positive_possible && positive_key) || (negative_possible && negative_key))
+ return possible;
+ }
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "%s doesn't map to any possible values for %s",
+ key,
+ priv->name);
+ return NULL;
+}
+
+/**
+ * fwupd_bios_setting_has_possible_value:
+ * @self: a #FwupdBiosSetting
+ * @val: the possible value string
+ *
+ * Finds out if a specific possible value was added to the attribute.
+ *
+ * Returns: %TRUE if the self matches.
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fwupd_bios_setting_has_possible_value(FwupdBiosSetting *self, const gchar *val)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), FALSE);
+ g_return_val_if_fail(val != NULL, FALSE);
+
+ if (priv->possible_values->len == 0)
+ return TRUE;
+
+ for (guint i = 0; i < priv->possible_values->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->possible_values, i);
+ if (g_strcmp0(tmp, val) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_bios_setting_add_possible_value:
+ * @self: a #FwupdBiosSetting
+ * @possible_value: the possible
+ *
+ * Adds a possible value to the attribute. This indicates one of the values the
+ * kernel driver will accept from userspace.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_add_possible_value(FwupdBiosSetting *self, const gchar *possible_value)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ if (priv->possible_values->len > 0 &&
+ fwupd_bios_setting_has_possible_value(self, possible_value))
+ return;
+ g_ptr_array_add(priv->possible_values, g_strdup(possible_value));
+}
+
+/**
+ * fwupd_bios_setting_get_possible_values:
+ * @self: a #FwupdBiosSetting
+ *
+ * Find all possible values for an enumeration attribute.
+ *
+ * Returns: (transfer container) (element-type gchar*): all possible values.
+ *
+ * Since: 1.8.4
+ **/
+GPtrArray *
+fwupd_bios_setting_get_possible_values(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ g_return_val_if_fail(priv->kind == FWUPD_BIOS_SETTING_KIND_ENUMERATION, NULL);
+ return priv->possible_values;
+}
+
+/**
+ * fwupd_bios_setting_get_name:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the attribute name.
+ *
+ * Returns: the attribute name, or %NULL if unset.
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_bios_setting_get_name(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ return priv->name;
+}
+
+/**
+ * fwupd_bios_setting_get_path:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the path for the driver providing the attribute.
+ *
+ * Returns: (nullable): the driver, or %NULL if unfound.
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_bios_setting_get_path(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ return priv->path;
+}
+
+/**
+ * fwupd_bios_setting_get_description:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the attribute description which is provided by some drivers to explain
+ * what they change.
+ *
+ * Returns: the attribute description, or %NULL if unset.
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_bios_setting_get_description(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ return priv->description;
+}
+
+/**
+ * fwupd_bios_setting_get_current_value:
+ * @self: a #FwupdBiosSetting
+ *
+ * Gets the string representation of the current_value stored in an attribute
+ * from the kernel. This value is cached; so changing it outside of fwupd may
+ * may put it out of sync.
+ *
+ * Returns: the current value of the attribute.
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_bios_setting_get_current_value(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+ return priv->current_value;
+}
+
+/**
+ * fwupd_bios_setting_set_current_value:
+ * @self: a #FwupdBiosSetting
+ * @value: The string to set an attribute to
+ *
+ * Sets the string stored in an attribute.
+ * This doesn't change the representation in the kernel.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_set_current_value(FwupdBiosSetting *self, const gchar *value)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->current_value, value) == 0)
+ return;
+
+ g_free(priv->current_value);
+ priv->current_value = g_strdup(value);
+}
+
+static gboolean
+fwupd_bios_setting_trusted(FwupdBiosSetting *self, gboolean trusted)
+{
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), FALSE);
+
+ if (trusted)
+ return TRUE;
+ if (g_strcmp0(fwupd_bios_setting_get_name(self), "pending_reboot") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * fwupd_bios_setting_to_variant:
+ * @self: a #FwupdBiosSetting
+ * @trusted: whether the caller should receive trusted values
+ *
+ * Serialize the bios setting.
+ *
+ * Returns: the serialized data, or %NULL for error.
+ *
+ * Since: 1.8.4
+ **/
+GVariant *
+fwupd_bios_setting_to_variant(FwupdBiosSetting *self, gboolean trusted)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_TYPE,
+ g_variant_new_uint64(priv->kind));
+ if (priv->id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_ID,
+ g_variant_new_string(priv->id));
+ }
+ if (priv->name != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_NAME,
+ g_variant_new_string(priv->name));
+ }
+ if (priv->path != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_FILENAME,
+ g_variant_new_string(priv->path));
+ }
+ if (priv->description != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_DESCRIPTION,
+ g_variant_new_string(priv->description));
+ }
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY,
+ g_variant_new_boolean(priv->read_only));
+ if (fwupd_bios_setting_trusted(self, trusted)) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ g_variant_new_string(priv->current_value));
+ }
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_INTEGER ||
+ priv->kind == FWUPD_BIOS_SETTING_KIND_STRING) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND,
+ g_variant_new_uint64(priv->lower_bound));
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND,
+ g_variant_new_uint64(priv->upper_bound));
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_INTEGER) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT,
+ g_variant_new_uint64(priv->scalar_increment));
+ }
+ } else if (priv->kind == FWUPD_BIOS_SETTING_KIND_ENUMERATION) {
+ if (priv->possible_values->len > 0) {
+ g_autofree const gchar **strv =
+ g_new0(const gchar *, priv->possible_values->len + 1);
+ for (guint i = 0; i < priv->possible_values->len; i++)
+ strv[i] =
+ (const gchar *)g_ptr_array_index(priv->possible_values, i);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES,
+ g_variant_new_strv(strv, -1));
+ }
+ }
+ return g_variant_new("a{sv}", &builder);
+}
+
+static void
+fwupd_bios_setting_from_key_value(FwupdBiosSetting *self, const gchar *key, GVariant *value)
+{
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_TYPE) == 0) {
+ fwupd_bios_setting_set_kind(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_ID) == 0) {
+ fwupd_bios_setting_set_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
+ fwupd_bios_setting_set_name(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FILENAME) == 0) {
+ fwupd_bios_setting_set_path(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE) == 0) {
+ fwupd_bios_setting_set_current_value(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
+ fwupd_bios_setting_set_description(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES) == 0) {
+ g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
+ for (guint i = 0; strv[i] != NULL; i++)
+ fwupd_bios_setting_add_possible_value(self, strv[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND) == 0) {
+ fwupd_bios_setting_set_lower_bound(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND) == 0) {
+ fwupd_bios_setting_set_upper_bound(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT) == 0) {
+ fwupd_bios_setting_set_scalar_increment(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY) == 0) {
+ fwupd_bios_setting_set_read_only(self, g_variant_get_boolean(value));
+ return;
+ }
+}
+
+/**
+ * fwupd_bios_setting_from_json:
+ * @self: a #FwupdBiosSetting
+ * @json_node: a JSON node
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads a fwupd bios setting from a JSON node.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fwupd_bios_setting_from_json(FwupdBiosSetting *self, JsonNode *json_node, GError **error)
+{
+#if JSON_CHECK_VERSION(1, 6, 0)
+ JsonObject *obj;
+
+ /* sanity check */
+ if (!JSON_NODE_HOLDS_OBJECT(json_node)) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "not JSON object");
+ return FALSE;
+ }
+ obj = json_node_get_object(json_node);
+
+ fwupd_bios_setting_set_kind(
+ self,
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_BIOS_SETTING_TYPE, 0));
+ fwupd_bios_setting_set_id(
+ self,
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_ID,
+ NULL));
+
+ fwupd_bios_setting_set_name(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_NAME, NULL));
+ fwupd_bios_setting_set_description(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_DESCRIPTION, NULL));
+ fwupd_bios_setting_set_path(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_FILENAME, NULL));
+ fwupd_bios_setting_set_current_value(
+ self,
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ NULL));
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES)) {
+ JsonArray *array =
+ json_object_get_array_member(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES);
+ for (guint i = 0; i < json_array_get_length(array); i++) {
+ const gchar *tmp = json_array_get_string_element(array, i);
+ fwupd_bios_setting_add_possible_value(self, tmp);
+ }
+ }
+ fwupd_bios_setting_set_lower_bound(
+ self,
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND,
+ 0));
+ fwupd_bios_setting_set_upper_bound(
+ self,
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND,
+ 0));
+ fwupd_bios_setting_set_scalar_increment(
+ self,
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT,
+ 0));
+ fwupd_bios_setting_set_read_only(
+ self,
+ json_object_get_boolean_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY,
+ FALSE));
+ /* success */
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "json-glib version too old");
+ return FALSE;
+#endif
+}
+
+/**
+ * fwupd_bios_setting_to_json:
+ * @self: a #FwupdBiosSetting
+ * @builder: a JSON builder
+ *
+ * Adds a fwupd bios setting to a JSON builder.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_bios_setting_to_json(FwupdBiosSetting *self, JsonBuilder *builder)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_BIOS_SETTING(self));
+ g_return_if_fail(builder != NULL);
+
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_FILENAME, priv->path);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_BIOS_SETTING_ID, priv->id);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ priv->current_value);
+ fwupd_common_json_add_boolean(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY,
+ priv->read_only);
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_BIOS_SETTING_TYPE, priv->kind);
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_ENUMERATION) {
+ if (priv->possible_values->len > 0) {
+ json_builder_set_member_name(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->possible_values->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->possible_values, i);
+ json_builder_add_string_value(builder, tmp);
+ }
+ json_builder_end_array(builder);
+ }
+ }
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_INTEGER ||
+ priv->kind == FWUPD_BIOS_SETTING_KIND_STRING) {
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND,
+ priv->lower_bound);
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND,
+ priv->upper_bound);
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_INTEGER) {
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT,
+ priv->scalar_increment);
+ }
+ }
+}
+
+/**
+ * fwupd_bios_setting_to_string:
+ * @self: a #FwupdBiosSetting
+ *
+ * Builds a text representation of the object.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 1.8.4
+ **/
+gchar *
+fwupd_bios_setting_to_string(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ GString *str;
+
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(self), NULL);
+
+ str = g_string_new(NULL);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_BIOS_SETTING_ID, priv->id);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_FILENAME, priv->path);
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_BIOS_SETTING_TYPE, priv->kind);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE, priv->current_value);
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY,
+ priv->read_only ? "True" : "False");
+
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_ENUMERATION) {
+ for (guint i = 0; i < priv->possible_values->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->possible_values, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES, tmp);
+ }
+ }
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_INTEGER ||
+ priv->kind == FWUPD_BIOS_SETTING_KIND_STRING) {
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND, priv->lower_bound);
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND, priv->upper_bound);
+ if (priv->kind == FWUPD_BIOS_SETTING_KIND_INTEGER) {
+ fwupd_pad_kv_int(str,
+ FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT,
+ priv->scalar_increment);
+ }
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+static void
+fwupd_bios_setting_class_init(FwupdBiosSettingClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fwupd_bios_setting_finalize;
+}
+
+static void
+fwupd_bios_setting_init(FwupdBiosSetting *self)
+{
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+ priv->possible_values = g_ptr_array_new_with_free_func(g_free);
+}
+
+static void
+fwupd_bios_setting_finalize(GObject *object)
+{
+ FwupdBiosSetting *self = FWUPD_BIOS_SETTING(object);
+ FwupdBiosSettingPrivate *priv = GET_PRIVATE(self);
+
+ g_free(priv->current_value);
+ g_free(priv->id);
+ g_free(priv->name);
+ g_free(priv->description);
+ g_free(priv->path);
+ g_ptr_array_unref(priv->possible_values);
+
+ G_OBJECT_CLASS(fwupd_bios_setting_parent_class)->finalize(object);
+}
+
+static void
+fwupd_bios_setting_set_from_variant_iter(FwupdBiosSetting *self, GVariantIter *iter)
+{
+ GVariant *value;
+ const gchar *key;
+ while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
+ fwupd_bios_setting_from_key_value(self, key, value);
+ g_variant_unref(value);
+ }
+}
+
+/**
+ * fwupd_bios_setting_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new bios setting using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdBiosSetting, or %NULL if @value was invalid.
+ *
+ * Since: 1.8.4
+ **/
+FwupdBiosSetting *
+fwupd_bios_setting_from_variant(GVariant *value)
+{
+ FwupdBiosSetting *rel = NULL;
+ const gchar *type_string;
+ g_autoptr(GVariantIter) iter = NULL;
+
+ g_return_val_if_fail(value != NULL, NULL);
+
+ type_string = g_variant_get_type_string(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ rel = g_object_new(FWUPD_TYPE_BIOS_SETTING, NULL);
+ g_variant_get(value, "(a{sv})", &iter);
+ fwupd_bios_setting_set_from_variant_iter(rel, iter);
+ } else if (g_strcmp0(type_string, "a{sv}") == 0) {
+ rel = g_object_new(FWUPD_TYPE_BIOS_SETTING, NULL);
+ g_variant_get(value, "a{sv}", &iter);
+ fwupd_bios_setting_set_from_variant_iter(rel, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return rel;
+}
+
+/**
+ * fwupd_bios_setting_array_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates an array of new bios settings using serialized data.
+ *
+ * Returns: (transfer container) (element-type FwupdBiosSetting): attributes,
+ * or %NULL if @value was invalid.
+ *
+ * Since: 1.8.4
+ **/
+GPtrArray *
+fwupd_bios_setting_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++) {
+ FwupdBiosSetting *rel;
+ g_autoptr(GVariant) data = NULL;
+ data = g_variant_get_child_value(untuple, i);
+ rel = fwupd_bios_setting_from_variant(data);
+ if (rel == NULL)
+ continue;
+ g_ptr_array_add(array, rel);
+ }
+ return array;
+}
+
+/**
+ * fwupd_bios_setting_new:
+ * @name: (nullable): the attribute name
+ * @path: (nullable): the path the driver providing this attribute uses
+ *
+ * Creates a new bios setting.
+ *
+ * Returns: a new #FwupdBiosSetting.
+ *
+ * Since: 1.8.4
+ **/
+FwupdBiosSetting *
+fwupd_bios_setting_new(const gchar *name, const gchar *path)
+{
+ FwupdBiosSetting *self;
+
+ self = g_object_new(FWUPD_TYPE_BIOS_SETTING, NULL);
+ if (name != NULL)
+ fwupd_bios_setting_set_name(self, name);
+ if (path != NULL)
+ fwupd_bios_setting_set_path(self, path);
+
+ return FWUPD_BIOS_SETTING(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-bios-setting.h b/fwupd-1.8.6/libfwupd/fwupd-bios-setting.h
new file mode 100644
index 0000000000000000000000000000000000000000..37c0483c90ccc582a852c05e35267053499c6881
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-bios-setting.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-enums.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_BIOS_SETTING (fwupd_bios_setting_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdBiosSetting, fwupd_bios_setting, FWUPD, BIOS_SETTING, GObject)
+
+struct _FwupdBiosSettingClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ void (*_fwupd_reserved7)(void);
+};
+
+/* special attributes */
+#define FWUPD_BIOS_SETTING_PENDING_REBOOT "pending_reboot"
+#define FWUPD_BIOS_SETTING_RESET_BIOS "reset_bios"
+#define FWUPD_BIOS_SETTING_DEBUG_CMD "debug_cmd"
+
+/**
+ * FwupdBiosSettingKind:
+ * @FWUPD_BIOS_SETTING_KIND_UNKNOWN: BIOS setting type is unknown
+ * @FWUPD_BIOS_SETTING_KIND_ENUMERATION: BIOS setting that has enumerated possible
+ *values
+ * @FWUPD_BIOS_SETTING_KIND_INTEGER: BIOS setting that is an integer
+ * @FWUPD_BIOS_SETTING_KIND_STRING: BIOS setting that accepts a string
+ *
+ * The type of BIOS setting.
+ **/
+typedef enum {
+ FWUPD_BIOS_SETTING_KIND_UNKNOWN = 0, /* Since: 1.8.4 */
+ FWUPD_BIOS_SETTING_KIND_ENUMERATION = 1, /* Since: 1.8.4 */
+ FWUPD_BIOS_SETTING_KIND_INTEGER = 2, /* Since: 1.8.4 */
+ FWUPD_BIOS_SETTING_KIND_STRING = 3, /* Since: 1.8.4 */
+ /*< private >*/
+ FWUPD_BIOS_SETTING_KIND_LAST = 4 /* perhaps increased in the future */
+} FwupdBiosSettingKind;
+
+FwupdBiosSetting *
+fwupd_bios_setting_new(const gchar *name, const gchar *path);
+gchar *
+fwupd_bios_setting_to_string(FwupdBiosSetting *self);
+
+gboolean
+fwupd_bios_setting_get_read_only(FwupdBiosSetting *self);
+void
+fwupd_bios_setting_set_read_only(FwupdBiosSetting *self, gboolean val);
+
+guint64
+fwupd_bios_setting_get_upper_bound(FwupdBiosSetting *self);
+guint64
+fwupd_bios_setting_get_lower_bound(FwupdBiosSetting *self);
+guint64
+fwupd_bios_setting_get_scalar_increment(FwupdBiosSetting *self);
+
+void
+fwupd_bios_setting_set_upper_bound(FwupdBiosSetting *self, guint64 val);
+void
+fwupd_bios_setting_set_lower_bound(FwupdBiosSetting *self, guint64 val);
+void
+fwupd_bios_setting_set_scalar_increment(FwupdBiosSetting *self, guint64 val);
+
+void
+fwupd_bios_setting_set_kind(FwupdBiosSetting *self, FwupdBiosSettingKind type);
+void
+fwupd_bios_setting_set_name(FwupdBiosSetting *self, const gchar *name);
+void
+fwupd_bios_setting_set_path(FwupdBiosSetting *self, const gchar *path);
+void
+fwupd_bios_setting_set_description(FwupdBiosSetting *self, const gchar *description);
+
+FwupdBiosSettingKind
+fwupd_bios_setting_get_kind(FwupdBiosSetting *self);
+const gchar *
+fwupd_bios_setting_get_name(FwupdBiosSetting *self);
+const gchar *
+fwupd_bios_setting_get_path(FwupdBiosSetting *self);
+const gchar *
+fwupd_bios_setting_get_description(FwupdBiosSetting *self);
+const gchar *
+fwupd_bios_setting_map_possible_value(FwupdBiosSetting *self, const gchar *key, GError **error);
+gboolean
+fwupd_bios_setting_has_possible_value(FwupdBiosSetting *self, const gchar *val);
+void
+fwupd_bios_setting_add_possible_value(FwupdBiosSetting *self, const gchar *possible_value);
+GPtrArray *
+fwupd_bios_setting_get_possible_values(FwupdBiosSetting *self);
+
+FwupdBiosSetting *
+fwupd_bios_setting_from_variant(GVariant *value);
+GPtrArray *
+fwupd_bios_setting_array_from_variant(GVariant *value);
+
+const gchar *
+fwupd_bios_setting_get_current_value(FwupdBiosSetting *self);
+void
+fwupd_bios_setting_set_current_value(FwupdBiosSetting *self, const gchar *value);
+
+const gchar *
+fwupd_bios_setting_get_id(FwupdBiosSetting *self);
+void
+fwupd_bios_setting_set_id(FwupdBiosSetting *self, const gchar *id);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-client-private.h b/fwupd-1.8.6/libfwupd/fwupd-client-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..2022faf850be7d86b289073f071e04a6fadb96fb
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-client-private.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fwupd-client.h"
+
+#ifdef HAVE_GIO_UNIX
+#include
+#endif
+
+void
+fwupd_client_download_bytes2_async(FwupdClient *self,
+ GPtrArray *urls,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+
+#ifdef HAVE_GIO_UNIX
+void
+fwupd_client_get_details_stream_async(FwupdClient *self,
+ GUnixInputStream *istr,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+void
+fwupd_client_install_stream_async(FwupdClient *self,
+ const gchar *device_id,
+ GUnixInputStream *istr,
+ const gchar *filename_hint,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+void
+fwupd_client_update_metadata_stream_async(FwupdClient *self,
+ const gchar *remote_id,
+ GUnixInputStream *istr,
+ GUnixInputStream *istr_sig,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+#endif
diff --git a/fwupd-1.8.6/libfwupd/fwupd-client-sync.c b/fwupd-1.8.6/libfwupd/fwupd-client-sync.c
new file mode 100644
index 0000000000000000000000000000000000000000..a1505a47e73200342ed388a4d19793110fa14538
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-client-sync.c
@@ -0,0 +1,2419 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#ifdef HAVE_GIO_UNIX
+#include
+#endif
+
+#include "fwupd-client-private.h"
+#include "fwupd-client-sync.h"
+#include "fwupd-client.h"
+#include "fwupd-common-private.h"
+#include "fwupd-error.h"
+
+typedef struct {
+ gboolean ret;
+ gchar *str;
+ GError *error;
+ GPtrArray *array;
+ GMainContext *context;
+ GMainLoop *loop;
+ GVariant *val;
+ GHashTable *hash;
+ GBytes *bytes;
+ FwupdDevice *device;
+} FwupdClientHelper;
+
+static void
+fwupd_client_helper_free(FwupdClientHelper *helper)
+{
+ if (helper->val != NULL)
+ g_variant_unref(helper->val);
+ if (helper->error != NULL)
+ g_error_free(helper->error);
+ if (helper->array != NULL)
+ g_ptr_array_unref(helper->array);
+ if (helper->hash != NULL)
+ g_hash_table_unref(helper->hash);
+ if (helper->bytes != NULL)
+ g_bytes_unref(helper->bytes);
+ if (helper->device != NULL)
+ g_object_unref(helper->device);
+ g_free(helper->str);
+ g_main_loop_unref(helper->loop);
+ g_main_context_unref(helper->context);
+ g_main_context_pop_thread_default(helper->context);
+ g_free(helper);
+}
+
+static FwupdClientHelper *
+fwupd_client_helper_new(FwupdClient *self)
+{
+ FwupdClientHelper *helper;
+ helper = g_new0(FwupdClientHelper, 1);
+ helper->context = fwupd_client_get_main_context(self);
+ helper->loop = g_main_loop_new(helper->context, FALSE);
+ g_main_context_push_thread_default(helper->context);
+ 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_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_connect_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_connect: (skip)
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets up the client ready for use. Most other methods call this
+ * for you, and do you only need to call this if you are just watching
+ * the client.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.1
+ **/
+gboolean
+fwupd_client_connect(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_connect_async(self, cancellable, fwupd_client_connect_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_get_devices_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array = fwupd_client_get_devices_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_devices:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the devices registered with the daemon.
+ *
+ * Returns: (element-type FwupdDevice) (transfer container): results
+ *
+ * Since: 0.9.2
+ **/
+GPtrArray *
+fwupd_client_get_devices(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_devices_async(self, cancellable, fwupd_client_get_devices_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_plugins_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array = fwupd_client_get_plugins_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_plugins:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the plugins being used the daemon.
+ *
+ * Returns: (element-type FwupdPlugin) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_plugins(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_plugins_async(self, cancellable, fwupd_client_get_plugins_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_history_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array = fwupd_client_get_history_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_history:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the history.
+ *
+ * Returns: (element-type FwupdDevice) (transfer container): results
+ *
+ * Since: 1.0.4
+ **/
+GPtrArray *
+fwupd_client_get_history(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_history_async(self, cancellable, fwupd_client_get_history_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_releases_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array = fwupd_client_get_releases_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_releases:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the releases for a specific device
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 0.9.3
+ **/
+GPtrArray *
+fwupd_client_get_releases(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(device_id != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_releases_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_get_releases_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_downgrades_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_downgrades_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_downgrades:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the downgrades for a specific device.
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 0.9.8
+ **/
+GPtrArray *
+fwupd_client_get_downgrades(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(device_id != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_downgrades_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_get_downgrades_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_upgrades_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array = fwupd_client_get_upgrades_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_upgrades:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the upgrades for a specific device.
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 0.9.8
+ **/
+GPtrArray *
+fwupd_client_get_upgrades(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(device_id != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_upgrades_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_get_upgrades_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_details_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_details_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_details_bytes:
+ * @self: a #FwupdClient
+ * @bytes: the firmware archive
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets details about a specific firmware file.
+ *
+ * Returns: (transfer container) (element-type FwupdDevice): an array of results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_details_bytes(FwupdClient *self,
+ GBytes *bytes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(bytes != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_details_bytes_async(self,
+ bytes,
+ cancellable,
+ fwupd_client_get_details_bytes_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+#ifdef HAVE_GIO_UNIX
+static void
+fwupd_client_get_details_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_details_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+#endif
+
+/**
+ * fwupd_client_get_details:
+ * @self: a #FwupdClient
+ * @filename: the firmware filename, e.g. `firmware.cab`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets details about a specific firmware file.
+ *
+ * Returns: (transfer container) (element-type FwupdDevice): an array of results
+ *
+ * Since: 1.0.0
+ **/
+GPtrArray *
+fwupd_client_get_details(FwupdClient *self,
+ const gchar *filename,
+ GCancellable *cancellable,
+ GError **error)
+{
+#ifdef HAVE_GIO_UNIX
+ g_autoptr(GUnixInputStream) istr = NULL;
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(filename != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ istr = fwupd_unix_input_stream_from_fn(filename, error);
+ if (istr == NULL)
+ return NULL;
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_details_stream_async(self,
+ istr,
+ cancellable,
+ fwupd_client_get_details_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Get Details only supported on Linux");
+ return NULL;
+#endif
+}
+
+static void
+fwupd_client_verify_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_verify_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_verify:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Verify a specific device.
+ *
+ * Returns: %TRUE for verification success
+ *
+ * Since: 0.7.0
+ **/
+gboolean
+fwupd_client_verify(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_verify_async(self, device_id, cancellable, fwupd_client_verify_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_verify_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_verify_update_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_verify_update:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Update the verification record for a specific device.
+ *
+ * Returns: %TRUE for verification success
+ *
+ * Since: 0.8.0
+ **/
+gboolean
+fwupd_client_verify_update(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_verify_update_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_verify_update_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_unlock_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_unlock_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_unlock:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Unlocks a specific device so firmware can be read or wrote.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ **/
+gboolean
+fwupd_client_unlock(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_unlock_async(self, device_id, cancellable, fwupd_client_unlock_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+static void
+fwupd_client_modify_config_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_modify_config_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_modify_config
+ * @self: a #FwupdClient
+ * @key: config key, e.g. `DisabledPlugins`
+ * @value: config value, e.g. `*`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * 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 *self,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(value != 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_modify_config_async(self,
+ key,
+ value,
+ cancellable,
+ fwupd_client_modify_config_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_activate_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_activate_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_activate:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @device_id: a device
+ * @error: (nullable): optional return location for an error
+ *
+ * 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 *self,
+ GCancellable *cancellable,
+ const gchar *device_id, /* yes, this is the wrong way around :/ */
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_activate_async(self, device_id, cancellable, fwupd_client_activate_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_clear_results_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_clear_results_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_clear_results:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Clears the results for a specific device.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ **/
+gboolean
+fwupd_client_clear_results(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_clear_results_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_clear_results_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_get_results_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->device = fwupd_client_get_results_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_results:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the results of a previous firmware update for a specific device.
+ *
+ * Returns: (transfer full): a device, or %NULL for failure
+ *
+ * Since: 0.7.0
+ **/
+FwupdDevice *
+fwupd_client_get_results(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(device_id != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_results_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_get_results_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->device == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->device);
+}
+
+static void
+fwupd_client_modify_bios_setting_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_modify_bios_setting_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_modify_bios_setting
+ * @self: a #FwupdClient
+ * @settings: (transfer container): BIOS settings
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Modifies a BIOS setting using kernel API.
+ * The daemon will only respond to this request with proper permissions.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fwupd_client_modify_bios_setting(FwupdClient *self,
+ GHashTable *settings,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(settings != 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_modify_bios_setting_async(self,
+ settings,
+ cancellable,
+ fwupd_client_modify_bios_setting_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_get_bios_settings_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_bios_settings_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_bios_settings:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the BIOS settings from the daemon.
+ *
+ * Returns: (element-type FwupdBiosSetting) (transfer container): attributes
+ *
+ * Since: 1.8.4
+ **/
+GPtrArray *
+fwupd_client_get_bios_settings(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_bios_settings_async(self,
+ cancellable,
+ fwupd_client_get_bios_settings_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_host_security_attrs_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_host_security_attrs_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_host_security_attrs:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the host security attributes from the daemon.
+ *
+ * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_host_security_attrs(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_host_security_attrs_async(self,
+ cancellable,
+ fwupd_client_get_host_security_attrs_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_host_security_events_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_host_security_events_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_host_security_events:
+ * @self: a #FwupdClient
+ * @limit: maximum number of events, or 0 for no limit
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the host security events from the daemon.
+ *
+ * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes
+ *
+ * Since: 1.7.1
+ **/
+GPtrArray *
+fwupd_client_get_host_security_events(FwupdClient *self,
+ guint limit,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_host_security_events_async(self,
+ limit,
+ cancellable,
+ fwupd_client_get_host_security_events_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static void
+fwupd_client_get_device_by_id_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->device =
+ fwupd_client_get_device_by_id_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_device_by_id:
+ * @self: a #FwupdClient
+ * @device_id: the device ID, e.g. `usb:00:01:03:03`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets a device by its device ID.
+ *
+ * Returns: (transfer full): a device or %NULL
+ *
+ * Since: 0.9.3
+ **/
+FwupdDevice *
+fwupd_client_get_device_by_id(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(device_id != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_device_by_id_async(self,
+ device_id,
+ cancellable,
+ fwupd_client_get_device_by_id_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->device == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->device);
+}
+
+static void
+fwupd_client_get_devices_by_guid_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_devices_by_guid_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_devices_by_guid:
+ * @self: a #FwupdClient
+ * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets any devices that provide a specific GUID. An error is returned if no
+ * devices contains this GUID.
+ *
+ * Returns: (element-type FwupdDevice) (transfer container): devices or %NULL
+ *
+ * Since: 1.4.1
+ **/
+GPtrArray *
+fwupd_client_get_devices_by_guid(FwupdClient *self,
+ const gchar *guid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(guid != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_devices_by_guid_async(self,
+ guid,
+ cancellable,
+ fwupd_client_get_devices_by_guid_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+#ifdef HAVE_GIO_UNIX
+static void
+fwupd_client_install_fd_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_install_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+#endif
+
+/**
+ * fwupd_client_install:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @filename: the filename to install
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Install a file onto a specific device.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ **/
+gboolean
+fwupd_client_install(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *filename,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+#ifdef HAVE_GIO_UNIX
+ g_autoptr(GUnixInputStream) istr = NULL;
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(device_id != NULL, FALSE);
+ g_return_val_if_fail(filename != 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(self, cancellable, error))
+ return FALSE;
+
+ /* move to a thread if this ever takes more than a few ms */
+ istr = fwupd_unix_input_stream_from_fn(filename, error);
+ if (istr == NULL)
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_install_stream_async(self,
+ device_id,
+ istr,
+ filename,
+ install_flags,
+ cancellable,
+ fwupd_client_install_fd_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Install CAB only supported on Linux");
+ return FALSE;
+#endif
+}
+
+static void
+fwupd_client_install_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_install_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_install_bytes:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @bytes: cabinet archive
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Install firmware onto a specific device.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ **/
+gboolean
+fwupd_client_install_bytes(FwupdClient *self,
+ const gchar *device_id,
+ GBytes *bytes,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(device_id != NULL, FALSE);
+ g_return_val_if_fail(bytes != 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_install_bytes_async(self,
+ device_id,
+ bytes,
+ install_flags,
+ cancellable,
+ fwupd_client_install_bytes_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+static void
+fwupd_client_install_release_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_install_release_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_install_release2:
+ * @self: a #FwupdClient
+ * @device: a device
+ * @release: a release
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @download_flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Installs a new release on a device, downloading the firmware if required.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.6
+ **/
+gboolean
+fwupd_client_install_release2(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ FwupdClientDownloadFlags download_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(device), FALSE);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(release), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_install_release2_async(self,
+ device,
+ release,
+ install_flags,
+ download_flags,
+ cancellable,
+ fwupd_client_install_release_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * fwupd_client_install_release:
+ * @self: a #FwupdClient
+ * @device: a device
+ * @release: a release
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Installs a new release on a device, downloading the firmware if required.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ * Deprecated: 1.5.6
+ **/
+gboolean
+fwupd_client_install_release(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return fwupd_client_install_release2(self,
+ device,
+ release,
+ install_flags,
+ FWUPD_CLIENT_DOWNLOAD_FLAG_NONE,
+ cancellable,
+ error);
+}
+
+#ifdef HAVE_GIO_UNIX
+static void
+fwupd_client_update_metadata_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_update_metadata_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+#endif
+
+/**
+ * fwupd_client_update_metadata:
+ * @self: a #FwupdClient
+ * @remote_id: the remote ID, e.g. `lvfs-testing`
+ * @metadata_fn: the XML metadata filename
+ * @signature_fn: the GPG signature file
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Updates the metadata. This allows a session process to download the metadata
+ * and metadata signing file to be passed into the daemon to be checked and
+ * parsed.
+ *
+ * The @remote_id allows the firmware to be tagged so that the remote can be
+ * matched when the firmware is downloaded.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.0.0
+ **/
+gboolean
+fwupd_client_update_metadata(FwupdClient *self,
+ const gchar *remote_id,
+ const gchar *metadata_fn,
+ const gchar *signature_fn,
+ GCancellable *cancellable,
+ GError **error)
+{
+#ifdef HAVE_GIO_UNIX
+ g_autoptr(GUnixInputStream) istr = NULL;
+ g_autoptr(GUnixInputStream) istr_sig = NULL;
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(remote_id != NULL, FALSE);
+ g_return_val_if_fail(metadata_fn != NULL, FALSE);
+ g_return_val_if_fail(signature_fn != 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(self, cancellable, error))
+ return FALSE;
+
+ istr = fwupd_unix_input_stream_from_fn(metadata_fn, error);
+ if (istr == NULL)
+ return FALSE;
+ istr_sig = fwupd_unix_input_stream_from_fn(signature_fn, error);
+ if (istr_sig == NULL)
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_update_metadata_stream_async(self,
+ remote_id,
+ istr,
+ istr_sig,
+ cancellable,
+ fwupd_client_update_metadata_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Update metadata only supported on Linux");
+ return FALSE;
+#endif
+}
+
+static void
+fwupd_client_update_metadata_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_update_metadata_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_update_metadata_bytes:
+ * @self: a #FwupdClient
+ * @remote_id: remote ID, e.g. `lvfs-testing`
+ * @metadata: XML metadata data
+ * @signature: signature data
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Updates the metadata. This allows a session process to download the metadata
+ * and metadata signing file to be passed into the daemon to be checked and
+ * parsed.
+ *
+ * The @remote_id allows the firmware to be tagged so that the remote can be
+ * matched when the firmware is downloaded.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ **/
+gboolean
+fwupd_client_update_metadata_bytes(FwupdClient *self,
+ const gchar *remote_id,
+ GBytes *metadata,
+ GBytes *signature,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(remote_id != NULL, FALSE);
+ g_return_val_if_fail(metadata != NULL, FALSE);
+ g_return_val_if_fail(signature != 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_update_metadata_bytes_async(self,
+ remote_id,
+ metadata,
+ signature,
+ cancellable,
+ fwupd_client_update_metadata_bytes_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_refresh_remote_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_refresh_remote_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_refresh_remote:
+ * @self: a #FwupdClient
+ * @remote: a #FwupdRemote
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Refreshes a remote by downloading new metadata.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ **/
+gboolean
+fwupd_client_refresh_remote(FwupdClient *self,
+ FwupdRemote *remote,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(remote), FALSE);
+ g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_refresh_remote_async(self,
+ remote,
+ cancellable,
+ fwupd_client_refresh_remote_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_modify_remote_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_modify_remote_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_modify_remote:
+ * @self: a #FwupdClient
+ * @remote_id: the remote ID, e.g. `lvfs-testing`
+ * @key: the key, e.g. `Enabled`
+ * @value: the key, e.g. `true`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Modifies a system remote in a specific way.
+ *
+ * NOTE: User authentication may be required to complete this action.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.9.8
+ **/
+gboolean
+fwupd_client_modify_remote(FwupdClient *self,
+ const gchar *remote_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(remote_id != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(value != 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_modify_remote_async(self,
+ remote_id,
+ key,
+ value,
+ cancellable,
+ fwupd_client_modify_remote_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_get_report_metadata_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->hash =
+ fwupd_client_get_report_metadata_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_report_metadata:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets all the report metadata from the daemon.
+ *
+ * Returns: (transfer container): attributes
+ *
+ * Since: 1.5.0
+ **/
+GHashTable *
+fwupd_client_get_report_metadata(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_report_metadata_async(self,
+ cancellable,
+ fwupd_client_get_report_metadata_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->hash == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->hash);
+}
+
+static void
+fwupd_client_modify_device_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret = fwupd_client_modify_device_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_modify_device:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @key: (not nullable): the key, e.g. `Flags`
+ * @value: (not nullable): the key, e.g. `reported`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Modifies a device in a specific way. Not all properties on the #FwupdDevice
+ * are settable by the client, and some may have other restrictions on @value.
+ *
+ * NOTE: User authentication may be required to complete this action.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.0.4
+ **/
+gboolean
+fwupd_client_modify_device(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(device_id != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(value != 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_modify_device_async(self,
+ device_id,
+ key,
+ value,
+ cancellable,
+ fwupd_client_modify_device_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_get_remotes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array = fwupd_client_get_remotes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_remotes:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the list of remotes that have been configured for the system.
+ *
+ * Returns: (element-type FwupdRemote) (transfer container): list of remotes, or %NULL
+ *
+ * Since: 0.9.3
+ **/
+GPtrArray *
+fwupd_client_get_remotes(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_remotes_async(self, cancellable, fwupd_client_get_remotes_cb, helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->array);
+}
+
+static FwupdRemote *
+fwupd_client_get_remote_by_id_noref(GPtrArray *remotes, const gchar *remote_id)
+{
+ 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;
+ }
+ return NULL;
+}
+
+/**
+ * fwupd_client_get_remote_by_id:
+ * @self: a #FwupdClient
+ * @remote_id: the remote ID, e.g. `lvfs-testing`
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets a specific remote that has been configured for the system.
+ *
+ * Returns: (transfer full): a #FwupdRemote, or %NULL if not found
+ *
+ * Since: 0.9.3
+ **/
+FwupdRemote *
+fwupd_client_get_remote_by_id(FwupdClient *self,
+ const gchar *remote_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ FwupdRemote *remote;
+ g_autoptr(GPtrArray) remotes = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(remote_id != NULL, NULL);
+ g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* find remote in list */
+ remotes = fwupd_client_get_remotes(self, cancellable, error);
+ if (remotes == NULL)
+ return NULL;
+ remote = fwupd_client_get_remote_by_id_noref(remotes, remote_id);
+ if (remote == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_FOUND,
+ "No remote '%s' found in search paths",
+ remote_id);
+ return NULL;
+ }
+
+ /* success */
+ return g_object_ref(remote);
+}
+
+static void
+fwupd_client_get_approved_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_approved_firmware_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_approved_firmware:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the list of approved firmware.
+ *
+ * Returns: (transfer full): checksums, or %NULL for error
+ *
+ * Since: 1.2.6
+ **/
+gchar **
+fwupd_client_get_approved_firmware(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+ gchar **argv;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_approved_firmware_async(self,
+ cancellable,
+ fwupd_client_get_approved_firmware_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ argv = g_new0(gchar *, helper->array->len + 1);
+ for (guint i = 0; i < helper->array->len; i++) {
+ const gchar *tmp = g_ptr_array_index(helper->array, i);
+ argv[i] = g_strdup(tmp);
+ }
+ return argv;
+}
+
+static void
+fwupd_client_set_approved_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_set_approved_firmware_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_set_approved_firmware:
+ * @self: a #FwupdClient
+ * @checksums: (not nullable): Array of checksums
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets the list of approved firmware.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.2.6
+ **/
+gboolean
+fwupd_client_set_approved_firmware(FwupdClient *self,
+ gchar **checksums,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+ g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free);
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(checksums != 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(self, cancellable, error))
+ return FALSE;
+
+ /* convert */
+ for (guint i = 0; checksums[i] != NULL; i++)
+ g_ptr_array_add(array, g_strdup(checksums[i]));
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_set_approved_firmware_async(self,
+ array,
+ cancellable,
+ fwupd_client_set_approved_firmware_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_get_blocked_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->array =
+ fwupd_client_get_blocked_firmware_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_get_blocked_firmware:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the list of blocked firmware.
+ *
+ * Returns: (transfer full): checksums, or %NULL for error
+ *
+ * Since: 1.4.6
+ **/
+gchar **
+fwupd_client_get_blocked_firmware(FwupdClient *self, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+ gchar **argv;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_get_blocked_firmware_async(self,
+ cancellable,
+ fwupd_client_get_blocked_firmware_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->array == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ argv = g_new0(gchar *, helper->array->len + 1);
+ for (guint i = 0; i < helper->array->len; i++) {
+ const gchar *tmp = g_ptr_array_index(helper->array, i);
+ argv[i] = g_strdup(tmp);
+ }
+ return argv;
+}
+
+static void
+fwupd_client_set_blocked_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_set_blocked_firmware_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_set_blocked_firmware:
+ * @self: a #FwupdClient
+ * @checksums: Array of checksums
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets the list of approved firmware.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.6
+ **/
+gboolean
+fwupd_client_set_blocked_firmware(FwupdClient *self,
+ gchar **checksums,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+ g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free);
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(checksums != 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(self, cancellable, error))
+ return FALSE;
+
+ for (guint i = 0; checksums[i] != NULL; i++)
+ g_ptr_array_add(array, g_strdup(checksums[i]));
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_set_blocked_firmware_async(self,
+ array,
+ cancellable,
+ fwupd_client_set_blocked_firmware_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_set_feature_flags_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->ret =
+ fwupd_client_set_feature_flags_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_set_feature_flags:
+ * @self: a #FwupdClient
+ * @feature_flags: feature flags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets the features the client supports. This allows firmware to depend on
+ * specific front-end features, for instance showing the user an image on
+ * how to detach the hardware.
+ *
+ * Clients can call this none or multiple times.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ **/
+gboolean
+fwupd_client_set_feature_flags(FwupdClient *self,
+ FwupdFeatureFlags feature_flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 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(self, cancellable, error))
+ return FALSE;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_set_feature_flags_async(self,
+ feature_flags,
+ cancellable,
+ fwupd_client_set_feature_flags_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (!helper->ret) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fwupd_client_self_sign_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->str = fwupd_client_self_sign_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_self_sign:
+ * @self: a #FwupdClient
+ * @value: (not nullable): a string to sign, typically a JSON blob
+ * @flags: signing flags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Signs the data using the client self-signed certificate.
+ *
+ * Returns: a signature, or %NULL for failure
+ *
+ * Since: 1.2.6
+ **/
+gchar *
+fwupd_client_self_sign(FwupdClient *self,
+ const gchar *value,
+ FwupdSelfSignFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(value != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_self_sign_async(self,
+ value,
+ flags,
+ cancellable,
+ fwupd_client_self_sign_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->str == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->str);
+}
+
+static void
+fwupd_client_download_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->bytes =
+ fwupd_client_download_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_download_bytes:
+ * @self: a #FwupdClient
+ * @url: (not nullable): the remote URL
+ * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Downloads data from a remote server. The [method@Client.set_user_agent] function
+ * should be called before this method is used.
+ *
+ * Returns: (transfer full): downloaded data, or %NULL for error
+ *
+ * Since: 1.4.5
+ **/
+GBytes *
+fwupd_client_download_bytes(FwupdClient *self,
+ const gchar *url,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(url != NULL, NULL);
+ g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail(fwupd_client_get_user_agent(self) != NULL, NULL);
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_download_bytes_async(self,
+ url,
+ flags,
+ cancellable,
+ fwupd_client_download_bytes_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->bytes == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->bytes);
+}
+
+/**
+ * fwupd_client_download_file:
+ * @self: a #FwupdClient
+ * @url: (not nullable): the remote URL
+ * @file: (not nullable): a file
+ * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Downloads data from a remote server. The [method@Client.set_user_agent] function
+ * should be called before this method is used.
+ *
+ * Returns: %TRUE if the file was written
+ *
+ * Since: 1.5.2
+ **/
+gboolean
+fwupd_client_download_file(FwupdClient *self,
+ const gchar *url,
+ GFile *file,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gssize size;
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GOutputStream) ostream = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(url != NULL, FALSE);
+ g_return_val_if_fail(G_IS_FILE(file), FALSE);
+ g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail(fwupd_client_get_user_agent(self) != NULL, FALSE);
+
+ /* download then write */
+ bytes = fwupd_client_download_bytes(self, url, flags, cancellable, error);
+ if (bytes == NULL)
+ return FALSE;
+ ostream =
+ G_OUTPUT_STREAM(g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error));
+ if (ostream == NULL)
+ return FALSE;
+ size = g_output_stream_write_bytes(ostream, bytes, NULL, error);
+ if (size < 0)
+ return FALSE;
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fwupd_client_upload_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdClientHelper *helper = (FwupdClientHelper *)user_data;
+ helper->bytes = fwupd_client_upload_bytes_finish(FWUPD_CLIENT(source), res, &helper->error);
+ g_main_loop_quit(helper->loop);
+}
+
+/**
+ * fwupd_client_upload_bytes:
+ * @self: a #FwupdClient
+ * @url: (not nullable): the remote URL
+ * @payload: (not nullable): payload string
+ * @signature: (nullable): signature string
+ * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Uploads data to a remote server. The [method@Client.set_user_agent] function
+ * should be called before this method is used.
+ *
+ * Returns: (transfer full): response data, or %NULL for error
+ *
+ * Since: 1.4.5
+ **/
+GBytes *
+fwupd_client_upload_bytes(FwupdClient *self,
+ const gchar *url,
+ const gchar *payload,
+ const gchar *signature,
+ FwupdClientUploadFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(FwupdClientHelper) helper = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(url != NULL, NULL);
+ g_return_val_if_fail(payload != NULL, 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(self, cancellable, error))
+ return NULL;
+
+ /* call async version and run loop until complete */
+ helper = fwupd_client_helper_new(self);
+ fwupd_client_upload_bytes_async(self,
+ url,
+ payload,
+ signature,
+ flags,
+ cancellable,
+ fwupd_client_upload_bytes_cb,
+ helper);
+ g_main_loop_run(helper->loop);
+ if (helper->bytes == NULL) {
+ g_propagate_error(error, g_steal_pointer(&helper->error));
+ return NULL;
+ }
+ return g_steal_pointer(&helper->bytes);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-client-sync.h b/fwupd-1.8.6/libfwupd/fwupd-client-sync.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc38cf1e6b690a45962cbd0b8033361628d2ce35
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-client-sync.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fwupd-client.h"
+
+G_BEGIN_DECLS
+
+gboolean
+fwupd_client_connect(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_devices(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_plugins(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_history(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_releases(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_downgrades(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_upgrades(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_details(FwupdClient *self,
+ const gchar *filename,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_details_bytes(FwupdClient *self,
+ GBytes *bytes,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_verify(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_verify_update(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_unlock(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_modify_config(FwupdClient *self,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_activate(FwupdClient *self,
+ GCancellable *cancellable,
+ const gchar *device_id,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_clear_results(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+FwupdDevice *
+fwupd_client_get_results(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_modify_bios_setting(FwupdClient *self,
+ GHashTable *settings,
+ GCancellable *cancellable,
+ GError **error);
+GPtrArray *
+fwupd_client_get_bios_settings(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_host_security_attrs(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_host_security_events(FwupdClient *self,
+ guint limit,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+FwupdDevice *
+fwupd_client_get_device_by_id(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_devices_by_guid(FwupdClient *self,
+ const gchar *guid,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_install(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *filename,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_install_bytes(FwupdClient *self,
+ const gchar *device_id,
+ GBytes *bytes,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_install_release(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GError **error) G_DEPRECATED_FOR(fwupd_client_install_release2);
+gboolean
+fwupd_client_install_release2(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ FwupdClientDownloadFlags download_flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_update_metadata(FwupdClient *self,
+ const gchar *remote_id,
+ const gchar *metadata_fn,
+ const gchar *signature_fn,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_update_metadata_bytes(FwupdClient *self,
+ const gchar *remote_id,
+ GBytes *metadata,
+ GBytes *signature,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_refresh_remote(FwupdClient *self,
+ FwupdRemote *remote,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_modify_remote(FwupdClient *self,
+ const gchar *remote_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_modify_device(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GHashTable *
+fwupd_client_get_report_metadata(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GPtrArray *
+fwupd_client_get_remotes(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+FwupdRemote *
+fwupd_client_get_remote_by_id(FwupdClient *self,
+ const gchar *remote_id,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gchar **
+fwupd_client_get_approved_firmware(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_set_approved_firmware(FwupdClient *self,
+ gchar **checksums,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gchar **
+fwupd_client_get_blocked_firmware(FwupdClient *self,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_set_blocked_firmware(FwupdClient *self,
+ gchar **checksums,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gchar *
+fwupd_client_self_sign(FwupdClient *self,
+ const gchar *value,
+ FwupdSelfSignFlags flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_set_feature_flags(FwupdClient *self,
+ FwupdFeatureFlags feature_flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fwupd_client_download_bytes(FwupdClient *self,
+ const gchar *url,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_download_file(FwupdClient *self,
+ const gchar *url,
+ GFile *file,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fwupd_client_upload_bytes(FwupdClient *self,
+ const gchar *url,
+ const gchar *payload,
+ const gchar *signature,
+ FwupdClientUploadFlags flags,
+ GCancellable *cancellable,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-client.c b/fwupd-1.8.6/libfwupd/fwupd-client.c
new file mode 100644
index 0000000000000000000000000000000000000000..82ffaabe4aa7ae87e6d92615bbd31d4869319ba5
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-client.c
@@ -0,0 +1,5960 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+#include
+#ifdef HAVE_LIBCURL
+#include
+#endif
+#ifdef HAVE_GIO_UNIX
+#include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include "fwupd-bios-setting-private.h"
+#include "fwupd-client-private.h"
+#include "fwupd-client-sync.h"
+#include "fwupd-common-private.h"
+#include "fwupd-deprecated.h"
+#include "fwupd-device-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-error.h"
+#include "fwupd-plugin-private.h"
+#include "fwupd-release-private.h"
+#include "fwupd-remote-private.h"
+#include "fwupd-request-private.h"
+#include "fwupd-security-attr-private.h"
+
+static void
+fwupd_client_fixup_dbus_error(GError *error);
+
+typedef GObject *(*FwupdClientObjectNewFunc)(void);
+
+#define FWUPD_CLIENT_DBUS_PROXY_TIMEOUT 180000 /* ms */
+
+/**
+ * FwupdClient:
+ *
+ * Allow client code to call the daemon methods.
+ *
+ * See also: [class@FwupdDevice]
+ */
+
+static void
+fwupd_client_finalize(GObject *object);
+
+typedef struct {
+ GMainContext *main_ctx;
+ FwupdStatus status;
+ gboolean tainted;
+ gboolean interactive;
+ guint percentage;
+ guint32 battery_level;
+ guint32 battery_threshold;
+ GMutex idle_mutex; /* for @idle_id and @idle_sources */
+ guint idle_id;
+ GPtrArray *idle_sources; /* element-type FwupdClientContextHelper */
+ gchar *daemon_version;
+ gchar *host_bkc;
+ gchar *host_product;
+ gchar *host_vendor;
+ gchar *host_machine_id;
+ gchar *host_security_id;
+ gboolean only_trusted;
+ GMutex proxy_mutex; /* for @proxy */
+ GDBusProxy *proxy;
+ GProxyResolver *proxy_resolver;
+ gchar *user_agent;
+ GHashTable *hints; /* str:str */
+#ifdef SOUP_SESSION_COMPAT
+ GObject *soup_session;
+ GModule *soup_module; /* we leak this */
+#endif
+} FwupdClientPrivate;
+
+#ifdef HAVE_LIBCURL
+typedef struct {
+ GPtrArray *urls;
+ CURL *curl;
+ curl_mime *mime;
+ struct curl_slist *headers;
+} FwupdCurlHelper;
+#endif
+
+enum {
+ SIGNAL_CHANGED,
+ SIGNAL_STATUS_CHANGED,
+ SIGNAL_DEVICE_ADDED,
+ SIGNAL_DEVICE_REMOVED,
+ SIGNAL_DEVICE_CHANGED,
+ SIGNAL_DEVICE_REQUEST,
+ SIGNAL_LAST
+};
+
+enum {
+ PROP_0,
+ PROP_STATUS,
+ PROP_PERCENTAGE,
+ PROP_DAEMON_VERSION,
+ PROP_TAINTED,
+ PROP_SOUP_SESSION, /* compat ABI, do not use! */
+ PROP_HOST_PRODUCT,
+ PROP_HOST_VENDOR,
+ PROP_HOST_MACHINE_ID,
+ PROP_HOST_SECURITY_ID,
+ PROP_HOST_BKC,
+ PROP_INTERACTIVE,
+ PROP_ONLY_TRUSTED,
+ PROP_BATTERY_LEVEL,
+ PROP_BATTERY_THRESHOLD,
+ PROP_LAST
+};
+
+static guint signals[SIGNAL_LAST] = {0};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdClient, fwupd_client, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_client_get_instance_private(o))
+
+#ifdef HAVE_LIBCURL_7_62_0
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup)
+#endif
+
+#ifdef HAVE_LIBCURL
+static void
+fwupd_client_curl_helper_free(FwupdCurlHelper *helper)
+{
+ if (helper->curl != NULL)
+ curl_easy_cleanup(helper->curl);
+ if (helper->mime != NULL)
+ curl_mime_free(helper->mime);
+ if (helper->headers != NULL)
+ curl_slist_free_all(helper->headers);
+ if (helper->urls != NULL)
+ g_ptr_array_unref(helper->urls);
+ g_free(helper);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdCurlHelper, fwupd_client_curl_helper_free)
+#endif
+
+typedef struct {
+ FwupdClient *self;
+ gchar *property_name;
+ guint signal_id;
+ GObject *payload;
+} FwupdClientContextHelper;
+
+static void
+fwupd_client_context_helper_free(FwupdClientContextHelper *helper)
+{
+ g_clear_object(&helper->payload);
+ g_object_unref(helper->self);
+ g_free(helper->property_name);
+ g_free(helper);
+}
+
+/* always executed in the main context given by priv->main_ctx */
+static void
+fwupd_client_context_object_notify(FwupdClient *self, const gchar *property_name)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(g_main_context_is_owner(priv->main_ctx));
+
+ /* property */
+ g_object_notify(G_OBJECT(self), property_name);
+
+ /* legacy signal name */
+ if (g_strcmp0(property_name, "status") == 0)
+ g_signal_emit(self, signals[SIGNAL_STATUS_CHANGED], 0, priv->status);
+}
+
+/* emits all pending context helpers in the correct GMainContext */
+static gboolean
+fwupd_client_context_idle_cb(gpointer user_data)
+{
+ FwupdClient *self = FWUPD_CLIENT(user_data);
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->idle_mutex);
+
+ g_assert(locker != NULL);
+
+ for (guint i = 0; i < priv->idle_sources->len; i++) {
+ FwupdClientContextHelper *helper = g_ptr_array_index(priv->idle_sources, i);
+
+ /* property */
+ if (helper->property_name != NULL)
+ fwupd_client_context_object_notify(self, helper->property_name);
+
+ /* payload signal */
+ if (helper->signal_id != 0 && helper->payload != NULL)
+ g_signal_emit(self, signals[helper->signal_id], 0, helper->payload);
+ }
+
+ /* all done */
+ g_ptr_array_set_size(priv->idle_sources, 0);
+ priv->idle_id = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static void
+fwupd_client_context_helper(FwupdClient *self, FwupdClientContextHelper *helper)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->idle_mutex);
+
+ g_assert(locker != NULL);
+
+ /* no source already attached to the context */
+ if (priv->idle_id == 0) {
+ g_autoptr(GSource) source = g_idle_source_new();
+ g_source_set_callback(source, fwupd_client_context_idle_cb, self, NULL);
+ priv->idle_id = g_source_attach(g_steal_pointer(&source), priv->main_ctx);
+ }
+
+ /* run in the correct GMainContext and thread */
+ g_ptr_array_add(priv->idle_sources, helper);
+}
+
+/* run callback in the correct thread */
+static void
+fwupd_client_object_notify(FwupdClient *self, const gchar *property_name)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ FwupdClientContextHelper *helper = NULL;
+
+ /* shortcut */
+ if (g_main_context_is_owner(priv->main_ctx)) {
+ fwupd_client_context_object_notify(self, property_name);
+ return;
+ }
+
+ /* run in the correct GMainContext and thread */
+ helper = g_new0(FwupdClientContextHelper, 1);
+ helper->self = g_object_ref(self);
+ helper->property_name = g_strdup(property_name);
+ fwupd_client_context_helper(self, helper);
+}
+
+/* run callback in the correct thread */
+static void
+fwupd_client_signal_emit_object(FwupdClient *self, guint signal_id, GObject *payload)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ FwupdClientContextHelper *helper = NULL;
+
+ /* shortcut */
+ if (g_main_context_is_owner(priv->main_ctx)) {
+ g_signal_emit(self, signals[signal_id], 0, payload);
+ return;
+ }
+
+ /* run in the correct GMainContext and thread */
+ helper = g_new0(FwupdClientContextHelper, 1);
+ helper->self = g_object_ref(self);
+ helper->signal_id = signal_id;
+ helper->payload = g_object_ref(payload);
+ fwupd_client_context_helper(self, helper);
+}
+
+static void
+fwupd_client_set_host_vendor(FwupdClient *self, const gchar *host_vendor)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->host_vendor, host_vendor) == 0)
+ return;
+
+ g_free(priv->host_vendor);
+ priv->host_vendor = g_strdup(host_vendor);
+ fwupd_client_object_notify(self, "host-vendor");
+}
+
+static void
+fwupd_client_set_host_product(FwupdClient *self, const gchar *host_product)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->host_product, host_product) == 0)
+ return;
+
+ g_free(priv->host_product);
+ priv->host_product = g_strdup(host_product);
+ fwupd_client_object_notify(self, "host-product");
+}
+
+static void
+fwupd_client_set_host_machine_id(FwupdClient *self, const gchar *host_machine_id)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->host_machine_id, host_machine_id) == 0)
+ return;
+
+ g_free(priv->host_machine_id);
+ priv->host_machine_id = g_strdup(host_machine_id);
+ fwupd_client_object_notify(self, "host-machine-id");
+}
+
+static void
+fwupd_client_set_host_security_id(FwupdClient *self, const gchar *host_security_id)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->host_security_id, host_security_id) == 0)
+ return;
+
+ g_free(priv->host_security_id);
+ priv->host_security_id = g_strdup(host_security_id);
+ fwupd_client_object_notify(self, "host-security-id");
+}
+
+static void
+fwupd_client_set_daemon_version(FwupdClient *self, const gchar *daemon_version)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->daemon_version, daemon_version) == 0)
+ return;
+
+ g_free(priv->daemon_version);
+ priv->daemon_version = g_strdup(daemon_version);
+ fwupd_client_object_notify(self, "daemon-version");
+}
+
+static void
+fwupd_client_set_host_bkc(FwupdClient *self, const gchar *host_bkc)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ /* emulate a D-Bus maybe type */
+ if (g_strcmp0(host_bkc, "") == 0)
+ host_bkc = NULL;
+
+ /* not changed */
+ if (g_strcmp0(priv->host_bkc, host_bkc) == 0)
+ return;
+
+ g_free(priv->host_bkc);
+ priv->host_bkc = g_strdup(host_bkc);
+ fwupd_client_object_notify(self, "host-bkc");
+}
+
+static void
+fwupd_client_set_status(FwupdClient *self, FwupdStatus status)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ if (priv->status == status)
+ return;
+ priv->status = status;
+ g_debug("Emitting ::status-changed() [%s]", fwupd_status_to_string(priv->status));
+ fwupd_client_object_notify(self, "status");
+}
+
+static void
+fwupd_client_set_percentage(FwupdClient *self, guint percentage)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ if (priv->percentage == percentage)
+ return;
+ priv->percentage = percentage;
+ fwupd_client_object_notify(self, "percentage");
+}
+
+static void
+fwupd_client_set_battery_level(FwupdClient *self, guint32 battery_level)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ if (priv->battery_level == battery_level)
+ return;
+ priv->battery_level = battery_level;
+ g_object_notify(G_OBJECT(self), "battery-level");
+}
+
+static void
+fwupd_client_set_battery_threshold(FwupdClient *self, guint32 battery_threshold)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ if (priv->battery_threshold == battery_threshold)
+ return;
+ priv->battery_threshold = battery_threshold;
+ g_object_notify(G_OBJECT(self), "battery-threshold");
+}
+
+static void
+fwupd_client_properties_changed_cb(GDBusProxy *proxy,
+ GVariant *changed_properties,
+ const GStrv invalidated_properties,
+ FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GVariantDict) dict = NULL;
+
+ /* print to the console */
+ dict = g_variant_dict_new(changed_properties);
+ if (g_variant_dict_contains(dict, "Status")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "Status");
+ if (val != NULL)
+ fwupd_client_set_status(self, g_variant_get_uint32(val));
+ }
+ 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);
+ fwupd_client_object_notify(self, "tainted");
+ }
+ }
+ if (g_variant_dict_contains(dict, "Interactive")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "Interactive");
+ if (val != NULL) {
+ priv->interactive = g_variant_get_boolean(val);
+ fwupd_client_object_notify(self, "interactive");
+ }
+ }
+ if (g_variant_dict_contains(dict, "Percentage")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "Percentage");
+ if (val != NULL)
+ fwupd_client_set_percentage(self, g_variant_get_uint32(val));
+ }
+ if (g_variant_dict_contains(dict, FWUPD_RESULT_KEY_BATTERY_LEVEL)) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, FWUPD_RESULT_KEY_BATTERY_LEVEL);
+ if (val != NULL)
+ fwupd_client_set_battery_level(self, g_variant_get_uint32(val));
+ }
+ if (g_variant_dict_contains(dict, FWUPD_RESULT_KEY_BATTERY_THRESHOLD)) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, FWUPD_RESULT_KEY_BATTERY_THRESHOLD);
+ if (val != NULL)
+ fwupd_client_set_battery_threshold(self, g_variant_get_uint32(val));
+ }
+ if (g_variant_dict_contains(dict, "DaemonVersion")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "DaemonVersion");
+ if (val != NULL)
+ fwupd_client_set_daemon_version(self, g_variant_get_string(val, NULL));
+ }
+ if (g_variant_dict_contains(dict, "HostBkc")) {
+ g_autoptr(GVariant) val = g_dbus_proxy_get_cached_property(proxy, "HostBkc");
+ if (val != NULL)
+ fwupd_client_set_host_bkc(self, g_variant_get_string(val, NULL));
+ }
+ if (g_variant_dict_contains(dict, "HostVendor")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "HostVendor");
+ if (val != NULL)
+ fwupd_client_set_host_vendor(self, g_variant_get_string(val, NULL));
+ }
+ if (g_variant_dict_contains(dict, "HostProduct")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "HostProduct");
+ if (val != NULL)
+ fwupd_client_set_host_product(self, g_variant_get_string(val, NULL));
+ }
+ if (g_variant_dict_contains(dict, "HostMachineId")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "HostMachineId");
+ if (val != NULL)
+ fwupd_client_set_host_machine_id(self, g_variant_get_string(val, NULL));
+ }
+ if (g_variant_dict_contains(dict, "HostSecurityId")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "HostSecurityId");
+ if (val != NULL)
+ fwupd_client_set_host_security_id(self, g_variant_get_string(val, NULL));
+ }
+ if (g_variant_dict_contains(dict, "OnlyTrusted")) {
+ g_autoptr(GVariant) val = NULL;
+ val = g_dbus_proxy_get_cached_property(proxy, "OnlyTrusted");
+ if (val != NULL) {
+ priv->only_trusted = g_variant_get_boolean(val);
+ fwupd_client_object_notify(self, "only-trusted");
+ }
+ }
+}
+
+static void
+fwupd_client_signal_cb(GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ FwupdClient *self)
+{
+ g_autoptr(FwupdDevice) dev = NULL;
+ if (g_strcmp0(signal_name, "Changed") == 0) {
+ g_debug("Emitting ::changed()");
+ g_signal_emit(self, signals[SIGNAL_CHANGED], 0);
+ return;
+ }
+ if (g_strcmp0(signal_name, "DeviceAdded") == 0) {
+ dev = fwupd_device_from_variant(parameters);
+ g_debug("Emitting ::device-added(%s)", fwupd_device_get_id(dev));
+ fwupd_client_signal_emit_object(self, SIGNAL_DEVICE_ADDED, G_OBJECT(dev));
+ return;
+ }
+ if (g_strcmp0(signal_name, "DeviceRemoved") == 0) {
+ dev = fwupd_device_from_variant(parameters);
+ g_debug("Emitting ::device-removed(%s)", fwupd_device_get_id(dev));
+ fwupd_client_signal_emit_object(self, SIGNAL_DEVICE_REMOVED, G_OBJECT(dev));
+ return;
+ }
+ if (g_strcmp0(signal_name, "DeviceChanged") == 0) {
+ dev = fwupd_device_from_variant(parameters);
+ g_debug("Emitting ::device-changed(%s)", fwupd_device_get_id(dev));
+ fwupd_client_signal_emit_object(self, SIGNAL_DEVICE_CHANGED, G_OBJECT(dev));
+ return;
+ }
+ if (g_strcmp0(signal_name, "DeviceRequest") == 0) {
+ g_autoptr(FwupdRequest) req = fwupd_request_from_variant(parameters);
+ g_debug("Emitting ::device-request(%s)", fwupd_request_get_id(req));
+ fwupd_client_signal_emit_object(self, SIGNAL_DEVICE_REQUEST, G_OBJECT(req));
+ return;
+ }
+ g_debug("Unknown signal name '%s' from %s", signal_name, sender_name);
+}
+
+/**
+ * fwupd_client_get_main_context:
+ * @self: a #FwupdClient
+ *
+ * Gets the internal #GMainContext to use for synchronous methods.
+ * By default the value is set a new #GMainContext.
+ *
+ * Returns: (transfer full): the main context
+ *
+ * Since: 1.5.3
+ **/
+GMainContext *
+fwupd_client_get_main_context(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ if (priv->main_ctx != NULL)
+ return g_main_context_ref(priv->main_ctx);
+ return g_main_context_new();
+}
+
+/**
+ * fwupd_client_set_main_context:
+ * @self: a #FwupdClient
+ * @main_ctx: (nullable): the global default main context to use
+ *
+ * Sets the internal main context to use for returning progress signals.
+ *
+ * Since: 1.5.3
+ **/
+void
+fwupd_client_set_main_context(FwupdClient *self, GMainContext *main_ctx)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ if (main_ctx == priv->main_ctx)
+ return;
+ g_clear_pointer(&priv->main_ctx, g_main_context_unref);
+ if (main_ctx != NULL)
+ priv->main_ctx = g_main_context_ref(main_ctx);
+}
+
+/**
+ * fwupd_client_ensure_networking:
+ * @self: a #FwupdClient
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets up the client networking support ready for use. Most other download and
+ * upload methods call this automatically, and do you only need to call this if
+ * the session is being used outside the [class@FwupdClient].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ **/
+gboolean
+fwupd_client_ensure_networking(FwupdClient *self, GError **error)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* check the user agent is sane */
+ if (priv->user_agent == NULL) {
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "user agent unset");
+ return FALSE;
+ }
+ if (g_strstr_len(priv->user_agent, -1, "fwupd/") == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "user agent unsuitable; fwupd version required");
+ return FALSE;
+ }
+#ifdef SOUP_SESSION_COMPAT
+ if (priv->soup_session != NULL) {
+ g_object_set(priv->soup_session, "user-agent", priv->user_agent, NULL);
+ }
+#endif
+ return TRUE;
+}
+
+#ifdef HAVE_LIBCURL
+static int
+fwupd_client_progress_callback_cb(void *clientp,
+ curl_off_t dltotal,
+ curl_off_t dlnow,
+ curl_off_t ultotal,
+ curl_off_t ulnow)
+{
+ FwupdClient *self = FWUPD_CLIENT(clientp);
+
+ /* calculate percentage */
+ if (dltotal > 0 && dlnow >= 0 && dlnow <= dltotal) {
+ guint percentage = (guint)((100 * dlnow) / dltotal);
+ g_debug("download progress: %u%%", percentage);
+ fwupd_client_set_percentage(self, percentage);
+ } else if (ultotal > 0 && ulnow >= 0 && ulnow <= ultotal) {
+ guint percentage = (guint)((100 * ulnow) / ultotal);
+ g_debug("upload progress: %u%%", percentage);
+ fwupd_client_set_percentage(self, percentage);
+ }
+
+ return 0;
+}
+
+static void
+fwupd_client_curl_helper_set_proxy(FwupdClient *self, FwupdCurlHelper *helper, const gchar *url)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_auto(GStrv) proxies = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ proxies = g_proxy_resolver_lookup(priv->proxy_resolver, url, NULL, &error_local);
+ if (proxies == NULL) {
+ g_warning("failed to lookup proxy for %s: %s", url, error_local->message);
+ return;
+ }
+ if (g_strcmp0(proxies[0], "direct://") != 0)
+ (void)curl_easy_setopt(helper->curl, CURLOPT_PROXY, proxies[0]);
+}
+
+static FwupdCurlHelper *
+fwupd_client_curl_new(FwupdClient *self, GError **error)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(FwupdCurlHelper) helper = g_new0(FwupdCurlHelper, 1);
+
+ /* check the user agent is sane */
+ if (!fwupd_client_ensure_networking(self, error))
+ return NULL;
+
+ /* create the session */
+ helper->curl = curl_easy_init();
+ if (helper->curl == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "failed to setup networking");
+ return NULL;
+ }
+ if (g_getenv("FWUPD_CURL_VERBOSE") != NULL)
+ (void)curl_easy_setopt(helper->curl, CURLOPT_VERBOSE, 1L);
+ (void)curl_easy_setopt(helper->curl,
+ CURLOPT_XFERINFOFUNCTION,
+ fwupd_client_progress_callback_cb);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_XFERINFODATA, self);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_USERAGENT, priv->user_agent);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_CONNECTTIMEOUT, 60L);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_NOPROGRESS, 0L);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_FOLLOWLOCATION, 1L);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_MAXREDIRS, 5L);
+#if CURL_AT_LEAST_VERSION(7, 71, 0)
+ (void)curl_easy_setopt(helper->curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
+#endif
+
+ /* relax the SSL checks for broken corporate proxies */
+ if (g_getenv("DISABLE_SSL_STRICT") != NULL)
+ (void)curl_easy_setopt(helper->curl, CURLOPT_SSL_VERIFYPEER, 0L);
+
+ /* this disables the double-compression of the firmware.xml.gz file */
+ (void)curl_easy_setopt(helper->curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
+ return g_steal_pointer(&helper);
+}
+#endif
+
+static void
+fwupd_client_set_hints_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ /* new libfwupd and old daemon, just swallow the error */
+ if (g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
+ g_debug("ignoring %s", error->message);
+ g_task_return_boolean(task, TRUE);
+ return;
+ }
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+static void
+fwupd_client_connect_get_proxy_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ GVariantBuilder builder;
+ GHashTableIter iter;
+ gpointer key, value;
+ FwupdClient *self = g_task_get_source_object(task);
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ GCancellable *cancellable = g_task_get_cancellable(task);
+ g_autoptr(GDBusProxy) proxy = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+ g_autoptr(GVariant) val2 = NULL;
+ g_autoptr(GVariant) val3 = NULL;
+ g_autoptr(GVariant) val4 = NULL;
+ g_autoptr(GVariant) val5 = NULL;
+ g_autoptr(GVariant) val6 = NULL;
+ g_autoptr(GVariant) val7 = NULL;
+ g_autoptr(GVariant) val8 = NULL;
+ g_autoptr(GVariant) val9 = NULL;
+ g_autoptr(GVariant) val10 = NULL;
+ g_autoptr(GMutexLocker) locker = NULL;
+
+ proxy = g_dbus_proxy_new_finish(res, &error);
+ if (proxy == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* another thread did this for us */
+ locker = g_mutex_locker_new(&priv->proxy_mutex);
+ if (locker == NULL || priv->proxy != NULL) {
+ g_task_return_boolean(task, TRUE);
+ return;
+ }
+ priv->proxy = g_steal_pointer(&proxy);
+
+ /* connect signals, etc. */
+ g_signal_connect(G_DBUS_PROXY(priv->proxy),
+ "g-properties-changed",
+ G_CALLBACK(fwupd_client_properties_changed_cb),
+ self);
+ g_signal_connect(G_DBUS_PROXY(priv->proxy),
+ "g-signal",
+ G_CALLBACK(fwupd_client_signal_cb),
+ self);
+ val = g_dbus_proxy_get_cached_property(priv->proxy, "DaemonVersion");
+ if (val != NULL)
+ fwupd_client_set_daemon_version(self, 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);
+ val3 = g_dbus_proxy_get_cached_property(priv->proxy, "Status");
+ if (val3 != NULL)
+ fwupd_client_set_status(self, g_variant_get_uint32(val3));
+ val4 = g_dbus_proxy_get_cached_property(priv->proxy, "Interactive");
+ if (val4 != NULL)
+ priv->interactive = g_variant_get_boolean(val4);
+ val5 = g_dbus_proxy_get_cached_property(priv->proxy, "HostProduct");
+ if (val5 != NULL)
+ fwupd_client_set_host_product(self, g_variant_get_string(val5, NULL));
+ val10 = g_dbus_proxy_get_cached_property(priv->proxy, "HostVendor");
+ if (val10 != NULL)
+ fwupd_client_set_host_vendor(self, g_variant_get_string(val10, NULL));
+ val6 = g_dbus_proxy_get_cached_property(priv->proxy, "HostMachineId");
+ if (val6 != NULL)
+ fwupd_client_set_host_machine_id(self, g_variant_get_string(val6, NULL));
+ val7 = g_dbus_proxy_get_cached_property(priv->proxy, "HostSecurityId");
+ if (val7 != NULL)
+ fwupd_client_set_host_security_id(self, g_variant_get_string(val7, NULL));
+ val8 = g_dbus_proxy_get_cached_property(priv->proxy, "HostBkc");
+ if (val8 != NULL)
+ fwupd_client_set_host_bkc(self, g_variant_get_string(val8, NULL));
+ val9 = g_dbus_proxy_get_cached_property(priv->proxy, "OnlyTrusted");
+ if (val9 != NULL)
+ priv->only_trusted = g_variant_get_boolean(val9);
+
+ /* build client hints */
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
+ g_hash_table_iter_init(&iter, priv->hints);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (value == NULL)
+ continue;
+ g_variant_builder_add(&builder, "{ss}", (const gchar *)key, (const gchar *)value);
+ }
+
+ /* only supported on fwupd >= 1.7.1 */
+ g_dbus_proxy_call(priv->proxy,
+ "SetHints",
+ g_variant_new("(a{ss})", &builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_set_hints_cb,
+ g_steal_pointer(&task));
+}
+
+static void
+fwupd_client_connect_get_connection_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ GCancellable *cancellable = g_task_get_cancellable(task);
+ g_autoptr(GDBusConnection) connection = NULL;
+ g_autoptr(GError) error = NULL;
+
+ connection = g_dbus_connection_new_for_address_finish(res, &error);
+ if (connection == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ g_dbus_proxy_new(connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ NULL, /* bus_name */
+ FWUPD_DBUS_PATH,
+ FWUPD_DBUS_INTERFACE,
+ cancellable,
+ fwupd_client_connect_get_proxy_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_connect_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Sets up the client ready for use. This is probably the first method you call
+ * when wanting to use libfwupd in an asynchronous manner.
+ *
+ * Other methods such as [method@FwupdClient.get_devices_async] should only be called
+ * after [method@FwupdClient.connect_finish] has been called without an error.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_connect_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ const gchar *socket_filename = g_getenv("FWUPD_DBUS_SOCKET");
+ g_autofree gchar *socket_address = NULL;
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->proxy_mutex);
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+
+ g_assert(locker != NULL);
+
+ /* nothing to do */
+ if (priv->proxy != NULL) {
+ g_task_return_boolean(task, TRUE);
+ return;
+ }
+
+ /* convert from filename to address, if required */
+ if (socket_filename != NULL) {
+ if (g_strrstr(socket_filename, "=") == NULL) {
+ socket_address = g_strdup_printf("unix:path=%s", socket_filename);
+ } else {
+ socket_address = g_strdup(socket_filename);
+ }
+ } else {
+#ifdef _WIN32
+ socket_address = g_strdup(FWUPD_DBUS_P2P_SOCKET_ADDRESS);
+#endif
+ }
+
+ /* use peer-to-peer only if the env variable is set */
+ if (socket_address != NULL) {
+ g_dbus_connection_new_for_address(socket_address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL,
+ cancellable,
+ fwupd_client_connect_get_connection_cb,
+ g_steal_pointer(&task));
+ return;
+ }
+
+ /* typical case */
+ g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ FWUPD_DBUS_SERVICE,
+ FWUPD_DBUS_PATH,
+ FWUPD_DBUS_INTERFACE,
+ cancellable,
+ fwupd_client_connect_get_proxy_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_connect_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@Client.connect_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_connect_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+/**
+ * fwupd_client_disconnect: (skip)
+ * @self: a #FwupdClient
+ * @error: (nullable): optional return location for an error
+ *
+ * Tears down client after use. You only need to call this method if you are:
+ *
+ * - connecting to the daemon in one thread and finalizing the client in another one
+ * - to change the `FWUPD_DBUS_SOCKET` for a different peer-to-peer connection
+ * - to add or change connection hints as specified by [method@FwupdClient.add_hint].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.0
+ **/
+gboolean
+fwupd_client_disconnect(FwupdClient *self, GError **error)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->proxy_mutex);
+
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ g_assert(locker != NULL);
+
+ /* sanity check */
+ if (priv->proxy == NULL) {
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "not connected");
+ return FALSE;
+ }
+ g_signal_handlers_disconnect_by_data(priv->proxy, self);
+ g_clear_object(&priv->proxy);
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fwupd_client_fixup_dbus_error(GError *error)
+{
+ g_autofree gchar *name = NULL;
+
+ g_return_if_fail(error != NULL);
+
+ /* is a remote error? */
+ if (!g_dbus_error_is_remote_error(error))
+ return;
+
+ /* parse the remote error */
+ name = g_dbus_error_get_remote_error(error);
+ if (g_str_has_prefix(name, FWUPD_DBUS_INTERFACE)) {
+ error->domain = FWUPD_ERROR;
+ error->code = fwupd_error_from_string(name);
+ } else if (g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
+ error->domain = FWUPD_ERROR;
+ error->code = FWUPD_ERROR_NOT_SUPPORTED;
+ } else if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
+ error->domain = FWUPD_ERROR;
+ error->code = FWUPD_ERROR_NOT_SUPPORTED;
+ } else {
+ error->domain = FWUPD_ERROR;
+ error->code = FWUPD_ERROR_INTERNAL;
+ }
+ g_dbus_error_strip_remote_error(error);
+}
+
+static void
+fwupd_client_get_host_security_attrs_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_security_attr_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_host_security_attrs_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the host security attributes from the daemon.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_host_security_attrs_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetHostSecurityAttrs",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_host_security_attrs_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_host_security_attrs_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_host_security_attrs_async].
+ *
+ * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_host_security_attrs_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_modify_bios_setting_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_modify_bios_setting_async:
+ * @self: a #FwupdClient
+ * @settings: (transfer container): BIOS settings
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Modifies a BIOS setting using kernel API.
+ * The daemon will only respond to this request with proper permissions.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_client_modify_bios_setting_async(FwupdClient *self,
+ GHashTable *settings,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+ GHashTableIter iter;
+ gpointer key, value;
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(settings != NULL);
+ g_return_if_fail(g_hash_table_size(settings) > 0);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
+ g_hash_table_iter_init(&iter, settings);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (value == NULL)
+ continue;
+ g_variant_builder_add(&builder, "{ss}", (const gchar *)key, (const gchar *)value);
+ }
+ g_dbus_proxy_call(priv->proxy,
+ "SetBiosSettings",
+ g_variant_new("(a{ss})", &builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_modify_bios_setting_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_modify_bios_setting_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.modify_bios_setting_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fwupd_client_modify_bios_setting_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_bios_settings_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_bios_setting_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_bios_settings_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the host security attributes from the daemon.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_client_get_bios_settings_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetBiosSettings",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_bios_settings_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_bios_settings_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_bios_settings_async].
+ *
+ * Returns: (element-type FwupdBiosSetting) (transfer container): attributes
+ *
+ * Since: 1.8.4
+ **/
+GPtrArray *
+fwupd_client_get_bios_settings_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_host_security_events_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_security_attr_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_host_security_events_async:
+ * @self: a #FwupdClient
+ * @limit: maximum number of events, or 0 for no limit
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the host security events from the daemon.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.7.1
+ **/
+void
+fwupd_client_get_host_security_events_async(FwupdClient *self,
+ guint limit,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetHostSecurityEvents",
+ g_variant_new("(u)", limit),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_host_security_events_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_host_security_events_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_host_security_events_async].
+ *
+ * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes
+ *
+ * Since: 1.7.1
+ **/
+GPtrArray *
+fwupd_client_get_host_security_events_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static GHashTable *
+fwupd_report_metadata_hash_from_variant(GVariant *value)
+{
+ GHashTable *hash;
+ gsize sz;
+ g_autoptr(GVariant) untuple = NULL;
+
+ hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ 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 = NULL;
+ const gchar *key = NULL;
+ const gchar *val = NULL;
+ data = g_variant_get_child_value(untuple, i);
+ g_variant_get(data, "{&s&s}", &key, &val);
+ g_hash_table_insert(hash, g_strdup(key), g_strdup(val));
+ }
+ return hash;
+}
+
+static void
+fwupd_client_get_report_metadata_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_report_metadata_hash_from_variant(val),
+ (GDestroyNotify)g_hash_table_unref);
+}
+
+/**
+ * fwupd_client_get_report_metadata_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the report metadata from the daemon.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_report_metadata_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetReportMetadata",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_report_metadata_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_report_metadata_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_report_metadata_async].
+ *
+ * Returns: (transfer container): attributes
+ *
+ * Since: 1.5.0
+ **/
+GHashTable *
+fwupd_client_get_report_metadata_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_devices_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_device_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_devices_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the devices registered with the daemon.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_devices_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetDevices",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_devices_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_devices_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_devices_async].
+ *
+ * Returns: (element-type FwupdDevice) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_devices_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_plugins_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_plugin_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_plugins_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the plugins being used by the daemon.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_plugins_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetPlugins",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_plugins_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_plugins_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_plugins_async].
+ *
+ * Returns: (element-type FwupdDevice) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_plugins_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_history_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_device_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_history_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the history.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_history_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetHistory",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_history_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_history_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_history_async].
+ *
+ * Returns: (element-type FwupdDevice) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_history_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_device_by_id_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdDevice *device_result = NULL;
+ gsize device_id_len;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) devices = NULL;
+ const gchar *device_id = g_task_get_task_data(task);
+
+ devices = fwupd_client_get_devices_finish(FWUPD_CLIENT(source), res, &error);
+ if (devices == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* support abbreviated hashes (client side) */
+ device_id_len = strlen(device_id);
+ for (guint i = 0; i < devices->len; i++) {
+ FwupdDevice *dev = g_ptr_array_index(devices, i);
+ if (strncmp(fwupd_device_get_id(dev), device_id, device_id_len) == 0) {
+ if (device_result != NULL) {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_FOUND,
+ "more than one matching ID prefix '%s'",
+ device_id);
+ return;
+ }
+ device_result = dev;
+ }
+ }
+
+ /* one result */
+ if (device_result != NULL) {
+ g_task_return_pointer(task,
+ g_object_ref(device_result),
+ (GDestroyNotify)g_object_unref);
+ return;
+ }
+
+ /* failed */
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_FOUND,
+ "failed to find %s",
+ device_id);
+}
+
+/**
+ * fwupd_client_get_device_by_id_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets a device by it's device ID.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_device_by_id_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_set_task_data(task, g_strdup(device_id), g_free);
+ fwupd_client_get_devices_async(self,
+ cancellable,
+ fwupd_client_get_device_by_id_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_device_by_id_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_device_by_id_async].
+ *
+ * Returns: (transfer full): a device, or %NULL for failure
+ *
+ * Since: 1.5.0
+ **/
+FwupdDevice *
+fwupd_client_get_device_by_id_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_devices_by_guid_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) devices = NULL;
+ g_autoptr(GPtrArray) devices_tmp = NULL;
+ const gchar *guid = g_task_get_task_data(task);
+
+ /* get all the devices */
+ devices_tmp = fwupd_client_get_devices_finish(FWUPD_CLIENT(source), res, &error);
+ if (devices_tmp == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* find the devices by GUID (client side) */
+ devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ for (guint i = 0; i < devices_tmp->len; i++) {
+ FwupdDevice *dev_tmp = g_ptr_array_index(devices_tmp, i);
+ if (fwupd_device_has_guid(dev_tmp, guid))
+ g_ptr_array_add(devices, g_object_ref(dev_tmp));
+ }
+
+ /* nothing */
+ if (devices->len == 0) {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_FOUND,
+ "failed to find any device providing %s",
+ guid);
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task, g_steal_pointer(&devices), (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_devices_by_guid_async:
+ * @self: a #FwupdClient
+ * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63`
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets any devices that provide a specific GUID. An error is returned if no
+ * devices contains this GUID.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_devices_by_guid_async(FwupdClient *self,
+ const gchar *guid,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(guid != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_set_task_data(task, g_strdup(guid), g_free);
+ fwupd_client_get_devices_async(self,
+ cancellable,
+ fwupd_client_get_devices_by_guid_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_devices_by_guid_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_devices_by_guid_async].
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_devices_by_guid_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_releases_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_release_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_releases_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the releases for a specific device
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_releases_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetReleases",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_releases_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_releases_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_releases_async].
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_releases_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_downgrades_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_release_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_downgrades_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the downgrades for a specific device.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_downgrades_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetDowngrades",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_downgrades_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_downgrades_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_downgrades_async].
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_downgrades_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_upgrades_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_release_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_upgrades_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets all the upgrades for a specific device.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_upgrades_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetUpgrades",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_upgrades_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_upgrades_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_upgrades_async].
+ *
+ * Returns: (element-type FwupdRelease) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_upgrades_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_modify_config_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_modify_config_async:
+ * @self: a #FwupdClient
+ * @key: config key, e.g. `DisabledPlugins`
+ * @value: config value, e.g. `*`
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Modifies a daemon config option.
+ * The daemon will only respond to this request with proper permissions.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_modify_config_async(FwupdClient *self,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(value != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "ModifyConfig",
+ g_variant_new("(ss)", key, value),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_modify_config_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_modify_config_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.modify_config_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_modify_config_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_activate_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_activate_async:
+ * @self: a #FwupdClient
+ * @device_id: a device
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * 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.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_activate_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "Activate",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_activate_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_activate_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.activate_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_activate_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_verify_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_verify_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Verify a specific device.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_verify_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "Verify",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_verify_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_verify_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.verify_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_verify_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_verify_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_verify_update_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Update the verification record for a specific device.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_verify_update_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "VerifyUpdate",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_verify_update_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_verify_update_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.verify_update_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_verify_update_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_unlock_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_unlock_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Unlocks a specific device so firmware can be read or wrote.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_unlock_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "Unlock",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_unlock_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_unlock_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.unlock_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_unlock_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_clear_results_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_clear_results_async:
+ * @self: a #FwupdClient
+ * @device_id: a device
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Clears the results for a specific device.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_clear_results_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "ClearResults",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_clear_results_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_clear_results_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.clear_results_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_clear_results_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_results_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_device_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_results_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets the results of a previous firmware update for a specific device.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_results_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetResults",
+ g_variant_new("(s)", device_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_results_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_results_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_results_async].
+ *
+ * Returns: (transfer full): a device, or %NULL for failure
+ *
+ * Since: 1.5.0
+ **/
+FwupdDevice *
+fwupd_client_get_results_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+#ifdef HAVE_GIO_UNIX
+
+static void
+fwupd_client_install_stream_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GDBusMessage) msg = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+
+ msg = g_dbus_connection_send_message_with_reply_finish(G_DBUS_CONNECTION(source),
+ res,
+ &error);
+ if (msg == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ if (g_dbus_message_to_gerror(msg, &error)) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+void
+fwupd_client_install_stream_async(FwupdClient *self,
+ const gchar *device_id,
+ GUnixInputStream *istr,
+ const gchar *filename_hint,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+ g_autoptr(GDBusMessage) request = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+
+ /* set options */
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&builder, "{sv}", "reason", g_variant_new_string("user-action"));
+ if (filename_hint != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "filename",
+ g_variant_new_string(filename_hint));
+ }
+ if (install_flags & FWUPD_INSTALL_FLAG_OFFLINE) {
+ g_variant_builder_add(&builder, "{sv}", "offline", g_variant_new_boolean(TRUE));
+ }
+ if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_OLDER) {
+ g_variant_builder_add(&builder, "{sv}", "allow-older", g_variant_new_boolean(TRUE));
+ }
+ if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "allow-reinstall",
+ g_variant_new_boolean(TRUE));
+ }
+ if (install_flags & FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "allow-branch-switch",
+ g_variant_new_boolean(TRUE));
+ }
+ if (install_flags & FWUPD_INSTALL_FLAG_FORCE) {
+ g_variant_builder_add(&builder, "{sv}", "force", g_variant_new_boolean(TRUE));
+ }
+ if (install_flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "ignore-power",
+ 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));
+ }
+
+ /* set out of band file descriptor */
+ fd_list = g_unix_fd_list_new();
+ g_unix_fd_list_append(fd_list, g_unix_input_stream_get_fd(istr), NULL);
+ request = g_dbus_message_new_method_call(FWUPD_DBUS_SERVICE,
+ FWUPD_DBUS_PATH,
+ FWUPD_DBUS_INTERFACE,
+ "Install");
+ g_dbus_message_set_unix_fd_list(request, fd_list);
+
+ /* call into daemon */
+ g_dbus_message_set_body(
+ request,
+ g_variant_new("(sha{sv})", device_id, g_unix_input_stream_get_fd(istr), &builder));
+ g_dbus_connection_send_message_with_reply(g_dbus_proxy_get_connection(priv->proxy),
+ request,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ cancellable,
+ fwupd_client_install_stream_cb,
+ g_steal_pointer(&task));
+}
+#endif
+
+/**
+ * fwupd_client_install_bytes_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @bytes: cabinet archive
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Install firmware onto a specific device.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_install_bytes_async(FwupdClient *self,
+ const gchar *device_id,
+ GBytes *bytes,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+#ifdef HAVE_GIO_UNIX
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GUnixInputStream) istr = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* move to a thread if this ever takes more than a few ms */
+ istr = fwupd_unix_input_stream_from_bytes(bytes, &error);
+ if (istr == NULL) {
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* call into daemon */
+ fwupd_client_install_stream_async(self,
+ device_id,
+ istr,
+ NULL,
+ install_flags,
+ cancellable,
+ callback,
+ callback_data);
+#else
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Install CAB only supported on Linux");
+#endif
+}
+
+/**
+ * fwupd_client_install_bytes_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.install_bytes_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_install_bytes_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+/**
+ * fwupd_client_install_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @filename: the filename to install
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Install firmware onto a specific device.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_install_async(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *filename,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+#ifdef HAVE_GIO_UNIX
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GUnixInputStream) istr = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(filename != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* move to a thread if this ever takes more than a few ms */
+ istr = fwupd_unix_input_stream_from_fn(filename, &error);
+ if (istr == NULL) {
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* call into daemon */
+ fwupd_client_install_stream_async(self,
+ device_id,
+ istr,
+ NULL,
+ install_flags,
+ cancellable,
+ callback,
+ callback_data);
+#else
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Install CAB async only supported on Linux");
+#endif
+}
+
+/**
+ * fwupd_client_install_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.install_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_install_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+typedef struct {
+ FwupdDevice *device;
+ FwupdRelease *release;
+ FwupdInstallFlags install_flags;
+ FwupdClientDownloadFlags download_flags;
+} FwupdClientInstallReleaseData;
+
+static void
+fwupd_client_install_release_data_free(FwupdClientInstallReleaseData *data)
+{
+ g_object_unref(data->device);
+ g_object_unref(data->release);
+ g_free(data);
+}
+
+static void
+fwupd_client_install_release_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+
+ if (!fwupd_client_install_release_finish(FWUPD_CLIENT(source), res, &error)) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+static void
+fwupd_client_install_release_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+
+ if (!fwupd_client_install_bytes_finish(FWUPD_CLIENT(source), res, &error)) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+static void
+fwupd_client_install_release_download_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GBytes) blob = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ FwupdClientInstallReleaseData *data = g_task_get_task_data(task);
+ GChecksumType checksum_type;
+ GCancellable *cancellable = g_task_get_cancellable(task);
+ const gchar *checksum_expected;
+ g_autofree gchar *checksum_actual = NULL;
+
+ blob = fwupd_client_download_bytes_finish(FWUPD_CLIENT(source), res, &error);
+ if (blob == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* verify checksum */
+ checksum_expected = fwupd_checksum_get_best(fwupd_release_get_checksums(data->release));
+ checksum_type = fwupd_checksum_guess_kind(checksum_expected);
+ checksum_actual = g_compute_checksum_for_bytes(checksum_type, blob);
+ if (g_strcmp0(checksum_expected, checksum_actual) != 0) {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "checksum invalid, expected %s got %s",
+ checksum_expected,
+ checksum_actual);
+ return;
+ }
+
+ /* if the device specifies ONLY_OFFLINE automatically set this flag */
+ if (fwupd_device_has_flag(data->device, FWUPD_DEVICE_FLAG_ONLY_OFFLINE))
+ data->install_flags |= FWUPD_INSTALL_FLAG_OFFLINE;
+ fwupd_client_install_bytes_async(FWUPD_CLIENT(source),
+ fwupd_device_get_id(data->device),
+ blob,
+ data->install_flags,
+ cancellable,
+ fwupd_client_install_release_bytes_cb,
+ g_steal_pointer(&task));
+}
+
+static gboolean
+fwupd_client_is_url_http(const gchar *perhaps_url)
+{
+#ifdef HAVE_LIBCURL_7_62_0
+ g_autoptr(CURLU) h = curl_url();
+ return curl_url_set(h, CURLUPART_URL, perhaps_url, 0) == CURLUE_OK;
+#else
+ return g_str_has_prefix(perhaps_url, "http://") ||
+ g_str_has_prefix(perhaps_url, "https://");
+#endif
+}
+
+static gboolean
+fwupd_client_is_url_ipfs(const gchar *perhaps_url)
+{
+ return g_str_has_prefix(perhaps_url, "ipfs://") || g_str_has_prefix(perhaps_url, "ipns://");
+}
+
+static void
+fwupd_client_install_release_remote_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ GPtrArray *locations;
+ const gchar *uri_tmp;
+ g_autofree gchar *fn = NULL;
+ g_autoptr(FwupdRemote) remote = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GPtrArray) uris_built = g_ptr_array_new_with_free_func(g_free);
+ FwupdClientInstallReleaseData *data = g_task_get_task_data(task);
+ GCancellable *cancellable = g_task_get_cancellable(task);
+
+ /* if a remote-id was specified, the remote has to exist */
+ remote = fwupd_client_get_remote_by_id_finish(FWUPD_CLIENT(source), res, &error);
+ if (remote == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* get the default release only until other parts of fwupd can cope */
+ locations = fwupd_release_get_locations(data->release);
+ if (locations->len == 0) {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "release missing URI");
+ return;
+ }
+ uri_tmp = g_ptr_array_index(locations, 0);
+
+ /* local and directory remotes may have the firmware already */
+ if (fwupd_remote_get_kind(remote) == FWUPD_REMOTE_KIND_LOCAL &&
+ !fwupd_client_is_url_http(uri_tmp)) {
+ const gchar *fn_cache = fwupd_remote_get_filename_cache(remote);
+ g_autofree gchar *path = g_path_get_dirname(fn_cache);
+ 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) {
+ fwupd_client_install_async(FWUPD_CLIENT(source),
+ fwupd_device_get_id(data->device),
+ fn,
+ data->install_flags,
+ cancellable,
+ fwupd_client_install_release_cb,
+ g_steal_pointer(&task));
+ return;
+ }
+
+ /* remote file */
+ for (guint i = 0; i < locations->len; i++) {
+ uri_tmp = g_ptr_array_index(locations, i);
+ if (fwupd_client_is_url_ipfs(uri_tmp)) {
+ g_ptr_array_add(uris_built, g_strdup(uri_tmp));
+ } else if (fwupd_client_is_url_http(uri_tmp)) {
+ g_autofree gchar *uri_str = NULL;
+ uri_str = fwupd_remote_build_firmware_uri(remote, uri_tmp, &error);
+ if (uri_str == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ g_ptr_array_add(uris_built, g_steal_pointer(&uri_str));
+ }
+ }
+
+ /* download file */
+ fwupd_client_download_bytes2_async(FWUPD_CLIENT(source),
+ uris_built,
+ data->download_flags,
+ cancellable,
+ fwupd_client_install_release_download_cb,
+ g_steal_pointer(&task));
+}
+
+#ifdef HAVE_LIBCURL
+static GPtrArray *
+fwupd_client_filter_locations(GPtrArray *locations,
+ FwupdClientDownloadFlags download_flags,
+ GError **error)
+{
+ g_autoptr(GPtrArray) uris_filtered = g_ptr_array_new_with_free_func(g_free);
+
+ g_return_val_if_fail(locations != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ for (guint i = 0; i < locations->len; i++) {
+ const gchar *uri = g_ptr_array_index(locations, i);
+ if ((download_flags & FWUPD_CLIENT_DOWNLOAD_FLAG_ONLY_IPFS) > 0 &&
+ !fwupd_client_is_url_ipfs(uri))
+ continue;
+ g_ptr_array_add(uris_filtered, g_strdup(uri));
+ }
+ if (uris_filtered->len == 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no valid release URIs");
+ return NULL;
+ }
+ return g_steal_pointer(&uris_filtered);
+}
+#endif
+
+/**
+ * fwupd_client_install_release2_async:
+ * @self: a #FwupdClient
+ * @device: a device
+ * @release: a release
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @download_flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_DISABLE_IPFS
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Installs a new release on a device, downloading the firmware if required.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.6
+ **/
+void
+fwupd_client_install_release2_async(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ FwupdClientDownloadFlags download_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+ FwupdClientInstallReleaseData *data;
+ const gchar *remote_id;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(FWUPD_IS_DEVICE(device));
+ g_return_if_fail(FWUPD_IS_RELEASE(release));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ data = g_new0(FwupdClientInstallReleaseData, 1);
+ data->device = g_object_ref(device);
+ data->release = g_object_ref(release);
+ data->download_flags = download_flags;
+ data->install_flags = install_flags;
+ g_task_set_task_data(task, data, (GDestroyNotify)fwupd_client_install_release_data_free);
+
+ /* work out what remote-specific URI fields this should use */
+ remote_id = fwupd_release_get_remote_id(release);
+ if (remote_id == NULL) {
+ fwupd_client_download_bytes2_async(self,
+ fwupd_release_get_locations(release),
+ download_flags,
+ cancellable,
+ fwupd_client_install_release_download_cb,
+ g_steal_pointer(&task));
+ return;
+ }
+
+ /* if a remote-id was specified, the remote has to exist */
+ fwupd_client_get_remote_by_id_async(self,
+ remote_id,
+ cancellable,
+ fwupd_client_install_release_remote_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_install_release_async:
+ * @self: a #FwupdClient
+ * @device: a device
+ * @release: a release
+ * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Installs a new release on a device, downloading the firmware if required.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ * Deprecated: 1.5.6
+ **/
+void
+fwupd_client_install_release_async(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ return fwupd_client_install_release2_async(self,
+ device,
+ release,
+ install_flags,
+ FWUPD_CLIENT_DOWNLOAD_FLAG_NONE,
+ cancellable,
+ callback,
+ callback_data);
+}
+
+/**
+ * fwupd_client_install_release_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.install_release_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_install_release_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+#ifdef HAVE_GIO_UNIX
+
+static void
+fwupd_client_get_details_stream_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GDBusMessage) msg = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+
+ msg = g_dbus_connection_send_message_with_reply_finish(G_DBUS_CONNECTION(source),
+ res,
+ &error);
+ if (msg == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ if (g_dbus_message_to_gerror(msg, &error)) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_device_array_from_variant(g_dbus_message_get_body(msg)),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+void
+fwupd_client_get_details_stream_async(FwupdClient *self,
+ GUnixInputStream *istr,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ gint fd = g_unix_input_stream_get_fd(istr);
+ g_autoptr(GDBusMessage) request = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+
+ /* set out of band file descriptor */
+ fd_list = g_unix_fd_list_new();
+ g_unix_fd_list_append(fd_list, fd, NULL);
+ request = g_dbus_message_new_method_call(FWUPD_DBUS_SERVICE,
+ FWUPD_DBUS_PATH,
+ FWUPD_DBUS_INTERFACE,
+ "GetDetails");
+ g_dbus_message_set_unix_fd_list(request, fd_list);
+
+ /* call into daemon */
+ g_dbus_message_set_body(request, g_variant_new("(h)", fd));
+ g_dbus_connection_send_message_with_reply(g_dbus_proxy_get_connection(priv->proxy),
+ request,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ cancellable,
+ fwupd_client_get_details_stream_cb,
+ g_steal_pointer(&task));
+}
+#endif
+
+/**
+ * fwupd_client_get_details_bytes_async:
+ * @self: a #FwupdClient
+ * @bytes: firmware archive
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets details about a specific firmware file.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_details_bytes_async(FwupdClient *self,
+ GBytes *bytes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+#ifdef HAVE_GIO_UNIX
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GUnixInputStream) istr = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* move to a thread if this ever takes more than a few ms */
+ istr = fwupd_unix_input_stream_from_bytes(bytes, &error);
+ if (istr == NULL) {
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* call into daemon */
+ fwupd_client_get_details_stream_async(self, istr, cancellable, callback, callback_data);
+#else
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Get Details only supported on Linux");
+#endif
+}
+
+/**
+ * fwupd_client_get_details_bytes_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_details_bytes_async].
+ *
+ * Returns: (transfer container) (element-type FwupdDevice): an array of results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_details_bytes_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+/**
+ * fwupd_client_get_percentage:
+ * @self: a #FwupdClient
+ *
+ * Gets the last returned percentage value.
+ *
+ * Returns: a percentage, or 0 for unknown.
+ *
+ * Since: 0.7.3
+ **/
+guint
+fwupd_client_get_percentage(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), 0);
+ return priv->percentage;
+}
+
+/**
+ * fwupd_client_get_daemon_version:
+ * @self: a #FwupdClient
+ *
+ * Gets the daemon version number.
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 0.9.6
+ **/
+const gchar *
+fwupd_client_get_daemon_version(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->daemon_version;
+}
+
+/**
+ * fwupd_client_get_host_bkc:
+ * @self: a #FwupdClient
+ *
+ * Gets the daemon version number.
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 1.7.3
+ **/
+const gchar *
+fwupd_client_get_host_bkc(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->host_bkc;
+}
+
+/**
+ * fwupd_client_get_host_product:
+ * @self: a #FwupdClient
+ *
+ * Gets the string that represents the host running fwupd
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 1.3.1
+ **/
+const gchar *
+fwupd_client_get_host_product(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->host_product;
+}
+
+/**
+ * fwupd_client_get_host_vendor:
+ * @self: a #FwupdClient
+ *
+ * Gets the string that represents the vendor of the host running fwupd
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 1.8.2
+ **/
+const gchar *
+fwupd_client_get_host_vendor(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->host_vendor;
+}
+
+/**
+ * fwupd_client_get_host_machine_id:
+ * @self: a #FwupdClient
+ *
+ * Gets the string that represents the host machine ID
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 1.3.2
+ **/
+const gchar *
+fwupd_client_get_host_machine_id(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->host_machine_id;
+}
+
+/**
+ * fwupd_client_get_host_security_id:
+ * @self: a #FwupdClient
+ *
+ * Gets the string that represents the host machine ID
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_client_get_host_security_id(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->host_security_id;
+}
+
+/**
+ * fwupd_client_get_battery_level:
+ * @self: a #FwupdClient
+ *
+ * Returns the system battery level.
+ *
+ * Returns: value in percent
+ *
+ * Since: 1.8.1
+ **/
+guint32
+fwupd_client_get_battery_level(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FWUPD_BATTERY_LEVEL_INVALID);
+ return priv->battery_level;
+}
+
+/**
+ * fwupd_client_get_battery_threshold:
+ * @self: a #FwupdClient
+ *
+ * Returns the system battery threshold under which a firmware update cannot be
+ * performed.
+ *
+ * Returns: value in percent
+ *
+ * Since: 1.8.1
+ **/
+guint32
+fwupd_client_get_battery_threshold(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FWUPD_BATTERY_LEVEL_INVALID);
+ return priv->battery_threshold;
+}
+
+/**
+ * fwupd_client_get_status:
+ * @self: a #FwupdClient
+ *
+ * Gets the last returned status value.
+ *
+ * Returns: a #FwupdStatus, or %FWUPD_STATUS_UNKNOWN for unknown.
+ *
+ * Since: 0.7.3
+ **/
+FwupdStatus
+fwupd_client_get_status(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FWUPD_STATUS_UNKNOWN);
+ return priv->status;
+}
+
+/**
+ * fwupd_client_get_tainted:
+ * @self: 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 *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ return priv->tainted;
+}
+
+/**
+ * fwupd_client_get_only_trusted:
+ * @self: a #FwupdClient
+ *
+ * Gets if the daemon is verifying signatures from a trusted authority.
+ *
+ * Returns: %TRUE if the daemon is checking signatures
+ *
+ * Since: 1.8.0
+ **/
+gboolean
+fwupd_client_get_only_trusted(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ return priv->only_trusted;
+}
+
+/**
+ * fwupd_client_get_daemon_interactive:
+ * @self: a #FwupdClient
+ *
+ * Gets if the daemon is running in an interactive terminal.
+ *
+ * Returns: %TRUE if the daemon is running in an interactive terminal
+ *
+ * Since: 1.3.4
+ **/
+gboolean
+fwupd_client_get_daemon_interactive(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ return priv->interactive;
+}
+
+#ifdef HAVE_GIO_UNIX
+
+static void
+fwupd_client_update_metadata_stream_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GDBusMessage) msg = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+
+ msg = g_dbus_connection_send_message_with_reply_finish(G_DBUS_CONNECTION(source),
+ res,
+ &error);
+ if (msg == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ if (g_dbus_message_to_gerror(msg, &error)) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+void
+fwupd_client_update_metadata_stream_async(FwupdClient *self,
+ const gchar *remote_id,
+ GUnixInputStream *istr,
+ GUnixInputStream *istr_sig,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GDBusMessage) request = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+
+ /* set out of band file descriptor */
+ fd_list = g_unix_fd_list_new();
+ g_unix_fd_list_append(fd_list, g_unix_input_stream_get_fd(istr), NULL);
+ g_unix_fd_list_append(fd_list, g_unix_input_stream_get_fd(istr_sig), NULL);
+ request = g_dbus_message_new_method_call(FWUPD_DBUS_SERVICE,
+ FWUPD_DBUS_PATH,
+ FWUPD_DBUS_INTERFACE,
+ "UpdateMetadata");
+ g_dbus_message_set_unix_fd_list(request, fd_list);
+
+ /* call into daemon */
+ g_dbus_message_set_body(request,
+ g_variant_new("(shh)",
+ remote_id,
+ g_unix_input_stream_get_fd(istr),
+ g_unix_input_stream_get_fd(istr_sig)));
+ g_dbus_connection_send_message_with_reply(g_dbus_proxy_get_connection(priv->proxy),
+ request,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ G_MAXINT,
+ NULL,
+ cancellable,
+ fwupd_client_update_metadata_stream_cb,
+ g_steal_pointer(&task));
+}
+#endif
+
+/**
+ * fwupd_client_update_metadata_bytes_async:
+ * @self: a #FwupdClient
+ * @remote_id: remote ID, e.g. `lvfs-testing`
+ * @metadata: XML metadata data
+ * @signature: signature data
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Updates the metadata. This allows a session process to download the metadata
+ * and metadata signing file to be passed into the daemon to be checked and
+ * parsed.
+ *
+ * The @remote_id allows the firmware to be tagged so that the remote can be
+ * matched when the firmware is downloaded.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_update_metadata_bytes_async(FwupdClient *self,
+ const gchar *remote_id,
+ GBytes *metadata,
+ GBytes *signature,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+#ifdef HAVE_GIO_UNIX
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GUnixInputStream) istr = NULL;
+ g_autoptr(GUnixInputStream) istr_sig = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(remote_id != NULL);
+ g_return_if_fail(metadata != NULL);
+ g_return_if_fail(signature != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* move to a thread if this ever takes more than a few ms */
+ istr = fwupd_unix_input_stream_from_bytes(metadata, &error);
+ if (istr == NULL) {
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ istr_sig = fwupd_unix_input_stream_from_bytes(signature, &error);
+ if (istr_sig == NULL) {
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* call into daemon */
+ fwupd_client_update_metadata_stream_async(self,
+ remote_id,
+ istr,
+ istr_sig,
+ cancellable,
+ callback,
+ callback_data);
+#else
+ g_autoptr(GTask) task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Update metadata only supported on Linux");
+#endif
+}
+
+/**
+ * fwupd_client_update_metadata_bytes_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.update_metadata_bytes_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_update_metadata_bytes_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+typedef struct {
+ FwupdRemote *remote;
+ GBytes *signature;
+ GBytes *metadata;
+} FwupdClientRefreshRemoteData;
+
+static void
+fwupd_client_refresh_remote_data_free(FwupdClientRefreshRemoteData *data)
+{
+ if (data->signature != NULL)
+ g_bytes_unref(data->signature);
+ if (data->metadata != NULL)
+ g_bytes_unref(data->metadata);
+ g_object_unref(data->remote);
+ g_free(data);
+}
+
+static void
+fwupd_client_refresh_remote_update_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+
+ /* save metadata */
+ if (!fwupd_client_update_metadata_bytes_finish(FWUPD_CLIENT(source), res, &error)) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+static void
+fwupd_client_refresh_remote_metadata_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ FwupdClientRefreshRemoteData *data = g_task_get_task_data(task);
+ FwupdClient *self = g_task_get_source_object(task);
+ GCancellable *cancellable = g_task_get_cancellable(task);
+
+ /* save metadata */
+ bytes = fwupd_client_download_bytes_finish(FWUPD_CLIENT(source), res, &error);
+ if (bytes == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ data->metadata = g_steal_pointer(&bytes);
+
+ /* send all this to fwupd */
+ fwupd_client_update_metadata_bytes_async(self,
+ fwupd_remote_get_id(data->remote),
+ data->metadata,
+ data->signature,
+ cancellable,
+ fwupd_client_refresh_remote_update_cb,
+ g_steal_pointer(&task));
+}
+
+static void
+fwupd_client_refresh_remote_signature_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ FwupdClientRefreshRemoteData *data = g_task_get_task_data(task);
+ FwupdClient *self = g_task_get_source_object(task);
+ GCancellable *cancellable = g_task_get_cancellable(task);
+ GChecksumType checksum_kind;
+ g_autofree gchar *checksum = NULL;
+
+ /* save signature */
+ bytes = fwupd_client_download_bytes_finish(FWUPD_CLIENT(source), res, &error);
+ if (bytes == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ data->signature = g_steal_pointer(&bytes);
+ if (fwupd_remote_get_keyring_kind(data->remote) == FWUPD_KEYRING_KIND_JCAT) {
+ if (!fwupd_remote_load_signature_bytes(data->remote, data->signature, &error)) {
+ g_prefix_error(&error, "Failed to load signature: ");
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ }
+
+ /* is the signature checksum the same? */
+ checksum_kind = fwupd_checksum_guess_kind(fwupd_remote_get_checksum(data->remote));
+ checksum =
+ g_compute_checksum_for_data(checksum_kind,
+ (const guchar *)g_bytes_get_data(data->signature, NULL),
+ g_bytes_get_size(data->signature));
+ if (g_strcmp0(checksum, fwupd_remote_get_checksum(data->remote)) == 0) {
+ g_debug("metadata signature of %s is unchanged, skipping",
+ fwupd_remote_get_id(data->remote));
+ g_task_return_boolean(task, TRUE);
+ return;
+ }
+
+ /* download metadata */
+ fwupd_client_download_bytes_async(self,
+ fwupd_remote_get_metadata_uri(data->remote),
+ FWUPD_CLIENT_DOWNLOAD_FLAG_NONE,
+ cancellable,
+ fwupd_client_refresh_remote_metadata_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_refresh_remote_async:
+ * @self: a #FwupdClient
+ * @remote: a #FwupdRemote
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Refreshes a remote by downloading new metadata.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_refresh_remote_async(FwupdClient *self,
+ FwupdRemote *remote,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientRefreshRemoteData *data;
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(FWUPD_IS_REMOTE(remote));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+
+ task = g_task_new(self, cancellable, callback, callback_data);
+ data = g_new0(FwupdClientRefreshRemoteData, 1);
+ data->remote = g_object_ref(remote);
+ g_task_set_task_data(task,
+ g_steal_pointer(&data),
+ (GDestroyNotify)fwupd_client_refresh_remote_data_free);
+
+ /* sanity check */
+ if (fwupd_remote_get_metadata_uri_sig(remote) == NULL ||
+ fwupd_remote_get_metadata_uri(remote) == NULL) {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "no metadata URIs for %s",
+ fwupd_remote_get_id(remote));
+ return;
+ }
+
+ /* download signature */
+ fwupd_client_download_bytes_async(self,
+ fwupd_remote_get_metadata_uri_sig(remote),
+ FWUPD_CLIENT_DOWNLOAD_FLAG_NONE,
+ cancellable,
+ fwupd_client_refresh_remote_signature_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_refresh_remote_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.refresh_remote_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_refresh_remote_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_remotes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task,
+ fwupd_remote_array_from_variant(val),
+ (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_remotes_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets the list of remotes that have been configured for the system.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_remotes_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetRemotes",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_remotes_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_remotes_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_remotes_async].
+ *
+ * Returns: (element-type FwupdRemote) (transfer container): results
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_remotes_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_approved_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_auto(GStrv) strv = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free);
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ g_variant_get(val, "(^as)", &strv);
+ for (guint i = 0; strv[i] != NULL; i++)
+ g_ptr_array_add(array, g_strdup(strv[i]));
+
+ /* success */
+ g_task_return_pointer(task, g_steal_pointer(&array), (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_approved_firmware_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets the list of approved firmware.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_approved_firmware_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetApprovedFirmware",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_approved_firmware_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_approved_firmware_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_approved_firmware_async].
+ *
+ * Returns: (element-type utf8) (transfer container): checksums, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_approved_firmware_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_set_approved_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_set_approved_firmware_async:
+ * @self: a #FwupdClient
+ * @checksums: (element-type utf8): firmware checksums
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Sets the list of approved firmware.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_set_approved_firmware_async(FwupdClient *self,
+ GPtrArray *checksums,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+ g_auto(GStrv) strv = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ strv = g_new0(gchar *, checksums->len + 1);
+ for (guint i = 0; i < checksums->len; i++) {
+ const gchar *tmp = g_ptr_array_index(checksums, i);
+ strv[i] = g_strdup(tmp);
+ }
+ g_dbus_proxy_call(priv->proxy,
+ "SetApprovedFirmware",
+ g_variant_new("(^as)", strv),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_set_approved_firmware_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_set_approved_firmware_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.set_approved_firmware_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_set_approved_firmware_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_get_blocked_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_auto(GStrv) strv = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free);
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ g_variant_get(val, "(^as)", &strv);
+ for (guint i = 0; strv[i] != NULL; i++)
+ g_ptr_array_add(array, g_strdup(strv[i]));
+
+ /* success */
+ g_task_return_pointer(task, g_steal_pointer(&array), (GDestroyNotify)g_ptr_array_unref);
+}
+
+/**
+ * fwupd_client_get_blocked_firmware_async:
+ * @self: a #FwupdClient
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets the list of blocked firmware.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_blocked_firmware_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "GetBlockedFirmware",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_get_blocked_firmware_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_blocked_firmware_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_blocked_firmware_async].
+ *
+ * Returns: (element-type utf8) (transfer container): checksums, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_client_get_blocked_firmware_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_set_blocked_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_set_blocked_firmware_async:
+ * @self: a #FwupdClient
+ * @checksums: (element-type utf8): firmware checksums
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Sets the list of blocked firmware.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_set_blocked_firmware_async(FwupdClient *self,
+ GPtrArray *checksums,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+ g_auto(GStrv) strv = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ strv = g_new0(gchar *, checksums->len + 1);
+ for (guint i = 0; i < checksums->len; i++) {
+ const gchar *tmp = g_ptr_array_index(checksums, i);
+ strv[i] = g_strdup(tmp);
+ }
+ g_dbus_proxy_call(priv->proxy,
+ "SetBlockedFirmware",
+ g_variant_new("(^as)", strv),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_set_blocked_firmware_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_set_blocked_firmware_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.set_blocked_firmware_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_set_blocked_firmware_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_set_feature_flags_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_set_feature_flags_async:
+ * @self: a #FwupdClient
+ * @feature_flags: feature flags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Sets the features the client supports. This allows firmware to depend on
+ * specific front-end features, for instance showing the user an image on
+ * how to detach the hardware.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_set_feature_flags_async(FwupdClient *self,
+ FwupdFeatureFlags feature_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "SetFeatureFlags",
+ g_variant_new("(t)", (guint64)feature_flags),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_set_feature_flags_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_set_feature_flags_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.set_feature_flags_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_set_feature_flags_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_self_sign_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ gchar *str = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_variant_get(val, "(s)", &str);
+ g_task_return_pointer(task, g_steal_pointer(&str), (GDestroyNotify)g_free);
+}
+
+/**
+ * fwupd_client_self_sign_async:
+ * @self: a #FwupdClient
+ * @value: a string to sign, typically a JSON blob
+ * @flags: signing flags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Signs the data using the client self-signed certificate.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_self_sign_async(FwupdClient *self,
+ const gchar *value,
+ FwupdSelfSignFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(value != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != 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 */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "SelfSign",
+ g_variant_new("(sa{sv})", value, &builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_self_sign_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_self_sign_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.self_sign_async].
+ *
+ * Returns: a signature, or %NULL for failure
+ *
+ * Since: 1.5.0
+ **/
+gchar *
+fwupd_client_self_sign_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+static void
+fwupd_client_modify_remote_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_modify_remote_async:
+ * @self: a #FwupdClient
+ * @remote_id: the remote ID, e.g. `lvfs-testing`
+ * @key: the key, e.g. `Enabled`
+ * @value: the key, e.g. `true`
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Modifies a system remote in a specific way.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_modify_remote_async(FwupdClient *self,
+ const gchar *remote_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(remote_id != NULL);
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(value != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "ModifyRemote",
+ g_variant_new("(sss)", remote_id, key, value),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_modify_remote_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_modify_remote_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.modify_remote_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_modify_remote_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static void
+fwupd_client_modify_device_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ val = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
+ if (val == NULL) {
+ fwupd_client_fixup_dbus_error(error);
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* success */
+ g_task_return_boolean(task, TRUE);
+}
+
+/**
+ * fwupd_client_modify_device_async:
+ * @self: a #FwupdClient
+ * @device_id: (not nullable): the device ID
+ * @key: (not nullable): the key, e.g. `Flags`
+ * @value: (not nullable): the value, e.g. `reported`
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Modifies a device in a specific way. Not all properties on the #FwupdDevice
+ * are settable by the client, and some may have other restrictions on @value.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_modify_device_async(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(device_id != NULL);
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(value != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_dbus_proxy_call(priv->proxy,
+ "ModifyDevice",
+ g_variant_new("(sss)", device_id, key, value),
+ G_DBUS_CALL_FLAGS_NONE,
+ FWUPD_CLIENT_DBUS_PROXY_TIMEOUT,
+ cancellable,
+ fwupd_client_modify_device_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_modify_device_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.modify_device_async].
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_client_modify_device_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE);
+ g_return_val_if_fail(g_task_is_valid(res, self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return g_task_propagate_boolean(G_TASK(res), error);
+}
+
+static FwupdRemote *
+fwupd_client_get_remote_by_id_noref(GPtrArray *remotes, const gchar *remote_id)
+{
+ 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;
+ }
+ return NULL;
+}
+
+static void
+fwupd_client_get_remote_by_id_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ FwupdRemote *remote_tmp;
+ g_autoptr(GTask) task = G_TASK(user_data);
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) remotes = NULL;
+ const gchar *remote_id = g_task_get_task_data(task);
+
+ remotes = fwupd_client_get_remotes_finish(FWUPD_CLIENT(source), res, &error);
+ if (remotes == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ remote_tmp = fwupd_client_get_remote_by_id_noref(remotes, remote_id);
+ if (remote_tmp == NULL) {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_FOUND,
+ "no remote '%s' found in search paths",
+ remote_id);
+ return;
+ }
+
+ /* success */
+ g_task_return_pointer(task, g_object_ref(remote_tmp), (GDestroyNotify)g_object_unref);
+}
+
+/**
+ * fwupd_client_get_remote_by_id_async:
+ * @self: a #FwupdClient
+ * @remote_id: (not nullable): the remote ID, e.g. `lvfs-testing`
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Gets a specific remote that has been configured for the system.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_get_remote_by_id_async(FwupdClient *self,
+ const gchar *remote_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(remote_id != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* call into daemon */
+ task = g_task_new(self, cancellable, callback, callback_data);
+ g_task_set_task_data(task, g_strdup(remote_id), g_free);
+ fwupd_client_get_remotes_async(self,
+ cancellable,
+ fwupd_client_get_remote_by_id_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_client_get_remote_by_id_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.get_remote_by_id_async].
+ *
+ * Returns: (transfer full): a #FwupdRemote, or %NULL if not found
+ *
+ * Since: 1.5.0
+ **/
+FwupdRemote *
+fwupd_client_get_remote_by_id_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+/**
+ * fwupd_client_set_user_agent:
+ * @self: a #FwupdClient
+ * @user_agent: the user agent ID, e.g. `gnome-software/3.34.1`
+ *
+ * Manually sets the user agent that is used for downloading. The user agent
+ * should contain the runtime version of fwupd somewhere in the provided string.
+ *
+ * Since: 1.4.5
+ **/
+void
+fwupd_client_set_user_agent(FwupdClient *self, const gchar *user_agent)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(user_agent != NULL);
+
+ /* not changed */
+ if (g_strcmp0(priv->user_agent, user_agent) == 0)
+ return;
+
+ g_free(priv->user_agent);
+ priv->user_agent = g_strdup(user_agent);
+}
+
+/**
+ * fwupd_client_get_user_agent:
+ * @self: a #FwupdClient
+ *
+ * Gets the string that represents the user agent that is used for
+ * uploading and downloading. The user agent will contain the runtime
+ * version of fwupd somewhere in the provided string.
+ *
+ * Returns: a string, or %NULL for unknown.
+ *
+ * Since: 1.5.2
+ **/
+const gchar *
+fwupd_client_get_user_agent(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ return priv->user_agent;
+}
+
+/**
+ * fwupd_client_set_user_agent_for_package:
+ * @self: a #FwupdClient
+ * @package_name: (not nullable): client program name, e.g. `gnome-software`
+ * @package_version: (not nullable): client program version, e.g. `3.28.1`
+ *
+ * Builds a user-agent to use for the download.
+ *
+ * Supplying harmless details to the server means it knows more about each
+ * client. This allows the web service to respond in a different way, for
+ * instance sending a different metadata file for old versions of fwupd, or
+ * returning an error for Solaris machines.
+ *
+ * Before freaking out about theoretical privacy implications, much more data
+ * than this is sent to each and every website you visit.
+ *
+ * Since: 1.4.5
+ **/
+void
+fwupd_client_set_user_agent_for_package(FwupdClient *self,
+ const gchar *package_name,
+ const gchar *package_version)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_autofree gchar *system = NULL;
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(package_name != NULL);
+ g_return_if_fail(package_version != NULL);
+
+ /* application name and version */
+ g_string_append_printf(str, "%s/%s", package_name, package_version);
+
+ /* system information */
+ system = fwupd_build_user_agent_system();
+ if (system != NULL)
+ g_string_append_printf(str, " (%s)", system);
+
+ /* platform, which in our case is just fwupd */
+ if (g_strcmp0(package_name, "fwupd") != 0)
+ g_string_append_printf(str, " fwupd/%s", priv->daemon_version);
+
+ /* success */
+ g_free(priv->user_agent);
+ priv->user_agent = g_string_free(g_steal_pointer(&str), FALSE);
+}
+
+#ifdef HAVE_LIBCURL
+static size_t
+fwupd_client_download_write_callback_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ GByteArray *buf = (GByteArray *)userdata;
+ gsize realsize = size * nmemb;
+ g_byte_array_append(buf, (const guint8 *)ptr, realsize);
+ return realsize;
+}
+
+static GBytes *
+fwupd_client_download_ipfs(FwupdClient *self,
+ const gchar *url,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSubprocessFlags flags = G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE;
+ g_autofree gchar *path = NULL;
+ g_autoptr(GBytes) bstdout = NULL;
+ g_autoptr(GBytes) bstderr = NULL;
+ g_autoptr(GSubprocess) subprocess = NULL;
+
+ /* we get no detailed progress details */
+ fwupd_client_set_status(self, FWUPD_STATUS_DOWNLOADING);
+ fwupd_client_set_percentage(self, 0);
+
+ /* convert from URI to path */
+ if (g_str_has_prefix(url, "ipfs://")) {
+ path = g_strdup_printf("/ipfs/%s", url + 7);
+ } else if (g_str_has_prefix(url, "ipns://")) {
+ path = g_strdup_printf("/ipns/%s", url + 7);
+ } else {
+ path = g_strdup(url);
+ }
+
+ /* run sync */
+ subprocess = g_subprocess_new(flags, error, "ipfs", "cat", path, NULL);
+ if (subprocess == NULL)
+ return NULL;
+ if (!g_subprocess_communicate(subprocess, NULL, cancellable, &bstdout, &bstderr, error))
+ return NULL;
+ fwupd_client_set_status(self, FWUPD_STATUS_IDLE);
+ if (g_subprocess_get_exit_status(subprocess) != 0) {
+ const gchar *msg = g_bytes_get_data(bstderr, NULL);
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to download file: %s",
+ msg);
+ return NULL;
+ }
+ return g_steal_pointer(&bstdout);
+}
+
+static GBytes *
+fwupd_client_download_http(FwupdClient *self, CURL *curl, const gchar *url, GError **error)
+{
+ CURLcode res;
+ gchar errbuf[CURL_ERROR_SIZE] = {'\0'};
+ glong status_code = 0;
+ g_autoptr(GByteArray) buf = g_byte_array_new();
+
+ fwupd_client_set_status(self, FWUPD_STATUS_DOWNLOADING);
+ (void)curl_easy_setopt(curl, CURLOPT_URL, url);
+ (void)curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
+ (void)curl_easy_setopt(curl,
+ CURLOPT_WRITEFUNCTION,
+ fwupd_client_download_write_callback_cb);
+ (void)curl_easy_setopt(curl, CURLOPT_WRITEDATA, buf);
+ res = curl_easy_perform(curl);
+ fwupd_client_set_status(self, FWUPD_STATUS_IDLE);
+ if (res != CURLE_OK) {
+ if (errbuf[0] != '\0') {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to download file: %s",
+ errbuf);
+ return NULL;
+ }
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to download file: %s",
+ curl_easy_strerror(res));
+ return NULL;
+ }
+
+ /* check for server limit */
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
+ g_debug("status-code was %ld", status_code);
+ if (status_code == 429) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "Failed to download due to server limit");
+ return NULL;
+ }
+ if (status_code >= 400) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "Failed to download, server response was %u",
+ (guint)status_code);
+ return NULL;
+ }
+
+ return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+}
+
+static void
+fwupd_client_download_bytes_thread_cb(GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ FwupdClient *self = FWUPD_CLIENT(source_object);
+ FwupdCurlHelper *helper = g_task_get_task_data(task);
+ g_autoptr(GBytes) blob = NULL;
+
+ for (guint i = 0; i < helper->urls->len; i++) {
+ const gchar *url = g_ptr_array_index(helper->urls, i);
+ g_autoptr(GError) error = NULL;
+ g_debug("downloading %s", url);
+ fwupd_client_curl_helper_set_proxy(self, helper, url);
+ if (fwupd_client_is_url_http(url)) {
+ blob = fwupd_client_download_http(self, helper->curl, url, &error);
+ if (blob != NULL)
+ break;
+ } else if (fwupd_client_is_url_ipfs(url)) {
+ blob = fwupd_client_download_ipfs(self, url, cancellable, &error);
+ if (blob != NULL)
+ break;
+ } else {
+ g_set_error(&error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "not sure how to handle: %s",
+ url);
+ }
+ if (i == helper->urls->len - 1) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ fwupd_client_set_percentage(self, 0);
+ fwupd_client_set_status(self, FWUPD_STATUS_IDLE);
+ g_debug("failed to download %s: %s, trying next URI…", url, error->message);
+ }
+ g_task_return_pointer(task, g_steal_pointer(&blob), (GDestroyNotify)g_bytes_unref);
+}
+#endif
+
+/* private */
+void
+fwupd_client_download_bytes2_async(FwupdClient *self,
+ GPtrArray *urls,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ g_autoptr(GTask) task = NULL;
+#ifdef HAVE_LIBCURL
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FwupdCurlHelper) helper = NULL;
+#endif
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(urls != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+
+ /* ensure networking set up */
+ task = g_task_new(self, cancellable, callback, callback_data);
+#ifdef HAVE_LIBCURL
+ helper = fwupd_client_curl_new(self, &error);
+ if (helper == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ helper->urls = fwupd_client_filter_locations(urls, flags, &error);
+ if (helper->urls == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+ g_task_set_task_data(task,
+ g_steal_pointer(&helper),
+ (GDestroyNotify)fwupd_client_curl_helper_free);
+
+ /* download data */
+ g_task_run_in_thread(task, fwupd_client_download_bytes_thread_cb);
+#else
+ g_task_return_new_error(task, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "no libcurl support");
+#endif
+}
+
+/**
+ * fwupd_client_download_bytes_async:
+ * @self: a #FwupdClient
+ * @url: (not nullable): the remote URL
+ * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Downloads data from a remote server. The [method@Client.set_user_agent] function
+ * should be called before this method is used.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_download_bytes_async(FwupdClient *self,
+ const gchar *url,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ g_autoptr(GPtrArray) urls = g_ptr_array_new_with_free_func(g_free);
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(url != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+
+ /* just proxy */
+ g_ptr_array_add(urls, g_strdup(url));
+ fwupd_client_download_bytes2_async(self, urls, flags, cancellable, callback, callback_data);
+}
+
+/**
+ * fwupd_client_download_bytes_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.download_bytes_async].
+ *
+ * Returns: (transfer full): downloaded data, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GBytes *
+fwupd_client_download_bytes_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+#ifdef HAVE_LIBCURL
+static void
+fwupd_client_upload_bytes_thread_cb(GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ FwupdClient *self = FWUPD_CLIENT(source_object);
+ FwupdCurlHelper *helper = g_task_get_task_data(task);
+ CURLcode res;
+ gchar errbuf[CURL_ERROR_SIZE] = {'\0'};
+ g_autoptr(GByteArray) buf = g_byte_array_new();
+
+ (void)curl_easy_setopt(helper->curl, CURLOPT_ERRORBUFFER, errbuf);
+ (void)curl_easy_setopt(helper->curl,
+ CURLOPT_WRITEFUNCTION,
+ fwupd_client_download_write_callback_cb);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_WRITEDATA, buf);
+ res = curl_easy_perform(helper->curl);
+ fwupd_client_set_status(self, FWUPD_STATUS_IDLE);
+ if (res != CURLE_OK) {
+ glong status_code = 0;
+ curl_easy_getinfo(helper->curl, CURLINFO_RESPONSE_CODE, &status_code);
+ g_debug("status-code was %ld", status_code);
+ if (errbuf[0] != '\0') {
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to upload file: %s",
+ errbuf);
+ return;
+ }
+ g_task_return_new_error(task,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to upload file: %s",
+ curl_easy_strerror(res));
+
+ return;
+ }
+ g_task_return_pointer(task,
+ g_byte_array_free_to_bytes(g_steal_pointer(&buf)),
+ (GDestroyNotify)g_bytes_unref);
+}
+#endif
+
+/**
+ * fwupd_client_upload_bytes_async:
+ * @self: a #FwupdClient
+ * @url: (not nullable): the remote URL
+ * @payload: (not nullable): payload string
+ * @signature: (nullable): signature string
+ * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE
+ * @cancellable: (nullable): optional #GCancellable
+ * @callback: the function to run on completion
+ * @callback_data: the data to pass to @callback
+ *
+ * Uploads data to a remote server. The [method@Client.set_user_agent] function
+ * should be called before this method is used.
+ *
+ * You must have called [method@Client.connect_async] on @self before using
+ * this method.
+ *
+ * NOTE: This method is thread-safe, but progress signals will be
+ * emitted in the global default main context, if not explicitly set with
+ * [method@Client.set_main_context].
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_client_upload_bytes_async(FwupdClient *self,
+ const gchar *url,
+ const gchar *payload,
+ const gchar *signature,
+ FwupdClientUploadFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GTask) task = NULL;
+#ifdef HAVE_LIBCURL
+ g_autoptr(FwupdCurlHelper) helper = NULL;
+ g_autoptr(GError) error = NULL;
+#endif
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(url != NULL);
+ g_return_if_fail(payload != NULL);
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+ g_return_if_fail(priv->proxy != NULL);
+
+ /* ensure networking set up */
+ task = g_task_new(self, cancellable, callback, callback_data);
+#ifdef HAVE_LIBCURL
+ helper = fwupd_client_curl_new(self, &error);
+ if (helper == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* build message */
+ if ((flags & FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART) > 0 || signature != NULL) {
+ curl_mimepart *part;
+ helper->mime = curl_mime_init(helper->curl);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_MIMEPOST, helper->mime);
+ part = curl_mime_addpart(helper->mime);
+ (void)curl_mime_data(part, payload, CURL_ZERO_TERMINATED);
+ curl_mime_name(part, "payload");
+ if (signature != NULL) {
+ part = curl_mime_addpart(helper->mime);
+ (void)curl_mime_data(part, signature, CURL_ZERO_TERMINATED);
+ curl_mime_name(part, "signature");
+ }
+ } else {
+ helper->headers = curl_slist_append(helper->headers, "Content-Type: text/plain");
+ (void)curl_easy_setopt(helper->curl, CURLOPT_HTTPHEADER, helper->headers);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_POST, 1L);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_POSTFIELDSIZE, strlen(payload));
+ (void)curl_easy_setopt(helper->curl, CURLOPT_COPYPOSTFIELDS, payload);
+ }
+
+ fwupd_client_set_status(self, FWUPD_STATUS_IDLE);
+ g_debug("uploading to %s", url);
+ (void)curl_easy_setopt(helper->curl, CURLOPT_URL, url);
+ g_task_set_task_data(task,
+ g_steal_pointer(&helper),
+ (GDestroyNotify)fwupd_client_curl_helper_free);
+ g_task_run_in_thread(task, fwupd_client_upload_bytes_thread_cb);
+#else
+ g_task_return_new_error(task, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "no libcurl support");
+#endif
+}
+
+/**
+ * fwupd_client_upload_bytes_finish:
+ * @self: a #FwupdClient
+ * @res: the asynchronous result
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the result of [method@FwupdClient.upload_bytes_async].
+ *
+ * Returns: (transfer full): response data, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GBytes *
+fwupd_client_upload_bytes_finish(FwupdClient *self, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+/**
+ * fwupd_client_add_hint:
+ * @self: a #FwupdClient
+ * @key: (not nullable): the key, e.g. `locale`
+ * @value: (nullable): the value @key should be set
+ *
+ * Sets optional hints from the client that may affect the list of devices.
+ *
+ * Since: 1.7.1
+ **/
+void
+fwupd_client_add_hint(FwupdClient *self, const gchar *key, const gchar *value)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_CLIENT(self));
+ g_return_if_fail(key != NULL);
+
+ g_hash_table_insert(priv->hints, g_strdup(key), g_strdup(value));
+}
+
+#ifdef SOUP_SESSION_COMPAT
+/* this is bad; we dlopen libsoup-2.4.so.1 and get the gtype manually
+ * to avoid deps on both libcurl and libsoup whilst preserving ABI */
+static void
+fwupd_client_ensure_soup_session(FwupdClient *self)
+{
+ FwupdClientObjectNewFunc func = NULL;
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ GType soup_gtype;
+
+ /* already set up */
+ if (priv->soup_session != NULL)
+ return;
+
+ /* known GType, just create */
+ soup_gtype = g_type_from_name("SoupSession");
+ if (soup_gtype != 0) {
+ priv->soup_session = g_object_new(soup_gtype, NULL);
+ return;
+ }
+
+ /* load the library at runtime, leaking the module */
+ if (priv->soup_module == NULL) {
+ g_autofree gchar *fn = NULL;
+ fn = g_build_filename(FWUPD_LIBDIR, "libsoup-2.4.so.1", NULL);
+ priv->soup_module = g_module_open(fn, G_MODULE_BIND_LAZY);
+ if (priv->soup_module == NULL) {
+ g_warning("failed to find libsoup library");
+ return;
+ }
+ }
+ if (!g_module_symbol(priv->soup_module, "soup_session_new", (gpointer *)&func)) {
+ g_warning("failed to find soup_session_get_type()");
+ g_module_close(priv->soup_module);
+ priv->soup_module = NULL;
+ return;
+ }
+ priv->soup_session = func();
+ g_object_set(priv->soup_session, "timeout", (guint)60, NULL);
+}
+#endif
+
+static void
+fwupd_client_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FwupdClient *self = FWUPD_CLIENT(object);
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ switch (prop_id) {
+ case PROP_STATUS:
+ g_value_set_uint(value, priv->status);
+ break;
+ case PROP_TAINTED:
+ g_value_set_boolean(value, priv->tainted);
+ break;
+ case PROP_SOUP_SESSION:
+#ifdef SOUP_SESSION_COMPAT
+ fwupd_client_ensure_soup_session(self);
+ g_value_set_object(value, priv->soup_session);
+#else
+ g_value_set_object(value, NULL);
+#endif
+ break;
+ case PROP_PERCENTAGE:
+ g_value_set_uint(value, priv->percentage);
+ break;
+ case PROP_DAEMON_VERSION:
+ g_value_set_string(value, priv->daemon_version);
+ break;
+ case PROP_HOST_BKC:
+ g_value_set_string(value, priv->host_bkc);
+ break;
+ case PROP_HOST_VENDOR:
+ g_value_set_string(value, priv->host_vendor);
+ break;
+ case PROP_HOST_PRODUCT:
+ g_value_set_string(value, priv->host_product);
+ break;
+ case PROP_HOST_MACHINE_ID:
+ g_value_set_string(value, priv->host_machine_id);
+ break;
+ case PROP_HOST_SECURITY_ID:
+ g_value_set_string(value, priv->host_security_id);
+ break;
+ case PROP_ONLY_TRUSTED:
+ g_value_set_boolean(value, priv->only_trusted);
+ break;
+ case PROP_INTERACTIVE:
+ g_value_set_boolean(value, priv->interactive);
+ break;
+ case PROP_BATTERY_LEVEL:
+ g_value_set_uint(value, priv->battery_level);
+ break;
+ case PROP_BATTERY_THRESHOLD:
+ g_value_set_uint(value, priv->battery_threshold);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_client_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FwupdClient *self = FWUPD_CLIENT(object);
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ switch (prop_id) {
+ case PROP_STATUS:
+ priv->status = g_value_get_uint(value);
+ break;
+ case PROP_PERCENTAGE:
+ priv->percentage = g_value_get_uint(value);
+ break;
+ case PROP_BATTERY_LEVEL:
+ fwupd_client_set_battery_level(self, g_value_get_uint(value));
+ break;
+ case PROP_BATTERY_THRESHOLD:
+ fwupd_client_set_battery_threshold(self, g_value_get_uint(value));
+ break;
+ case PROP_HOST_BKC:
+ fwupd_client_set_host_bkc(self, g_value_get_string(value));
+ break;
+ case PROP_HOST_VENDOR:
+ fwupd_client_set_host_vendor(self, g_value_get_string(value));
+ break;
+ case PROP_HOST_PRODUCT:
+ fwupd_client_set_host_product(self, g_value_get_string(value));
+ break;
+ case PROP_HOST_MACHINE_ID:
+ fwupd_client_set_host_machine_id(self, g_value_get_string(value));
+ break;
+ case PROP_HOST_SECURITY_ID:
+ fwupd_client_set_host_security_id(self, g_value_get_string(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_client_class_init(FwupdClientClass *klass)
+{
+ GParamSpec *pspec;
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fwupd_client_finalize;
+ object_class->get_property = fwupd_client_get_property;
+ object_class->set_property = fwupd_client_set_property;
+
+ /**
+ * FwupdClient::changed:
+ * @self: the #FwupdClient instance that emitted the signal
+ *
+ * The ::changed signal is emitted when the daemon internal has
+ * changed, for instance when a device has been added or removed.
+ *
+ * Since: 0.7.0
+ **/
+ signals[SIGNAL_CHANGED] = g_signal_new("changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FwupdClientClass, changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ /**
+ * FwupdClient::state-changed:
+ * @self: the #FwupdClient instance that emitted the signal
+ * @status: the #FwupdStatus
+ *
+ * The ::state-changed signal is emitted when the daemon status has
+ * changed, e.g. going from %FWUPD_STATUS_IDLE to %FWUPD_STATUS_DEVICE_WRITE.
+ *
+ * Since: 0.7.0
+ **/
+ signals[SIGNAL_STATUS_CHANGED] =
+ g_signal_new("status-changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FwupdClientClass, status_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ /**
+ * FwupdClient::device-added:
+ * @self: the #FwupdClient instance that emitted the signal
+ * @result: the #FwupdDevice
+ *
+ * The ::device-added signal is emitted when a device has been
+ * added.
+ *
+ * Since: 0.7.1
+ **/
+ signals[SIGNAL_DEVICE_ADDED] = g_signal_new("device-added",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FwupdClientClass, device_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 1,
+ FWUPD_TYPE_DEVICE);
+
+ /**
+ * FwupdClient::device-removed:
+ * @self: the #FwupdClient instance that emitted the signal
+ * @result: the #FwupdDevice
+ *
+ * The ::device-removed signal is emitted when a device has been
+ * removed.
+ *
+ * Since: 0.7.1
+ **/
+ signals[SIGNAL_DEVICE_REMOVED] =
+ g_signal_new("device-removed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FwupdClientClass, device_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 1,
+ FWUPD_TYPE_DEVICE);
+
+ /**
+ * FwupdClient::device-changed:
+ * @self: the #FwupdClient instance that emitted the signal
+ * @result: the #FwupdDevice
+ *
+ * The ::device-changed signal is emitted when a device has been
+ * changed in some way, e.g. the version number is updated.
+ *
+ * Since: 0.7.1
+ **/
+ signals[SIGNAL_DEVICE_CHANGED] =
+ g_signal_new("device-changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FwupdClientClass, device_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 1,
+ FWUPD_TYPE_DEVICE);
+
+ /**
+ * FwupdClient::device-request:
+ * @self: the #FwupdClient instance that emitted the signal
+ * @msg: the #FwupdRequest
+ *
+ * The ::device-request signal is emitted when a device has been
+ * emitted some kind of event, e.g. a manual action is required.
+ *
+ * Since: 1.6.2
+ **/
+ signals[SIGNAL_DEVICE_REQUEST] =
+ g_signal_new("device-request",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FwupdClientClass, device_request),
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 1,
+ FWUPD_TYPE_REQUEST);
+
+ /**
+ * FwupdClient:status:
+ *
+ * The last-reported status of the daemon.
+ *
+ * Since: 0.7.0
+ */
+ pspec = g_param_spec_uint("status",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_STATUS_LAST,
+ FWUPD_STATUS_UNKNOWN,
+ 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:interactive:
+ *
+ * If the daemon is running in an interactive terminal
+ *
+ * Since: 1.3.4
+ */
+ pspec = g_param_spec_boolean("interactive",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_INTERACTIVE, pspec);
+
+ /**
+ * FwupdClient:percentage:
+ *
+ * The last-reported percentage of the daemon.
+ *
+ * Since: 0.7.3
+ */
+ pspec = g_param_spec_uint("percentage",
+ NULL,
+ NULL,
+ 0,
+ 100,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PERCENTAGE, pspec);
+
+ /**
+ * FwupdClient:daemon-version:
+ *
+ * The daemon version number.
+ *
+ * Since: 0.9.6
+ */
+ pspec = g_param_spec_string("daemon-version",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_DAEMON_VERSION, pspec);
+
+ /**
+ * FwupdClient:host-bkc:
+ *
+ * The host best known configuration.
+ *
+ * Since: 1.7.3
+ */
+ pspec = g_param_spec_string("host-bkc",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_HOST_BKC, pspec);
+
+ /**
+ * FwupdClient:soup-session:
+ *
+ * The libsoup session, now unused.
+ *
+ * Since: 1.4.5
+ */
+ pspec = g_param_spec_object("soup-session",
+ NULL,
+ NULL,
+ G_TYPE_OBJECT,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_SOUP_SESSION, pspec);
+
+ /**
+ * FwupdClient:host-vendor:
+ *
+ * The host vendor string
+ *
+ * Since: 1.8.2
+ */
+ pspec = g_param_spec_string("host-vendor",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_HOST_VENDOR, pspec);
+
+ /**
+ * FwupdClient:host-product:
+ *
+ * The host product string
+ *
+ * Since: 1.3.1
+ */
+ pspec = g_param_spec_string("host-product",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_HOST_PRODUCT, pspec);
+
+ /**
+ * FwupdClient:host-machine-id:
+ *
+ * The host machine-id string
+ *
+ * Since: 1.3.2
+ */
+ pspec = g_param_spec_string("host-machine-id",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_HOST_MACHINE_ID, pspec);
+
+ /**
+ * FwupdClient:host-security-id:
+ *
+ * The host machine-id string
+ *
+ * Since: 1.5.0
+ */
+ pspec = g_param_spec_string("host-security-id",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_HOST_SECURITY_ID, pspec);
+
+ /**
+ * FwupdClient:only-trusted:
+ *
+ * If the daemon is verifying signatures from a trusted authority.
+ *
+ * Since: 1.8.0
+ */
+ pspec = g_param_spec_boolean("only-trusted",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_ONLY_TRUSTED, pspec);
+
+ /**
+ * FwupdClient:battery-level:
+ *
+ * The system battery level in percent.
+ *
+ * Since: 1.8.1
+ */
+ pspec = g_param_spec_uint("battery-level",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_LEVEL, pspec);
+
+ /**
+ * FwupdClient:battery-threshold:
+ *
+ * The system battery threshold in percent.
+ *
+ * Since: 1.8.1
+ */
+ pspec = g_param_spec_uint("battery-threshold",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_THRESHOLD, pspec);
+}
+
+static void
+fwupd_client_init(FwupdClient *self)
+{
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+ g_mutex_init(&priv->proxy_mutex);
+ g_mutex_init(&priv->idle_mutex);
+ priv->idle_sources =
+ g_ptr_array_new_with_free_func((GDestroyNotify)fwupd_client_context_helper_free);
+ priv->proxy_resolver = g_proxy_resolver_get_default();
+ priv->hints = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ priv->battery_level = FWUPD_BATTERY_LEVEL_INVALID;
+ priv->battery_threshold = FWUPD_BATTERY_LEVEL_INVALID;
+
+ /* we get this one for free */
+ fwupd_client_add_hint(self, "locale", g_getenv("LANG"));
+}
+
+static void
+fwupd_client_finalize(GObject *object)
+{
+ FwupdClient *self = FWUPD_CLIENT(object);
+ FwupdClientPrivate *priv = GET_PRIVATE(self);
+
+ g_clear_pointer(&priv->main_ctx, g_main_context_unref);
+ g_free(priv->user_agent);
+ g_free(priv->daemon_version);
+ g_free(priv->host_bkc);
+ g_free(priv->host_vendor);
+ g_free(priv->host_product);
+ g_free(priv->host_machine_id);
+ g_free(priv->host_security_id);
+ g_hash_table_unref(priv->hints);
+ g_mutex_clear(&priv->idle_mutex);
+ if (priv->idle_id != 0)
+ g_source_remove(priv->idle_id);
+ g_ptr_array_unref(priv->idle_sources);
+ g_mutex_clear(&priv->proxy_mutex);
+ if (priv->proxy != NULL)
+ g_object_unref(priv->proxy);
+#ifdef SOUP_SESSION_COMPAT
+ if (priv->soup_session != NULL)
+ g_object_unref(priv->soup_session);
+#endif
+
+ G_OBJECT_CLASS(fwupd_client_parent_class)->finalize(object);
+}
+
+/**
+ * fwupd_client_new:
+ *
+ * Creates a new client.
+ *
+ * Returns: a new #FwupdClient
+ *
+ * Since: 0.7.0
+ **/
+FwupdClient *
+fwupd_client_new(void)
+{
+ FwupdClient *self;
+ self = g_object_new(FWUPD_TYPE_CLIENT, NULL);
+ return FWUPD_CLIENT(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-client.h b/fwupd-1.8.6/libfwupd/fwupd-client.h
new file mode 100644
index 0000000000000000000000000000000000000000..d6d9d9e84d5f54950df6cb9de01cbd65eba44df0
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-client.h
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-device.h"
+#include "fwupd-enums.h"
+#include "fwupd-plugin.h"
+#include "fwupd-remote.h"
+#include "fwupd-request.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_CLIENT (fwupd_client_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdClient, fwupd_client, FWUPD, CLIENT, GObject)
+
+struct _FwupdClientClass {
+ GObjectClass parent_class;
+ void (*changed)(FwupdClient *client);
+ void (*status_changed)(FwupdClient *client, FwupdStatus status);
+ void (*device_added)(FwupdClient *client, FwupdDevice *result);
+ void (*device_removed)(FwupdClient *client, FwupdDevice *result);
+ void (*device_changed)(FwupdClient *client, FwupdDevice *result);
+ void (*device_request)(FwupdClient *client, FwupdRequest *request);
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+};
+
+/**
+ * FwupdClientDownloadFlags:
+ * @FWUPD_CLIENT_DOWNLOAD_FLAG_NONE: No flags set
+ * @FWUPD_CLIENT_DOWNLOAD_FLAG_ONLY_IPFS: Only use IPFS when downloading URIs
+ *
+ * The options to use for downloading.
+ **/
+typedef enum {
+ FWUPD_CLIENT_DOWNLOAD_FLAG_NONE = 0, /* Since: 1.4.5 */
+ FWUPD_CLIENT_DOWNLOAD_FLAG_ONLY_IPFS = 1 << 0, /* Since: 1.5.6 */
+ /*< private >*/
+ FWUPD_CLIENT_DOWNLOAD_FLAG_LAST
+} FwupdClientDownloadFlags;
+
+/**
+ * FwupdClientUploadFlags:
+ * @FWUPD_CLIENT_UPLOAD_FLAG_NONE: No flags set
+ * @FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART: Always use multipart/form-data
+ *
+ * The options to use for uploading.
+ **/
+typedef enum {
+ FWUPD_CLIENT_UPLOAD_FLAG_NONE = 0, /* Since: 1.4.5 */
+ FWUPD_CLIENT_UPLOAD_FLAG_ALWAYS_MULTIPART = 1 << 0, /* Since: 1.4.5 */
+ /*< private >*/
+ FWUPD_CLIENT_UPLOAD_FLAG_LAST
+} FwupdClientUploadFlags;
+
+FwupdClient *
+fwupd_client_new(void);
+GMainContext *
+fwupd_client_get_main_context(FwupdClient *self);
+void
+fwupd_client_set_main_context(FwupdClient *self, GMainContext *main_ctx);
+void
+fwupd_client_connect_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_connect_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_disconnect(FwupdClient *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_devices_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_devices_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_plugins_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_plugins_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_history_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_history_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_releases_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_releases_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_downgrades_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_downgrades_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_upgrades_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_upgrades_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_details_bytes_async(FwupdClient *self,
+ GBytes *bytes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_details_bytes_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_verify_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_verify_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_verify_update_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_verify_update_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_unlock_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_unlock_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_modify_config_async(FwupdClient *self,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_modify_config_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_activate_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_activate_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_clear_results_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_clear_results_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_results_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+FwupdDevice *
+fwupd_client_get_results_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_modify_bios_setting_async(FwupdClient *self,
+ GHashTable *settings,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_modify_bios_setting_finish(FwupdClient *self, GAsyncResult *res, GError **error);
+void
+fwupd_client_get_bios_settings_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_bios_settings_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_host_security_attrs_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_host_security_attrs_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_host_security_events_async(FwupdClient *self,
+ guint limit,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_host_security_events_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_device_by_id_async(FwupdClient *self,
+ const gchar *device_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+FwupdDevice *
+fwupd_client_get_device_by_id_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_devices_by_guid_async(FwupdClient *self,
+ const gchar *guid,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_devices_by_guid_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_install_async(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *filename,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_install_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_install_bytes_async(FwupdClient *self,
+ const gchar *device_id,
+ GBytes *bytes,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_install_bytes_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_install_release_async(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+ G_DEPRECATED_FOR(fwupd_client_install_release2_async);
+void
+fwupd_client_install_release2_async(FwupdClient *self,
+ FwupdDevice *device,
+ FwupdRelease *release,
+ FwupdInstallFlags install_flags,
+ FwupdClientDownloadFlags download_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_install_release_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_update_metadata_bytes_async(FwupdClient *self,
+ const gchar *remote_id,
+ GBytes *metadata,
+ GBytes *signature,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_update_metadata_bytes_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_refresh_remote_async(FwupdClient *self,
+ FwupdRemote *remote,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_refresh_remote_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_modify_remote_async(FwupdClient *self,
+ const gchar *remote_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_modify_remote_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_modify_device_async(FwupdClient *self,
+ const gchar *device_id,
+ const gchar *key,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_modify_device_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_report_metadata_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GHashTable *
+fwupd_client_get_report_metadata_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+FwupdStatus
+fwupd_client_get_status(FwupdClient *self);
+gboolean
+fwupd_client_get_tainted(FwupdClient *self);
+gboolean
+fwupd_client_get_only_trusted(FwupdClient *self);
+gboolean
+fwupd_client_get_daemon_interactive(FwupdClient *self);
+guint
+fwupd_client_get_percentage(FwupdClient *self);
+const gchar *
+fwupd_client_get_daemon_version(FwupdClient *self);
+const gchar *
+fwupd_client_get_host_bkc(FwupdClient *self);
+const gchar *
+fwupd_client_get_host_vendor(FwupdClient *self);
+const gchar *
+fwupd_client_get_host_product(FwupdClient *self);
+const gchar *
+fwupd_client_get_host_machine_id(FwupdClient *self);
+const gchar *
+fwupd_client_get_host_security_id(FwupdClient *self);
+guint32
+fwupd_client_get_battery_level(FwupdClient *self);
+guint32
+fwupd_client_get_battery_threshold(FwupdClient *self);
+
+void
+fwupd_client_get_remotes_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_remotes_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_remote_by_id_async(FwupdClient *self,
+ const gchar *remote_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+FwupdRemote *
+fwupd_client_get_remote_by_id_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_approved_firmware_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_approved_firmware_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_set_approved_firmware_async(FwupdClient *self,
+ GPtrArray *checksums,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_set_approved_firmware_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_get_blocked_firmware_async(FwupdClient *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GPtrArray *
+fwupd_client_get_blocked_firmware_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_set_blocked_firmware_async(FwupdClient *self,
+ GPtrArray *checksums,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_set_blocked_firmware_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_self_sign_async(FwupdClient *self,
+ const gchar *value,
+ FwupdSelfSignFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gchar *
+fwupd_client_self_sign_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_set_feature_flags_async(FwupdClient *self,
+ FwupdFeatureFlags feature_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+gboolean
+fwupd_client_set_feature_flags_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+const gchar *
+fwupd_client_get_user_agent(FwupdClient *self);
+void
+fwupd_client_set_user_agent(FwupdClient *self, const gchar *user_agent);
+void
+fwupd_client_set_user_agent_for_package(FwupdClient *self,
+ const gchar *package_name,
+ const gchar *package_version);
+void
+fwupd_client_download_bytes_async(FwupdClient *self,
+ const gchar *url,
+ FwupdClientDownloadFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GBytes *
+fwupd_client_download_bytes_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_upload_bytes_async(FwupdClient *self,
+ const gchar *url,
+ const gchar *payload,
+ const gchar *signature,
+ FwupdClientUploadFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GBytes *
+fwupd_client_upload_bytes_finish(FwupdClient *self,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_client_ensure_networking(FwupdClient *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fwupd_client_add_hint(FwupdClient *self, const gchar *key, const gchar *value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-common-private.h b/fwupd-1.8.6/libfwupd/fwupd-common-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..c58d79b0d78d46b15b23399b52b907bccbf5663b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-common-private.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#ifdef HAVE_GIO_UNIX
+#include
+#endif
+
+#include
+
+#include "fwupd-common.h"
+
+G_BEGIN_DECLS
+
+GVariant *
+fwupd_hash_kv_to_variant(GHashTable *hash);
+GHashTable *
+fwupd_variant_to_hash_kv(GVariant *dict);
+gchar *
+fwupd_build_user_agent_system(void);
+
+void
+fwupd_input_stream_read_bytes_async(GInputStream *stream,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data);
+GBytes *
+fwupd_input_stream_read_bytes_finish(GInputStream *stream,
+ GAsyncResult *res,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+void
+fwupd_common_json_add_string(JsonBuilder *builder, const gchar *key, const gchar *value);
+void
+fwupd_common_json_add_stringv(JsonBuilder *builder, const gchar *key, gchar **value);
+void
+fwupd_common_json_add_int(JsonBuilder *builder, const gchar *key, guint64 value);
+void
+fwupd_common_json_add_boolean(JsonBuilder *builder, const gchar *key, gboolean value);
+
+#ifdef HAVE_GIO_UNIX
+GUnixInputStream *
+fwupd_unix_input_stream_from_bytes(GBytes *bytes, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GUnixInputStream *
+fwupd_unix_input_stream_from_fn(const gchar *fn, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+#endif
+
+void
+fwupd_pad_kv_unx(GString *str, const gchar *key, guint64 value);
+void
+fwupd_pad_kv_str(GString *str, const gchar *key, const gchar *value);
+void
+fwupd_pad_kv_int(GString *str, const gchar *key, guint32 value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-common.c b/fwupd-1.8.6/libfwupd/fwupd-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..62906e946ce9b852a5912f191052dd6fe9cd66a9
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-common.c
@@ -0,0 +1,1270 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fwupd-common-private.h"
+#include "fwupd-device.h"
+#include "fwupd-error.h"
+#include "fwupd-release.h"
+
+#ifdef HAVE_GIO_UNIX
+#include
+#include
+#include
+#include
+#endif
+
+#ifdef HAVE_MEMFD_CREATE
+#include
+#endif
+
+#include
+#include
+#ifdef HAVE_UTSNAME_H
+#include
+#endif
+#include
+
+#if !GLIB_CHECK_VERSION(2, 54, 0)
+#include
+#endif
+
+/**
+ * fwupd_checksum_guess_kind:
+ * @checksum: (nullable): a checksum
+ *
+ * Guesses the checksum kind based on the length of the hash.
+ *
+ * Returns: a checksum type, e.g. %G_CHECKSUM_SHA1
+ *
+ * Since: 0.9.3
+ **/
+GChecksumType
+fwupd_checksum_guess_kind(const gchar *checksum)
+{
+ guint len;
+ if (checksum == NULL)
+ return G_CHECKSUM_SHA1;
+ len = strlen(checksum);
+ if (len == 32)
+ return G_CHECKSUM_MD5;
+ if (len == 40)
+ return G_CHECKSUM_SHA1;
+ if (len == 64)
+ return G_CHECKSUM_SHA256;
+ if (len == 128)
+ return G_CHECKSUM_SHA512;
+ return G_CHECKSUM_SHA1;
+}
+
+static const gchar *
+fwupd_checksum_type_to_string_display(GChecksumType checksum_type)
+{
+ if (checksum_type == G_CHECKSUM_MD5)
+ return "MD5";
+ 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 NULL;
+}
+
+/**
+ * fwupd_checksum_format_for_display:
+ * @checksum: (nullable): a checksum
+ *
+ * Formats a checksum for display.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 0.9.3
+ **/
+gchar *
+fwupd_checksum_format_for_display(const gchar *checksum)
+{
+ GChecksumType kind = fwupd_checksum_guess_kind(checksum);
+ return g_strdup_printf("%s(%s)", fwupd_checksum_type_to_string_display(kind), checksum);
+}
+
+/**
+ * fwupd_checksum_get_by_kind:
+ * @checksums: (element-type utf8): checksums
+ * @kind: a checksum type, e.g. %G_CHECKSUM_SHA512
+ *
+ * Gets a specific checksum kind.
+ *
+ * Returns: a checksum from the array, or %NULL if not found
+ *
+ * Since: 0.9.4
+ **/
+const gchar *
+fwupd_checksum_get_by_kind(GPtrArray *checksums, GChecksumType kind)
+{
+ g_return_val_if_fail(checksums != NULL, NULL);
+ for (guint i = 0; i < checksums->len; i++) {
+ const gchar *checksum = g_ptr_array_index(checksums, i);
+ if (fwupd_checksum_guess_kind(checksum) == kind)
+ return checksum;
+ }
+ return NULL;
+}
+
+/**
+ * fwupd_checksum_get_best:
+ * @checksums: (element-type utf8): checksums
+ *
+ * Gets a the best possible checksum kind.
+ *
+ * Returns: a checksum from the array, or %NULL if nothing was suitable
+ *
+ * Since: 0.9.4
+ **/
+const gchar *
+fwupd_checksum_get_best(GPtrArray *checksums)
+{
+ GChecksumType checksum_types[] = {G_CHECKSUM_SHA512, G_CHECKSUM_SHA256, G_CHECKSUM_SHA1, 0};
+ g_return_val_if_fail(checksums != NULL, NULL);
+ for (guint i = 0; checksum_types[i] != 0; i++) {
+ for (guint j = 0; j < checksums->len; j++) {
+ const gchar *checksum = g_ptr_array_index(checksums, j);
+ if (fwupd_checksum_guess_kind(checksum) == checksum_types[i])
+ return checksum;
+ }
+ }
+ return NULL;
+}
+
+static gchar *
+fwupd_get_os_release_filename(void)
+{
+#ifndef _WIN32
+ const gchar *sysconfdir = g_getenv("FWUPD_SYSCONFDIR");
+ g_autofree gchar *fn1 = NULL;
+
+ /* override */
+ if (sysconfdir != NULL) {
+ g_autofree gchar *fn2 = g_build_filename(sysconfdir, "os-release", NULL);
+ if (g_file_test(fn2, G_FILE_TEST_EXISTS))
+ return g_steal_pointer(&fn2);
+ }
+
+ /* host locations */
+ if (g_strcmp0(sysconfdir, "/etc") != 0) {
+ g_autofree gchar *fn2 = g_strdup("/etc/os-release");
+ if (g_file_test(fn2, G_FILE_TEST_EXISTS))
+ return g_steal_pointer(&fn2);
+ }
+ fn1 = g_strdup("/usr/lib/os-release");
+ if (g_file_test(fn1, G_FILE_TEST_EXISTS))
+ return g_steal_pointer(&fn1);
+#endif
+ return NULL;
+}
+
+/**
+ * fwupd_get_os_release:
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads information from the system os-release file.
+ *
+ * Returns: (transfer container) (element-type utf8 utf8): keys from os-release
+ *
+ * Since: 1.0.7
+ **/
+GHashTable *
+fwupd_get_os_release(GError **error)
+{
+ g_autofree gchar *buf = NULL;
+ g_autofree gchar *filename = NULL;
+ g_auto(GStrv) lines = NULL;
+ g_autoptr(GHashTable) hash = NULL;
+
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ filename = fwupd_get_os_release_filename();
+ if (filename == NULL) {
+#if defined(_WIN32)
+ /* TODO: Read the Windows version */
+ g_hash_table_insert(hash, g_strdup("OS"), g_strdup("Windows"));
+#elif defined(__NetBSD__)
+ g_hash_table_insert(hash, g_strdup("OS"), g_strdup("NetBSD"));
+#elif defined(__OpenBSD__)
+ g_hash_table_insert(hash, g_strdup("OS"), g_strdup("OpenBSD"));
+#endif
+ if (g_hash_table_size(hash) > 0)
+ return g_steal_pointer(&hash);
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_READ, "No os-release found");
+ return NULL;
+ }
+
+ /* load each line */
+ if (!g_file_get_contents(filename, &buf, NULL, error))
+ return NULL;
+ lines = g_strsplit(buf, "\n", -1);
+ for (guint i = 0; lines[i] != NULL; i++) {
+ gsize len, off = 0;
+ g_auto(GStrv) split = NULL;
+
+ /* split up into sections */
+ split = g_strsplit(lines[i], "=", 2);
+ if (g_strv_length(split) < 2)
+ continue;
+
+ /* remove double quotes if set both ends */
+ len = strlen(split[1]);
+ if (len == 0)
+ continue;
+ if (split[1][0] == '\"' && split[1][len - 1] == '\"') {
+ off++;
+ len -= 2;
+ }
+ g_hash_table_insert(hash, g_strdup(split[0]), g_strndup(split[1] + off, len));
+ }
+ return g_steal_pointer(&hash);
+}
+
+static gchar *
+fwupd_build_user_agent_os_release(void)
+{
+ const gchar *keys[] = {"NAME", "VERSION_ID", "VARIANT", NULL};
+ g_autoptr(GHashTable) hash = NULL;
+ g_autoptr(GPtrArray) ids_os = g_ptr_array_new();
+
+ /* get all keys */
+ hash = fwupd_get_os_release(NULL);
+ if (hash == NULL)
+ return NULL;
+
+ /* create an array of the keys that exist */
+ for (guint i = 0; keys[i] != NULL; i++) {
+ const gchar *value = g_hash_table_lookup(hash, keys[i]);
+ if (value != NULL)
+ g_ptr_array_add(ids_os, (gpointer)value);
+ }
+ if (ids_os->len == 0)
+ return NULL;
+ g_ptr_array_add(ids_os, NULL);
+ return g_strjoinv(" ", (gchar **)ids_os->pdata);
+}
+
+/**
+ * fwupd_build_user_agent_system: (skip):
+ **/
+gchar *
+fwupd_build_user_agent_system(void)
+{
+#ifdef HAVE_UTSNAME_H
+ struct utsname name_tmp;
+#endif
+ 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" */
+#ifdef HAVE_UTSNAME_H
+ 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,
+ name_tmp.machine,
+ name_tmp.release));
+ }
+#endif
+
+ /* current locale, e.g. "en-gb" */
+#ifdef HAVE_LC_MESSAGES
+ locale = g_strdup(setlocale(LC_MESSAGES, NULL));
+#endif
+ if (locale != NULL) {
+ g_strdelimit(locale, ".", '\0');
+ g_strdelimit(locale, "_", '-');
+ g_ptr_array_add(ids, g_steal_pointer(&locale));
+ }
+
+ /* OS release, e.g. "Fedora 27 Workstation" */
+ os_release = fwupd_build_user_agent_os_release();
+ if (os_release != NULL)
+ g_ptr_array_add(ids, g_steal_pointer(&os_release));
+
+ /* convert to string */
+ if (ids->len == 0)
+ return NULL;
+ g_ptr_array_add(ids, NULL);
+ return g_strjoinv("; ", (gchar **)ids->pdata);
+}
+
+/**
+ * fwupd_build_user_agent:
+ * @package_name: (not nullable): client program name, e.g. `gnome-software`
+ * @package_version: (not nullable): client program version, e.g. `3.28.1`
+ *
+ * Builds a user-agent to use for the download.
+ *
+ * Supplying harmless details to the server means it knows more about each
+ * client. This allows the web service to respond in a different way, for
+ * instance sending a different metadata file for old versions of fwupd, or
+ * returning an error for Solaris machines.
+ *
+ * Before freaking out about theoretical privacy implications, much more data
+ * than this is sent to each and every website you visit.
+ *
+ * Rather that using this function you should use [method@Client.set_user_agent_for_package]
+ * which uses the *runtime* version of the daemon rather than the *build-time*
+ * version.
+ *
+ * Returns: a string, e.g. `foo/0.1 (Linux i386 4.14.5; en; Fedora 27) fwupd/1.0.3`
+ *
+ * Since: 1.0.3
+ **/
+gchar *
+fwupd_build_user_agent(const gchar *package_name, const gchar *package_version)
+{
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_autofree gchar *system = NULL;
+
+ g_return_val_if_fail(package_name != NULL, NULL);
+ g_return_val_if_fail(package_version != NULL, NULL);
+
+ /* application name and version */
+ g_string_append_printf(str, "%s/%s", package_name, package_version);
+
+ /* system information */
+ system = fwupd_build_user_agent_system();
+ if (system != NULL)
+ g_string_append_printf(str, " (%s)", system);
+
+ /* platform, which in our case is just fwupd */
+ if (g_strcmp0(package_name, "fwupd") != 0)
+ g_string_append_printf(str, " fwupd/%s", PACKAGE_VERSION);
+
+ /* success */
+ return g_string_free(g_steal_pointer(&str), FALSE);
+}
+
+/**
+ * fwupd_build_machine_id:
+ * @salt: (nullable): optional salt
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets a salted hash of the /etc/machine-id contents. This can be used to
+ * identify a specific machine. It is not possible to recover the original
+ * machine-id from the machine-hash.
+ *
+ * Returns: the SHA256 machine hash, or %NULL if the ID is not present
+ *
+ * Since: 1.0.4
+ **/
+gchar *
+fwupd_build_machine_id(const gchar *salt, GError **error)
+{
+ const gchar *fn = NULL;
+ g_autofree gchar *buf = NULL;
+ g_auto(GStrv) fns = g_new0(gchar *, 6);
+ g_autoptr(GChecksum) csum = NULL;
+ gsize sz = 0;
+
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* one of these has to exist */
+ fns[0] = g_build_filename(FWUPD_SYSCONFDIR, "machine-id", NULL);
+ fns[1] = g_build_filename(FWUPD_LOCALSTATEDIR, "lib", "dbus", "machine-id", NULL);
+ fns[2] = g_strdup("/etc/machine-id");
+ fns[3] = g_strdup("/var/lib/dbus/machine-id");
+ fns[4] = g_strdup("/var/db/dbus/machine-id");
+ for (guint i = 0; fns[i] != NULL; i++) {
+ if (g_file_test(fns[i], G_FILE_TEST_EXISTS)) {
+ fn = fns[i];
+ break;
+ }
+ }
+ if (fn == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_READ,
+ "The machine-id is not present");
+ return NULL;
+ }
+ if (!g_file_get_contents(fn, &buf, &sz, error))
+ return NULL;
+ if (sz == 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_READ,
+ "The machine-id is present but unset");
+ return NULL;
+ }
+ csum = g_checksum_new(G_CHECKSUM_SHA256);
+ if (salt != NULL)
+ g_checksum_update(csum, (const guchar *)salt, (gssize)strlen(salt));
+ g_checksum_update(csum, (const guchar *)buf, (gssize)sz);
+ return g_strdup(g_checksum_get_string(csum));
+}
+
+static void
+fwupd_build_history_report_json_metadata_device(JsonBuilder *builder, FwupdDevice *dev)
+{
+ FwupdRelease *rel = fwupd_device_get_release_default(dev);
+ GHashTable *metadata = fwupd_release_get_metadata(rel);
+ g_autoptr(GList) keys = NULL;
+
+ /* add each metadata value */
+ keys = g_hash_table_get_keys(metadata);
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *key = l->data;
+ const gchar *value = g_hash_table_lookup(metadata, key);
+ json_builder_set_member_name(builder, key);
+ json_builder_add_string_value(builder, value);
+ }
+}
+
+static void
+fwupd_build_history_report_json_device(JsonBuilder *builder, FwupdDevice *dev)
+{
+ FwupdRelease *rel = fwupd_device_get_release_default(dev);
+ GChecksumType checksum_types[] = {G_CHECKSUM_SHA256, G_CHECKSUM_SHA1, 0};
+ GPtrArray *checksums;
+ GPtrArray *guids;
+
+ /* identify the firmware used */
+ checksums = fwupd_release_get_checksums(rel);
+ for (guint i = 0; checksum_types[i] != 0; i++) {
+ const gchar *checksum = fwupd_checksum_get_by_kind(checksums, checksum_types[i]);
+ if (checksum != NULL) {
+ json_builder_set_member_name(builder, "Checksum");
+ json_builder_add_string_value(builder, checksum);
+ break;
+ }
+ }
+
+ /* 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);
+ }
+
+ /* allow matching the specific component */
+ json_builder_set_member_name(builder, "ReleaseId");
+ json_builder_add_string_value(builder, fwupd_release_get_id(rel));
+
+ /* 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));
+ if (fwupd_device_get_update_error(dev) != NULL) {
+ 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 */
+ guids = fwupd_device_get_guids(dev);
+ if (guids->len > 0) {
+ json_builder_set_member_name(builder, "Guid");
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < guids->len; i++) {
+ const gchar *guid = g_ptr_array_index(guids, i);
+ json_builder_add_string_value(builder, guid);
+ }
+ json_builder_end_array(builder);
+ }
+
+ json_builder_set_member_name(builder, "Plugin");
+ json_builder_add_string_value(builder, fwupd_device_get_plugin(dev));
+
+ /* report what we're trying to update *from* and *to* */
+ json_builder_set_member_name(builder, "VersionOld");
+ json_builder_add_string_value(builder, fwupd_device_get_version(dev));
+ json_builder_set_member_name(builder, "VersionNew");
+ json_builder_add_string_value(builder, fwupd_release_get_version(rel));
+
+ /* to know the state of the dev we're trying to update */
+ json_builder_set_member_name(builder, "Flags");
+ json_builder_add_int_value(builder, fwupd_device_get_flags(dev));
+
+ /* to know when the update tried to happen, and how soon after boot */
+ json_builder_set_member_name(builder, "Created");
+ json_builder_add_int_value(builder, fwupd_device_get_created(dev));
+ json_builder_set_member_name(builder, "Modified");
+ json_builder_add_int_value(builder, fwupd_device_get_modified(dev));
+
+ /* add saved metadata to the report */
+ json_builder_set_member_name(builder, "Metadata");
+ json_builder_begin_object(builder);
+ fwupd_build_history_report_json_metadata_device(builder, dev);
+ json_builder_end_object(builder);
+}
+
+static gboolean
+fwupd_build_history_report_json_metadata(JsonBuilder *builder, GError **error)
+{
+ g_autoptr(GHashTable) hash = NULL;
+ struct {
+ const gchar *key;
+ const gchar *val;
+ } distro_kv[] = {{"ID", "DistroId"},
+ {"VERSION_ID", "DistroVersion"},
+ {"VARIANT_ID", "DistroVariant"},
+ {NULL, NULL}};
+
+ /* get all required os-release keys */
+ hash = fwupd_get_os_release(error);
+ if (hash == NULL)
+ return FALSE;
+ for (guint i = 0; distro_kv[i].key != NULL; i++) {
+ const gchar *tmp = g_hash_table_lookup(hash, distro_kv[i].key);
+ if (tmp != NULL) {
+ json_builder_set_member_name(builder, distro_kv[i].val);
+ json_builder_add_string_value(builder, tmp);
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * fwupd_build_history_report_json:
+ * @devices: (element-type FwupdDevice): devices
+ * @error: (nullable): optional return location for an error
+ *
+ * Builds a JSON report for the list of devices. No filtering is done on the
+ * @devices array, and it is expected that the caller will filter to something
+ * sane, e.g. %FWUPD_DEVICE_FLAG_REPORTED at the bare minimum.
+ *
+ * Returns: a string, or %NULL if the ID is not present
+ *
+ * Since: 1.0.4
+ **/
+gchar *
+fwupd_build_history_report_json(GPtrArray *devices, GError **error)
+{
+ gchar *data;
+ g_autofree gchar *machine_id = NULL;
+ g_autoptr(JsonBuilder) builder = NULL;
+ g_autoptr(JsonGenerator) json_generator = NULL;
+ g_autoptr(JsonNode) json_root = NULL;
+
+ g_return_val_if_fail(devices != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* get a hash that represents the machine */
+ machine_id = fwupd_build_machine_id("fwupd", error);
+ if (machine_id == NULL)
+ return NULL;
+
+ /* create header */
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+ json_builder_set_member_name(builder, "ReportVersion");
+ json_builder_add_int_value(builder, 2);
+ json_builder_set_member_name(builder, "MachineId");
+ json_builder_add_string_value(builder, machine_id);
+
+ /* this is system metadata not stored in the database */
+ json_builder_set_member_name(builder, "Metadata");
+ json_builder_begin_object(builder);
+ if (!fwupd_build_history_report_json_metadata(builder, error))
+ return NULL;
+ json_builder_end_object(builder);
+
+ /* add each device */
+ json_builder_set_member_name(builder, "Reports");
+ 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_build_history_report_json_device(builder, dev);
+ 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);
+ 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 NULL;
+ }
+ 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: GUID flags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN
+ *
+ * Returns a text GUID of mixed or BE endian for a packed buffer.
+ *
+ * Returns: a new GUID string
+ *
+ * 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",
+ (guint)GUINT32_FROM_LE(gnat.a),
+ (guint)GUINT16_FROM_LE(gnat.b),
+ (guint)GUINT16_FROM_LE(gnat.c),
+ (guint)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",
+ (guint)GUINT32_FROM_BE(gnat.a),
+ (guint)GUINT16_FROM_BE(gnat.b),
+ (guint)GUINT16_FROM_BE(gnat.c),
+ (guint)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: (not nullable): a GUID, e.g. `00112233-4455-6677-8899-aabbccddeeff`
+ * @guid: (nullable): a #fwupd_guid_t, or NULL to just check the GUID
+ * @flags: GUID flags, e.g. %FWUPD_GUID_FLAG_MIXED_ENDIAN
+ * @error: (nullable): optional return location for an error
+ *
+ * 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);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* split into sections */
+ if (strlen(guidstr) != 36) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "GUID 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,
+ "GUID 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,
+ "GUID 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: GUID flags, 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)
+{
+ gsize digestlen = 20;
+ guint8 hash[20];
+ fwupd_guid_t uu_new;
+ g_autoptr(GChecksum) csum = NULL;
+ const fwupd_guid_t uu_default = {0x6b,
+ 0xa7,
+ 0xb8,
+ 0x10,
+ 0x9d,
+ 0xad,
+ 0x11,
+ 0xd1,
+ 0x80,
+ 0xb4,
+ 0x00,
+ 0xc0,
+ 0x4f,
+ 0xd4,
+ 0x30,
+ 0xc8};
+ const fwupd_guid_t uu_microso = {0x70, 0xff, 0xd8, 0x12, 0x4c, 0x7f, 0x4c, 0x7d};
+ const fwupd_guid_t *uu_namespace = &uu_default;
+
+ 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)
+ uu_namespace = &uu_microso;
+
+ /* 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_device_id_is_valid:
+ * @device_id: string to check, e.g. `d3fae86d95e5d56626129d00e332c4b8dac95442`
+ *
+ * Checks the string is a valid non-partial device ID. It is important to note
+ * that the wildcard ID of `*` is not considered a valid ID in this function and
+ * the client must check for this manually if this should be allowed.
+ *
+ * Returns: %TRUE if @guid was a fwupd device ID, %FALSE otherwise
+ *
+ * Since: 1.4.1
+ **/
+gboolean
+fwupd_device_id_is_valid(const gchar *device_id)
+{
+ if (device_id == NULL)
+ return FALSE;
+ if (strlen(device_id) != 40)
+ return FALSE;
+ for (guint i = 0; device_id[i] != '\0'; i++) {
+ gchar tmp = device_id[i];
+ /* isalnum isn't case specific */
+ if ((tmp < 'a' || tmp > 'f') && (tmp < '0' || tmp > '9'))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * 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)
+{
+ const gchar zeroguid[] = {"00000000-0000-0000-0000-000000000000"};
+
+ /* sanity check */
+ if (guid == NULL)
+ return FALSE;
+
+ /* check for dashes and hexdigits in the right place */
+ for (guint i = 0; i < sizeof(zeroguid) - 1; i++) {
+ if (guid[i] == '\0')
+ return FALSE;
+ if (zeroguid[i] == '-') {
+ if (guid[i] != '-')
+ return FALSE;
+ continue;
+ }
+ if (!g_ascii_isxdigit(guid[i]))
+ return FALSE;
+ }
+
+ /* longer than required */
+ if (guid[sizeof(zeroguid) - 1] != '\0')
+ return FALSE;
+
+ /* not valid */
+ return g_strcmp0(guid, zeroguid) != 0;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * fwupd_hash_kv_to_variant: (skip):
+ **/
+GVariant *
+fwupd_hash_kv_to_variant(GHashTable *hash)
+{
+ GVariantBuilder builder;
+ g_autoptr(GList) keys = g_hash_table_get_keys(hash);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *key = l->data;
+ const gchar *value = g_hash_table_lookup(hash, key);
+ g_variant_builder_add(&builder, "{ss}", key, value);
+ }
+ return g_variant_builder_end(&builder);
+}
+
+/**
+ * fwupd_variant_to_hash_kv: (skip):
+ **/
+GHashTable *
+fwupd_variant_to_hash_kv(GVariant *dict)
+{
+ GHashTable *hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ GVariantIter iter;
+ const gchar *key;
+ const gchar *value;
+ g_variant_iter_init(&iter, dict);
+ while (g_variant_iter_loop(&iter, "{&s&s}", &key, &value))
+ g_hash_table_insert(hash, g_strdup(key), g_strdup(value));
+ return hash;
+}
+
+static void
+fwupd_input_stream_read_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ GByteArray *bufarr;
+ GInputStream *stream = G_INPUT_STREAM(source);
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = G_TASK(user_data);
+#if GLIB_CHECK_VERSION(2, 64, 0)
+ guint8 *buf;
+ gsize bufsz = 0;
+#endif
+
+ /* read buf */
+ bytes = g_input_stream_read_bytes_finish(stream, res, &error);
+ if (bytes == NULL) {
+ g_task_return_error(task, g_steal_pointer(&error));
+ return;
+ }
+
+ /* add bytes to buffer */
+ bufarr = g_task_get_task_data(task);
+ if (g_bytes_get_size(bytes) > 0) {
+ GCancellable *cancellable = g_task_get_cancellable(task);
+ g_debug("add %u", (guint)g_bytes_get_size(bytes));
+ g_byte_array_append(bufarr, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes));
+ g_input_stream_read_bytes_async(g_steal_pointer(&stream),
+ 256 * 1024, /* bigger chunk */
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ fwupd_input_stream_read_bytes_cb,
+ g_steal_pointer(&task));
+ return;
+ }
+
+ /* success */
+#if GLIB_CHECK_VERSION(2, 64, 0)
+ buf = g_byte_array_steal(bufarr, &bufsz);
+ g_task_return_pointer(task, g_bytes_new_take(buf, bufsz), (GDestroyNotify)g_bytes_unref);
+#else
+ g_task_return_pointer(task,
+ g_bytes_new(bufarr->data, bufarr->len),
+ (GDestroyNotify)g_bytes_unref);
+#endif
+}
+
+/**
+ * fwupd_input_stream_read_bytes_async: (skip):
+ **/
+void
+fwupd_input_stream_read_bytes_async(GInputStream *stream,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer callback_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail(G_IS_INPUT_STREAM(stream));
+ g_return_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable));
+
+ task = g_task_new(stream, cancellable, callback, callback_data);
+ g_task_set_task_data(task, g_byte_array_new(), (GDestroyNotify)g_byte_array_unref);
+ g_input_stream_read_bytes_async(stream,
+ 64 * 1024, /* small */
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ fwupd_input_stream_read_bytes_cb,
+ g_steal_pointer(&task));
+}
+
+/**
+ * fwupd_input_stream_read_bytes_finish: (skip):
+ **/
+GBytes *
+fwupd_input_stream_read_bytes_finish(GInputStream *stream, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(G_IS_INPUT_STREAM(stream), NULL);
+ g_return_val_if_fail(g_task_is_valid(res, stream), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return g_task_propagate_pointer(G_TASK(res), error);
+}
+
+#ifdef HAVE_GIO_UNIX
+/**
+ * fwupd_unix_input_stream_from_bytes: (skip):
+ **/
+GUnixInputStream *
+fwupd_unix_input_stream_from_bytes(GBytes *bytes, GError **error)
+{
+ gint fd;
+ gssize rc;
+#ifndef HAVE_MEMFD_CREATE
+ gchar tmp_file[] = "/tmp/fwupd.XXXXXX";
+#endif
+
+#ifdef HAVE_MEMFD_CREATE
+ fd = memfd_create("fwupd", MFD_CLOEXEC);
+#else
+ /* emulate in-memory file by an unlinked temporary file */
+ fd = g_mkstemp(tmp_file);
+ if (fd != -1) {
+ rc = g_unlink(tmp_file);
+ if (rc != 0) {
+ if (!g_close(fd, error)) {
+ g_prefix_error(error, "failed to close temporary file: ");
+ return NULL;
+ }
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to unlink temporary file");
+ return NULL;
+ }
+ }
+#endif
+
+ if (fd < 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to create memfd");
+ return NULL;
+ }
+ rc = write(fd, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes));
+ if (rc < 0) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to write %" G_GSSIZE_FORMAT,
+ rc);
+ return NULL;
+ }
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "failed to seek: %s",
+ g_strerror(errno));
+ return NULL;
+ }
+ return G_UNIX_INPUT_STREAM(g_unix_input_stream_new(fd, TRUE));
+}
+
+/**
+ * fwupd_unix_input_stream_from_fn: (skip):
+ **/
+GUnixInputStream *
+fwupd_unix_input_stream_from_fn(const gchar *fn, GError **error)
+{
+ gint fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", fn);
+ return NULL;
+ }
+ return G_UNIX_INPUT_STREAM(g_unix_input_stream_new(fd, TRUE));
+}
+#endif
+
+/**
+ * fwupd_common_json_add_string: (skip):
+ **/
+void
+fwupd_common_json_add_string(JsonBuilder *builder, const gchar *key, const gchar *value)
+{
+ if (value == NULL)
+ return;
+ json_builder_set_member_name(builder, key);
+ json_builder_add_string_value(builder, value);
+}
+
+/**
+ * fwupd_common_json_add_int: (skip):
+ **/
+void
+fwupd_common_json_add_int(JsonBuilder *builder, const gchar *key, guint64 value)
+{
+ json_builder_set_member_name(builder, key);
+ json_builder_add_int_value(builder, value);
+}
+
+/**
+ * fwupd_common_json_add_boolean: (skip):
+ **/
+void
+fwupd_common_json_add_boolean(JsonBuilder *builder, const gchar *key, gboolean value)
+{
+ json_builder_set_member_name(builder, key);
+ json_builder_add_string_value(builder, value ? "true" : "false");
+}
+
+/**
+ * fwupd_common_json_add_stringv: (skip):
+ **/
+void
+fwupd_common_json_add_stringv(JsonBuilder *builder, const gchar *key, gchar **value)
+{
+ if (value == NULL)
+ return;
+ json_builder_set_member_name(builder, key);
+ json_builder_begin_array(builder);
+ for (guint i = 0; value[i] != NULL; i++)
+ json_builder_add_string_value(builder, value[i]);
+ json_builder_end_array(builder);
+}
+
+/**
+ * fwupd_pad_kv_str: (skip):
+ **/
+void
+fwupd_pad_kv_str(GString *str, const gchar *key, const gchar *value)
+{
+ /* ignore */
+ if (key == NULL || value == NULL)
+ return;
+ g_string_append_printf(str, " %s: ", key);
+ for (gsize i = strlen(key); i < 20; i++)
+ g_string_append(str, " ");
+ g_string_append_printf(str, "%s\n", value);
+}
+
+/**
+ * fwupd_pad_kv_unx: (skip):
+ **/
+void
+fwupd_pad_kv_unx(GString *str, const gchar *key, guint64 value)
+{
+ g_autoptr(GDateTime) date = NULL;
+ g_autofree gchar *tmp = NULL;
+
+ /* ignore */
+ if (value == 0)
+ return;
+
+ date = g_date_time_new_from_unix_utc((gint64)value);
+ tmp = g_date_time_format(date, "%F");
+ fwupd_pad_kv_str(str, key, tmp);
+}
+
+/**
+ * fwupd_pad_kv_int: (skip):
+ **/
+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);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-common.h b/fwupd-1.8.6/libfwupd/fwupd-common.h
new file mode 100644
index 0000000000000000000000000000000000000000..ede9ce69755d91a89777b5a25bf35a1241f565f2
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-common.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+/**
+ * FWUPD_DBUS_PATH:
+ *
+ * The dbus path
+ **/
+#define FWUPD_DBUS_PATH "/"
+/**
+ * FWUPD_DBUS_SERVICE:
+ *
+ * The dbus service
+ **/
+#define FWUPD_DBUS_SERVICE "org.freedesktop.fwupd"
+/**
+ * FWUPD_DBUS_INTERFACE:
+ *
+ * The dbus interface
+ **/
+#define FWUPD_DBUS_INTERFACE "org.freedesktop.fwupd"
+/**
+ * FWUPD_DBUS_P2P_SOCKET_ADDRESS:
+ *
+ * The D-Bus socket address when using point-to-point connections.
+ **/
+#define FWUPD_DBUS_P2P_SOCKET_ADDRESS "tcp:host=localhost,port=1341"
+
+/**
+ * FWUPD_DEVICE_ID_ANY:
+ *
+ * Wildcard used for matching all device ids in 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);
+GChecksumType
+fwupd_checksum_guess_kind(const gchar *checksum);
+gchar *
+fwupd_checksum_format_for_display(const gchar *checksum);
+gchar *
+fwupd_build_user_agent(const gchar *package_name, const gchar *package_version)
+ G_DEPRECATED_FOR(fwupd_client_set_user_agent_for_package);
+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);
+gboolean
+fwupd_device_id_is_valid(const gchar *device_id);
+#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);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-context-test.c b/fwupd-1.8.6/libfwupd/fwupd-context-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..54126cf18bd6c47a7dc4e41276180651e6e8c77f
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-context-test.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 Philip Withnall
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include
+
+typedef struct {
+ GApplication *app;
+ FwupdClient *client;
+ GThread *main_thread;
+ GThread *worker_thread;
+} FuThreadTestSelf;
+
+static gboolean
+fwupd_thread_test_exit_idle_cb(gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_application_release(self->app);
+ return G_SOURCE_REMOVE;
+}
+
+static gpointer
+fwupd_thread_test_thread_cb(gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GMainContext) context = g_main_context_new();
+ g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new(context);
+
+ g_assert_nonnull(pusher);
+ g_message("Calling fwupd_client_get_devices() in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+ if (!fwupd_client_connect(self->client, NULL, &error_local))
+ g_warning("%s", error_local->message);
+ g_idle_add(fwupd_thread_test_exit_idle_cb, self);
+ return NULL;
+}
+
+static gboolean
+fwupd_thread_test_idle_cb(gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_message("fwupd_thread_test_idle_cb() in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+ self->worker_thread = g_thread_new("worker00", fwupd_thread_test_thread_cb, self);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+fwupd_thread_test_activate_cb(GApplication *app, gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_application_hold(self->app);
+ g_idle_add(fwupd_thread_test_idle_cb, self);
+}
+
+static void
+fwupd_thread_test_notify_cb(GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_message("fwupd_thread_test_notify_cb() in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+ g_assert_true(g_thread_self() == self->main_thread);
+ g_assert_null(g_main_context_get_thread_default());
+}
+
+static gboolean
+fwupd_thread_test_has_system_bus(void)
+{
+ g_autoptr(GDBusConnection) conn = NULL;
+ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+ return conn != NULL;
+}
+
+int
+main(void)
+{
+ gint retval;
+ g_autoptr(FwupdClient) client = fwupd_client_new();
+ g_autoptr(GApplication) app =
+ g_application_new("org.fwupd.ContextTest", G_APPLICATION_NON_UNIQUE);
+ g_autoptr(GThread) worker_thread = NULL;
+ FuThreadTestSelf self = {
+ .app = app,
+ .client = client,
+ .worker_thread = worker_thread,
+ .main_thread = g_thread_self(),
+ };
+
+ /* only some of the CI targets have a DBus daemon */
+ if (!fwupd_thread_test_has_system_bus()) {
+ g_message("D-Bus system bus unavailable, skipping tests.");
+ return 0;
+ }
+ g_message("Created FwupdClient in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+ g_signal_connect(FWUPD_CLIENT(client),
+ "notify::status",
+ G_CALLBACK(fwupd_thread_test_notify_cb),
+ &self);
+ g_signal_connect(G_APPLICATION(app),
+ "activate",
+ G_CALLBACK(fwupd_thread_test_activate_cb),
+ &self);
+ retval = g_application_run(app, 0, NULL);
+ if (self.worker_thread != NULL)
+ g_thread_join(g_steal_pointer(&self.worker_thread));
+
+ return retval;
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-deprecated.h b/fwupd-1.8.6/libfwupd/fwupd-deprecated.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3671517a3f4125927ea8d6644c498e100b5067b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-deprecated.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+G_BEGIN_DECLS
+
+/* indeed, nothing */
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-device-private.h b/fwupd-1.8.6/libfwupd/fwupd-device-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fe7b2dff9cd8455cf6d18d3cd49e92055c497e4
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-device-private.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-device.h"
+
+G_BEGIN_DECLS
+
+GVariant *
+fwupd_device_to_variant(FwupdDevice *self);
+GVariant *
+fwupd_device_to_variant_full(FwupdDevice *self, FwupdDeviceFlags flags);
+void
+fwupd_device_incorporate(FwupdDevice *self, FwupdDevice *donor);
+void
+fwupd_device_to_json(FwupdDevice *self, JsonBuilder *builder);
+void
+fwupd_device_to_json_full(FwupdDevice *self, JsonBuilder *builder, FwupdDeviceFlags flags);
+gboolean
+fwupd_device_from_json(FwupdDevice *self, JsonNode *json_node, GError **error);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-device.c b/fwupd-1.8.6/libfwupd/fwupd-device.c
new file mode 100644
index 0000000000000000000000000000000000000000..735a3492702df704e9ef6ee88c472777a66b2d34
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-device.c
@@ -0,0 +1,4028 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+#include
+
+#include "fwupd-common-private.h"
+#include "fwupd-device-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-error.h"
+#include "fwupd-release-private.h"
+
+/**
+ * FwupdDevice:
+ *
+ * A physical device on the host with optionally updatable firmware.
+ *
+ * See also: [class@FwupdRelease]
+ */
+
+static void
+fwupd_device_finalize(GObject *object);
+
+typedef struct {
+ gchar *id;
+ gchar *parent_id;
+ gchar *composite_id;
+ guint64 created;
+ guint64 modified;
+ guint64 flags;
+ guint64 problems;
+ GPtrArray *guids;
+ GPtrArray *vendor_ids;
+ GPtrArray *protocols;
+ GPtrArray *instance_ids;
+ GPtrArray *icons;
+ GPtrArray *issues; /* of utf-8 */
+ gchar *name;
+ gchar *serial;
+ gchar *summary;
+ gchar *branch;
+ gchar *description;
+ gchar *vendor;
+ gchar *vendor_id; /* for compat only */
+ gchar *homepage;
+ gchar *plugin;
+ gchar *protocol;
+ gchar *version;
+ gchar *version_lowest;
+ gchar *version_bootloader;
+ FwupdVersionFormat version_format;
+ guint64 version_raw;
+ guint64 version_build_date;
+ guint64 version_lowest_raw;
+ guint64 version_bootloader_raw;
+ GPtrArray *checksums;
+ GPtrArray *children;
+ guint32 flashes_left;
+ guint32 battery_level;
+ guint32 battery_threshold;
+ guint32 install_duration;
+ FwupdUpdateState update_state;
+ gchar *update_error;
+ gchar *update_message;
+ gchar *update_image;
+ FwupdStatus status;
+ GPtrArray *releases;
+ FwupdDevice *parent; /* noref */
+} FwupdDevicePrivate;
+
+enum {
+ PROP_0,
+ PROP_VERSION_FORMAT,
+ PROP_FLAGS,
+ PROP_PROTOCOL,
+ PROP_STATUS,
+ PROP_PARENT,
+ PROP_UPDATE_STATE,
+ PROP_UPDATE_MESSAGE,
+ PROP_UPDATE_ERROR,
+ PROP_UPDATE_IMAGE,
+ PROP_BATTERY_LEVEL,
+ PROP_BATTERY_THRESHOLD,
+ PROP_PROBLEMS,
+ PROP_LAST
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdDevice, fwupd_device, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_device_get_instance_private(o))
+
+#define FWUPD_BATTERY_THRESHOLD_DEFAULT 10 /* % */
+
+/**
+ * fwupd_device_get_checksums:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device checksums.
+ *
+ * Returns: (element-type utf8) (transfer none): the checksums, which may be empty
+ *
+ * Since: 0.9.3
+ **/
+GPtrArray *
+fwupd_device_get_checksums(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->checksums;
+}
+
+/**
+ * fwupd_device_add_checksum:
+ * @self: a #FwupdDevice
+ * @checksum: (not nullable): the device checksum
+ *
+ * Adds a device checksum.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_add_checksum(FwupdDevice *self, const gchar *checksum)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(checksum != NULL);
+ 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;
+ }
+ g_ptr_array_add(priv->checksums, g_strdup(checksum));
+}
+
+/**
+ * fwupd_device_get_issues:
+ * @self: a #FwupdDevice
+ *
+ * Gets the list of issues currently affecting this device.
+ *
+ * Returns: (element-type utf8) (transfer none): the issues, which may be empty
+ *
+ * Since: 1.7.6
+ **/
+GPtrArray *
+fwupd_device_get_issues(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->issues;
+}
+
+/**
+ * fwupd_device_add_issue:
+ * @self: a #FwupdDevice
+ * @issue: (not nullable): the update issue, e.g. `CVE-2019-12345`
+ *
+ * Adds an current issue to this device.
+ *
+ * Since: 1.7.6
+ **/
+void
+fwupd_device_add_issue(FwupdDevice *self, const gchar *issue)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(issue != NULL);
+ for (guint i = 0; i < priv->issues->len; i++) {
+ const gchar *issue_tmp = g_ptr_array_index(priv->issues, i);
+ if (g_strcmp0(issue_tmp, issue) == 0)
+ return;
+ }
+ g_ptr_array_add(priv->issues, g_strdup(issue));
+}
+
+/**
+ * fwupd_device_get_children:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device children. These can only be assigned using fwupd_device_set_parent().
+ *
+ * Returns: (element-type FwupdDevice) (transfer none): the children, which may be empty
+ *
+ * Since: 1.3.7
+ **/
+GPtrArray *
+fwupd_device_get_children(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->children;
+}
+
+/**
+ * fwupd_device_get_summary:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device summary.
+ *
+ * Returns: the device summary, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_summary(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->summary;
+}
+
+/**
+ * fwupd_device_set_summary:
+ * @self: a #FwupdDevice
+ * @summary: (nullable): the device one line summary
+ *
+ * Sets the device summary.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_summary(FwupdDevice *self, const gchar *summary)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->summary, summary) == 0)
+ return;
+
+ g_free(priv->summary);
+ priv->summary = g_strdup(summary);
+}
+
+/**
+ * fwupd_device_get_branch:
+ * @self: a #FwupdDevice
+ *
+ * Gets the current device branch.
+ *
+ * Returns: the device branch, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_device_get_branch(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->branch;
+}
+
+/**
+ * fwupd_device_set_branch:
+ * @self: a #FwupdDevice
+ * @branch: (nullable): the device one line branch
+ *
+ * Sets the current device branch.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_device_set_branch(FwupdDevice *self, const gchar *branch)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->branch, branch) == 0)
+ return;
+
+ g_free(priv->branch);
+ priv->branch = g_strdup(branch);
+}
+
+/**
+ * fwupd_device_get_serial:
+ * @self: 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 *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->serial;
+}
+
+/**
+ * fwupd_device_set_serial:
+ * @self: a #FwupdDevice
+ * @serial: (nullable): the device serial number
+ *
+ * Sets the serial number for the device.
+ *
+ * Since: 1.1.2
+ **/
+void
+fwupd_device_set_serial(FwupdDevice *self, const gchar *serial)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->serial, serial) == 0)
+ return;
+
+ g_free(priv->serial);
+ priv->serial = g_strdup(serial);
+}
+
+/**
+ * fwupd_device_get_id:
+ * @self: a #FwupdDevice
+ *
+ * Gets the ID.
+ *
+ * Returns: the ID, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_id(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->id;
+}
+
+/**
+ * fwupd_device_set_id:
+ * @self: a #FwupdDevice
+ * @id: (nullable): the device ID, e.g. `USB:foo`
+ *
+ * Sets the ID.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_id(FwupdDevice *self, const gchar *id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->id, id) == 0)
+ return;
+
+ g_free(priv->id);
+ priv->id = g_strdup(id);
+}
+
+/**
+ * fwupd_device_get_parent_id:
+ * @self: a #FwupdDevice
+ *
+ * Gets the parent ID.
+ *
+ * Returns: the parent ID, or %NULL if unset
+ *
+ * Since: 1.0.8
+ **/
+const gchar *
+fwupd_device_get_parent_id(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->parent_id;
+}
+
+/**
+ * fwupd_device_set_parent_id:
+ * @self: a #FwupdDevice
+ * @parent_id: (nullable): the device ID, e.g. `USB:foo`
+ *
+ * Sets the parent ID.
+ *
+ * Since: 1.0.8
+ **/
+void
+fwupd_device_set_parent_id(FwupdDevice *self, const gchar *parent_id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->parent_id, parent_id) == 0)
+ return;
+
+ g_free(priv->parent_id);
+ priv->parent_id = g_strdup(parent_id);
+}
+
+/**
+ * fwupd_device_get_composite_id:
+ * @self: a #FwupdDevice
+ *
+ * Gets the composite ID, falling back to the device ID if unset.
+ *
+ * The composite ID will be the same value for all parent, child and sibling
+ * devices.
+ *
+ * Returns: (nullable): the composite ID
+ *
+ * Since: 1.6.0
+ **/
+const gchar *
+fwupd_device_get_composite_id(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ if (priv->composite_id != NULL)
+ return priv->composite_id;
+ return priv->id;
+}
+
+/**
+ * fwupd_device_set_composite_id:
+ * @self: a #FwupdDevice
+ * @composite_id: (nullable): a device ID
+ *
+ * Sets the composite ID, which is usually a SHA1 hash of a grandparent or
+ * parent device.
+ *
+ * Since: 1.6.0
+ **/
+void
+fwupd_device_set_composite_id(FwupdDevice *self, const gchar *composite_id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->composite_id, composite_id) == 0)
+ return;
+
+ g_free(priv->composite_id);
+ priv->composite_id = g_strdup(composite_id);
+}
+
+/**
+ * fwupd_device_get_parent:
+ * @self: 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 *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->parent;
+}
+
+/**
+ * fwupd_device_get_root:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device root.
+ *
+ * Returns: (transfer none): the root device, or %NULL if unset
+ *
+ * Since: 1.7.4
+ **/
+FwupdDevice *
+fwupd_device_get_root(FwupdDevice *self)
+{
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ while (1) {
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ if (priv->parent == NULL)
+ break;
+ self = priv->parent;
+ }
+ return self;
+}
+
+/**
+ * fwupd_device_set_parent:
+ * @self: a #FwupdDevice
+ * @parent: (nullable): another #FwupdDevice
+ *
+ * Sets the parent. Only used internally.
+ *
+ * Since: 1.0.8
+ **/
+void
+fwupd_device_set_parent(FwupdDevice *self, FwupdDevice *parent)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(self != parent);
+
+ if (priv->parent != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->parent), (gpointer *)&priv->parent);
+ if (parent != NULL)
+ 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(self, parent != NULL ? fwupd_device_get_id(parent) : NULL);
+}
+
+static void
+fwupd_device_child_finalized_cb(gpointer data, GObject *where_the_object_was)
+{
+ FwupdDevice *self = FWUPD_DEVICE(data);
+ g_critical("FuDevice child %p was finalized while still having parent %s [%s]!",
+ where_the_object_was,
+ fwupd_device_get_name(self),
+ fwupd_device_get_id(self));
+}
+
+/**
+ * fwupd_device_add_child:
+ * @self: a #FwupdDevice
+ * @child: Another #FwupdDevice
+ *
+ * Adds a child device. An child device is logically linked to the primary
+ * device in some way.
+ *
+ * NOTE: You should never call this function from user code, it is for daemon
+ * use only. Only use fwupd_device_set_parent() to set up a logical tree.
+ *
+ * Since: 1.5.1
+ **/
+void
+fwupd_device_add_child(FwupdDevice *self, FwupdDevice *child)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(FWUPD_IS_DEVICE(child));
+ g_return_if_fail(self != child);
+
+ /* add if the child does not already exist */
+ for (guint i = 0; i < priv->children->len; i++) {
+ FwupdDevice *devtmp = g_ptr_array_index(priv->children, i);
+ if (devtmp == child)
+ return;
+ }
+ g_object_weak_ref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
+ g_ptr_array_add(priv->children, g_object_ref(child));
+}
+
+/**
+ * fwupd_device_remove_child:
+ * @self: a #FwupdDevice
+ * @child: Another #FwupdDevice
+ *
+ * Removes a child device.
+ *
+ * NOTE: You should never call this function from user code, it is for daemon
+ * use only.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_device_remove_child(FwupdDevice *self, FwupdDevice *child)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ /* remove if the child exists */
+ for (guint i = 0; i < priv->children->len; i++) {
+ FwupdDevice *child_tmp = g_ptr_array_index(priv->children, i);
+ if (child_tmp == child) {
+ g_object_weak_unref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
+ g_ptr_array_remove_index(priv->children, i);
+ return;
+ }
+ }
+}
+
+/**
+ * fwupd_device_get_guids:
+ * @self: a #FwupdDevice
+ *
+ * Gets the GUIDs.
+ *
+ * Returns: (element-type utf8) (transfer none): the GUIDs
+ *
+ * Since: 0.9.3
+ **/
+GPtrArray *
+fwupd_device_get_guids(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->guids;
+}
+
+/**
+ * fwupd_device_has_guid:
+ * @self: a #FwupdDevice
+ * @guid: (not nullable): the GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad`
+ *
+ * Finds out if the device has this specific GUID.
+ *
+ * Returns: %TRUE if the GUID is found
+ *
+ * Since: 0.9.3
+ **/
+gboolean
+fwupd_device_has_guid(FwupdDevice *self, const gchar *guid)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(guid != NULL, FALSE);
+
+ for (guint i = 0; i < priv->guids->len; i++) {
+ const gchar *guid_tmp = g_ptr_array_index(priv->guids, i);
+ if (g_strcmp0(guid, guid_tmp) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_device_add_guid:
+ * @self: a #FwupdDevice
+ * @guid: the GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad`
+ *
+ * Adds the GUID if it does not already exist.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_add_guid(FwupdDevice *self, const gchar *guid)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(guid != NULL);
+ if (fwupd_device_has_guid(self, guid))
+ return;
+ g_ptr_array_add(priv->guids, g_strdup(guid));
+}
+
+/**
+ * fwupd_device_get_guid_default:
+ * @self: a #FwupdDevice
+ *
+ * Gets the default GUID.
+ *
+ * Returns: the GUID, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_guid_default(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ if (priv->guids->len == 0)
+ return NULL;
+ return g_ptr_array_index(priv->guids, 0);
+}
+
+/**
+ * fwupd_device_get_instance_ids:
+ * @self: a #FwupdDevice
+ *
+ * Gets the instance IDs.
+ *
+ * Returns: (element-type utf8) (transfer none): the instance IDs
+ *
+ * Since: 1.2.5
+ **/
+GPtrArray *
+fwupd_device_get_instance_ids(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->instance_ids;
+}
+
+/**
+ * fwupd_device_has_instance_id:
+ * @self: a #FwupdDevice
+ * @instance_id: (not nullable): the instance ID, e.g. `PCI\VEN_10EC&DEV_525A`
+ *
+ * Finds out if the device has this specific instance ID.
+ *
+ * Returns: %TRUE if the instance ID is found
+ *
+ * Since: 1.2.5
+ **/
+gboolean
+fwupd_device_has_instance_id(FwupdDevice *self, const gchar *instance_id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(instance_id != NULL, 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:
+ * @self: a #FwupdDevice
+ * @instance_id: (not nullable): the instance ID, e.g. `PCI\VEN_10EC&DEV_525A`
+ *
+ * Adds the instance ID if it does not already exist.
+ *
+ * Since: 1.2.5
+ **/
+void
+fwupd_device_add_instance_id(FwupdDevice *self, const gchar *instance_id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(instance_id != NULL);
+ if (fwupd_device_has_instance_id(self, instance_id))
+ return;
+ g_ptr_array_add(priv->instance_ids, g_strdup(instance_id));
+}
+
+/**
+ * fwupd_device_get_icons:
+ * @self: a #FwupdDevice
+ *
+ * Gets the icon names to use for the device.
+ *
+ * NOTE: Icons specified without a full path are stock icons and should
+ * be loaded from the users icon theme.
+ *
+ * Returns: (element-type utf8) (transfer none): an array of icon names
+ *
+ * Since: 0.9.8
+ **/
+GPtrArray *
+fwupd_device_get_icons(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->icons;
+}
+
+/**
+ * fwupd_device_has_icon:
+ * @self: a #FwupdDevice
+ * @icon: the icon name, e.g. `input-mouse` or `/usr/share/icons/foo.png`
+ *
+ * Finds out if the device has this specific icon.
+ *
+ * Returns: %TRUE if the icon name is found
+ *
+ * Since: 1.6.2
+ **/
+gboolean
+fwupd_device_has_icon(FwupdDevice *self, const gchar *icon)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ for (guint i = 0; i < priv->icons->len; i++) {
+ const gchar *icon_tmp = g_ptr_array_index(priv->icons, i);
+ if (g_strcmp0(icon, icon_tmp) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_device_add_icon:
+ * @self: a #FwupdDevice
+ * @icon: (not nullable): the icon name, e.g. `input-mouse` or `/usr/share/icons/foo.png`
+ *
+ * Adds the icon name if it does not already exist.
+ *
+ * Since: 0.9.8
+ **/
+void
+fwupd_device_add_icon(FwupdDevice *self, const gchar *icon)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(icon != NULL);
+ if (fwupd_device_has_icon(self, icon))
+ return;
+ g_ptr_array_add(priv->icons, g_strdup(icon));
+}
+
+/**
+ * fwupd_device_get_name:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device name.
+ *
+ * Returns: the device name, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_name(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->name;
+}
+
+/**
+ * fwupd_device_set_name:
+ * @self: a #FwupdDevice
+ * @name: (nullable): the device name, e.g. `ColorHug2`
+ *
+ * Sets the device name.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_name(FwupdDevice *self, const gchar *name)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->name, name) == 0)
+ return;
+
+ g_free(priv->name);
+ priv->name = g_strdup(name);
+}
+
+/**
+ * fwupd_device_get_vendor:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device vendor.
+ *
+ * Returns: the device vendor, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_vendor(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->vendor;
+}
+
+/**
+ * fwupd_device_set_vendor:
+ * @self: a #FwupdDevice
+ * @vendor: (nullable): the vendor
+ *
+ * Sets the device vendor.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_vendor(FwupdDevice *self, const gchar *vendor)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->vendor, vendor) == 0)
+ return;
+
+ g_free(priv->vendor);
+ priv->vendor = g_strdup(vendor);
+}
+
+/**
+ * fwupd_device_get_vendor_id:
+ * @self: a #FwupdDevice
+ *
+ * Gets the combined device vendor ID.
+ *
+ * Returns: the device vendor, e.g. 'USB:0x1234|PCI:0x5678', or %NULL if unset
+ *
+ * Since: 0.9.4
+ *
+ * Deprecated: 1.5.5: Use fwupd_device_get_vendor_ids() instead.
+ **/
+const gchar *
+fwupd_device_get_vendor_id(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->vendor_id;
+}
+
+/**
+ * fwupd_device_set_vendor_id:
+ * @self: a #FwupdDevice
+ * @vendor_id: (not nullable): the vendor ID, e.g. 'USB:0x1234' or 'USB:0x1234|PCI:0x5678'
+ *
+ * Sets the device vendor ID.
+ *
+ * Since: 0.9.4
+ *
+ * Deprecated: 1.5.5: Use fwupd_device_add_vendor_id() instead.
+ **/
+void
+fwupd_device_set_vendor_id(FwupdDevice *self, const gchar *vendor_id)
+{
+ g_auto(GStrv) vendor_ids = NULL;
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(vendor_id != NULL);
+
+ /* add all */
+ vendor_ids = g_strsplit(vendor_id, "|", -1);
+ for (guint i = 0; vendor_ids[i] != NULL; i++)
+ fwupd_device_add_vendor_id(self, vendor_ids[i]);
+}
+
+/**
+ * fwupd_device_get_vendor_ids:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device vendor ID.
+ *
+ * Returns: (element-type utf8) (transfer none): the device vendor ID
+ *
+ * Since: 1.5.5
+ **/
+GPtrArray *
+fwupd_device_get_vendor_ids(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->vendor_ids;
+}
+
+/**
+ * fwupd_device_has_vendor_id:
+ * @self: a #FwupdDevice
+ * @vendor_id: (not nullable): the vendor ID, e.g. 'USB:0x1234'
+ *
+ * Finds out if the device has this specific vendor ID.
+ *
+ * Returns: %TRUE if the vendor ID is found
+ *
+ * Since: 1.5.5
+ **/
+gboolean
+fwupd_device_has_vendor_id(FwupdDevice *self, const gchar *vendor_id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(vendor_id != NULL, FALSE);
+
+ for (guint i = 0; i < priv->vendor_ids->len; i++) {
+ const gchar *vendor_id_tmp = g_ptr_array_index(priv->vendor_ids, i);
+ if (g_strcmp0(vendor_id, vendor_id_tmp) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_device_add_vendor_id:
+ * @self: a #FwupdDevice
+ * @vendor_id: (not nullable): the ID, e.g. 'USB:0x1234'
+ *
+ * Adds a device vendor ID.
+ *
+ * Since: 1.5.5
+ **/
+void
+fwupd_device_add_vendor_id(FwupdDevice *self, const gchar *vendor_id)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_auto(GStrv) vendor_ids_tmp = NULL;
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(vendor_id != NULL);
+
+ if (fwupd_device_has_vendor_id(self, vendor_id))
+ return;
+ g_ptr_array_add(priv->vendor_ids, g_strdup(vendor_id));
+
+ /* build for compatibility */
+ vendor_ids_tmp = g_new0(gchar *, priv->vendor_ids->len + 1);
+ for (guint i = 0; i < priv->vendor_ids->len; i++) {
+ const gchar *vendor_id_tmp = g_ptr_array_index(priv->vendor_ids, i);
+ vendor_ids_tmp[i] = g_strdup(vendor_id_tmp);
+ }
+ g_free(priv->vendor_id);
+ priv->vendor_id = g_strjoinv("|", vendor_ids_tmp);
+}
+
+/**
+ * fwupd_device_get_description:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device description in AppStream markup format.
+ *
+ * Returns: the device description, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_description(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->description;
+}
+
+/**
+ * fwupd_device_set_description:
+ * @self: a #FwupdDevice
+ * @description: (nullable): the description in AppStream markup format
+ *
+ * Sets the device description.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_description(FwupdDevice *self, const gchar *description)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->description, description) == 0)
+ return;
+
+ g_free(priv->description);
+ priv->description = g_strdup(description);
+}
+
+/**
+ * fwupd_device_get_version:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device version.
+ *
+ * Returns: the device version, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_version(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->version;
+}
+
+/**
+ * fwupd_device_set_version:
+ * @self: a #FwupdDevice
+ * @version: (nullable): the device version, e.g. `1.2.3`
+ *
+ * Sets the device version.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_version(FwupdDevice *self, const gchar *version)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->version, version) == 0)
+ return;
+
+ g_free(priv->version);
+ priv->version = g_strdup(version);
+}
+
+/**
+ * fwupd_device_get_version_lowest:
+ * @self: a #FwupdDevice
+ *
+ * Gets the lowest version of firmware the device will accept.
+ *
+ * Returns: the device version_lowest, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_version_lowest(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->version_lowest;
+}
+
+/**
+ * fwupd_device_set_version_lowest:
+ * @self: a #FwupdDevice
+ * @version_lowest: (nullable): the version
+ *
+ * Sets the lowest version of firmware the device will accept.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_version_lowest(FwupdDevice *self, const gchar *version_lowest)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->version_lowest, version_lowest) == 0)
+ return;
+
+ g_free(priv->version_lowest);
+ priv->version_lowest = g_strdup(version_lowest);
+}
+
+/**
+ * fwupd_device_get_version_lowest_raw:
+ * @self: a #FwupdDevice
+ *
+ * Gets the lowest version of firmware the device will accept in raw format.
+ *
+ * Returns: integer version number, or %0 if unset
+ *
+ * Since: 1.4.0
+ **/
+guint64
+fwupd_device_get_version_lowest_raw(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->version_lowest_raw;
+}
+
+/**
+ * fwupd_device_set_version_lowest_raw:
+ * @self: a #FwupdDevice
+ * @version_lowest_raw: the raw hardware version
+ *
+ * Sets the raw lowest version number from the hardware before converted to a string.
+ *
+ * Since: 1.4.0
+ **/
+void
+fwupd_device_set_version_lowest_raw(FwupdDevice *self, guint64 version_lowest_raw)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->version_lowest_raw = version_lowest_raw;
+}
+
+/**
+ * fwupd_device_get_version_bootloader:
+ * @self: a #FwupdDevice
+ *
+ * Gets the version of the bootloader.
+ *
+ * Returns: the device version_bootloader, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_device_get_version_bootloader(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->version_bootloader;
+}
+
+/**
+ * fwupd_device_set_version_bootloader:
+ * @self: a #FwupdDevice
+ * @version_bootloader: (nullable): the version
+ *
+ * Sets the bootloader version.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_version_bootloader(FwupdDevice *self, const gchar *version_bootloader)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->version_bootloader, version_bootloader) == 0)
+ return;
+
+ g_free(priv->version_bootloader);
+ priv->version_bootloader = g_strdup(version_bootloader);
+}
+
+/**
+ * fwupd_device_get_version_bootloader_raw:
+ * @self: a #FwupdDevice
+ *
+ * Gets the bootloader version of firmware the device will accept in raw format.
+ *
+ * Returns: integer version number, or %0 if unset
+ *
+ * Since: 1.4.0
+ **/
+guint64
+fwupd_device_get_version_bootloader_raw(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->version_bootloader_raw;
+}
+
+/**
+ * fwupd_device_set_version_bootloader_raw:
+ * @self: a #FwupdDevice
+ * @version_bootloader_raw: the raw hardware version
+ *
+ * Sets the raw bootloader version number from the hardware before converted to a string.
+ *
+ * Since: 1.4.0
+ **/
+void
+fwupd_device_set_version_bootloader_raw(FwupdDevice *self, guint64 version_bootloader_raw)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->version_bootloader_raw = version_bootloader_raw;
+}
+
+/**
+ * fwupd_device_get_flashes_left:
+ * @self: a #FwupdDevice
+ *
+ * Gets the number of flash cycles left on the device
+ *
+ * Returns: the flash cycles left, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+guint32
+fwupd_device_get_flashes_left(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->flashes_left;
+}
+
+/**
+ * fwupd_device_set_flashes_left:
+ * @self: a #FwupdDevice
+ * @flashes_left: the description
+ *
+ * Sets the number of flash cycles left on the device
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_flashes_left(FwupdDevice *self, guint32 flashes_left)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->flashes_left = flashes_left;
+}
+
+/**
+ * fwupd_device_get_battery_level:
+ * @self: a #FwupdDevice
+ *
+ * Returns the battery level.
+ *
+ * Returns: value in percent
+ *
+ * Since: 1.8.1
+ **/
+guint32
+fwupd_device_get_battery_level(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), G_MAXUINT);
+ return priv->battery_level;
+}
+
+/**
+ * fwupd_device_set_battery_level:
+ * @self: a #FwupdDevice
+ * @battery_level: the percentage value
+ *
+ * Sets the battery level, or %FWUPD_BATTERY_LEVEL_INVALID.
+ *
+ * Setting this allows fwupd to show a warning if the device change is too low
+ * to perform the update.
+ *
+ * Since: 1.8.1
+ **/
+void
+fwupd_device_set_battery_level(FwupdDevice *self, guint32 battery_level)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(battery_level <= FWUPD_BATTERY_LEVEL_INVALID);
+
+ if (priv->battery_level == battery_level)
+ return;
+ priv->battery_level = battery_level;
+ g_object_notify(G_OBJECT(self), "battery-level");
+}
+
+/**
+ * fwupd_device_get_battery_threshold:
+ * @self: a #FwupdDevice
+ *
+ * Returns the battery threshold under which a firmware update cannot be
+ * performed.
+ *
+ * If fwupd_device_set_battery_threshold() has not been used, a default value is
+ * used instead.
+ *
+ * Returns: value in percent
+ *
+ * Since: 1.8.1
+ **/
+guint32
+fwupd_device_get_battery_threshold(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FWUPD_BATTERY_LEVEL_INVALID);
+
+ /* default value */
+ if (priv->battery_threshold == FWUPD_BATTERY_LEVEL_INVALID)
+ return FWUPD_BATTERY_THRESHOLD_DEFAULT;
+
+ return priv->battery_threshold;
+}
+
+/**
+ * fwupd_device_set_battery_threshold:
+ * @self: a #FwupdDevice
+ * @battery_threshold: the percentage value
+ *
+ * Sets the battery level, or %FWUPD_BATTERY_LEVEL_INVALID for the default.
+ *
+ * Setting this allows fwupd to show a warning if the device change is too low
+ * to perform the update.
+ *
+ * Since: 1.8.1
+ **/
+void
+fwupd_device_set_battery_threshold(FwupdDevice *self, guint32 battery_threshold)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(battery_threshold <= FWUPD_BATTERY_LEVEL_INVALID);
+
+ if (priv->battery_threshold == battery_threshold)
+ return;
+ priv->battery_threshold = battery_threshold;
+ g_object_notify(G_OBJECT(self), "battery-threshold");
+}
+
+/**
+ * fwupd_device_get_install_duration:
+ * @self: 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 *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->install_duration;
+}
+
+/**
+ * fwupd_device_set_install_duration:
+ * @self: 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 *self, guint32 duration)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->install_duration = duration;
+}
+
+/**
+ * fwupd_device_get_plugin:
+ * @self: a #FwupdDevice
+ *
+ * Gets the plugin that created the device.
+ *
+ * Returns: the plugin name, or %NULL if unset
+ *
+ * Since: 1.0.0
+ **/
+const gchar *
+fwupd_device_get_plugin(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->plugin;
+}
+
+/**
+ * fwupd_device_set_plugin:
+ * @self: a #FwupdDevice
+ * @plugin: (nullable): the plugin name, e.g. `colorhug`
+ *
+ * Sets the plugin that created the device.
+ *
+ * Since: 1.0.0
+ **/
+void
+fwupd_device_set_plugin(FwupdDevice *self, const gchar *plugin)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->plugin, plugin) == 0)
+ return;
+
+ g_free(priv->plugin);
+ priv->plugin = g_strdup(plugin);
+}
+
+/**
+ * fwupd_device_get_protocol:
+ * @self: a #FwupdDevice
+ *
+ * Gets the protocol name that the device uses for updating.
+ *
+ * Returns: the protocol name, or %NULL if unset
+ *
+ * Since: 1.3.6
+ *
+ * Deprecated: 1.5.8: Use fwupd_device_get_protocols() instead.
+ **/
+const gchar *
+fwupd_device_get_protocol(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->protocol;
+}
+
+/**
+ * fwupd_device_set_protocol:
+ * @self: a #FwupdDevice
+ * @protocol: (not nullable): the protocol name, e.g. `com.hughski.colorhug`
+ *
+ * Sets the protocol name that is used to update the device.
+ *
+ * Since: 1.3.6
+ *
+ * Deprecated: 1.5.8: Use fwupd_device_add_protocol() instead.
+ **/
+void
+fwupd_device_set_protocol(FwupdDevice *self, const gchar *protocol)
+{
+ g_auto(GStrv) protocols = NULL;
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(protocol != NULL);
+
+ /* add all */
+ protocols = g_strsplit(protocol, "|", -1);
+ for (guint i = 0; protocols[i] != NULL; i++)
+ fwupd_device_add_protocol(self, protocols[i]);
+}
+
+/**
+ * fwupd_device_get_protocols:
+ * @self: a #FwupdDevice
+ *
+ * Gets the device protocol names.
+ *
+ * Returns: (element-type utf8) (transfer none): the device protocol names
+ *
+ * Since: 1.5.8
+ **/
+GPtrArray *
+fwupd_device_get_protocols(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->protocols;
+}
+
+/**
+ * fwupd_device_has_protocol:
+ * @self: a #FwupdDevice
+ * @protocol: (not nullable): the protocol name, e.g. `com.hughski.colorhug`
+ *
+ * Finds out if the device has this specific protocol name.
+ *
+ * Returns: %TRUE if the protocol name is found
+ *
+ * Since: 1.5.8
+ **/
+gboolean
+fwupd_device_has_protocol(FwupdDevice *self, const gchar *protocol)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(protocol != NULL, FALSE);
+
+ for (guint i = 0; i < priv->protocols->len; i++) {
+ const gchar *protocol_tmp = g_ptr_array_index(priv->protocols, i);
+ if (g_strcmp0(protocol, protocol_tmp) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_device_add_protocol:
+ * @self: a #FwupdDevice
+ * @protocol: (not nullable): the protocol name, e.g. `com.hughski.colorhug`
+ *
+ * Adds a device protocol name.
+ *
+ * Since: 1.5.8
+ **/
+void
+fwupd_device_add_protocol(FwupdDevice *self, const gchar *protocol)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_auto(GStrv) protocols_tmp = NULL;
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(protocol != NULL);
+
+ if (fwupd_device_has_protocol(self, protocol))
+ return;
+ g_ptr_array_add(priv->protocols, g_strdup(protocol));
+
+ /* build for compatibility */
+ protocols_tmp = g_new0(gchar *, priv->protocols->len + 1);
+ for (guint i = 0; i < priv->protocols->len; i++) {
+ const gchar *protocol_tmp = g_ptr_array_index(priv->protocols, i);
+ protocols_tmp[i] = g_strdup(protocol_tmp);
+ }
+ g_free(priv->protocol);
+ priv->protocol = g_strjoinv("|", protocols_tmp);
+}
+
+/**
+ * fwupd_device_get_flags:
+ * @self: a #FwupdDevice
+ *
+ * Gets device flags.
+ *
+ * Returns: device flags, or 0 if unset
+ *
+ * Since: 0.9.3
+ **/
+guint64
+fwupd_device_get_flags(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->flags;
+}
+
+/**
+ * fwupd_device_set_flags:
+ * @self: a #FwupdDevice
+ * @flags: device flags, e.g. %FWUPD_DEVICE_FLAG_REQUIRE_AC
+ *
+ * Sets device flags.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_flags(FwupdDevice *self, guint64 flags)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (priv->flags == flags)
+ return;
+ priv->flags = flags;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_device_add_flag:
+ * @self: a #FwupdDevice
+ * @flag: the #FwupdDeviceFlags
+ *
+ * Adds a specific device flag to the device.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_add_flag(FwupdDevice *self, FwupdDeviceFlags flag)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (flag == 0)
+ return;
+ if ((priv->flags | flag) == priv->flags)
+ return;
+ priv->flags |= flag;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_device_remove_flag:
+ * @self: a #FwupdDevice
+ * @flag: the #FwupdDeviceFlags
+ *
+ * Removes a specific device flag from the device.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_remove_flag(FwupdDevice *self, FwupdDeviceFlags flag)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (flag == 0)
+ return;
+ if ((priv->flags & flag) == 0)
+ return;
+ priv->flags &= ~flag;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_device_has_flag:
+ * @self: a #FwupdDevice
+ * @flag: the #FwupdDeviceFlags
+ *
+ * Finds if the device has a specific device flag.
+ *
+ * Returns: %TRUE if the flag is set
+ *
+ * Since: 0.9.3
+ **/
+gboolean
+fwupd_device_has_flag(FwupdDevice *self, FwupdDeviceFlags flag)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+ return (priv->flags & flag) > 0;
+}
+
+/**
+ * fwupd_device_get_problems:
+ * @self: a #FwupdDevice
+ *
+ * Gets device problems.
+ *
+ * Returns: device problems, or 0 if unset
+ *
+ * Since: 1.8.1
+ **/
+guint64
+fwupd_device_get_problems(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->problems;
+}
+
+/**
+ * fwupd_device_set_problems:
+ * @self: a #FwupdDevice
+ * @problems: device problems, e.g. %FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
+ *
+ * Sets device problems.
+ *
+ * Since: 1.8.1
+ **/
+void
+fwupd_device_set_problems(FwupdDevice *self, guint64 problems)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (priv->problems == problems)
+ return;
+ priv->problems = problems;
+ g_object_notify(G_OBJECT(self), "problems");
+}
+
+/**
+ * fwupd_device_add_problem:
+ * @self: a #FwupdDevice
+ * @problem: the #FwupdDeviceProblem, e.g. #FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
+ *
+ * Adds a specific device problem kind to the device.
+ *
+ * Since: 1.8.1
+ **/
+void
+fwupd_device_add_problem(FwupdDevice *self, FwupdDeviceProblem problem)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (problem == FWUPD_DEVICE_PROBLEM_NONE)
+ return;
+ if (fwupd_device_has_problem(self, problem))
+ return;
+ priv->problems |= problem;
+ g_object_notify(G_OBJECT(self), "problems");
+}
+
+/**
+ * fwupd_device_remove_problem:
+ * @self: a #FwupdDevice
+ * @problem: the #FwupdDeviceProblem, e.g. #FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
+ *
+ * Removes a specific device problem kind from the device.
+ *
+ * Since: 1.8.1
+ **/
+void
+fwupd_device_remove_problem(FwupdDevice *self, FwupdDeviceProblem problem)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (problem == FWUPD_DEVICE_PROBLEM_NONE)
+ return;
+ if (!fwupd_device_has_problem(self, problem))
+ return;
+ priv->problems &= ~problem;
+ g_object_notify(G_OBJECT(self), "problems");
+}
+
+/**
+ * fwupd_device_has_problem:
+ * @self: a #FwupdDevice
+ * @problem: the #FwupdDeviceProblem
+ *
+ * Finds if the device has a specific device problem kind.
+ *
+ * Returns: %TRUE if the problem is set
+ *
+ * Since: 1.8.1
+ **/
+gboolean
+fwupd_device_has_problem(FwupdDevice *self, FwupdDeviceProblem problem)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+ return (priv->problems & problem) > 0;
+}
+
+/**
+ * fwupd_device_get_created:
+ * @self: a #FwupdDevice
+ *
+ * Gets when the device was created.
+ *
+ * Returns: the UNIX time, or 0 if unset
+ *
+ * Since: 0.9.3
+ **/
+guint64
+fwupd_device_get_created(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->created;
+}
+
+/**
+ * fwupd_device_set_created:
+ * @self: a #FwupdDevice
+ * @created: the UNIX time
+ *
+ * Sets when the device was created.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_created(FwupdDevice *self, guint64 created)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->created = created;
+}
+
+/**
+ * fwupd_device_get_modified:
+ * @self: a #FwupdDevice
+ *
+ * Gets when the device was modified.
+ *
+ * Returns: the UNIX time, or 0 if unset
+ *
+ * Since: 0.9.3
+ **/
+guint64
+fwupd_device_get_modified(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->modified;
+}
+
+/**
+ * fwupd_device_set_modified:
+ * @self: a #FwupdDevice
+ * @modified: the UNIX time
+ *
+ * Sets when the device was modified.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_device_set_modified(FwupdDevice *self, guint64 modified)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->modified = modified;
+}
+
+/**
+ * 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);
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(FWUPD_IS_DEVICE(donor));
+
+ fwupd_device_add_flag(self, priv_donor->flags);
+ fwupd_device_add_problem(self, priv_donor->problems);
+ 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->version_build_date == 0)
+ fwupd_device_set_version_build_date(self, priv_donor->version_build_date);
+ if (priv->flashes_left == 0)
+ fwupd_device_set_flashes_left(self, priv_donor->flashes_left);
+ if (priv->battery_level == FWUPD_BATTERY_LEVEL_INVALID)
+ fwupd_device_set_battery_level(self, priv_donor->battery_level);
+ if (priv->battery_threshold == FWUPD_BATTERY_LEVEL_INVALID)
+ fwupd_device_set_battery_threshold(self, priv_donor->battery_threshold);
+ if (priv->install_duration == 0)
+ fwupd_device_set_install_duration(self, priv_donor->install_duration);
+ if (priv->update_state == FWUPD_UPDATE_STATE_UNKNOWN)
+ 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->composite_id == NULL)
+ fwupd_device_set_composite_id(self, priv_donor->composite_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->branch == NULL)
+ fwupd_device_set_branch(self, priv_donor->branch);
+ if (priv->vendor == NULL)
+ fwupd_device_set_vendor(self, priv_donor->vendor);
+ for (guint i = 0; i < priv_donor->vendor_ids->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv_donor->vendor_ids, i);
+ fwupd_device_add_vendor_id(self, tmp);
+ }
+ if (priv->plugin == NULL)
+ fwupd_device_set_plugin(self, priv_donor->plugin);
+ for (guint i = 0; i < priv_donor->protocols->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv_donor->protocols, i);
+ fwupd_device_add_protocol(self, tmp);
+ }
+ 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->update_image == NULL)
+ fwupd_device_set_update_image(self, priv_donor->update_image);
+ 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);
+ if (priv->version_raw == 0)
+ fwupd_device_set_version_raw(self, priv_donor->version_raw);
+ if (priv->version_lowest_raw == 0)
+ fwupd_device_set_version_lowest_raw(self, priv_donor->version_lowest_raw);
+ if (priv->version_bootloader_raw == 0)
+ fwupd_device_set_version_bootloader_raw(self, priv_donor->version_bootloader_raw);
+ 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:
+ * @self: a #FwupdDevice
+ * @flags: device flags
+ *
+ * Serialize the device data.
+ * Optionally provides additional data based upon flags
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.1.2
+ **/
+GVariant *
+fwupd_device_to_variant_full(FwupdDevice *self, FwupdDeviceFlags flags)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+
+ /* create an array with all the metadata in */
+ 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->composite_id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_COMPOSITE_ID,
+ g_variant_new_string(priv->composite_id));
+ }
+ if (priv->guids->len > 0) {
+ const gchar *const *tmp = (const gchar *const *)priv->guids->pdata;
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_GUID,
+ g_variant_new_strv(tmp, priv->guids->len));
+ }
+ if (priv->icons->len > 0) {
+ const gchar *const *tmp = (const gchar *const *)priv->icons->pdata;
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_ICON,
+ g_variant_new_strv(tmp, priv->icons->len));
+ }
+ if (priv->name != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_NAME,
+ g_variant_new_string(priv->name));
+ }
+ if (priv->vendor != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VENDOR,
+ g_variant_new_string(priv->vendor));
+ }
+ if (priv->vendor_ids->len > 0) {
+ g_autoptr(GString) str = g_string_new(NULL);
+ for (guint i = 0; i < priv->vendor_ids->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->vendor_ids, i);
+ g_string_append_printf(str, "%s|", tmp);
+ }
+ if (str->len > 0)
+ g_string_truncate(str, str->len - 1);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VENDOR_ID,
+ g_variant_new_string(str->str));
+ }
+ if (priv->flags > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_FLAGS,
+ g_variant_new_uint64(priv->flags));
+ }
+ if (priv->problems > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_PROBLEMS,
+ g_variant_new_uint64(priv->problems));
+ }
+ if (priv->created > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CREATED,
+ g_variant_new_uint64(priv->created));
+ }
+ if (priv->modified > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_MODIFIED,
+ g_variant_new_uint64(priv->modified));
+ }
+ if (priv->version_build_date > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
+ g_variant_new_uint64(priv->version_build_date));
+ }
+
+ if (priv->description != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_DESCRIPTION,
+ g_variant_new_string(priv->description));
+ }
+ if (priv->summary != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_SUMMARY,
+ g_variant_new_string(priv->summary));
+ }
+ if (priv->branch != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BRANCH,
+ g_variant_new_string(priv->branch));
+ }
+ if (priv->checksums->len > 0) {
+ g_autoptr(GString) str = g_string_new("");
+ for (guint i = 0; i < priv->checksums->len; i++) {
+ const gchar *checksum = g_ptr_array_index(priv->checksums, i);
+ g_string_append_printf(str, "%s,", checksum);
+ }
+ if (str->len > 0)
+ g_string_truncate(str, str->len - 1);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CHECKSUM,
+ g_variant_new_string(str->str));
+ }
+ if (priv->plugin != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_PLUGIN,
+ g_variant_new_string(priv->plugin));
+ }
+ if (priv->protocols->len > 0) {
+ g_autoptr(GString) str = g_string_new(NULL);
+ for (guint i = 0; i < priv->protocols->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->protocols, i);
+ g_string_append_printf(str, "%s|", tmp);
+ }
+ if (str->len > 0)
+ g_string_truncate(str, str->len - 1);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_PROTOCOL,
+ g_variant_new_string(str->str));
+ }
+ if (priv->issues->len > 0) {
+ g_autofree const gchar **strv = g_new0(const gchar *, priv->issues->len + 1);
+ for (guint i = 0; i < priv->issues->len; i++)
+ strv[i] = (const gchar *)g_ptr_array_index(priv->issues, i);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_ISSUES,
+ g_variant_new_strv(strv, -1));
+ }
+ if (priv->version != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION,
+ g_variant_new_string(priv->version));
+ }
+ if (priv->version_lowest != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION_LOWEST,
+ g_variant_new_string(priv->version_lowest));
+ }
+ if (priv->version_bootloader != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
+ g_variant_new_string(priv->version_bootloader));
+ }
+ if (priv->version_raw > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION_RAW,
+ g_variant_new_uint64(priv->version_raw));
+ }
+ if (priv->version_lowest_raw > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION_LOWEST_RAW,
+ g_variant_new_uint64(priv->version_lowest_raw));
+ }
+ if (priv->version_bootloader_raw > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW,
+ g_variant_new_uint64(priv->version_raw));
+ }
+ if (priv->flashes_left > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_FLASHES_LEFT,
+ g_variant_new_uint32(priv->flashes_left));
+ }
+ if (priv->battery_level != FWUPD_BATTERY_LEVEL_INVALID) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BATTERY_LEVEL,
+ g_variant_new_uint32(priv->battery_level));
+ }
+ if (priv->battery_threshold != FWUPD_BATTERY_LEVEL_INVALID) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
+ g_variant_new_uint32(priv->battery_threshold));
+ }
+ 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_image != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_UPDATE_IMAGE,
+ g_variant_new_string(priv->update_image));
+ }
+ 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->status != FWUPD_STATUS_UNKNOWN) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_STATUS,
+ g_variant_new_uint32(priv->status));
+ }
+ 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) {
+ g_autofree GVariant **children = NULL;
+ children = g_new0(GVariant *, priv->releases->len);
+ for (guint i = 0; i < priv->releases->len; i++) {
+ FwupdRelease *release = g_ptr_array_index(priv->releases, i);
+ children[i] = fwupd_release_to_variant(release);
+ }
+ g_variant_builder_add(
+ &builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_RELEASE,
+ g_variant_new_array(G_VARIANT_TYPE("a{sv}"), children, priv->releases->len));
+ }
+ return g_variant_new("a{sv}", &builder);
+}
+
+/**
+ * fwupd_device_to_variant:
+ * @self: a #FwupdDevice
+ *
+ * Serialize the device data omitting sensitive fields
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.0.0
+ **/
+GVariant *
+fwupd_device_to_variant(FwupdDevice *self)
+{
+ return fwupd_device_to_variant_full(self, FWUPD_DEVICE_FLAG_NONE);
+}
+
+static void
+fwupd_device_from_key_value(FwupdDevice *self, const gchar *key, GVariant *value)
+{
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_RELEASE) == 0) {
+ GVariantIter iter;
+ GVariant *child;
+ g_variant_iter_init(&iter, value);
+ while ((child = g_variant_iter_next_value(&iter))) {
+ g_autoptr(FwupdRelease) release = fwupd_release_from_variant(child);
+ if (release != NULL)
+ fwupd_device_add_release(self, release);
+ g_variant_unref(child);
+ }
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DEVICE_ID) == 0) {
+ fwupd_device_set_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_PARENT_DEVICE_ID) == 0) {
+ fwupd_device_set_parent_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_COMPOSITE_ID) == 0) {
+ fwupd_device_set_composite_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FLAGS) == 0) {
+ fwupd_device_set_flags(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_PROBLEMS) == 0) {
+ fwupd_device_set_problems(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
+ fwupd_device_set_created(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_MODIFIED) == 0) {
+ fwupd_device_set_modified(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_BUILD_DATE) == 0) {
+ fwupd_device_set_version_build_date(self, g_variant_get_uint64(value));
+ return;
+ }
+ 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 != NULL && guids[i] != NULL; i++)
+ fwupd_device_add_guid(self, 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(self, 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 != NULL && icons[i] != NULL; i++)
+ fwupd_device_add_icon(self, icons[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
+ fwupd_device_set_name(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR) == 0) {
+ fwupd_device_set_vendor(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR_ID) == 0) {
+ g_auto(GStrv) vendor_ids = NULL;
+ vendor_ids = g_strsplit(g_variant_get_string(value, NULL), "|", -1);
+ for (guint i = 0; vendor_ids[i] != NULL; i++)
+ fwupd_device_add_vendor_id(self, vendor_ids[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_SERIAL) == 0) {
+ fwupd_device_set_serial(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_SUMMARY) == 0) {
+ fwupd_device_set_summary(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BRANCH) == 0) {
+ fwupd_device_set_branch(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
+ fwupd_device_set_description(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_CHECKSUM) == 0) {
+ const gchar *checksums = g_variant_get_string(value, NULL);
+ if (checksums != NULL) {
+ g_auto(GStrv) split = g_strsplit(checksums, ",", -1);
+ for (guint i = 0; split[i] != NULL; i++)
+ fwupd_device_add_checksum(self, split[i]);
+ }
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_PLUGIN) == 0) {
+ fwupd_device_set_plugin(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_PROTOCOL) == 0) {
+ g_auto(GStrv) protocols = NULL;
+ protocols = g_strsplit(g_variant_get_string(value, NULL), "|", -1);
+ for (guint i = 0; protocols[i] != NULL; i++)
+ fwupd_device_add_protocol(self, protocols[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_ISSUES) == 0) {
+ g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
+ for (guint i = 0; strv[i] != NULL; i++)
+ fwupd_device_add_issue(self, strv[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION) == 0) {
+ fwupd_device_set_version(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_LOWEST) == 0) {
+ fwupd_device_set_version_lowest(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_BOOTLOADER) == 0) {
+ fwupd_device_set_version_bootloader(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FLASHES_LEFT) == 0) {
+ fwupd_device_set_flashes_left(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BATTERY_LEVEL) == 0) {
+ fwupd_device_set_battery_level(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BATTERY_THRESHOLD) == 0) {
+ fwupd_device_set_battery_threshold(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) {
+ fwupd_device_set_install_duration(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_ERROR) == 0) {
+ fwupd_device_set_update_error(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) {
+ fwupd_device_set_update_message(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) {
+ fwupd_device_set_update_image(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) {
+ fwupd_device_set_update_state(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_STATUS) == 0) {
+ fwupd_device_set_status(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_FORMAT) == 0) {
+ fwupd_device_set_version_format(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_RAW) == 0) {
+ fwupd_device_set_version_raw(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_LOWEST_RAW) == 0) {
+ fwupd_device_set_version_lowest_raw(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW) == 0) {
+ fwupd_device_set_version_bootloader_raw(self, g_variant_get_uint64(value));
+ return;
+ }
+}
+
+static void
+fwupd_pad_kv_dfl(GString *str, const gchar *key, guint64 device_flags)
+{
+ g_autoptr(GString) tmp = g_string_new("");
+ for (guint i = 0; i < 64; i++) {
+ if ((device_flags & ((guint64)1 << i)) == 0)
+ continue;
+ g_string_append_printf(tmp, "%s|", fwupd_device_flag_to_string((guint64)1 << i));
+ }
+ if (tmp->len == 0) {
+ g_string_append(tmp, fwupd_device_flag_to_string(0));
+ } else {
+ g_string_truncate(tmp, tmp->len - 1);
+ }
+ fwupd_pad_kv_str(str, key, tmp->str);
+}
+
+static void
+fwupd_device_pad_kv_problems(GString *str, const gchar *key, guint64 device_problems)
+{
+ g_autoptr(GString) tmp = g_string_new("");
+ for (guint i = 0; i < 64; i++) {
+ if ((device_problems & ((guint64)1 << i)) == 0)
+ continue;
+ g_string_append_printf(tmp, "%s|", fwupd_device_problem_to_string((guint64)1 << i));
+ }
+ if (tmp->len == 0) {
+ g_string_append(tmp, fwupd_device_problem_to_string(0));
+ } else {
+ g_string_truncate(tmp, tmp->len - 1);
+ }
+ fwupd_pad_kv_str(str, key, tmp->str);
+}
+
+/**
+ * fwupd_device_get_update_state:
+ * @self: a #FwupdDevice
+ *
+ * Gets the update state.
+ *
+ * Returns: the update state, or %FWUPD_UPDATE_STATE_UNKNOWN if unset
+ *
+ * Since: 0.9.8
+ **/
+FwupdUpdateState
+fwupd_device_get_update_state(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FWUPD_UPDATE_STATE_UNKNOWN);
+ return priv->update_state;
+}
+
+/**
+ * fwupd_device_set_update_state:
+ * @self: a #FwupdDevice
+ * @update_state: the state, e.g. %FWUPD_UPDATE_STATE_PENDING
+ *
+ * Sets the update state.
+ *
+ * Since: 0.9.8
+ **/
+void
+fwupd_device_set_update_state(FwupdDevice *self, FwupdUpdateState update_state)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (priv->update_state == update_state)
+ return;
+ priv->update_state = update_state;
+ g_object_notify(G_OBJECT(self), "update-state");
+}
+
+/**
+ * fwupd_device_get_version_format:
+ * @self: a #FwupdDevice
+ *
+ * Gets the version format.
+ *
+ * Returns: the version format, or %FWUPD_VERSION_FORMAT_UNKNOWN if unset
+ *
+ * Since: 1.2.9
+ **/
+FwupdVersionFormat
+fwupd_device_get_version_format(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FWUPD_VERSION_FORMAT_UNKNOWN);
+ return priv->version_format;
+}
+
+/**
+ * fwupd_device_set_version_format:
+ * @self: a #FwupdDevice
+ * @version_format: the version format, e.g. %FWUPD_VERSION_FORMAT_NUMBER
+ *
+ * Sets the version format.
+ *
+ * Since: 1.2.9
+ **/
+void
+fwupd_device_set_version_format(FwupdDevice *self, FwupdVersionFormat version_format)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->version_format = version_format;
+}
+
+/**
+ * fwupd_device_get_version_raw:
+ * @self: a #FwupdDevice
+ *
+ * Gets the raw version number from the hardware before converted to a string.
+ *
+ * Returns: the hardware version, or 0 if unset
+ *
+ * Since: 1.3.6
+ **/
+guint64
+fwupd_device_get_version_raw(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->version_raw;
+}
+
+/**
+ * fwupd_device_set_version_raw:
+ * @self: a #FwupdDevice
+ * @version_raw: the raw hardware version
+ *
+ * Sets the raw version number from the hardware before converted to a string.
+ *
+ * Since: 1.3.6
+ **/
+void
+fwupd_device_set_version_raw(FwupdDevice *self, guint64 version_raw)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->version_raw = version_raw;
+}
+
+/**
+ * fwupd_device_get_version_build_date:
+ * @self: a #FwupdDevice
+ *
+ * Gets the date when the firmware was built.
+ *
+ * Returns: the UNIX time, or 0 if unset
+ *
+ * Since: 1.6.2
+ **/
+guint64
+fwupd_device_get_version_build_date(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->version_build_date;
+}
+
+/**
+ * fwupd_device_set_version_build_date:
+ * @self: a #FwupdDevice
+ * @version_build_date: the UNIX time
+ *
+ * Sets the date when the firmware was built.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_device_set_version_build_date(FwupdDevice *self, guint64 version_build_date)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ priv->version_build_date = version_build_date;
+}
+
+/**
+ * fwupd_device_get_update_message:
+ * @self: a #FwupdDevice
+ *
+ * Gets the update message string.
+ *
+ * Returns: the update message string, or %NULL if unset
+ *
+ * Since: 1.2.4
+ **/
+const gchar *
+fwupd_device_get_update_message(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->update_message;
+}
+
+/**
+ * fwupd_device_set_update_message:
+ * @self: a #FwupdDevice
+ * @update_message: (nullable): the update message string
+ *
+ * Sets the update message string.
+ *
+ * Since: 1.2.4
+ **/
+void
+fwupd_device_set_update_message(FwupdDevice *self, const gchar *update_message)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->update_message, update_message) == 0)
+ return;
+
+ g_free(priv->update_message);
+ priv->update_message = g_strdup(update_message);
+ g_object_notify(G_OBJECT(self), "update-message");
+}
+
+/**
+ * fwupd_device_get_update_image:
+ * @self: a #FwupdDevice
+ *
+ * Gets the update image URL.
+ *
+ * Returns: the update image URL, or %NULL if unset
+ *
+ * Since: 1.4.5
+ **/
+const gchar *
+fwupd_device_get_update_image(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->update_image;
+}
+
+/**
+ * fwupd_device_set_update_image:
+ * @self: a #FwupdDevice
+ * @update_image: (nullable): the update image URL
+ *
+ * Sets the update image URL.
+ *
+ * Since: 1.4.5
+ **/
+void
+fwupd_device_set_update_image(FwupdDevice *self, const gchar *update_image)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->update_image, update_image) == 0)
+ return;
+
+ g_free(priv->update_image);
+ priv->update_image = g_strdup(update_image);
+ g_object_notify(G_OBJECT(self), "update-image");
+}
+
+/**
+ * fwupd_device_get_update_error:
+ * @self: a #FwupdDevice
+ *
+ * Gets the update error string.
+ *
+ * Returns: the update error string, or %NULL if unset
+ *
+ * Since: 0.9.8
+ **/
+const gchar *
+fwupd_device_get_update_error(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->update_error;
+}
+
+/**
+ * fwupd_device_set_update_error:
+ * @self: a #FwupdDevice
+ * @update_error: (nullable): the update error string
+ *
+ * Sets the update error string.
+ *
+ * Since: 0.9.8
+ **/
+void
+fwupd_device_set_update_error(FwupdDevice *self, const gchar *update_error)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->update_error, update_error) == 0)
+ return;
+
+ g_free(priv->update_error);
+ priv->update_error = g_strdup(update_error);
+ g_object_notify(G_OBJECT(self), "update-error");
+}
+
+/**
+ * fwupd_device_get_release_default:
+ * @self: a #FwupdDevice
+ *
+ * Gets the default release for this device.
+ *
+ * Returns: (transfer none): the #FwupdRelease, or %NULL if not set
+ *
+ * Since: 0.9.8
+ **/
+FwupdRelease *
+fwupd_device_get_release_default(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ if (priv->releases->len == 0)
+ return NULL;
+ return FWUPD_RELEASE(g_ptr_array_index(priv->releases, 0));
+}
+
+/**
+ * fwupd_device_get_releases:
+ * @self: a #FwupdDevice
+ *
+ * Gets all the releases for this device.
+ *
+ * Returns: (transfer none) (element-type FwupdRelease): array of releases
+ *
+ * Since: 0.9.8
+ **/
+GPtrArray *
+fwupd_device_get_releases(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+ return priv->releases;
+}
+
+/**
+ * fwupd_device_add_release:
+ * @self: a #FwupdDevice
+ * @release: (not nullable): a release
+ *
+ * Adds a release for this device.
+ *
+ * Since: 0.9.8
+ **/
+void
+fwupd_device_add_release(FwupdDevice *self, FwupdRelease *release)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(FWUPD_IS_RELEASE(release));
+ g_ptr_array_add(priv->releases, g_object_ref(release));
+}
+
+/**
+ * fwupd_device_get_status:
+ * @self: a #FwupdDevice
+ *
+ * Returns what the device is currently doing.
+ *
+ * Returns: the status value, e.g. %FWUPD_STATUS_DEVICE_WRITE
+ *
+ * Since: 1.4.0
+ **/
+FwupdStatus
+fwupd_device_get_status(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
+ return priv->status;
+}
+
+/**
+ * fwupd_device_set_status:
+ * @self: a #FwupdDevice
+ * @status: the status value, e.g. %FWUPD_STATUS_DEVICE_WRITE
+ *
+ * Sets what the device is currently doing.
+ *
+ * Since: 1.4.0
+ **/
+void
+fwupd_device_set_status(FwupdDevice *self, FwupdStatus status)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ if (priv->status == status)
+ return;
+ priv->status = status;
+ g_object_notify(G_OBJECT(self), "status");
+}
+
+static void
+fwupd_pad_kv_ups(GString *str, const gchar *key, FwupdUpdateState value)
+{
+ if (value == FWUPD_UPDATE_STATE_UNKNOWN)
+ return;
+ fwupd_pad_kv_str(str, key, fwupd_update_state_to_string(value));
+}
+
+/**
+ * fwupd_device_to_json_full:
+ * @self: a #FwupdDevice
+ * @builder: (not nullable): a JSON builder
+ * @flags: device flags
+ *
+ * Adds a fwupd device to a JSON builder
+ * Optionally provides additional data based upon flags
+ *
+ * Since: 1.8.2
+ **/
+void
+fwupd_device_to_json_full(FwupdDevice *self, JsonBuilder *builder, FwupdDeviceFlags flags)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_DEVICE(self));
+ g_return_if_fail(builder != NULL);
+
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DEVICE_ID, priv->id);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_PARENT_DEVICE_ID, priv->parent_id);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_COMPOSITE_ID, priv->composite_id);
+ if (flags & FWUPD_DEVICE_FLAG_TRUSTED && priv->instance_ids->len > 0) {
+ json_builder_set_member_name(builder, FWUPD_RESULT_KEY_INSTANCE_IDS);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->instance_ids->len; i++) {
+ const gchar *instance_id = g_ptr_array_index(priv->instance_ids, i);
+ json_builder_add_string_value(builder, instance_id);
+ }
+ json_builder_end_array(builder);
+ }
+ 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);
+ }
+ if (flags & FWUPD_DEVICE_FLAG_TRUSTED)
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_SERIAL, priv->serial);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_BRANCH, priv->branch);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
+ if (priv->protocols->len > 1) { /* --> 0 when bumping API */
+ json_builder_set_member_name(builder, "Protocols");
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->protocols->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->protocols, i);
+ json_builder_add_string_value(builder, tmp);
+ }
+ json_builder_end_array(builder);
+ }
+ if (priv->issues->len > 0) {
+ json_builder_set_member_name(builder, FWUPD_RESULT_KEY_ISSUES);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->issues->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->issues, i);
+ json_builder_add_string_value(builder, tmp);
+ }
+ json_builder_end_array(builder);
+ }
+ 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->problems != FWUPD_DEVICE_PROBLEM_NONE) {
+ json_builder_set_member_name(builder, FWUPD_RESULT_KEY_PROBLEMS);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < 64; i++) {
+ const gchar *tmp;
+ if ((priv->problems & ((guint64)1 << i)) == 0)
+ continue;
+ tmp = fwupd_device_problem_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_common_json_add_string(builder, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_VENDOR_ID, priv->vendor_id);
+ if (priv->vendor_ids->len > 1) { /* --> 0 when bumping API */
+ json_builder_set_member_name(builder, "VendorIds");
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->vendor_ids->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->vendor_ids, i);
+ json_builder_add_string_value(builder, tmp);
+ }
+ json_builder_end_array(builder);
+ }
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_VERSION, priv->version);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_VERSION_LOWEST,
+ priv->version_lowest);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
+ priv->version_bootloader);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_VERSION_FORMAT,
+ fwupd_version_format_to_string(priv->version_format));
+ if (priv->flashes_left > 0)
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_FLASHES_LEFT,
+ priv->flashes_left);
+ if (priv->battery_level != FWUPD_BATTERY_LEVEL_INVALID) {
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_BATTERY_LEVEL,
+ priv->battery_level);
+ }
+ if (priv->battery_threshold != FWUPD_BATTERY_LEVEL_INVALID) {
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
+ priv->battery_threshold);
+ }
+ if (priv->version_raw > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_VERSION_RAW, priv->version_raw);
+ if (priv->version_lowest_raw > 0)
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_VERSION_LOWEST_RAW,
+ priv->version_lowest_raw);
+ if (priv->version_bootloader_raw > 0)
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW,
+ priv->version_bootloader_raw);
+ if (priv->version_build_date > 0)
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
+ priv->version_build_date);
+ 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);
+ }
+ if (priv->install_duration > 0) {
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_INSTALL_DURATION,
+ priv->install_duration);
+ }
+ if (priv->created > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_CREATED, priv->created);
+ if (priv->modified > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_MODIFIED, priv->modified);
+ if (priv->update_state > 0)
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_UPDATE_STATE,
+ priv->update_state);
+ if (priv->status > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_STATUS, priv->status);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_UPDATE_MESSAGE,
+ priv->update_message);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image);
+ 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_from_json:
+ * @self: a #FwupdDevice
+ * @json_node: a JSON node
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads a fwupd security attribute from a JSON node.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.3
+ **/
+gboolean
+fwupd_device_from_json(FwupdDevice *self, JsonNode *json_node, GError **error)
+{
+#if JSON_CHECK_VERSION(1, 6, 0)
+ JsonObject *obj;
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
+
+ /* sanity check */
+ if (!JSON_NODE_HOLDS_OBJECT(json_node)) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "not JSON object");
+ return FALSE;
+ }
+ obj = json_node_get_object(json_node);
+
+ /* this has to exist */
+ if (!json_object_has_member(obj, FWUPD_RESULT_KEY_DEVICE_ID)) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "no %s property in object",
+ FWUPD_RESULT_KEY_DEVICE_ID);
+ return FALSE;
+ }
+ fwupd_device_set_id(self, json_object_get_string_member(obj, FWUPD_RESULT_KEY_DEVICE_ID));
+
+ /* also optional */
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_NAME)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_NAME, NULL);
+ fwupd_device_set_name(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_PARENT_DEVICE_ID)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_PARENT_DEVICE_ID,
+ NULL);
+ fwupd_device_set_parent_id(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_COMPOSITE_ID)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_COMPOSITE_ID,
+ NULL);
+ fwupd_device_set_composite_id(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_PROTOCOL)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_PROTOCOL,
+ NULL);
+ fwupd_device_add_protocol(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_SERIAL)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_SERIAL, NULL);
+ fwupd_device_set_serial(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_SUMMARY)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_SUMMARY, NULL);
+ fwupd_device_set_summary(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_DESCRIPTION)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_DESCRIPTION,
+ NULL);
+ fwupd_device_set_description(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_BRANCH)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_BRANCH, NULL);
+ fwupd_device_set_branch(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_PLUGIN)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_PLUGIN, NULL);
+ fwupd_device_set_plugin(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VENDOR)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_VENDOR, NULL);
+ fwupd_device_set_vendor(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VENDOR_ID)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_VENDOR_ID,
+ NULL);
+ if (tmp != NULL) {
+ g_auto(GStrv) split = g_strsplit(tmp, "|", -1);
+ for (guint i = 0; split[i] != NULL; i++)
+ fwupd_device_add_vendor_id(self, split[i]);
+ }
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_VERSION, NULL);
+ fwupd_device_set_version(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_LOWEST)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_VERSION_LOWEST,
+ NULL);
+ fwupd_device_set_version_lowest(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_BOOTLOADER)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
+ NULL);
+ fwupd_device_set_version_bootloader(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_FORMAT)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_VERSION_FORMAT,
+ NULL);
+ fwupd_device_set_version_format(self, fwupd_version_format_from_string(tmp));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_FLASHES_LEFT)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_FLASHES_LEFT, 0);
+ fwupd_device_set_flashes_left(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_BATTERY_LEVEL)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_BATTERY_LEVEL, 0);
+ fwupd_device_set_battery_level(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_BATTERY_THRESHOLD)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
+ 0);
+ fwupd_device_set_battery_threshold(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_RAW)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_VERSION_RAW, 0);
+ fwupd_device_set_version_raw(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_LOWEST_RAW)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_VERSION_LOWEST_RAW,
+ 0);
+ fwupd_device_set_version_lowest_raw(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW,
+ 0);
+ fwupd_device_set_version_bootloader_raw(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_BUILD_DATE)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
+ 0);
+ fwupd_device_set_version_build_date(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_INSTALL_DURATION)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj,
+ FWUPD_RESULT_KEY_INSTALL_DURATION,
+ 0);
+ fwupd_device_set_install_duration(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_CREATED)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_CREATED, 0);
+ fwupd_device_set_created(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_MODIFIED)) {
+ gint64 tmp =
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_MODIFIED, 0);
+ fwupd_device_set_modified(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_UPDATE_STATE)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_UPDATE_STATE,
+ NULL);
+ fwupd_device_set_update_state(self, fwupd_update_state_from_string(tmp));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_STATUS)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_STATUS, NULL);
+ fwupd_device_set_status(self, fwupd_status_from_string(tmp));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_UPDATE_ERROR)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_UPDATE_ERROR,
+ NULL);
+ fwupd_device_set_update_error(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_UPDATE_MESSAGE)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_UPDATE_MESSAGE,
+ NULL);
+ fwupd_device_set_update_message(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_UPDATE_IMAGE)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_UPDATE_IMAGE,
+ NULL);
+ fwupd_device_set_update_image(self, tmp);
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_INSTANCE_IDS)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_INSTANCE_IDS);
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_instance_id(self, json_array_get_string_element(array, i));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_GUID)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_GUID);
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_guid(self, json_array_get_string_element(array, i));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_ISSUES)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_ISSUES);
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_issue(self, json_array_get_string_element(array, i));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_FLAGS)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_FLAGS);
+ for (guint i = 0; i < json_array_get_length(array); i++) {
+ const gchar *tmp = json_array_get_string_element(array, i);
+ fwupd_device_add_flag(self, fwupd_device_flag_from_string(tmp));
+ }
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_PROBLEMS)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_PROBLEMS);
+ for (guint i = 0; i < json_array_get_length(array); i++) {
+ const gchar *tmp = json_array_get_string_element(array, i);
+ fwupd_device_add_problem(self, fwupd_device_flag_from_string(tmp));
+ }
+ }
+ if (json_object_has_member(obj, "VendorIds")) {
+ JsonArray *array = json_object_get_array_member(obj, "VendorIds");
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_vendor_id(self, json_array_get_string_element(array, i));
+ }
+ if (json_object_has_member(obj, "Protocols")) {
+ JsonArray *array = json_object_get_array_member(obj, "Protocols");
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_protocol(self, json_array_get_string_element(array, i));
+ }
+ if (json_object_has_member(obj, "Icons")) {
+ JsonArray *array = json_object_get_array_member(obj, "Icons");
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_icon(self, json_array_get_string_element(array, i));
+ }
+ if (json_object_has_member(obj, "Checksums")) {
+ JsonArray *array = json_object_get_array_member(obj, "Checksums");
+ for (guint i = 0; i < json_array_get_length(array); i++)
+ fwupd_device_add_checksum(self, json_array_get_string_element(array, i));
+ }
+
+ /* success */
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "json-glib version too old");
+ return FALSE;
+#endif
+}
+
+/**
+ * fwupd_device_to_json:
+ * @self: a #FwupdDevice
+ * @builder: (not nullable): a JSON builder
+ *
+ * Adds a fwupd device to a JSON builder
+ *
+ * Since: 1.2.6
+ **/
+void
+fwupd_device_to_json(FwupdDevice *self, JsonBuilder *builder)
+{
+ return fwupd_device_to_json_full(self, builder, FWUPD_DEVICE_FLAG_NONE);
+}
+
+static gchar *
+fwupd_device_verstr_raw(guint64 value_raw)
+{
+ if (value_raw > 0xffffffff) {
+ return g_strdup_printf("0x%08x%08x",
+ (guint)(value_raw >> 32),
+ (guint)(value_raw & 0xffffffff));
+ }
+ return g_strdup_printf("0x%08x", (guint)value_raw);
+}
+
+typedef struct {
+ gchar *guid;
+ gchar *instance_id;
+} FwupdDeviceGuidHelper;
+
+static void
+fwupd_device_guid_helper_new(FwupdDeviceGuidHelper *helper)
+{
+ g_free(helper->guid);
+ g_free(helper->instance_id);
+ g_free(helper);
+}
+
+static FwupdDeviceGuidHelper *
+fwupd_device_guid_helper_array_find(GPtrArray *array, const gchar *guid)
+{
+ for (guint i = 0; i < array->len; i++) {
+ FwupdDeviceGuidHelper *helper = g_ptr_array_index(array, i);
+ if (g_strcmp0(helper->guid, guid) == 0)
+ return helper;
+ }
+ return NULL;
+}
+
+/**
+ * fwupd_device_to_string:
+ * @self: a #FwupdDevice
+ *
+ * Builds a text representation of the object.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 0.9.3
+ **/
+gchar *
+fwupd_device_to_string(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GString) str = g_string_new(NULL);
+ g_autoptr(GPtrArray) guid_helpers = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
+
+ g_string_append_printf(str, "%s:\n", G_OBJECT_TYPE_NAME(self));
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_DEVICE_ID, priv->id);
+ if (g_strcmp0(priv->composite_id, priv->parent_id) != 0)
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_PARENT_DEVICE_ID, priv->parent_id);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_COMPOSITE_ID, priv->composite_id);
+ if (priv->name != NULL)
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_NAME, priv->name);
+ if (priv->status != FWUPD_STATUS_UNKNOWN) {
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_STATUS,
+ fwupd_status_to_string(priv->status));
+ }
+
+ /* show instance IDs optionally mapped to GUIDs, and also "standalone" GUIDs */
+ guid_helpers = g_ptr_array_new_with_free_func((GDestroyNotify)fwupd_device_guid_helper_new);
+ for (guint i = 0; i < priv->instance_ids->len; i++) {
+ FwupdDeviceGuidHelper *helper = g_new0(FwupdDeviceGuidHelper, 1);
+ const gchar *instance_id = g_ptr_array_index(priv->instance_ids, i);
+ helper->guid = fwupd_guid_hash_string(instance_id);
+ helper->instance_id = g_strdup(instance_id);
+ g_ptr_array_add(guid_helpers, helper);
+ }
+ for (guint i = 0; i < priv->guids->len; i++) {
+ const gchar *guid = g_ptr_array_index(priv->guids, i);
+ if (fwupd_device_guid_helper_array_find(guid_helpers, guid) == NULL) {
+ FwupdDeviceGuidHelper *helper = g_new0(FwupdDeviceGuidHelper, 1);
+ helper->guid = g_strdup(guid);
+ g_ptr_array_add(guid_helpers, helper);
+ }
+ }
+ for (guint i = 0; i < guid_helpers->len; i++) {
+ FwupdDeviceGuidHelper *helper = g_ptr_array_index(guid_helpers, i);
+ g_autoptr(GString) tmp = g_string_new(helper->guid);
+ if (helper->instance_id != NULL)
+ g_string_append_printf(tmp, " ← %s", helper->instance_id);
+ if (!fwupd_device_has_guid(self, helper->guid))
+ g_string_append(tmp, " ⚠");
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_GUID, tmp->str);
+ }
+
+ 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_BRANCH, priv->branch);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
+ for (guint i = 0; i < priv->protocols->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->protocols, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_PROTOCOL, tmp);
+ }
+ for (guint i = 0; i < priv->issues->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->issues, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_ISSUES, tmp);
+ }
+ fwupd_pad_kv_dfl(str, FWUPD_RESULT_KEY_FLAGS, priv->flags);
+ if (priv->problems != FWUPD_DEVICE_PROBLEM_NONE) {
+ fwupd_device_pad_kv_problems(str, FWUPD_RESULT_KEY_PROBLEMS, priv->problems);
+ }
+ 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);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_CHECKSUM, checksum_display);
+ }
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
+ for (guint i = 0; i < priv->vendor_ids->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->vendor_ids, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_VENDOR_ID, tmp);
+ }
+ 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->battery_level != FWUPD_BATTERY_LEVEL_INVALID)
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_BATTERY_LEVEL, priv->battery_level);
+ if (priv->battery_threshold != FWUPD_BATTERY_LEVEL_INVALID)
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_BATTERY_THRESHOLD, priv->battery_threshold);
+ if (priv->version_raw > 0) {
+ g_autofree gchar *tmp = fwupd_device_verstr_raw(priv->version_raw);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_VERSION_RAW, tmp);
+ }
+ if (priv->version_lowest_raw > 0) {
+ g_autofree gchar *tmp = fwupd_device_verstr_raw(priv->version_lowest_raw);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_VERSION_LOWEST_RAW, tmp);
+ }
+ if (priv->version_build_date > 0) {
+ fwupd_pad_kv_unx(str,
+ FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
+ priv->version_build_date);
+ }
+ if (priv->version_bootloader_raw > 0) {
+ g_autofree gchar *tmp = fwupd_device_verstr_raw(priv->version_bootloader_raw);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW, tmp);
+ }
+ if (priv->icons->len > 0) {
+ g_autoptr(GString) tmp = g_string_new(NULL);
+ for (guint i = 0; i < priv->icons->len; i++) {
+ const gchar *icon = g_ptr_array_index(priv->icons, i);
+ g_string_append_printf(tmp, "%s,", icon);
+ }
+ if (tmp->len > 1)
+ 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);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image);
+ 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);
+ g_string_append_printf(str, " \n [%s]\n%s", FWUPD_RESULT_KEY_RELEASE, tmp);
+ }
+
+ return g_string_free(g_steal_pointer(&str), FALSE);
+}
+
+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;
+ case PROP_FLAGS:
+ g_value_set_uint64(value, priv->flags);
+ break;
+ case PROP_PROBLEMS:
+ g_value_set_uint64(value, priv->problems);
+ break;
+ case PROP_PROTOCOL:
+ g_value_set_string(value, priv->protocol);
+ break;
+ case PROP_UPDATE_MESSAGE:
+ g_value_set_string(value, priv->update_message);
+ break;
+ case PROP_UPDATE_ERROR:
+ g_value_set_string(value, priv->update_error);
+ break;
+ case PROP_UPDATE_IMAGE:
+ g_value_set_string(value, priv->update_image);
+ break;
+ case PROP_STATUS:
+ g_value_set_uint(value, priv->status);
+ break;
+ case PROP_PARENT:
+ g_value_set_object(value, priv->parent);
+ break;
+ case PROP_UPDATE_STATE:
+ g_value_set_uint(value, priv->update_state);
+ break;
+ case PROP_BATTERY_LEVEL:
+ g_value_set_uint(value, priv->battery_level);
+ break;
+ case PROP_BATTERY_THRESHOLD:
+ g_value_set_uint(value, priv->battery_threshold);
+ 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;
+ case PROP_FLAGS:
+ fwupd_device_set_flags(self, g_value_get_uint64(value));
+ break;
+ case PROP_PROBLEMS:
+ fwupd_device_set_problems(self, g_value_get_uint64(value));
+ break;
+ case PROP_PROTOCOL:
+ fwupd_device_add_protocol(self, g_value_get_string(value));
+ break;
+ case PROP_UPDATE_MESSAGE:
+ fwupd_device_set_update_message(self, g_value_get_string(value));
+ break;
+ case PROP_UPDATE_ERROR:
+ fwupd_device_set_update_error(self, g_value_get_string(value));
+ break;
+ case PROP_UPDATE_IMAGE:
+ fwupd_device_set_update_image(self, g_value_get_string(value));
+ break;
+ case PROP_STATUS:
+ fwupd_device_set_status(self, g_value_get_uint(value));
+ break;
+ case PROP_PARENT:
+ fwupd_device_set_parent(self, g_value_get_object(value));
+ break;
+ case PROP_UPDATE_STATE:
+ fwupd_device_set_update_state(self, g_value_get_uint(value));
+ break;
+ case PROP_BATTERY_LEVEL:
+ fwupd_device_set_battery_level(self, g_value_get_uint(value));
+ break;
+ case PROP_BATTERY_THRESHOLD:
+ fwupd_device_set_battery_threshold(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;
+
+ /**
+ * FwupdDevice:version-format:
+ *
+ * The version format of the device.
+ *
+ * Since: 1.2.9
+ */
+ 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);
+
+ /**
+ * FwupdDevice:flags:
+ *
+ * The device flags.
+ *
+ * Since: 0.9.3
+ */
+ pspec = g_param_spec_uint64("flags",
+ NULL,
+ NULL,
+ FWUPD_DEVICE_FLAG_NONE,
+ FWUPD_DEVICE_FLAG_UNKNOWN,
+ FWUPD_DEVICE_FLAG_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_FLAGS, pspec);
+
+ /**
+ * FwupdDevice:problems:
+ *
+ * The problems with the device that the user could fix, e.g. "lid open".
+ *
+ * Since: 1.8.1
+ */
+ pspec = g_param_spec_uint64("problems",
+ NULL,
+ NULL,
+ FWUPD_DEVICE_PROBLEM_NONE,
+ FWUPD_DEVICE_PROBLEM_UNKNOWN,
+ FWUPD_DEVICE_PROBLEM_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PROBLEMS, pspec);
+
+ /**
+ * FwupdDevice:protocol:
+ *
+ * The device protocol.
+ *
+ * Since: 1.3.6
+ * Deprecated: 1.5.8
+ */
+ pspec = g_param_spec_string("protocol",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PROTOCOL, pspec);
+
+ /**
+ * FwupdDevice:status:
+ *
+ * The current device status.
+ *
+ * Since: 1.4.0
+ */
+ pspec = g_param_spec_uint("status",
+ NULL,
+ NULL,
+ FWUPD_STATUS_UNKNOWN,
+ FWUPD_STATUS_LAST,
+ FWUPD_STATUS_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_STATUS, pspec);
+
+ /**
+ * FwupdDevice:parent:
+ *
+ * The device parent.
+ *
+ * Since: 1.0.8
+ */
+ pspec = g_param_spec_object("parent",
+ NULL,
+ NULL,
+ FWUPD_TYPE_DEVICE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PARENT, pspec);
+
+ /**
+ * FwupdDevice:update-state:
+ *
+ * The device update state.
+ *
+ * Since: 0.9.8
+ */
+ pspec = g_param_spec_uint("update-state",
+ NULL,
+ NULL,
+ FWUPD_UPDATE_STATE_UNKNOWN,
+ FWUPD_UPDATE_STATE_LAST,
+ FWUPD_UPDATE_STATE_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_UPDATE_STATE, pspec);
+
+ /**
+ * FwupdDevice:update-message:
+ *
+ * The device update message.
+ *
+ * Since: 1.2.4
+ */
+ pspec = g_param_spec_string("update-message",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_UPDATE_MESSAGE, pspec);
+
+ /**
+ * FwupdDevice:update-error:
+ *
+ * The device update error.
+ *
+ * Since: 0.9.8
+ */
+ pspec = g_param_spec_string("update-error",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_UPDATE_ERROR, pspec);
+
+ /**
+ * FwupdDevice:update-image:
+ *
+ * The update image for the device.
+ *
+ * Since: 1.4.5
+ */
+ pspec = g_param_spec_string("update-image",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_UPDATE_IMAGE, pspec);
+
+ /**
+ * FwupdDevice:battery-level:
+ *
+ * The device battery level in percent.
+ *
+ * Since: 1.5.8
+ */
+ pspec = g_param_spec_uint("battery-level",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_LEVEL, pspec);
+
+ /**
+ * FwupdDevice:battery-threshold:
+ *
+ * The device battery threshold in percent.
+ *
+ * Since: 1.5.8
+ */
+ pspec = g_param_spec_uint("battery-threshold",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_THRESHOLD, pspec);
+}
+
+static void
+fwupd_device_init(FwupdDevice *self)
+{
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+ 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->vendor_ids = g_ptr_array_new_with_free_func(g_free);
+ priv->protocols = g_ptr_array_new_with_free_func(g_free);
+ priv->issues = g_ptr_array_new_with_free_func(g_free);
+ priv->children = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ priv->releases = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ priv->battery_level = FWUPD_BATTERY_LEVEL_INVALID;
+ priv->battery_threshold = FWUPD_BATTERY_LEVEL_INVALID;
+}
+
+static void
+fwupd_device_finalize(GObject *object)
+{
+ FwupdDevice *self = FWUPD_DEVICE(object);
+ FwupdDevicePrivate *priv = GET_PRIVATE(self);
+
+ if (priv->parent != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->parent), (gpointer *)&priv->parent);
+ for (guint i = 0; i < priv->children->len; i++) {
+ FwupdDevice *child = g_ptr_array_index(priv->children, i);
+ g_object_weak_unref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
+ }
+
+ g_free(priv->description);
+ g_free(priv->id);
+ g_free(priv->parent_id);
+ g_free(priv->composite_id);
+ g_free(priv->name);
+ g_free(priv->serial);
+ g_free(priv->summary);
+ g_free(priv->branch);
+ g_free(priv->vendor);
+ g_free(priv->vendor_id);
+ g_free(priv->plugin);
+ g_free(priv->protocol);
+ g_free(priv->update_error);
+ g_free(priv->update_message);
+ g_free(priv->update_image);
+ 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->vendor_ids);
+ g_ptr_array_unref(priv->protocols);
+ g_ptr_array_unref(priv->instance_ids);
+ g_ptr_array_unref(priv->icons);
+ g_ptr_array_unref(priv->checksums);
+ g_ptr_array_unref(priv->children);
+ g_ptr_array_unref(priv->releases);
+ g_ptr_array_unref(priv->issues);
+
+ G_OBJECT_CLASS(fwupd_device_parent_class)->finalize(object);
+}
+
+static void
+fwupd_device_set_from_variant_iter(FwupdDevice *self, GVariantIter *iter)
+{
+ GVariant *value;
+ const gchar *key;
+ while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
+ fwupd_device_from_key_value(self, key, value);
+ g_variant_unref(value);
+ }
+}
+
+/**
+ * fwupd_device_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new device using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdDevice, or %NULL if @value was invalid
+ *
+ * Since: 1.0.0
+ **/
+FwupdDevice *
+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(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ dev = fwupd_device_new();
+ 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(value, "a{sv}", &iter);
+ fwupd_device_set_from_variant_iter(dev, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return dev;
+}
+
+/**
+ * fwupd_device_array_ensure_parents:
+ * @devices: (element-type FwupdDevice): devices
+ *
+ * Sets the parent object on all devices in the array using the parent ID.
+ *
+ * Since: 1.3.7
+ **/
+void
+fwupd_device_array_ensure_parents(GPtrArray *devices)
+{
+ g_autoptr(GHashTable) devices_by_id = NULL;
+
+ /* create hash of ID->FwupdDevice */
+ devices_by_id = g_hash_table_new(g_str_hash, g_str_equal);
+ for (guint i = 0; i < devices->len; i++) {
+ FwupdDevice *dev = g_ptr_array_index(devices, i);
+ if (fwupd_device_get_id(dev) == NULL)
+ continue;
+ 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 < devices->len; i++) {
+ FwupdDevice *dev = g_ptr_array_index(devices, 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);
+ if (dev_tmp != NULL)
+ fwupd_device_set_parent(dev, dev_tmp);
+ }
+ }
+}
+
+/**
+ * fwupd_device_array_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates an array of new devices using serialized 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_return_val_if_fail(value != NULL, 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++) {
+ 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);
+ }
+
+ /* set the parent on each child */
+ fwupd_device_array_ensure_parents(array);
+ return array;
+}
+
+/**
+ * fwupd_device_compare:
+ * @self1: a device
+ * @self2: a different device
+ *
+ * Comparison function for comparing two device objects.
+ *
+ * Returns: negative, 0 or positive
+ *
+ * Since: 1.1.1
+ **/
+gint
+fwupd_device_compare(FwupdDevice *self1, FwupdDevice *self2)
+{
+ FwupdDevicePrivate *priv1 = GET_PRIVATE(self1);
+ FwupdDevicePrivate *priv2 = GET_PRIVATE(self2);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self1), 0);
+ g_return_val_if_fail(FWUPD_IS_DEVICE(self2), 0);
+ return g_strcmp0(priv1->id, priv2->id);
+}
+
+/**
+ * fwupd_device_new:
+ *
+ * Creates a new device.
+ *
+ * Returns: a new #FwupdDevice
+ *
+ * Since: 0.9.3
+ **/
+FwupdDevice *
+fwupd_device_new(void)
+{
+ FwupdDevice *self;
+ self = g_object_new(FWUPD_TYPE_DEVICE, NULL);
+ return FWUPD_DEVICE(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-device.h b/fwupd-1.8.6/libfwupd/fwupd-device.h
new file mode 100644
index 0000000000000000000000000000000000000000..42322acd343f4c82693ee3e74f07ea3e098fe296
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-device.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-enums.h"
+#include "fwupd-release.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_DEVICE (fwupd_device_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdDevice, fwupd_device, FWUPD, DEVICE, GObject)
+
+struct _FwupdDeviceClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ void (*_fwupd_reserved7)(void);
+};
+
+FwupdDevice *
+fwupd_device_new(void);
+gchar *
+fwupd_device_to_string(FwupdDevice *self);
+
+const gchar *
+fwupd_device_get_id(FwupdDevice *self);
+void
+fwupd_device_set_id(FwupdDevice *self, const gchar *id);
+const gchar *
+fwupd_device_get_parent_id(FwupdDevice *self);
+void
+fwupd_device_set_parent_id(FwupdDevice *self, const gchar *parent_id);
+const gchar *
+fwupd_device_get_composite_id(FwupdDevice *self);
+void
+fwupd_device_set_composite_id(FwupdDevice *self, const gchar *composite_id);
+FwupdDevice *
+fwupd_device_get_root(FwupdDevice *self);
+FwupdDevice *
+fwupd_device_get_parent(FwupdDevice *self);
+void
+fwupd_device_set_parent(FwupdDevice *self, FwupdDevice *parent);
+void
+fwupd_device_add_child(FwupdDevice *self, FwupdDevice *child);
+void
+fwupd_device_remove_child(FwupdDevice *self, FwupdDevice *child);
+GPtrArray *
+fwupd_device_get_children(FwupdDevice *self);
+const gchar *
+fwupd_device_get_name(FwupdDevice *self);
+void
+fwupd_device_set_name(FwupdDevice *self, const gchar *name);
+const gchar *
+fwupd_device_get_serial(FwupdDevice *self);
+void
+fwupd_device_set_serial(FwupdDevice *self, const gchar *serial);
+const gchar *
+fwupd_device_get_summary(FwupdDevice *self);
+void
+fwupd_device_set_summary(FwupdDevice *self, const gchar *summary);
+const gchar *
+fwupd_device_get_branch(FwupdDevice *self);
+void
+fwupd_device_set_branch(FwupdDevice *self, const gchar *branch);
+const gchar *
+fwupd_device_get_description(FwupdDevice *self);
+void
+fwupd_device_set_description(FwupdDevice *self, const gchar *description);
+const gchar *
+fwupd_device_get_version(FwupdDevice *self);
+void
+fwupd_device_set_version(FwupdDevice *self, const gchar *version);
+const gchar *
+fwupd_device_get_version_lowest(FwupdDevice *self);
+void
+fwupd_device_set_version_lowest(FwupdDevice *self, const gchar *version_lowest);
+guint64
+fwupd_device_get_version_lowest_raw(FwupdDevice *self);
+void
+fwupd_device_set_version_lowest_raw(FwupdDevice *self, guint64 version_lowest_raw);
+const gchar *
+fwupd_device_get_version_bootloader(FwupdDevice *self);
+void
+fwupd_device_set_version_bootloader(FwupdDevice *self, const gchar *version_bootloader);
+guint64
+fwupd_device_get_version_bootloader_raw(FwupdDevice *self);
+void
+fwupd_device_set_version_bootloader_raw(FwupdDevice *self, guint64 version_bootloader_raw);
+guint64
+fwupd_device_get_version_raw(FwupdDevice *self);
+void
+fwupd_device_set_version_raw(FwupdDevice *self, guint64 version_raw);
+guint64
+fwupd_device_get_version_build_date(FwupdDevice *self);
+void
+fwupd_device_set_version_build_date(FwupdDevice *self, guint64 version_build_date);
+FwupdVersionFormat
+fwupd_device_get_version_format(FwupdDevice *self);
+void
+fwupd_device_set_version_format(FwupdDevice *self, FwupdVersionFormat version_format);
+guint32
+fwupd_device_get_flashes_left(FwupdDevice *self);
+void
+fwupd_device_set_flashes_left(FwupdDevice *self, guint32 flashes_left);
+guint32
+fwupd_device_get_battery_level(FwupdDevice *self);
+void
+fwupd_device_set_battery_level(FwupdDevice *self, guint32 battery_level);
+guint32
+fwupd_device_get_battery_threshold(FwupdDevice *self);
+void
+fwupd_device_set_battery_threshold(FwupdDevice *self, guint32 battery_threshold);
+guint32
+fwupd_device_get_install_duration(FwupdDevice *self);
+void
+fwupd_device_set_install_duration(FwupdDevice *self, guint32 duration);
+guint64
+fwupd_device_get_flags(FwupdDevice *self);
+void
+fwupd_device_set_flags(FwupdDevice *self, guint64 flags);
+void
+fwupd_device_add_flag(FwupdDevice *self, FwupdDeviceFlags flag);
+void
+fwupd_device_remove_flag(FwupdDevice *self, FwupdDeviceFlags flag);
+gboolean
+fwupd_device_has_flag(FwupdDevice *self, FwupdDeviceFlags flag);
+guint64
+fwupd_device_get_problems(FwupdDevice *self);
+void
+fwupd_device_set_problems(FwupdDevice *self, guint64 problems);
+void
+fwupd_device_add_problem(FwupdDevice *self, FwupdDeviceProblem problem);
+void
+fwupd_device_remove_problem(FwupdDevice *self, FwupdDeviceProblem problem);
+gboolean
+fwupd_device_has_problem(FwupdDevice *self, FwupdDeviceProblem problem);
+guint64
+fwupd_device_get_created(FwupdDevice *self);
+void
+fwupd_device_set_created(FwupdDevice *self, guint64 created);
+guint64
+fwupd_device_get_modified(FwupdDevice *self);
+void
+fwupd_device_set_modified(FwupdDevice *self, guint64 modified);
+GPtrArray *
+fwupd_device_get_checksums(FwupdDevice *self);
+void
+fwupd_device_add_checksum(FwupdDevice *self, const gchar *checksum);
+const gchar *
+fwupd_device_get_plugin(FwupdDevice *self);
+void
+fwupd_device_set_plugin(FwupdDevice *self, const gchar *plugin);
+G_DEPRECATED_FOR(fwupd_device_get_protocols)
+const gchar *
+fwupd_device_get_protocol(FwupdDevice *self);
+G_DEPRECATED_FOR(fwupd_device_add_protocol)
+void
+fwupd_device_set_protocol(FwupdDevice *self, const gchar *protocol);
+void
+fwupd_device_add_protocol(FwupdDevice *self, const gchar *protocol);
+gboolean
+fwupd_device_has_protocol(FwupdDevice *self, const gchar *protocol);
+GPtrArray *
+fwupd_device_get_protocols(FwupdDevice *self);
+const gchar *
+fwupd_device_get_vendor(FwupdDevice *self);
+void
+fwupd_device_set_vendor(FwupdDevice *self, const gchar *vendor);
+G_DEPRECATED_FOR(fwupd_device_get_vendor_ids)
+const gchar *
+fwupd_device_get_vendor_id(FwupdDevice *self);
+G_DEPRECATED_FOR(fwupd_device_add_vendor_id)
+void
+fwupd_device_set_vendor_id(FwupdDevice *self, const gchar *vendor_id);
+void
+fwupd_device_add_vendor_id(FwupdDevice *self, const gchar *vendor_id);
+gboolean
+fwupd_device_has_vendor_id(FwupdDevice *self, const gchar *vendor_id);
+GPtrArray *
+fwupd_device_get_vendor_ids(FwupdDevice *self);
+void
+fwupd_device_add_guid(FwupdDevice *self, const gchar *guid);
+gboolean
+fwupd_device_has_guid(FwupdDevice *self, const gchar *guid);
+GPtrArray *
+fwupd_device_get_guids(FwupdDevice *self);
+const gchar *
+fwupd_device_get_guid_default(FwupdDevice *self);
+void
+fwupd_device_add_instance_id(FwupdDevice *self, const gchar *instance_id);
+gboolean
+fwupd_device_has_instance_id(FwupdDevice *self, const gchar *instance_id);
+GPtrArray *
+fwupd_device_get_instance_ids(FwupdDevice *self);
+void
+fwupd_device_add_icon(FwupdDevice *self, const gchar *icon);
+gboolean
+fwupd_device_has_icon(FwupdDevice *self, const gchar *icon);
+GPtrArray *
+fwupd_device_get_icons(FwupdDevice *self);
+GPtrArray *
+fwupd_device_get_issues(FwupdDevice *self);
+void
+fwupd_device_add_issue(FwupdDevice *self, const gchar *issue);
+
+FwupdUpdateState
+fwupd_device_get_update_state(FwupdDevice *self);
+void
+fwupd_device_set_update_state(FwupdDevice *self, FwupdUpdateState update_state);
+const gchar *
+fwupd_device_get_update_error(FwupdDevice *self);
+void
+fwupd_device_set_update_error(FwupdDevice *self, const gchar *update_error);
+const gchar *
+fwupd_device_get_update_message(FwupdDevice *self);
+void
+fwupd_device_set_update_message(FwupdDevice *self, const gchar *update_message);
+const gchar *
+fwupd_device_get_update_image(FwupdDevice *self);
+void
+fwupd_device_set_update_image(FwupdDevice *self, const gchar *update_image);
+FwupdStatus
+fwupd_device_get_status(FwupdDevice *self);
+void
+fwupd_device_set_status(FwupdDevice *self, FwupdStatus status);
+void
+fwupd_device_add_release(FwupdDevice *self, FwupdRelease *release);
+GPtrArray *
+fwupd_device_get_releases(FwupdDevice *self);
+FwupdRelease *
+fwupd_device_get_release_default(FwupdDevice *self);
+gint
+fwupd_device_compare(FwupdDevice *self1, FwupdDevice *self2);
+
+FwupdDevice *
+fwupd_device_from_variant(GVariant *value);
+GPtrArray *
+fwupd_device_array_from_variant(GVariant *value);
+void
+fwupd_device_array_ensure_parents(GPtrArray *devices);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-enums-private.h b/fwupd-1.8.6/libfwupd/fwupd-enums-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..b7926a4eb985d3d6c468131d28f63aca51a39fb1
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-enums-private.h
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+/**
+ * FWUPD_RESULT_KEY_APPSTREAM_ID:
+ *
+ * Result key to represent AppstreamId
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_APPSTREAM_ID "AppstreamId"
+/**
+ * FWUPD_RESULT_KEY_RELEASE_ID:
+ *
+ * Result key to represent the release ID.
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_RELEASE_ID "ReleaseId"
+/**
+ * FWUPD_RESULT_KEY_CHECKSUM:
+ *
+ * Result key to represent Checksum
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_CHECKSUM "Checksum"
+/**
+ * FWUPD_RESULT_KEY_TAGS:
+ *
+ * Result key to represent release tags
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_TAGS "Tags"
+/**
+ * FWUPD_RESULT_KEY_CREATED:
+ *
+ * Result key to represent Created
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_CREATED "Created"
+/**
+ * FWUPD_RESULT_KEY_DESCRIPTION:
+ *
+ * Result key to represent Description
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_DESCRIPTION "Description"
+/**
+ * FWUPD_RESULT_KEY_DETACH_CAPTION:
+ *
+ * Result key to represent DetachCaption
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_DETACH_CAPTION "DetachCaption"
+/**
+ * FWUPD_RESULT_KEY_DETACH_IMAGE:
+ *
+ * Result key to represent DetachImage
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_DETACH_IMAGE "DetachImage"
+/**
+ * FWUPD_RESULT_KEY_DEVICE_ID:
+ *
+ * Result key to represent DeviceId
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_DEVICE_ID "DeviceId"
+/**
+ * FWUPD_RESULT_KEY_PARENT_DEVICE_ID:
+ *
+ * Result key to represent ParentDeviceId
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_PARENT_DEVICE_ID "ParentDeviceId"
+/**
+ * FWUPD_RESULT_KEY_COMPOSITE_ID:
+ *
+ * Result key to represent CompositeId
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_COMPOSITE_ID "CompositeId"
+/**
+ * FWUPD_RESULT_KEY_FILENAME:
+ *
+ * Result key to represent Filename
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_FILENAME "Filename"
+/**
+ * FWUPD_RESULT_KEY_PROTOCOL:
+ *
+ * Result key to represent Protocol
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_PROTOCOL "Protocol"
+/**
+ * FWUPD_RESULT_KEY_CATEGORIES:
+ *
+ * Result key to represent Categories
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_CATEGORIES "Categories"
+/**
+ * FWUPD_RESULT_KEY_ISSUES:
+ *
+ * Result key to represent Issues
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_ISSUES "Issues"
+/**
+ * FWUPD_RESULT_KEY_FLAGS:
+ *
+ * Result key to represent Flags
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_FLAGS "Flags"
+/**
+ * FWUPD_RESULT_KEY_FLASHES_LEFT:
+ *
+ * Result key to represent FlashesLeft
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_FLASHES_LEFT "FlashesLeft"
+/**
+ * FWUPD_RESULT_KEY_URGENCY:
+ *
+ * Result key to represent Urgency
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_URGENCY "Urgency"
+/**
+ * FWUPD_RESULT_KEY_REQUEST_KIND:
+ *
+ * Result key to represent RequestKind
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_REQUEST_KIND "RequestKind"
+/**
+ * FWUPD_RESULT_KEY_HSI_LEVEL:
+ *
+ * Result key to represent HsiLevel
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_HSI_LEVEL "HsiLevel"
+/**
+ * FWUPD_RESULT_KEY_HSI_RESULT:
+ *
+ * Result key to represent HsiResult
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_HSI_RESULT "HsiResult"
+/**
+ * FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK:
+ *
+ * Result key to represent the fallback HsiResult
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK "HsiResultFallback"
+/**
+ * FWUPD_RESULT_KEY_INSTALL_DURATION:
+ *
+ * Result key to represent InstallDuration
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_INSTALL_DURATION "InstallDuration"
+/**
+ * FWUPD_RESULT_KEY_GUID:
+ *
+ * Result key to represent Guid
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_GUID "Guid"
+/**
+ * FWUPD_RESULT_KEY_INSTANCE_IDS:
+ *
+ * Result key to represent InstanceIds
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_INSTANCE_IDS "InstanceIds"
+/**
+ * FWUPD_RESULT_KEY_HOMEPAGE:
+ *
+ * Result key to represent Homepage
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_HOMEPAGE "Homepage"
+/**
+ * FWUPD_RESULT_KEY_DETAILS_URL:
+ *
+ * Result key to represent DetailsUrl
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_DETAILS_URL "DetailsUrl"
+/**
+ * FWUPD_RESULT_KEY_SOURCE_URL:
+ *
+ * Result key to represent SourceUrl
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_SOURCE_URL "SourceUrl"
+/**
+ * FWUPD_RESULT_KEY_ICON:
+ *
+ * Result key to represent Icon
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_ICON "Icon"
+/**
+ * FWUPD_RESULT_KEY_LICENSE:
+ *
+ * Result key to represent License
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_LICENSE "License"
+/**
+ * FWUPD_RESULT_KEY_MODIFIED:
+ *
+ * Result key to represent Modified
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_MODIFIED "Modified"
+/**
+ * FWUPD_RESULT_KEY_VERSION_BUILD_DATE:
+ *
+ * Result key to represent VersionBuildDate
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_BUILD_DATE "VersionBuildDate"
+/**
+ * FWUPD_RESULT_KEY_METADATA:
+ *
+ * Result key to represent Metadata
+ *
+ * The D-Bus type signature string is 'a{ss}' i.e. a string dictionary.
+ **/
+#define FWUPD_RESULT_KEY_METADATA "Metadata"
+/**
+ * FWUPD_RESULT_KEY_NAME:
+ *
+ * Result key to represent Name
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_NAME "Name"
+/**
+ * FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX:
+ *
+ * Result key to represent NameVariantSuffix
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX "NameVariantSuffix"
+/**
+ * FWUPD_RESULT_KEY_PLUGIN:
+ *
+ * Result key to represent Plugin
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_PLUGIN "Plugin"
+/**
+ * FWUPD_RESULT_KEY_RELEASE:
+ *
+ * Result key to represent Release
+ *
+ * The D-Bus type signature string is 'a{sv}' i.e. a variant dictionary.
+ **/
+#define FWUPD_RESULT_KEY_RELEASE "Release"
+/**
+ * FWUPD_RESULT_KEY_REMOTE_ID:
+ *
+ * Result key to represent RemoteId
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_REMOTE_ID "RemoteId"
+/**
+ * FWUPD_RESULT_KEY_SERIAL:
+ *
+ * Result key to represent Serial
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_SERIAL "Serial"
+/**
+ * FWUPD_RESULT_KEY_SIZE:
+ *
+ * Result key to represent Size
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_SIZE "Size"
+/**
+ * FWUPD_RESULT_KEY_STATUS:
+ *
+ * Result key to represent Status
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_STATUS "Status"
+/**
+ * FWUPD_RESULT_KEY_SUMMARY:
+ *
+ * Result key to represent Summary
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_SUMMARY "Summary"
+/**
+ * FWUPD_RESULT_KEY_BRANCH:
+ *
+ * Result key to represent Branch
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_BRANCH "Branch"
+/**
+ * FWUPD_RESULT_KEY_TRUST_FLAGS:
+ *
+ * Result key to represent TrustFlags
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags"
+/**
+ * FWUPD_RESULT_KEY_PROBLEMS:
+ *
+ * Result key to represent problems
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_PROBLEMS "Problems"
+/**
+ * FWUPD_RESULT_KEY_UPDATE_MESSAGE:
+ *
+ * Result key to represent UpdateMessage
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage"
+/**
+ * FWUPD_RESULT_KEY_UPDATE_IMAGE:
+ *
+ * Result key to represent UpdateImage
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_UPDATE_IMAGE "UpdateImage"
+/**
+ * FWUPD_RESULT_KEY_UPDATE_ERROR:
+ *
+ * Result key to represent UpdateError
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_UPDATE_ERROR "UpdateError"
+/**
+ * FWUPD_RESULT_KEY_UPDATE_STATE:
+ *
+ * Result key to represent UpdateState
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_UPDATE_STATE "UpdateState"
+/**
+ * FWUPD_RESULT_KEY_URI:
+ *
+ * Result key to represent Uri
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_URI "Uri"
+/**
+ * FWUPD_RESULT_KEY_LOCATIONS:
+ *
+ * Result key to represent Locations
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_LOCATIONS "Locations"
+/**
+ * FWUPD_RESULT_KEY_VENDOR_ID:
+ *
+ * Result key to represent VendorId
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_VENDOR_ID "VendorId"
+/**
+ * FWUPD_RESULT_KEY_VENDOR:
+ *
+ * Result key to represent Vendor
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_VENDOR "Vendor"
+/**
+ * FWUPD_RESULT_KEY_VERSION_BOOTLOADER:
+ *
+ * Result key to represent VersionBootloader
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_BOOTLOADER "VersionBootloader"
+/**
+ * FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW:
+ *
+ * Result key to represent VersionBootloaderRaw
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW "VersionBootloaderRaw"
+/**
+ * FWUPD_RESULT_KEY_VERSION_FORMAT:
+ *
+ * Result key to represent VersionFormat
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_FORMAT "VersionFormat"
+/**
+ * FWUPD_RESULT_KEY_VERSION_RAW:
+ *
+ * Result key to represent VersionRaw
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_RAW "VersionRaw"
+/**
+ * FWUPD_RESULT_KEY_VERSION_LOWEST:
+ *
+ * Result key to represent VersionLowest
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_LOWEST "VersionLowest"
+/**
+ * FWUPD_RESULT_KEY_VERSION_LOWEST_RAW:
+ *
+ * Result key to represent VersionLowestRaw
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_VERSION_LOWEST_RAW "VersionLowestRaw"
+/**
+ * FWUPD_RESULT_KEY_VERSION:
+ *
+ * Result key to represent Version
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_VERSION "Version"
+/**
+ * FWUPD_RESULT_KEY_BATTERY_LEVEL:
+ *
+ * Result key to represent the current battery level in percent.
+ * Expressed from 0-100%, or 101 for invalid or unset.
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_BATTERY_LEVEL "BatteryLevel"
+/**
+ * FWUPD_RESULT_KEY_BATTERY_THRESHOLD:
+ *
+ * Result key to represent the minimum battery level required to perform an update.
+ * Expressed from 0-100%, or 101 for invalid or unset.
+ *
+ * The D-Bus type signature string is 'u' i.e. a unsigned 32 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_BATTERY_THRESHOLD "BatteryThreshold"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_ID:
+ *
+ * Result key to represent the unique identifier of the BIOS setting.
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_ID "BiosSettingId"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE:
+ *
+ * Result key to represent the value that would enable this attribute.
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE "BiosSettingTargetValue"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE:
+ *
+ * Result key to represent the current value of BIOS setting.
+ *
+ * The D-Bus type signature string is 's' i.e. a string.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE "BiosSettingCurrentValue"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_TYPE:
+ *
+ * Result key to represent the type of BIOS setting.
+ * 0 is invalid, 1+ represent an attribute type
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_TYPE "BiosSettingType"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES:
+ *
+ * Result key to represent possible values
+ *
+ * The D-Bus type signature string is 'as' i.e. an array of strings.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_POSSIBLE_VALUES "BiosSettingPossibleValues"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND:
+ *
+ * Result key to represent the upper bound for an integer BIOS setting.
+ * or minimum length for string BIOS setting.
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_LOWER_BOUND "BiosSettingLowerBound"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND:
+ *
+ * Result key to represent the lower bound for an integer BIOS setting
+ * or maximum length for string BIOS setting.
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_UPPER_BOUND "BiosSettingUpperBound"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT:
+ *
+ * Result key to represent the scalar increment for an integer BIOS setting.
+ *
+ * The D-Bus type signature string is 't' i.e. a unsigned 64 bit integer.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_SCALAR_INCREMENT "BiosSettingScalarIncrement"
+/**
+ * FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY:
+ *
+ * Result key to represent whether BIOS setting is read only
+ *
+ * The D-Bus type signature string is 'b' i.e. a boolean.
+ **/
+#define FWUPD_RESULT_KEY_BIOS_SETTING_READ_ONLY "BiosSettingReadOnly"
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-enums.c b/fwupd-1.8.6/libfwupd/fwupd-enums.c
new file mode 100644
index 0000000000000000000000000000000000000000..4d457b5ed756b3d0bc43dfa7f76624448d416533
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-enums.c
@@ -0,0 +1,914 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fwupd-enums.h"
+
+/**
+ * fwupd_status_to_string:
+ * @status: a status, e.g. %FWUPD_STATUS_DECOMPRESSING
+ *
+ * Converts an enumerated status to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 0.1.1
+ **/
+const gchar *
+fwupd_status_to_string(FwupdStatus status)
+{
+ if (status == FWUPD_STATUS_UNKNOWN)
+ return "unknown";
+ if (status == FWUPD_STATUS_IDLE)
+ return "idle";
+ if (status == FWUPD_STATUS_DECOMPRESSING)
+ return "decompressing";
+ if (status == FWUPD_STATUS_LOADING)
+ return "loading";
+ if (status == FWUPD_STATUS_DEVICE_RESTART)
+ return "device-restart";
+ if (status == FWUPD_STATUS_DEVICE_WRITE)
+ return "device-write";
+ if (status == FWUPD_STATUS_DEVICE_READ)
+ return "device-read";
+ if (status == FWUPD_STATUS_DEVICE_ERASE)
+ return "device-erase";
+ if (status == FWUPD_STATUS_DEVICE_VERIFY)
+ return "device-verify";
+ if (status == FWUPD_STATUS_DEVICE_BUSY)
+ return "device-busy";
+ if (status == FWUPD_STATUS_SCHEDULING)
+ return "scheduling";
+ if (status == FWUPD_STATUS_DOWNLOADING)
+ return "downloading";
+ if (status == FWUPD_STATUS_WAITING_FOR_AUTH)
+ return "waiting-for-auth";
+ if (status == FWUPD_STATUS_SHUTDOWN)
+ return "shutdown";
+ return NULL;
+}
+
+/**
+ * fwupd_status_from_string:
+ * @status: (nullable): a string, e.g. `decompressing`
+ *
+ * Converts a string to an enumerated status.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 0.1.1
+ **/
+FwupdStatus
+fwupd_status_from_string(const gchar *status)
+{
+ if (g_strcmp0(status, "unknown") == 0)
+ return FWUPD_STATUS_UNKNOWN;
+ if (g_strcmp0(status, "idle") == 0)
+ return FWUPD_STATUS_IDLE;
+ if (g_strcmp0(status, "decompressing") == 0)
+ return FWUPD_STATUS_DECOMPRESSING;
+ if (g_strcmp0(status, "loading") == 0)
+ return FWUPD_STATUS_LOADING;
+ if (g_strcmp0(status, "device-restart") == 0)
+ return FWUPD_STATUS_DEVICE_RESTART;
+ if (g_strcmp0(status, "device-write") == 0)
+ return FWUPD_STATUS_DEVICE_WRITE;
+ if (g_strcmp0(status, "device-verify") == 0)
+ return FWUPD_STATUS_DEVICE_VERIFY;
+ if (g_strcmp0(status, "scheduling") == 0)
+ return FWUPD_STATUS_SCHEDULING;
+ if (g_strcmp0(status, "downloading") == 0)
+ return FWUPD_STATUS_DOWNLOADING;
+ if (g_strcmp0(status, "device-read") == 0)
+ return FWUPD_STATUS_DEVICE_READ;
+ if (g_strcmp0(status, "device-erase") == 0)
+ return FWUPD_STATUS_DEVICE_ERASE;
+ if (g_strcmp0(status, "device-busy") == 0)
+ 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;
+}
+
+/**
+ * fwupd_device_flag_to_string:
+ * @device_flag: a device flag, e.g. %FWUPD_DEVICE_FLAG_REQUIRE_AC
+ *
+ * Converts a device flag to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+fwupd_device_flag_to_string(FwupdDeviceFlags device_flag)
+{
+ if (device_flag == FWUPD_DEVICE_FLAG_NONE)
+ return "none";
+ if (device_flag == FWUPD_DEVICE_FLAG_INTERNAL)
+ return "internal";
+ if (device_flag == FWUPD_DEVICE_FLAG_UPDATABLE)
+ return "updatable";
+ if (device_flag == FWUPD_DEVICE_FLAG_ONLY_OFFLINE)
+ return "only-offline";
+ if (device_flag == FWUPD_DEVICE_FLAG_REQUIRE_AC)
+ return "require-ac";
+ if (device_flag == FWUPD_DEVICE_FLAG_LOCKED)
+ return "locked";
+ if (device_flag == FWUPD_DEVICE_FLAG_SUPPORTED)
+ return "supported";
+ if (device_flag == FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)
+ return "needs-bootloader";
+ if (device_flag == FWUPD_DEVICE_FLAG_REGISTERED)
+ 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_TRUSTED)
+ return "trusted";
+ 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_HISTORICAL)
+ return "historical";
+ if (device_flag == FWUPD_DEVICE_FLAG_ONLY_SUPPORTED)
+ return "only-supported";
+ if (device_flag == FWUPD_DEVICE_FLAG_WILL_DISAPPEAR)
+ return "will-disappear";
+ if (device_flag == FWUPD_DEVICE_FLAG_CAN_VERIFY)
+ return "can-verify";
+ if (device_flag == FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE)
+ return "can-verify-image";
+ if (device_flag == FWUPD_DEVICE_FLAG_DUAL_IMAGE)
+ return "dual-image";
+ if (device_flag == FWUPD_DEVICE_FLAG_SELF_RECOVERY)
+ return "self-recovery";
+ if (device_flag == FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)
+ return "usable-during-update";
+ if (device_flag == FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED)
+ return "version-check-required";
+ if (device_flag == FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES)
+ return "install-all-releases";
+ if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_NAME)
+ return "md-set-name";
+ if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY)
+ return "md-set-name-category";
+ if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_VERFMT)
+ return "md-set-verfmt";
+ if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_ICON)
+ return "md-set-icon";
+ if (device_flag == FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS)
+ return "add-counterpart-guids";
+ if (device_flag == FWUPD_DEVICE_FLAG_NO_GUID_MATCHING)
+ return "no-guid-matching";
+ if (device_flag == FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN)
+ return "updatable-hidden";
+ if (device_flag == FWUPD_DEVICE_FLAG_SKIPS_RESTART)
+ return "skips-restart";
+ if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)
+ return "has-multiple-branches";
+ if (device_flag == FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL)
+ return "backup-before-install";
+ if (device_flag == FWUPD_DEVICE_FLAG_WILDCARD_INSTALL)
+ return "wildcard-install";
+ if (device_flag == FWUPD_DEVICE_FLAG_ONLY_VERSION_UPGRADE)
+ return "only-version-upgrade";
+ if (device_flag == FWUPD_DEVICE_FLAG_UNREACHABLE)
+ return "unreachable";
+ if (device_flag == FWUPD_DEVICE_FLAG_AFFECTS_FDE)
+ return "affects-fde";
+ if (device_flag == FWUPD_DEVICE_FLAG_END_OF_LIFE)
+ return "end-of-life";
+ if (device_flag == FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD)
+ return "signed-payload";
+ if (device_flag == FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD)
+ return "unsigned-payload";
+ if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN)
+ return "unknown";
+ return NULL;
+}
+
+/**
+ * fwupd_device_flag_from_string:
+ * @device_flag: (nullable): a string, e.g. `require-ac`
+ *
+ * Converts a string to an enumerated device flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 0.7.0
+ **/
+FwupdDeviceFlags
+fwupd_device_flag_from_string(const gchar *device_flag)
+{
+ if (g_strcmp0(device_flag, "none") == 0)
+ return FWUPD_DEVICE_FLAG_NONE;
+ if (g_strcmp0(device_flag, "internal") == 0)
+ return FWUPD_DEVICE_FLAG_INTERNAL;
+ if (g_strcmp0(device_flag, "updatable") == 0 || g_strcmp0(device_flag, "allow-online") == 0)
+ return FWUPD_DEVICE_FLAG_UPDATABLE;
+ if (g_strcmp0(device_flag, "only-offline") == 0 ||
+ g_strcmp0(device_flag, "allow-offline") == 0)
+ return FWUPD_DEVICE_FLAG_ONLY_OFFLINE;
+ if (g_strcmp0(device_flag, "require-ac") == 0)
+ return FWUPD_DEVICE_FLAG_REQUIRE_AC;
+ if (g_strcmp0(device_flag, "locked") == 0)
+ return FWUPD_DEVICE_FLAG_LOCKED;
+ if (g_strcmp0(device_flag, "supported") == 0)
+ return FWUPD_DEVICE_FLAG_SUPPORTED;
+ if (g_strcmp0(device_flag, "needs-bootloader") == 0)
+ return FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER;
+ if (g_strcmp0(device_flag, "registered") == 0)
+ 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, "trusted") == 0)
+ return FWUPD_DEVICE_FLAG_TRUSTED;
+ 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;
+ if (g_strcmp0(device_flag, "historical") == 0)
+ return FWUPD_DEVICE_FLAG_HISTORICAL;
+ if (g_strcmp0(device_flag, "only-supported") == 0)
+ return FWUPD_DEVICE_FLAG_ONLY_SUPPORTED;
+ if (g_strcmp0(device_flag, "will-disappear") == 0)
+ return FWUPD_DEVICE_FLAG_WILL_DISAPPEAR;
+ if (g_strcmp0(device_flag, "can-verify") == 0)
+ return FWUPD_DEVICE_FLAG_CAN_VERIFY;
+ if (g_strcmp0(device_flag, "can-verify-image") == 0)
+ return FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE;
+ if (g_strcmp0(device_flag, "dual-image") == 0)
+ return FWUPD_DEVICE_FLAG_DUAL_IMAGE;
+ if (g_strcmp0(device_flag, "self-recovery") == 0)
+ return FWUPD_DEVICE_FLAG_SELF_RECOVERY;
+ if (g_strcmp0(device_flag, "usable-during-update") == 0)
+ return FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE;
+ if (g_strcmp0(device_flag, "version-check-required") == 0)
+ return FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED;
+ if (g_strcmp0(device_flag, "install-all-releases") == 0)
+ return FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES;
+ if (g_strcmp0(device_flag, "md-set-name") == 0)
+ return FWUPD_DEVICE_FLAG_MD_SET_NAME;
+ if (g_strcmp0(device_flag, "md-set-name-category") == 0)
+ return FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY;
+ if (g_strcmp0(device_flag, "md-set-verfmt") == 0)
+ return FWUPD_DEVICE_FLAG_MD_SET_VERFMT;
+ if (g_strcmp0(device_flag, "md-set-icon") == 0)
+ return FWUPD_DEVICE_FLAG_MD_SET_ICON;
+ if (g_strcmp0(device_flag, "add-counterpart-guids") == 0)
+ return FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS;
+ if (g_strcmp0(device_flag, "no-guid-matching") == 0)
+ return FWUPD_DEVICE_FLAG_NO_GUID_MATCHING;
+ if (g_strcmp0(device_flag, "updatable-hidden") == 0)
+ return FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN;
+ if (g_strcmp0(device_flag, "skips-restart") == 0)
+ return FWUPD_DEVICE_FLAG_SKIPS_RESTART;
+ if (g_strcmp0(device_flag, "has-multiple-branches") == 0)
+ return FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES;
+ if (g_strcmp0(device_flag, "backup-before-install") == 0)
+ return FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL;
+ if (g_strcmp0(device_flag, "wildcard-install") == 0)
+ return FWUPD_DEVICE_FLAG_WILDCARD_INSTALL;
+ if (g_strcmp0(device_flag, "only-version-upgrade") == 0)
+ return FWUPD_DEVICE_FLAG_ONLY_VERSION_UPGRADE;
+ if (g_strcmp0(device_flag, "unreachable") == 0)
+ return FWUPD_DEVICE_FLAG_UNREACHABLE;
+ if (g_strcmp0(device_flag, "affects-fde") == 0)
+ return FWUPD_DEVICE_FLAG_AFFECTS_FDE;
+ if (g_strcmp0(device_flag, "end-of-life") == 0)
+ return FWUPD_DEVICE_FLAG_END_OF_LIFE;
+ if (g_strcmp0(device_flag, "signed-payload") == 0)
+ return FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD;
+ if (g_strcmp0(device_flag, "unsigned-payload") == 0)
+ return FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD;
+ return FWUPD_DEVICE_FLAG_UNKNOWN;
+}
+
+/**
+ * fwupd_device_problem_to_string:
+ * @device_problem: a device inhibit kind, e.g. %FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
+ *
+ * Converts a device inhibit kind to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.8.1
+ **/
+const gchar *
+fwupd_device_problem_to_string(FwupdDeviceProblem device_problem)
+{
+ if (device_problem == FWUPD_DEVICE_PROBLEM_NONE)
+ return "none";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW)
+ return "system-power-too-low";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_UNREACHABLE)
+ return "unreachable";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW)
+ return "power-too-low";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_UPDATE_PENDING)
+ return "update-pending";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER)
+ return "require-ac-power";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_LID_IS_CLOSED)
+ return "lid-is-closed";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_IS_EMULATED)
+ return "is-emulated";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_MISSING_LICENSE)
+ return "missing-license";
+ if (device_problem == FWUPD_DEVICE_PROBLEM_UNKNOWN)
+ return "unknown";
+ return NULL;
+}
+
+/**
+ * fwupd_device_problem_from_string:
+ * @device_problem: (nullable): a string, e.g. `require-ac`
+ *
+ * Converts a string to a enumerated device inhibit kind.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.8.1
+ **/
+FwupdDeviceProblem
+fwupd_device_problem_from_string(const gchar *device_problem)
+{
+ if (g_strcmp0(device_problem, "none") == 0)
+ return FWUPD_DEVICE_PROBLEM_NONE;
+ if (g_strcmp0(device_problem, "system-power-too-low") == 0)
+ return FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW;
+ if (g_strcmp0(device_problem, "unreachable") == 0)
+ return FWUPD_DEVICE_PROBLEM_UNREACHABLE;
+ if (g_strcmp0(device_problem, "power-too-low") == 0)
+ return FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW;
+ if (g_strcmp0(device_problem, "update-pending") == 0)
+ return FWUPD_DEVICE_PROBLEM_UPDATE_PENDING;
+ if (g_strcmp0(device_problem, "require-ac-power") == 0)
+ return FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER;
+ if (g_strcmp0(device_problem, "lid-is-closed") == 0)
+ return FWUPD_DEVICE_PROBLEM_LID_IS_CLOSED;
+ if (g_strcmp0(device_problem, "is-emulated") == 0)
+ return FWUPD_DEVICE_PROBLEM_IS_EMULATED;
+ if (g_strcmp0(device_problem, "missing-license") == 0)
+ return FWUPD_DEVICE_PROBLEM_MISSING_LICENSE;
+ return FWUPD_DEVICE_PROBLEM_UNKNOWN;
+}
+
+/**
+ * fwupd_plugin_flag_to_string:
+ * @plugin_flag: plugin flags, e.g. %FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE
+ *
+ * Converts an enumerated plugin flag to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_plugin_flag_to_string(FwupdPluginFlags plugin_flag)
+{
+ if (plugin_flag == FWUPD_DEVICE_FLAG_NONE)
+ return "none";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_DISABLED)
+ return "disabled";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_USER_WARNING)
+ return "user-warning";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE)
+ return "clear-updatable";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_NO_HARDWARE)
+ return "no-hardware";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED)
+ return "capsules-unsupported";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED)
+ return "unlock-required";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED)
+ return "efivar-not-mounted";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND)
+ return "esp-not-found";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_LEGACY_BIOS)
+ return "legacy-bios";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_FAILED_OPEN)
+ return "failed-open";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_REQUIRE_HWID)
+ return "require-hwid";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD)
+ return "kernel-too-old";
+ if (plugin_flag == FWUPD_DEVICE_FLAG_UNKNOWN)
+ return "unknown";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_AUTH_REQUIRED)
+ return "auth-required";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_SECURE_CONFIG)
+ return "secure-config";
+ if (plugin_flag == FWUPD_PLUGIN_FLAG_MODULAR)
+ return "modular";
+ return NULL;
+}
+
+/**
+ * fwupd_plugin_flag_from_string:
+ * @plugin_flag: (nullable): a string, e.g. `require-ac`
+ *
+ * Converts a string to an enumerated plugin flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.5.0
+ **/
+FwupdPluginFlags
+fwupd_plugin_flag_from_string(const gchar *plugin_flag)
+{
+ if (g_strcmp0(plugin_flag, "none") == 0)
+ return FWUPD_DEVICE_FLAG_NONE;
+ if (g_strcmp0(plugin_flag, "disabled") == 0)
+ return FWUPD_PLUGIN_FLAG_DISABLED;
+ if (g_strcmp0(plugin_flag, "user-warning") == 0)
+ return FWUPD_PLUGIN_FLAG_USER_WARNING;
+ if (g_strcmp0(plugin_flag, "clear-updatable") == 0)
+ return FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE;
+ if (g_strcmp0(plugin_flag, "no-hardware") == 0)
+ return FWUPD_PLUGIN_FLAG_NO_HARDWARE;
+ if (g_strcmp0(plugin_flag, "capsules-unsupported") == 0)
+ return FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED;
+ if (g_strcmp0(plugin_flag, "unlock-required") == 0)
+ return FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED;
+ if (g_strcmp0(plugin_flag, "efivar-not-mounted") == 0)
+ return FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED;
+ if (g_strcmp0(plugin_flag, "esp-not-found") == 0)
+ return FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND;
+ if (g_strcmp0(plugin_flag, "legacy-bios") == 0)
+ return FWUPD_PLUGIN_FLAG_LEGACY_BIOS;
+ if (g_strcmp0(plugin_flag, "failed-open") == 0)
+ return FWUPD_PLUGIN_FLAG_FAILED_OPEN;
+ if (g_strcmp0(plugin_flag, "require-hwid") == 0)
+ return FWUPD_PLUGIN_FLAG_REQUIRE_HWID;
+ if (g_strcmp0(plugin_flag, "kernel-too-old") == 0)
+ return FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD;
+ if (g_strcmp0(plugin_flag, "auth-required") == 0)
+ return FWUPD_PLUGIN_FLAG_AUTH_REQUIRED;
+ if (g_strcmp0(plugin_flag, "secure-config") == 0)
+ return FWUPD_PLUGIN_FLAG_SECURE_CONFIG;
+ if (g_strcmp0(plugin_flag, "modular") == 0)
+ return FWUPD_PLUGIN_FLAG_MODULAR;
+ return FWUPD_DEVICE_FLAG_UNKNOWN;
+}
+
+/**
+ * fwupd_update_state_to_string:
+ * @update_state: the update state, e.g. %FWUPD_UPDATE_STATE_PENDING
+ *
+ * Converts an enumerated update state to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+fwupd_update_state_to_string(FwupdUpdateState update_state)
+{
+ if (update_state == FWUPD_UPDATE_STATE_UNKNOWN)
+ return "unknown";
+ if (update_state == FWUPD_UPDATE_STATE_PENDING)
+ return "pending";
+ if (update_state == FWUPD_UPDATE_STATE_SUCCESS)
+ 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;
+}
+
+/**
+ * fwupd_update_state_from_string:
+ * @update_state: (nullable): a string, e.g. `pending`
+ *
+ * Converts a string to an enumerated update state.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 0.7.0
+ **/
+FwupdUpdateState
+fwupd_update_state_from_string(const gchar *update_state)
+{
+ if (g_strcmp0(update_state, "unknown") == 0)
+ return FWUPD_UPDATE_STATE_UNKNOWN;
+ if (g_strcmp0(update_state, "pending") == 0)
+ return FWUPD_UPDATE_STATE_PENDING;
+ if (g_strcmp0(update_state, "success") == 0)
+ 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;
+}
+
+/**
+ * fwupd_trust_flag_to_string:
+ * @trust_flag: the trust flags, e.g. %FWUPD_TRUST_FLAG_PAYLOAD
+ *
+ * Converts an enumerated trust flag to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+fwupd_trust_flag_to_string(FwupdTrustFlags trust_flag)
+{
+ if (trust_flag == FWUPD_TRUST_FLAG_NONE)
+ return "none";
+ if (trust_flag == FWUPD_TRUST_FLAG_PAYLOAD)
+ return "payload";
+ if (trust_flag == FWUPD_TRUST_FLAG_METADATA)
+ return "metadata";
+ return NULL;
+}
+
+/**
+ * fwupd_trust_flag_from_string:
+ * @trust_flag: (nullable): a string, e.g. `payload`
+ *
+ * Converts a string to an enumerated trust flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 0.7.0
+ **/
+FwupdTrustFlags
+fwupd_trust_flag_from_string(const gchar *trust_flag)
+{
+ if (g_strcmp0(trust_flag, "none") == 0)
+ return FWUPD_TRUST_FLAG_NONE;
+ if (g_strcmp0(trust_flag, "payload") == 0)
+ return FWUPD_TRUST_FLAG_PAYLOAD;
+ if (g_strcmp0(trust_flag, "metadata") == 0)
+ return FWUPD_TRUST_FLAG_METADATA;
+ return FWUPD_TRUST_FLAG_LAST;
+}
+
+/**
+ * fwupd_feature_flag_to_string:
+ * @feature_flag: a single feature flag, e.g. %FWUPD_FEATURE_FLAG_DETACH_ACTION
+ *
+ * Converts a feature flag to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.4.5
+ **/
+const gchar *
+fwupd_feature_flag_to_string(FwupdFeatureFlags feature_flag)
+{
+ if (feature_flag == FWUPD_FEATURE_FLAG_NONE)
+ return "none";
+ if (feature_flag == FWUPD_FEATURE_FLAG_CAN_REPORT)
+ return "can-report";
+ if (feature_flag == FWUPD_FEATURE_FLAG_DETACH_ACTION)
+ return "detach-action";
+ if (feature_flag == FWUPD_FEATURE_FLAG_UPDATE_ACTION)
+ return "update-action";
+ if (feature_flag == FWUPD_FEATURE_FLAG_SWITCH_BRANCH)
+ return "switch-branch";
+ if (feature_flag == FWUPD_FEATURE_FLAG_REQUESTS)
+ return "requests";
+ if (feature_flag == FWUPD_FEATURE_FLAG_FDE_WARNING)
+ return "fde-warning";
+ if (feature_flag == FWUPD_FEATURE_FLAG_COMMUNITY_TEXT)
+ return "community-text";
+ if (feature_flag == FWUPD_FEATURE_FLAG_SHOW_PROBLEMS)
+ return "show-problems";
+ if (feature_flag == FWUPD_FEATURE_FLAG_ALLOW_AUTHENTICATION)
+ return "allow-authentication";
+ return NULL;
+}
+
+/**
+ * fwupd_feature_flag_from_string:
+ * @feature_flag: (nullable): a string, e.g. `detach-action`
+ *
+ * Converts a string to an enumerated feature flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.4.5
+ **/
+FwupdFeatureFlags
+fwupd_feature_flag_from_string(const gchar *feature_flag)
+{
+ if (g_strcmp0(feature_flag, "none") == 0)
+ return FWUPD_FEATURE_FLAG_NONE;
+ if (g_strcmp0(feature_flag, "can-report") == 0)
+ return FWUPD_FEATURE_FLAG_CAN_REPORT;
+ if (g_strcmp0(feature_flag, "detach-action") == 0)
+ return FWUPD_FEATURE_FLAG_DETACH_ACTION;
+ if (g_strcmp0(feature_flag, "update-action") == 0)
+ return FWUPD_FEATURE_FLAG_UPDATE_ACTION;
+ if (g_strcmp0(feature_flag, "switch-branch") == 0)
+ return FWUPD_FEATURE_FLAG_SWITCH_BRANCH;
+ if (g_strcmp0(feature_flag, "requests") == 0)
+ return FWUPD_FEATURE_FLAG_REQUESTS;
+ if (g_strcmp0(feature_flag, "fde-warning") == 0)
+ return FWUPD_FEATURE_FLAG_FDE_WARNING;
+ if (g_strcmp0(feature_flag, "community-text") == 0)
+ return FWUPD_FEATURE_FLAG_COMMUNITY_TEXT;
+ if (g_strcmp0(feature_flag, "show-problems") == 0)
+ return FWUPD_FEATURE_FLAG_SHOW_PROBLEMS;
+ if (g_strcmp0(feature_flag, "allow-authentication") == 0)
+ return FWUPD_FEATURE_FLAG_ALLOW_AUTHENTICATION;
+ return FWUPD_FEATURE_FLAG_LAST;
+}
+
+/**
+ * fwupd_keyring_kind_from_string:
+ * @keyring_kind: (nullable): a string, e.g. `gpg`
+ *
+ * Converts an printable string to an enumerated keyring kind.
+ *
+ * Returns: keyring kind, e.g. %FWUPD_KEYRING_KIND_GPG
+ *
+ * Since: 0.9.7
+ **/
+FwupdKeyringKind
+fwupd_keyring_kind_from_string(const gchar *keyring_kind)
+{
+ if (g_strcmp0(keyring_kind, "none") == 0)
+ return FWUPD_KEYRING_KIND_NONE;
+ if (g_strcmp0(keyring_kind, "gpg") == 0)
+ return FWUPD_KEYRING_KIND_GPG;
+ if (g_strcmp0(keyring_kind, "pkcs7") == 0)
+ return FWUPD_KEYRING_KIND_PKCS7;
+ if (g_strcmp0(keyring_kind, "jcat") == 0)
+ return FWUPD_KEYRING_KIND_JCAT;
+ return FWUPD_KEYRING_KIND_UNKNOWN;
+}
+
+/**
+ * fwupd_keyring_kind_to_string:
+ * @keyring_kind: a #FwupdKeyringKind, e.g. %FWUPD_KEYRING_KIND_GPG
+ *
+ * Converts an enumerated keyring kind to a printable string.
+ *
+ * Returns: a string, e.g. `gpg`
+ *
+ * Since: 0.9.7
+ **/
+const gchar *
+fwupd_keyring_kind_to_string(FwupdKeyringKind keyring_kind)
+{
+ if (keyring_kind == FWUPD_KEYRING_KIND_NONE)
+ return "none";
+ if (keyring_kind == FWUPD_KEYRING_KIND_GPG)
+ return "gpg";
+ if (keyring_kind == FWUPD_KEYRING_KIND_PKCS7)
+ return "pkcs7";
+ if (keyring_kind == FWUPD_KEYRING_KIND_JCAT)
+ return "jcat";
+ return NULL;
+}
+
+/**
+ * fwupd_release_flag_to_string:
+ * @release_flag: a release flag, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD
+ *
+ * Converts an enumerated release flag to a string.
+ *
+ * Returns: 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";
+ if (release_flag == FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH)
+ return "is-alternate-branch";
+ if (release_flag == FWUPD_RELEASE_FLAG_IS_COMMUNITY)
+ return "is-community";
+ return NULL;
+}
+
+/**
+ * fwupd_release_flag_from_string:
+ * @release_flag: (nullable): a string, e.g. `trusted-payload`
+ *
+ * Converts a string to an enumerated release flag.
+ *
+ * Returns: 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;
+ if (g_strcmp0(release_flag, "is-alternate-branch") == 0)
+ return FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH;
+ if (g_strcmp0(release_flag, "is-community") == 0)
+ return FWUPD_RELEASE_FLAG_IS_COMMUNITY;
+ return FWUPD_RELEASE_FLAG_NONE;
+}
+
+/**
+ * fwupd_release_urgency_to_string:
+ * @release_urgency: a release urgency, e.g. %FWUPD_RELEASE_URGENCY_HIGH
+ *
+ * Converts an enumerated release urgency to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.4.0
+ **/
+const gchar *
+fwupd_release_urgency_to_string(FwupdReleaseUrgency release_urgency)
+{
+ if (release_urgency == FWUPD_RELEASE_URGENCY_LOW)
+ return "low";
+ if (release_urgency == FWUPD_RELEASE_URGENCY_MEDIUM)
+ return "medium";
+ if (release_urgency == FWUPD_RELEASE_URGENCY_HIGH)
+ return "high";
+ if (release_urgency == FWUPD_RELEASE_URGENCY_CRITICAL)
+ return "critical";
+ return NULL;
+}
+
+/**
+ * fwupd_release_urgency_from_string:
+ * @release_urgency: (nullable): a string, e.g. `low`
+ *
+ * Converts a string to an enumerated release urgency value.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.4.0
+ **/
+FwupdReleaseUrgency
+fwupd_release_urgency_from_string(const gchar *release_urgency)
+{
+ if (g_strcmp0(release_urgency, "low") == 0)
+ return FWUPD_RELEASE_URGENCY_LOW;
+ if (g_strcmp0(release_urgency, "medium") == 0)
+ return FWUPD_RELEASE_URGENCY_MEDIUM;
+ if (g_strcmp0(release_urgency, "high") == 0)
+ return FWUPD_RELEASE_URGENCY_HIGH;
+ if (g_strcmp0(release_urgency, "critical") == 0)
+ return FWUPD_RELEASE_URGENCY_CRITICAL;
+ return FWUPD_RELEASE_URGENCY_UNKNOWN;
+}
+
+/**
+ * fwupd_version_format_from_string:
+ * @str: (nullable): a string, e.g. `quad`
+ *
+ * Converts text to a display version type.
+ *
+ * Returns: an enumerated version format, 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;
+ if (g_strcmp0(str, "surface-legacy") == 0)
+ return FWUPD_VERSION_FORMAT_SURFACE_LEGACY;
+ if (g_strcmp0(str, "surface") == 0)
+ return FWUPD_VERSION_FORMAT_SURFACE;
+ if (g_strcmp0(str, "dell-bios") == 0)
+ return FWUPD_VERSION_FORMAT_DELL_BIOS;
+ if (g_strcmp0(str, "hex") == 0)
+ return FWUPD_VERSION_FORMAT_HEX;
+ return FWUPD_VERSION_FORMAT_UNKNOWN;
+}
+
+/**
+ * fwupd_version_format_to_string:
+ * @kind: a version format, e.g. %FWUPD_VERSION_FORMAT_TRIPLET
+ *
+ * Converts an enumerated version format 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";
+ if (kind == FWUPD_VERSION_FORMAT_SURFACE_LEGACY)
+ return "surface-legacy";
+ if (kind == FWUPD_VERSION_FORMAT_SURFACE)
+ return "surface";
+ if (kind == FWUPD_VERSION_FORMAT_DELL_BIOS)
+ return "dell-bios";
+ if (kind == FWUPD_VERSION_FORMAT_HEX)
+ return "hex";
+ return NULL;
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-enums.h b/fwupd-1.8.6/libfwupd/fwupd-enums.h
new file mode 100644
index 0000000000000000000000000000000000000000..6593455c9d266366f44b7c94972524f541a0d008
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-enums.h
@@ -0,0 +1,1082 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+/**
+ * FwupdStatus:
+ * @FWUPD_STATUS_UNKNOWN: Unknown state
+ * @FWUPD_STATUS_IDLE: Idle
+ * @FWUPD_STATUS_LOADING: Loading a resource
+ * @FWUPD_STATUS_DECOMPRESSING: Decompressing firmware
+ * @FWUPD_STATUS_DEVICE_RESTART: Restarting the device
+ * @FWUPD_STATUS_DEVICE_WRITE: Writing to a device
+ * @FWUPD_STATUS_DEVICE_VERIFY: Verifying (reading) a device
+ * @FWUPD_STATUS_SCHEDULING: Scheduling an offline update
+ * @FWUPD_STATUS_DOWNLOADING: A file is downloading
+ * @FWUPD_STATUS_DEVICE_READ: Reading from a device
+ * @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.
+ **/
+typedef enum {
+ FWUPD_STATUS_UNKNOWN, /* Since: 0.1.1 */
+ FWUPD_STATUS_IDLE, /* Since: 0.1.1 */
+ FWUPD_STATUS_LOADING, /* Since: 0.1.1 */
+ FWUPD_STATUS_DECOMPRESSING, /* Since: 0.1.1 */
+ FWUPD_STATUS_DEVICE_RESTART, /* Since: 0.1.1 */
+ FWUPD_STATUS_DEVICE_WRITE, /* Since: 0.1.1 */
+ FWUPD_STATUS_DEVICE_VERIFY, /* Since: 0.1.1 */
+ FWUPD_STATUS_SCHEDULING, /* Since: 0.1.1 */
+ FWUPD_STATUS_DOWNLOADING, /* Since: 0.9.4 */
+ FWUPD_STATUS_DEVICE_READ, /* Since: 1.0.0 */
+ 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;
+
+/**
+ * FwupdTrustFlags:
+ * @FWUPD_TRUST_FLAG_NONE: No trust
+ * @FWUPD_TRUST_FLAG_PAYLOAD: The firmware is trusted
+ * @FWUPD_TRUST_FLAG_METADATA: The metadata is trusted
+ *
+ * The flags to show the level of trust.
+ **/
+typedef enum {
+ FWUPD_TRUST_FLAG_NONE = 0, /* Since: 0.1.2 */
+ FWUPD_TRUST_FLAG_PAYLOAD = 1 << 0, /* Since: 0.1.2 */
+ FWUPD_TRUST_FLAG_METADATA = 1 << 1, /* Since: 0.1.2 */
+ /*< private >*/
+ FWUPD_TRUST_FLAG_LAST
+} FwupdTrustFlags;
+
+/**
+ * FwupdFeatureFlags:
+ * @FWUPD_FEATURE_FLAG_NONE: No trust
+ * @FWUPD_FEATURE_FLAG_CAN_REPORT: Can upload a report of the update back to the server
+ * @FWUPD_FEATURE_FLAG_DETACH_ACTION: Can perform detach action, typically showing text
+ * @FWUPD_FEATURE_FLAG_UPDATE_ACTION: Can perform update action, typically showing text
+ * @FWUPD_FEATURE_FLAG_SWITCH_BRANCH: Can switch the firmware branch
+ * @FWUPD_FEATURE_FLAG_REQUESTS: Can show interactive requests
+ * @FWUPD_FEATURE_FLAG_FDE_WARNING: Can warn about full disk encryption
+ * @FWUPD_FEATURE_FLAG_COMMUNITY_TEXT: Can show information about community supported
+ * @FWUPD_FEATURE_FLAG_SHOW_PROBLEMS: Can show problems when getting the update list
+ * @FWUPD_FEATURE_FLAG_ALLOW_AUTHENTICATION: Can authenticate with PolicyKit for requests
+ *
+ * The flags to the feature capabilities of the front-end client.
+ **/
+typedef enum {
+ FWUPD_FEATURE_FLAG_NONE = 0, /* Since: 1.4.5 */
+ FWUPD_FEATURE_FLAG_CAN_REPORT = 1 << 0, /* Since: 1.4.5 */
+ FWUPD_FEATURE_FLAG_DETACH_ACTION = 1 << 1, /* Since: 1.4.5 */
+ FWUPD_FEATURE_FLAG_UPDATE_ACTION = 1 << 2, /* Since: 1.4.5 */
+ FWUPD_FEATURE_FLAG_SWITCH_BRANCH = 1 << 3, /* Since: 1.5.0 */
+ FWUPD_FEATURE_FLAG_REQUESTS = 1 << 4, /* Since: 1.6.2 */
+ FWUPD_FEATURE_FLAG_FDE_WARNING = 1 << 5, /* Since: 1.7.1 */
+ FWUPD_FEATURE_FLAG_COMMUNITY_TEXT = 1 << 6, /* Since: 1.7.5 */
+ FWUPD_FEATURE_FLAG_SHOW_PROBLEMS = 1 << 7, /* Since: 1.8.1 */
+ FWUPD_FEATURE_FLAG_ALLOW_AUTHENTICATION = 1 << 8, /* Since: 1.8.4 */
+ /*< private >*/
+ FWUPD_FEATURE_FLAG_LAST
+} FwupdFeatureFlags;
+
+/**
+ * FWUPD_DEVICE_FLAG_NONE:
+ *
+ * No flags set
+ *
+ * Since 0.1.3
+ */
+#define FWUPD_DEVICE_FLAG_NONE (0u)
+/**
+ * FWUPD_DEVICE_FLAG_INTERNAL:
+ *
+ * Device is internal to the platform and cannot be removed easily.
+ *
+ * Since 0.1.3
+ */
+#define FWUPD_DEVICE_FLAG_INTERNAL (1u << 0)
+/**
+ * FWUPD_DEVICE_FLAG_UPDATABLE:
+ *
+ * Device has the ability to be updated in this or any other mode.
+ *
+ * Since 0.9.7
+ */
+#define FWUPD_DEVICE_FLAG_UPDATABLE (1u << 1)
+/**
+ * FWUPD_DEVICE_FLAG_ONLY_OFFLINE:
+ *
+ * Update can only be done from a limited functionality OS (offline mode).
+ *
+ * Since 0.9.7
+ */
+#define FWUPD_DEVICE_FLAG_ONLY_OFFLINE (1u << 2)
+/**
+ * FWUPD_DEVICE_FLAG_REQUIRE_AC:
+ *
+ * Device requires an external power source to be connected or the battery
+ * level at a minimum threshold to update.
+ *
+ * Since 0.6.3
+ */
+#define FWUPD_DEVICE_FLAG_REQUIRE_AC (1u << 3)
+/**
+ * FWUPD_DEVICE_FLAG_LOCKED:
+ *
+ * The device can not be updated without manual user interaction.
+ *
+ * Since 0.6.3
+ */
+#define FWUPD_DEVICE_FLAG_LOCKED (1u << 4)
+/**
+ * FWUPD_DEVICE_FLAG_SUPPORTED:
+ *
+ * The device is found in metadata loaded into the daemon.
+ *
+ * Since 0.7.1
+ */
+#define FWUPD_DEVICE_FLAG_SUPPORTED (1u << 5)
+/**
+ * FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER:
+ *
+ * The device requires entering a bootloader mode to be manually.
+ *
+ * Since 0.7.3
+ */
+#define FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER (1u << 6)
+/**
+ * FWUPD_DEVICE_FLAG_REGISTERED:
+ *
+ * The device has been registered with other plugins.
+ *
+ * Since 0.9.7
+ */
+#define FWUPD_DEVICE_FLAG_REGISTERED (1u << 7)
+/**
+ * FWUPD_DEVICE_FLAG_NEEDS_REBOOT:
+ *
+ * The device requires a system reboot to apply firmware or to reload hardware.
+ *
+ * Since 0.9.7
+ */
+#define FWUPD_DEVICE_FLAG_NEEDS_REBOOT (1u << 8)
+/**
+ * FWUPD_DEVICE_FLAG_REPORTED:
+ *
+ * The success or failure of a previous update has been reported to a metadata server.
+ *
+ * Since: 1.0.4
+ */
+#define FWUPD_DEVICE_FLAG_REPORTED (1u << 9)
+/**
+ * FWUPD_DEVICE_FLAG_NOTIFIED:
+ *
+ * The user has been notified about a change in the device state.
+ *
+ * Since: 1.0.5
+ */
+#define FWUPD_DEVICE_FLAG_NOTIFIED (1u << 10)
+/**
+ * FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION:
+ *
+ * The device will always display use the runtime version rather than the bootloader version.
+ *
+ * Since: 1.0.6
+ */
+#define FWUPD_DEVICE_FLAG_USE_RUNTIME_VERSION (1u << 11)
+/**
+ * FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST:
+ *
+ * The composite device requires installation of composite firmware on the parent before the child.
+ * Normally the child is installed before the parent.
+ *
+ * Since: 1.0.8
+ */
+#define FWUPD_DEVICE_FLAG_INSTALL_PARENT_FIRST (1u << 12)
+/**
+ * FWUPD_DEVICE_FLAG_IS_BOOTLOADER:
+ *
+ * The device is currently in a read-only bootloader mode and not running application code.
+ *
+ * Since: 1.0.8
+ */
+#define FWUPD_DEVICE_FLAG_IS_BOOTLOADER (1u << 13)
+/**
+ * FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG:
+ *
+ * The device is in the middle of and update and the hardware is waiting to be probed/replugged.
+ *
+ * Since: 1.1.2
+ */
+#define FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG (1u << 14)
+/**
+ * FWUPD_DEVICE_FLAG_IGNORE_VALIDATION:
+ *
+ * When processing an update for the device, plugins should ignore all validation safety checks.
+ *
+ * Since: 1.1.2
+ */
+#define FWUPD_DEVICE_FLAG_IGNORE_VALIDATION (1u << 15)
+/**
+ * FWUPD_DEVICE_FLAG_TRUSTED:
+ *
+ * A trusted client is reading information about the device.
+ * Extra metadata such as serial number can be exposed about this device.
+ *
+ * Since: 1.1.2
+ */
+#define FWUPD_DEVICE_FLAG_TRUSTED (1u << 16)
+/**
+ * FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN:
+ *
+ * The device requires the system to be shutdown to finish application of new firmware.
+ *
+ * Since: 1.2.4
+ */
+#define FWUPD_DEVICE_FLAG_NEEDS_SHUTDOWN (1u << 17)
+/**
+ * FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED:
+ *
+ * The device requires the update to be retried, possibly with a different plugin.
+ *
+ * Since: 1.2.5
+ */
+#define FWUPD_DEVICE_FLAG_ANOTHER_WRITE_REQUIRED (1u << 18)
+/**
+ * FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.2.5
+ * Deprecated 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_NO_AUTO_INSTANCE_IDS (1u << 19)
+/**
+ * FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION:
+ *
+ * The device update needs to be separately activated.
+ * This process may occur automatically on shutdown in some operating systems
+ * or when the device is unplugged with some devices.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION (1u << 20)
+/**
+ * FWUPD_DEVICE_FLAG_ENSURE_SEMVER:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.2.9
+ * Deprecate: 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_ENSURE_SEMVER (1u << 21)
+/**
+ * FWUPD_DEVICE_FLAG_HISTORICAL:
+ *
+ * The device is used for historical data only.
+ *
+ * Since: 1.3.2
+ */
+#define FWUPD_DEVICE_FLAG_HISTORICAL (1u << 22)
+/**
+ * FWUPD_DEVICE_FLAG_ONLY_SUPPORTED:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.3.3
+ * Deprecated 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_ONLY_SUPPORTED (1u << 23)
+/**
+ * FWUPD_DEVICE_FLAG_WILL_DISAPPEAR:
+ *
+ * The device will disappear after the update is complete and success
+ * or failure can't be verified.
+ *
+ * Since: 1.3.3
+ */
+#define FWUPD_DEVICE_FLAG_WILL_DISAPPEAR (1u << 24)
+/**
+ * FWUPD_DEVICE_FLAG_CAN_VERIFY:
+ *
+ * The device checksums can be compared against metadata.
+ *
+ * Since: 1.3.3
+ */
+#define FWUPD_DEVICE_FLAG_CAN_VERIFY (1u << 25)
+/**
+ * FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE:
+ *
+ * The device application firmware image can be dumped from device for verification.
+ *
+ * Since: 1.3.3
+ */
+#define FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE (1u << 26)
+/**
+ * FWUPD_DEVICE_FLAG_DUAL_IMAGE:
+ *
+ * The device firmware update architecture uses a redundancy mechanism such
+ * as A/B partitions for updates.
+ *
+ * Since: 1.3.3
+ */
+#define FWUPD_DEVICE_FLAG_DUAL_IMAGE (1u << 27)
+/**
+ * FWUPD_DEVICE_FLAG_SELF_RECOVERY:
+ *
+ * In flashing mode, the device will only accept intended payloads and will
+ * revert back to a valid firmware image if an invalid or incomplete payload was sent.
+ *
+ * Since: 1.3.3
+ */
+#define FWUPD_DEVICE_FLAG_SELF_RECOVERY (1u << 28)
+/**
+ * FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE:
+ *
+ * The device remains usable while the update flashes or schedules the update.
+ * The update will implicitly be applied next time the device is power cycled or possibly activated.
+ *
+ * Since: 1.3.3
+ */
+#define FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE (1u << 29)
+/**
+ * FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED:
+ *
+ * All firmware updates for this device require a firmware version check.
+ *
+ * Since: 1.3.7
+ */
+#define FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED (1u << 30)
+/**
+ * FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES:
+ *
+ * Install each intermediate releases for the device rather than jumping directly to the newest.
+ *
+ * Since: 1.3.7
+ */
+#define FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES (1u << 31)
+/**
+ * FWUPD_DEVICE_FLAG_MD_SET_NAME:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.4.0
+ * Deprecated 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_MD_SET_NAME (1llu << 32)
+/**
+ * FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.4.0
+ * Deprecated 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_MD_SET_NAME_CATEGORY (1llu << 33)
+/**
+ * FWUPD_DEVICE_FLAG_MD_SET_VERFMT:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.4.0
+ * Deprecated 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_MD_SET_VERFMT (1llu << 34)
+/**
+ * FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS:
+ *
+ * The device will add counterpart GUIDs from an alternate mode like bootloader.
+ * This flag is typically specified in a quirk.
+ *
+ * Since: 1.4.0
+ */
+#define FWUPD_DEVICE_FLAG_ADD_COUNTERPART_GUIDS (1llu << 35)
+/**
+ * FWUPD_DEVICE_FLAG_NO_GUID_MATCHING:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.4.1
+ * Deprecated 1.5.8
+ */
+#define FWUPD_DEVICE_FLAG_NO_GUID_MATCHING (1llu << 36)
+/**
+ * FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN:
+ *
+ * The device is updatable but is currently inhbitied from updates in the client.
+ * Reasons include but are not limited to low power or requiring reboot from a previous update.
+ *
+ * Since: 1.4.1
+ */
+#define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37)
+/**
+ * FWUPD_DEVICE_FLAG_SKIPS_RESTART:
+ *
+ * The device relies upon activation or power cycle to load firmware.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38)
+/**
+ * FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES:
+ *
+ * The device supports switching to a different stream of firmware.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES (1llu << 39)
+/**
+ * FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL:
+ *
+ * The device firmware should be saved before installing firmware.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_DEVICE_FLAG_BACKUP_BEFORE_INSTALL (1llu << 40)
+/**
+ * FWUPD_DEVICE_FLAG_MD_SET_ICON:
+ *
+ * Deprecated, no not use
+ *
+ * Since: 1.5.2
+ * Deprecated 1.5.5
+ */
+#define FWUPD_DEVICE_FLAG_MD_SET_ICON (1llu << 41)
+/**
+ * FWUPD_DEVICE_FLAG_WILDCARD_INSTALL:
+ *
+ * All devices with matching GUIDs will be updated at the same time.
+ *
+ * For some devices it is not possible to have different versions of firmware
+ * for hardware of the same type. Updating one device will force update of
+ * others with exactly the same instance IDs.
+ *
+ * Since: 1.6.2
+ */
+#define FWUPD_DEVICE_FLAG_WILDCARD_INSTALL (1llu << 42)
+/**
+ * FWUPD_DEVICE_FLAG_ONLY_VERSION_UPGRADE:
+ *
+ * The device firmware can only be updated to a newer version and never downgraded or reinstalled.
+ *
+ * Since 1.6.2
+ */
+#define FWUPD_DEVICE_FLAG_ONLY_VERSION_UPGRADE (1llu << 43)
+/**
+ * FWUPD_DEVICE_FLAG_UNREACHABLE:
+ *
+ * The device is currently unreachable, perhaps because it is in a lower power state or is out of
+ * wireless range.
+ *
+ * Since 1.7.0
+ */
+#define FWUPD_DEVICE_FLAG_UNREACHABLE (1llu << 44)
+/**
+ * FWUPD_DEVICE_FLAG_AFFECTS_FDE:
+ *
+ * The device is warning that a volume with full-disk-encryption was found on this machine,
+ * typically a Windows NTFS partition with BitLocker.
+ * Updating the firmware on this device may invalidate secrets used to decrypt the volume, and
+ * the recovery key may be required.
+ *
+ * Supported clients will display this information as a warning to the user.
+ *
+ * Since: 1.7.1
+ */
+#define FWUPD_DEVICE_FLAG_AFFECTS_FDE (1llu << 45)
+/**
+ * FWUPD_DEVICE_FLAG_END_OF_LIFE:
+ *
+ * The device is no longer supported by the original hardware vendor as it is considered
+ * end-of-life. It it unlikely to receive firmware updates, even for security issues.
+ *
+ * Since: 1.7.5
+ */
+#define FWUPD_DEVICE_FLAG_END_OF_LIFE (1llu << 46)
+/**
+ * FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD:
+ *
+ * The firmware payload is verified on-device the payload using strong cryptography such
+ * as RSA, AES or ECC.
+ *
+ * It is usually not possible to modify or flash custom firmware not provided by the vendor.
+ *
+ * Since: 1.7.6
+ */
+#define FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD (1llu << 47)
+/**
+ * FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD:
+ *
+ * The firmware payload is unsigned and it is possible to modify and flash custom firmware.
+ *
+ * Since: 1.7.6
+ */
+#define FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD (1llu << 48)
+/**
+ * FWUPD_DEVICE_FLAG_UNKNOWN:
+ *
+ * This flag is not defined, this typically will happen from mismatched
+ * fwupd library and clients.
+ *
+ * Since 0.7.3
+ */
+#define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64
+/**
+ * FwupdDeviceFlags:
+ *
+ * Flags used to represent device attributes
+ */
+typedef guint64 FwupdDeviceFlags;
+
+/**
+ * FWUPD_DEVICE_PROBLEM_NONE:
+ *
+ * No device problems detected.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_NONE (0u)
+/**
+ * FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW:
+ *
+ * The system power is too low to perform the update.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW (1u << 0)
+/**
+ * FWUPD_DEVICE_PROBLEM_UNREACHABLE:
+ *
+ * The device is unreachable, or out of wireless range.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_UNREACHABLE (1u << 1)
+/**
+ * FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW:
+ *
+ * The device battery power is too low.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW (1u << 2)
+/**
+ * FWUPD_DEVICE_PROBLEM_UPDATE_PENDING:
+ *
+ * The device is waiting for the update to be applied.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_UPDATE_PENDING (1u << 3)
+/**
+ * FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER:
+ *
+ * The device requires AC power to be connected.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER (1u << 4)
+/**
+ * FWUPD_DEVICE_PROBLEM_LID_IS_CLOSED:
+ *
+ * The device cannot be used while the laptop lid is closed.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_LID_IS_CLOSED (1u << 5)
+/**
+ * FWUPD_DEVICE_PROBLEM_IS_EMULATED:
+ *
+ * The device is emulated from a different host.
+ *
+ * Since 1.8.3
+ */
+#define FWUPD_DEVICE_PROBLEM_IS_EMULATED (1u << 6)
+/**
+ * FWUPD_DEVICE_PROBLEM_MISSING_LICENSE:
+ *
+ * The device cannot be updated due to missing vendor's license.
+ *
+ * Since 1.8.6
+ */
+#define FWUPD_DEVICE_PROBLEM_MISSING_LICENSE (1u << 7)
+/**
+ * FWUPD_DEVICE_PROBLEM_UNKNOWN:
+ *
+ * This problem is not defined, this typically will happen from mismatched
+ * fwupd library and clients.
+ *
+ * Since 1.8.1
+ */
+#define FWUPD_DEVICE_PROBLEM_UNKNOWN G_MAXUINT64
+/**
+ * FwupdDeviceProblem:
+ *
+ * Problems are reasons why the device is not updatable.
+ *
+ * All problems have to be fixable by the user, rather than the plugin author.
+ */
+typedef guint64 FwupdDeviceProblem;
+
+/**
+ * FWUPD_RELEASE_FLAG_NONE:
+ *
+ * No flags are set.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_NONE (0u)
+/**
+ * FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD:
+ *
+ * The payload binary is trusted.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD (1u << 0)
+/**
+ * FWUPD_RELEASE_FLAG_TRUSTED_METADATA:
+ *
+ * The payload metadata is trusted.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_TRUSTED_METADATA (1u << 1)
+/**
+ * FWUPD_RELEASE_FLAG_IS_UPGRADE:
+ *
+ * The release is newer than the device version.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_IS_UPGRADE (1u << 2)
+/**
+ * FWUPD_RELEASE_FLAG_IS_DOWNGRADE:
+ *
+ * The release is older than the device version.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_IS_DOWNGRADE (1u << 3)
+/**
+ * FWUPD_RELEASE_FLAG_BLOCKED_VERSION:
+ *
+ * The installation of the release is blocked as below device version-lowest.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_BLOCKED_VERSION (1u << 4)
+/**
+ * FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL:
+ *
+ * The installation of the release is blocked as release not approved by an administrator.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL (1u << 5)
+/**
+ * FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH:
+ *
+ * The release is an alternate branch of firmware.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH (1u << 6)
+/**
+ * FWUPD_RELEASE_FLAG_IS_COMMUNITY:
+ *
+ * The release is supported by the community and not the hardware vendor.
+ *
+ * Since: 1.7.5
+ */
+#define FWUPD_RELEASE_FLAG_IS_COMMUNITY (1u << 7)
+/**
+ * FWUPD_RELEASE_FLAG_UNKNOWN:
+ *
+ * The release flag is unknown, typically caused by using mismatched client and daemon.
+ *
+ * Since: 1.2.6
+ */
+#define FWUPD_RELEASE_FLAG_UNKNOWN G_MAXUINT64
+/**
+ * FwupdReleaseFlags:
+ *
+ * Flags used to represent release attributes
+ */
+typedef guint64 FwupdReleaseFlags;
+
+/**
+ * FwupdReleaseUrgency:
+ * @FWUPD_RELEASE_URGENCY_UNKNOWN: Unknown
+ * @FWUPD_RELEASE_URGENCY_LOW: Low
+ * @FWUPD_RELEASE_URGENCY_MEDIUM: Medium
+ * @FWUPD_RELEASE_URGENCY_HIGH: High
+ * @FWUPD_RELEASE_URGENCY_CRITICAL: Critical, e.g. a security fix
+ *
+ * The release urgency.
+ **/
+typedef enum {
+ FWUPD_RELEASE_URGENCY_UNKNOWN, /* Since: 1.4.0 */
+ FWUPD_RELEASE_URGENCY_LOW, /* Since: 1.4.0 */
+ FWUPD_RELEASE_URGENCY_MEDIUM, /* Since: 1.4.0 */
+ FWUPD_RELEASE_URGENCY_HIGH, /* Since: 1.4.0 */
+ FWUPD_RELEASE_URGENCY_CRITICAL, /* Since: 1.4.0 */
+ /*< private >*/
+ FWUPD_RELEASE_URGENCY_LAST
+} FwupdReleaseUrgency;
+
+/**
+ * FWUPD_PLUGIN_FLAG_NONE:
+ *
+ * No plugin flags are set.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_NONE (0u)
+/**
+ * FWUPD_PLUGIN_FLAG_DISABLED:
+ *
+ * The plugin has been disabled, either by daemon configuration or a problem.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_DISABLED (1u << 0)
+/**
+ * FWUPD_PLUGIN_FLAG_USER_WARNING:
+ *
+ * The plugin has a problem and would like to show a user warning to a supported client.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_USER_WARNING (1u << 1)
+/**
+ * FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE:
+ *
+ * When the plugin loads it should clear the UPDATABLE flag from any devices.
+ * This typically happens when the device requires a system restart.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE (1u << 2)
+/**
+ * FWUPD_PLUGIN_FLAG_NO_HARDWARE:
+ *
+ * The plugin won't load because no supported hardware was found.
+ * This typically happens with plugins designed for a specific platform design
+ * (such as the dell plugin only works on Dell systems).
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_NO_HARDWARE (1u << 3)
+/**
+ * FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED:
+ *
+ * The plugin discovered that UEFI UpdateCapsule are unsupported.
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED (1u << 4)
+/**
+ * FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED:
+ *
+ * The plugin discovered that hardware unlock is required.
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_UNLOCK_REQUIRED (1u << 5)
+/**
+ * FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED:
+ *
+ * The plugin discovered the efivar filesystem is not found and is required for this plugin.
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_EFIVAR_NOT_MOUNTED (1u << 6)
+/**
+ * FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND:
+ *
+ * The plugins discovered that the EFI system partition was not found.
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_ESP_NOT_FOUND (1u << 7)
+/**
+ * FWUPD_PLUGIN_FLAG_LEGACY_BIOS:
+ *
+ * The plugin discovered the system is running in legacy CSM mode.
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_LEGACY_BIOS (1u << 8)
+/**
+ * FWUPD_PLUGIN_FLAG_FAILED_OPEN:
+ *
+ * Failed to open plugin (missing dependency).
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_FAILED_OPEN (1u << 9)
+/**
+ * FWUPD_PLUGIN_FLAG_REQUIRE_HWID:
+ *
+ * A specific HWID is required to use this plugin.
+ *
+ * Since: 1.5.8
+ */
+#define FWUPD_PLUGIN_FLAG_REQUIRE_HWID (1u << 10)
+/**
+ * FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD:
+ *
+ * The feature is not supported as the kernel is too old.
+ *
+ * Since: 1.6.2
+ */
+#define FWUPD_PLUGIN_FLAG_KERNEL_TOO_OLD (1u << 11)
+/**
+ * FWUPD_PLUGIN_FLAG_AUTH_REQUIRED:
+ *
+ * The plugin requires the user to provide authentication details.
+ * Supported clients will display this information to a user.
+ *
+ * Since: 1.6.2
+ */
+#define FWUPD_PLUGIN_FLAG_AUTH_REQUIRED (1u << 12)
+/**
+ * FWUPD_PLUGIN_FLAG_SECURE_CONFIG:
+ *
+ * The plugin requires the config file to be saved with permissions that only allow the root user
+ * to read.
+ *
+ * Since: 1.8.5
+ */
+#define FWUPD_PLUGIN_FLAG_SECURE_CONFIG (1u << 13)
+/**
+ * FWUPD_PLUGIN_FLAG_MODULAR:
+ *
+ * The plugin is loaded from an external module.
+ *
+ * Since: 1.8.6
+ */
+#define FWUPD_PLUGIN_FLAG_MODULAR (1u << 14)
+/**
+ * FWUPD_PLUGIN_FLAG_UNKNOWN:
+ *
+ * The plugin flag is Unknown.
+ * This is usually caused by a mismatched libfwupdplugin and daemon.
+ *
+ * Since: 1.5.0
+ */
+#define FWUPD_PLUGIN_FLAG_UNKNOWN G_MAXUINT64
+/**
+ * FwupdPluginFlags:
+ *
+ * Flags used to represent plugin attributes
+ */
+typedef guint64 FwupdPluginFlags;
+
+/**
+ * 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
+ * @FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH: Allow firmware branch switching
+ * @FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM: Ignore firmware CRCs and checksums
+ * @FWUPD_INSTALL_FLAG_IGNORE_VID_PID: Ignore firmware vendor and project checks
+ * @FWUPD_INSTALL_FLAG_IGNORE_POWER: Ignore requirement of external power source
+ *(Deprecated since 1.7.0)
+ * @FWUPD_INSTALL_FLAG_NO_SEARCH: Do not use heuristics when parsing the image
+ *
+ * Flags to set when performing the firmware update or install.
+ **/
+typedef enum {
+ 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 */
+ FWUPD_INSTALL_FLAG_ALLOW_BRANCH_SWITCH = 1 << 5, /* Since: 1.5.0 */
+ FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM = 1 << 6, /* Since: 1.5.0 */
+ FWUPD_INSTALL_FLAG_IGNORE_VID_PID = 1 << 7, /* Since: 1.5.0 */
+ FWUPD_INSTALL_FLAG_IGNORE_POWER = 1 << 8, /* Since: 1.5.0 */
+ FWUPD_INSTALL_FLAG_NO_SEARCH = 1 << 9, /* Since: 1.5.0 */
+ /*< 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 firmware 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 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.
+ **/
+typedef enum {
+ FWUPD_UPDATE_STATE_UNKNOWN, /* Since: 0.7.0 */
+ FWUPD_UPDATE_STATE_PENDING, /* Since: 0.7.0 */
+ 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;
+
+/**
+ * FwupdKeyringKind:
+ * @FWUPD_KEYRING_KIND_UNKNOWN: Unknown
+ * @FWUPD_KEYRING_KIND_NONE: No verification
+ * @FWUPD_KEYRING_KIND_GPG: Verification using GPG
+ * @FWUPD_KEYRING_KIND_PKCS7: Verification using PKCS7
+ * @FWUPD_KEYRING_KIND_JCAT: Verification using Jcat
+ *
+ * Type of keyring used on a remote.
+ **/
+typedef enum {
+ FWUPD_KEYRING_KIND_UNKNOWN, /* Since: 0.9.7 */
+ FWUPD_KEYRING_KIND_NONE, /* Since: 0.9.7 */
+ FWUPD_KEYRING_KIND_GPG, /* Since: 0.9.7 */
+ FWUPD_KEYRING_KIND_PKCS7, /* Since: 0.9.7 */
+ FWUPD_KEYRING_KIND_JCAT, /* Since: 1.4.0 */
+ /*< private >*/
+ 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: UEFI-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
+ * @FWUPD_VERSION_FORMAT_SURFACE_LEGACY: Legacy Microsoft Surface 10b.12b.10b
+ * @FWUPD_VERSION_FORMAT_SURFACE: Microsoft Surface 8b.16b.8b
+ * @FWUPD_VERSION_FORMAT_DELL_BIOS: Dell BIOS BB.CC.DD style
+ * @FWUPD_VERSION_FORMAT_HEX: Hexadecimal 0xAABCCDD style
+ *
+ * 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 */
+ FWUPD_VERSION_FORMAT_SURFACE_LEGACY, /* Since: 1.3.4 */
+ FWUPD_VERSION_FORMAT_SURFACE, /* Since: 1.3.4 */
+ FWUPD_VERSION_FORMAT_DELL_BIOS, /* Since: 1.3.6 */
+ FWUPD_VERSION_FORMAT_HEX, /* Since: 1.4.0 */
+ /*< private >*/
+ FWUPD_VERSION_FORMAT_LAST
+} FwupdVersionFormat;
+
+/**
+ * FWUPD_BATTERY_LEVEL_INVALID:
+ *
+ * This value signifies the battery level is either unset, or the value cannot
+ * be discovered.
+ */
+#define FWUPD_BATTERY_LEVEL_INVALID 101
+
+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_device_problem_to_string(FwupdDeviceProblem device_problem);
+FwupdDeviceProblem
+fwupd_device_problem_from_string(const gchar *device_problem);
+const gchar *
+fwupd_plugin_flag_to_string(FwupdPluginFlags plugin_flag);
+FwupdPluginFlags
+fwupd_plugin_flag_from_string(const gchar *plugin_flag);
+const gchar *
+fwupd_release_flag_to_string(FwupdReleaseFlags release_flag);
+FwupdReleaseFlags
+fwupd_release_flag_from_string(const gchar *release_flag);
+const gchar *
+fwupd_release_urgency_to_string(FwupdReleaseUrgency release_urgency);
+FwupdReleaseUrgency
+fwupd_release_urgency_from_string(const gchar *release_urgency);
+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);
+const gchar *
+fwupd_feature_flag_to_string(FwupdFeatureFlags feature_flag);
+FwupdFeatureFlags
+fwupd_feature_flag_from_string(const gchar *feature_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);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-error.c b/fwupd-1.8.6/libfwupd/fwupd-error.c
new file mode 100644
index 0000000000000000000000000000000000000000..05db35a5125d5756b147f3f9ee6392c836562f89
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-error.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015-2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+
+#include "fwupd-common.h"
+#include "fwupd-enums.h"
+#include "fwupd-error.h"
+
+/**
+ * fwupd_error_to_string:
+ * @error: an enumerated error, e.g. %FWUPD_ERROR_VERSION_NEWER
+ *
+ * Converts an enumerated error to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+fwupd_error_to_string(FwupdError error)
+{
+ if (error == FWUPD_ERROR_INTERNAL)
+ return FWUPD_DBUS_INTERFACE ".Internal";
+ if (error == FWUPD_ERROR_VERSION_NEWER)
+ return FWUPD_DBUS_INTERFACE ".VersionNewer";
+ if (error == FWUPD_ERROR_VERSION_SAME)
+ return FWUPD_DBUS_INTERFACE ".VersionSame";
+ if (error == FWUPD_ERROR_ALREADY_PENDING)
+ return FWUPD_DBUS_INTERFACE ".AlreadyPending";
+ if (error == FWUPD_ERROR_AUTH_FAILED)
+ return FWUPD_DBUS_INTERFACE ".AuthFailed";
+ if (error == FWUPD_ERROR_READ)
+ return FWUPD_DBUS_INTERFACE ".Read";
+ if (error == FWUPD_ERROR_WRITE)
+ return FWUPD_DBUS_INTERFACE ".Write";
+ if (error == FWUPD_ERROR_INVALID_FILE)
+ return FWUPD_DBUS_INTERFACE ".InvalidFile";
+ if (error == FWUPD_ERROR_NOT_FOUND)
+ return FWUPD_DBUS_INTERFACE ".NotFound";
+ if (error == FWUPD_ERROR_NOTHING_TO_DO)
+ return FWUPD_DBUS_INTERFACE ".NothingToDo";
+ if (error == FWUPD_ERROR_NOT_SUPPORTED)
+ return FWUPD_DBUS_INTERFACE ".NotSupported";
+ if (error == FWUPD_ERROR_SIGNATURE_INVALID)
+ return FWUPD_DBUS_INTERFACE ".SignatureInvalid";
+ if (error == FWUPD_ERROR_AC_POWER_REQUIRED)
+ 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";
+ if (error == FWUPD_ERROR_NEEDS_USER_ACTION)
+ return FWUPD_DBUS_INTERFACE ".NeedsUserAction";
+ if (error == FWUPD_ERROR_AUTH_EXPIRED)
+ return FWUPD_DBUS_INTERFACE ".AuthExpired";
+ return NULL;
+}
+
+/**
+ * fwupd_error_from_string:
+ * @error: (nullable): a string, e.g. `org.freedesktop.fwupd.VersionNewer`
+ *
+ * Converts a string to an enumerated error.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 0.7.0
+ **/
+FwupdError
+fwupd_error_from_string(const gchar *error)
+{
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".Internal") == 0)
+ return FWUPD_ERROR_INTERNAL;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".VersionNewer") == 0)
+ return FWUPD_ERROR_VERSION_NEWER;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".VersionSame") == 0)
+ return FWUPD_ERROR_VERSION_SAME;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".AlreadyPending") == 0)
+ return FWUPD_ERROR_ALREADY_PENDING;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".AuthFailed") == 0)
+ return FWUPD_ERROR_AUTH_FAILED;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".Read") == 0)
+ return FWUPD_ERROR_READ;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".Write") == 0)
+ return FWUPD_ERROR_WRITE;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".InvalidFile") == 0)
+ return FWUPD_ERROR_INVALID_FILE;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".NotFound") == 0)
+ return FWUPD_ERROR_NOT_FOUND;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".NothingToDo") == 0)
+ return FWUPD_ERROR_NOTHING_TO_DO;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".NotSupported") == 0)
+ return FWUPD_ERROR_NOT_SUPPORTED;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".SignatureInvalid") == 0)
+ return FWUPD_ERROR_SIGNATURE_INVALID;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".AcPowerRequired") == 0)
+ 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;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".NeedsUserAction") == 0)
+ return FWUPD_ERROR_NEEDS_USER_ACTION;
+ if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".AuthExpired") == 0)
+ return FWUPD_ERROR_AUTH_EXPIRED;
+ return FWUPD_ERROR_LAST;
+}
+
+/**
+ * fwupd_error_quark:
+ *
+ * The error quark for [enum@FwupdError].
+ *
+ * Returns: an error quark
+ *
+ * Since: 0.1.1
+ **/
+GQuark
+fwupd_error_quark(void)
+{
+ static GQuark quark = 0;
+ if (!quark) {
+ quark = g_quark_from_static_string("FwupdError");
+ for (gint i = 0; i < FWUPD_ERROR_LAST; i++) {
+ g_dbus_error_register_error(quark, i, fwupd_error_to_string(i));
+ }
+ }
+ return quark;
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-error.h b/fwupd-1.8.6/libfwupd/fwupd-error.h
new file mode 100644
index 0000000000000000000000000000000000000000..2740818c5d7e8b687c89deb216800520df868f8b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-error.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015-2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+#define FWUPD_ERROR fwupd_error_quark()
+
+/**
+ * FwupdError:
+ * @FWUPD_ERROR_INTERNAL: Internal error
+ * @FWUPD_ERROR_VERSION_NEWER: Installed newer firmware version
+ * @FWUPD_ERROR_VERSION_SAME: Installed same firmware version
+ * @FWUPD_ERROR_ALREADY_PENDING: Already set to be installed offline
+ * @FWUPD_ERROR_AUTH_FAILED: Failed to get authentication
+ * @FWUPD_ERROR_READ: Failed to read from device
+ * @FWUPD_ERROR_WRITE: Failed to write to the device
+ * @FWUPD_ERROR_INVALID_FILE: Invalid file format
+ * @FWUPD_ERROR_NOT_FOUND: No matching device exists
+ * @FWUPD_ERROR_NOTHING_TO_DO: Nothing to do
+ * @FWUPD_ERROR_NOT_SUPPORTED: Action was not possible
+ * @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
+ * @FWUPD_ERROR_NEEDS_USER_ACTION: User needs to do an action to complete the update
+ * @FWUPD_ERROR_AUTH_EXPIRED: Failed to get auth as credentials have expired
+ *
+ * The error code.
+ **/
+typedef enum {
+ FWUPD_ERROR_INTERNAL, /* Since: 0.1.1 */
+ FWUPD_ERROR_VERSION_NEWER, /* Since: 0.1.1 */
+ FWUPD_ERROR_VERSION_SAME, /* Since: 0.1.1 */
+ FWUPD_ERROR_ALREADY_PENDING, /* Since: 0.1.1 */
+ FWUPD_ERROR_AUTH_FAILED, /* Since: 0.1.1 */
+ FWUPD_ERROR_READ, /* Since: 0.1.1 */
+ FWUPD_ERROR_WRITE, /* Since: 0.1.1 */
+ FWUPD_ERROR_INVALID_FILE, /* Since: 0.1.1 */
+ FWUPD_ERROR_NOT_FOUND, /* Since: 0.1.1 */
+ FWUPD_ERROR_NOTHING_TO_DO, /* Since: 0.1.1 */
+ FWUPD_ERROR_NOT_SUPPORTED, /* Since: 0.1.1 */
+ 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 */
+ FWUPD_ERROR_NEEDS_USER_ACTION, /* Since: 1.3.3 */
+ FWUPD_ERROR_AUTH_EXPIRED, /* Since: 1.7.5 */
+ /*< private >*/
+ FWUPD_ERROR_LAST
+} FwupdError;
+
+GQuark
+fwupd_error_quark(void);
+const gchar *
+fwupd_error_to_string(FwupdError error);
+FwupdError
+fwupd_error_from_string(const gchar *error);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-plugin-private.h b/fwupd-1.8.6/libfwupd/fwupd-plugin-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..8897dcec1e8ebd174ae360e25aea8bb8435aa2e2
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-plugin-private.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-plugin.h"
+
+G_BEGIN_DECLS
+
+GVariant *
+fwupd_plugin_to_variant(FwupdPlugin *self);
+void
+fwupd_plugin_to_json(FwupdPlugin *self, JsonBuilder *builder);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-plugin.c b/fwupd-1.8.6/libfwupd/fwupd-plugin.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c045df67c4de6a2664b315593f75b0ee6331e3e
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-plugin.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+
+#include "fwupd-common-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-plugin-private.h"
+
+/**
+ * FwupdPlugin:
+ *
+ * A plugin which is used by fwupd to enumerate and update devices.
+ *
+ * See also: [class@FwupdRelease]
+ */
+
+static void
+fwupd_plugin_finalize(GObject *object);
+
+typedef struct {
+ gchar *name;
+ guint64 flags;
+} FwupdPluginPrivate;
+
+enum { PROP_0, PROP_NAME, PROP_FLAGS, PROP_LAST };
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdPlugin, fwupd_plugin, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_plugin_get_instance_private(o))
+
+/**
+ * fwupd_plugin_get_name:
+ * @self: a #FwupdPlugin
+ *
+ * Gets the plugin name.
+ *
+ * Returns: the plugin name, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_plugin_get_name(FwupdPlugin *self)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_PLUGIN(self), NULL);
+ return priv->name;
+}
+
+/**
+ * fwupd_plugin_set_name:
+ * @self: a #FwupdPlugin
+ * @name: the plugin name, e.g. `bios`
+ *
+ * Sets the plugin name.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_plugin_set_name(FwupdPlugin *self, const gchar *name)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_PLUGIN(self));
+ g_return_if_fail(name != NULL);
+
+ /* not changed */
+ if (g_strcmp0(priv->name, name) == 0)
+ return;
+
+ g_free(priv->name);
+ priv->name = g_strdup(name);
+ g_object_notify(G_OBJECT(self), "name");
+}
+
+/**
+ * fwupd_plugin_get_flags:
+ * @self: a #FwupdPlugin
+ *
+ * Gets the plugin flags.
+ *
+ * Returns: plugin flags, or 0 if unset
+ *
+ * Since: 1.5.0
+ **/
+guint64
+fwupd_plugin_get_flags(FwupdPlugin *self)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_PLUGIN(self), 0);
+ return priv->flags;
+}
+
+/**
+ * fwupd_plugin_set_flags:
+ * @self: a #FwupdPlugin
+ * @flags: plugin flags, e.g. %FWUPD_PLUGIN_FLAG_CAPSULES_UNSUPPORTED
+ *
+ * Sets the plugin flags.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_plugin_set_flags(FwupdPlugin *self, guint64 flags)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_PLUGIN(self));
+ if (priv->flags == flags)
+ return;
+ priv->flags = flags;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_plugin_add_flag:
+ * @self: a #FwupdPlugin
+ * @flag: the #FwupdPluginFlags
+ *
+ * Adds a specific plugin flag to the plugin.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_plugin_add_flag(FwupdPlugin *self, FwupdPluginFlags flag)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_PLUGIN(self));
+ if (flag == 0)
+ return;
+ if ((priv->flags & flag) > 0)
+ return;
+ priv->flags |= flag;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_plugin_remove_flag:
+ * @self: a #FwupdPlugin
+ * @flag: a plugin flag
+ *
+ * Removes a specific plugin flag from the plugin.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_plugin_remove_flag(FwupdPlugin *self, FwupdPluginFlags flag)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_PLUGIN(self));
+ if (flag == 0)
+ return;
+ if ((priv->flags & flag) == 0)
+ return;
+ priv->flags &= ~flag;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_plugin_has_flag:
+ * @self: a #FwupdPlugin
+ * @flag: a plugin flag
+ *
+ * Finds if the plugin has a specific plugin flag.
+ *
+ * Returns: %TRUE if the flag is set
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_plugin_has_flag(FwupdPlugin *self, FwupdPluginFlags flag)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_PLUGIN(self), FALSE);
+ return (priv->flags & flag) > 0;
+}
+
+/**
+ * fwupd_plugin_to_variant:
+ * @self: a #FwupdPlugin
+ *
+ * Serialize the plugin data omitting sensitive fields
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GVariant *
+fwupd_plugin_to_variant(FwupdPlugin *self)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FWUPD_IS_PLUGIN(self), NULL);
+
+ /* create an array with all the metadata in */
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ if (priv->name != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_NAME,
+ g_variant_new_string(priv->name));
+ }
+ if (priv->flags > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_FLAGS,
+ g_variant_new_uint64(priv->flags));
+ }
+ return g_variant_new("a{sv}", &builder);
+}
+
+static void
+fwupd_plugin_from_key_value(FwupdPlugin *self, const gchar *key, GVariant *value)
+{
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
+ fwupd_plugin_set_name(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FLAGS) == 0) {
+ fwupd_plugin_set_flags(self, g_variant_get_uint64(value));
+ return;
+ }
+}
+
+static void
+fwupd_pad_kv_dfl(GString *str, const gchar *key, guint64 plugin_flags)
+{
+ g_autoptr(GString) tmp = g_string_new("");
+ for (guint i = 0; i < 64; i++) {
+ if ((plugin_flags & ((guint64)1 << i)) == 0)
+ continue;
+ g_string_append_printf(tmp, "%s|", fwupd_plugin_flag_to_string((guint64)1 << i));
+ }
+ if (tmp->len == 0) {
+ g_string_append(tmp, fwupd_plugin_flag_to_string(0));
+ } else {
+ g_string_truncate(tmp, tmp->len - 1);
+ }
+ fwupd_pad_kv_str(str, key, tmp->str);
+}
+
+/**
+ * fwupd_plugin_to_json:
+ * @self: a #FwupdPlugin
+ * @builder: a JSON builder
+ *
+ * Adds a fwupd plugin to a JSON builder
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_plugin_to_json(FwupdPlugin *self, JsonBuilder *builder)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_PLUGIN(self));
+ g_return_if_fail(builder != NULL);
+
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_NAME, priv->name);
+ if (priv->flags != FWUPD_PLUGIN_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_plugin_flag_to_string((guint64)1 << i);
+ json_builder_add_string_value(builder, tmp);
+ }
+ json_builder_end_array(builder);
+ }
+}
+
+/**
+ * fwupd_plugin_to_string:
+ * @self: a #FwupdPlugin
+ *
+ * Builds a text representation of the object.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 1.5.0
+ **/
+gchar *
+fwupd_plugin_to_string(FwupdPlugin *self)
+{
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ GString *str;
+
+ g_return_val_if_fail(FWUPD_IS_PLUGIN(self), NULL);
+
+ str = g_string_new(NULL);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_pad_kv_dfl(str, FWUPD_RESULT_KEY_FLAGS, priv->flags);
+ return g_string_free(str, FALSE);
+}
+
+static void
+fwupd_plugin_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FwupdPlugin *self = FWUPD_PLUGIN(object);
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string(value, priv->name);
+ break;
+ case PROP_FLAGS:
+ g_value_set_uint64(value, priv->flags);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_plugin_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FwupdPlugin *self = FWUPD_PLUGIN(object);
+ switch (prop_id) {
+ case PROP_NAME:
+ fwupd_plugin_set_name(self, g_value_get_string(value));
+ break;
+ case PROP_FLAGS:
+ fwupd_plugin_set_flags(self, g_value_get_uint64(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_plugin_class_init(FwupdPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
+
+ object_class->finalize = fwupd_plugin_finalize;
+ object_class->get_property = fwupd_plugin_get_property;
+ object_class->set_property = fwupd_plugin_set_property;
+
+ /**
+ * FwupdPlugin:name:
+ *
+ * The plugin name.
+ *
+ * Since: 1.5.0
+ */
+ pspec =
+ g_param_spec_string("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_NAME, pspec);
+
+ /**
+ * FwupdPlugin:flags:
+ *
+ * The plugin flags.
+ *
+ * Since: 1.5.0
+ */
+ pspec = g_param_spec_uint64("flags",
+ NULL,
+ NULL,
+ FWUPD_PLUGIN_FLAG_NONE,
+ FWUPD_PLUGIN_FLAG_UNKNOWN,
+ FWUPD_PLUGIN_FLAG_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_FLAGS, pspec);
+}
+
+static void
+fwupd_plugin_init(FwupdPlugin *self)
+{
+}
+
+static void
+fwupd_plugin_finalize(GObject *object)
+{
+ FwupdPlugin *self = FWUPD_PLUGIN(object);
+ FwupdPluginPrivate *priv = GET_PRIVATE(self);
+ g_free(priv->name);
+ G_OBJECT_CLASS(fwupd_plugin_parent_class)->finalize(object);
+}
+
+static void
+fwupd_plugin_set_from_variant_iter(FwupdPlugin *self, GVariantIter *iter)
+{
+ GVariant *value;
+ const gchar *key;
+ while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
+ fwupd_plugin_from_key_value(self, key, value);
+ g_variant_unref(value);
+ }
+}
+
+/**
+ * fwupd_plugin_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new plugin using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdPlugin, or %NULL if @value was invalid
+ *
+ * Since: 1.5.0
+ **/
+FwupdPlugin *
+fwupd_plugin_from_variant(GVariant *value)
+{
+ FwupdPlugin *self = NULL;
+ const gchar *type_string;
+ g_autoptr(GVariantIter) iter = NULL;
+
+ /* format from GetDetails */
+ type_string = g_variant_get_type_string(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ self = fwupd_plugin_new();
+ g_variant_get(value, "(a{sv})", &iter);
+ fwupd_plugin_set_from_variant_iter(self, iter);
+ } else if (g_strcmp0(type_string, "a{sv}") == 0) {
+ self = fwupd_plugin_new();
+ g_variant_get(value, "a{sv}", &iter);
+ fwupd_plugin_set_from_variant_iter(self, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return self;
+}
+
+/**
+ * fwupd_plugin_array_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates an array of new plugins using serialized data.
+ *
+ * Returns: (transfer container) (element-type FwupdPlugin): plugins, or %NULL if @value was invalid
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_plugin_array_from_variant(GVariant *value)
+{
+ GPtrArray *array = NULL;
+ gsize sz;
+ g_autoptr(GVariant) untuple = NULL;
+
+ g_return_val_if_fail(value != NULL, 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++) {
+ FwupdPlugin *self;
+ g_autoptr(GVariant) data = NULL;
+ data = g_variant_get_child_value(untuple, i);
+ self = fwupd_plugin_from_variant(data);
+ if (self == NULL)
+ continue;
+ g_ptr_array_add(array, self);
+ }
+ return array;
+}
+
+/**
+ * fwupd_plugin_new:
+ *
+ * Creates a new plugin.
+ *
+ * Returns: a new #FwupdPlugin
+ *
+ * Since: 1.5.0
+ **/
+FwupdPlugin *
+fwupd_plugin_new(void)
+{
+ FwupdPlugin *self;
+ self = g_object_new(FWUPD_TYPE_PLUGIN, NULL);
+ return FWUPD_PLUGIN(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-plugin.h b/fwupd-1.8.6/libfwupd/fwupd-plugin.h
new file mode 100644
index 0000000000000000000000000000000000000000..95072d05df3e08a4211694af273cc5329abaedbd
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-plugin.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-enums.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_PLUGIN (fwupd_plugin_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdPlugin, fwupd_plugin, FWUPD, PLUGIN, GObject)
+
+struct _FwupdPluginClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ void (*_fwupd_reserved7)(void);
+};
+
+FwupdPlugin *
+fwupd_plugin_new(void);
+gchar *
+fwupd_plugin_to_string(FwupdPlugin *self);
+
+const gchar *
+fwupd_plugin_get_name(FwupdPlugin *self);
+void
+fwupd_plugin_set_name(FwupdPlugin *self, const gchar *name);
+guint64
+fwupd_plugin_get_flags(FwupdPlugin *self);
+void
+fwupd_plugin_set_flags(FwupdPlugin *self, guint64 flags);
+void
+fwupd_plugin_add_flag(FwupdPlugin *self, FwupdPluginFlags flag);
+void
+fwupd_plugin_remove_flag(FwupdPlugin *self, FwupdPluginFlags flag);
+gboolean
+fwupd_plugin_has_flag(FwupdPlugin *self, FwupdPluginFlags flag);
+
+FwupdPlugin *
+fwupd_plugin_from_variant(GVariant *value);
+GPtrArray *
+fwupd_plugin_array_from_variant(GVariant *value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-release-private.h b/fwupd-1.8.6/libfwupd/fwupd-release-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..cfc05854c9f34186c0d1e8bc68d6ce4d4b043b9d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-release-private.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-release.h"
+
+G_BEGIN_DECLS
+
+GVariant *
+fwupd_release_to_variant(FwupdRelease *self);
+void
+fwupd_release_to_json(FwupdRelease *self, JsonBuilder *builder);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-release.c b/fwupd-1.8.6/libfwupd/fwupd-release.c
new file mode 100644
index 0000000000000000000000000000000000000000..838d153773ca8bfcd41e8511bd8f6945320c7356
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-release.c
@@ -0,0 +1,2376 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+#include
+
+#include "fwupd-common-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-error.h"
+#include "fwupd-release-private.h"
+
+/**
+ * FwupdRelease:
+ *
+ * A firmware release with a specific version.
+ *
+ * Devices can have more than one release, and the releases are typically
+ * ordered by their version.
+ *
+ * See also: [class@FwupdDevice]
+ */
+
+static void
+fwupd_release_finalize(GObject *object);
+
+typedef struct {
+ GPtrArray *checksums;
+ GPtrArray *tags;
+ GPtrArray *categories;
+ GPtrArray *issues;
+ GHashTable *metadata;
+ gchar *description;
+ gchar *filename;
+ gchar *protocol;
+ gchar *homepage;
+ gchar *details_url;
+ gchar *source_url;
+ gchar *appstream_id;
+ gchar *id;
+ gchar *detach_caption;
+ gchar *detach_image;
+ gchar *license;
+ gchar *name;
+ gchar *name_variant_suffix;
+ gchar *summary;
+ gchar *branch;
+ GPtrArray *locations;
+ gchar *vendor;
+ gchar *version;
+ gchar *remote_id;
+ guint64 size;
+ guint64 created;
+ guint32 install_duration;
+ FwupdReleaseFlags flags;
+ FwupdReleaseUrgency urgency;
+ gchar *update_message;
+ gchar *update_image;
+} FwupdReleasePrivate;
+
+enum { PROP_0, PROP_REMOTE_ID, PROP_LAST };
+
+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:
+ * @self: a #FwupdRelease
+ *
+ * Gets the remote ID that can be used for downloading.
+ *
+ * Returns: the ID, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_remote_id(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->remote_id;
+}
+
+/**
+ * fwupd_release_set_remote_id:
+ * @self: a #FwupdRelease
+ * @remote_id: the release ID, e.g. `USB:foo`
+ *
+ * Sets the remote ID that can be used for downloading.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_remote_id(FwupdRelease *self, const gchar *remote_id)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->remote_id, remote_id) == 0)
+ return;
+
+ g_free(priv->remote_id);
+ priv->remote_id = g_strdup(remote_id);
+ g_object_notify(G_OBJECT(self), "remote-id");
+}
+
+/**
+ * fwupd_release_get_version:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update version.
+ *
+ * Returns: the update version, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_version(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->version;
+}
+
+/**
+ * fwupd_release_set_version:
+ * @self: a #FwupdRelease
+ * @version: the update version, e.g. `1.2.4`
+ *
+ * Sets the update version.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_version(FwupdRelease *self, const gchar *version)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->version, version) == 0)
+ return;
+
+ g_free(priv->version);
+ priv->version = g_strdup(version);
+}
+
+/**
+ * fwupd_release_get_filename:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update filename.
+ *
+ * Returns: the update filename, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_filename(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->filename;
+}
+
+/**
+ * fwupd_release_set_filename:
+ * @self: a #FwupdRelease
+ * @filename: the update filename on disk
+ *
+ * Sets the update filename.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_filename(FwupdRelease *self, const gchar *filename)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->filename, filename) == 0)
+ return;
+
+ g_free(priv->filename);
+ priv->filename = g_strdup(filename);
+}
+
+/**
+ * fwupd_release_get_update_message:
+ * @self: 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 *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->update_message;
+}
+
+/**
+ * fwupd_release_set_update_message:
+ * @self: a #FwupdRelease
+ * @update_message: (nullable): the update message string
+ *
+ * Sets the update message.
+ *
+ * Since: 1.2.4
+ **/
+void
+fwupd_release_set_update_message(FwupdRelease *self, const gchar *update_message)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->update_message, update_message) == 0)
+ return;
+
+ g_free(priv->update_message);
+ priv->update_message = g_strdup(update_message);
+}
+
+/**
+ * fwupd_release_get_update_image:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update image.
+ *
+ * Returns: the update image URL, or %NULL if unset
+ *
+ * Since: 1.4.5
+ **/
+const gchar *
+fwupd_release_get_update_image(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->update_image;
+}
+
+/**
+ * fwupd_release_set_update_image:
+ * @self: a #FwupdRelease
+ * @update_image: (nullable): the update image URL
+ *
+ * Sets the update image.
+ *
+ * Since: 1.4.5
+ **/
+void
+fwupd_release_set_update_image(FwupdRelease *self, const gchar *update_image)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->update_image, update_image) == 0)
+ return;
+
+ g_free(priv->update_image);
+ priv->update_image = g_strdup(update_image);
+}
+
+/**
+ * fwupd_release_get_protocol:
+ * @self: 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 *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->protocol;
+}
+
+/**
+ * fwupd_release_set_protocol:
+ * @self: a #FwupdRelease
+ * @protocol: (nullable): the update protocol, e.g. `org.usb.dfu`
+ *
+ * Sets the update protocol.
+ *
+ * Since: 1.2.2
+ **/
+void
+fwupd_release_set_protocol(FwupdRelease *self, const gchar *protocol)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->protocol, protocol) == 0)
+ return;
+
+ g_free(priv->protocol);
+ priv->protocol = g_strdup(protocol);
+}
+
+/**
+ * fwupd_release_get_issues:
+ * @self: a #FwupdRelease
+ *
+ * Gets the list of issues fixed in this release.
+ *
+ * Returns: (element-type utf8) (transfer none): the issues, which may be empty
+ *
+ * Since: 1.3.2
+ **/
+GPtrArray *
+fwupd_release_get_issues(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->issues;
+}
+
+/**
+ * fwupd_release_add_issue:
+ * @self: a #FwupdRelease
+ * @issue: (not nullable): the update issue, e.g. `CVE-2019-12345`
+ *
+ * Adds an resolved issue to this release.
+ *
+ * Since: 1.3.2
+ **/
+void
+fwupd_release_add_issue(FwupdRelease *self, const gchar *issue)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(issue != NULL);
+ for (guint i = 0; i < priv->issues->len; i++) {
+ const gchar *issue_tmp = g_ptr_array_index(priv->issues, i);
+ if (g_strcmp0(issue_tmp, issue) == 0)
+ return;
+ }
+ g_ptr_array_add(priv->issues, g_strdup(issue));
+}
+
+/**
+ * fwupd_release_get_categories:
+ * @self: 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 *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->categories;
+}
+
+/**
+ * fwupd_release_add_category:
+ * @self: a #FwupdRelease
+ * @category: (not nullable): the update category, e.g. `X-EmbeddedController`
+ *
+ * Adds the update category.
+ *
+ * Since: 1.2.7
+ **/
+void
+fwupd_release_add_category(FwupdRelease *self, const gchar *category)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ 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:
+ * @self: a #FwupdRelease
+ * @category: (not nullable): 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 *self, const gchar *category)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 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:
+ * @self: a #FwupdRelease
+ *
+ * Gets the release container checksums.
+ *
+ * Returns: (element-type utf8) (transfer none): the checksums, which may be empty
+ *
+ * Since: 0.9.3
+ **/
+GPtrArray *
+fwupd_release_get_checksums(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->checksums;
+}
+
+/**
+ * fwupd_release_add_checksum:
+ * @self: a #FwupdRelease
+ * @checksum: (not nullable): the update container checksum
+ *
+ * Sets the update checksum.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_add_checksum(FwupdRelease *self, const gchar *checksum)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(checksum != NULL);
+ 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;
+ }
+ g_ptr_array_add(priv->checksums, g_strdup(checksum));
+}
+
+/**
+ * fwupd_release_has_checksum:
+ * @self: a #FwupdRelease
+ * @checksum: (not nullable): the update checksum
+ *
+ * Finds out if the release has the update container checksum.
+ *
+ * Returns: %TRUE if the release matches
+ *
+ * Since: 1.2.6
+ **/
+gboolean
+fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 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_tags:
+ * @self: a #FwupdRelease
+ *
+ * Gets the release tags.
+ *
+ * Returns: (element-type utf8) (transfer none): the tags, which may be empty
+ *
+ * Since: 1.7.3
+ **/
+GPtrArray *
+fwupd_release_get_tags(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->tags;
+}
+
+/**
+ * fwupd_release_add_tag:
+ * @self: a #FwupdRelease
+ * @tag: (not nullable): the update tag, e.g. `vendor-factory-2021q1`
+ *
+ * Adds a specific release tag.
+ *
+ * Since: 1.7.3
+ **/
+void
+fwupd_release_add_tag(FwupdRelease *self, const gchar *tag)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(tag != NULL);
+ for (guint i = 0; i < priv->tags->len; i++) {
+ const gchar *tag_tmp = g_ptr_array_index(priv->tags, i);
+ if (g_strcmp0(tag_tmp, tag) == 0)
+ return;
+ }
+ g_ptr_array_add(priv->tags, g_strdup(tag));
+}
+
+/**
+ * fwupd_release_has_tag:
+ * @self: a #FwupdRelease
+ * @tag: (not nullable): the update tag, e.g. `vendor-factory-2021q1`
+ *
+ * Finds out if the release has a specific tag.
+ *
+ * Returns: %TRUE if the release matches
+ *
+ * Since: 1.7.3
+ **/
+gboolean
+fwupd_release_has_tag(FwupdRelease *self, const gchar *tag)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
+ g_return_val_if_fail(tag != NULL, FALSE);
+ for (guint i = 0; i < priv->tags->len; i++) {
+ const gchar *tag_tmp = g_ptr_array_index(priv->tags, i);
+ if (g_strcmp0(tag_tmp, tag) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_release_get_metadata:
+ * @self: a #FwupdRelease
+ *
+ * Gets the release metadata.
+ *
+ * Returns: (transfer none): the metadata, which may be empty
+ *
+ * Since: 1.0.4
+ **/
+GHashTable *
+fwupd_release_get_metadata(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->metadata;
+}
+
+/**
+ * fwupd_release_add_metadata_item:
+ * @self: a #FwupdRelease
+ * @key: (not nullable): the key
+ * @value: (not nullable): the value
+ *
+ * Sets a release metadata item.
+ *
+ * Since: 1.0.4
+ **/
+void
+fwupd_release_add_metadata_item(FwupdRelease *self, const gchar *key, const gchar *value)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(value != NULL);
+ g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
+}
+
+/**
+ * fwupd_release_add_metadata:
+ * @self: a #FwupdRelease
+ * @hash: (not nullable): the key-values
+ *
+ * Sets multiple release metadata items.
+ *
+ * Since: 1.0.4
+ **/
+void
+fwupd_release_add_metadata(FwupdRelease *self, GHashTable *hash)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GList) keys = NULL;
+
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(hash != NULL);
+
+ /* deep copy the whole map */
+ keys = g_hash_table_get_keys(hash);
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *key = l->data;
+ const gchar *value = g_hash_table_lookup(hash, key);
+ g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
+ }
+}
+
+/**
+ * fwupd_release_get_metadata_item:
+ * @self: a #FwupdRelease
+ * @key: (not nullable): the key
+ *
+ * Gets a release metadata item.
+ *
+ * Returns: the value, or %NULL if unset
+ *
+ * Since: 1.0.4
+ **/
+const gchar *
+fwupd_release_get_metadata_item(FwupdRelease *self, const gchar *key)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+ return g_hash_table_lookup(priv->metadata, key);
+}
+
+/**
+ * fwupd_release_get_uri:
+ * @self: a #FwupdRelease
+ *
+ * Gets the default update URI.
+ *
+ * Returns: the update URI, or %NULL if unset
+ *
+ * Since: 0.9.3
+ * Deprecated: 1.5.6: Use fwupd_release_get_locations() instead.
+ **/
+const gchar *
+fwupd_release_get_uri(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ if (priv->locations->len == 0)
+ return NULL;
+ return (const gchar *)g_ptr_array_index(priv->locations, 0);
+}
+
+/**
+ * fwupd_release_set_uri:
+ * @self: a #FwupdRelease
+ * @uri: the update URI
+ *
+ * Sets the update URI, i.e. where you can download the firmware from.
+ *
+ * Since: 0.9.3
+ * Deprecated: 1.5.6: Use fwupd_release_add_location() instead.
+ **/
+void
+fwupd_release_set_uri(FwupdRelease *self, const gchar *uri)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_ptr_array_set_size(priv->locations, 0);
+ g_ptr_array_add(priv->locations, g_strdup(uri));
+}
+
+/**
+ * fwupd_release_get_locations:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update URI, i.e. where you can download the firmware from.
+ *
+ * Typically the first URI will be the main HTTP mirror, but all URIs may not
+ * be valid HTTP URIs. For example, "ipns://QmSrPmba" is valid here.
+ *
+ * Returns: (element-type utf8) (transfer none): the URIs
+ *
+ * Since: 1.5.6
+ **/
+GPtrArray *
+fwupd_release_get_locations(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->locations;
+}
+
+/**
+ * fwupd_release_add_location:
+ * @self: a #FwupdRelease
+ * @location: (not nullable): the update URI
+ *
+ * Adds an update URI, i.e. where you can download the firmware from.
+ *
+ * Since: 1.5.6
+ **/
+void
+fwupd_release_add_location(FwupdRelease *self, const gchar *location)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(location != NULL);
+ for (guint i = 0; i < priv->locations->len; i++) {
+ const gchar *location_tmp = g_ptr_array_index(priv->locations, i);
+ if (g_strcmp0(location_tmp, location) == 0)
+ return;
+ }
+ g_ptr_array_add(priv->locations, g_strdup(location));
+}
+
+/**
+ * fwupd_release_get_homepage:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update homepage.
+ *
+ * Returns: the update homepage, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_homepage(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->homepage;
+}
+
+/**
+ * fwupd_release_set_homepage:
+ * @self: a #FwupdRelease
+ * @homepage: (nullable): the URL
+ *
+ * Sets the update homepage URL.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_homepage(FwupdRelease *self, const gchar *homepage)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->homepage, homepage) == 0)
+ return;
+
+ g_free(priv->homepage);
+ priv->homepage = g_strdup(homepage);
+}
+
+/**
+ * fwupd_release_get_details_url:
+ * @self: 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 *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->details_url;
+}
+
+/**
+ * fwupd_release_set_details_url:
+ * @self: a #FwupdRelease
+ * @details_url: (nullable): the URL
+ *
+ * Sets the URL for the online update notes.
+ *
+ * Since: 1.2.4
+ **/
+void
+fwupd_release_set_details_url(FwupdRelease *self, const gchar *details_url)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->details_url, details_url) == 0)
+ return;
+
+ g_free(priv->details_url);
+ priv->details_url = g_strdup(details_url);
+}
+
+/**
+ * fwupd_release_get_source_url:
+ * @self: 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 *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->source_url;
+}
+
+/**
+ * fwupd_release_set_source_url:
+ * @self: a #FwupdRelease
+ * @source_url: (nullable): 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 *self, const gchar *source_url)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->source_url, source_url) == 0)
+ return;
+
+ g_free(priv->source_url);
+ priv->source_url = g_strdup(source_url);
+}
+
+/**
+ * fwupd_release_get_description:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update description in AppStream markup format.
+ *
+ * Returns: the update description, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_description(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->description;
+}
+
+/**
+ * fwupd_release_set_description:
+ * @self: a #FwupdRelease
+ * @description: (nullable): the update description in AppStream markup format
+ *
+ * Sets the update description.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_description(FwupdRelease *self, const gchar *description)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->description, description) == 0)
+ return;
+
+ g_free(priv->description);
+ priv->description = g_strdup(description);
+}
+
+/**
+ * fwupd_release_get_appstream_id:
+ * @self: a #FwupdRelease
+ *
+ * Gets the AppStream ID.
+ *
+ * Returns: the AppStream ID, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_appstream_id(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->appstream_id;
+}
+
+/**
+ * fwupd_release_set_appstream_id:
+ * @self: a #FwupdRelease
+ * @appstream_id: (nullable): the AppStream component ID, e.g. `org.hughski.ColorHug2.firmware`
+ *
+ * Sets the AppStream ID.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_appstream_id(FwupdRelease *self, const gchar *appstream_id)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->appstream_id, appstream_id) == 0)
+ return;
+
+ g_free(priv->appstream_id);
+ priv->appstream_id = g_strdup(appstream_id);
+}
+
+/**
+ * fwupd_release_get_id:
+ * @self: a #FwupdRelease
+ *
+ * Gets the release ID, which allows identifying the specific uploaded component.
+ *
+ * Returns: the ID, or %NULL if unset
+ *
+ * Since: 1.7.2
+ **/
+const gchar *
+fwupd_release_get_id(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->id;
+}
+
+/**
+ * fwupd_release_set_id:
+ * @self: a #FwupdRelease
+ * @id: (nullable): the AppStream component ID, e.g. `component:1234`
+ *
+ * Sets the ID, which allows identifying the specific uploaded component.
+ *
+ * Since: 1.7.2
+ **/
+void
+fwupd_release_set_id(FwupdRelease *self, const gchar *id)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->id, id) == 0)
+ return;
+
+ g_free(priv->id);
+ priv->id = g_strdup(id);
+}
+
+/**
+ * fwupd_release_get_detach_caption:
+ * @self: a #FwupdRelease
+ *
+ * Gets the optional text caption used to manually detach the device.
+ *
+ * Returns: the string caption, or %NULL if unset
+ *
+ * Since: 1.3.3
+ **/
+const gchar *
+fwupd_release_get_detach_caption(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->detach_caption;
+}
+
+/**
+ * fwupd_release_set_detach_caption:
+ * @self: a #FwupdRelease
+ * @detach_caption: (nullable): string caption
+ *
+ * Sets the optional text caption used to manually detach the device.
+ *
+ * Since: 1.3.3
+ **/
+void
+fwupd_release_set_detach_caption(FwupdRelease *self, const gchar *detach_caption)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->detach_caption, detach_caption) == 0)
+ return;
+
+ g_free(priv->detach_caption);
+ priv->detach_caption = g_strdup(detach_caption);
+}
+
+/**
+ * fwupd_release_get_detach_image:
+ * @self: a #FwupdRelease
+ *
+ * Gets the optional image used to manually detach the device.
+ *
+ * Returns: the URI, or %NULL if unset
+ *
+ * Since: 1.3.3
+ **/
+const gchar *
+fwupd_release_get_detach_image(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->detach_image;
+}
+
+/**
+ * fwupd_release_set_detach_image:
+ * @self: a #FwupdRelease
+ * @detach_image: (nullable): a fully qualified URI
+ *
+ * Sets the optional image used to manually detach the device.
+ *
+ * Since: 1.3.3
+ **/
+void
+fwupd_release_set_detach_image(FwupdRelease *self, const gchar *detach_image)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->detach_image, detach_image) == 0)
+ return;
+
+ g_free(priv->detach_image);
+ priv->detach_image = g_strdup(detach_image);
+}
+
+/**
+ * fwupd_release_get_size:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update size.
+ *
+ * Returns: the update size in bytes, or 0 if unset
+ *
+ * Since: 0.9.3
+ **/
+guint64
+fwupd_release_get_size(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
+ return priv->size;
+}
+
+/**
+ * fwupd_release_set_size:
+ * @self: a #FwupdRelease
+ * @size: the update size in bytes
+ *
+ * Sets the update size.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_size(FwupdRelease *self, guint64 size)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->size = size;
+}
+
+/**
+ * fwupd_release_get_created:
+ * @self: a #FwupdRelease
+ *
+ * Gets when the update was created.
+ *
+ * Returns: UTC timestamp in UNIX format, or 0 if unset
+ *
+ * Since: 1.4.0
+ **/
+guint64
+fwupd_release_get_created(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
+ return priv->created;
+}
+
+/**
+ * fwupd_release_set_created:
+ * @self: a #FwupdRelease
+ * @created: UTC timestamp in UNIX format
+ *
+ * Sets when the update was created.
+ *
+ * Since: 1.4.0
+ **/
+void
+fwupd_release_set_created(FwupdRelease *self, guint64 created)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->created = created;
+}
+
+/**
+ * fwupd_release_get_summary:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update summary.
+ *
+ * Returns: the update summary, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_summary(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->summary;
+}
+
+/**
+ * fwupd_release_set_summary:
+ * @self: a #FwupdRelease
+ * @summary: (nullable): the update one line summary
+ *
+ * Sets the update summary.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_summary(FwupdRelease *self, const gchar *summary)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->summary, summary) == 0)
+ return;
+
+ g_free(priv->summary);
+ priv->summary = g_strdup(summary);
+}
+
+/**
+ * fwupd_release_get_branch:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update branch.
+ *
+ * Returns: the alternate branch, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_release_get_branch(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->branch;
+}
+
+/**
+ * fwupd_release_set_branch:
+ * @self: a #FwupdRelease
+ * @branch: (nullable): the update one line branch
+ *
+ * Sets the alternate branch.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_release_set_branch(FwupdRelease *self, const gchar *branch)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->branch, branch) == 0)
+ return;
+
+ g_free(priv->branch);
+ priv->branch = g_strdup(branch);
+}
+
+/**
+ * fwupd_release_get_vendor:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update vendor.
+ *
+ * Returns: the update vendor, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_vendor(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->vendor;
+}
+
+/**
+ * fwupd_release_set_vendor:
+ * @self: a #FwupdRelease
+ * @vendor: (nullable): the vendor name, e.g. `Hughski Limited`
+ *
+ * Sets the update vendor.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_vendor(FwupdRelease *self, const gchar *vendor)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->vendor, vendor) == 0)
+ return;
+
+ g_free(priv->vendor);
+ priv->vendor = g_strdup(vendor);
+}
+
+/**
+ * fwupd_release_get_license:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update license.
+ *
+ * Returns: the update license, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_license(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->license;
+}
+
+/**
+ * fwupd_release_set_license:
+ * @self: a #FwupdRelease
+ * @license: (nullable): the update license.
+ *
+ * Sets the update license.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_license(FwupdRelease *self, const gchar *license)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->license, license) == 0)
+ return;
+
+ g_free(priv->license);
+ priv->license = g_strdup(license);
+}
+
+/**
+ * fwupd_release_get_name:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update name.
+ *
+ * Returns: the update name, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_release_get_name(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->name;
+}
+
+/**
+ * fwupd_release_set_name:
+ * @self: a #FwupdRelease
+ * @name: (nullable): the update name.
+ *
+ * Sets the update name.
+ *
+ * Since: 0.9.3
+ **/
+void
+fwupd_release_set_name(FwupdRelease *self, const gchar *name)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->name, name) == 0)
+ return;
+
+ g_free(priv->name);
+ priv->name = g_strdup(name);
+}
+
+/**
+ * fwupd_release_get_name_variant_suffix:
+ * @self: a #FwupdRelease
+ *
+ * Gets the update variant suffix.
+ *
+ * Returns: the update variant, or %NULL if unset
+ *
+ * Since: 1.3.2
+ **/
+const gchar *
+fwupd_release_get_name_variant_suffix(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+ return priv->name_variant_suffix;
+}
+
+/**
+ * fwupd_release_set_name_variant_suffix:
+ * @self: a #FwupdRelease
+ * @name_variant_suffix: (nullable): the description
+ *
+ * Sets the update variant suffix.
+ *
+ * Since: 1.3.2
+ **/
+void
+fwupd_release_set_name_variant_suffix(FwupdRelease *self, const gchar *name_variant_suffix)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->name_variant_suffix, name_variant_suffix) == 0)
+ return;
+
+ g_free(priv->name_variant_suffix);
+ priv->name_variant_suffix = g_strdup(name_variant_suffix);
+}
+
+/**
+ * fwupd_release_get_trust_flags:
+ * @self: a #FwupdRelease
+ *
+ * Gets the trust level of the release.
+ *
+ * Returns: the trust bitfield, e.g. #FWUPD_TRUST_FLAG_PAYLOAD
+ *
+ * Since: 0.9.8
+ **/
+FwupdTrustFlags
+fwupd_release_get_trust_flags(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
+ return priv->flags & FWUPD_RELEASE_TRUST_FLAGS_MASK;
+}
+
+/**
+ * fwupd_release_set_trust_flags:
+ * @self: a #FwupdRelease
+ * @trust_flags: the bitfield, e.g. #FWUPD_TRUST_FLAG_PAYLOAD
+ *
+ * Sets the trust level of the release.
+ *
+ * Since: 0.9.8
+ **/
+void
+fwupd_release_set_trust_flags(FwupdRelease *self, FwupdTrustFlags trust_flags)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+
+ /* only overwrite the last two bits of the flags */
+ priv->flags &= ~FWUPD_RELEASE_TRUST_FLAGS_MASK;
+ priv->flags |= trust_flags;
+}
+
+/**
+ * fwupd_release_get_flags:
+ * @self: a #FwupdRelease
+ *
+ * Gets the release flags.
+ *
+ * Returns: release flags, or 0 if unset
+ *
+ * Since: 1.2.6
+ **/
+FwupdReleaseFlags
+fwupd_release_get_flags(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
+ return priv->flags;
+}
+
+/**
+ * fwupd_release_set_flags:
+ * @self: a #FwupdRelease
+ * @flags: release flags, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD
+ *
+ * Sets the release flags.
+ *
+ * Since: 1.2.6
+ **/
+void
+fwupd_release_set_flags(FwupdRelease *self, FwupdReleaseFlags flags)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->flags = flags;
+}
+
+/**
+ * fwupd_release_add_flag:
+ * @self: a #FwupdRelease
+ * @flag: the #FwupdReleaseFlags
+ *
+ * Adds a specific release flag to the release.
+ *
+ * Since: 1.2.6
+ **/
+void
+fwupd_release_add_flag(FwupdRelease *self, FwupdReleaseFlags flag)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->flags |= flag;
+}
+
+/**
+ * fwupd_release_remove_flag:
+ * @self: a #FwupdRelease
+ * @flag: the #FwupdReleaseFlags
+ *
+ * Removes a specific release flag from the release.
+ *
+ * Since: 1.2.6
+ **/
+void
+fwupd_release_remove_flag(FwupdRelease *self, FwupdReleaseFlags flag)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->flags &= ~flag;
+}
+
+/**
+ * fwupd_release_has_flag:
+ * @self: 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 *self, FwupdReleaseFlags flag)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
+ return (priv->flags & flag) > 0;
+}
+
+/**
+ * fwupd_release_get_urgency:
+ * @self: a #FwupdRelease
+ *
+ * Gets the release urgency.
+ *
+ * Returns: the release urgency, or 0 if unset
+ *
+ * Since: 1.4.0
+ **/
+FwupdReleaseUrgency
+fwupd_release_get_urgency(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
+ return priv->urgency;
+}
+
+/**
+ * fwupd_release_set_urgency:
+ * @self: a #FwupdRelease
+ * @urgency: the release urgency, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD
+ *
+ * Sets the release urgency.
+ *
+ * Since: 1.4.0
+ **/
+void
+fwupd_release_set_urgency(FwupdRelease *self, FwupdReleaseUrgency urgency)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->urgency = urgency;
+}
+
+/**
+ * fwupd_release_get_install_duration:
+ * @self: 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 *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
+ return priv->install_duration;
+}
+
+/**
+ * fwupd_release_set_install_duration:
+ * @self: a #FwupdRelease
+ * @duration: amount of time in seconds
+ *
+ * Sets the time estimate for firmware installation (in seconds)
+ *
+ * Since: 1.2.1
+ **/
+void
+fwupd_release_set_install_duration(FwupdRelease *self, guint32 duration)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ priv->install_duration = duration;
+}
+
+/**
+ * fwupd_release_to_variant:
+ * @self: a #FwupdRelease
+ *
+ * Serialize the release data.
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.0.0
+ **/
+GVariant *
+fwupd_release_to_variant(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+
+ /* create an array with all the metadata in */
+ 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,
+ g_variant_new_string(priv->remote_id));
+ }
+ if (priv->appstream_id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_APPSTREAM_ID,
+ g_variant_new_string(priv->appstream_id));
+ }
+ if (priv->id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_RELEASE_ID,
+ g_variant_new_string(priv->id));
+ }
+ if (priv->detach_caption != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_DETACH_CAPTION,
+ g_variant_new_string(priv->detach_caption));
+ }
+ if (priv->detach_image != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_DETACH_IMAGE,
+ g_variant_new_string(priv->detach_image));
+ }
+ 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_image != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_UPDATE_IMAGE,
+ g_variant_new_string(priv->update_image));
+ }
+ if (priv->filename != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ 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,
+ g_variant_new_string(priv->license));
+ }
+ if (priv->name != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_NAME,
+ g_variant_new_string(priv->name));
+ }
+ if (priv->name_variant_suffix != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX,
+ g_variant_new_string(priv->name_variant_suffix));
+ }
+ if (priv->size != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_SIZE,
+ g_variant_new_uint64(priv->size));
+ }
+ if (priv->created != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CREATED,
+ g_variant_new_uint64(priv->created));
+ }
+ if (priv->summary != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_SUMMARY,
+ g_variant_new_string(priv->summary));
+ }
+ if (priv->branch != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BRANCH,
+ g_variant_new_string(priv->branch));
+ }
+ if (priv->description != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ 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->issues->len > 0) {
+ g_autofree const gchar **strv = g_new0(const gchar *, priv->issues->len + 1);
+ for (guint i = 0; i < priv->issues->len; i++)
+ strv[i] = (const gchar *)g_ptr_array_index(priv->issues, i);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_ISSUES,
+ 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++) {
+ const gchar *checksum = g_ptr_array_index(priv->checksums, i);
+ g_string_append_printf(str, "%s,", checksum);
+ }
+ if (str->len > 0)
+ g_string_truncate(str, str->len - 1);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CHECKSUM,
+ g_variant_new_string(str->str));
+ }
+ if (priv->locations->len > 0) {
+ g_variant_builder_add(
+ &builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_LOCATIONS,
+ g_variant_new_strv((const gchar *const *)priv->locations->pdata,
+ priv->locations->len));
+ /* for compatibility */
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_URI,
+ g_variant_new_string(g_ptr_array_index(priv->locations, 0)));
+ }
+ if (priv->tags->len > 0) {
+ g_variant_builder_add(
+ &builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_TAGS,
+ g_variant_new_strv((const gchar *const *)priv->tags->pdata, priv->tags->len));
+ }
+ if (priv->homepage != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ 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,
+ g_variant_new_string(priv->version));
+ }
+ if (priv->vendor != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_VENDOR,
+ g_variant_new_string(priv->vendor));
+ }
+ if (priv->flags != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_TRUST_FLAGS,
+ g_variant_new_uint64(priv->flags));
+ }
+ if (priv->urgency != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_URGENCY,
+ g_variant_new_uint32(priv->urgency));
+ }
+ if (g_hash_table_size(priv->metadata) > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_METADATA,
+ fwupd_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);
+}
+
+static void
+fwupd_release_from_key_value(FwupdRelease *self, const gchar *key, GVariant *value)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_REMOTE_ID) == 0) {
+ fwupd_release_set_remote_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) {
+ fwupd_release_set_appstream_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_RELEASE_ID) == 0) {
+ fwupd_release_set_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DETACH_CAPTION) == 0) {
+ fwupd_release_set_detach_caption(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DETACH_IMAGE) == 0) {
+ fwupd_release_set_detach_image(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FILENAME) == 0) {
+ fwupd_release_set_filename(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_PROTOCOL) == 0) {
+ fwupd_release_set_protocol(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_LICENSE) == 0) {
+ fwupd_release_set_license(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
+ fwupd_release_set_name(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX) == 0) {
+ fwupd_release_set_name_variant_suffix(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_SIZE) == 0) {
+ fwupd_release_set_size(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
+ fwupd_release_set_created(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_SUMMARY) == 0) {
+ fwupd_release_set_summary(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BRANCH) == 0) {
+ fwupd_release_set_branch(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
+ fwupd_release_set_description(self, 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(self, strv[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_ISSUES) == 0) {
+ g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
+ for (guint i = 0; strv[i] != NULL; i++)
+ fwupd_release_add_issue(self, 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);
+ for (guint i = 0; split[i] != NULL; i++)
+ fwupd_release_add_checksum(self, split[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_LOCATIONS) == 0) {
+ g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
+ for (guint i = 0; strv[i] != NULL; i++)
+ fwupd_release_add_location(self, strv[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_TAGS) == 0) {
+ g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
+ for (guint i = 0; strv[i] != NULL; i++)
+ fwupd_release_add_tag(self, strv[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_URI) == 0) {
+ fwupd_release_add_location(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_HOMEPAGE) == 0) {
+ fwupd_release_set_homepage(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DETAILS_URL) == 0) {
+ fwupd_release_set_details_url(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_SOURCE_URL) == 0) {
+ fwupd_release_set_source_url(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION) == 0) {
+ fwupd_release_set_version(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR) == 0) {
+ fwupd_release_set_vendor(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_TRUST_FLAGS) == 0) {
+ fwupd_release_set_flags(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_URGENCY) == 0) {
+ fwupd_release_set_urgency(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) {
+ fwupd_release_set_install_duration(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) {
+ fwupd_release_set_update_message(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) {
+ fwupd_release_set_update_image(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_METADATA) == 0) {
+ g_hash_table_unref(priv->metadata);
+ priv->metadata = fwupd_variant_to_hash_kv(value);
+ return;
+ }
+}
+
+static void
+fwupd_pad_kv_siz(GString *str, const gchar *key, guint64 value)
+{
+ g_autofree gchar *tmp = NULL;
+
+ /* ignore */
+ if (value == 0)
+ return;
+ tmp = g_format_size(value);
+ fwupd_pad_kv_str(str, key, tmp);
+}
+
+static void
+fwupd_pad_kv_tfl(GString *str, const gchar *key, FwupdReleaseFlags release_flags)
+{
+ g_autoptr(GString) tmp = g_string_new("");
+ for (guint i = 0; i < 64; i++) {
+ if ((release_flags & ((guint64)1 << i)) == 0)
+ continue;
+ g_string_append_printf(tmp, "%s|", fwupd_release_flag_to_string((guint64)1 << i));
+ }
+ if (tmp->len == 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);
+}
+
+/**
+ * fwupd_release_to_json:
+ * @self: a #FwupdRelease
+ * @builder: a JSON builder
+ *
+ * Adds a fwupd release to a JSON builder
+ *
+ * Since: 1.2.6
+ **/
+void
+fwupd_release_to_json(FwupdRelease *self, JsonBuilder *builder)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GList) keys = NULL;
+
+ g_return_if_fail(FWUPD_IS_RELEASE(self));
+ g_return_if_fail(builder != NULL);
+
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_RELEASE_ID, priv->id);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX,
+ priv->name_variant_suffix);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_BRANCH, priv->branch);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_VERSION, priv->version);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_FILENAME, priv->filename);
+ fwupd_common_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->issues->len > 0) {
+ json_builder_set_member_name(builder, FWUPD_RESULT_KEY_ISSUES);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->issues->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->issues, 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);
+ }
+ if (priv->tags->len > 0) {
+ json_builder_set_member_name(builder, FWUPD_RESULT_KEY_TAGS);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->tags->len; i++) {
+ const gchar *tag = g_ptr_array_index(priv->tags, i);
+ json_builder_add_string_value(builder, tag);
+ }
+ json_builder_end_array(builder);
+ }
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_LICENSE, priv->license);
+ if (priv->size > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_SIZE, priv->size);
+ if (priv->created > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_CREATED, priv->created);
+ if (priv->locations->len > 0) {
+ json_builder_set_member_name(builder, FWUPD_RESULT_KEY_LOCATIONS);
+ json_builder_begin_array(builder);
+ for (guint i = 0; i < priv->locations->len; i++) {
+ const gchar *location = g_ptr_array_index(priv->locations, i);
+ json_builder_add_string_value(builder, location);
+ }
+ json_builder_end_array(builder);
+ /* for compatibility */
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_URI,
+ (const gchar *)g_ptr_array_index(priv->locations, 0));
+ }
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url);
+ fwupd_common_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);
+ }
+ if (priv->install_duration > 0) {
+ fwupd_common_json_add_int(builder,
+ FWUPD_RESULT_KEY_INSTALL_DURATION,
+ priv->install_duration);
+ }
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_DETACH_CAPTION,
+ priv->detach_caption);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_UPDATE_MESSAGE,
+ priv->update_message);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image);
+
+ /* 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_common_json_add_string(builder, key, value);
+ }
+}
+
+/**
+ * fwupd_release_to_string:
+ * @self: a #FwupdRelease
+ *
+ * Builds a text representation of the object.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 0.9.3
+ **/
+gchar *
+fwupd_release_to_string(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ GString *str;
+ g_autoptr(GList) keys = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
+
+ str = g_string_new("");
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_RELEASE_ID, priv->id);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
+ 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_BRANCH, priv->branch);
+ 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->issues->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->issues, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_ISSUES, 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);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_CHECKSUM, checksum_display);
+ }
+ for (guint i = 0; i < priv->tags->len; i++) {
+ const gchar *tag = g_ptr_array_index(priv->tags, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_TAGS, tag);
+ }
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_LICENSE, priv->license);
+ fwupd_pad_kv_siz(str, FWUPD_RESULT_KEY_SIZE, priv->size);
+ fwupd_pad_kv_unx(str, FWUPD_RESULT_KEY_CREATED, priv->created);
+ for (guint i = 0; i < priv->locations->len; i++) {
+ const gchar *location = g_ptr_array_index(priv->locations, i);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_URI, location);
+ }
+ 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);
+ if (priv->urgency != FWUPD_RELEASE_URGENCY_UNKNOWN) {
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_URGENCY,
+ fwupd_release_urgency_to_string(priv->urgency));
+ }
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
+ fwupd_pad_kv_tfl(str, FWUPD_RESULT_KEY_FLAGS, priv->flags);
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_INSTALL_DURATION, priv->install_duration);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_DETACH_CAPTION, priv->detach_caption);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image);
+ if (priv->update_message != NULL)
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message);
+ if (priv->update_image != NULL)
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image);
+ /* 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_pad_kv_str(str, key, value);
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+static void
+fwupd_release_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FwupdRelease *self = FWUPD_RELEASE(obj);
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+
+ switch (prop_id) {
+ case PROP_REMOTE_ID:
+ g_value_set_string(value, priv->remote_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_release_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FwupdRelease *self = FWUPD_RELEASE(obj);
+
+ switch (prop_id) {
+ case PROP_REMOTE_ID:
+ fwupd_release_set_remote_id(self, g_value_get_string(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_release_class_init(FwupdReleaseClass *klass)
+{
+ GParamSpec *pspec;
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fwupd_release_finalize;
+ object_class->get_property = fwupd_release_get_property;
+ object_class->set_property = fwupd_release_set_property;
+
+ /**
+ * FwupdRelease:remote-id:
+ *
+ * The remote ID.
+ *
+ * Since: 1.8.0
+ */
+ pspec = g_param_spec_string("remote-id",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_REMOTE_ID, pspec);
+}
+
+static void
+fwupd_release_init(FwupdRelease *self)
+{
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+ priv->categories = g_ptr_array_new_with_free_func(g_free);
+ priv->issues = g_ptr_array_new_with_free_func(g_free);
+ priv->checksums = g_ptr_array_new_with_free_func(g_free);
+ priv->tags = g_ptr_array_new_with_free_func(g_free);
+ priv->locations = 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);
+}
+
+static void
+fwupd_release_finalize(GObject *object)
+{
+ FwupdRelease *self = FWUPD_RELEASE(object);
+ FwupdReleasePrivate *priv = GET_PRIVATE(self);
+
+ g_free(priv->description);
+ g_free(priv->filename);
+ g_free(priv->protocol);
+ g_free(priv->appstream_id);
+ g_free(priv->id);
+ g_free(priv->detach_caption);
+ g_free(priv->detach_image);
+ g_free(priv->license);
+ g_free(priv->name);
+ g_free(priv->name_variant_suffix);
+ g_free(priv->summary);
+ g_free(priv->branch);
+ g_ptr_array_unref(priv->locations);
+ 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_free(priv->update_image);
+ g_ptr_array_unref(priv->categories);
+ g_ptr_array_unref(priv->issues);
+ g_ptr_array_unref(priv->checksums);
+ g_ptr_array_unref(priv->tags);
+ g_hash_table_unref(priv->metadata);
+
+ G_OBJECT_CLASS(fwupd_release_parent_class)->finalize(object);
+}
+
+static void
+fwupd_release_set_from_variant_iter(FwupdRelease *self, GVariantIter *iter)
+{
+ GVariant *value;
+ const gchar *key;
+ while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
+ fwupd_release_from_key_value(self, key, value);
+ g_variant_unref(value);
+ }
+}
+
+/**
+ * fwupd_release_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new release using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdRelease, or %NULL if @value was invalid
+ *
+ * Since: 1.0.0
+ **/
+FwupdRelease *
+fwupd_release_from_variant(GVariant *value)
+{
+ FwupdRelease *self = NULL;
+ const gchar *type_string;
+ g_autoptr(GVariantIter) iter = NULL;
+
+ /* format from GetDetails */
+ type_string = g_variant_get_type_string(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ self = fwupd_release_new();
+ g_variant_get(value, "(a{sv})", &iter);
+ fwupd_release_set_from_variant_iter(self, iter);
+ } else if (g_strcmp0(type_string, "a{sv}") == 0) {
+ self = fwupd_release_new();
+ g_variant_get(value, "a{sv}", &iter);
+ fwupd_release_set_from_variant_iter(self, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return self;
+}
+
+/**
+ * fwupd_release_array_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates an array of new releases using serialized 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;
+
+ g_return_val_if_fail(value != NULL, 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 *self;
+ g_autoptr(GVariant) data = NULL;
+ data = g_variant_get_child_value(untuple, i);
+ self = fwupd_release_from_variant(data);
+ if (self == NULL)
+ continue;
+ g_ptr_array_add(array, self);
+ }
+ return array;
+}
+
+/**
+ * fwupd_release_new:
+ *
+ * Creates a new release.
+ *
+ * Returns: a new #FwupdRelease
+ *
+ * Since: 0.9.3
+ **/
+FwupdRelease *
+fwupd_release_new(void)
+{
+ FwupdRelease *self;
+ self = g_object_new(FWUPD_TYPE_RELEASE, NULL);
+ return FWUPD_RELEASE(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-release.h b/fwupd-1.8.6/libfwupd/fwupd-release.h
new file mode 100644
index 0000000000000000000000000000000000000000..df60e8739edbfa8c3920783f18dde88e28404bc8
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-release.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-enums.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_RELEASE (fwupd_release_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdRelease, fwupd_release, FWUPD, RELEASE, GObject)
+
+struct _FwupdReleaseClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ void (*_fwupd_reserved7)(void);
+};
+
+FwupdRelease *
+fwupd_release_new(void);
+gchar *
+fwupd_release_to_string(FwupdRelease *self);
+
+const gchar *
+fwupd_release_get_version(FwupdRelease *self);
+void
+fwupd_release_set_version(FwupdRelease *self, const gchar *version);
+G_DEPRECATED_FOR(fwupd_release_get_locations)
+const gchar *
+fwupd_release_get_uri(FwupdRelease *self);
+G_DEPRECATED_FOR(fwupd_release_add_location)
+void
+fwupd_release_set_uri(FwupdRelease *self, const gchar *uri);
+GPtrArray *
+fwupd_release_get_locations(FwupdRelease *self);
+void
+fwupd_release_add_location(FwupdRelease *self, const gchar *location);
+GPtrArray *
+fwupd_release_get_issues(FwupdRelease *self);
+void
+fwupd_release_add_issue(FwupdRelease *self, const gchar *issue);
+GPtrArray *
+fwupd_release_get_categories(FwupdRelease *self);
+void
+fwupd_release_add_category(FwupdRelease *self, const gchar *category);
+gboolean
+fwupd_release_has_category(FwupdRelease *self, const gchar *category);
+GPtrArray *
+fwupd_release_get_checksums(FwupdRelease *self);
+void
+fwupd_release_add_checksum(FwupdRelease *self, const gchar *checksum);
+gboolean
+fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum);
+GPtrArray *
+fwupd_release_get_tags(FwupdRelease *self);
+void
+fwupd_release_add_tag(FwupdRelease *self, const gchar *tag);
+gboolean
+fwupd_release_has_tag(FwupdRelease *self, const gchar *tag);
+
+GHashTable *
+fwupd_release_get_metadata(FwupdRelease *self);
+void
+fwupd_release_add_metadata(FwupdRelease *self, GHashTable *hash);
+void
+fwupd_release_add_metadata_item(FwupdRelease *self, const gchar *key, const gchar *value);
+const gchar *
+fwupd_release_get_metadata_item(FwupdRelease *self, const gchar *key);
+
+const gchar *
+fwupd_release_get_filename(FwupdRelease *self);
+void
+fwupd_release_set_filename(FwupdRelease *self, const gchar *filename);
+const gchar *
+fwupd_release_get_protocol(FwupdRelease *self);
+void
+fwupd_release_set_protocol(FwupdRelease *self, const gchar *protocol);
+const gchar *
+fwupd_release_get_id(FwupdRelease *self);
+void
+fwupd_release_set_id(FwupdRelease *self, const gchar *id);
+const gchar *
+fwupd_release_get_appstream_id(FwupdRelease *self);
+void
+fwupd_release_set_appstream_id(FwupdRelease *self, const gchar *appstream_id);
+const gchar *
+fwupd_release_get_detach_caption(FwupdRelease *self);
+void
+fwupd_release_set_detach_caption(FwupdRelease *self, const gchar *detach_caption);
+const gchar *
+fwupd_release_get_detach_image(FwupdRelease *self);
+void
+fwupd_release_set_detach_image(FwupdRelease *self, const gchar *detach_image);
+const gchar *
+fwupd_release_get_remote_id(FwupdRelease *self);
+void
+fwupd_release_set_remote_id(FwupdRelease *self, const gchar *remote_id);
+const gchar *
+fwupd_release_get_vendor(FwupdRelease *self);
+void
+fwupd_release_set_vendor(FwupdRelease *self, const gchar *vendor);
+const gchar *
+fwupd_release_get_name(FwupdRelease *self);
+void
+fwupd_release_set_name(FwupdRelease *self, const gchar *name);
+const gchar *
+fwupd_release_get_name_variant_suffix(FwupdRelease *self);
+void
+fwupd_release_set_name_variant_suffix(FwupdRelease *self, const gchar *name_variant_suffix);
+const gchar *
+fwupd_release_get_summary(FwupdRelease *self);
+void
+fwupd_release_set_summary(FwupdRelease *self, const gchar *summary);
+const gchar *
+fwupd_release_get_branch(FwupdRelease *self);
+void
+fwupd_release_set_branch(FwupdRelease *self, const gchar *branch);
+const gchar *
+fwupd_release_get_description(FwupdRelease *self);
+void
+fwupd_release_set_description(FwupdRelease *self, const gchar *description);
+const gchar *
+fwupd_release_get_homepage(FwupdRelease *self);
+void
+fwupd_release_set_homepage(FwupdRelease *self, const gchar *homepage);
+const gchar *
+fwupd_release_get_details_url(FwupdRelease *self);
+void
+fwupd_release_set_details_url(FwupdRelease *self, const gchar *details_url);
+const gchar *
+fwupd_release_get_source_url(FwupdRelease *self);
+void
+fwupd_release_set_source_url(FwupdRelease *self, const gchar *source_url);
+guint64
+fwupd_release_get_size(FwupdRelease *self);
+void
+fwupd_release_set_size(FwupdRelease *self, guint64 size);
+guint64
+fwupd_release_get_created(FwupdRelease *self);
+void
+fwupd_release_set_created(FwupdRelease *self, guint64 created);
+const gchar *
+fwupd_release_get_license(FwupdRelease *self);
+void
+fwupd_release_set_license(FwupdRelease *self, const gchar *license);
+FwupdTrustFlags
+fwupd_release_get_trust_flags(FwupdRelease *self) G_DEPRECATED_FOR(fwupd_release_get_flags);
+void
+fwupd_release_set_trust_flags(FwupdRelease *self, FwupdTrustFlags trust_flags)
+ G_DEPRECATED_FOR(fwupd_release_set_flags);
+FwupdReleaseFlags
+fwupd_release_get_flags(FwupdRelease *self);
+void
+fwupd_release_set_flags(FwupdRelease *self, FwupdReleaseFlags flags);
+void
+fwupd_release_add_flag(FwupdRelease *self, FwupdReleaseFlags flag);
+void
+fwupd_release_remove_flag(FwupdRelease *self, FwupdReleaseFlags flag);
+gboolean
+fwupd_release_has_flag(FwupdRelease *self, FwupdReleaseFlags flag);
+FwupdReleaseUrgency
+fwupd_release_get_urgency(FwupdRelease *self);
+void
+fwupd_release_set_urgency(FwupdRelease *self, FwupdReleaseUrgency urgency);
+guint32
+fwupd_release_get_install_duration(FwupdRelease *self);
+void
+fwupd_release_set_install_duration(FwupdRelease *self, guint32 duration);
+const gchar *
+fwupd_release_get_update_message(FwupdRelease *self);
+void
+fwupd_release_set_update_message(FwupdRelease *self, const gchar *update_message);
+const gchar *
+fwupd_release_get_update_image(FwupdRelease *self);
+void
+fwupd_release_set_update_image(FwupdRelease *self, const gchar *update_image);
+
+FwupdRelease *
+fwupd_release_from_variant(GVariant *value);
+GPtrArray *
+fwupd_release_array_from_variant(GVariant *value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-remote-private.h b/fwupd-1.8.6/libfwupd/fwupd-remote-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..07c1437c944c19e092a605d31ce49a7758fd350e
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-remote-private.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-remote.h"
+
+G_BEGIN_DECLS
+
+GVariant *
+fwupd_remote_to_variant(FwupdRemote *self);
+gboolean
+fwupd_remote_load_from_filename(FwupdRemote *self,
+ const gchar *filename,
+ GCancellable *cancellable,
+ 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_checksum(FwupdRemote *self, const gchar *checksum);
+void
+fwupd_remote_set_filename_cache(FwupdRemote *self, const gchar *filename);
+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);
+
+void
+fwupd_remote_set_remotes_dir(FwupdRemote *self, const gchar *directory);
+void
+fwupd_remote_set_filename_source(FwupdRemote *self, const gchar *filename_source);
+void
+fwupd_remote_set_keyring_kind(FwupdRemote *self, FwupdKeyringKind keyring_kind);
+gboolean
+fwupd_remote_setup(FwupdRemote *self, GError **error);
+void
+fwupd_remote_to_json(FwupdRemote *self, JsonBuilder *builder);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-remote.c b/fwupd-1.8.6/libfwupd/fwupd-remote.c
new file mode 100644
index 0000000000000000000000000000000000000000..72093735e887fc16321220af0edb97270594b2fa
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-remote.c
@@ -0,0 +1,1816 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBCURL
+#include
+#endif
+#include
+
+#include "fwupd-common-private.h"
+#include "fwupd-deprecated.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-error.h"
+#include "fwupd-remote-private.h"
+
+/**
+ * FwupdRemote:
+ *
+ * A source of metadata that provides firmware.
+ *
+ * Remotes can be local (e.g. folders on a disk) or remote (e.g. downloaded
+ * over HTTP or IPFS).
+ *
+ * See also: [class@FwupdClient]
+ */
+
+static void
+fwupd_remote_finalize(GObject *obj);
+
+typedef struct {
+ FwupdRemoteKind kind;
+ FwupdKeyringKind keyring_kind;
+ gchar *id;
+ gchar *firmware_base_uri;
+ gchar *report_uri;
+ gchar *security_report_uri;
+ gchar *metadata_uri;
+ gchar *metadata_uri_sig;
+ 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;
+ gchar **order_before;
+ gchar *remotes_dir;
+ gboolean automatic_reports;
+ gboolean automatic_security_reports;
+} FwupdRemotePrivate;
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_ENABLED,
+ PROP_APPROVAL_REQUIRED,
+ PROP_AUTOMATIC_REPORTS,
+ PROP_AUTOMATIC_SECURITY_REPORTS,
+ PROP_LAST
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdRemote, fwupd_remote, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_remote_get_instance_private(o))
+
+#ifdef HAVE_LIBCURL_7_62_0
+typedef gchar curlptr;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(curlptr, curl_free)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURLU, curl_url_cleanup)
+#endif
+
+/**
+ * fwupd_remote_to_json:
+ * @self: a #FwupdRemote
+ * @builder: a JSON builder
+ *
+ * Adds a fwupd remote to a JSON builder
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_remote_to_json(FwupdRemote *self, JsonBuilder *builder)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_REMOTE(self));
+ g_return_if_fail(builder != NULL);
+
+ fwupd_common_json_add_string(builder, "Id", priv->id);
+ if (priv->kind != FWUPD_REMOTE_KIND_UNKNOWN) {
+ fwupd_common_json_add_string(builder,
+ "Kind",
+ fwupd_remote_kind_to_string(priv->kind));
+ }
+ if (priv->keyring_kind != FWUPD_KEYRING_KIND_UNKNOWN) {
+ fwupd_common_json_add_string(builder,
+ "KeyringKind",
+ fwupd_keyring_kind_to_string(priv->keyring_kind));
+ }
+ fwupd_common_json_add_string(builder, "FirmwareBaseUri", priv->firmware_base_uri);
+ fwupd_common_json_add_string(builder, "ReportUri", priv->report_uri);
+ fwupd_common_json_add_string(builder, "SecurityReportUri", priv->security_report_uri);
+ fwupd_common_json_add_string(builder, "MetadataUri", priv->metadata_uri);
+ fwupd_common_json_add_string(builder, "MetadataUriSig", priv->metadata_uri_sig);
+ fwupd_common_json_add_string(builder, "Username", priv->username);
+ fwupd_common_json_add_string(builder, "Password", priv->password);
+ fwupd_common_json_add_string(builder, "Title", priv->title);
+ fwupd_common_json_add_string(builder, "Agreement", priv->agreement);
+ fwupd_common_json_add_string(builder, "Checksum", priv->checksum);
+ fwupd_common_json_add_string(builder, "FilenameCache", priv->filename_cache);
+ fwupd_common_json_add_string(builder, "FilenameCacheSig", priv->filename_cache_sig);
+ fwupd_common_json_add_string(builder, "FilenameSource", priv->filename_source);
+ fwupd_common_json_add_boolean(builder, "Enabled", priv->enabled);
+ fwupd_common_json_add_boolean(builder, "ApprovalRequired", priv->approval_required);
+ fwupd_common_json_add_boolean(builder, "AutomaticReports", priv->automatic_reports);
+ fwupd_common_json_add_boolean(builder,
+ "AutomaticSecurityReports",
+ priv->automatic_security_reports);
+ fwupd_common_json_add_int(builder, "Priority", priv->priority);
+ fwupd_common_json_add_int(builder, "Mtime", priv->mtime);
+ fwupd_common_json_add_string(builder, "RemotesDir", priv->remotes_dir);
+ fwupd_common_json_add_stringv(builder, "OrderAfter", priv->order_after);
+ fwupd_common_json_add_stringv(builder, "OrderBefore", priv->order_before);
+}
+
+static gchar *
+fwupd_strdup_nonempty(const gchar *text)
+{
+ if (text == NULL || text[0] == '\0')
+ return NULL;
+ return g_strdup(text);
+}
+
+static void
+fwupd_remote_set_username(FwupdRemote *self, const gchar *username)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->username, username) == 0)
+ return;
+
+ g_free(priv->username);
+ priv->username = g_strdup(username);
+}
+
+static void
+fwupd_remote_set_title(FwupdRemote *self, const gchar *title)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->title, title) == 0)
+ return;
+
+ g_free(priv->title);
+ priv->title = g_strdup(title);
+}
+
+/**
+ * fwupd_remote_set_agreement:
+ * @self: a #FwupdRemote
+ * @agreement: (nullable): agreement markup text
+ *
+ * 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);
+
+ /* not changed */
+ if (g_strcmp0(priv->agreement, agreement) == 0)
+ return;
+
+ g_free(priv->agreement);
+ priv->agreement = g_strdup(agreement);
+}
+
+/**
+ * fwupd_remote_set_checksum:
+ * @self: a #FwupdRemote
+ * @checksum: (nullable): checksum string
+ *
+ * Sets the remote checksum, typically only useful in the self tests.
+ *
+ * Since: 1.8.2
+ **/
+void
+fwupd_remote_set_checksum(FwupdRemote *self, const gchar *checksum)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->checksum, checksum) == 0)
+ return;
+
+ g_free(priv->checksum);
+ priv->checksum = g_strdup(checksum);
+}
+
+static void
+fwupd_remote_set_password(FwupdRemote *self, const gchar *password)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->password, password) == 0)
+ return;
+
+ g_free(priv->password);
+ priv->password = g_strdup(password);
+}
+
+static void
+fwupd_remote_set_kind(FwupdRemote *self, FwupdRemoteKind kind)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ priv->kind = kind;
+}
+
+/**
+ * fwupd_remote_set_keyring_kind:
+ * @self: a #FwupdRemote
+ * @keyring_kind: keyring kind e.g. #FWUPD_KEYRING_KIND_PKCS7
+ *
+ * Sets the keyring kind
+ *
+ * Since: 1.5.3
+ **/
+void
+fwupd_remote_set_keyring_kind(FwupdRemote *self, FwupdKeyringKind keyring_kind)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ priv->keyring_kind = keyring_kind;
+}
+
+/* note, this has to be set before url */
+static void
+fwupd_remote_set_id(FwupdRemote *self, const gchar *id)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->id, id) == 0)
+ return;
+
+ g_free(priv->id);
+ priv->id = g_strdup(id);
+ g_strdelimit(priv->id, ".", '\0');
+}
+
+/**
+ * fwupd_remote_set_filename_source:
+ * @self: a #FwupdRemote
+ * @filename_source: (nullable): filename
+ *
+ * Sets the source filename. This is typically a file in `/etc/fwupd/remotes/`.
+ *
+ * Since: 1.6.1
+ **/
+void
+fwupd_remote_set_filename_source(FwupdRemote *self, const gchar *filename_source)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ if (priv->filename_source == filename_source)
+ return;
+ g_free(priv->filename_source);
+ priv->filename_source = g_strdup(filename_source);
+}
+
+static const gchar *
+fwupd_remote_get_suffix_for_keyring_kind(FwupdKeyringKind keyring_kind)
+{
+ if (keyring_kind == FWUPD_KEYRING_KIND_JCAT)
+ return ".jcat";
+ if (keyring_kind == FWUPD_KEYRING_KIND_GPG)
+ return ".asc";
+ if (keyring_kind == FWUPD_KEYRING_KIND_PKCS7)
+ return ".p7b";
+ return NULL;
+}
+
+static gchar *
+fwupd_remote_build_uri(FwupdRemote *self, const gchar *url, GError **error)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+#ifdef HAVE_LIBCURL_7_62_0
+ g_autoptr(curlptr) tmp_uri = NULL;
+ g_autoptr(CURLU) uri = curl_url();
+
+ /* create URI, substituting if required */
+ if (priv->firmware_base_uri != NULL) {
+ g_autofree gchar *basename = NULL;
+ g_autofree gchar *path_new = NULL;
+ g_autoptr(curlptr) path = NULL;
+ g_autoptr(CURLU) uri_tmp = curl_url();
+ if (curl_url_set(uri_tmp, CURLUPART_URL, url, 0) != CURLUE_OK) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "Failed to parse url '%s'",
+ url);
+ return NULL;
+ }
+ (void)curl_url_get(uri_tmp, CURLUPART_PATH, &path, 0);
+ basename = g_path_get_basename(path);
+ path_new = g_build_filename(priv->firmware_base_uri, basename, NULL);
+ (void)curl_url_set(uri, CURLUPART_URL, path_new, 0);
+
+ /* use the base URI of the metadata to build the full path */
+ } else if (g_strstr_len(url, -1, "/") == NULL) {
+ g_autofree gchar *basename = NULL;
+ g_autofree gchar *path_new = NULL;
+ g_autoptr(curlptr) path = NULL;
+ if (curl_url_set(uri, CURLUPART_URL, priv->metadata_uri, 0) != CURLUE_OK) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "Failed to parse url '%s'",
+ priv->metadata_uri);
+ return NULL;
+ }
+ (void)curl_url_get(uri, CURLUPART_PATH, &path, 0);
+ basename = g_path_get_dirname(path);
+ path_new = g_build_filename(basename, url, NULL);
+ (void)curl_url_set(uri, CURLUPART_URL, path_new, 0);
+
+ /* a normal URI */
+ } else {
+ if (curl_url_set(uri, CURLUPART_URL, url, 0) != CURLUE_OK) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "Failed to parse URI '%s'",
+ url);
+ return NULL;
+ }
+ }
+
+ /* set the username and password */
+ if (priv->username != NULL)
+ (void)curl_url_set(uri, CURLUPART_USER, priv->username, 0);
+ if (priv->password != NULL)
+ (void)curl_url_set(uri, CURLUPART_PASSWORD, priv->password, 0);
+ (void)curl_url_get(uri, CURLUPART_URL, &tmp_uri, 0);
+ return g_strdup(tmp_uri);
+#else
+ if (priv->firmware_base_uri != NULL) {
+ g_autofree gchar *basename = g_path_get_basename(url);
+ return g_build_filename(priv->firmware_base_uri, basename, NULL);
+ }
+ if (g_strstr_len(url, -1, "/") == NULL) {
+ g_autofree gchar *basename = g_path_get_dirname(priv->metadata_uri);
+ return g_build_filename(basename, url, NULL);
+ }
+ return g_strdup(url);
+#endif
+}
+
+/* note, this has to be set before username and password */
+static void
+fwupd_remote_set_metadata_uri(FwupdRemote *self, const gchar *metadata_uri)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ const gchar *suffix;
+
+ /* save this so we can export the object as a GVariant */
+ priv->metadata_uri = g_strdup(metadata_uri);
+
+ /* generate the signature URI too */
+ suffix = fwupd_remote_get_suffix_for_keyring_kind(priv->keyring_kind);
+ if (suffix != NULL)
+ priv->metadata_uri_sig = g_strconcat(metadata_uri, suffix, NULL);
+}
+
+/* note, this has to be set after MetadataURI */
+static void
+fwupd_remote_set_firmware_base_uri(FwupdRemote *self, const gchar *firmware_base_uri)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->firmware_base_uri, firmware_base_uri) == 0)
+ return;
+
+ g_free(priv->firmware_base_uri);
+ priv->firmware_base_uri = g_strdup(firmware_base_uri);
+}
+
+static void
+fwupd_remote_set_report_uri(FwupdRemote *self, const gchar *report_uri)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_autofree gchar *report_uri_safe = fwupd_strdup_nonempty(report_uri);
+
+ /* not changed */
+ if (g_strcmp0(priv->report_uri, report_uri_safe) == 0)
+ return;
+
+ g_free(priv->report_uri);
+ priv->report_uri = g_steal_pointer(&report_uri_safe);
+}
+
+static void
+fwupd_remote_set_security_report_uri(FwupdRemote *self, const gchar *security_report_uri)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_autofree gchar *security_report_uri_safe = fwupd_strdup_nonempty(security_report_uri);
+
+ /* not changed */
+ if (g_strcmp0(priv->security_report_uri, security_report_uri_safe) == 0)
+ return;
+
+ g_free(priv->security_report_uri);
+ priv->security_report_uri = g_steal_pointer(&security_report_uri_safe);
+}
+
+/**
+ * fwupd_remote_kind_from_string:
+ * @kind: (nullable): a string, e.g. `download`
+ *
+ * Converts an printable string to an enumerated type.
+ *
+ * Returns: a #FwupdRemoteKind, e.g. %FWUPD_REMOTE_KIND_DOWNLOAD
+ *
+ * Since: 0.9.6
+ **/
+FwupdRemoteKind
+fwupd_remote_kind_from_string(const gchar *kind)
+{
+ if (g_strcmp0(kind, "download") == 0)
+ 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;
+}
+
+/**
+ * fwupd_remote_kind_to_string:
+ * @kind: a #FwupdRemoteKind, e.g. %FWUPD_REMOTE_KIND_DOWNLOAD
+ *
+ * Converts an enumerated type to a printable string.
+ *
+ * Returns: a string, e.g. `download`
+ *
+ * Since: 0.9.6
+ **/
+const gchar *
+fwupd_remote_kind_to_string(FwupdRemoteKind kind)
+{
+ if (kind == FWUPD_REMOTE_KIND_DOWNLOAD)
+ return "download";
+ if (kind == FWUPD_REMOTE_KIND_LOCAL)
+ return "local";
+ if (kind == FWUPD_REMOTE_KIND_DIRECTORY)
+ return "directory";
+ return NULL;
+}
+
+/**
+ * fwupd_remote_set_filename_cache:
+ * @self: a #FwupdRemote
+ * @filename: (nullable): filename string
+ *
+ * Sets the remote filename cache filename, typically only useful in the self tests.
+ *
+ * Since: 1.8.2
+ **/
+void
+fwupd_remote_set_filename_cache(FwupdRemote *self, const gchar *filename)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ const gchar *suffix;
+
+ g_return_if_fail(FWUPD_IS_REMOTE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->filename_cache, filename) == 0)
+ return;
+
+ g_free(priv->filename_cache);
+ priv->filename_cache = g_strdup(filename);
+
+ /* create for all remote types */
+ suffix = fwupd_remote_get_suffix_for_keyring_kind(priv->keyring_kind);
+ if (suffix != NULL) {
+ g_free(priv->filename_cache_sig);
+ priv->filename_cache_sig = g_strconcat(filename, suffix, NULL);
+ }
+}
+
+static void
+fwupd_remote_set_order_before(FwupdRemote *self, const gchar *order_before)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_clear_pointer(&priv->order_before, g_strfreev);
+ if (order_before != NULL)
+ priv->order_before = g_strsplit_set(order_before, ",:;", -1);
+}
+
+static void
+fwupd_remote_set_order_after(FwupdRemote *self, const gchar *order_after)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_clear_pointer(&priv->order_after, g_strfreev);
+ if (order_after != NULL)
+ priv->order_after = g_strsplit_set(order_after, ",:;", -1);
+}
+
+/**
+ * fwupd_remote_setup:
+ * @self: a #FwupdRemote
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets up the remote ready for use, checking that required parameters have
+ * been set. Calling this method multiple times has no effect.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.6.1
+ **/
+gboolean
+fwupd_remote_setup(FwupdRemote *self, GError **error)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* we can override, hence the extra section */
+ if (priv->kind == FWUPD_REMOTE_KIND_UNKNOWN) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "metadata kind invalid");
+ return FALSE;
+ }
+
+ /* some validation for DOWNLOAD types */
+ if (priv->kind == FWUPD_REMOTE_KIND_DOWNLOAD) {
+ g_autofree gchar *filename_cache = NULL;
+
+ if (priv->remotes_dir == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "remotes directory not set");
+ return FALSE;
+ }
+ /* set cache to /var/lib... */
+ filename_cache =
+ g_build_filename(priv->remotes_dir, priv->id, "metadata.xml.gz", NULL);
+ fwupd_remote_set_filename_cache(self, filename_cache);
+ }
+
+ /* some validation for 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 (priv->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;
+ }
+ }
+
+ /* load the checksum */
+ if (priv->filename_cache_sig != NULL &&
+ g_file_test(priv->filename_cache_sig, G_FILE_TEST_EXISTS)) {
+ gsize sz = 0;
+ g_autofree gchar *buf = NULL;
+ g_autoptr(GChecksum) checksum = g_checksum_new(G_CHECKSUM_SHA256);
+ if (!g_file_get_contents(priv->filename_cache_sig, &buf, &sz, error)) {
+ g_prefix_error(error, "failed to get checksum: ");
+ return FALSE;
+ }
+ g_checksum_update(checksum, (guchar *)buf, (gssize)sz);
+ fwupd_remote_set_checksum(self, g_checksum_get_string(checksum));
+ } else {
+ fwupd_remote_set_checksum(self, NULL);
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fwupd_remote_load_from_filename:
+ * @self: a #FwupdRemote
+ * @filename: (not nullable): a filename
+ * @cancellable: (nullable): optional #GCancellable
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads metadata about the remote from a keyfile.
+ * This can be called zero or multiple times for each remote.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.9.3
+ **/
+gboolean
+fwupd_remote_load_from_filename(FwupdRemote *self,
+ const gchar *filename,
+ GCancellable *cancellable,
+ GError **error)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ const gchar *group = "fwupd Remote";
+ g_autofree gchar *id = NULL;
+ g_autoptr(GKeyFile) kf = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ g_return_val_if_fail(filename != NULL, FALSE);
+ g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* set ID */
+ id = g_path_get_basename(filename);
+ fwupd_remote_set_id(self, id);
+
+ /* load file */
+ kf = g_key_file_new();
+ if (!g_key_file_load_from_file(kf, filename, G_KEY_FILE_NONE, error))
+ return FALSE;
+
+ /* optional verification type */
+ if (g_key_file_has_key(kf, group, "Keyring", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "Keyring", NULL);
+ priv->keyring_kind = fwupd_keyring_kind_from_string(tmp);
+ if (priv->keyring_kind == FWUPD_KEYRING_KIND_UNKNOWN) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "keyring kind '%s' unknown",
+ tmp);
+ return FALSE;
+ }
+ }
+
+ /* the first remote sets the URI, even if it's file:// to the cache */
+ if (g_key_file_has_key(kf, group, "MetadataURI", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "MetadataURI", NULL);
+ if (g_str_has_prefix(tmp, "file://")) {
+ const gchar *filename_cache = tmp;
+ 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(tmp, "http://") || g_str_has_prefix(tmp, "https://") ||
+ g_str_has_prefix(tmp, "ipfs://") || g_str_has_prefix(tmp, "ipns://")) {
+ priv->kind = FWUPD_REMOTE_KIND_DOWNLOAD;
+ fwupd_remote_set_metadata_uri(self, tmp);
+ }
+ }
+
+ /* all keys are optional */
+ if (g_key_file_has_key(kf, group, "Enabled", NULL))
+ priv->enabled = g_key_file_get_boolean(kf, group, "Enabled", NULL);
+ if (g_key_file_has_key(kf, group, "ApprovalRequired", NULL))
+ priv->approval_required =
+ g_key_file_get_boolean(kf, group, "ApprovalRequired", NULL);
+ if (g_key_file_has_key(kf, group, "Title", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "Title", NULL);
+ fwupd_remote_set_title(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "ReportURI", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "ReportURI", NULL);
+ fwupd_remote_set_report_uri(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "SecurityReportURI", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "SecurityReportURI", NULL);
+ fwupd_remote_set_security_report_uri(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "Username", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "Username", NULL);
+ fwupd_remote_set_username(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "Password", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "Password", NULL);
+ fwupd_remote_set_password(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "FirmwareBaseURI", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "FirmwareBaseURI", NULL);
+ fwupd_remote_set_firmware_base_uri(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "OrderBefore", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "OrderBefore", NULL);
+ fwupd_remote_set_order_before(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "OrderAfter", NULL)) {
+ g_autofree gchar *tmp = g_key_file_get_string(kf, group, "OrderAfter", NULL);
+ fwupd_remote_set_order_after(self, tmp);
+ }
+ if (g_key_file_has_key(kf, group, "AutomaticReports", NULL))
+ priv->automatic_reports =
+ g_key_file_get_boolean(kf, group, "AutomaticReports", NULL);
+ if (g_key_file_has_key(kf, group, "AutomaticSecurityReports", NULL))
+ priv->automatic_security_reports =
+ g_key_file_get_boolean(kf, group, "AutomaticSecurityReports", NULL);
+
+ /* success */
+ fwupd_remote_set_filename_source(self, filename);
+ return TRUE;
+}
+
+/**
+ * fwupd_remote_get_order_after:
+ * @self: a #FwupdRemote
+ *
+ * Gets the list of remotes this plugin should be ordered after.
+ *
+ * Returns: (transfer none): an array
+ *
+ * Since: 0.9.5
+ **/
+gchar **
+fwupd_remote_get_order_after(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->order_after;
+}
+
+/**
+ * fwupd_remote_get_order_before:
+ * @self: a #FwupdRemote
+ *
+ * Gets the list of remotes this plugin should be ordered before.
+ *
+ * Returns: (transfer none): an array
+ *
+ * Since: 0.9.5
+ **/
+gchar **
+fwupd_remote_get_order_before(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->order_before;
+}
+
+/**
+ * fwupd_remote_get_filename_cache:
+ * @self: a #FwupdRemote
+ *
+ * Gets the path and filename that the remote is using for a cache.
+ *
+ * Returns: a string, or %NULL for unset
+ *
+ * Since: 0.9.6
+ **/
+const gchar *
+fwupd_remote_get_filename_cache(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->filename_cache;
+}
+
+/**
+ * fwupd_remote_get_filename_cache_sig:
+ * @self: a #FwupdRemote
+ *
+ * Gets the path and filename that the remote is using for a signature cache.
+ *
+ * Returns: a string, or %NULL for unset
+ *
+ * Since: 0.9.7
+ **/
+const gchar *
+fwupd_remote_get_filename_cache_sig(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->filename_cache_sig;
+}
+
+/**
+ * fwupd_remote_get_filename_source:
+ * @self: a #FwupdRemote
+ *
+ * Gets the path and filename of the remote itself, typically a `.conf` file.
+ *
+ * Returns: a string, or %NULL for unset
+ *
+ * Since: 0.9.8
+ **/
+const gchar *
+fwupd_remote_get_filename_source(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->filename_source;
+}
+
+/**
+ * fwupd_remote_get_priority:
+ * @self: a #FwupdRemote
+ *
+ * Gets the priority of the remote, where bigger numbers are better.
+ *
+ * Returns: a priority, or 0 for the default value
+ *
+ * Since: 0.9.5
+ **/
+gint
+fwupd_remote_get_priority(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), 0);
+ return priv->priority;
+}
+
+/**
+ * fwupd_remote_get_kind:
+ * @self: a #FwupdRemote
+ *
+ * Gets the kind of the remote.
+ *
+ * Returns: a #FwupdRemoteKind, e.g. #FWUPD_REMOTE_KIND_LOCAL
+ *
+ * Since: 0.9.6
+ **/
+FwupdRemoteKind
+fwupd_remote_get_kind(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), 0);
+ return priv->kind;
+}
+
+/**
+ * fwupd_remote_get_keyring_kind:
+ * @self: a #FwupdRemote
+ *
+ * Gets the keyring kind of the remote.
+ *
+ * Returns: a #FwupdKeyringKind, e.g. #FWUPD_KEYRING_KIND_GPG
+ *
+ * Since: 0.9.7
+ **/
+FwupdKeyringKind
+fwupd_remote_get_keyring_kind(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), 0);
+ return priv->keyring_kind;
+}
+
+/**
+ * fwupd_remote_get_age:
+ * @self: a #FwupdRemote
+ *
+ * Gets the age of the remote in seconds.
+ *
+ * Returns: a age, or %G_MAXUINT64 for unavailable
+ *
+ * Since: 0.9.5
+ **/
+guint64
+fwupd_remote_get_age(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ guint64 now;
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), 0);
+ now = (guint64)g_get_real_time() / G_USEC_PER_SEC;
+ if (priv->mtime > now)
+ return G_MAXUINT64;
+ return now - priv->mtime;
+}
+
+/**
+ * fwupd_remote_set_remotes_dir:
+ * @self: a #FwupdRemote
+ * @directory: (nullable): Remotes directory
+ *
+ * Sets the directory to store remote data
+ *
+ * Since: 1.3.1
+ **/
+void
+fwupd_remote_set_remotes_dir(FwupdRemote *self, const gchar *directory)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REMOTE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->remotes_dir, directory) == 0)
+ return;
+
+ g_free(priv->remotes_dir);
+ priv->remotes_dir = g_strdup(directory);
+}
+
+/**
+ * fwupd_remote_set_priority:
+ * @self: a #FwupdRemote
+ * @priority: an integer, where 1 is better
+ *
+ * Sets the plugin priority.
+ *
+ * Since: 0.9.5
+ **/
+void
+fwupd_remote_set_priority(FwupdRemote *self, gint priority)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REMOTE(self));
+ priv->priority = priority;
+}
+
+/**
+ * fwupd_remote_set_mtime:
+ * @self: a #FwupdRemote
+ * @mtime: a UNIX timestamp
+ *
+ * Sets the plugin modification time.
+ *
+ * Since: 0.9.5
+ **/
+void
+fwupd_remote_set_mtime(FwupdRemote *self, guint64 mtime)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REMOTE(self));
+ priv->mtime = mtime;
+}
+
+/**
+ * fwupd_remote_get_username:
+ * @self: a #FwupdRemote
+ *
+ * Gets the username configured for the remote.
+ *
+ * Returns: a string, or %NULL for unset
+ *
+ * Since: 0.9.5
+ **/
+const gchar *
+fwupd_remote_get_username(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->username;
+}
+
+/**
+ * fwupd_remote_get_password:
+ * @self: a #FwupdRemote
+ *
+ * Gets the password configured for the remote.
+ *
+ * Returns: a string, or %NULL for unset
+ *
+ * Since: 0.9.5
+ **/
+const gchar *
+fwupd_remote_get_password(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->password;
+}
+
+/**
+ * fwupd_remote_get_title:
+ * @self: a #FwupdRemote
+ *
+ * Gets the remote title, e.g. `Linux Vendor Firmware Service`.
+ *
+ * Returns: a string, or %NULL if unset
+ *
+ * Since: 0.9.8
+ **/
+const gchar *
+fwupd_remote_get_title(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->title;
+}
+
+/**
+ * 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_remotes_dir:
+ * @self: a #FwupdRemote
+ *
+ * Gets the base directory for storing remote metadata
+ *
+ * Returns: a string, or %NULL if unset
+ *
+ * Since: 1.3.1
+ **/
+const gchar *
+fwupd_remote_get_remotes_dir(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->remotes_dir;
+}
+
+/**
+ * fwupd_remote_get_checksum:
+ * @self: a #FwupdRemote
+ *
+ * Gets the remote checksum.
+ *
+ * Returns: a string, or %NULL if unset
+ *
+ * Since: 1.0.0
+ **/
+const gchar *
+fwupd_remote_get_checksum(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->checksum;
+}
+
+/**
+ * fwupd_remote_build_firmware_uri:
+ * @self: a #FwupdRemote
+ * @url: (not nullable): the URL to use
+ * @error: (nullable): optional return location for an error
+ *
+ * Builds a URI for the URL using the username and password set for the remote,
+ * including any basename URI substitution.
+ *
+ * Returns: (transfer full): a URI, or %NULL for error
+ *
+ * Since: 0.9.7
+ **/
+gchar *
+fwupd_remote_build_firmware_uri(FwupdRemote *self, const gchar *url, GError **error)
+{
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ g_return_val_if_fail(url != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return fwupd_remote_build_uri(self, url, error);
+}
+
+/**
+ * fwupd_remote_get_report_uri:
+ * @self: a #FwupdRemote
+ *
+ * Gets the URI for the remote reporting.
+ *
+ * Returns: (transfer none): a URI, or %NULL for invalid.
+ *
+ * Since: 1.0.4
+ **/
+const gchar *
+fwupd_remote_get_report_uri(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->report_uri;
+}
+
+/**
+ * fwupd_remote_get_security_report_uri:
+ * @self: a #FwupdRemote
+ *
+ * Gets the URI for the security report.
+ *
+ * Returns: (transfer none): a URI, or %NULL for invalid.
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_remote_get_security_report_uri(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->security_report_uri;
+}
+
+/**
+ * fwupd_remote_get_metadata_uri:
+ * @self: a #FwupdRemote
+ *
+ * Gets the URI for the remote metadata.
+ *
+ * Returns: (transfer none): a URI, or %NULL for invalid.
+ *
+ * Since: 0.9.7
+ **/
+const gchar *
+fwupd_remote_get_metadata_uri(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->metadata_uri;
+}
+
+static gboolean
+fwupd_remote_load_signature_jcat(FwupdRemote *self, JcatFile *jcat_file, GError **error)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ const gchar *id;
+ g_autofree gchar *basename = NULL;
+ g_autofree gchar *baseuri = NULL;
+ g_autofree gchar *metadata_uri = NULL;
+ g_autoptr(JcatItem) jcat_item = NULL;
+
+ /* this seems pointless to get the item by ID then just read the ID,
+ * but _get_item_by_id() uses the AliasIds as a fallback */
+ basename = g_path_get_basename(priv->metadata_uri);
+ jcat_item = jcat_file_get_item_by_id(jcat_file, basename, NULL);
+ if (jcat_item == NULL) {
+ /* if we're using libjcat 0.1.0 just get the default item */
+ jcat_item = jcat_file_get_item_default(jcat_file, error);
+ if (jcat_item == NULL)
+ return FALSE;
+ }
+ id = jcat_item_get_id(jcat_item);
+ if (id == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "No ID for JCat item");
+ return FALSE;
+ }
+
+ /* replace the URI if required */
+ baseuri = g_path_get_dirname(priv->metadata_uri);
+ metadata_uri = g_build_path("/", baseuri, id, NULL);
+ if (g_strcmp0(metadata_uri, priv->metadata_uri) != 0) {
+ g_debug("changing metadata URI from %s to %s", priv->metadata_uri, metadata_uri);
+ g_free(priv->metadata_uri);
+ priv->metadata_uri = g_steal_pointer(&metadata_uri);
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fwupd_remote_load_signature_bytes:
+ * @self: a #FwupdRemote
+ * @bytes: (not nullable): data blob
+ * @error: (nullable): optional return location for an error
+ *
+ * Parses the signature, updating the metadata URI as appropriate.
+ *
+ * This can only be called for remotes with `Keyring=jcat` which is
+ * the default for most remotes.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.5
+ **/
+gboolean
+fwupd_remote_load_signature_bytes(FwupdRemote *self, GBytes *bytes, GError **error)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GInputStream) istr = NULL;
+ g_autoptr(JcatFile) jcat_file = jcat_file_new();
+
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ g_return_val_if_fail(bytes != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* sanity check */
+ if (priv->keyring_kind != FWUPD_KEYRING_KIND_JCAT) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "only supported for JCat remotes");
+ return FALSE;
+ }
+
+ istr = g_memory_input_stream_new_from_bytes(bytes);
+ if (!jcat_file_import_stream(jcat_file, istr, JCAT_IMPORT_FLAG_NONE, NULL, error))
+ return FALSE;
+ return fwupd_remote_load_signature_jcat(self, jcat_file, error);
+}
+
+/**
+ * fwupd_remote_load_signature:
+ * @self: a #FwupdRemote
+ * @filename: (not nullable): a filename
+ * @error: (nullable): optional return location for an error
+ *
+ * Parses the signature, updating the metadata URI as appropriate.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.0
+ **/
+gboolean
+fwupd_remote_load_signature(FwupdRemote *self, const gchar *filename, GError **error)
+{
+ g_autoptr(GFile) gfile = NULL;
+ g_autoptr(JcatFile) jcat_file = jcat_file_new();
+
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ g_return_val_if_fail(filename != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* load JCat file */
+ gfile = g_file_new_for_path(filename);
+ if (!jcat_file_import_file(jcat_file, gfile, JCAT_IMPORT_FLAG_NONE, NULL, error))
+ return FALSE;
+ return fwupd_remote_load_signature_jcat(self, jcat_file, error);
+}
+
+/**
+ * fwupd_remote_get_metadata_uri_sig:
+ * @self: a #FwupdRemote
+ *
+ * Gets the URI for the remote metadata signature.
+ *
+ * Returns: (transfer none): a URI, or %NULL for invalid.
+ *
+ * Since: 0.9.7
+ **/
+const gchar *
+fwupd_remote_get_metadata_uri_sig(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->metadata_uri_sig;
+}
+
+/**
+ * fwupd_remote_get_firmware_base_uri:
+ * @self: a #FwupdRemote
+ *
+ * Gets the base URI for firmware.
+ *
+ * Returns: (transfer none): a URI, or %NULL for unset.
+ *
+ * Since: 0.9.7
+ **/
+const gchar *
+fwupd_remote_get_firmware_base_uri(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->firmware_base_uri;
+}
+
+/**
+ * fwupd_remote_get_enabled:
+ * @self: a #FwupdRemote
+ *
+ * Gets if the remote is enabled and should be used.
+ *
+ * Returns: a #TRUE if the remote is enabled
+ *
+ * Since: 0.9.3
+ **/
+gboolean
+fwupd_remote_get_enabled(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ return priv->enabled;
+}
+
+/**
+ * fwupd_remote_get_automatic_reports:
+ * @self: a #FwupdRemote
+ *
+ * Gets if reports should be automatically uploaded to this remote
+ *
+ * Returns: a #TRUE if the remote should have reports uploaded automatically
+ *
+ * Since: 1.3.3
+ **/
+gboolean
+fwupd_remote_get_automatic_reports(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ return priv->automatic_reports;
+}
+
+/**
+ * fwupd_remote_get_automatic_security_reports:
+ * @self: a #FwupdRemote
+ *
+ * Gets if security reports should be automatically uploaded to this remote
+ *
+ * Returns: a #TRUE if the remote should have reports uploaded automatically
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_remote_get_automatic_security_reports(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), FALSE);
+ return priv->automatic_security_reports;
+}
+
+/**
+ * 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
+ *
+ * Gets the remote ID, e.g. `lvfs-testing`.
+ *
+ * Returns: a string, or %NULL if unset
+ *
+ * Since: 0.9.3
+ **/
+const gchar *
+fwupd_remote_get_id(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REMOTE(self), NULL);
+ return priv->id;
+}
+
+static void
+fwupd_remote_set_from_variant_iter(FwupdRemote *self, GVariantIter *iter)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ GVariant *value;
+ const gchar *key;
+ g_autoptr(GVariantIter) iter2 = g_variant_iter_copy(iter);
+ g_autoptr(GVariantIter) iter3 = g_variant_iter_copy(iter);
+
+ /* three passes, as we have to construct Id -> Url -> * */
+ while (g_variant_iter_loop(iter, "{&sv}", &key, &value)) {
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_REMOTE_ID) == 0)
+ fwupd_remote_set_id(self, g_variant_get_string(value, NULL));
+ if (g_strcmp0(key, "Type") == 0)
+ fwupd_remote_set_kind(self, g_variant_get_uint32(value));
+ if (g_strcmp0(key, "Keyring") == 0)
+ fwupd_remote_set_keyring_kind(self, g_variant_get_uint32(value));
+ }
+ while (g_variant_iter_loop(iter2, "{&sv}", &key, &value)) {
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_URI) == 0)
+ fwupd_remote_set_metadata_uri(self, g_variant_get_string(value, NULL));
+ if (g_strcmp0(key, "FilenameCache") == 0)
+ fwupd_remote_set_filename_cache(self, g_variant_get_string(value, NULL));
+ if (g_strcmp0(key, "FilenameSource") == 0)
+ fwupd_remote_set_filename_source(self, g_variant_get_string(value, NULL));
+ if (g_strcmp0(key, "ReportUri") == 0)
+ fwupd_remote_set_report_uri(self, g_variant_get_string(value, NULL));
+ if (g_strcmp0(key, "SecurityReportUri") == 0)
+ fwupd_remote_set_security_report_uri(self,
+ g_variant_get_string(value, NULL));
+ }
+ while (g_variant_iter_loop(iter3, "{&sv}", &key, &value)) {
+ if (g_strcmp0(key, "Username") == 0) {
+ fwupd_remote_set_username(self, g_variant_get_string(value, NULL));
+ } else if (g_strcmp0(key, "Password") == 0) {
+ 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) {
+ priv->mtime = g_variant_get_uint64(value);
+ } else if (g_strcmp0(key, "FirmwareBaseUri") == 0) {
+ fwupd_remote_set_firmware_base_uri(self, g_variant_get_string(value, NULL));
+ } else if (g_strcmp0(key, "AutomaticReports") == 0) {
+ priv->automatic_reports = g_variant_get_boolean(value);
+ } else if (g_strcmp0(key, "AutomaticSecurityReports") == 0) {
+ priv->automatic_security_reports = g_variant_get_boolean(value);
+ }
+ }
+}
+
+/**
+ * fwupd_remote_to_variant:
+ * @self: a #FwupdRemote
+ *
+ * Serialize the remote data.
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.0.0
+ **/
+GVariant *
+fwupd_remote_to_variant(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ 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_VARDICT);
+ if (priv->id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_REMOTE_ID,
+ g_variant_new_string(priv->id));
+ }
+ if (priv->username != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "Username",
+ g_variant_new_string(priv->username));
+ }
+ if (priv->password != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "Password",
+ g_variant_new_string(priv->password));
+ }
+ if (priv->title != NULL) {
+ 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));
+ }
+ if (priv->metadata_uri != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_URI,
+ g_variant_new_string(priv->metadata_uri));
+ }
+ if (priv->report_uri != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "ReportUri",
+ g_variant_new_string(priv->report_uri));
+ }
+ if (priv->security_report_uri != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "SecurityReportUri",
+ g_variant_new_string(priv->security_report_uri));
+ }
+ if (priv->firmware_base_uri != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "FirmwareBaseUri",
+ g_variant_new_string(priv->firmware_base_uri));
+ }
+ if (priv->priority != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "Priority",
+ g_variant_new_int32(priv->priority));
+ }
+ if (priv->kind != FWUPD_REMOTE_KIND_UNKNOWN) {
+ g_variant_builder_add(&builder, "{sv}", "Type", g_variant_new_uint32(priv->kind));
+ }
+ if (priv->keyring_kind != FWUPD_KEYRING_KIND_UNKNOWN) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "Keyring",
+ g_variant_new_uint32(priv->keyring_kind));
+ }
+ if (priv->mtime != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "ModificationTime",
+ g_variant_new_uint64(priv->mtime));
+ }
+ if (priv->filename_cache != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "FilenameCache",
+ g_variant_new_string(priv->filename_cache));
+ }
+ if (priv->filename_source != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "FilenameSource",
+ g_variant_new_string(priv->filename_source));
+ }
+ if (priv->remotes_dir != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "RemotesDir",
+ g_variant_new_string(priv->remotes_dir));
+ }
+ 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));
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "AutomaticReports",
+ g_variant_new_boolean(priv->automatic_reports));
+ g_variant_builder_add(&builder,
+ "{sv}",
+ "AutomaticSecurityReports",
+ g_variant_new_boolean(priv->automatic_security_reports));
+ return g_variant_new("a{sv}", &builder);
+}
+
+static void
+fwupd_remote_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FwupdRemote *self = FWUPD_REMOTE(obj);
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ switch (prop_id) {
+ 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;
+ case PROP_AUTOMATIC_REPORTS:
+ g_value_set_boolean(value, priv->automatic_reports);
+ break;
+ case PROP_AUTOMATIC_SECURITY_REPORTS:
+ g_value_set_boolean(value, priv->automatic_security_reports);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_remote_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FwupdRemote *self = FWUPD_REMOTE(obj);
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ switch (prop_id) {
+ 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;
+ case PROP_AUTOMATIC_REPORTS:
+ priv->automatic_reports = g_value_get_boolean(value);
+ break;
+ case PROP_AUTOMATIC_SECURITY_REPORTS:
+ priv->automatic_security_reports = g_value_get_boolean(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_remote_class_init(FwupdRemoteClass *klass)
+{
+ GParamSpec *pspec;
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fwupd_remote_finalize;
+ object_class->get_property = fwupd_remote_get_property;
+ object_class->set_property = fwupd_remote_set_property;
+
+ /**
+ * FwupdRemote:id:
+ *
+ * The remote ID.
+ *
+ * Since: 0.9.3
+ */
+ pspec =
+ g_param_spec_string("id", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_ID, pspec);
+
+ /**
+ * FwupdRemote:enabled:
+ *
+ * If the remote is enabled and should be used.
+ *
+ * Since: 0.9.3
+ */
+ pspec = g_param_spec_boolean("enabled",
+ NULL,
+ NULL,
+ 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);
+
+ /**
+ * FwupdRemote:automatic-reports:
+ *
+ * The behavior for auto-uploading reports.
+ *
+ * Since: 1.3.3
+ */
+ pspec = g_param_spec_boolean("automatic-reports",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_AUTOMATIC_REPORTS, pspec);
+
+ /**
+ * FwupdRemote:automatic-security-reports:
+ *
+ * The behavior for auto-uploading security reports.
+ *
+ * Since: 1.5.0
+ */
+ pspec = g_param_spec_boolean("automatic-security-reports",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_AUTOMATIC_SECURITY_REPORTS, pspec);
+}
+
+static void
+fwupd_remote_init(FwupdRemote *self)
+{
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+ priv->keyring_kind = FWUPD_KEYRING_KIND_JCAT;
+}
+
+static void
+fwupd_remote_finalize(GObject *obj)
+{
+ FwupdRemote *self = FWUPD_REMOTE(obj);
+ FwupdRemotePrivate *priv = GET_PRIVATE(self);
+
+ g_free(priv->id);
+ g_free(priv->metadata_uri);
+ g_free(priv->metadata_uri_sig);
+ g_free(priv->firmware_base_uri);
+ g_free(priv->report_uri);
+ g_free(priv->security_report_uri);
+ g_free(priv->username);
+ g_free(priv->password);
+ g_free(priv->title);
+ g_free(priv->agreement);
+ g_free(priv->remotes_dir);
+ g_free(priv->checksum);
+ g_free(priv->filename_cache);
+ g_free(priv->filename_cache_sig);
+ g_free(priv->filename_source);
+ g_strfreev(priv->order_after);
+ g_strfreev(priv->order_before);
+
+ G_OBJECT_CLASS(fwupd_remote_parent_class)->finalize(obj);
+}
+
+/**
+ * fwupd_remote_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new remote using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdRemote, or %NULL if @value was invalid
+ *
+ * Since: 1.0.0
+ **/
+FwupdRemote *
+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(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ rel = fwupd_remote_new();
+ 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(value, "a{sv}", &iter);
+ fwupd_remote_set_from_variant_iter(rel, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return rel;
+}
+
+/**
+ * fwupd_remote_array_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates an array of new devices using serialized 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;
+
+ g_return_val_if_fail(value != NULL, 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.
+ *
+ * Returns: a new #FwupdRemote
+ *
+ * Since: 0.9.3
+ **/
+FwupdRemote *
+fwupd_remote_new(void)
+{
+ FwupdRemote *self;
+ self = g_object_new(FWUPD_TYPE_REMOTE, NULL);
+ return FWUPD_REMOTE(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-remote.h b/fwupd-1.8.6/libfwupd/fwupd-remote.h
new file mode 100644
index 0000000000000000000000000000000000000000..c8551d5cdf2dbdbf09c28761d5b1bd68b467561d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-remote.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fwupd-enums.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_REMOTE (fwupd_remote_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdRemote, fwupd_remote, FWUPD, REMOTE, GObject)
+
+struct _FwupdRemoteClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ 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;
+
+FwupdRemoteKind
+fwupd_remote_kind_from_string(const gchar *kind);
+const gchar *
+fwupd_remote_kind_to_string(FwupdRemoteKind kind);
+
+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_remotes_dir(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);
+const gchar *
+fwupd_remote_get_filename_cache(FwupdRemote *self);
+const gchar *
+fwupd_remote_get_filename_cache_sig(FwupdRemote *self);
+const gchar *
+fwupd_remote_get_filename_source(FwupdRemote *self);
+const gchar *
+fwupd_remote_get_firmware_base_uri(FwupdRemote *self);
+const gchar *
+fwupd_remote_get_report_uri(FwupdRemote *self);
+const gchar *
+fwupd_remote_get_security_report_uri(FwupdRemote *self);
+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);
+gboolean
+fwupd_remote_get_automatic_reports(FwupdRemote *self);
+gboolean
+fwupd_remote_get_automatic_security_reports(FwupdRemote *self);
+gint
+fwupd_remote_get_priority(FwupdRemote *self);
+guint64
+fwupd_remote_get_age(FwupdRemote *self);
+FwupdRemoteKind
+fwupd_remote_get_kind(FwupdRemote *self);
+FwupdKeyringKind
+fwupd_remote_get_keyring_kind(FwupdRemote *self);
+gchar *
+fwupd_remote_build_firmware_uri(FwupdRemote *self,
+ const gchar *url,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_remote_load_signature(FwupdRemote *self,
+ const gchar *filename,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fwupd_remote_load_signature_bytes(FwupdRemote *self,
+ GBytes *bytes,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+FwupdRemote *
+fwupd_remote_from_variant(GVariant *value);
+GPtrArray *
+fwupd_remote_array_from_variant(GVariant *value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-request-private.h b/fwupd-1.8.6/libfwupd/fwupd-request-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..cd112d37673e7c475933613e94f3dbc6cd413944
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-request-private.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fwupd-request.h"
+
+G_BEGIN_DECLS
+
+GVariant *
+fwupd_request_to_variant(FwupdRequest *self);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-request.c b/fwupd-1.8.6/libfwupd/fwupd-request.c
new file mode 100644
index 0000000000000000000000000000000000000000..a363f32b423e1994e731c1ca6b318a87e8189eba
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-request.c
@@ -0,0 +1,828 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fwupd-common-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-request-private.h"
+
+/**
+ * FwupdRequest:
+ *
+ * A user request from the device.
+ *
+ * See also: [class@FwupdDevice]
+ */
+
+typedef struct {
+ gchar *id;
+ FwupdRequestKind kind;
+ FwupdRequestFlags flags;
+ guint64 created;
+ gchar *device_id;
+ gchar *message;
+ gchar *image;
+} FwupdRequestPrivate;
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_KIND,
+ PROP_FLAGS,
+ PROP_MESSAGE,
+ PROP_IMAGE,
+ PROP_DEVICE_ID,
+ PROP_LAST
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdRequest, fwupd_request, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_request_get_instance_private(o))
+
+/**
+ * fwupd_request_kind_to_string:
+ * @kind: a update message kind, e.g. %FWUPD_REQUEST_KIND_IMMEDIATE
+ *
+ * Converts an enumerated update message kind to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.6.2
+ **/
+const gchar *
+fwupd_request_kind_to_string(FwupdRequestKind kind)
+{
+ if (kind == FWUPD_REQUEST_KIND_UNKNOWN)
+ return "unknown";
+ if (kind == FWUPD_REQUEST_KIND_POST)
+ return "post";
+ if (kind == FWUPD_REQUEST_KIND_IMMEDIATE)
+ return "immediate";
+ return NULL;
+}
+
+/**
+ * fwupd_request_kind_from_string:
+ * @kind: (nullable): a string, e.g. `immediate`
+ *
+ * Converts a string to an enumerated update message kind.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.6.2
+ **/
+FwupdRequestKind
+fwupd_request_kind_from_string(const gchar *kind)
+{
+ if (g_strcmp0(kind, "unknown") == 0)
+ return FWUPD_REQUEST_KIND_UNKNOWN;
+ if (g_strcmp0(kind, "post") == 0)
+ return FWUPD_REQUEST_KIND_POST;
+ if (g_strcmp0(kind, "immediate") == 0)
+ return FWUPD_REQUEST_KIND_IMMEDIATE;
+ return FWUPD_REQUEST_KIND_LAST;
+}
+
+/**
+ * fwupd_request_flag_to_string:
+ * @flag: a request flag, e.g. %FWUPD_REQUEST_FLAG_NONE
+ *
+ * Converts an enumerated request flag to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.8.6
+ **/
+const gchar *
+fwupd_request_flag_to_string(FwupdRequestFlags flag)
+{
+ if (flag == FWUPD_REQUEST_FLAG_NONE)
+ return "none";
+ if (flag == FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE)
+ return "allow-generic-message";
+ if (flag == FWUPD_REQUEST_FLAG_ALLOW_GENERIC_IMAGE)
+ return "allow-generic-image";
+ return NULL;
+}
+
+/**
+ * fwupd_request_flag_from_string:
+ * @flag: (nullable): a string, e.g. `none`
+ *
+ * Converts a string to an enumerated request flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.8.6
+ **/
+FwupdRequestFlags
+fwupd_request_flag_from_string(const gchar *flag)
+{
+ if (g_strcmp0(flag, "allow-generic-message") == 0)
+ return FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE;
+ if (g_strcmp0(flag, "allow-generic-image") == 0)
+ return FWUPD_REQUEST_FLAG_ALLOW_GENERIC_IMAGE;
+ return FWUPD_REQUEST_FLAG_NONE;
+}
+
+/**
+ * fwupd_request_get_id:
+ * @self: a #FwupdRequest
+ *
+ * Gets the ID.
+ *
+ * Returns: the ID, or %NULL if unset
+ *
+ * Since: 1.6.2
+ **/
+const gchar *
+fwupd_request_get_id(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), NULL);
+ return priv->id;
+}
+
+/**
+ * fwupd_request_set_id:
+ * @self: a #FwupdRequest
+ * @id: (nullable): the request ID, e.g. `USB:foo`
+ *
+ * Sets the ID.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_request_set_id(FwupdRequest *self, const gchar *id)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->id, id) == 0)
+ return;
+
+ g_free(priv->id);
+ priv->id = g_strdup(id);
+}
+
+/**
+ * fwupd_request_get_device_id:
+ * @self: a #FwupdRequest
+ *
+ * Gets the device_id that created the request.
+ *
+ * Returns: the device_id, or %NULL if unset
+ *
+ * Since: 1.6.2
+ **/
+const gchar *
+fwupd_request_get_device_id(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), NULL);
+ return priv->device_id;
+}
+
+/**
+ * fwupd_request_set_device_id:
+ * @self: a #FwupdRequest
+ * @device_id: (nullable): the device_id, e.g. `colorhug`
+ *
+ * Sets the device_id that created the request.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_request_set_device_id(FwupdRequest *self, const gchar *device_id)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->device_id, device_id) == 0)
+ return;
+
+ g_free(priv->device_id);
+ priv->device_id = g_strdup(device_id);
+}
+
+/**
+ * fwupd_request_get_created:
+ * @self: a #FwupdRequest
+ *
+ * Gets when the request was created.
+ *
+ * Returns: the UNIX time, or 0 if unset
+ *
+ * Since: 1.6.2
+ **/
+guint64
+fwupd_request_get_created(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), 0);
+ return priv->created;
+}
+
+/**
+ * fwupd_request_set_created:
+ * @self: a #FwupdRequest
+ * @created: the UNIX time
+ *
+ * Sets when the request was created.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_request_set_created(FwupdRequest *self, guint64 created)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+ priv->created = created;
+}
+
+/**
+ * fwupd_request_to_variant:
+ * @self: a #FwupdRequest
+ *
+ * Serialize the request data.
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.6.2
+ **/
+GVariant *
+fwupd_request_to_variant(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), NULL);
+
+ /* create an array with all the metadata in */
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ if (priv->id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_APPSTREAM_ID,
+ g_variant_new_string(priv->id));
+ }
+ if (priv->created > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CREATED,
+ g_variant_new_uint64(priv->created));
+ }
+ if (priv->device_id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_DEVICE_ID,
+ g_variant_new_string(priv->device_id));
+ }
+ if (priv->message != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_UPDATE_MESSAGE,
+ g_variant_new_string(priv->message));
+ }
+ if (priv->image != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_UPDATE_IMAGE,
+ g_variant_new_string(priv->image));
+ }
+ if (priv->kind != FWUPD_REQUEST_KIND_UNKNOWN) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_REQUEST_KIND,
+ g_variant_new_uint32(priv->kind));
+ }
+ if (priv->flags != FWUPD_REQUEST_FLAG_NONE) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_FLAGS,
+ g_variant_new_uint64(priv->flags));
+ }
+ return g_variant_new("a{sv}", &builder);
+}
+
+static void
+fwupd_request_from_key_value(FwupdRequest *self, const gchar *key, GVariant *value)
+{
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) {
+ fwupd_request_set_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
+ fwupd_request_set_created(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DEVICE_ID) == 0) {
+ fwupd_request_set_device_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) {
+ fwupd_request_set_message(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) {
+ fwupd_request_set_image(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_REQUEST_KIND) == 0) {
+ fwupd_request_set_kind(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FLAGS) == 0) {
+ fwupd_request_set_flags(self, g_variant_get_uint64(value));
+ return;
+ }
+}
+
+/**
+ * fwupd_request_get_message:
+ * @self: a #FwupdRequest
+ *
+ * Gets the update message.
+ *
+ * Returns: the update message, or %NULL if unset
+ *
+ * Since: 1.6.2
+ **/
+const gchar *
+fwupd_request_get_message(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), NULL);
+ return priv->message;
+}
+
+/**
+ * fwupd_request_set_message:
+ * @self: a #FwupdRequest
+ * @message: (nullable): the update message string
+ *
+ * Sets the update message.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_request_set_message(FwupdRequest *self, const gchar *message)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->message, message) == 0)
+ return;
+
+ g_free(priv->message);
+ priv->message = g_strdup(message);
+ g_object_notify(G_OBJECT(self), "message");
+}
+
+/**
+ * fwupd_request_get_image:
+ * @self: a #FwupdRequest
+ *
+ * Gets the update image.
+ *
+ * Returns: the update image URL, or %NULL if unset
+ *
+ * Since: 1.6.2
+ **/
+const gchar *
+fwupd_request_get_image(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), NULL);
+ return priv->image;
+}
+
+/**
+ * fwupd_request_set_image:
+ * @self: a #FwupdRequest
+ * @image: (nullable): the update image URL
+ *
+ * Sets the update image.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_request_set_image(FwupdRequest *self, const gchar *image)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->image, image) == 0)
+ return;
+
+ g_free(priv->image);
+ priv->image = g_strdup(image);
+ g_object_notify(G_OBJECT(self), "image");
+}
+
+/**
+ * fwupd_request_get_kind:
+ * @self: a #FwupdRequest
+ *
+ * Returns what the request is currently doing.
+ *
+ * Returns: the kind value, e.g. %FWUPD_STATUS_REQUEST_WRITE
+ *
+ * Since: 1.6.2
+ **/
+FwupdRequestKind
+fwupd_request_get_kind(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), 0);
+ return priv->kind;
+}
+
+/**
+ * fwupd_request_set_kind:
+ * @self: a #FwupdRequest
+ * @kind: the kind value, e.g. %FWUPD_STATUS_REQUEST_WRITE
+ *
+ * Sets what the request is currently doing.
+ *
+ * Since: 1.6.2
+ **/
+void
+fwupd_request_set_kind(FwupdRequest *self, FwupdRequestKind kind)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+ if (priv->kind == kind)
+ return;
+ priv->kind = kind;
+ g_object_notify(G_OBJECT(self), "kind");
+}
+
+/**
+ * fwupd_request_get_flags:
+ * @self: a #FwupdRequest
+ *
+ * Gets the request flags.
+ *
+ * Returns: request flags, or 0 if unset
+ *
+ * Since: 1.8.6
+ **/
+FwupdRequestFlags
+fwupd_request_get_flags(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), 0);
+ return priv->flags;
+}
+
+/**
+ * fwupd_request_set_flags:
+ * @self: a #FwupdRequest
+ * @flags: request flags, e.g. %FWUPD_REQUEST_FLAG_NONE
+ *
+ * Sets the request flags.
+ *
+ * Since: 1.8.6
+ **/
+void
+fwupd_request_set_flags(FwupdRequest *self, FwupdRequestFlags flags)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+
+ /* not changed */
+ if (priv->flags == flags)
+ return;
+
+ priv->flags = flags;
+ g_object_notify(G_OBJECT(self), "flags");
+}
+
+/**
+ * fwupd_request_add_flag:
+ * @self: a #FwupdRequest
+ * @flag: the #FwupdRequestFlags
+ *
+ * Adds a specific flag to the request.
+ *
+ * Since: 1.8.6
+ **/
+void
+fwupd_request_add_flag(FwupdRequest *self, FwupdRequestFlags flag)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+ priv->flags |= flag;
+}
+
+/**
+ * fwupd_request_remove_flag:
+ * @self: a #FwupdRequest
+ * @flag: the #FwupdRequestFlags
+ *
+ * Removes a specific flag from the request.
+ *
+ * Since: 1.8.6
+ **/
+void
+fwupd_request_remove_flag(FwupdRequest *self, FwupdRequestFlags flag)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_REQUEST(self));
+ priv->flags &= ~flag;
+}
+
+/**
+ * fwupd_request_has_flag:
+ * @self: a #FwupdRequest
+ * @flag: the #FwupdRequestFlags
+ *
+ * Finds if the request has a specific flag.
+ *
+ * Returns: %TRUE if the flag is set
+ *
+ * Since: 1.8.6
+ **/
+gboolean
+fwupd_request_has_flag(FwupdRequest *self, FwupdRequestFlags flag)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), FALSE);
+ return (priv->flags & flag) > 0;
+}
+
+/**
+ * fwupd_request_to_string:
+ * @self: a #FwupdRequest
+ *
+ * Builds a text representation of the object.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 1.6.2
+ **/
+gchar *
+fwupd_request_to_string(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GString) str = g_string_new(NULL);
+
+ g_return_val_if_fail(FWUPD_IS_REQUEST(self), NULL);
+
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->id);
+ if (priv->kind != FWUPD_REQUEST_KIND_UNKNOWN) {
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_REQUEST_KIND,
+ fwupd_request_kind_to_string(priv->kind));
+ }
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_FLAGS, fwupd_request_flag_to_string(priv->flags));
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_DEVICE_ID, priv->device_id);
+ fwupd_pad_kv_unx(str, FWUPD_RESULT_KEY_CREATED, priv->created);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->message);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->image);
+ return g_string_free(g_steal_pointer(&str), FALSE);
+}
+
+static void
+fwupd_request_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FwupdRequest *self = FWUPD_REQUEST(object);
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_ID:
+ g_value_set_string(value, priv->id);
+ break;
+ case PROP_MESSAGE:
+ g_value_set_string(value, priv->message);
+ break;
+ case PROP_IMAGE:
+ g_value_set_string(value, priv->image);
+ break;
+ case PROP_DEVICE_ID:
+ g_value_set_string(value, priv->device_id);
+ break;
+ case PROP_KIND:
+ g_value_set_uint(value, priv->kind);
+ break;
+ case PROP_FLAGS:
+ g_value_set_uint64(value, priv->flags);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_request_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FwupdRequest *self = FWUPD_REQUEST(object);
+ switch (prop_id) {
+ case PROP_ID:
+ fwupd_request_set_id(self, g_value_get_string(value));
+ break;
+ case PROP_MESSAGE:
+ fwupd_request_set_message(self, g_value_get_string(value));
+ break;
+ case PROP_IMAGE:
+ fwupd_request_set_image(self, g_value_get_string(value));
+ break;
+ case PROP_DEVICE_ID:
+ fwupd_request_set_device_id(self, g_value_get_string(value));
+ break;
+ case PROP_KIND:
+ fwupd_request_set_kind(self, g_value_get_uint(value));
+ break;
+ case PROP_FLAGS:
+ fwupd_request_set_flags(self, g_value_get_uint64(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fwupd_request_finalize(GObject *object)
+{
+ FwupdRequest *self = FWUPD_REQUEST(object);
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+
+ g_free(priv->id);
+ g_free(priv->device_id);
+ g_free(priv->message);
+ g_free(priv->image);
+
+ G_OBJECT_CLASS(fwupd_request_parent_class)->finalize(object);
+}
+
+static void
+fwupd_request_init(FwupdRequest *self)
+{
+ FwupdRequestPrivate *priv = GET_PRIVATE(self);
+ priv->created = g_get_real_time() / G_USEC_PER_SEC;
+}
+
+static void
+fwupd_request_class_init(FwupdRequestClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
+
+ object_class->finalize = fwupd_request_finalize;
+ object_class->get_property = fwupd_request_get_property;
+ object_class->set_property = fwupd_request_set_property;
+
+ /**
+ * FwupdRequest:id:
+ *
+ * The request identifier.
+ *
+ * Since: 1.6.2
+ */
+ pspec =
+ g_param_spec_string("id", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_ID, pspec);
+
+ /**
+ * FwupdRequest:kind:
+ *
+ * The kind of the request.
+ *
+ * Since: 1.6.2
+ */
+ pspec = g_param_spec_uint("kind",
+ NULL,
+ NULL,
+ FWUPD_REQUEST_KIND_UNKNOWN,
+ FWUPD_REQUEST_KIND_LAST,
+ FWUPD_REQUEST_KIND_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_KIND, pspec);
+
+ /**
+ * FwupdRequest:flags:
+ *
+ * The flags for the request.
+ *
+ * Since: 1.8.6
+ */
+ pspec = g_param_spec_uint64("flags",
+ NULL,
+ NULL,
+ FWUPD_REQUEST_FLAG_NONE,
+ FWUPD_REQUEST_FLAG_UNKNOWN,
+ FWUPD_REQUEST_FLAG_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_FLAGS, pspec);
+
+ /**
+ * FwupdRequest:message:
+ *
+ * The message text in the request.
+ *
+ * Since: 1.6.2
+ */
+ pspec = g_param_spec_string("message",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_MESSAGE, pspec);
+
+ /**
+ * FwupdRequest:image:
+ *
+ * The image link for the request.
+ *
+ * Since: 1.6.2
+ */
+ pspec =
+ g_param_spec_string("image", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_IMAGE, pspec);
+
+ /**
+ * FwupdRequest:device-id:
+ *
+ * The device ID for the request.
+ *
+ * Since: 1.8.2
+ */
+ pspec = g_param_spec_string("device-id",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_DEVICE_ID, pspec);
+}
+
+static void
+fwupd_request_set_from_variant_iter(FwupdRequest *self, GVariantIter *iter)
+{
+ GVariant *value;
+ const gchar *key;
+ while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
+ fwupd_request_from_key_value(self, key, value);
+ g_variant_unref(value);
+ }
+}
+
+/**
+ * fwupd_request_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new request using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdRequest, or %NULL if @value was invalid
+ *
+ * Since: 1.6.2
+ **/
+FwupdRequest *
+fwupd_request_from_variant(GVariant *value)
+{
+ FwupdRequest *self = NULL;
+ const gchar *type_string;
+ g_autoptr(GVariantIter) iter = NULL;
+
+ g_return_val_if_fail(value != NULL, NULL);
+
+ /* format from GetDetails */
+ type_string = g_variant_get_type_string(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ self = fwupd_request_new();
+ g_variant_get(value, "(a{sv})", &iter);
+ fwupd_request_set_from_variant_iter(self, iter);
+ } else if (g_strcmp0(type_string, "a{sv}") == 0) {
+ self = fwupd_request_new();
+ g_variant_get(value, "a{sv}", &iter);
+ fwupd_request_set_from_variant_iter(self, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return self;
+}
+
+/**
+ * fwupd_request_new:
+ *
+ * Creates a new request.
+ *
+ * Returns: a new #FwupdRequest
+ *
+ * Since: 1.6.2
+ **/
+FwupdRequest *
+fwupd_request_new(void)
+{
+ FwupdRequest *self;
+ self = g_object_new(FWUPD_TYPE_REQUEST, NULL);
+ return FWUPD_REQUEST(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-request.h b/fwupd-1.8.6/libfwupd/fwupd-request.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb425dd0956513a78363c433a76492e550372240
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-request.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_REQUEST (fwupd_request_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdRequest, fwupd_request, FWUPD, REQUEST, GObject)
+
+struct _FwupdRequestClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ void (*_fwupd_reserved7)(void);
+};
+
+/**
+ * FwupdRequestKind:
+ * @FWUPD_REQUEST_KIND_UNKNOWN: Unknown kind
+ * @FWUPD_REQUEST_KIND_POST: After the update
+ * @FWUPD_REQUEST_KIND_IMMEDIATE: Immediately
+ *
+ * The kind of request we are asking of the user.
+ **/
+typedef enum {
+ FWUPD_REQUEST_KIND_UNKNOWN, /* Since: 1.6.2 */
+ FWUPD_REQUEST_KIND_POST, /* Since: 1.6.2 */
+ FWUPD_REQUEST_KIND_IMMEDIATE, /* Since: 1.6.2 */
+ /*< private >*/
+ FWUPD_REQUEST_KIND_LAST
+} FwupdRequestKind;
+
+/**
+ * FWUPD_REQUEST_ID_REMOVE_REPLUG:
+ *
+ * The user needs to remove and reinsert the device to complete the update, e.g.
+ * "The update will continue when the device USB cable has been unplugged and then re-inserted."
+ *
+ * Since 1.6.2
+ */
+#define FWUPD_REQUEST_ID_REMOVE_REPLUG "org.freedesktop.fwupd.request.remove-replug"
+
+/**
+ * FWUPD_REQUEST_ID_PRESS_UNLOCK:
+ *
+ * The user needs to press unlock on the device to continue, e.g.
+ * "Press unlock on the device to continue the update process."
+ *
+ * Since 1.6.2
+ */
+#define FWUPD_REQUEST_ID_PRESS_UNLOCK "org.freedesktop.fwupd.request.press-unlock"
+
+/**
+ * FWUPD_REQUEST_ID_REMOVE_USB_CABLE:
+ *
+ * The user needs to remove the device to complete the update, e.g.
+ * "The update will continue when the device USB cable has been unplugged."
+ *
+ * Since 1.8.6
+ */
+#define FWUPD_REQUEST_ID_REMOVE_USB_CABLE "org.freedesktop.fwupd.request.remove-usb-cable"
+
+/**
+ * FWUPD_REQUEST_ID_DO_NOT_POWER_OFF:
+ *
+ * Show the user a message not to unplug the machine from the AC power, e.g.
+ * "Do not turn off your computer or remove the AC adaptor until you are sure the update has
+ * completed."
+ *
+ * Since 1.8.6
+ */
+#define FWUPD_REQUEST_ID_DO_NOT_POWER_OFF "org.freedesktop.fwupd.request.do-not-power-off"
+
+/**
+ * FWUPD_REQUEST_FLAG_NONE:
+ *
+ * No flags are set.
+ *
+ * Since: 1.8.6
+ */
+#define FWUPD_REQUEST_FLAG_NONE (0u)
+
+/**
+ * FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE:
+ *
+ * Use a generic (translated) request message.
+ *
+ * Since: 1.8.6
+ */
+#define FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE (1u << 0)
+
+/**
+ * FWUPD_REQUEST_FLAG_ALLOW_GENERIC_IMAGE:
+ *
+ * Use a generic (translated) request image.
+ *
+ * Since: 1.8.6
+ */
+#define FWUPD_REQUEST_FLAG_ALLOW_GENERIC_IMAGE (1u << 1)
+
+/**
+ * FWUPD_REQUEST_FLAG_UNKNOWN:
+ *
+ * The request flag is unknown, typically caused by using mismatched client and daemon.
+ *
+ * Since: 1.8.6
+ */
+#define FWUPD_REQUEST_FLAG_UNKNOWN G_MAXUINT64
+
+/**
+ * FwupdRequestFlags:
+ *
+ * Flags used to represent request attributes
+ */
+typedef guint64 FwupdRequestFlags;
+
+const gchar *
+fwupd_request_kind_to_string(FwupdRequestKind kind);
+FwupdRequestKind
+fwupd_request_kind_from_string(const gchar *kind);
+
+const gchar *
+fwupd_request_flag_to_string(FwupdRequestFlags flag);
+FwupdRequestFlags
+fwupd_request_flag_from_string(const gchar *flag);
+
+FwupdRequest *
+fwupd_request_new(void);
+gchar *
+fwupd_request_to_string(FwupdRequest *self);
+
+const gchar *
+fwupd_request_get_id(FwupdRequest *self);
+void
+fwupd_request_set_id(FwupdRequest *self, const gchar *id);
+guint64
+fwupd_request_get_created(FwupdRequest *self);
+void
+fwupd_request_set_created(FwupdRequest *self, guint64 created);
+const gchar *
+fwupd_request_get_device_id(FwupdRequest *self);
+void
+fwupd_request_set_device_id(FwupdRequest *self, const gchar *device_id);
+const gchar *
+fwupd_request_get_message(FwupdRequest *self);
+void
+fwupd_request_set_message(FwupdRequest *self, const gchar *message);
+const gchar *
+fwupd_request_get_image(FwupdRequest *self);
+void
+fwupd_request_set_image(FwupdRequest *self, const gchar *image);
+FwupdRequestKind
+fwupd_request_get_kind(FwupdRequest *self);
+void
+fwupd_request_set_kind(FwupdRequest *self, FwupdRequestKind kind);
+
+FwupdRequestFlags
+fwupd_request_get_flags(FwupdRequest *self);
+void
+fwupd_request_set_flags(FwupdRequest *self, FwupdRequestFlags flags);
+void
+fwupd_request_add_flag(FwupdRequest *self, FwupdRequestFlags flag);
+void
+fwupd_request_remove_flag(FwupdRequest *self, FwupdRequestFlags flag);
+gboolean
+fwupd_request_has_flag(FwupdRequest *self, FwupdRequestFlags flag);
+
+FwupdRequest *
+fwupd_request_from_variant(GVariant *value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-security-attr-private.h b/fwupd-1.8.6/libfwupd/fwupd-security-attr-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..f6025beace088b23a8185249f6689c19ec3073a9
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-security-attr-private.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-security-attr.h"
+
+G_BEGIN_DECLS
+
+/**
+ * FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION:
+ *
+ * Host Security ID attribute for Pre-boot DMA protection
+ *
+ * This was previously known as org.fwupd.hsi.AcpiDmar for Intel from 1.5.0+.
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION "org.fwupd.hsi.PrebootDma"
+/**
+ * FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM:
+ *
+ * Host Security ID attribute indicating encrypted RAM available
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam"
+/**
+ * FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION:
+ *
+ * Host Security ID attribute for attesation
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation"
+/**
+ * FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS:
+ *
+ * Host Security ID attribute for plugins
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins"
+/**
+ * FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES:
+ *
+ * Host Security ID attribute for updates
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED:
+ *
+ * Host Security ID attribute for Intel Bootguard enabled
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED:
+ *
+ * Host Security ID attribute for Intel Bootguard verified
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM:
+ *
+ * Host Security ID attribute for Intel Bootguard ACM
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY:
+ *
+ * Host Security ID attribute for Intel Bootguard policy
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP:
+ *
+ * Host Security ID attribute for Intel Bootguard OTP fuse
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED:
+ *
+ * Host Security ID attribute for Intel CET enabled
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE:
+ *
+ * Host Security ID attribute for Intel CET active
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active"
+/**
+ * FWUPD_SECURITY_ATTR_ID_INTEL_SMAP:
+ *
+ * Host Security ID attribute for Intel SMAP
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap"
+/**
+ * FWUPD_SECURITY_ATTR_ID_IOMMU:
+ *
+ * Host Security ID attribute for IOMMU
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu"
+/**
+ * FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN:
+ *
+ * Host Security ID attribute for kernel lockdown
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown"
+/**
+ * FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP:
+ *
+ * Host Security ID attribute for kernel swap
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap"
+/**
+ * FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED:
+ *
+ * Host Security ID attribute for kernel taint
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted"
+/**
+ * FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE:
+ *
+ * Host Security ID attribute for Intel ME manufacturing mode
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode"
+/**
+ * FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP:
+ *
+ * Host Security ID attribute for Intel ME override strap
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap"
+/**
+ * FWUPD_SECURITY_ATTR_ID_MEI_VERSION:
+ *
+ * Host Security ID attribute for Intel ME version
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE:
+ *
+ * Host Security ID attribute for Intel SPI BIOSWE configuration
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SPI_BLE:
+ *
+ * Host Security ID attribute for Intel SPI BLE configuration
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP:
+ *
+ * Host Security ID attribute for Intel SPI SMM BWP
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR:
+ *
+ * Host Security ID attribute for Intel SPI descriptor
+ *
+ * Since: 1.6.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR "org.fwupd.hsi.Spi.Descriptor"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE:
+ *
+ * Host Security ID attribute for Suspend to Idle
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM:
+ *
+ * Host Security ID attribute for Suspend to RAM
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam"
+/**
+ * FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR:
+ *
+ * Host Security ID attribute for empty PCR
+ *
+ * Since: 1.7.2
+ **/
+#define FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR "org.fwupd.hsi.Tpm.EmptyPcr"
+/**
+ * FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0:
+ *
+ * Host Security ID attribute for TPM PCR0 reconstruction
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0"
+/**
+ * FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20:
+ *
+ * Host Security ID attribute for TPM 2.0
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20"
+/**
+ * FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT:
+ *
+ * Host Security ID attribute for UEFI secure boot
+ *
+ * Since: 1.5.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot"
+/**
+ * FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED:
+ *
+ * Host Security ID attribute for parts with debugging capabilities enabled
+ *
+ * This was previously known as org.fwupd.hsi.PlatformDebugEnabled for Intel 1.5.0+
+ * It was renamed for all vendor support in 1.8.0. *
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED "org.fwupd.hsi.PlatformDebugEnabled"
+/**
+ * FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED:
+ *
+ * Host Security ID attribute for fused parts
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED "org.fwupd.hsi.PlatformFused"
+/**
+ * FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED:
+ *
+ * Host Security ID attribute for parts locked from debugging
+ *
+ * This was previously known as org.fwupd.hsi.IntelDci.Locked for Intel 1.5.0+
+ * It was renamed for all vendor support in 1.8.0.
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED "org.fwupd.hsi.PlatformDebugLocked"
+/**
+ * FWUPD_SECURITY_ATTR_ID_UEFI_PK:
+ *
+ * Host Security ID attribute for UEFI PK
+ *
+ * Since: 1.5.5
+ **/
+#define FWUPD_SECURITY_ATTR_ID_UEFI_PK "org.fwupd.hsi.Uefi.Pk"
+/**
+ * FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU
+ *
+ * Host Security ID attribute for Supported CPU
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU "org.fwupd.hsi.SupportedCpu"
+/**
+ * FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION
+ *
+ * Host Security ID attribute for Rollback protection of AMD platform
+ * firmware
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION "org.fwupd.hsi.Amd.RollbackProtection"
+/**
+ * FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION
+ *
+ * Host Security ID attribute for SPI Write protection
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION "org.fwupd.hsi.Amd.SpiWriteProtection"
+/**
+ * FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION
+ *
+ * Host Security ID attribute for SPI replay protection
+ *
+ * Since: 1.8.0
+ **/
+#define FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION "org.fwupd.hsi.Amd.SpiReplayProtection"
+/**
+ * FWUPD_SECURITY_ATTR_ID_HOST_EMULATION
+ *
+ * Host Security ID attribute for host emulation
+ *
+ * Since: 1.8.3
+ **/
+#define FWUPD_SECURITY_ATTR_ID_HOST_EMULATION "org.fwupd.hsi.HostEmulation"
+
+GVariant *
+fwupd_security_attr_to_variant(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_to_json(FwupdSecurityAttr *self, JsonBuilder *builder);
+gboolean
+fwupd_security_attr_from_json(FwupdSecurityAttr *self, JsonNode *json_node, GError **error);
+FwupdSecurityAttr *
+fwupd_security_attr_copy(FwupdSecurityAttr *self);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-security-attr.c b/fwupd-1.8.6/libfwupd/fwupd-security-attr.c
new file mode 100644
index 0000000000000000000000000000000000000000..52c235223cc47c06293a43276b0657574036a1cb
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-security-attr.c
@@ -0,0 +1,1721 @@
+/*
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+#include
+
+#include "fwupd-common-private.h"
+#include "fwupd-enums-private.h"
+#include "fwupd-error.h"
+#include "fwupd-security-attr-private.h"
+
+/**
+ * FwupdSecurityAttr:
+ *
+ * A Host Security ID attribute that represents something that was measured.
+ */
+
+static void
+fwupd_security_attr_finalize(GObject *object);
+
+typedef struct {
+ gchar *appstream_id;
+ GPtrArray *obsoletes;
+ GPtrArray *guids;
+ GHashTable *metadata; /* (nullable) */
+ gchar *name;
+ gchar *title;
+ gchar *description;
+ gchar *plugin;
+ gchar *url;
+ guint64 created;
+ FwupdSecurityAttrLevel level;
+ FwupdSecurityAttrResult result;
+ FwupdSecurityAttrResult result_fallback;
+ FwupdSecurityAttrFlags flags;
+ gchar *bios_setting_id;
+ gchar *bios_setting_target_value;
+ gchar *bios_setting_current_value;
+} FwupdSecurityAttrPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FwupdSecurityAttr, fwupd_security_attr, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fwupd_security_attr_get_instance_private(o))
+
+/**
+ * fwupd_security_attr_flag_to_string:
+ * @flag: security attribute flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_SUCCESS
+ *
+ * Returns the printable string for the flag.
+ *
+ * Returns: string, or %NULL
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_flag_to_string(FwupdSecurityAttrFlags flag)
+{
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_NONE)
+ return "none";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_SUCCESS)
+ return "success";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)
+ return "obsoleted";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA)
+ return "missing-data";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES)
+ return "runtime-updates";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION)
+ return "runtime-attestation";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)
+ return "runtime-issue";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM)
+ return "action-contact-oem";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW)
+ return "action-config-fw";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS)
+ return "action-config-os";
+ return NULL;
+}
+
+/**
+ * fwupd_security_attr_flag_from_string:
+ * @flag: (nullable): a string, e.g. `success`
+ *
+ * Converts a string to an enumerated flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.7.1
+ **/
+FwupdSecurityAttrFlags
+fwupd_security_attr_flag_from_string(const gchar *flag)
+{
+ if (g_strcmp0(flag, "success") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_SUCCESS;
+ if (g_strcmp0(flag, "obsoleted") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_OBSOLETED;
+ if (g_strcmp0(flag, "missing-data") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA;
+ if (g_strcmp0(flag, "runtime-updates") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES;
+ if (g_strcmp0(flag, "runtime-attestation") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION;
+ if (g_strcmp0(flag, "runtime-issue") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE;
+ if (g_strcmp0(flag, "action-contact-oem") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM;
+ if (g_strcmp0(flag, "action-config-fw") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW;
+ if (g_strcmp0(flag, "action-config-os") == 0)
+ return FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS;
+ return FWUPD_SECURITY_ATTR_FLAG_NONE;
+}
+
+/**
+ * fwupd_security_attr_result_to_string:
+ * @result: security attribute result, e.g. %FWUPD_SECURITY_ATTR_RESULT_ENABLED
+ *
+ * Returns the printable string for the result enum.
+ *
+ * Returns: string, or %NULL
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_result_to_string(FwupdSecurityAttrResult result)
+{
+ if (result == FWUPD_SECURITY_ATTR_RESULT_VALID)
+ return "valid";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID)
+ return "not-valid";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED)
+ return "enabled";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED)
+ return "not-enabled";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_LOCKED)
+ return "locked";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED)
+ return "not-locked";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED)
+ return "encrypted";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED)
+ return "not-encrypted";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_TAINTED)
+ return "tainted";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED)
+ return "not-tainted";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_FOUND)
+ return "found";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND)
+ return "not-found";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_SUPPORTED)
+ return "supported";
+ if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED)
+ return "not-supported";
+ return NULL;
+}
+
+/**
+ * fwupd_security_attr_result_from_string:
+ * @result: (nullable): a string, e.g. `not-encrypted`
+ *
+ * Converts a string to an enumerated result.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.7.1
+ **/
+FwupdSecurityAttrResult
+fwupd_security_attr_result_from_string(const gchar *result)
+{
+ if (g_strcmp0(result, "valid") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_VALID;
+ if (g_strcmp0(result, "not-valid") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_VALID;
+ if (g_strcmp0(result, "enabled") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_ENABLED;
+ if (g_strcmp0(result, "not-enabled") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED;
+ if (g_strcmp0(result, "locked") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_LOCKED;
+ if (g_strcmp0(result, "not-locked") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED;
+ if (g_strcmp0(result, "encrypted") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED;
+ if (g_strcmp0(result, "not-encrypted") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED;
+ if (g_strcmp0(result, "tainted") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_TAINTED;
+ if (g_strcmp0(result, "not-tainted") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED;
+ if (g_strcmp0(result, "found") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_FOUND;
+ if (g_strcmp0(result, "not-found") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND;
+ if (g_strcmp0(result, "supported") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_SUPPORTED;
+ if (g_strcmp0(result, "not-supported") == 0)
+ return FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED;
+ return FWUPD_SECURITY_ATTR_RESULT_UNKNOWN;
+}
+
+/**
+ * fwupd_security_attr_flag_to_suffix:
+ * @flag: security attribute flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES
+ *
+ * Returns the string suffix for the flag.
+ *
+ * Returns: string, or %NULL
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_flag_to_suffix(FwupdSecurityAttrFlags flag)
+{
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES)
+ return "U";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION)
+ return "A";
+ if (flag == FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)
+ return "!";
+ return NULL;
+}
+
+/**
+ * fwupd_security_attr_get_bios_setting_id:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the #FwupdBiosSetting that can be used to improve this
+ * #FwupdSecurityAttr.
+ *
+ * Returns: The unique ID used for #FwupdBiosSetting or NULL
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_security_attr_get_bios_setting_id(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->bios_setting_id;
+}
+
+/**
+ * fwupd_security_attr_set_bios_setting_id:
+ * @self: a #FwupdSecurityAttr
+ * @id: Unique identifier used for #FwupdBiosSetting
+ *
+ * Sets the #FwupdBiosSetting that can be used to improve this
+ * #FwupdSecurityAttr.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_security_attr_set_bios_setting_id(FwupdSecurityAttr *self, const gchar *id)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ if (priv->bios_setting_id == id)
+ return;
+ g_free(priv->bios_setting_id);
+ priv->bios_setting_id = g_strdup(id);
+}
+
+/**
+ * fwupd_security_attr_get_obsoletes:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the list of attribute obsoletes. The obsoleted attributes will not
+ * contribute to the calculated HSI value or be visible in command line tools.
+ *
+ * Returns: (element-type utf8) (transfer none): the obsoletes, which may be empty
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_security_attr_get_obsoletes(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->obsoletes;
+}
+
+/**
+ * fwupd_security_attr_add_obsolete:
+ * @self: a #FwupdSecurityAttr
+ * @appstream_id: the appstream_id or plugin name
+ *
+ * Adds an attribute appstream_id to obsolete. The obsoleted attribute will not
+ * contribute to the calculated HSI value or be visible in command line tools.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_add_obsolete(FwupdSecurityAttr *self, const gchar *appstream_id)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ g_return_if_fail(appstream_id != NULL);
+ if (fwupd_security_attr_has_obsolete(self, appstream_id))
+ return;
+ g_ptr_array_add(priv->obsoletes, g_strdup(appstream_id));
+}
+
+/**
+ * fwupd_security_attr_has_obsolete:
+ * @self: a #FwupdSecurityAttr
+ * @appstream_id: the attribute appstream_id
+ *
+ * Finds out if the attribute obsoletes a specific appstream_id.
+ *
+ * Returns: %TRUE if the self matches
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_security_attr_has_obsolete(FwupdSecurityAttr *self, const gchar *appstream_id)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), FALSE);
+ g_return_val_if_fail(appstream_id != NULL, FALSE);
+ for (guint i = 0; i < priv->obsoletes->len; i++) {
+ const gchar *obsolete_tmp = g_ptr_array_index(priv->obsoletes, i);
+ if (g_strcmp0(obsolete_tmp, appstream_id) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_security_attr_get_guids:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the list of attribute GUIDs. The GUID values will not modify the calculated HSI value.
+ *
+ * Returns: (element-type utf8) (transfer none): the GUIDs, which may be empty
+ *
+ * Since: 1.7.0
+ **/
+GPtrArray *
+fwupd_security_attr_get_guids(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->guids;
+}
+
+/**
+ * fwupd_security_attr_add_guid:
+ * @self: a #FwupdSecurityAttr
+ * @guid: the GUID
+ *
+ * Adds a device GUID to the attribute. This indicates the GUID in some way contributed to the
+ * result decided.
+ *
+ * Since: 1.7.0
+ **/
+void
+fwupd_security_attr_add_guid(FwupdSecurityAttr *self, const gchar *guid)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ g_return_if_fail(fwupd_guid_is_valid(guid));
+ if (fwupd_security_attr_has_guid(self, guid))
+ return;
+ g_ptr_array_add(priv->guids, g_strdup(guid));
+}
+
+/**
+ * fwupd_security_attr_add_guids:
+ * @self: a #FwupdSecurityAttr
+ * @guids: (element-type utf8): the GUIDs
+ *
+ * Adds device GUIDs to the attribute. This indicates the GUIDs in some way contributed to the
+ * result decided.
+ *
+ * Since: 1.7.0
+ **/
+void
+fwupd_security_attr_add_guids(FwupdSecurityAttr *self, GPtrArray *guids)
+{
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ g_return_if_fail(guids != NULL);
+ for (guint i = 0; i < guids->len; i++) {
+ const gchar *guid = g_ptr_array_index(guids, i);
+ fwupd_security_attr_add_guid(self, guid);
+ }
+}
+
+/**
+ * fwupd_security_attr_has_guid:
+ * @self: a #FwupdSecurityAttr
+ * @guid: the attribute guid
+ *
+ * Finds out if a specific GUID was added to the attribute.
+ *
+ * Returns: %TRUE if the self matches
+ *
+ * Since: 1.7.0
+ **/
+gboolean
+fwupd_security_attr_has_guid(FwupdSecurityAttr *self, const gchar *guid)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), FALSE);
+ g_return_val_if_fail(guid != NULL, FALSE);
+ for (guint i = 0; i < priv->guids->len; i++) {
+ const gchar *guid_tmp = g_ptr_array_index(priv->guids, i);
+ if (g_strcmp0(guid_tmp, guid) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fwupd_security_attr_get_appstream_id:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the AppStream ID.
+ *
+ * Returns: the AppStream ID, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_get_appstream_id(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->appstream_id;
+}
+
+/**
+ * fwupd_security_attr_set_appstream_id:
+ * @self: a #FwupdSecurityAttr
+ * @appstream_id: (nullable): the AppStream component ID, e.g. `com.intel.BiosGuard`
+ *
+ * Sets the AppStream ID.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_appstream_id(FwupdSecurityAttr *self, const gchar *appstream_id)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->appstream_id, appstream_id) == 0)
+ return;
+
+ /* sanity check */
+ if (!g_str_has_prefix(appstream_id, "org.fwupd.hsi."))
+ g_critical("HSI attributes need to have a 'org.fwupd.hsi.' prefix");
+
+ g_free(priv->appstream_id);
+ priv->appstream_id = g_strdup(appstream_id);
+}
+
+/**
+ * fwupd_security_attr_get_url:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the attribute URL.
+ *
+ * Returns: the attribute result, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_get_url(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->url;
+}
+
+/**
+ * fwupd_security_attr_set_name:
+ * @self: a #FwupdSecurityAttr
+ * @name: (nullable): the attribute name
+ *
+ * Sets the attribute name.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_name(FwupdSecurityAttr *self, const gchar *name)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->name, name) == 0)
+ return;
+
+ g_free(priv->name);
+ priv->name = g_strdup(name);
+}
+
+/**
+ * fwupd_security_attr_get_bios_setting_target_value:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the value that when written to an attribute would activate it or satisfy
+ * a security requirement.
+ *
+ * Returns: the target value of the attribute.
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_security_attr_get_bios_setting_target_value(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->bios_setting_target_value;
+}
+
+/**
+ * fwupd_security_attr_set_bios_setting_target_value:
+ * @self: a #FwupdSecurityAttr
+ * @value: The string to set target value to
+ *
+ * Sets the string used for the target value of an attribute.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_security_attr_set_bios_setting_target_value(FwupdSecurityAttr *self, const gchar *value)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->bios_setting_target_value, value) == 0)
+ return;
+
+ g_free(priv->bios_setting_target_value);
+ priv->bios_setting_target_value = g_strdup(value);
+}
+
+/**
+ * fwupd_security_attr_get_bios_setting_current_value:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the current value of the BIOS setting that can be changed.
+ *
+ * Returns: the current value of the attribute.
+ *
+ * Since: 1.8.4
+ **/
+const gchar *
+fwupd_security_attr_get_bios_setting_current_value(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->bios_setting_current_value;
+}
+
+/**
+ * fwupd_security_attr_set_bios_setting_current_value:
+ * @self: a #FwupdSecurityAttr
+ * @value: The string to set current value to
+ *
+ * Sets the current value of the BIOS setting that can be changed.
+ *
+ * Since: 1.8.4
+ **/
+void
+fwupd_security_attr_set_bios_setting_current_value(FwupdSecurityAttr *self, const gchar *value)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ /* not changed */
+ if (g_strcmp0(priv->bios_setting_current_value, value) == 0)
+ return;
+
+ g_free(priv->bios_setting_current_value);
+ priv->bios_setting_current_value = g_strdup(value);
+}
+
+/**
+ * fwupd_security_attr_set_title:
+ * @self: a #FwupdSecurityAttr
+ * @title: (nullable): the attribute title
+ *
+ * Sets the attribute title.
+ *
+ * Since: 1.8.2
+ **/
+void
+fwupd_security_attr_set_title(FwupdSecurityAttr *self, const gchar *title)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->title, title) == 0)
+ return;
+
+ g_free(priv->title);
+ priv->title = g_strdup(title);
+}
+
+/**
+ * fwupd_security_attr_set_description:
+ * @self: a #FwupdSecurityAttr
+ * @description: (nullable): the attribute description
+ *
+ * Sets the attribute description.
+ *
+ * Since: 1.8.2
+ **/
+void
+fwupd_security_attr_set_description(FwupdSecurityAttr *self, const gchar *description)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->description, description) == 0)
+ return;
+
+ g_free(priv->description);
+ priv->description = g_strdup(description);
+}
+
+/**
+ * fwupd_security_attr_set_plugin:
+ * @self: a #FwupdSecurityAttr
+ * @plugin: (nullable): the plugin name
+ *
+ * Sets the plugin that created the attribute.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_plugin(FwupdSecurityAttr *self, const gchar *plugin)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->plugin, plugin) == 0)
+ return;
+
+ g_free(priv->plugin);
+ priv->plugin = g_strdup(plugin);
+}
+
+/**
+ * fwupd_security_attr_set_url:
+ * @self: a #FwupdSecurityAttr
+ * @url: (nullable): the attribute URL
+ *
+ * Sets the attribute result.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_url(FwupdSecurityAttr *self, const gchar *url)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->url, url) == 0)
+ return;
+
+ g_free(priv->url);
+ priv->url = g_strdup(url);
+}
+/**
+ * fwupd_security_attr_get_created:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets when the attribute was created.
+ *
+ * Returns: the UNIX time, or 0 if unset
+ *
+ * Since: 1.7.1
+ **/
+guint64
+fwupd_security_attr_get_created(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), 0);
+ return priv->created;
+}
+
+/**
+ * fwupd_security_attr_set_created:
+ * @self: a #FwupdSecurityAttr
+ * @created: the UNIX time
+ *
+ * Sets when the attribute was created.
+ *
+ * Since: 1.7.1
+ **/
+void
+fwupd_security_attr_set_created(FwupdSecurityAttr *self, guint64 created)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ priv->created = created;
+}
+
+/**
+ * fwupd_security_attr_get_name:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the attribute name.
+ *
+ * Returns: the attribute name, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_get_name(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->name;
+}
+
+/**
+ * fwupd_security_attr_get_title:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the attribute title, which is typically a two word title.
+ *
+ * The fwupd client program may be able to get translations for this value using a method call
+ * like `dgettext("fwupd",str)`.
+ *
+ * Returns: the attribute title, or %NULL if unset
+ *
+ * Since: 1.8.2
+ **/
+const gchar *
+fwupd_security_attr_get_title(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->title;
+}
+
+/**
+ * fwupd_security_attr_get_description:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the attribute description which is a few lines of prose that normal users will understand.
+ *
+ * The fwupd client program may be able to get translations for this value using a method call
+ * like `dgettext("fwupd",str)`.
+ *
+ * NOTE: The returned string may contain placeholders such as `$HostVendor$` or `$HostProduct$`
+ * and these should be replaced with the values from [method@FwupdClient.get_host_vendor] and
+ * [method@FwupdClient.get_host_product].
+ *
+ * Returns: the attribute description, or %NULL if unset
+ *
+ * Since: 1.8.2
+ **/
+const gchar *
+fwupd_security_attr_get_description(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->description;
+}
+
+/**
+ * fwupd_security_attr_get_plugin:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the plugin that created the attribute.
+ *
+ * Returns: the plugin name, or %NULL if unset
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_get_plugin(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ return priv->plugin;
+}
+
+/**
+ * fwupd_security_attr_get_flags:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the self flags.
+ *
+ * Returns: security attribute flags, or 0 if unset
+ *
+ * Since: 1.5.0
+ **/
+FwupdSecurityAttrFlags
+fwupd_security_attr_get_flags(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), 0);
+ return priv->flags;
+}
+
+/**
+ * fwupd_security_attr_set_flags:
+ * @self: a #FwupdSecurityAttr
+ * @flags: security attribute flags, e.g. %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED
+ *
+ * Sets the attribute flags.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_flags(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flags)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ priv->flags = flags;
+}
+
+/**
+ * fwupd_security_attr_add_flag:
+ * @self: a #FwupdSecurityAttr
+ * @flag: the #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED
+ *
+ * Adds a specific attribute flag to the attribute.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_add_flag(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ priv->flags |= flag;
+}
+
+/**
+ * fwupd_security_attr_remove_flag:
+ * @self: a #FwupdSecurityAttr
+ * @flag: the #FwupdSecurityAttrFlags, e.g. %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED
+ *
+ * Removes a specific attribute flag from the attribute.
+ *
+ * Since: 1.8.3
+ **/
+void
+fwupd_security_attr_remove_flag(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ priv->flags &= ~flag;
+}
+
+/**
+ * fwupd_security_attr_has_flag:
+ * @self: a #FwupdSecurityAttr
+ * @flag: the attribute flag, e.g. %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED
+ *
+ * Finds if the attribute has a specific attribute flag.
+ *
+ * Returns: %TRUE if the flag is set
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fwupd_security_attr_has_flag(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), FALSE);
+ return (priv->flags & flag) > 0;
+}
+
+/**
+ * fwupd_security_attr_get_level:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the HSI level.
+ *
+ * Returns: the security attribute level, or %FWUPD_SECURITY_ATTR_LEVEL_NONE if unset
+ *
+ * Since: 1.5.0
+ **/
+FwupdSecurityAttrLevel
+fwupd_security_attr_get_level(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), 0);
+ return priv->level;
+}
+
+/**
+ * fwupd_security_attr_set_level:
+ * @self: a #FwupdSecurityAttr
+ * @level: a security attribute level, e.g. %FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT
+ *
+ * Sets the HSI level. A @level of %FWUPD_SECURITY_ATTR_LEVEL_NONE is not used
+ * for the HSI calculation.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_level(FwupdSecurityAttr *self, FwupdSecurityAttrLevel level)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ priv->level = level;
+}
+
+/**
+ * fwupd_security_attr_set_result:
+ * @self: a #FwupdSecurityAttr
+ * @result: a security attribute result, e.g. %FWUPD_SECURITY_ATTR_LEVEL_LOCKED
+ *
+ * Sets the optional HSI result. This is required because some attributes may
+ * be a "success" when something is `locked` or may be "failed" if `found`.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_set_result(FwupdSecurityAttr *self, FwupdSecurityAttrResult result)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+
+ /* fixup any legacy attributes to the 'modern' value */
+ if (g_strcmp0(priv->appstream_id, FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM) == 0 &&
+ result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED) {
+ result = FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED;
+ }
+
+ priv->result = result;
+}
+
+/**
+ * fwupd_security_attr_get_result:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the optional HSI result.
+ *
+ * Returns: the #FwupdSecurityAttrResult, e.g %FWUPD_SECURITY_ATTR_LEVEL_LOCKED
+ *
+ * Since: 1.5.0
+ **/
+FwupdSecurityAttrResult
+fwupd_security_attr_get_result(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), 0);
+ return priv->result;
+}
+
+/**
+ * fwupd_security_attr_set_result_fallback:
+ * @self: a #FwupdSecurityAttr
+ * @result: a security attribute, e.g. %FWUPD_SECURITY_ATTR_LEVEL_LOCKED
+ *
+ * Sets the optional fallback HSI result. The fallback may represent the old state, or a state
+ * that may be considered equivalent.
+ *
+ * Since: 1.7.1
+ **/
+void
+fwupd_security_attr_set_result_fallback(FwupdSecurityAttr *self, FwupdSecurityAttrResult result)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ priv->result_fallback = result;
+}
+
+/**
+ * fwupd_security_attr_get_result_fallback:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Gets the optional fallback HSI result.
+ *
+ * Returns: the #FwupdSecurityAttrResult, e.g %FWUPD_SECURITY_ATTR_LEVEL_LOCKED
+ *
+ * Since: 1.7.1
+ **/
+FwupdSecurityAttrResult
+fwupd_security_attr_get_result_fallback(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), 0);
+ return priv->result_fallback;
+}
+
+/**
+ * fwupd_security_attr_to_variant:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Serialize the security attribute.
+ *
+ * Returns: the serialized data, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GVariant *
+fwupd_security_attr_to_variant(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ if (priv->appstream_id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_APPSTREAM_ID,
+ g_variant_new_string(priv->appstream_id));
+ }
+ if (priv->created > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CREATED,
+ g_variant_new_uint64(priv->created));
+ }
+ if (priv->name != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_NAME,
+ g_variant_new_string(priv->name));
+ }
+ if (priv->title != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_SUMMARY,
+ g_variant_new_string(priv->title));
+ }
+ if (priv->description != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_DESCRIPTION,
+ g_variant_new_string(priv->description));
+ }
+ if (priv->plugin != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_PLUGIN,
+ g_variant_new_string(priv->plugin));
+ }
+ if (priv->url != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_URI,
+ g_variant_new_string(priv->url));
+ }
+ if (priv->obsoletes->len > 0) {
+ g_autofree const gchar **strv = g_new0(const gchar *, priv->obsoletes->len + 1);
+ for (guint i = 0; i < priv->obsoletes->len; i++)
+ strv[i] = (const gchar *)g_ptr_array_index(priv->obsoletes, i);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_CATEGORIES,
+ g_variant_new_strv(strv, -1));
+ }
+ if (priv->guids->len > 0) {
+ g_autofree const gchar **strv = g_new0(const gchar *, priv->guids->len + 1);
+ for (guint i = 0; i < priv->guids->len; i++)
+ strv[i] = (const gchar *)g_ptr_array_index(priv->guids, i);
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_GUID,
+ g_variant_new_strv(strv, -1));
+ }
+ if (priv->flags != 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_FLAGS,
+ g_variant_new_uint64(priv->flags));
+ }
+ if (priv->level > 0) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_HSI_LEVEL,
+ g_variant_new_uint32(priv->level));
+ }
+ if (priv->result != FWUPD_SECURITY_ATTR_RESULT_UNKNOWN) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_HSI_RESULT,
+ g_variant_new_uint32(priv->result));
+ }
+ if (priv->result_fallback != FWUPD_SECURITY_ATTR_RESULT_UNKNOWN) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK,
+ g_variant_new_uint32(priv->result_fallback));
+ }
+ if (priv->metadata != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_METADATA,
+ fwupd_hash_kv_to_variant(priv->metadata));
+ }
+ if (priv->bios_setting_id != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_ID,
+ g_variant_new_string(priv->bios_setting_id));
+ }
+ if (priv->bios_setting_target_value != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE,
+ g_variant_new_string(priv->bios_setting_target_value));
+ }
+ if (priv->bios_setting_current_value != NULL) {
+ g_variant_builder_add(&builder,
+ "{sv}",
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ g_variant_new_string(priv->bios_setting_current_value));
+ }
+ return g_variant_new("a{sv}", &builder);
+}
+
+/**
+ * fwupd_security_attr_get_metadata:
+ * @self: a #FwupdSecurityAttr
+ * @key: metadata key
+ *
+ * Gets private metadata from the attribute which may be used in the name.
+ *
+ * Returns: (nullable): the metadata value, or %NULL if unfound
+ *
+ * Since: 1.5.0
+ **/
+const gchar *
+fwupd_security_attr_get_metadata(FwupdSecurityAttr *self, const gchar *key)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
+ if (priv->metadata == NULL)
+ return NULL;
+ return g_hash_table_lookup(priv->metadata, key);
+}
+
+/**
+ * fwupd_security_attr_add_metadata:
+ * @self: a #FwupdSecurityAttr
+ * @key: metadata key
+ * @value: (nullable): metadata value
+ *
+ * Adds metadata to the attribute which may be used in the name.
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_add_metadata(FwupdSecurityAttr *self, const gchar *key, const gchar *value)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ g_return_if_fail(key != NULL);
+
+ if (priv->metadata == NULL) {
+ priv->metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ }
+ g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
+}
+
+static void
+fwupd_security_attr_from_key_value(FwupdSecurityAttr *self, const gchar *key, GVariant *value)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) {
+ fwupd_security_attr_set_appstream_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
+ fwupd_security_attr_set_created(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
+ fwupd_security_attr_set_name(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_SUMMARY) == 0) {
+ fwupd_security_attr_set_title(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
+ fwupd_security_attr_set_description(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_PLUGIN) == 0) {
+ fwupd_security_attr_set_plugin(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_URI) == 0) {
+ fwupd_security_attr_set_url(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_FLAGS) == 0) {
+ fwupd_security_attr_set_flags(self, g_variant_get_uint64(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_HSI_LEVEL) == 0) {
+ fwupd_security_attr_set_level(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_HSI_RESULT) == 0) {
+ fwupd_security_attr_set_result(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK) == 0) {
+ fwupd_security_attr_set_result_fallback(self, g_variant_get_uint32(value));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_GUID) == 0) {
+ g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
+ for (guint i = 0; strv[i] != NULL; i++)
+ fwupd_security_attr_add_guid(self, strv[i]);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_METADATA) == 0) {
+ if (priv->metadata != NULL)
+ g_hash_table_unref(priv->metadata);
+ priv->metadata = fwupd_variant_to_hash_kv(value);
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_ID) == 0) {
+ fwupd_security_attr_set_bios_setting_id(self, g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE) == 0) {
+ fwupd_security_attr_set_bios_setting_target_value(
+ self,
+ g_variant_get_string(value, NULL));
+ return;
+ }
+ if (g_strcmp0(key, FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE) == 0) {
+ fwupd_security_attr_set_bios_setting_current_value(
+ self,
+ g_variant_get_string(value, NULL));
+ return;
+ }
+}
+
+static void
+fwupd_pad_kv_tfl(GString *str, const gchar *key, FwupdSecurityAttrFlags security_attr_flags)
+{
+ g_autoptr(GString) tmp = g_string_new("");
+ for (guint i = 0; i < 64; i++) {
+ if ((security_attr_flags & ((guint64)1 << i)) == 0)
+ continue;
+ g_string_append_printf(tmp,
+ "%s|",
+ fwupd_security_attr_flag_to_string((guint64)1 << i));
+ }
+ if (tmp->len == 0) {
+ g_string_append(tmp, fwupd_security_attr_flag_to_string(0));
+ } else {
+ g_string_truncate(tmp, tmp->len - 1);
+ }
+ fwupd_pad_kv_str(str, key, tmp->str);
+}
+
+/**
+ * fwupd_security_attr_from_json:
+ * @self: a #FwupdSecurityAttr
+ * @json_node: a JSON node
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads a fwupd security attribute from a JSON node.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.7.1
+ **/
+gboolean
+fwupd_security_attr_from_json(FwupdSecurityAttr *self, JsonNode *json_node, GError **error)
+{
+#if JSON_CHECK_VERSION(1, 6, 0)
+ JsonObject *obj;
+
+ /* sanity check */
+ if (!JSON_NODE_HOLDS_OBJECT(json_node)) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "not JSON object");
+ return FALSE;
+ }
+ obj = json_node_get_object(json_node);
+
+ /* this has to exist */
+ if (!json_object_has_member(obj, FWUPD_RESULT_KEY_APPSTREAM_ID)) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "no %s property in object",
+ FWUPD_RESULT_KEY_APPSTREAM_ID);
+ return FALSE;
+ }
+
+ /* all optional */
+ fwupd_security_attr_set_appstream_id(
+ self,
+ json_object_get_string_member(obj, FWUPD_RESULT_KEY_APPSTREAM_ID));
+ fwupd_security_attr_set_name(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_NAME, NULL));
+ fwupd_security_attr_set_title(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_SUMMARY, NULL));
+ fwupd_security_attr_set_description(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_DESCRIPTION, NULL));
+ fwupd_security_attr_set_plugin(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_PLUGIN, NULL));
+ fwupd_security_attr_set_url(
+ self,
+ json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_URI, NULL));
+ fwupd_security_attr_set_level(
+ self,
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_HSI_LEVEL, 0));
+ fwupd_security_attr_set_created(
+ self,
+ json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_CREATED, 0));
+ fwupd_security_attr_set_bios_setting_id(
+ self,
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_ID,
+ NULL));
+ fwupd_security_attr_set_bios_setting_target_value(
+ self,
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE,
+ NULL));
+ fwupd_security_attr_set_bios_setting_current_value(
+ self,
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ NULL));
+
+ /* also optional */
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_HSI_RESULT)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_HSI_RESULT,
+ NULL);
+ fwupd_security_attr_set_result(self, fwupd_security_attr_result_from_string(tmp));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK)) {
+ const gchar *tmp =
+ json_object_get_string_member_with_default(obj,
+ FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK,
+ NULL);
+ fwupd_security_attr_set_result_fallback(
+ self,
+ fwupd_security_attr_result_from_string(tmp));
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_FLAGS)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_FLAGS);
+ for (guint i = 0; i < json_array_get_length(array); i++) {
+ const gchar *tmp = json_array_get_string_element(array, i);
+ FwupdSecurityAttrFlags flag = fwupd_security_attr_flag_from_string(tmp);
+ if (flag != FWUPD_SECURITY_ATTR_FLAG_NONE)
+ fwupd_security_attr_add_flag(self, flag);
+ }
+ }
+ if (json_object_has_member(obj, FWUPD_RESULT_KEY_GUID)) {
+ JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_GUID);
+ for (guint i = 0; i < json_array_get_length(array); i++) {
+ const gchar *tmp = json_array_get_string_element(array, i);
+ fwupd_security_attr_add_guid(self, tmp);
+ }
+ }
+
+ /* success */
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "json-glib version too old");
+ return FALSE;
+#endif
+}
+
+/**
+ * fwupd_security_attr_to_json:
+ * @self: a #FwupdSecurityAttr
+ * @builder: a JSON builder
+ *
+ * Adds a fwupd security attribute to a JSON builder
+ *
+ * Since: 1.5.0
+ **/
+void
+fwupd_security_attr_to_json(FwupdSecurityAttr *self, JsonBuilder *builder)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FWUPD_IS_SECURITY_ATTR(self));
+ g_return_if_fail(builder != NULL);
+
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id);
+ if (priv->created > 0)
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_CREATED, priv->created);
+ fwupd_common_json_add_int(builder, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_HSI_RESULT,
+ fwupd_security_attr_result_to_string(priv->result));
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK,
+ fwupd_security_attr_result_to_string(priv->result_fallback));
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_SUMMARY, priv->title);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
+ fwupd_common_json_add_string(builder, FWUPD_RESULT_KEY_URI, priv->url);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE,
+ priv->bios_setting_target_value);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ priv->bios_setting_current_value);
+ fwupd_common_json_add_string(builder,
+ FWUPD_RESULT_KEY_BIOS_SETTING_ID,
+ priv->bios_setting_id);
+
+ if (priv->flags != FWUPD_SECURITY_ATTR_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_security_attr_flag_to_string((guint64)1 << i);
+ json_builder_add_string_value(builder, tmp);
+ }
+ json_builder_end_array(builder);
+ }
+ 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);
+ }
+ if (priv->metadata != NULL) {
+ g_autoptr(GList) 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_common_json_add_string(builder, key, value);
+ }
+ }
+}
+
+/**
+ * fwupd_security_attr_to_string:
+ * @self: a #FwupdSecurityAttr
+ *
+ * Builds a text representation of the object.
+ *
+ * Returns: text, or %NULL for invalid
+ *
+ * Since: 1.5.0
+ **/
+gchar *
+fwupd_security_attr_to_string(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ GString *str;
+
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+
+ str = g_string_new("");
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id);
+ if (priv->created > 0)
+ fwupd_pad_kv_unx(str, FWUPD_RESULT_KEY_CREATED, priv->created);
+ fwupd_pad_kv_int(str, FWUPD_RESULT_KEY_HSI_LEVEL, priv->level);
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_HSI_RESULT,
+ fwupd_security_attr_result_to_string(priv->result));
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_HSI_RESULT_FALLBACK,
+ fwupd_security_attr_result_to_string(priv->result_fallback));
+ if (priv->flags != FWUPD_SECURITY_ATTR_FLAG_NONE)
+ fwupd_pad_kv_tfl(str, FWUPD_RESULT_KEY_FLAGS, priv->flags);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_NAME, priv->name);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_SUMMARY, priv->title);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_URI, priv->url);
+ fwupd_pad_kv_str(str, FWUPD_RESULT_KEY_BIOS_SETTING_ID, priv->bios_setting_id);
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_BIOS_SETTING_TARGET_VALUE,
+ priv->bios_setting_target_value);
+ fwupd_pad_kv_str(str,
+ FWUPD_RESULT_KEY_BIOS_SETTING_CURRENT_VALUE,
+ priv->bios_setting_current_value);
+
+ for (guint i = 0; i < priv->obsoletes->len; i++) {
+ const gchar *appstream_id = g_ptr_array_index(priv->obsoletes, i);
+ fwupd_pad_kv_str(str, "Obsolete", appstream_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);
+ }
+ if (priv->metadata != NULL) {
+ g_autoptr(GList) 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_pad_kv_str(str, key, value);
+ }
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+static void
+fwupd_security_attr_class_init(FwupdSecurityAttrClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fwupd_security_attr_finalize;
+}
+
+static void
+fwupd_security_attr_init(FwupdSecurityAttr *self)
+{
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+ priv->level = FWUPD_SECURITY_ATTR_LEVEL_NONE;
+ priv->obsoletes = g_ptr_array_new_with_free_func(g_free);
+ priv->guids = g_ptr_array_new_with_free_func(g_free);
+ priv->created = (guint64)g_get_real_time() / G_USEC_PER_SEC;
+}
+
+static void
+fwupd_security_attr_finalize(GObject *object)
+{
+ FwupdSecurityAttr *self = FWUPD_SECURITY_ATTR(object);
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ if (priv->metadata != NULL)
+ g_hash_table_unref(priv->metadata);
+ g_free(priv->bios_setting_id);
+ g_free(priv->bios_setting_target_value);
+ g_free(priv->bios_setting_current_value);
+ g_free(priv->appstream_id);
+ g_free(priv->name);
+ g_free(priv->title);
+ g_free(priv->description);
+ g_free(priv->plugin);
+ g_free(priv->url);
+ g_ptr_array_unref(priv->obsoletes);
+ g_ptr_array_unref(priv->guids);
+
+ G_OBJECT_CLASS(fwupd_security_attr_parent_class)->finalize(object);
+}
+
+static void
+fwupd_security_attr_set_from_variant_iter(FwupdSecurityAttr *self, GVariantIter *iter)
+{
+ GVariant *value;
+ const gchar *key;
+ while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
+ fwupd_security_attr_from_key_value(self, key, value);
+ g_variant_unref(value);
+ }
+}
+
+/**
+ * fwupd_security_attr_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates a new security attribute using serialized data.
+ *
+ * Returns: (transfer full): a new #FwupdSecurityAttr, or %NULL if @value was invalid
+ *
+ * Since: 1.5.0
+ **/
+FwupdSecurityAttr *
+fwupd_security_attr_from_variant(GVariant *value)
+{
+ FwupdSecurityAttr *rel = NULL;
+ const gchar *type_string;
+ g_autoptr(GVariantIter) iter = NULL;
+
+ g_return_val_if_fail(value != NULL, NULL);
+
+ type_string = g_variant_get_type_string(value);
+ if (g_strcmp0(type_string, "(a{sv})") == 0) {
+ rel = fwupd_security_attr_new(NULL);
+ g_variant_get(value, "(a{sv})", &iter);
+ fwupd_security_attr_set_from_variant_iter(rel, iter);
+ } else if (g_strcmp0(type_string, "a{sv}") == 0) {
+ rel = fwupd_security_attr_new(NULL);
+ g_variant_get(value, "a{sv}", &iter);
+ fwupd_security_attr_set_from_variant_iter(rel, iter);
+ } else {
+ g_warning("type %s not known", type_string);
+ }
+ return rel;
+}
+
+/**
+ * fwupd_security_attr_array_from_variant:
+ * @value: (not nullable): the serialized data
+ *
+ * Creates an array of new security attributes using serialized data.
+ *
+ * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes, or %NULL if @value
+ *was invalid
+ *
+ * Since: 1.5.0
+ **/
+GPtrArray *
+fwupd_security_attr_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++) {
+ FwupdSecurityAttr *rel;
+ g_autoptr(GVariant) data = NULL;
+ data = g_variant_get_child_value(untuple, i);
+ rel = fwupd_security_attr_from_variant(data);
+ if (rel == NULL)
+ continue;
+ g_ptr_array_add(array, rel);
+ }
+ return array;
+}
+
+/**
+ * fwupd_security_attr_copy:
+ * @self: (nullable): a #FwupdSecurityAttr
+ *
+ * Makes a full (deep) copy of a security attribute.
+ *
+ * Returns: (transfer full): a new #FwupdSecurityAttr
+ *
+ * Since: 1.7.1
+ **/
+FwupdSecurityAttr *
+fwupd_security_attr_copy(FwupdSecurityAttr *self)
+{
+ g_autoptr(FwupdSecurityAttr) new = g_object_new(FWUPD_TYPE_SECURITY_ATTR, NULL);
+ FwupdSecurityAttrPrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FWUPD_IS_SECURITY_ATTR(self), NULL);
+
+ fwupd_security_attr_set_appstream_id(new, priv->appstream_id);
+ fwupd_security_attr_set_name(new, priv->name);
+ fwupd_security_attr_set_title(new, priv->title);
+ fwupd_security_attr_set_description(new, priv->description);
+ fwupd_security_attr_set_plugin(new, priv->plugin);
+ fwupd_security_attr_set_url(new, priv->url);
+ fwupd_security_attr_set_level(new, priv->level);
+ fwupd_security_attr_set_flags(new, priv->flags);
+ fwupd_security_attr_set_result(new, priv->result);
+ fwupd_security_attr_set_created(new, priv->created);
+ fwupd_security_attr_set_bios_setting_id(new, priv->bios_setting_id);
+
+ for (guint i = 0; i < priv->guids->len; i++) {
+ const gchar *guid = g_ptr_array_index(priv->guids, i);
+ fwupd_security_attr_add_guid(new, guid);
+ }
+ for (guint i = 0; i < priv->obsoletes->len; i++) {
+ const gchar *obsolete = g_ptr_array_index(priv->obsoletes, i);
+ fwupd_security_attr_add_obsolete(new, obsolete);
+ }
+ if (priv->metadata != NULL) {
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init(&iter, priv->metadata);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ fwupd_security_attr_add_metadata(new,
+ (const gchar *)key,
+ (const gchar *)value);
+ }
+ }
+ return g_steal_pointer(&new);
+}
+
+/**
+ * fwupd_security_attr_new:
+ * @appstream_id: (nullable): the AppStream component ID, e.g. `com.intel.BiosGuard`
+ *
+ * Creates a new security attribute.
+ *
+ * Plugins should not use this method, and should instead use `fu_plugin_security_attr_new()` or
+ * `fu_security_attr_new()`.
+ *
+ * Returns: a new #FwupdSecurityAttr
+ *
+ * Since: 1.5.0
+ **/
+FwupdSecurityAttr *
+fwupd_security_attr_new(const gchar *appstream_id)
+{
+ FwupdSecurityAttr *self;
+ self = g_object_new(FWUPD_TYPE_SECURITY_ATTR, NULL);
+ if (appstream_id != NULL)
+ fwupd_security_attr_set_appstream_id(self, appstream_id);
+ return FWUPD_SECURITY_ATTR(self);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-security-attr.h b/fwupd-1.8.6/libfwupd/fwupd-security-attr.h
new file mode 100644
index 0000000000000000000000000000000000000000..4ada93a41a0f8d521e5c5db7ef506cd40861ae56
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-security-attr.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fwupd-enums.h"
+
+G_BEGIN_DECLS
+
+#define FWUPD_TYPE_SECURITY_ATTR (fwupd_security_attr_get_type())
+G_DECLARE_DERIVABLE_TYPE(FwupdSecurityAttr, fwupd_security_attr, FWUPD, SECURITY_ATTR, GObject)
+
+struct _FwupdSecurityAttrClass {
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_fwupd_reserved1)(void);
+ void (*_fwupd_reserved2)(void);
+ void (*_fwupd_reserved3)(void);
+ void (*_fwupd_reserved4)(void);
+ void (*_fwupd_reserved5)(void);
+ void (*_fwupd_reserved6)(void);
+ void (*_fwupd_reserved7)(void);
+};
+
+/**
+ * FwupdSecurityAttrFlags:
+ * @FWUPD_SECURITY_ATTR_FLAG_NONE: No flags set
+ * @FWUPD_SECURITY_ATTR_FLAG_SUCCESS: Success
+ * @FWUPD_SECURITY_ATTR_FLAG_OBSOLETED: Obsoleted by another attribute
+ * @FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA: Missing data
+ * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES: Suffix `U`
+ * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION: Suffix `A`
+ * @FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE: Suffix `!`
+ * @FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM: Contact the firmware vendor for a update
+ * @FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW: Failure may be fixed by changing FW config
+ * @FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS: Failure may be fixed by changing OS config
+ *
+ * The flags available for HSI attributes.
+ **/
+typedef enum {
+ FWUPD_SECURITY_ATTR_FLAG_NONE = 0,
+ FWUPD_SECURITY_ATTR_FLAG_SUCCESS = 1 << 0,
+ FWUPD_SECURITY_ATTR_FLAG_OBSOLETED = 1 << 1,
+ FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA = 1 << 2,
+ FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES = 1 << 8,
+ FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION = 1 << 9,
+ FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE = 1 << 10,
+ FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM = 1 << 11,
+ FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW = 1 << 12,
+ FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS = 1 << 13,
+} FwupdSecurityAttrFlags;
+
+/**
+ * FwupdSecurityAttrLevel:
+ * @FWUPD_SECURITY_ATTR_LEVEL_NONE: Very few detected firmware protections
+ * @FWUPD_SECURITY_ATTR_LEVEL_CRITICAL: The most basic of security protections
+ * @FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT: Firmware security issues considered
+ *important
+ * @FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL: Firmware security issues that pose a
+ *theoretical concern
+ * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION: Out-of-band protection of the system
+ *firmware
+ * @FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION: Out-of-band attestation of the system
+ *firmware
+ *
+ * The HSI level.
+ **/
+typedef enum {
+ FWUPD_SECURITY_ATTR_LEVEL_NONE = 0, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_LEVEL_CRITICAL = 1, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT = 2, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL = 3, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION = 4, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_ATTESTATION = 5, /* Since: 1.5.0 */
+ /*< private >*/
+ FWUPD_SECURITY_ATTR_LEVEL_LAST = 6 /* perhaps increased in the future */
+} FwupdSecurityAttrLevel;
+
+/**
+ * FwupdSecurityAttrResult:
+ * @FWUPD_SECURITY_ATTR_RESULT_UNKNOWN: Not known
+ * @FWUPD_SECURITY_ATTR_RESULT_ENABLED: Enabled
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED: Not enabled
+ * @FWUPD_SECURITY_ATTR_RESULT_VALID: Valid
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_VALID: Not valid
+ * @FWUPD_SECURITY_ATTR_RESULT_LOCKED: Locked
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED: Not locked
+ * @FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED: Encrypted
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED: Not encrypted
+ * @FWUPD_SECURITY_ATTR_RESULT_TAINTED: Tainted
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED: Not tainted
+ * @FWUPD_SECURITY_ATTR_RESULT_FOUND: Found
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND: NOt found
+ * @FWUPD_SECURITY_ATTR_RESULT_SUPPORTED: Supported
+ * @FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED: Not supported
+ *
+ * The HSI result.
+ **/
+typedef enum {
+ FWUPD_SECURITY_ATTR_RESULT_UNKNOWN, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_ENABLED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_VALID, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_VALID, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_LOCKED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_TAINTED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_FOUND, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_SUPPORTED, /* Since: 1.5.0 */
+ FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED, /* Since: 1.5.0 */
+ /*< private >*/
+ FWUPD_SECURITY_ATTR_RESULT_LAST
+} FwupdSecurityAttrResult;
+
+FwupdSecurityAttr *
+fwupd_security_attr_new(const gchar *appstream_id);
+gchar *
+fwupd_security_attr_to_string(FwupdSecurityAttr *self);
+
+const gchar *
+fwupd_security_attr_get_bios_setting_id(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_bios_setting_id(FwupdSecurityAttr *self, const gchar *id);
+const gchar *
+fwupd_security_attr_get_bios_setting_target_value(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_bios_setting_target_value(FwupdSecurityAttr *self, const gchar *value);
+const gchar *
+fwupd_security_attr_get_bios_setting_current_value(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_bios_setting_current_value(FwupdSecurityAttr *self, const gchar *value);
+
+const gchar *
+fwupd_security_attr_get_appstream_id(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_appstream_id(FwupdSecurityAttr *self, const gchar *appstream_id);
+FwupdSecurityAttrLevel
+fwupd_security_attr_get_level(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_level(FwupdSecurityAttr *self, FwupdSecurityAttrLevel level);
+FwupdSecurityAttrResult
+fwupd_security_attr_get_result(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_result(FwupdSecurityAttr *self, FwupdSecurityAttrResult result);
+FwupdSecurityAttrResult
+fwupd_security_attr_get_result_fallback(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_result_fallback(FwupdSecurityAttr *self, FwupdSecurityAttrResult result);
+const gchar *
+fwupd_security_attr_get_name(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_name(FwupdSecurityAttr *self, const gchar *name);
+const gchar *
+fwupd_security_attr_get_title(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_title(FwupdSecurityAttr *self, const gchar *title);
+const gchar *
+fwupd_security_attr_get_description(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_description(FwupdSecurityAttr *self, const gchar *description);
+const gchar *
+fwupd_security_attr_get_plugin(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_plugin(FwupdSecurityAttr *self, const gchar *plugin);
+const gchar *
+fwupd_security_attr_get_url(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_url(FwupdSecurityAttr *self, const gchar *url);
+guint64
+fwupd_security_attr_get_created(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_created(FwupdSecurityAttr *self, guint64 created);
+GPtrArray *
+fwupd_security_attr_get_obsoletes(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_add_obsolete(FwupdSecurityAttr *self, const gchar *appstream_id);
+gboolean
+fwupd_security_attr_has_obsolete(FwupdSecurityAttr *self, const gchar *appstream_id);
+GPtrArray *
+fwupd_security_attr_get_guids(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_add_guid(FwupdSecurityAttr *self, const gchar *guid);
+void
+fwupd_security_attr_add_guids(FwupdSecurityAttr *self, GPtrArray *guids);
+gboolean
+fwupd_security_attr_has_guid(FwupdSecurityAttr *self, const gchar *guid);
+const gchar *
+fwupd_security_attr_get_metadata(FwupdSecurityAttr *self, const gchar *key);
+void
+fwupd_security_attr_add_metadata(FwupdSecurityAttr *self, const gchar *key, const gchar *value);
+FwupdSecurityAttrFlags
+fwupd_security_attr_get_flags(FwupdSecurityAttr *self);
+void
+fwupd_security_attr_set_flags(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flags);
+void
+fwupd_security_attr_add_flag(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag);
+void
+fwupd_security_attr_remove_flag(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag);
+gboolean
+fwupd_security_attr_has_flag(FwupdSecurityAttr *self, FwupdSecurityAttrFlags flag);
+const gchar *
+fwupd_security_attr_flag_to_string(FwupdSecurityAttrFlags flag);
+FwupdSecurityAttrFlags
+fwupd_security_attr_flag_from_string(const gchar *flag);
+const gchar *
+fwupd_security_attr_flag_to_suffix(FwupdSecurityAttrFlags flag);
+const gchar *
+fwupd_security_attr_result_to_string(FwupdSecurityAttrResult result);
+FwupdSecurityAttrResult
+fwupd_security_attr_result_from_string(const gchar *result);
+
+FwupdSecurityAttr *
+fwupd_security_attr_from_variant(GVariant *value);
+GPtrArray *
+fwupd_security_attr_array_from_variant(GVariant *value);
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupd/fwupd-self-test.c b/fwupd-1.8.6/libfwupd/fwupd-self-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7d5fc3f2b95e5ebd2fc0390024571d4f0bc4410
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-self-test.c
@@ -0,0 +1,1556 @@
+/*
+ * Copyright (C) 2016 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include
+#include
+#ifdef HAVE_FNMATCH_H
+#include
+#endif
+
+#include "fwupd-bios-setting-private.h"
+#include "fwupd-client-sync.h"
+#include "fwupd-client.h"
+#include "fwupd-common.h"
+#include "fwupd-device-private.h"
+#include "fwupd-enums.h"
+#include "fwupd-error.h"
+#include "fwupd-plugin-private.h"
+#include "fwupd-release-private.h"
+#include "fwupd-remote-private.h"
+#include "fwupd-request-private.h"
+#include "fwupd-security-attr-private.h"
+
+static gboolean
+fu_test_compare_lines(const gchar *txt1, const gchar *txt2, GError **error)
+{
+ g_autofree gchar *output = NULL;
+
+ /* exactly the same */
+ if (g_strcmp0(txt1, txt2) == 0)
+ return TRUE;
+
+ /* matches a pattern */
+#ifdef HAVE_FNMATCH_H
+ if (fnmatch(txt2, txt1, FNM_NOESCAPE) == 0)
+ return TRUE;
+#else
+ if (g_strcmp0(txt1, txt2) == 0)
+ return TRUE;
+#endif
+
+ /* save temp files and diff them */
+ if (!g_file_set_contents("/tmp/a", txt1, -1, error))
+ return FALSE;
+ if (!g_file_set_contents("/tmp/b", txt2, -1, error))
+ return FALSE;
+ if (!g_spawn_command_line_sync("diff -urNp /tmp/b /tmp/a", &output, NULL, NULL, error))
+ return FALSE;
+
+ /* just output the diff */
+ g_set_error_literal(error, 1, 0, output);
+ 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)
+{
+ /* enums */
+ for (guint i = 0; i < FWUPD_ERROR_LAST; i++) {
+ const gchar *tmp = fwupd_error_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_error_from_string(tmp), ==, i);
+ }
+ for (guint i = 0; i < FWUPD_STATUS_LAST; i++) {
+ const gchar *tmp = fwupd_status_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_status_from_string(tmp), ==, i);
+ }
+ for (guint i = 0; i < FWUPD_UPDATE_STATE_LAST; i++) {
+ const gchar *tmp = fwupd_update_state_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_update_state_from_string(tmp), ==, i);
+ }
+ for (guint i = 0; i < FWUPD_TRUST_FLAG_LAST; i++) {
+ const gchar *tmp = fwupd_trust_flag_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_trust_flag_from_string(tmp), ==, i);
+ }
+ for (guint i = 0; i < FWUPD_REQUEST_KIND_LAST; i++) {
+ const gchar *tmp = fwupd_request_kind_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_request_kind_from_string(tmp), ==, i);
+ }
+ for (guint i = FWUPD_RELEASE_URGENCY_UNKNOWN + 1; i < FWUPD_RELEASE_URGENCY_LAST; i++) {
+ const gchar *tmp = fwupd_release_urgency_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_release_urgency_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);
+ }
+ for (guint i = 1; i < FWUPD_REMOTE_KIND_LAST; i++) {
+ const gchar *tmp = fwupd_remote_kind_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_remote_kind_from_string(tmp), ==, i);
+ }
+
+ /* bitfield */
+ for (guint64 i = 1; i <= FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD; i *= 2) {
+ const gchar *tmp = fwupd_device_flag_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing device flag 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_device_flag_from_string(tmp), ==, i);
+ }
+ for (guint64 i = 1; i <= FWUPD_DEVICE_PROBLEM_IS_EMULATED; i *= 2) {
+ const gchar *tmp = fwupd_device_problem_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing device problem 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_device_problem_from_string(tmp), ==, i);
+ }
+ for (guint64 i = 1; i <= FWUPD_PLUGIN_FLAG_MODULAR; i *= 2) {
+ const gchar *tmp = fwupd_plugin_flag_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing plugin flag 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_plugin_flag_from_string(tmp), ==, i);
+ }
+ for (guint64 i = 1; i <= FWUPD_FEATURE_FLAG_SHOW_PROBLEMS; i *= 2) {
+ const gchar *tmp = fwupd_feature_flag_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing feature flag 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_feature_flag_from_string(tmp), ==, i);
+ }
+ for (guint64 i = 1; i <= FWUPD_FEATURE_FLAG_ALLOW_AUTHENTICATION; i *= 2) {
+ const gchar *tmp = fwupd_feature_flag_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing feature flag 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_feature_flag_from_string(tmp), ==, i);
+ }
+ for (guint64 i = 1; i <= FWUPD_RELEASE_FLAG_IS_COMMUNITY; i *= 2) {
+ const gchar *tmp = fwupd_release_flag_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing release flag 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_release_flag_from_string(tmp), ==, i);
+ }
+ for (guint64 i = 1; i <= FWUPD_REQUEST_FLAG_NONE; i *= 2) {
+ const gchar *tmp = fwupd_request_flag_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing request flag 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_request_flag_from_string(tmp), ==, i);
+ }
+ for (guint i = 1; i < FWUPD_KEYRING_KIND_LAST; i++) {
+ const gchar *tmp = fwupd_keyring_kind_to_string(i);
+ if (tmp == NULL)
+ g_warning("missing keyring kind 0x%x", (guint)i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_keyring_kind_from_string(tmp), ==, i);
+ }
+}
+
+static void
+fwupd_remote_download_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *fn = NULL;
+ g_autofree gchar *directory = NULL;
+ g_autofree gchar *expected_metadata = NULL;
+ g_autofree gchar *expected_signature = NULL;
+ g_autoptr(FwupdRemote) remote = NULL;
+ g_autoptr(GError) error = NULL;
+
+ remote = fwupd_remote_new();
+ directory = g_build_filename(FWUPD_LOCALSTATEDIR, "lib", "fwupd", "remotes.d", NULL);
+ expected_metadata = g_build_filename(FWUPD_LOCALSTATEDIR,
+ "lib",
+ "fwupd",
+ "remotes.d",
+ "lvfs-testing",
+ "metadata.xml.gz",
+ NULL);
+ expected_signature = g_strdup_printf("%s.jcat", expected_metadata);
+ fwupd_remote_set_remotes_dir(remote, directory);
+ fn = g_test_build_filename(G_TEST_DIST, "tests", "remotes.d", "lvfs-testing.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ ret = fwupd_remote_setup(remote, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpint(fwupd_remote_get_kind(remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD);
+ g_assert_cmpint(fwupd_remote_get_keyring_kind(remote), ==, FWUPD_KEYRING_KIND_JCAT);
+ g_assert_cmpint(fwupd_remote_get_priority(remote), ==, 0);
+ g_assert_false(fwupd_remote_get_enabled(remote));
+ g_assert_nonnull(fwupd_remote_get_metadata_uri(remote));
+ g_assert_nonnull(fwupd_remote_get_metadata_uri_sig(remote));
+ g_assert_cmpstr(fwupd_remote_get_title(remote),
+ ==,
+ "Linux Vendor Firmware Service (testing)");
+ g_assert_cmpstr(fwupd_remote_get_report_uri(remote),
+ ==,
+ "https://fwupd.org/lvfs/firmware/report");
+ g_assert_cmpstr(fwupd_remote_get_filename_cache(remote), ==, expected_metadata);
+ g_assert_cmpstr(fwupd_remote_get_filename_cache_sig(remote), ==, expected_signature);
+}
+
+/* verify we used the FirmwareBaseURI just for firmware */
+static void
+fwupd_remote_baseuri_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *firmware_uri = NULL;
+ g_autofree gchar *fn = NULL;
+ g_autoptr(FwupdRemote) remote = NULL;
+ g_autofree gchar *directory = NULL;
+ g_autoptr(GError) error = NULL;
+
+ remote = fwupd_remote_new();
+ directory = g_build_filename(FWUPD_LOCALSTATEDIR, "lib", "fwupd", "remotes.d", NULL);
+ fwupd_remote_set_remotes_dir(remote, directory);
+ fn = g_test_build_filename(G_TEST_DIST, "tests", "firmware-base-uri.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpint(fwupd_remote_get_kind(remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD);
+ g_assert_cmpint(fwupd_remote_get_keyring_kind(remote), ==, FWUPD_KEYRING_KIND_JCAT);
+ g_assert_cmpint(fwupd_remote_get_priority(remote), ==, 0);
+ g_assert_true(fwupd_remote_get_enabled(remote));
+ g_assert_cmpstr(fwupd_remote_get_firmware_base_uri(remote), ==, "https://my.fancy.cdn/");
+ g_assert_cmpstr(fwupd_remote_get_agreement(remote), ==, NULL);
+ g_assert_cmpstr(fwupd_remote_get_checksum(remote), ==, NULL);
+ g_assert_cmpstr(fwupd_remote_get_metadata_uri(remote),
+ ==,
+ "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz");
+ g_assert_cmpstr(fwupd_remote_get_metadata_uri_sig(remote),
+ ==,
+ "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.jcat");
+ firmware_uri =
+ fwupd_remote_build_firmware_uri(remote, "http://bbc.co.uk/firmware.cab", &error);
+ g_assert_no_error(error);
+ g_assert_cmpstr(firmware_uri, ==, "https://my.fancy.cdn/firmware.cab");
+}
+
+static gchar *
+fwupd_remote_to_json_string(FwupdRemote *remote, GError **error)
+{
+ g_autofree gchar *data = NULL;
+ g_autoptr(JsonGenerator) json_generator = NULL;
+ g_autoptr(JsonBuilder) builder = json_builder_new();
+ g_autoptr(JsonNode) json_root = NULL;
+ json_builder_begin_object(builder);
+ fwupd_remote_to_json(remote, 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);
+ if (data == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "Failed to convert remote to json.");
+ return NULL;
+ }
+ return g_steal_pointer(&data);
+}
+
+static void
+fwupd_remote_auth_func(void)
+{
+ gboolean ret;
+ gchar **order;
+ g_autofree gchar *fn = NULL;
+ g_autofree gchar *remotes_dir = NULL;
+ g_autofree gchar *json = NULL;
+ g_autoptr(FwupdRemote) remote = fwupd_remote_new();
+ g_autoptr(FwupdRemote) remote2 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) data = NULL;
+
+ remotes_dir = g_test_build_filename(G_TEST_BUILT, "tests", NULL);
+ fwupd_remote_set_remotes_dir(remote, remotes_dir);
+
+ fn = g_test_build_filename(G_TEST_DIST, "tests", "auth.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpstr(fwupd_remote_get_username(remote), ==, "user");
+ g_assert_cmpstr(fwupd_remote_get_password(remote), ==, "pass");
+ g_assert_cmpstr(fwupd_remote_get_security_report_uri(remote),
+ ==,
+ "https://fwupd.org/lvfs/hsireports/upload");
+ g_assert_false(fwupd_remote_get_approval_required(remote));
+ g_assert_false(fwupd_remote_get_automatic_reports(remote));
+ g_assert_true(fwupd_remote_get_automatic_security_reports(remote));
+
+ g_assert_true(
+ g_str_has_suffix(fwupd_remote_get_filename_source(remote), "tests/auth.conf"));
+ g_assert_true(g_str_has_suffix(fwupd_remote_get_remotes_dir(remote), "/libfwupd/tests"));
+ g_assert_cmpint(fwupd_remote_get_age(remote), >, 1000000);
+
+ ret = fwupd_remote_setup(remote, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ order = fwupd_remote_get_order_before(remote);
+ g_assert_nonnull(order);
+ g_assert_cmpint(g_strv_length(order), ==, 1);
+ g_assert_cmpstr(order[0], ==, "before");
+ order = fwupd_remote_get_order_after(remote);
+ g_assert_nonnull(order);
+ g_assert_cmpint(g_strv_length(order), ==, 1);
+ g_assert_cmpstr(order[0], ==, "after");
+
+ /* to/from GVariant */
+ fwupd_remote_set_priority(remote, 999);
+ data = fwupd_remote_to_variant(remote);
+ remote2 = fwupd_remote_from_variant(data);
+ g_assert_cmpstr(fwupd_remote_get_username(remote2), ==, "user");
+ g_assert_cmpint(fwupd_remote_get_priority(remote2), ==, 999);
+
+ /* jcat-tool is not a hard dep, and the tests create an empty file if unfound */
+ ret = fwupd_remote_load_signature(remote,
+ fwupd_remote_get_filename_cache_sig(remote),
+ &error);
+ if (!ret) {
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT)) {
+ g_test_skip("no jcat-tool, so skipping test");
+ return;
+ }
+ }
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* to JSON */
+ fwupd_remote_set_filename_source(remote2, NULL);
+ fwupd_remote_set_checksum(
+ remote2,
+ "dd1b4fd2a59bb0e4d9ea760c658ac3cf9336c7b6729357bab443485b5cf071b2");
+ fwupd_remote_set_filename_cache(remote2, "./libfwupd/tests/auth/metadata.xml.gz");
+ json = fwupd_remote_to_json_string(remote2, &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json);
+ ret = fu_test_compare_lines(
+ json,
+ "{\n"
+ " \"Id\" : \"auth\",\n"
+ " \"Kind\" : \"download\",\n"
+ " \"KeyringKind\" : \"jcat\",\n"
+ " \"FirmwareBaseUri\" : \"https://my.fancy.cdn/\",\n"
+ " \"ReportUri\" : \"https://fwupd.org/lvfs/firmware/report\",\n"
+ " \"SecurityReportUri\" : \"https://fwupd.org/lvfs/hsireports/upload\",\n"
+ " \"MetadataUri\" : \"https://cdn.fwupd.org/downloads/firmware.xml.gz\",\n"
+ " \"MetadataUriSig\" : \"https://cdn.fwupd.org/downloads/firmware.xml.gz.jcat\",\n"
+ " \"Username\" : \"user\",\n"
+ " \"Password\" : \"pass\",\n"
+ " \"Checksum\" : "
+ "\"dd1b4fd2a59bb0e4d9ea760c658ac3cf9336c7b6729357bab443485b5cf071b2\",\n"
+ " \"FilenameCache\" : \"./libfwupd/tests/auth/metadata.xml.gz\",\n"
+ " \"FilenameCacheSig\" : \"./libfwupd/tests/auth/metadata.xml.gz.jcat\",\n"
+ " \"Enabled\" : \"true\",\n"
+ " \"ApprovalRequired\" : \"false\",\n"
+ " \"AutomaticReports\" : \"false\",\n"
+ " \"AutomaticSecurityReports\" : \"true\",\n"
+ " \"Priority\" : 999,\n"
+ " \"Mtime\" : 0\n"
+ "}",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+}
+
+static void
+fwupd_remote_duplicate_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *fn2 = NULL;
+ g_autofree gchar *fn = NULL;
+ g_autoptr(FwupdRemote) remote = fwupd_remote_new();
+ g_autoptr(GError) error = NULL;
+
+ fn = g_test_build_filename(G_TEST_DIST, "tests", "stable.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ fn2 = g_test_build_filename(G_TEST_DIST, "tests", "disabled.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn2, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ ret = fwupd_remote_setup(remote, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ ret = fwupd_remote_setup(remote, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_false(fwupd_remote_get_enabled(remote));
+ g_assert_cmpint(fwupd_remote_get_keyring_kind(remote), ==, FWUPD_KEYRING_KIND_NONE);
+ g_assert_cmpstr(fwupd_remote_get_username(remote), ==, NULL);
+ g_assert_cmpstr(fwupd_remote_get_password(remote), ==, "");
+ g_assert_cmpstr(fwupd_remote_get_filename_cache(remote),
+ ==,
+ "/tmp/fwupd-self-test/stable.xml");
+}
+
+/* verify we used the metadata path for firmware */
+static void
+fwupd_remote_nopath_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *firmware_uri = NULL;
+ g_autofree gchar *fn = NULL;
+ g_autoptr(FwupdRemote) remote = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *directory = NULL;
+
+ remote = fwupd_remote_new();
+ directory = g_build_filename(FWUPD_LOCALSTATEDIR, "lib", "fwupd", "remotes.d", NULL);
+ fwupd_remote_set_remotes_dir(remote, directory);
+ fn = g_test_build_filename(G_TEST_DIST, "tests", "firmware-nopath.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpint(fwupd_remote_get_kind(remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD);
+ g_assert_cmpint(fwupd_remote_get_keyring_kind(remote), ==, FWUPD_KEYRING_KIND_JCAT);
+ g_assert_cmpint(fwupd_remote_get_priority(remote), ==, 0);
+ g_assert_true(fwupd_remote_get_enabled(remote));
+ g_assert_cmpstr(fwupd_remote_get_checksum(remote), ==, NULL);
+ g_assert_cmpstr(fwupd_remote_get_metadata_uri(remote),
+ ==,
+ "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz");
+ g_assert_cmpstr(fwupd_remote_get_metadata_uri_sig(remote),
+ ==,
+ "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.jcat");
+ firmware_uri = fwupd_remote_build_firmware_uri(remote, "firmware.cab", &error);
+ g_assert_no_error(error);
+ g_assert_cmpstr(firmware_uri,
+ ==,
+ "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.cab");
+}
+
+static void
+fwupd_remote_local_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *fn = NULL;
+ g_autofree gchar *json = NULL;
+ g_autoptr(FwupdRemote) remote = NULL;
+ g_autoptr(FwupdRemote) remote2 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) data = NULL;
+
+ remote = fwupd_remote_new();
+ fn = g_test_build_filename(G_TEST_DIST, "tests", "dell-esrt.conf", NULL);
+ ret = fwupd_remote_load_from_filename(remote, fn, NULL, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpint(fwupd_remote_get_kind(remote), ==, FWUPD_REMOTE_KIND_LOCAL);
+ g_assert_cmpint(fwupd_remote_get_keyring_kind(remote), ==, FWUPD_KEYRING_KIND_NONE);
+ g_assert_true(fwupd_remote_get_enabled(remote));
+ g_assert_null(fwupd_remote_get_metadata_uri(remote));
+ g_assert_null(fwupd_remote_get_metadata_uri_sig(remote));
+ g_assert_null(fwupd_remote_get_report_uri(remote));
+ 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);
+
+ /* to/from GVariant */
+ data = fwupd_remote_to_variant(remote);
+ remote2 = fwupd_remote_from_variant(data);
+ g_assert_null(fwupd_remote_get_metadata_uri(remote));
+
+ /* to JSON */
+ fwupd_remote_set_filename_source(remote2, NULL);
+ json = fwupd_remote_to_json_string(remote2, &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json);
+ ret = fu_test_compare_lines(
+ json,
+ "{\n"
+ " \"Id\" : \"dell-esrt\",\n"
+ " \"Kind\" : \"local\",\n"
+ " \"KeyringKind\" : \"none\",\n"
+ " \"Title\" : \"Enable UEFI capsule updates on Dell systems\",\n"
+ " \"FilenameCache\" : \"@datadir@/fwupd/remotes.d/dell-esrt/metadata.xml\",\n"
+ " \"Enabled\" : \"true\",\n"
+ " \"ApprovalRequired\" : \"false\",\n"
+ " \"AutomaticReports\" : \"false\",\n"
+ " \"AutomaticSecurityReports\" : \"false\",\n"
+ " \"Priority\" : 0,\n"
+ " \"Mtime\" : 0\n"
+ "}",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+}
+
+static gchar *
+fwupd_release_to_json_string(FwupdRelease *release, GError **error)
+{
+ g_autofree gchar *data = NULL;
+ g_autoptr(JsonGenerator) json_generator = NULL;
+ g_autoptr(JsonBuilder) builder = json_builder_new();
+ g_autoptr(JsonNode) json_root = NULL;
+ json_builder_begin_object(builder);
+ fwupd_release_to_json(release, 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);
+ if (data == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "Failed to convert release to json.");
+ return NULL;
+ }
+ return g_steal_pointer(&data);
+}
+
+static void
+fwupd_release_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *json1 = NULL;
+ g_autofree gchar *json2 = NULL;
+ g_autofree gchar *str = NULL;
+ g_autoptr(FwupdRelease) release1 = NULL;
+ g_autoptr(FwupdRelease) release2 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) data = NULL;
+
+ release1 = fwupd_release_new();
+ fwupd_release_add_metadata_item(release1, "foo", "bar");
+ fwupd_release_add_metadata_item(release1, "baz", "bam");
+ fwupd_release_set_remote_id(release1, "remote-id");
+ fwupd_release_set_appstream_id(release1, "appstream-id");
+ fwupd_release_set_id(release1, "id");
+ fwupd_release_set_detach_caption(release1, "detach_caption");
+ fwupd_release_set_detach_image(release1, "detach_image");
+ fwupd_release_set_update_message(release1, "update_message");
+ fwupd_release_set_update_image(release1, "update_image");
+ fwupd_release_set_filename(release1, "filename");
+ fwupd_release_set_protocol(release1, "protocol");
+ fwupd_release_set_license(release1, "license");
+ fwupd_release_set_name(release1, "name");
+ fwupd_release_set_name_variant_suffix(release1, "name_variant_suffix");
+ fwupd_release_set_summary(release1, "summary");
+ fwupd_release_set_branch(release1, "branch");
+ fwupd_release_set_description(release1, "description");
+ fwupd_release_set_homepage(release1, "homepage");
+ fwupd_release_set_details_url(release1, "details_url");
+ fwupd_release_set_source_url(release1, "source_url");
+ fwupd_release_set_version(release1, "version");
+ fwupd_release_set_vendor(release1, "vendor");
+ fwupd_release_set_size(release1, 1234);
+ fwupd_release_set_created(release1, 5678);
+ fwupd_release_set_install_duration(release1, 2468);
+ fwupd_release_add_category(release1, "category");
+ fwupd_release_add_category(release1, "category");
+ fwupd_release_add_issue(release1, "issue");
+ fwupd_release_add_issue(release1, "issue");
+ fwupd_release_add_location(release1, "location");
+ fwupd_release_add_location(release1, "location");
+ fwupd_release_add_tag(release1, "tag");
+ fwupd_release_add_tag(release1, "tag");
+ fwupd_release_add_checksum(release1, "checksum");
+ fwupd_release_add_checksum(release1, "checksum");
+ fwupd_release_add_flag(release1, FWUPD_RELEASE_FLAG_IS_UPGRADE);
+ fwupd_release_add_flag(release1, FWUPD_RELEASE_FLAG_IS_UPGRADE);
+ fwupd_release_add_flag(release1, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL);
+ fwupd_release_remove_flag(release1, FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL);
+ fwupd_release_set_urgency(release1, FWUPD_RELEASE_URGENCY_MEDIUM);
+ data = fwupd_release_to_variant(release1);
+ release2 = fwupd_release_from_variant(data);
+ g_assert_cmpstr(fwupd_release_get_metadata_item(release2, "foo"), ==, "bar");
+ g_assert_cmpstr(fwupd_release_get_metadata_item(release2, "baz"), ==, "bam");
+ g_assert_cmpstr(fwupd_release_get_remote_id(release2), ==, "remote-id");
+ g_assert_cmpstr(fwupd_release_get_appstream_id(release2), ==, "appstream-id");
+ g_assert_cmpstr(fwupd_release_get_id(release2), ==, "id");
+ g_assert_cmpstr(fwupd_release_get_detach_caption(release2), ==, "detach_caption");
+ g_assert_cmpstr(fwupd_release_get_detach_image(release2), ==, "detach_image");
+ g_assert_cmpstr(fwupd_release_get_update_message(release2), ==, "update_message");
+ g_assert_cmpstr(fwupd_release_get_update_image(release2), ==, "update_image");
+ g_assert_cmpstr(fwupd_release_get_filename(release2), ==, "filename");
+ g_assert_cmpstr(fwupd_release_get_protocol(release2), ==, "protocol");
+ g_assert_cmpstr(fwupd_release_get_license(release2), ==, "license");
+ g_assert_cmpstr(fwupd_release_get_name(release2), ==, "name");
+ g_assert_cmpstr(fwupd_release_get_name_variant_suffix(release2), ==, "name_variant_suffix");
+ g_assert_cmpstr(fwupd_release_get_summary(release2), ==, "summary");
+ g_assert_cmpstr(fwupd_release_get_branch(release2), ==, "branch");
+ g_assert_cmpstr(fwupd_release_get_description(release2), ==, "description");
+ g_assert_cmpstr(fwupd_release_get_homepage(release2), ==, "homepage");
+ g_assert_cmpstr(fwupd_release_get_details_url(release2), ==, "details_url");
+ g_assert_cmpstr(fwupd_release_get_source_url(release2), ==, "source_url");
+ g_assert_cmpstr(fwupd_release_get_version(release2), ==, "version");
+ g_assert_cmpstr(fwupd_release_get_vendor(release2), ==, "vendor");
+ g_assert_cmpint(fwupd_release_get_size(release2), ==, 1234);
+ g_assert_cmpint(fwupd_release_get_created(release2), ==, 5678);
+ g_assert_true(fwupd_release_has_category(release2, "category"));
+ g_assert_true(fwupd_release_has_tag(release2, "tag"));
+ g_assert_true(fwupd_release_has_checksum(release2, "checksum"));
+ g_assert_true(fwupd_release_has_flag(release2, FWUPD_RELEASE_FLAG_IS_UPGRADE));
+ g_assert_false(fwupd_release_has_flag(release2, FWUPD_RELEASE_FLAG_IS_COMMUNITY));
+ g_assert_cmpint(fwupd_release_get_issues(release2)->len, ==, 1);
+ g_assert_cmpint(fwupd_release_get_locations(release2)->len, ==, 1);
+ g_assert_cmpint(fwupd_release_get_categories(release2)->len, ==, 1);
+ g_assert_cmpint(fwupd_release_get_tags(release2)->len, ==, 1);
+ g_assert_cmpint(fwupd_release_get_checksums(release2)->len, ==, 1);
+ g_assert_cmpint(fwupd_release_get_urgency(release2), ==, FWUPD_RELEASE_URGENCY_MEDIUM);
+ g_assert_cmpint(fwupd_release_get_install_duration(release2), ==, 2468);
+
+ /* to JSON */
+ json1 = fwupd_release_to_json_string(release1, &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json1);
+ json2 = fwupd_release_to_json_string(release2, &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json2);
+ ret = fu_test_compare_lines(json1, json2, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* to string */
+ str = fwupd_release_to_string(release2);
+ ret = fu_test_compare_lines(str,
+ " AppstreamId: appstream-id\n"
+ " ReleaseId: id\n"
+ " RemoteId: remote-id\n"
+ " Summary: summary\n"
+ " Description: description\n"
+ " Branch: branch\n"
+ " Version: version\n"
+ " Filename: filename\n"
+ " Protocol: protocol\n"
+ " Categories: category\n"
+ " Issues: issue\n"
+ " Checksum: SHA1(checksum)\n"
+ " Tags: tag\n"
+ " License: license\n"
+ " Size: 1.2 kB\n"
+ " Created: 1970-01-01\n"
+ " Uri: location\n"
+ " Homepage: homepage\n"
+ " DetailsUrl: details_url\n"
+ " SourceUrl: source_url\n"
+ " Urgency: medium\n"
+ " Vendor: vendor\n"
+ " Flags: is-upgrade\n"
+ " InstallDuration: 2468\n"
+ " DetachCaption: detach_caption\n"
+ " DetachImage: detach_image\n"
+ " UpdateMessage: update_message\n"
+ " UpdateImage: update_image\n"
+ " foo: bar\n"
+ " baz: bam\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+}
+
+static void
+fwupd_plugin_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *str = NULL;
+ g_autoptr(FwupdPlugin) plugin1 = NULL;
+ g_autoptr(FwupdPlugin) plugin2 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) data = NULL;
+
+ plugin1 = fwupd_plugin_new();
+ fwupd_plugin_set_name(plugin1, "foo");
+ fwupd_plugin_set_flags(plugin1, FWUPD_PLUGIN_FLAG_USER_WARNING);
+ fwupd_plugin_add_flag(plugin1, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE);
+ fwupd_plugin_add_flag(plugin1, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE);
+ fwupd_plugin_add_flag(plugin1, FWUPD_PLUGIN_FLAG_NO_HARDWARE);
+ fwupd_plugin_remove_flag(plugin1, FWUPD_PLUGIN_FLAG_NO_HARDWARE);
+ fwupd_plugin_remove_flag(plugin1, FWUPD_PLUGIN_FLAG_NO_HARDWARE);
+ data = fwupd_plugin_to_variant(plugin1);
+ plugin2 = fwupd_plugin_from_variant(data);
+ g_assert_cmpstr(fwupd_plugin_get_name(plugin2), ==, "foo");
+ g_assert_cmpint(fwupd_plugin_get_flags(plugin2),
+ ==,
+ FWUPD_PLUGIN_FLAG_USER_WARNING | FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE);
+ g_assert_true(fwupd_plugin_has_flag(plugin2, FWUPD_PLUGIN_FLAG_USER_WARNING));
+ g_assert_true(fwupd_plugin_has_flag(plugin2, FWUPD_PLUGIN_FLAG_CLEAR_UPDATABLE));
+ g_assert_false(fwupd_plugin_has_flag(plugin2, FWUPD_PLUGIN_FLAG_NO_HARDWARE));
+
+ str = fwupd_plugin_to_string(plugin2);
+ ret = fu_test_compare_lines(str,
+ " Name: foo\n"
+ " Flags: user-warning|clear-updatable\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+}
+
+static void
+fwupd_request_func(void)
+{
+ g_autofree gchar *str = NULL;
+ g_autoptr(FwupdRequest) request = fwupd_request_new();
+ g_autoptr(FwupdRequest) request2 = NULL;
+ g_autoptr(GVariant) data = NULL;
+
+ /* create dummy */
+ fwupd_request_set_kind(request, FWUPD_REQUEST_KIND_IMMEDIATE);
+ fwupd_request_set_id(request, FWUPD_REQUEST_ID_REMOVE_REPLUG);
+ fwupd_request_add_flag(request, FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE);
+ fwupd_request_set_message(request, "foo");
+ fwupd_request_set_image(request, "bar");
+ fwupd_request_set_device_id(request, "950da62d4c753a26e64f7f7d687104ce38e32ca5");
+ str = fwupd_request_to_string(request);
+ g_debug("%s", str);
+
+ g_assert_true(fwupd_request_has_flag(request, FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE));
+ g_assert_cmpint(fwupd_request_get_flags(request),
+ ==,
+ FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE);
+ fwupd_request_remove_flag(request, FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE);
+ g_assert_false(fwupd_request_has_flag(request, FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE));
+ g_assert_cmpint(fwupd_request_get_flags(request), ==, FWUPD_REQUEST_FLAG_NONE);
+
+ /* set in init */
+ g_assert_cmpint(fwupd_request_get_created(request), >, 0);
+
+ /* to serialized and back again */
+ data = fwupd_request_to_variant(request);
+ request2 = fwupd_request_from_variant(data);
+ g_assert_cmpint(fwupd_request_get_kind(request2), ==, FWUPD_REQUEST_KIND_IMMEDIATE);
+ g_assert_cmpint(fwupd_request_get_created(request2), >, 0);
+ g_assert_cmpstr(fwupd_request_get_id(request2), ==, FWUPD_REQUEST_ID_REMOVE_REPLUG);
+ g_assert_cmpstr(fwupd_request_get_message(request2), ==, "foo");
+ g_assert_cmpstr(fwupd_request_get_image(request2), ==, "bar");
+ g_assert_cmpstr(fwupd_request_get_device_id(request2),
+ ==,
+ "950da62d4c753a26e64f7f7d687104ce38e32ca5");
+}
+
+static void
+fwupd_device_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *data = NULL;
+ g_autofree gchar *str = NULL;
+ g_autoptr(FwupdDevice) dev = NULL;
+ g_autoptr(FwupdDevice) dev2 = fwupd_device_new();
+ g_autoptr(FwupdDevice) dev_new = fwupd_device_new();
+ 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;
+ g_autoptr(JsonParser) parser = json_parser_new();
+
+ /* create dummy object */
+ dev = fwupd_device_new();
+ fwupd_device_add_checksum(dev, "beefdead");
+ fwupd_device_set_created(dev, 1);
+ fwupd_device_add_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE);
+ fwupd_device_set_id(dev, "USB:foo");
+ fwupd_device_set_modified(dev, 60 * 60 * 24);
+ fwupd_device_set_name(dev, "ColorHug2");
+ fwupd_device_add_guid(dev, "2082b5e0-7a64-478a-b1b2-e3404fab6dad");
+ fwupd_device_add_guid(dev, "00000000-0000-0000-0000-000000000000");
+ fwupd_device_add_instance_id(dev, "USB\\VID_1234&PID_0001");
+ fwupd_device_add_icon(dev, "input-gaming");
+ fwupd_device_add_icon(dev, "input-mouse");
+ fwupd_device_add_vendor_id(dev, "USB:0x1234");
+ fwupd_device_add_vendor_id(dev, "PCI:0x5678");
+ fwupd_device_add_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE | FWUPD_DEVICE_FLAG_REQUIRE_AC);
+ g_assert_true(fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_REQUIRE_AC));
+ g_assert_true(fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_UPDATABLE));
+ g_assert_false(fwupd_device_has_flag(dev, FWUPD_DEVICE_FLAG_HISTORICAL));
+ rel = fwupd_release_new();
+ 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");
+ fwupd_release_set_appstream_id(rel, "org.dave.ColorHug.firmware");
+ fwupd_release_set_size(rel, 1024);
+ fwupd_release_add_location(rel, "http://foo.com");
+ fwupd_release_add_location(rel, "ftp://foo.com");
+ fwupd_release_add_tag(rel, "vendor-2021q1");
+ fwupd_release_add_tag(rel, "vendor-2021q2");
+ fwupd_release_set_version(rel, "1.2.3");
+ fwupd_device_add_release(dev, rel);
+ str = fwupd_device_to_string(dev);
+ g_print("\n%s", str);
+
+ /* check GUIDs */
+ g_assert_true(fwupd_device_has_guid(dev, "2082b5e0-7a64-478a-b1b2-e3404fab6dad"));
+ g_assert_true(fwupd_device_has_guid(dev, "00000000-0000-0000-0000-000000000000"));
+ g_assert_false(fwupd_device_has_guid(dev, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"));
+
+ /* 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,
+ "FwupdDevice:\n"
+ " DeviceId: USB:foo\n"
+ " Name: ColorHug2\n"
+ " Guid: 18f514d2-c12e-581f-a696-cc6d6c271699 "
+ "← USB\\VID_1234&PID_0001 ⚠\n"
+ " Guid: 2082b5e0-7a64-478a-b1b2-e3404fab6dad\n"
+ " Guid: 00000000-0000-0000-0000-000000000000\n"
+ " Flags: updatable|require-ac\n"
+ " Checksum: SHA1(beefdead)\n"
+ " VendorId: USB:0x1234\n"
+ " VendorId: PCI:0x5678\n"
+ " Icon: input-gaming,input-mouse\n"
+ " Created: 1970-01-01\n"
+ " Modified: 1970-01-02\n"
+ " \n"
+ " [Release]\n"
+ " AppstreamId: org.dave.ColorHug.firmware\n"
+ " Description: Hi there!
\n"
+ " Version: 1.2.3\n"
+ " Filename: firmware.bin\n"
+ " Checksum: SHA1(deadbeef)\n"
+ " Tags: vendor-2021q1\n"
+ " Tags: vendor-2021q2\n"
+ " Size: 1.0 kB\n"
+ " Uri: http://foo.com\n"
+ " Uri: ftp://foo.com\n"
+ " Flags: trusted-payload\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* export to json */
+ builder = json_builder_new();
+ json_builder_begin_object(builder);
+ fwupd_device_to_json_full(dev, builder, FWUPD_DEVICE_FLAG_TRUSTED);
+ 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"
+ " \"InstanceIds\" : [\n"
+ " \"USB\\\\VID_1234&PID_0001\"\n"
+ " ],\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"
+ " \"VendorId\" : \"USB:0x1234|PCI:0x5678\",\n"
+ " \"VendorIds\" : [\n"
+ " \"USB:0x1234\",\n"
+ " \"PCI:0x5678\"\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"
+ " \"Tags\" : [\n"
+ " \"vendor-2021q1\",\n"
+ " \"vendor-2021q2\"\n"
+ " ],\n"
+ " \"Size\" : 1024,\n"
+ " \"Locations\" : [\n"
+ " \"http://foo.com\",\n"
+ " \"ftp://foo.com\"\n"
+ " ],\n"
+ " \"Uri\" : \"http://foo.com\",\n"
+ " \"Flags\" : [\n"
+ " \"trusted-payload\"\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* incorporate */
+ fwupd_device_incorporate(dev_new, dev);
+ g_assert_true(fwupd_device_has_vendor_id(dev_new, "USB:0x1234"));
+ g_assert_true(fwupd_device_has_vendor_id(dev_new, "PCI:0x5678"));
+ g_assert_true(fwupd_device_has_instance_id(dev_new, "USB\\VID_1234&PID_0001"));
+
+ /* from JSON */
+ ret = json_parser_load_from_data(parser, data, -1, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ ret = fwupd_device_from_json(dev2, json_parser_get_root(parser), &error);
+ if (g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_test_skip(error->message);
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_true(fwupd_device_has_vendor_id(dev2, "USB:0x1234"));
+ g_assert_true(fwupd_device_has_instance_id(dev2, "USB\\VID_1234&PID_0001"));
+ g_assert_true(fwupd_device_has_flag(dev2, FWUPD_DEVICE_FLAG_UPDATABLE));
+ g_assert_false(fwupd_device_has_flag(dev2, FWUPD_DEVICE_FLAG_LOCKED));
+}
+
+static void
+fwupd_client_devices_func(void)
+{
+ FwupdDevice *dev;
+ gboolean ret;
+ g_autoptr(FwupdClient) client = NULL;
+ g_autoptr(GPtrArray) array = NULL;
+ g_autoptr(GError) error = NULL;
+
+ client = fwupd_client_new();
+
+ /* only run if running fwupd is new enough */
+ ret = fwupd_client_connect(client, NULL, &error);
+ if (ret == FALSE && (g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT) ||
+ g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER) ||
+ g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))) {
+ g_debug("%s", error->message);
+ g_test_skip("timeout connecting to daemon");
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ if (fwupd_client_get_daemon_version(client) == NULL) {
+ g_test_skip("no enabled fwupd daemon");
+ return;
+ }
+ if (!g_str_has_prefix(fwupd_client_get_daemon_version(client), "1.")) {
+ g_test_skip("running fwupd is too old");
+ return;
+ }
+
+ array = fwupd_client_get_devices(client, NULL, &error);
+ if (array == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) {
+ g_test_skip("no available fwupd devices");
+ return;
+ }
+ if (array == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_test_skip("no available fwupd daemon");
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_nonnull(array);
+ g_assert_cmpint(array->len, >, 0);
+
+ /* check device */
+ dev = g_ptr_array_index(array, 0);
+ g_assert_true(FWUPD_IS_DEVICE(dev));
+ g_assert_cmpstr(fwupd_device_get_guid_default(dev), !=, NULL);
+ g_assert_cmpstr(fwupd_device_get_id(dev), !=, NULL);
+}
+
+static void
+fwupd_client_remotes_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *remotesdir = NULL;
+ g_autoptr(FwupdClient) client = NULL;
+ g_autoptr(FwupdRemote) remote2 = NULL;
+ g_autoptr(FwupdRemote) remote3 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) array = NULL;
+
+ remotesdir = g_test_build_filename(G_TEST_DIST, "tests", "remotes.d", NULL);
+ (void)g_setenv("FU_SELF_TEST_REMOTES_DIR", remotesdir, TRUE);
+
+ client = fwupd_client_new();
+
+ /* only run if running fwupd is new enough */
+ ret = fwupd_client_connect(client, NULL, &error);
+ if (ret == FALSE && (g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT) ||
+ g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER) ||
+ g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))) {
+ g_debug("%s", error->message);
+ g_test_skip("timeout connecting to daemon");
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ if (fwupd_client_get_daemon_version(client) == NULL) {
+ g_test_skip("no enabled fwupd daemon");
+ return;
+ }
+ if (!g_str_has_prefix(fwupd_client_get_daemon_version(client), "1.")) {
+ g_test_skip("running fwupd is too old");
+ return;
+ }
+
+ array = fwupd_client_get_remotes(client, NULL, &error);
+ if (array == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) {
+ g_test_skip("no available fwupd remotes");
+ return;
+ }
+ if (array == NULL && g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_test_skip("no available fwupd daemon");
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_nonnull(array);
+ g_assert_cmpint(array->len, >, 0);
+
+ /* check we can find the right thing */
+ remote2 = fwupd_client_get_remote_by_id(client, "lvfs", NULL, &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(remote2);
+ g_assert_cmpstr(fwupd_remote_get_id(remote2), ==, "lvfs");
+ g_assert_nonnull(fwupd_remote_get_metadata_uri(remote2));
+
+ /* check we set an error when unfound */
+ remote3 = fwupd_client_get_remote_by_id(client, "XXXX", NULL, &error);
+ g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
+ g_assert_null(remote3);
+}
+
+static gboolean
+fwupd_has_system_bus(void)
+{
+ g_autoptr(GDBusConnection) conn = NULL;
+ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+ if (conn != NULL)
+ return TRUE;
+ g_debug("D-Bus system bus unavailable, skipping tests.");
+ return FALSE;
+}
+
+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;
+
+ if (!g_file_test("/etc/machine-id", G_FILE_TEST_EXISTS)) {
+ g_test_skip("Missing /etc/machine-id");
+ return;
+ }
+ if (!g_file_get_contents("/etc/machine-id", &buf, &sz, &error)) {
+ g_test_skip("/etc/machine-id is unreadable");
+ return;
+ }
+
+ if (sz == 0) {
+ g_test_skip("Empty /etc/machine-id");
+ return;
+ }
+
+ mhash1 = fwupd_build_machine_id("salt1", &error);
+ g_assert_no_error(error);
+ g_assert_cmpstr(mhash1, !=, NULL);
+ mhash2 = fwupd_build_machine_id("salt2", &error);
+ g_assert_no_error(error);
+ g_assert_cmpstr(mhash2, !=, NULL);
+ g_assert_cmpstr(mhash2, !=, mhash1);
+}
+
+static void
+fwupd_common_device_id_func(void)
+{
+ g_assert_false(fwupd_device_id_is_valid(NULL));
+ g_assert_false(fwupd_device_id_is_valid(""));
+ g_assert_false(fwupd_device_id_is_valid("1ff60ab2-3905-06a1-b476-0371f00c9e9b"));
+ g_assert_false(fwupd_device_id_is_valid("aaaaaad3fae86d95e5d56626129d00e332c4b8dac95442"));
+ g_assert_false(fwupd_device_id_is_valid("x3fae86d95e5d56626129d00e332c4b8dac95442"));
+ g_assert_false(fwupd_device_id_is_valid("D3FAE86D95E5D56626129D00E332C4B8DAC95442"));
+ g_assert_false(fwupd_device_id_is_valid(FWUPD_DEVICE_ID_ANY));
+ g_assert_true(fwupd_device_id_is_valid("d3fae86d95e5d56626129d00e332c4b8dac95442"));
+}
+
+static void
+fwupd_common_guid_func(void)
+{
+ const guint8 msbuf[] = "hello world!";
+ g_autofree gchar *guid1 = NULL;
+ g_autofree gchar *guid2 = NULL;
+ g_autofree gchar *guid3 = 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_false(fwupd_guid_is_valid(NULL));
+ g_assert_false(fwupd_guid_is_valid(""));
+ g_assert_false(fwupd_guid_is_valid("1ff60ab2-3905-06a1-b476"));
+ g_assert_false(fwupd_guid_is_valid("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b"));
+ g_assert_false(fwupd_guid_is_valid("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9bf"));
+ g_assert_false(fwupd_guid_is_valid(" 1ff60ab2-3905-06a1-b476-0371f00c9e9b"));
+ g_assert_false(fwupd_guid_is_valid("00000000-0000-0000-0000-000000000000"));
+
+ /* valid */
+ g_assert_true(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");
+
+ guid3 = fwupd_guid_hash_data(msbuf, sizeof(msbuf), FWUPD_GUID_FLAG_NAMESPACE_MICROSOFT);
+ g_assert_cmpstr(guid3, ==, "6836cfac-f77a-527f-b375-4f92f01449c5");
+
+ /* round-trip BE */
+ ret = fwupd_guid_from_string("00112233-4455-6677-8899-aabbccddeeff",
+ &buf,
+ FWUPD_GUID_FLAG_NONE,
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpint(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_no_error(error);
+ g_assert_true(ret);
+ g_assert_cmpint(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));
+}
+
+static gchar *
+fwupd_attr_to_json_string(GObject *attr, GError **error)
+{
+ g_autofree gchar *data = NULL;
+ g_autoptr(JsonGenerator) json_generator = NULL;
+ g_autoptr(JsonBuilder) builder = json_builder_new();
+ g_autoptr(JsonNode) json_root = NULL;
+ json_builder_begin_object(builder);
+ if (FWUPD_IS_SECURITY_ATTR(attr))
+ fwupd_security_attr_to_json(FWUPD_SECURITY_ATTR(attr), builder);
+ else if (FWUPD_IS_BIOS_SETTING(attr))
+ fwupd_bios_setting_to_json(FWUPD_BIOS_SETTING(attr), 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);
+ if (data == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "Failed to convert security attribute to json.");
+ return NULL;
+ }
+ return g_steal_pointer(&data);
+}
+
+static void
+fwupd_security_attr_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *str1 = NULL;
+ g_autofree gchar *str2 = NULL;
+ g_autofree gchar *str3 = NULL;
+ g_autofree gchar *json = NULL;
+ g_autoptr(FwupdSecurityAttr) attr1 = fwupd_security_attr_new("org.fwupd.hsi.bar");
+ g_autoptr(FwupdSecurityAttr) attr2 = fwupd_security_attr_new(NULL);
+ g_autoptr(FwupdSecurityAttr) attr3 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) data = NULL;
+ g_autoptr(JsonParser) parser = json_parser_new();
+
+ for (guint i = 1; i < FWUPD_SECURITY_ATTR_RESULT_LAST; i++) {
+ const gchar *tmp = fwupd_security_attr_result_to_string(i);
+ g_assert_cmpstr(tmp, !=, NULL);
+ g_assert_cmpint(fwupd_security_attr_result_from_string(tmp), ==, i);
+ }
+
+ g_assert_cmpstr(fwupd_security_attr_get_appstream_id(attr1), ==, "org.fwupd.hsi.bar");
+ fwupd_security_attr_set_appstream_id(attr1, "org.fwupd.hsi.baz");
+ g_assert_cmpstr(fwupd_security_attr_get_appstream_id(attr1), ==, "org.fwupd.hsi.baz");
+
+ fwupd_security_attr_set_level(attr1, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT);
+ g_assert_cmpint(fwupd_security_attr_get_level(attr1),
+ ==,
+ FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT);
+
+ fwupd_security_attr_set_result(attr1, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
+ g_assert_cmpint(fwupd_security_attr_get_result(attr1),
+ ==,
+ FWUPD_SECURITY_ATTR_RESULT_ENABLED);
+
+ fwupd_security_attr_add_flag(attr1, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
+ fwupd_security_attr_add_flag(attr1, FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA);
+ fwupd_security_attr_remove_flag(attr1, FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA);
+ g_assert_true(fwupd_security_attr_has_flag(attr1, FWUPD_SECURITY_ATTR_FLAG_SUCCESS));
+ g_assert_false(fwupd_security_attr_has_flag(attr1, FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA));
+ g_assert_false(fwupd_security_attr_has_flag(attr1, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED));
+
+ fwupd_security_attr_set_name(attr1, "DCI");
+ g_assert_cmpstr(fwupd_security_attr_get_name(attr1), ==, "DCI");
+
+ fwupd_security_attr_set_plugin(attr1, "uefi-capsule");
+ g_assert_cmpstr(fwupd_security_attr_get_plugin(attr1), ==, "uefi-capsule");
+
+ fwupd_security_attr_set_url(attr1, "https://foo.bar");
+ g_assert_cmpstr(fwupd_security_attr_get_url(attr1), ==, "https://foo.bar");
+
+ fwupd_security_attr_add_guid(attr1, "af3fc12c-d090-5783-8a67-845b90d3cfec");
+ g_assert_true(fwupd_security_attr_has_guid(attr1, "af3fc12c-d090-5783-8a67-845b90d3cfec"));
+ g_assert_false(fwupd_security_attr_has_guid(attr1, "NOT_GOING_TO_EXIST"));
+
+ fwupd_security_attr_add_metadata(attr1, "KEY", "VALUE");
+ g_assert_cmpstr(fwupd_security_attr_get_metadata(attr1, "KEY"), ==, "VALUE");
+
+ /* remove this from the output */
+ fwupd_security_attr_set_created(attr1, 0);
+
+ str1 = fwupd_security_attr_to_string(attr1);
+ ret = fu_test_compare_lines(str1,
+ " AppstreamId: org.fwupd.hsi.baz\n"
+ " HsiLevel: 2\n"
+ " HsiResult: enabled\n"
+ " Flags: success\n"
+ " Name: DCI\n"
+ " Plugin: uefi-capsule\n"
+ " Uri: https://foo.bar\n"
+ " Guid: af3fc12c-d090-5783-8a67-845b90d3cfec\n"
+ " KEY: VALUE\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* roundtrip GVariant */
+ data = fwupd_security_attr_to_variant(attr1);
+ attr3 = fwupd_security_attr_from_variant(data);
+ fwupd_security_attr_set_created(attr3, 0);
+ str3 = fwupd_security_attr_to_string(attr3);
+ ret = fu_test_compare_lines(str3,
+ " AppstreamId: org.fwupd.hsi.baz\n"
+ " HsiLevel: 2\n"
+ " HsiResult: enabled\n"
+ " Flags: success\n"
+ " Name: DCI\n"
+ " Plugin: uefi-capsule\n"
+ " Uri: https://foo.bar\n"
+ " Guid: af3fc12c-d090-5783-8a67-845b90d3cfec\n"
+ " KEY: VALUE\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* to JSON */
+ json = fwupd_attr_to_json_string(G_OBJECT(attr1), &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json);
+ ret = fu_test_compare_lines(json,
+ "{\n"
+ " \"AppstreamId\" : \"org.fwupd.hsi.baz\",\n"
+ " \"HsiLevel\" : 2,\n"
+ " \"HsiResult\" : \"enabled\",\n"
+ " \"Name\" : \"DCI\",\n"
+ " \"Plugin\" : \"uefi-capsule\",\n"
+ " \"Uri\" : \"https://foo.bar\",\n"
+ " \"Flags\" : [\n"
+ " \"success\"\n"
+ " ],\n"
+ " \"Guid\" : [\n"
+ " \"af3fc12c-d090-5783-8a67-845b90d3cfec\"\n"
+ " ],\n"
+ " \"KEY\" : \"VALUE\"\n"
+ "}",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* from JSON */
+ ret = json_parser_load_from_data(parser, json, -1, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ ret = fwupd_security_attr_from_json(attr2, json_parser_get_root(parser), &error);
+ if (g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_test_skip(error->message);
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* we don't load unconditionally load metadata from the JSON */
+ fwupd_security_attr_add_metadata(attr2, "KEY", "VALUE");
+
+ str2 = fwupd_security_attr_to_string(attr2);
+ ret = fu_test_compare_lines(str2, str1, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+}
+
+static void
+fwupd_bios_settings_func(void)
+{
+ gboolean ret;
+ g_autofree gchar *str1 = NULL;
+ g_autofree gchar *str2 = NULL;
+ g_autofree gchar *str3 = NULL;
+ g_autofree gchar *json1 = NULL;
+ g_autofree gchar *json2 = NULL;
+ g_autoptr(FwupdBiosSetting) attr1 = fwupd_bios_setting_new("foo", "/path/to/bar");
+ g_autoptr(FwupdBiosSetting) attr2 = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GVariant) data1 = NULL;
+ g_autoptr(GVariant) data2 = NULL;
+ g_autoptr(JsonParser) parser = json_parser_new();
+
+ g_assert_cmpstr(fwupd_bios_setting_get_name(attr1), ==, "foo");
+ fwupd_bios_setting_set_name(attr1, "UEFISecureBoot");
+ g_assert_cmpstr(fwupd_bios_setting_get_name(attr1), ==, "UEFISecureBoot");
+
+ fwupd_bios_setting_set_kind(attr1, FWUPD_BIOS_SETTING_KIND_ENUMERATION);
+ g_assert_cmpint(fwupd_bios_setting_get_kind(attr1),
+ ==,
+ FWUPD_BIOS_SETTING_KIND_ENUMERATION);
+
+ fwupd_bios_setting_set_description(attr1, "Controls Secure boot");
+ g_assert_cmpstr(fwupd_bios_setting_get_description(attr1), ==, "Controls Secure boot");
+ fwupd_bios_setting_set_current_value(attr1, "Disabled");
+ g_assert_cmpstr(fwupd_bios_setting_get_current_value(attr1), ==, "Disabled");
+
+ fwupd_bios_setting_add_possible_value(attr1, "Disabled");
+ fwupd_bios_setting_add_possible_value(attr1, "Enabled");
+ g_assert_true(fwupd_bios_setting_has_possible_value(attr1, "Disabled"));
+ g_assert_false(fwupd_bios_setting_has_possible_value(attr1, "NOT_GOING_TO_EXIST"));
+
+ str1 = fwupd_bios_setting_to_string(attr1);
+ ret = fu_test_compare_lines(str1,
+ " Name: UEFISecureBoot\n"
+ " Description: Controls Secure boot\n"
+ " Filename: /path/to/bar\n"
+ " BiosSettingType: 1\n"
+ " BiosSettingCurrentValue: Disabled\n"
+ " BiosSettingReadOnly: False\n"
+ " BiosSettingPossibleValues: Disabled\n"
+ " BiosSettingPossibleValues: Enabled\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* roundtrip GVariant */
+ data1 = fwupd_bios_setting_to_variant(attr1, TRUE);
+ attr2 = fwupd_bios_setting_from_variant(data1);
+ str2 = fwupd_bios_setting_to_string(attr2);
+ ret = fu_test_compare_lines(str2,
+ " Name: UEFISecureBoot\n"
+ " Description: Controls Secure boot\n"
+ " Filename: /path/to/bar\n"
+ " BiosSettingType: 1\n"
+ " BiosSettingCurrentValue: Disabled\n"
+ " BiosSettingReadOnly: False\n"
+ " BiosSettingPossibleValues: Disabled\n"
+ " BiosSettingPossibleValues: Enabled\n",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* to JSON */
+ json1 = fwupd_attr_to_json_string(G_OBJECT(attr1), &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json1);
+ ret = fu_test_compare_lines(json1,
+ "{\n"
+ " \"Name\" : \"UEFISecureBoot\",\n"
+ " \"Description\" : \"Controls Secure boot\",\n"
+ " \"Filename\" : \"/path/to/bar\",\n"
+ " \"BiosSettingCurrentValue\" : \"Disabled\",\n"
+ " \"BiosSettingReadOnly\" : \"false\",\n"
+ " \"BiosSettingType\" : 1,\n"
+ " \"BiosSettingPossibleValues\" : [\n"
+ " \"Disabled\",\n"
+ " \"Enabled\"\n"
+ " ]\n"
+ "}",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* from JSON */
+ ret = json_parser_load_from_data(parser, json1, -1, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+ ret = fwupd_bios_setting_from_json(attr2, json_parser_get_root(parser), &error);
+ if (g_error_matches(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_test_skip(error->message);
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ str3 = fwupd_bios_setting_to_string(attr2);
+ ret = fu_test_compare_lines(str3, str1, &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+
+ /* make sure we filter CurrentValue if not trusted */
+ data2 = fwupd_bios_setting_to_variant(attr1, TRUE);
+ json2 = fwupd_attr_to_json_string(G_OBJECT(attr1), &error);
+ g_assert_no_error(error);
+ g_assert_nonnull(json2);
+ ret = fu_test_compare_lines(json2,
+ "{\n"
+ " \"Name\" : \"UEFISecureBoot\",\n"
+ " \"Description\" : \"Controls Secure boot\",\n"
+ " \"Filename\" : \"/path/to/bar\",\n"
+ " \"BiosSettingCurrentValue\" : \"Disabled\",\n"
+ " \"BiosSettingReadOnly\" : \"false\",\n"
+ " \"BiosSettingType\" : 1,\n"
+ " \"BiosSettingPossibleValues\" : [\n"
+ " \"Disabled\",\n"
+ " \"Enabled\"\n"
+ " ]\n"
+ "}",
+ &error);
+ g_assert_no_error(error);
+ g_assert_true(ret);
+}
+
+int
+main(int argc, char **argv)
+{
+ setlocale(LC_ALL, "");
+ 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);
+ (void)g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
+
+ /* 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{device-id}", fwupd_common_device_id_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/plugin", fwupd_plugin_func);
+ g_test_add_func("/fwupd/request", fwupd_request_func);
+ g_test_add_func("/fwupd/device", fwupd_device_func);
+ g_test_add_func("/fwupd/security-attr", fwupd_security_attr_func);
+ g_test_add_func("/fwupd/remote{download}", fwupd_remote_download_func);
+ g_test_add_func("/fwupd/remote{base-uri}", fwupd_remote_baseuri_func);
+ g_test_add_func("/fwupd/remote{no-path}", fwupd_remote_nopath_func);
+ g_test_add_func("/fwupd/remote{local}", fwupd_remote_local_func);
+ g_test_add_func("/fwupd/remote{duplicate}", fwupd_remote_duplicate_func);
+ g_test_add_func("/fwupd/remote{auth}", fwupd_remote_auth_func);
+ g_test_add_func("/fwupd/bios-attrs", fwupd_bios_settings_func);
+ if (fwupd_has_system_bus()) {
+ g_test_add_func("/fwupd/client{remotes}", fwupd_client_remotes_func);
+ g_test_add_func("/fwupd/client{devices}", fwupd_client_devices_func);
+ }
+ return g_test_run();
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-thread-test.c b/fwupd-1.8.6/libfwupd/fwupd-thread-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..61a7e424f72c567dd91f4589b6b648d99d1d5ff9
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-thread-test.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 Philip Withnall
+ * Copyright (C) 2020 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include
+
+typedef struct {
+ GApplication *app;
+ FwupdClient *client;
+ GPtrArray *worker_threads;
+} FuThreadTestSelf;
+
+static gboolean
+fwupd_thread_test_exit_idle_cb(gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_application_release(self->app);
+ return G_SOURCE_REMOVE;
+}
+
+static gpointer
+fwupd_thread_test_thread_cb(gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) devices = NULL;
+ g_autoptr(GMainContext) context = g_main_context_new();
+ g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new(context);
+
+ g_assert_nonnull(pusher);
+ g_message("Calling fwupd_client_get_devices() in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+ devices = fwupd_client_get_devices(self->client, NULL, &error_local);
+ if (devices == NULL)
+ g_warning("%s", error_local->message);
+ g_idle_add(fwupd_thread_test_exit_idle_cb, self);
+ return NULL;
+}
+
+static gboolean
+fwupd_thread_test_idle_cb(gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+
+ g_message("fwupd_thread_test_idle_cb() in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+
+ /* create 'n' threads with a small delay, and 'n-1' references on the app */
+ for (guint i = 0; i < 30; i++) {
+ g_autofree gchar *thread_str = g_strdup_printf("worker%02u", i);
+ GThread *thread = g_thread_new(thread_str, fwupd_thread_test_thread_cb, self);
+ g_usleep(g_random_int_range(0, 1000));
+ g_ptr_array_add(self->worker_threads, thread);
+ if (i > 0)
+ g_application_hold(self->app);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+fwupd_thread_test_activate_cb(GApplication *app, gpointer user_data)
+{
+ FuThreadTestSelf *self = user_data;
+ g_application_hold(self->app);
+ g_idle_add(fwupd_thread_test_idle_cb, self);
+}
+
+static gboolean
+fwupd_thread_test_has_system_bus(void)
+{
+ g_autoptr(GDBusConnection) conn = NULL;
+ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+ return conn != NULL;
+}
+
+int
+main(void)
+{
+ gint retval;
+ g_autoptr(FwupdClient) client = fwupd_client_new();
+ g_autoptr(GApplication) app = g_application_new("org.test.Test", G_APPLICATION_NON_UNIQUE);
+ g_autoptr(GPtrArray) worker_threads = g_ptr_array_new();
+ FuThreadTestSelf self = {app, client, worker_threads};
+
+ /* only some of the CI targets have a DBus daemon */
+ if (!fwupd_thread_test_has_system_bus()) {
+ g_message("D-Bus system bus unavailable, skipping tests.");
+ return 0;
+ }
+
+ g_message("Created FwupdClient in thread %p with main context %p",
+ g_thread_self(),
+ g_main_context_get_thread_default());
+ g_signal_connect(G_APPLICATION(app),
+ "activate",
+ G_CALLBACK(fwupd_thread_test_activate_cb),
+ &self);
+ retval = g_application_run(app, 0, NULL);
+ for (guint i = 0; i < self.worker_threads->len; i++) {
+ GThread *thread = g_ptr_array_index(self.worker_threads, i);
+ g_thread_join(thread);
+ }
+
+ return retval;
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-version.c b/fwupd-1.8.6/libfwupd/fwupd-version.c
new file mode 100644
index 0000000000000000000000000000000000000000..966bd2b010b0fbaaddfeafeb8b83b1f0badf4884
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-version.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fwupd-version.h"
+
+/**
+ * fwupd_version_string:
+ *
+ * Gets the libfwupd installed runtime version.
+ *
+ * This may be different to the *build-time* version if the daemon and library
+ * objects somehow get out of sync.
+ *
+ * Returns: version string
+ *
+ * Since: 1.6.1
+ **/
+const gchar *
+fwupd_version_string(void)
+{
+ return G_STRINGIFY(FWUPD_MAJOR_VERSION) "." G_STRINGIFY(
+ FWUPD_MINOR_VERSION) "." G_STRINGIFY(FWUPD_MICRO_VERSION);
+}
diff --git a/fwupd-1.8.6/libfwupd/fwupd-version.h.in b/fwupd-1.8.6/libfwupd/fwupd-version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..77e4a1ccd3e14f53d09b6a61f2bef8313145dd4d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd-version.h.in
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#if !defined(__FWUPD_H_INSIDE__) && !defined(FWUPD_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+/* clang-format off */
+/**
+ * FWUPD_MAJOR_VERSION:
+ *
+ * The compile-time major version
+ */
+#define FWUPD_MAJOR_VERSION @MAJOR_VERSION@
+
+/**
+ * FWUPD_MINOR_VERSION:
+ *
+ * The compile-time minor version
+ */
+#define FWUPD_MINOR_VERSION @MINOR_VERSION@
+
+/**
+ * FWUPD_MICRO_VERSION:
+ *
+ * The compile-time micro version
+ */
+#define FWUPD_MICRO_VERSION @MICRO_VERSION@
+/* clang-format on */
+
+/**
+ * FWUPD_CHECK_VERSION:
+ * @major: Major version number
+ * @minor: Minor version number
+ * @micro: Micro version number
+ *
+ * Check whether a fwupd version equal to or greater than
+ * major.minor.micro.
+ *
+ * These compile time macros allow the user to enable parts of client code
+ * depending on the version of libfwupd installed.
+ */
+#define FWUPD_CHECK_VERSION(major, minor, micro) \
+ (FWUPD_MAJOR_VERSION > major || \
+ (FWUPD_MAJOR_VERSION == major && FWUPD_MINOR_VERSION > minor) || \
+ (FWUPD_MAJOR_VERSION == major && FWUPD_MINOR_VERSION == minor && \
+ FWUPD_MICRO_VERSION >= micro))
+
+const gchar *
+fwupd_version_string(void);
diff --git a/fwupd-1.8.6/libfwupd/fwupd.h b/fwupd-1.8.6/libfwupd/fwupd.h
new file mode 100644
index 0000000000000000000000000000000000000000..74a56e806f37ef8e37bc500b00bde5e0fa15020d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#define __FWUPD_H_INSIDE__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef FWUPD_DISABLE_DEPRECATED
+#include
+#endif
+
+#undef __FWUPD_H_INSIDE__
diff --git a/fwupd-1.8.6/libfwupd/fwupd.map b/fwupd-1.8.6/libfwupd/fwupd.map
new file mode 100644
index 0000000000000000000000000000000000000000..ebc653df4fe56bf19977e89a92362c25f05a957d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/fwupd.map
@@ -0,0 +1,863 @@
+# generated automatically, do not edit!
+
+LIBFWUPD_0.1.1 {
+ global:
+ fwupd_error_quark;
+ fwupd_status_from_string;
+ fwupd_status_to_string;
+ local: *;
+};
+
+LIBFWUPD_0.7.0 {
+ global:
+ fwupd_client_clear_results;
+ fwupd_client_get_results;
+ fwupd_client_get_type;
+ fwupd_client_install;
+ fwupd_client_new;
+ fwupd_client_unlock;
+ fwupd_client_verify;
+ fwupd_device_flag_from_string;
+ fwupd_device_flag_to_string;
+ fwupd_error_from_string;
+ fwupd_error_to_string;
+ fwupd_trust_flag_from_string;
+ fwupd_trust_flag_to_string;
+ fwupd_update_state_from_string;
+ fwupd_update_state_to_string;
+ local: *;
+} LIBFWUPD_0.1.1;
+
+LIBFWUPD_0.7.1 {
+ global:
+ fwupd_client_connect;
+ local: *;
+} LIBFWUPD_0.7.0;
+
+LIBFWUPD_0.7.3 {
+ global:
+ fwupd_client_get_percentage;
+ fwupd_client_get_status;
+ local: *;
+} LIBFWUPD_0.7.1;
+
+LIBFWUPD_0.8.0 {
+ global:
+ fwupd_client_verify_update;
+ local: *;
+} LIBFWUPD_0.7.3;
+
+LIBFWUPD_0.9.2 {
+ global:
+ fwupd_client_get_devices;
+ local: *;
+} LIBFWUPD_0.8.0;
+
+LIBFWUPD_0.9.3 {
+ global:
+ fwupd_checksum_format_for_display;
+ fwupd_checksum_guess_kind;
+ fwupd_client_get_device_by_id;
+ fwupd_client_get_releases;
+ fwupd_client_get_remote_by_id;
+ fwupd_client_get_remotes;
+ fwupd_device_add_checksum;
+ fwupd_device_add_flag;
+ fwupd_device_add_guid;
+ fwupd_device_get_checksums;
+ fwupd_device_get_created;
+ fwupd_device_get_description;
+ fwupd_device_get_flags;
+ fwupd_device_get_flashes_left;
+ fwupd_device_get_guid_default;
+ fwupd_device_get_guids;
+ fwupd_device_get_id;
+ fwupd_device_get_modified;
+ fwupd_device_get_name;
+ fwupd_device_get_summary;
+ fwupd_device_get_type;
+ fwupd_device_get_vendor;
+ fwupd_device_get_version;
+ fwupd_device_get_version_bootloader;
+ fwupd_device_get_version_lowest;
+ fwupd_device_has_flag;
+ fwupd_device_has_guid;
+ fwupd_device_new;
+ fwupd_device_remove_flag;
+ fwupd_device_set_created;
+ fwupd_device_set_description;
+ fwupd_device_set_flags;
+ fwupd_device_set_flashes_left;
+ fwupd_device_set_id;
+ fwupd_device_set_modified;
+ fwupd_device_set_name;
+ fwupd_device_set_summary;
+ fwupd_device_set_vendor;
+ fwupd_device_set_version;
+ fwupd_device_set_version_bootloader;
+ fwupd_device_set_version_lowest;
+ fwupd_device_to_string;
+ fwupd_release_add_checksum;
+ fwupd_release_get_appstream_id;
+ fwupd_release_get_checksums;
+ fwupd_release_get_description;
+ fwupd_release_get_filename;
+ fwupd_release_get_homepage;
+ fwupd_release_get_license;
+ fwupd_release_get_name;
+ fwupd_release_get_remote_id;
+ fwupd_release_get_size;
+ fwupd_release_get_summary;
+ fwupd_release_get_type;
+ fwupd_release_get_uri;
+ fwupd_release_get_vendor;
+ fwupd_release_get_version;
+ fwupd_release_new;
+ fwupd_release_set_appstream_id;
+ fwupd_release_set_description;
+ fwupd_release_set_filename;
+ fwupd_release_set_homepage;
+ fwupd_release_set_license;
+ fwupd_release_set_name;
+ fwupd_release_set_remote_id;
+ fwupd_release_set_size;
+ fwupd_release_set_summary;
+ fwupd_release_set_uri;
+ fwupd_release_set_vendor;
+ fwupd_release_set_version;
+ fwupd_release_to_string;
+ fwupd_remote_get_enabled;
+ fwupd_remote_get_id;
+ fwupd_remote_get_type;
+ fwupd_remote_load_from_filename;
+ fwupd_remote_new;
+ local: *;
+} LIBFWUPD_0.9.2;
+
+LIBFWUPD_0.9.4 {
+ global:
+ fwupd_checksum_get_best;
+ fwupd_checksum_get_by_kind;
+ fwupd_device_get_vendor_id;
+ fwupd_device_set_vendor_id;
+ local: *;
+} LIBFWUPD_0.9.3;
+
+LIBFWUPD_0.9.5 {
+ global:
+ fwupd_remote_get_age;
+ fwupd_remote_get_order_after;
+ fwupd_remote_get_order_before;
+ fwupd_remote_get_password;
+ fwupd_remote_get_priority;
+ fwupd_remote_get_username;
+ fwupd_remote_set_mtime;
+ fwupd_remote_set_priority;
+ local: *;
+} LIBFWUPD_0.9.4;
+
+LIBFWUPD_0.9.6 {
+ global:
+ fwupd_client_get_daemon_version;
+ fwupd_remote_get_filename_cache;
+ fwupd_remote_get_kind;
+ fwupd_remote_kind_from_string;
+ fwupd_remote_kind_to_string;
+ local: *;
+} LIBFWUPD_0.9.5;
+
+LIBFWUPD_0.9.7 {
+ global:
+ fwupd_keyring_kind_from_string;
+ fwupd_keyring_kind_to_string;
+ fwupd_remote_build_firmware_uri;
+ fwupd_remote_get_filename_cache_sig;
+ fwupd_remote_get_firmware_base_uri;
+ fwupd_remote_get_keyring_kind;
+ fwupd_remote_get_metadata_uri;
+ fwupd_remote_get_metadata_uri_sig;
+ local: *;
+} LIBFWUPD_0.9.6;
+
+LIBFWUPD_0.9.8 {
+ global:
+ fwupd_client_get_downgrades;
+ fwupd_client_get_upgrades;
+ fwupd_client_modify_remote;
+ fwupd_device_add_icon;
+ fwupd_device_add_release;
+ fwupd_device_get_icons;
+ fwupd_device_get_release_default;
+ fwupd_device_get_releases;
+ fwupd_device_get_update_error;
+ fwupd_device_get_update_state;
+ fwupd_device_set_update_error;
+ fwupd_device_set_update_state;
+ fwupd_release_get_trust_flags;
+ fwupd_release_set_trust_flags;
+ fwupd_remote_get_filename_source;
+ fwupd_remote_get_title;
+ local: *;
+} LIBFWUPD_0.9.7;
+
+LIBFWUPD_1.0.0 {
+ global:
+ fwupd_client_get_details;
+ fwupd_client_update_metadata;
+ fwupd_device_from_variant;
+ fwupd_device_get_plugin;
+ fwupd_device_set_plugin;
+ fwupd_device_to_variant;
+ fwupd_release_from_variant;
+ fwupd_release_to_variant;
+ fwupd_remote_from_variant;
+ fwupd_remote_get_checksum;
+ fwupd_remote_to_variant;
+ local: *;
+} LIBFWUPD_0.9.8;
+
+LIBFWUPD_1.0.3 {
+ global:
+ fwupd_build_user_agent;
+ local: *;
+} LIBFWUPD_1.0.0;
+
+LIBFWUPD_1.0.4 {
+ global:
+ fwupd_build_history_report_json;
+ fwupd_build_machine_id;
+ fwupd_client_get_history;
+ fwupd_client_modify_device;
+ fwupd_release_add_metadata;
+ fwupd_release_add_metadata_item;
+ fwupd_release_get_metadata;
+ fwupd_release_get_metadata_item;
+ 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;
+
+LIBFWUPD_1.3.1 {
+ global:
+ fwupd_client_get_host_product;
+ fwupd_remote_get_remotes_dir;
+ fwupd_remote_set_remotes_dir;
+ local: *;
+} LIBFWUPD_1.2.10;
+
+LIBFWUPD_1.3.2 {
+ global:
+ fwupd_client_get_host_machine_id;
+ fwupd_release_add_issue;
+ fwupd_release_get_issues;
+ fwupd_release_get_name_variant_suffix;
+ fwupd_release_set_name_variant_suffix;
+ local: *;
+} LIBFWUPD_1.3.1;
+
+LIBFWUPD_1.3.3 {
+ global:
+ fwupd_release_get_detach_caption;
+ fwupd_release_get_detach_image;
+ fwupd_release_set_detach_caption;
+ fwupd_release_set_detach_image;
+ fwupd_remote_get_automatic_reports;
+ local: *;
+} LIBFWUPD_1.3.2;
+
+LIBFWUPD_1.3.4 {
+ global:
+ fwupd_client_get_daemon_interactive;
+ local: *;
+} LIBFWUPD_1.3.3;
+
+LIBFWUPD_1.3.6 {
+ global:
+ fwupd_device_get_protocol;
+ fwupd_device_get_version_raw;
+ fwupd_device_set_protocol;
+ fwupd_device_set_version_raw;
+ local: *;
+} LIBFWUPD_1.3.4;
+
+LIBFWUPD_1.3.7 {
+ global:
+ fwupd_device_array_ensure_parents;
+ fwupd_device_get_children;
+ local: *;
+} LIBFWUPD_1.3.6;
+
+LIBFWUPD_1.4.0 {
+ global:
+ fwupd_device_get_status;
+ fwupd_device_get_version_bootloader_raw;
+ fwupd_device_get_version_lowest_raw;
+ fwupd_device_set_status;
+ fwupd_device_set_version_bootloader_raw;
+ fwupd_device_set_version_lowest_raw;
+ fwupd_release_get_created;
+ fwupd_release_get_urgency;
+ fwupd_release_set_created;
+ fwupd_release_set_urgency;
+ fwupd_release_urgency_from_string;
+ fwupd_release_urgency_to_string;
+ fwupd_remote_load_signature;
+ local: *;
+} LIBFWUPD_1.3.7;
+
+LIBFWUPD_1.4.1 {
+ global:
+ fwupd_client_get_devices_by_guid;
+ fwupd_device_id_is_valid;
+ local: *;
+} LIBFWUPD_1.4.0;
+
+LIBFWUPD_1.4.5 {
+ global:
+ fwupd_client_download_bytes;
+ fwupd_client_ensure_networking;
+ fwupd_client_install_bytes;
+ fwupd_client_install_release;
+ fwupd_client_refresh_remote;
+ fwupd_client_set_feature_flags;
+ fwupd_client_set_user_agent;
+ fwupd_client_set_user_agent_for_package;
+ fwupd_client_update_metadata_bytes;
+ fwupd_client_upload_bytes;
+ fwupd_device_get_update_image;
+ fwupd_device_set_update_image;
+ fwupd_feature_flag_from_string;
+ fwupd_feature_flag_to_string;
+ fwupd_release_get_update_image;
+ fwupd_release_set_update_image;
+ fwupd_remote_load_signature_bytes;
+ local: *;
+} LIBFWUPD_1.4.1;
+
+LIBFWUPD_1.4.6 {
+ global:
+ fwupd_client_get_blocked_firmware;
+ fwupd_client_set_blocked_firmware;
+ local: *;
+} LIBFWUPD_1.4.5;
+
+LIBFWUPD_1.5.0 {
+ global:
+ fwupd_client_activate_async;
+ fwupd_client_activate_finish;
+ fwupd_client_clear_results_async;
+ fwupd_client_clear_results_finish;
+ fwupd_client_connect_async;
+ fwupd_client_connect_finish;
+ fwupd_client_download_bytes_async;
+ fwupd_client_download_bytes_finish;
+ fwupd_client_get_approved_firmware_async;
+ fwupd_client_get_approved_firmware_finish;
+ fwupd_client_get_blocked_firmware_async;
+ fwupd_client_get_blocked_firmware_finish;
+ fwupd_client_get_details_bytes;
+ fwupd_client_get_details_bytes_async;
+ fwupd_client_get_details_bytes_finish;
+ fwupd_client_get_device_by_id_async;
+ fwupd_client_get_device_by_id_finish;
+ fwupd_client_get_devices_async;
+ fwupd_client_get_devices_by_guid_async;
+ fwupd_client_get_devices_by_guid_finish;
+ fwupd_client_get_devices_finish;
+ fwupd_client_get_downgrades_async;
+ fwupd_client_get_downgrades_finish;
+ fwupd_client_get_history_async;
+ fwupd_client_get_history_finish;
+ fwupd_client_get_host_security_attrs;
+ fwupd_client_get_host_security_attrs_async;
+ fwupd_client_get_host_security_attrs_finish;
+ fwupd_client_get_host_security_id;
+ fwupd_client_get_plugins;
+ fwupd_client_get_plugins_async;
+ fwupd_client_get_plugins_finish;
+ fwupd_client_get_releases_async;
+ fwupd_client_get_releases_finish;
+ fwupd_client_get_remote_by_id_async;
+ fwupd_client_get_remote_by_id_finish;
+ fwupd_client_get_remotes_async;
+ fwupd_client_get_remotes_finish;
+ fwupd_client_get_report_metadata;
+ fwupd_client_get_report_metadata_async;
+ fwupd_client_get_report_metadata_finish;
+ fwupd_client_get_results_async;
+ fwupd_client_get_results_finish;
+ fwupd_client_get_upgrades_async;
+ fwupd_client_get_upgrades_finish;
+ fwupd_client_install_async;
+ fwupd_client_install_bytes_async;
+ fwupd_client_install_bytes_finish;
+ fwupd_client_install_finish;
+ fwupd_client_install_release_async;
+ fwupd_client_install_release_finish;
+ fwupd_client_modify_config_async;
+ fwupd_client_modify_config_finish;
+ fwupd_client_modify_device_async;
+ fwupd_client_modify_device_finish;
+ fwupd_client_modify_remote_async;
+ fwupd_client_modify_remote_finish;
+ fwupd_client_refresh_remote_async;
+ fwupd_client_refresh_remote_finish;
+ fwupd_client_self_sign_async;
+ fwupd_client_self_sign_finish;
+ fwupd_client_set_approved_firmware_async;
+ fwupd_client_set_approved_firmware_finish;
+ fwupd_client_set_blocked_firmware_async;
+ fwupd_client_set_blocked_firmware_finish;
+ fwupd_client_set_feature_flags_async;
+ fwupd_client_set_feature_flags_finish;
+ fwupd_client_unlock_async;
+ fwupd_client_unlock_finish;
+ fwupd_client_update_metadata_bytes_async;
+ fwupd_client_update_metadata_bytes_finish;
+ fwupd_client_upload_bytes_async;
+ fwupd_client_upload_bytes_finish;
+ fwupd_client_verify_async;
+ fwupd_client_verify_finish;
+ fwupd_client_verify_update_async;
+ fwupd_client_verify_update_finish;
+ fwupd_device_get_branch;
+ fwupd_device_set_branch;
+ fwupd_plugin_add_flag;
+ fwupd_plugin_array_from_variant;
+ fwupd_plugin_flag_from_string;
+ fwupd_plugin_flag_to_string;
+ fwupd_plugin_from_variant;
+ fwupd_plugin_get_flags;
+ fwupd_plugin_get_name;
+ fwupd_plugin_get_type;
+ fwupd_plugin_has_flag;
+ fwupd_plugin_new;
+ fwupd_plugin_remove_flag;
+ fwupd_plugin_set_flags;
+ fwupd_plugin_set_name;
+ fwupd_plugin_to_json;
+ fwupd_plugin_to_string;
+ fwupd_plugin_to_variant;
+ fwupd_release_get_branch;
+ fwupd_release_set_branch;
+ fwupd_remote_get_automatic_security_reports;
+ fwupd_remote_get_security_report_uri;
+ fwupd_security_attr_add_flag;
+ fwupd_security_attr_add_metadata;
+ fwupd_security_attr_add_obsolete;
+ fwupd_security_attr_array_from_variant;
+ fwupd_security_attr_flag_to_string;
+ fwupd_security_attr_flag_to_suffix;
+ fwupd_security_attr_from_variant;
+ fwupd_security_attr_get_appstream_id;
+ fwupd_security_attr_get_flags;
+ fwupd_security_attr_get_level;
+ fwupd_security_attr_get_metadata;
+ fwupd_security_attr_get_name;
+ fwupd_security_attr_get_obsoletes;
+ fwupd_security_attr_get_plugin;
+ fwupd_security_attr_get_result;
+ fwupd_security_attr_get_type;
+ fwupd_security_attr_get_url;
+ fwupd_security_attr_has_flag;
+ fwupd_security_attr_has_obsolete;
+ fwupd_security_attr_new;
+ fwupd_security_attr_result_to_string;
+ fwupd_security_attr_set_appstream_id;
+ fwupd_security_attr_set_flags;
+ fwupd_security_attr_set_level;
+ fwupd_security_attr_set_name;
+ fwupd_security_attr_set_plugin;
+ fwupd_security_attr_set_result;
+ fwupd_security_attr_set_url;
+ fwupd_security_attr_to_json;
+ fwupd_security_attr_to_string;
+ fwupd_security_attr_to_variant;
+ local: *;
+} LIBFWUPD_1.4.6;
+
+LIBFWUPD_1.5.1 {
+ global:
+ fwupd_device_add_child;
+ local: *;
+} LIBFWUPD_1.5.0;
+
+LIBFWUPD_1.5.2 {
+ global:
+ fwupd_client_download_file;
+ fwupd_client_get_user_agent;
+ local: *;
+} LIBFWUPD_1.5.1;
+
+LIBFWUPD_1.5.3 {
+ global:
+ fwupd_client_get_main_context;
+ fwupd_client_set_main_context;
+ fwupd_remote_set_keyring_kind;
+ local: *;
+} LIBFWUPD_1.5.2;
+
+LIBFWUPD_1.5.5 {
+ global:
+ fwupd_device_add_vendor_id;
+ fwupd_device_get_vendor_ids;
+ fwupd_device_has_vendor_id;
+ local: *;
+} LIBFWUPD_1.5.3;
+
+LIBFWUPD_1.5.6 {
+ global:
+ fwupd_client_install_release2;
+ fwupd_client_install_release2_async;
+ fwupd_release_add_location;
+ fwupd_release_get_locations;
+ local: *;
+} LIBFWUPD_1.5.5;
+
+LIBFWUPD_1.5.8 {
+ global:
+ fwupd_device_add_protocol;
+ fwupd_device_get_protocols;
+ fwupd_device_has_protocol;
+ local: *;
+} LIBFWUPD_1.5.6;
+
+LIBFWUPD_1.6.0 {
+ global:
+ fwupd_device_get_composite_id;
+ fwupd_device_set_composite_id;
+ local: *;
+} LIBFWUPD_1.5.8;
+
+LIBFWUPD_1.6.1 {
+ global:
+ fwupd_remote_set_filename_source;
+ fwupd_remote_setup;
+ fwupd_version_string;
+ local: *;
+} LIBFWUPD_1.6.0;
+
+LIBFWUPD_1.6.2 {
+ global:
+ fwupd_device_get_version_build_date;
+ fwupd_device_has_icon;
+ fwupd_device_remove_child;
+ fwupd_device_set_version_build_date;
+ fwupd_remote_to_json;
+ fwupd_request_from_variant;
+ fwupd_request_get_created;
+ fwupd_request_get_device_id;
+ fwupd_request_get_id;
+ fwupd_request_get_image;
+ fwupd_request_get_kind;
+ fwupd_request_get_message;
+ fwupd_request_get_type;
+ fwupd_request_kind_from_string;
+ fwupd_request_kind_to_string;
+ fwupd_request_new;
+ fwupd_request_set_created;
+ fwupd_request_set_device_id;
+ fwupd_request_set_id;
+ fwupd_request_set_image;
+ fwupd_request_set_kind;
+ fwupd_request_set_message;
+ fwupd_request_to_string;
+ fwupd_request_to_variant;
+ local: *;
+} LIBFWUPD_1.6.1;
+
+LIBFWUPD_1.7.0 {
+ global:
+ fwupd_security_attr_add_guid;
+ fwupd_security_attr_add_guids;
+ fwupd_security_attr_get_guids;
+ fwupd_security_attr_has_guid;
+ local: *;
+} LIBFWUPD_1.6.2;
+
+LIBFWUPD_1.7.1 {
+ global:
+ fwupd_client_add_hint;
+ fwupd_client_get_host_security_events;
+ fwupd_client_get_host_security_events_async;
+ fwupd_client_get_host_security_events_finish;
+ fwupd_security_attr_copy;
+ fwupd_security_attr_flag_from_string;
+ fwupd_security_attr_from_json;
+ fwupd_security_attr_get_created;
+ fwupd_security_attr_get_result_fallback;
+ fwupd_security_attr_result_from_string;
+ fwupd_security_attr_set_created;
+ fwupd_security_attr_set_result_fallback;
+ local: *;
+} LIBFWUPD_1.7.0;
+
+LIBFWUPD_1.7.2 {
+ global:
+ fwupd_release_get_id;
+ fwupd_release_set_id;
+ local: *;
+} LIBFWUPD_1.7.1;
+
+LIBFWUPD_1.7.3 {
+ global:
+ fwupd_client_get_host_bkc;
+ fwupd_release_add_tag;
+ fwupd_release_get_tags;
+ fwupd_release_has_tag;
+ local: *;
+} LIBFWUPD_1.7.2;
+
+LIBFWUPD_1.7.4 {
+ global:
+ fwupd_device_get_root;
+ local: *;
+} LIBFWUPD_1.7.3;
+
+LIBFWUPD_1.7.6 {
+ global:
+ fwupd_device_add_issue;
+ fwupd_device_get_issues;
+ local: *;
+} LIBFWUPD_1.7.4;
+
+LIBFWUPD_1.8.0 {
+ global:
+ fwupd_client_disconnect;
+ fwupd_client_get_only_trusted;
+ local: *;
+} LIBFWUPD_1.7.6;
+
+LIBFWUPD_1.8.1 {
+ global:
+ fwupd_client_get_battery_level;
+ fwupd_client_get_battery_threshold;
+ fwupd_device_add_problem;
+ fwupd_device_get_battery_level;
+ fwupd_device_get_battery_threshold;
+ fwupd_device_get_problems;
+ fwupd_device_has_problem;
+ fwupd_device_problem_from_string;
+ fwupd_device_problem_to_string;
+ fwupd_device_remove_problem;
+ fwupd_device_set_battery_level;
+ fwupd_device_set_battery_threshold;
+ fwupd_device_set_problems;
+ local: *;
+} LIBFWUPD_1.8.0;
+
+LIBFWUPD_1.8.2 {
+ global:
+ fwupd_client_get_host_vendor;
+ fwupd_device_to_json_full;
+ fwupd_remote_set_checksum;
+ fwupd_remote_set_filename_cache;
+ fwupd_security_attr_get_description;
+ fwupd_security_attr_get_title;
+ fwupd_security_attr_set_description;
+ fwupd_security_attr_set_title;
+ local: *;
+} LIBFWUPD_1.8.1;
+
+LIBFWUPD_1.8.3 {
+ global:
+ fwupd_device_from_json;
+ fwupd_security_attr_remove_flag;
+ local: *;
+} LIBFWUPD_1.8.2;
+
+LIBFWUPD_1.8.4 {
+ global:
+ fwupd_bios_setting_add_possible_value;
+ fwupd_bios_setting_array_from_variant;
+ fwupd_bios_setting_from_json;
+ fwupd_bios_setting_from_variant;
+ fwupd_bios_setting_get_current_value;
+ fwupd_bios_setting_get_description;
+ fwupd_bios_setting_get_id;
+ fwupd_bios_setting_get_kind;
+ fwupd_bios_setting_get_lower_bound;
+ fwupd_bios_setting_get_name;
+ fwupd_bios_setting_get_path;
+ fwupd_bios_setting_get_possible_values;
+ fwupd_bios_setting_get_read_only;
+ fwupd_bios_setting_get_scalar_increment;
+ fwupd_bios_setting_get_type;
+ fwupd_bios_setting_get_upper_bound;
+ fwupd_bios_setting_has_possible_value;
+ fwupd_bios_setting_map_possible_value;
+ fwupd_bios_setting_new;
+ fwupd_bios_setting_set_current_value;
+ fwupd_bios_setting_set_description;
+ fwupd_bios_setting_set_id;
+ fwupd_bios_setting_set_kind;
+ fwupd_bios_setting_set_lower_bound;
+ fwupd_bios_setting_set_name;
+ fwupd_bios_setting_set_path;
+ fwupd_bios_setting_set_read_only;
+ fwupd_bios_setting_set_scalar_increment;
+ fwupd_bios_setting_set_upper_bound;
+ fwupd_bios_setting_to_json;
+ fwupd_bios_setting_to_string;
+ fwupd_bios_setting_to_variant;
+ fwupd_client_get_bios_settings;
+ fwupd_client_get_bios_settings_async;
+ fwupd_client_get_bios_settings_finish;
+ fwupd_client_modify_bios_setting;
+ fwupd_client_modify_bios_setting_async;
+ fwupd_client_modify_bios_setting_finish;
+ fwupd_security_attr_get_bios_setting_current_value;
+ fwupd_security_attr_get_bios_setting_id;
+ fwupd_security_attr_get_bios_setting_target_value;
+ fwupd_security_attr_set_bios_setting_current_value;
+ fwupd_security_attr_set_bios_setting_id;
+ fwupd_security_attr_set_bios_setting_target_value;
+ local: *;
+} LIBFWUPD_1.8.3;
+
+LIBFWUPD_1.8.6 {
+ global:
+ fwupd_request_add_flag;
+ fwupd_request_flag_from_string;
+ fwupd_request_flag_to_string;
+ fwupd_request_get_flags;
+ fwupd_request_has_flag;
+ fwupd_request_remove_flag;
+ fwupd_request_set_flags;
+ local: *;
+} LIBFWUPD_1.8.4;
diff --git a/fwupd-1.8.6/libfwupd/meson.build b/fwupd-1.8.6/libfwupd/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..07ce2eae7d0f9e069eaf51ca406e225fe4a4ff51
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/meson.build
@@ -0,0 +1,247 @@
+if get_option('tests')
+subdir('tests')
+endif
+
+fwupd_version_h = configure_file(
+ input: 'fwupd-version.h.in',
+ output: 'fwupd-version.h',
+ configuration: conf
+)
+
+install_headers(
+ 'fwupd.h',
+ subdir: 'fwupd-1',
+)
+
+install_headers([
+ 'fwupd-client.h',
+ 'fwupd-client-sync.h',
+ 'fwupd-common.h',
+ 'fwupd-deprecated.h',
+ 'fwupd-device.h',
+ 'fwupd-enums.h',
+ 'fwupd-error.h',
+ 'fwupd-remote.h',
+ 'fwupd-request.h',
+ 'fwupd-bios-setting.h',
+ 'fwupd-security-attr.h',
+ 'fwupd-release.h',
+ 'fwupd-plugin.h',
+ fwupd_version_h,
+ ],
+ subdir: 'fwupd-1/libfwupd',
+)
+
+libfwupd_deps = [
+ giounix,
+ gmodule,
+ libjcat,
+ libjsonglib,
+ libcurl,
+]
+
+libfwupd_src = [
+ 'fwupd-client.c',
+ 'fwupd-client-sync.c',
+ 'fwupd-common.c', # fuzzing
+ 'fwupd-device.c', # fuzzing
+ 'fwupd-enums.c', # fuzzing
+ 'fwupd-error.c', # fuzzing
+ 'fwupd-bios-setting.c', # fuzzing
+ 'fwupd-security-attr.c', # fuzzing
+ 'fwupd-release.c', # fuzzing
+ 'fwupd-plugin.c',
+ 'fwupd-remote.c',
+ 'fwupd-request.c', # fuzzing
+ 'fwupd-version.c',
+]
+
+fwupd_mapfile = 'fwupd.map'
+vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), fwupd_mapfile)
+fwupd = library(
+ 'fwupd',
+ sources: libfwupd_src,
+ soversion: libfwupd_lt_current,
+ version: libfwupd_lt_version,
+ dependencies: libfwupd_deps,
+ c_args: [
+ '-DG_LOG_DOMAIN="Fwupd"',
+ '-DLOCALSTATEDIR="' + localstatedir + '"',
+ ],
+ include_directories: root_incdir,
+ link_args: cc.get_supported_link_arguments([vflag]),
+ link_depends: fwupd_mapfile,
+ install: true
+)
+
+libfwupd_dep = declare_dependency(
+ link_with: fwupd,
+ include_directories: [root_incdir, include_directories('.')],
+ dependencies: libfwupd_deps
+)
+
+pkgg = import('pkgconfig')
+pkgg.generate(
+ fwupd,
+ requires: [ 'gio-2.0' ],
+ subdirs: 'fwupd-1',
+ version: meson.project_version(),
+ name: 'fwupd',
+ filebase: 'fwupd',
+ description: 'fwupd is a system daemon for installing device firmware',
+)
+
+if introspection.allowed()
+ fwupd_gir_deps = [
+ giounix,
+ libcurl,
+ ]
+ fwupd_gir = gnome.generate_gir(fwupd,
+ sources: [
+ 'fwupd-client.c',
+ 'fwupd-client.h',
+ 'fwupd-client-sync.c',
+ 'fwupd-client-sync.h',
+ 'fwupd-common.c',
+ 'fwupd-common.h',
+ 'fwupd-common-private.h',
+ 'fwupd-device.c',
+ 'fwupd-device.h',
+ 'fwupd-device-private.h',
+ 'fwupd-enums.c',
+ 'fwupd-enums.h',
+ 'fwupd-enums-private.h',
+ 'fwupd-error.c',
+ 'fwupd-error.h',
+ 'fwupd-bios-setting.c',
+ 'fwupd-bios-setting.h',
+ 'fwupd-bios-setting-private.h',
+ 'fwupd-security-attr.c',
+ 'fwupd-security-attr.h',
+ 'fwupd-security-attr-private.h',
+ 'fwupd-release.c',
+ 'fwupd-release.h',
+ 'fwupd-release-private.h',
+ 'fwupd-plugin.c',
+ 'fwupd-plugin.h',
+ 'fwupd-plugin-private.h',
+ 'fwupd-remote.c',
+ 'fwupd-remote.h',
+ 'fwupd-remote-private.h',
+ 'fwupd-request.c',
+ 'fwupd-request.h',
+ 'fwupd-request-private.h',
+ 'fwupd-version.c',
+ fwupd_version_h,
+ ],
+ nsversion: '2.0',
+ namespace: 'Fwupd',
+ symbol_prefix: 'fwupd',
+ identifier_prefix: 'Fwupd',
+ export_packages: 'fwupd',
+ header: 'fwupd.h',
+ dependencies: fwupd_gir_deps,
+ includes: [
+ 'Gio-2.0',
+ 'GObject-2.0',
+ 'Json-1.0',
+ ],
+ install: true
+ )
+
+ gnome.generate_vapi('fwupd',
+ sources: fwupd_gir[0],
+ packages: ['gio-2.0', 'json-glib-1.0'],
+ install: true,
+ )
+
+ # Verify the map file is correct -- note we can't actually use the generated
+ # file for two reasons:
+ #
+ # 1. We don't hard depend on GObject Introspection
+ # 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
+ # accidentally actually check in a version of the version script to git.
+ mapfile_target = custom_target('fwupd_mapfile',
+ input: fwupd_gir[0],
+ output: 'fwupd.map',
+ command: [
+ python3,
+ join_paths(meson.project_source_root(), 'contrib', 'generate-version-script.py'),
+ 'LIBFWUPD',
+ '@INPUT@',
+ '@OUTPUT@',
+ ],
+ )
+ test('fwupd-exported-api', diffcmd,
+ args: [
+ '-urNp',
+ files('fwupd.map'),
+ mapfile_target,
+ ],
+ )
+endif
+
+if get_option('tests')
+ env = environment()
+ env.set('G_TEST_SRCDIR', meson.current_source_dir())
+ env.set('G_TEST_BUILDDIR', meson.current_build_dir())
+ e = executable(
+ 'fwupd-self-test',
+ metadata_xml_gz_jcat,
+ sources: [
+ 'fwupd-self-test.c'
+ ],
+ include_directories: [
+ root_incdir,
+ ],
+ dependencies: [
+ libfwupd_deps,
+ ],
+ link_with: fwupd,
+ c_args: [
+ '-DG_LOG_DOMAIN="Fwupd"',
+ '-DLOCALSTATEDIR="' + localstatedir + '"',
+ ],
+ )
+ test('fwupd-self-test', e, timeout: 60, env: env)
+ if run_sanitize_unsafe_tests and gio.version().version_compare ('>= 2.64.0')
+ e = executable(
+ 'fwupd-thread-test',
+ sources: [
+ 'fwupd-thread-test.c'
+ ],
+ include_directories: [
+ root_incdir,
+ ],
+ dependencies: [
+ libfwupd_deps,
+ ],
+ link_with: fwupd,
+ c_args: [
+ '-DG_LOG_DOMAIN="Fwupd"',
+ ],
+ )
+ test('fwupd-thread-test', e, timeout: 60)
+ e = executable(
+ 'fwupd-context-test',
+ sources: [
+ 'fwupd-context-test.c'
+ ],
+ include_directories: [
+ root_incdir,
+ ],
+ dependencies: [
+ libfwupd_deps,
+ ],
+ link_with: fwupd,
+ c_args: [
+ '-DG_LOG_DOMAIN="Fwupd"',
+ ],
+ )
+ test('fwupd-context-test', e, timeout: 60)
+ endif
+endif
+
+fwupd_incdir = include_directories('.')
diff --git a/fwupd-1.8.6/libfwupd/tests/auth.conf b/fwupd-1.8.6/libfwupd/tests/auth.conf
new file mode 100644
index 0000000000000000000000000000000000000000..01167ebc64601500be7b02008be44fccd85edf49
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/auth.conf
@@ -0,0 +1,11 @@
+[fwupd Remote]
+Enabled=true
+MetadataURI=https://cdn.fwupd.org/downloads/firmware.xml.gz
+ReportURI=https://fwupd.org/lvfs/firmware/report
+SecurityReportURI=https://fwupd.org/lvfs/hsireports/upload
+AutomaticSecurityReports=true
+Username=user
+Password=pass
+OrderBefore=before
+OrderAfter=after
+FirmwareBaseURI=https://my.fancy.cdn/
diff --git a/fwupd-1.8.6/libfwupd/tests/auth/meson.build b/fwupd-1.8.6/libfwupd/tests/auth/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..b635e92806a3a45153f1622c8e9d59ad6d35e423
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/auth/meson.build
@@ -0,0 +1,23 @@
+jcat_tool = find_program('jcat-tool', required: false)
+
+if jcat_tool.found()
+metadata_xml_gz_jcat = custom_target('metadata-xml-gz-jcat',
+ input: [
+ 'metadata.xml.gz',
+ ],
+ output: 'metadata.xml.gz.jcat',
+ command: [
+ jcat_tool, '--basename', '--appstream-id', 'localhost', 'self-sign', '@OUTPUT@', '@INPUT@',
+ ],
+)
+else
+metadata_xml_gz_jcat = custom_target('metadata-xml-gz-jcat',
+ input: [
+ 'metadata.xml.gz',
+ ],
+ output: 'metadata.xml.gz.jcat',
+ command: [
+ 'touch', '@OUTPUT@',
+ ],
+)
+endif
diff --git a/fwupd-1.8.6/libfwupd/tests/auth/metadata.xml.gz b/fwupd-1.8.6/libfwupd/tests/auth/metadata.xml.gz
new file mode 100644
index 0000000000000000000000000000000000000000..3b18e512dba79e4c8300dd08aeb37f8e728b8dad
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/auth/metadata.xml.gz
@@ -0,0 +1 @@
+hello world
diff --git a/fwupd-1.8.6/libfwupd/tests/dell-esrt.conf b/fwupd-1.8.6/libfwupd/tests/dell-esrt.conf
new file mode 120000
index 0000000000000000000000000000000000000000..074887625c3a93ab77b91b65b471363cc4dc47ec
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/dell-esrt.conf
@@ -0,0 +1 @@
+../../plugins/dell-esrt/dell-esrt.conf
\ No newline at end of file
diff --git a/fwupd-1.8.6/libfwupd/tests/disabled.conf b/fwupd-1.8.6/libfwupd/tests/disabled.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7fd7d46d0926c4b583c129ed2394cf491eed2b46
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/disabled.conf
@@ -0,0 +1,4 @@
+[fwupd Remote]
+Enabled=false
+Keyring=none
+Password=
diff --git a/fwupd-1.8.6/libfwupd/tests/firmware-base-uri.conf b/fwupd-1.8.6/libfwupd/tests/firmware-base-uri.conf
new file mode 100644
index 0000000000000000000000000000000000000000..6445335778e8e16b3c8ee30d2786cfe94f52399d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/firmware-base-uri.conf
@@ -0,0 +1,6 @@
+[fwupd Remote]
+Enabled=true
+Type=download
+Keyring=jcat
+MetadataURI=https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz
+FirmwareBaseURI=https://my.fancy.cdn/
diff --git a/fwupd-1.8.6/libfwupd/tests/firmware-nopath.conf b/fwupd-1.8.6/libfwupd/tests/firmware-nopath.conf
new file mode 100644
index 0000000000000000000000000000000000000000..cf0162e1be9e7bf1d870120719d3fb7aaaf19996
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/firmware-nopath.conf
@@ -0,0 +1,5 @@
+[fwupd Remote]
+Enabled=true
+Type=download
+Keyring=jcat
+MetadataURI=https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz
diff --git a/fwupd-1.8.6/libfwupd/tests/meson.build b/fwupd-1.8.6/libfwupd/tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..bb7024cc597ae6a0ac02f21950646cfc84227ec5
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/meson.build
@@ -0,0 +1 @@
+subdir('auth')
diff --git a/fwupd-1.8.6/libfwupd/tests/remotes.d b/fwupd-1.8.6/libfwupd/tests/remotes.d
new file mode 120000
index 0000000000000000000000000000000000000000..958eb08404b21bf33d235dcd3ba0263e8e7d11c2
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/remotes.d
@@ -0,0 +1 @@
+../../data/remotes.d/
\ No newline at end of file
diff --git a/fwupd-1.8.6/libfwupd/tests/stable.conf b/fwupd-1.8.6/libfwupd/tests/stable.conf
new file mode 120000
index 0000000000000000000000000000000000000000..3619a13ec87faf39e3c94ddf57584e6db2da3ed4
--- /dev/null
+++ b/fwupd-1.8.6/libfwupd/tests/stable.conf
@@ -0,0 +1 @@
+../../src/tests/remotes.d/stable.conf
\ No newline at end of file
diff --git a/fwupd-1.8.6/libfwupdplugin/README.md b/fwupd-1.8.6/libfwupdplugin/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..857d17d22c5205c27ddca5d25e2c8543cb4c972e
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/README.md
@@ -0,0 +1,101 @@
+# libfwupdplugin
+
+This library is only partially API and ABI stable. Keeping unused, unsafe and
+deprecated functions around forever is a maintenance burden and so symbols are
+removed when branching for new minor versions.
+
+Use `./contrib/migrate.py` to migrate up out-of-tree plugins to the new API.
+
+Remember: Plugins should be upstream!
+
+## 1.5.5
+
+* `fu_common_is_cpu_intel()`: Use `fu_common_get_cpu_vendor()` instead.
+* `fu_firmware_strparse_uintXX()`: Use `fu_firmware_strparse_uintXX_safe()` instead.
+* `fu_plugin_get_usb_context()`: Remove, as no longer required.
+* `fu_plugin_set_usb_context()`: Remove, as no longer required.
+* `fu_plugin_runner_usb_device_added()`: Use `fu_plugin_runner_backend_device_added()` instead.
+* `fu_plugin_runner_udev_device_added()`: Use `fu_plugin_runner_backend_device_added()` instead.
+* `fu_plugin_runner_udev_device_changed()`: Use `fu_plugin_runner_backend_device_added()` instead.
+* `FuHidDevice->open()`: Use the `FuDevice` superclass instead.
+* `FuHidDevice->close()`: Use the `FuDevice` superclass instead.
+* `FuUsbDevice->probe()`: Use the `FuDevice` superclass instead.
+* `FuUsbDevice->open()`: Use the `FuDevice` superclass instead.
+* `FuUsbDevice->close()`: Use the `FuDevice` superclass instead.
+* `FuUdevDevice->to_string()`: Use the `FuDevice` superclass instead.
+* `FuUdevDevice->probe()`: Use the `FuDevice` superclass instead.
+* `FuUdevDevice->open()`: Use the `FuDevice` superclass instead.
+* `FuUdevDevice->close()`: Use the `FuDevice` superclass instead.
+
+## 1.5.6
+
+* `fu_device_get_protocol()`: Use `fu_device_get_protocols()` instead.
+* `fu_device_set_protocol()`: Use `fu_device_add_protocol()` instead.
+
+## 1.6.2
+
+* `fu_device_has_custom_flag()`: Use `fu_device_has_private_flag()` instead.
+
+## 1.6.3
+
+* `fu_device_sleep_with_progress()`: Use `fu_progress_sleep()` instead -- but be aware the unit of time has changed from *seconds* to *milliseconds*.
+* `fu_device_get_status()`: Use `fu_progress_get_status()` instead.
+* `fu_device_set_status()`: Use `fu_progress_set_status()` instead.
+* `fu_device_get_progress()`: Use `fu_progress_get_percentage()` instead.
+* `fu_device_set_progress_full()`: Use `fu_progress_set_percentage_full()` instead.
+* `fu_device_set_progress()`: Use `fu_progress_set_steps()`, `fu_progress_add_step()` and `fu_progress_done()` -- see the `FuProgress` docs for more details!
+
+## 1.8.2
+
+* `fu_udev_device_pread_full()`: Use `fu_udev_device_pread()` instead -- as the latter now specifies the buffer length.
+* `fu_udev_device_pread_full()`: Use `fu_udev_device_pwrite()` instead -- as the latter now specifies the buffer length.
+* `fu_udev_device_ioctl_full()`: Use `fu_udev_device_ioctl()` instead -- as the latter now always specifies the timeout.
+* `fu_udev_device_new_full()`: Use `fu_udev_device_new()` instead -- as the latter always specifies the context.
+* `fu_usb_device_new_full()`: Use `fu_usb_device_new()` instead -- as the latter always specifies the context.
+* `fu_device_new_with_context()`: Use `fu_device_new()` instead -- as the latter always specifies the context.
+* `fu_plugin_has_custom_flag()`: Use `fu_plugin_has_private_flag()` instead.
+* `fu_efivar_secure_boot_enabled_full()`: Use `fu_efivar_secure_boot_enabled()` instead -- as the latter always specifies the error.
+* `fu_progress_add_step()`: Add a 4th parameter to the function to specify the nice name for the step, or NULL.
+* `fu_backend_setup()`: Now requires a `FuProgress`, although it can be ignored.
+* `fu_backend_coldplug`: Now requires a `FuProgress`, although it can be ignored.
+* `FuPluginVfuncs->setup`: Now requires a `FuProgress`, although it can be ignored.
+* `FuPluginVfuncs->coldplug`: Now requires a `FuProgress`, although it can be ignored.
+* `fu_common_crc*`: Use `fu_crc` prefix, i.e. remove the `_common`
+* `fu_common_sum*`: Use `fu_sum` prefix, i.e. remove the `_common`
+* `fu_byte_array_set_size_full()`: Use `fu_byte_array_set_size` instead -- as the latter now always specifies the fill char.
+* `fu_common_string*`: Use `fu_string` prefix, i.e. remove the `_common`
+* `fu_common_bytes*`: Use `fu_bytes` prefix, i.e. remove the `_common`
+* `fu_common_set_contents_bytes()`: Use `fu_bytes_set_contents()` instead
+* `fu_common_get_contents_bytes()`: Use `fu_bytes_get_contents()` instead
+* `fu_common_read*`: Use `fu_memread` prefix, i.e. replace the `_common` with `_mem`
+* `fu_common_write*`: Use `fu_memwrite` prefix, i.e. replace the `_common` with `_mem`
+* `fu_common_bytes_compare_raw()`: Use `fu_memcmp_safe()` instead
+* `fu_common_spawn_sync()`: Use `g_spawn_sync()` instead, or ideally not at all!
+* `fu_common_extract_archive()`: Use `FuArchiveFirmware()` instead.
+* `fu_common_instance_id_strsafe()`: Use `fu_device_add_instance_strsafe()` instead.
+* `fu_common_kernel_locked_down()`: Use `fu_kernel_locked_down` instead.
+* `fu_common_check_kernel_version()`: Use `fu_kernel_check_version` instead.
+* `fu_common_get_firmware_search_path()`: Use `fu_kernel_get_firmware_search_path` instead.
+* `fu_common_set_firmware_search_path()`: Use `fu_kernel_set_firmware_search_path` instead.
+* `fu_common_reset_firmware_search_path()`: Use `fu_kernel_reset_firmware_search_path` instead.
+* `fu_common_firmware_builder()`: You should not be using this.
+* `fu_common_realpath()`: You should not be using this.
+* `fu_common_uri_get_scheme()`: You should not be using this.
+* `fu_common_dump*`: Use `fu_dump` prefix, i.e. remove the `_common`
+* `fu_common_error_array_get_best()`: You should not be using this.
+* `fu_common_cpuid()`: Use `fu_cpuid` instead.
+* `fu_common_get_cpu_vendor()`: Use `fu_cpu_get_vendor` instead.
+* `fu_common_vercmp_full()`: Use `fu_version_compare()` instead.
+* `fu_common_version_ensure_semver()`: Use `fu_version_ensure_semver()` instead.
+* `fu_common_version_from_uint*()`: Use `fu_version_from_uint*()` instead.
+* `fu_common_strtoull()`: Use `fu_strtoull()` instead -- as the latter always specifies the error.
+* `fu_smbios_to_string()`: Use `fu_firmware_to_string()` instead -- as `FuSmbios` is a `FuFirmware` superclass.
+* `fu_common_cab_build_silo()`: You should not be using this.
+* `fu_i2c_device_read_full()`: Use `fu_i2c_device_read` instead.
+* `fu_i2c_device_write_full()`: Use `fu_i2c_device_write` instead.
+* `fu_firmware_parse_full()`: Remove the `addr_end` parameter, and ensure that `offset` is a `gsize`.
+
+## 1.8.5
+
+* `fu_volume_new_esp_default()`: Use `fu_context_get_esp_volumes()` instead.
+* `fu_plugin_set_secure_config_value()`: Set `FWUPD_PLUGIN_FLAG_SECURE_CONFIG` and use `fu_plugin_set_config_value()`
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-archive-firmware.c b/fwupd-1.8.6/libfwupdplugin/fu-archive-firmware.c
new file mode 100644
index 0000000000000000000000000000000000000000..8ddf3a6b0bf36362a9dd385ea186027e1210eb66
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-archive-firmware.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ * Copyright (C) 2022 Gaël PORTAY
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuFirmware"
+
+#include "config.h"
+
+#include "fu-archive-firmware.h"
+#include "fu-archive.h"
+#include "fu-common.h"
+
+/**
+ * FuArchiveFirmware:
+ *
+ * An archive firmware image, typically for nested firmware volumes.
+ *
+ * See also: [class@FuFirmware]
+ */
+
+typedef struct {
+ FuArchiveFormat format;
+ FuArchiveCompression compression;
+} FuArchiveFirmwarePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuArchiveFirmware, fu_archive_firmware, FU_TYPE_FIRMWARE)
+#define GET_PRIVATE(o) (fu_archive_firmware_get_instance_private(o))
+
+static void
+fu_archive_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
+{
+ FuArchiveFirmware *self = FU_ARCHIVE_FIRMWARE(firmware);
+ FuArchiveFirmwarePrivate *priv = GET_PRIVATE(self);
+ fu_xmlb_builder_insert_kv(bn, "format", fu_archive_format_to_string(priv->format));
+ fu_xmlb_builder_insert_kv(bn,
+ "compression",
+ fu_archive_compression_to_string(priv->compression));
+}
+
+static gboolean
+fu_archive_firmware_parse_cb(FuArchive *self,
+ const gchar *filename,
+ GBytes *bytes,
+ gpointer user_data,
+ GError **error)
+{
+ FuFirmware *firmware = FU_FIRMWARE(user_data);
+ g_autoptr(FuFirmware) img = fu_firmware_new_from_bytes(bytes);
+ fu_firmware_set_id(img, filename);
+ fu_firmware_add_image(firmware, img);
+ return TRUE;
+}
+
+static gboolean
+fu_archive_firmware_parse(FuFirmware *firmware,
+ GBytes *fw,
+ gsize offset,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ g_autoptr(FuArchive) archive = NULL;
+
+ /* load archive */
+ archive = fu_archive_new(fw, FU_ARCHIVE_FLAG_IGNORE_PATH, error);
+ if (archive == NULL)
+ return FALSE;
+
+ /* decompress each image in the archive */
+ return fu_archive_iterate(archive, fu_archive_firmware_parse_cb, firmware, error);
+}
+
+/**
+ * fu_archive_firmware_get_format:
+ * @self: a #FuArchiveFirmware
+ *
+ * Gets the archive format.
+ *
+ * Returns: format
+ *
+ * Since: 1.8.1
+ **/
+FuArchiveFormat
+fu_archive_firmware_get_format(FuArchiveFirmware *self)
+{
+ FuArchiveFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_ARCHIVE_FIRMWARE(self), FU_ARCHIVE_FORMAT_UNKNOWN);
+ return priv->format;
+}
+
+/**
+ * fu_archive_firmware_set_format:
+ * @self: a #FuArchiveFirmware
+ * @format: the archive format, e.g. %FU_ARCHIVE_FORMAT_ZIP
+ *
+ * Sets the archive format.
+ *
+ * Since: 1.8.1
+ **/
+void
+fu_archive_firmware_set_format(FuArchiveFirmware *self, FuArchiveFormat format)
+{
+ FuArchiveFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_ARCHIVE_FIRMWARE(self));
+ priv->format = format;
+}
+
+/**
+ * fu_archive_firmware_get_compression:
+ * @self: A #FuArchiveFirmware
+ *
+ * Returns the compression.
+ *
+ * Returns: compression
+ *
+ * Since: 1.8.1
+ **/
+FuArchiveCompression
+fu_archive_firmware_get_compression(FuArchiveFirmware *self)
+{
+ FuArchiveFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_ARCHIVE_FIRMWARE(self), FU_ARCHIVE_COMPRESSION_UNKNOWN);
+ return priv->compression;
+}
+
+/**
+ * fu_archive_firmware_set_compression:
+ * @self: A #FuArchiveFirmware
+ * @compression: the compression, e.g. %FU_ARCHIVE_COMPRESSION_NONE
+ *
+ * Sets the compression.
+ *
+ * Since: 1.8.1
+ **/
+void
+fu_archive_firmware_set_compression(FuArchiveFirmware *self, FuArchiveCompression compression)
+{
+ FuArchiveFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_ARCHIVE_FIRMWARE(self));
+ priv->compression = compression;
+}
+
+static GBytes *
+fu_archive_firmware_write(FuFirmware *firmware, GError **error)
+{
+ FuArchiveFirmware *self = FU_ARCHIVE_FIRMWARE(firmware);
+ FuArchiveFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(FuArchive) archive = NULL;
+ g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware);
+
+ /* sanity check */
+ if (priv->format == FU_ARCHIVE_FORMAT_UNKNOWN) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "firmware archive format unspecified");
+ return NULL;
+ }
+ if (priv->compression == FU_ARCHIVE_COMPRESSION_UNKNOWN) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "firmware archive compression unspecified");
+ return NULL;
+ }
+
+ /* save archive and compress each image to the archive */
+ archive = fu_archive_new(NULL, FU_ARCHIVE_FLAG_NONE, NULL);
+ for (guint i = 0; i < images->len; i++) {
+ FuFirmware *img = g_ptr_array_index(images, i);
+ g_autoptr(GBytes) blob = NULL;
+
+ if (fu_firmware_get_id(img) == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "image has no ID");
+ return NULL;
+ }
+ blob = fu_firmware_get_bytes(img, error);
+ if (blob == NULL)
+ return NULL;
+ fu_archive_add_entry(archive, fu_firmware_get_id(img), blob);
+ }
+ return fu_archive_write(archive, priv->format, priv->compression, error);
+}
+
+static gboolean
+fu_archive_firmware_build(FuFirmware *firmware, XbNode *n, GError **error)
+{
+ FuArchiveFirmware *self = FU_ARCHIVE_FIRMWARE(firmware);
+ const gchar *tmp;
+
+ /* simple properties */
+ tmp = xb_node_query_text(n, "format", NULL);
+ if (tmp != NULL) {
+ FuArchiveFormat format = fu_archive_format_from_string(tmp);
+ if (format == FU_ARCHIVE_FORMAT_UNKNOWN) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "format %s not supported",
+ tmp);
+ return FALSE;
+ }
+ fu_archive_firmware_set_format(self, format);
+ }
+ tmp = xb_node_query_text(n, "compression", NULL);
+ if (tmp != NULL) {
+ FuArchiveCompression compression = fu_archive_compression_from_string(tmp);
+ if (compression == FU_ARCHIVE_COMPRESSION_UNKNOWN) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "compression %s not supported",
+ tmp);
+ return FALSE;
+ }
+ fu_archive_firmware_set_compression(self, compression);
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fu_archive_firmware_init(FuArchiveFirmware *self)
+{
+}
+
+static void
+fu_archive_firmware_class_init(FuArchiveFirmwareClass *klass)
+{
+ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
+ klass_firmware->parse = fu_archive_firmware_parse;
+ klass_firmware->write = fu_archive_firmware_write;
+ klass_firmware->build = fu_archive_firmware_build;
+ klass_firmware->export = fu_archive_firmware_export;
+}
+
+/**
+ * fu_archive_firmware_new:
+ *
+ * Creates a new archive #FuFirmware
+ *
+ * Since: 1.7.3
+ **/
+FuFirmware *
+fu_archive_firmware_new(void)
+{
+ return FU_FIRMWARE(g_object_new(FU_TYPE_ARCHIVE_FIRMWARE, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-archive-firmware.h b/fwupd-1.8.6/libfwupdplugin/fu-archive-firmware.h
new file mode 100644
index 0000000000000000000000000000000000000000..83283e6eab11dbb2d8baa247f7e0d6d43cd67488
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-archive-firmware.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ * Copyright (C) 2022 Gaël PORTAY
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-archive.h"
+#include "fu-firmware.h"
+
+#define FU_TYPE_ARCHIVE_FIRMWARE (fu_archive_firmware_get_type())
+#define FU_TYPE_ARCHIVE_FIRMWARE_RECORD (fu_archive_firmware_record_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuArchiveFirmware, fu_archive_firmware, FU, ARCHIVE_FIRMWARE, FuFirmware)
+
+struct _FuArchiveFirmwareClass {
+ FuFirmwareClass parent_class;
+};
+
+FuFirmware *
+fu_archive_firmware_new(void);
+FuArchiveFormat
+fu_archive_firmware_get_format(FuArchiveFirmware *self);
+void
+fu_archive_firmware_set_format(FuArchiveFirmware *self, FuArchiveFormat format);
+FuArchiveCompression
+fu_archive_firmware_get_compression(FuArchiveFirmware *self);
+void
+fu_archive_firmware_set_compression(FuArchiveFirmware *self, FuArchiveCompression compression);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-archive.c b/fwupd-1.8.6/libfwupdplugin/fu-archive.c
new file mode 100644
index 0000000000000000000000000000000000000000..9f799de7623dc20d6e5af44d4bc12aec565b9dac
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-archive.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2018 Richard Hughes
+ * Copyright (C) 2022 Gaël PORTAY
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuArchive"
+
+#include "config.h"
+
+#include
+
+#ifdef HAVE_LIBARCHIVE
+#include
+#include
+#endif
+
+#include "fwupd-error.h"
+
+#include "fu-archive.h"
+
+/**
+ * FuArchive:
+ *
+ * An in-memory archive decompressor
+ */
+
+struct _FuArchive {
+ GObject parent_instance;
+ GHashTable *entries; /* str:GBytes */
+};
+
+G_DEFINE_TYPE(FuArchive, fu_archive, G_TYPE_OBJECT)
+
+/**
+ * fu_archive_format_to_string:
+ * @format: a format, e.g. %FU_ARCHIVE_FORMAT_ZIP
+ *
+ * Converts an enumerated format to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.8.1
+ **/
+const gchar *
+fu_archive_format_to_string(FuArchiveFormat format)
+{
+ if (format == FU_ARCHIVE_FORMAT_UNKNOWN)
+ return "unknown";
+ if (format == FU_ARCHIVE_FORMAT_CPIO)
+ return "cpio";
+ if (format == FU_ARCHIVE_FORMAT_SHAR)
+ return "shar";
+ if (format == FU_ARCHIVE_FORMAT_TAR)
+ return "tar";
+ if (format == FU_ARCHIVE_FORMAT_USTAR)
+ return "ustar";
+ if (format == FU_ARCHIVE_FORMAT_PAX)
+ return "pax";
+ if (format == FU_ARCHIVE_FORMAT_GNUTAR)
+ return "gnutar";
+ if (format == FU_ARCHIVE_FORMAT_ISO9660)
+ return "iso9660";
+ if (format == FU_ARCHIVE_FORMAT_ZIP)
+ return "zip";
+ if (format == FU_ARCHIVE_FORMAT_AR)
+ return "ar";
+ if (format == FU_ARCHIVE_FORMAT_AR_SVR4)
+ return "ar-svr4";
+ if (format == FU_ARCHIVE_FORMAT_MTREE)
+ return "mtree";
+ if (format == FU_ARCHIVE_FORMAT_RAW)
+ return "raw";
+ if (format == FU_ARCHIVE_FORMAT_XAR)
+ return "xar";
+ if (format == FU_ARCHIVE_FORMAT_7ZIP)
+ return "7zip";
+ if (format == FU_ARCHIVE_FORMAT_WARC)
+ return "warc";
+ return NULL;
+}
+
+/**
+ * fu_archive_format_from_string:
+ * @format: (nullable): a string, e.g. `zip`
+ *
+ * Converts a string to an enumerated format.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.8.1
+ **/
+FuArchiveFormat
+fu_archive_format_from_string(const gchar *format)
+{
+ if (g_strcmp0(format, "unknown") == 0)
+ return FU_ARCHIVE_FORMAT_UNKNOWN;
+ if (g_strcmp0(format, "cpio") == 0)
+ return FU_ARCHIVE_FORMAT_CPIO;
+ if (g_strcmp0(format, "shar") == 0)
+ return FU_ARCHIVE_FORMAT_SHAR;
+ if (g_strcmp0(format, "tar") == 0)
+ return FU_ARCHIVE_FORMAT_TAR;
+ if (g_strcmp0(format, "ustar") == 0)
+ return FU_ARCHIVE_FORMAT_USTAR;
+ if (g_strcmp0(format, "pax") == 0)
+ return FU_ARCHIVE_FORMAT_PAX;
+ if (g_strcmp0(format, "gnutar") == 0)
+ return FU_ARCHIVE_FORMAT_GNUTAR;
+ if (g_strcmp0(format, "iso9660") == 0)
+ return FU_ARCHIVE_FORMAT_ISO9660;
+ if (g_strcmp0(format, "zip") == 0)
+ return FU_ARCHIVE_FORMAT_ZIP;
+ if (g_strcmp0(format, "ar") == 0)
+ return FU_ARCHIVE_FORMAT_AR;
+ if (g_strcmp0(format, "ar-svr4") == 0)
+ return FU_ARCHIVE_FORMAT_AR_SVR4;
+ if (g_strcmp0(format, "mtree") == 0)
+ return FU_ARCHIVE_FORMAT_MTREE;
+ if (g_strcmp0(format, "raw") == 0)
+ return FU_ARCHIVE_FORMAT_RAW;
+ if (g_strcmp0(format, "xar") == 0)
+ return FU_ARCHIVE_FORMAT_XAR;
+ if (g_strcmp0(format, "7zip") == 0)
+ return FU_ARCHIVE_FORMAT_7ZIP;
+ if (g_strcmp0(format, "warc") == 0)
+ return FU_ARCHIVE_FORMAT_WARC;
+ return FU_ARCHIVE_FORMAT_UNKNOWN;
+}
+
+/**
+ * fu_archive_compression_to_string:
+ * @compression: a compression, e.g. %FU_ARCHIVE_COMPRESSION_ZIP
+ *
+ * Converts an enumerated compression to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.8.1
+ **/
+const gchar *
+fu_archive_compression_to_string(FuArchiveCompression compression)
+{
+ if (compression == FU_ARCHIVE_COMPRESSION_UNKNOWN)
+ return "unknown";
+ if (compression == FU_ARCHIVE_COMPRESSION_NONE)
+ return "none";
+ if (compression == FU_ARCHIVE_COMPRESSION_GZIP)
+ return "gzip";
+ if (compression == FU_ARCHIVE_COMPRESSION_BZIP2)
+ return "bzip2";
+ if (compression == FU_ARCHIVE_COMPRESSION_COMPRESS)
+ return "compress";
+ if (compression == FU_ARCHIVE_COMPRESSION_LZMA)
+ return "lzma";
+ if (compression == FU_ARCHIVE_COMPRESSION_XZ)
+ return "xz";
+ if (compression == FU_ARCHIVE_COMPRESSION_UU)
+ return "uuencode";
+ if (compression == FU_ARCHIVE_COMPRESSION_LZIP)
+ return "lzip";
+ if (compression == FU_ARCHIVE_COMPRESSION_LRZIP)
+ return "lrzip";
+ if (compression == FU_ARCHIVE_COMPRESSION_LZOP)
+ return "lzop";
+ if (compression == FU_ARCHIVE_COMPRESSION_GRZIP)
+ return "grzip";
+ if (compression == FU_ARCHIVE_COMPRESSION_LZ4)
+ return "lz4";
+ if (compression == FU_ARCHIVE_COMPRESSION_ZSTD)
+ return "zstd";
+ return NULL;
+}
+
+/**
+ * fu_archive_compression_from_string:
+ * @compression: (nullable): a string, e.g. `zip`
+ *
+ * Converts a string to an enumerated compression.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.8.1
+ **/
+FuArchiveCompression
+fu_archive_compression_from_string(const gchar *compression)
+{
+ if (g_strcmp0(compression, "unknown") == 0)
+ return FU_ARCHIVE_COMPRESSION_UNKNOWN;
+ if (g_strcmp0(compression, "none") == 0)
+ return FU_ARCHIVE_COMPRESSION_NONE;
+ if (g_strcmp0(compression, "gzip") == 0)
+ return FU_ARCHIVE_COMPRESSION_GZIP;
+ if (g_strcmp0(compression, "bzip2") == 0)
+ return FU_ARCHIVE_COMPRESSION_BZIP2;
+ if (g_strcmp0(compression, "compress") == 0)
+ return FU_ARCHIVE_COMPRESSION_COMPRESS;
+ if (g_strcmp0(compression, "lzma") == 0)
+ return FU_ARCHIVE_COMPRESSION_LZMA;
+ if (g_strcmp0(compression, "xz") == 0)
+ return FU_ARCHIVE_COMPRESSION_XZ;
+ if (g_strcmp0(compression, "uuencode") == 0)
+ return FU_ARCHIVE_COMPRESSION_UU;
+ if (g_strcmp0(compression, "lzip") == 0)
+ return FU_ARCHIVE_COMPRESSION_LZIP;
+ if (g_strcmp0(compression, "lrzip") == 0)
+ return FU_ARCHIVE_COMPRESSION_LRZIP;
+ if (g_strcmp0(compression, "lzop") == 0)
+ return FU_ARCHIVE_COMPRESSION_LZOP;
+ if (g_strcmp0(compression, "grzip") == 0)
+ return FU_ARCHIVE_COMPRESSION_GRZIP;
+ if (g_strcmp0(compression, "lz4") == 0)
+ return FU_ARCHIVE_COMPRESSION_LZ4;
+ if (g_strcmp0(compression, "zstd") == 0)
+ return FU_ARCHIVE_COMPRESSION_ZSTD;
+ return FU_ARCHIVE_COMPRESSION_UNKNOWN;
+}
+
+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_add_entry:
+ * @self: a #FuArchive
+ * @fn: (not nullable): a filename
+ * @blob: (not nullable): a #GBytes
+ *
+ * Adds, or replaces an entry to an archive.
+ *
+ * Since: 1.8.1
+ **/
+void
+fu_archive_add_entry(FuArchive *self, const gchar *fn, GBytes *blob)
+{
+ g_return_if_fail(FU_IS_ARCHIVE(self));
+ g_return_if_fail(fn != NULL);
+ g_return_if_fail(blob != NULL);
+ g_hash_table_insert(self->entries, g_strdup(fn), g_bytes_ref(blob));
+}
+
+/**
+ * fu_archive_lookup_by_fn:
+ * @self: a #FuArchive
+ * @fn: a filename
+ * @error: (nullable): optional return location for an error
+ *
+ * Finds the blob referenced by filename
+ *
+ * Returns: (transfer none): a #GBytes, or %NULL if the filename was not found
+ *
+ * Since: 1.2.2
+ **/
+GBytes *
+fu_archive_lookup_by_fn(FuArchive *self, const gchar *fn, GError **error)
+{
+ GBytes *bytes;
+
+ 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);
+
+ bytes = g_hash_table_lookup(self->entries, fn);
+ if (bytes == NULL) {
+ g_set_error(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "no blob for %s", fn);
+ }
+ return bytes;
+}
+
+/**
+ * fu_archive_iterate:
+ * @self: a #FuArchive
+ * @callback: (scope call): a #FuArchiveIterateFunc.
+ * @user_data: user data
+ * @error: (nullable): optional return location for an error
+ *
+ * Iterates over the archive contents, calling the given function for each
+ * of the files found. If any @callback returns %FALSE scanning is aborted.
+ *
+ * Returns: True if no @callback returned FALSE
+ *
+ * Since: 1.3.4
+ */
+gboolean
+fu_archive_iterate(FuArchive *self,
+ FuArchiveIterateFunc callback,
+ gpointer user_data,
+ GError **error)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail(FU_IS_ARCHIVE(self), FALSE);
+ g_return_val_if_fail(callback != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ g_hash_table_iter_init(&iter, self->entries);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (!callback(self, (const gchar *)key, (GBytes *)value, user_data, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#ifdef HAVE_LIBARCHIVE
+/* 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)
+
+typedef struct archive _archive_write_ctx;
+
+static void
+_archive_write_ctx_free(_archive_write_ctx *arch)
+{
+ archive_write_close(arch);
+ archive_write_free(arch);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_write_ctx, _archive_write_ctx_free)
+
+typedef struct archive_entry _archive_entry_ctx;
+
+static void
+_archive_entry_ctx_free(_archive_entry_ctx *entry)
+{
+ archive_entry_free(entry);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(_archive_entry_ctx, _archive_entry_ctx_free)
+
+static void
+fu_archive_set_format(_archive_write_ctx *arch, FuArchiveFormat format)
+{
+ if (format == FU_ARCHIVE_FORMAT_CPIO)
+ archive_write_set_format_cpio(arch);
+ if (format == FU_ARCHIVE_FORMAT_SHAR)
+ archive_write_set_format_shar(arch);
+ if (format == FU_ARCHIVE_FORMAT_TAR)
+ archive_write_set_format_pax_restricted(arch);
+ if (format == FU_ARCHIVE_FORMAT_USTAR)
+ archive_write_set_format_ustar(arch);
+ if (format == FU_ARCHIVE_FORMAT_PAX)
+ archive_write_set_format_pax(arch);
+ if (format == FU_ARCHIVE_FORMAT_GNUTAR)
+ archive_write_set_format_gnutar(arch);
+ if (format == FU_ARCHIVE_FORMAT_ISO9660)
+ archive_write_set_format_iso9660(arch);
+ if (format == FU_ARCHIVE_FORMAT_ZIP)
+ archive_write_set_format_zip(arch);
+ if (format == FU_ARCHIVE_FORMAT_AR)
+ archive_write_set_format_ar_bsd(arch);
+ if (format == FU_ARCHIVE_FORMAT_AR_SVR4)
+ archive_write_set_format_ar_svr4(arch);
+ if (format == FU_ARCHIVE_FORMAT_MTREE)
+ archive_write_set_format_mtree(arch);
+ if (format == FU_ARCHIVE_FORMAT_RAW)
+ archive_write_set_format_raw(arch);
+ if (format == FU_ARCHIVE_FORMAT_XAR)
+ archive_write_set_format_xar(arch);
+ if (format == FU_ARCHIVE_FORMAT_7ZIP)
+ archive_write_set_format_7zip(arch);
+ if (format == FU_ARCHIVE_FORMAT_WARC)
+ archive_write_set_format_warc(arch);
+}
+
+static void
+fu_archive_set_compression(_archive_write_ctx *arch, FuArchiveCompression compression)
+{
+ if (compression == FU_ARCHIVE_COMPRESSION_BZIP2)
+ archive_write_add_filter_bzip2(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_COMPRESS)
+ archive_write_add_filter_compress(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_GRZIP)
+ archive_write_add_filter_grzip(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_GZIP)
+ archive_write_add_filter_gzip(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_LRZIP)
+ archive_write_add_filter_lrzip(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_LZ4)
+ archive_write_add_filter_lz4(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_LZIP)
+ archive_write_add_filter_lzip(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_LZMA)
+ archive_write_add_filter_lzma(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_LZOP)
+ archive_write_add_filter_lzop(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_UU)
+ archive_write_add_filter_uuencode(arch);
+ if (compression == FU_ARCHIVE_COMPRESSION_XZ)
+ archive_write_add_filter_xz(arch);
+#ifdef HAVE_LIBARCHIVE_WRITE_ADD_COMPRESSION_ZSTD
+ if (compression == FU_ARCHIVE_COMPRESSION_ZSTD)
+ archive_write_add_filter_zstd(arch);
+#endif
+}
+#endif
+
+static gboolean
+fu_archive_load(FuArchive *self, GBytes *blob, FuArchiveFlags flags, GError **error)
+{
+#ifdef HAVE_LIBARCHIVE
+ 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;
+ g_autoptr(GBytes) bytes = 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);
+ bytes = g_bytes_new_take(g_steal_pointer(&buf), bufsz);
+ fu_archive_add_entry(self, fn_key, bytes);
+ }
+
+ /* success */
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "missing libarchive support");
+ return FALSE;
+#endif
+}
+
+/**
+ * fu_archive_new:
+ * @data: (nullable): archive contents
+ * @flags: archive flags, e.g. %FU_ARCHIVE_FLAG_NONE
+ * @error: (nullable): optional return location for an error
+ *
+ * Parses @data as an archive and decompresses all files to memory blobs.
+ *
+ * If @data is unspecified then a new empty archive is created.
+ *
+ * Returns: a #FuArchive, or %NULL if the archive was invalid in any way.
+ *
+ * Since: 1.2.2
+ **/
+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(error == NULL || *error == NULL, NULL);
+ if (data != NULL) {
+ if (!fu_archive_load(self, data, flags, error))
+ return NULL;
+ }
+ return g_steal_pointer(&self);
+}
+
+#ifdef HAVE_LIBARCHIVE
+static gssize
+fu_archive_write_cb(struct archive *arch, void *user_data, const void *buf, gsize bufsz)
+{
+ GByteArray *blob = (GByteArray *)user_data;
+ g_byte_array_append(blob, buf, bufsz);
+ return (gssize)bufsz;
+}
+#endif
+
+/**
+ * fu_archive_write:
+ * @self: a #FuArchive
+ * @format: a compression, e.g. `FU_ARCHIVE_FORMAT_ZIP`
+ * @compression: a compression, e.g. `FU_ARCHIVE_COMPRESSION_NONE`
+ * @error: (nullable): optional return location for an error
+ *
+ * Writes an archive with specified @format and @compression.
+ *
+ * Returns: (transfer full): the archive blob
+ *
+ * Since: 1.8.1
+ **/
+GBytes *
+fu_archive_write(FuArchive *self,
+ FuArchiveFormat format,
+ FuArchiveCompression compression,
+ GError **error)
+{
+#ifdef HAVE_LIBARCHIVE
+ int r;
+ g_autoptr(_archive_write_ctx) arch = NULL;
+ g_autoptr(GByteArray) blob = g_byte_array_new();
+ g_autoptr(GList) keys = NULL;
+
+ g_return_val_if_fail(FU_IS_ARCHIVE(self), NULL);
+ g_return_val_if_fail(format != FU_ARCHIVE_FORMAT_UNKNOWN, NULL);
+ g_return_val_if_fail(compression != FU_ARCHIVE_COMPRESSION_UNKNOWN, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* sanity check */
+#ifndef HAVE_LIBARCHIVE_WRITE_ADD_COMPRESSION_ZSTD
+ if (compression == FU_ARCHIVE_COMPRESSION_ZSTD) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "archive_write_add_filter_zstd() not supported");
+ return NULL;
+ }
+#endif
+
+ /* compress anything matching either glob */
+ arch = archive_write_new();
+ if (arch == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "libarchive startup failed");
+ return NULL;
+ }
+ fu_archive_set_compression(arch, compression);
+ fu_archive_set_format(arch, format);
+ r = archive_write_open(arch, blob, NULL, fu_archive_write_cb, NULL);
+ if (r != 0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "cannot open: %s",
+ archive_error_string(arch));
+ return NULL;
+ }
+
+ keys = g_hash_table_get_keys(self->entries);
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *fn = l->data;
+ GBytes *bytes = g_hash_table_lookup(self->entries, fn);
+ gssize rc;
+ g_autoptr(_archive_entry_ctx) entry = NULL;
+
+ entry = archive_entry_new();
+ archive_entry_set_pathname(entry, fn);
+ archive_entry_set_filetype(entry, AE_IFREG);
+ archive_entry_set_perm(entry, 0644);
+ archive_entry_set_size(entry, g_bytes_get_size(bytes));
+
+ r = archive_write_header(arch, entry);
+ if (r != 0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "cannot write header: %s",
+ archive_error_string(arch));
+ return NULL;
+ }
+ rc = archive_write_data(arch,
+ g_bytes_get_data(bytes, NULL),
+ g_bytes_get_size(bytes));
+ if (rc < 0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "cannot write data: %s",
+ archive_error_string(arch));
+ return NULL;
+ }
+ }
+
+ r = archive_write_close(arch);
+ if (r != 0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "cannot close: %s",
+ archive_error_string(arch));
+ return NULL;
+ }
+
+ /* success */
+ return g_byte_array_free_to_bytes(g_steal_pointer(&blob));
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "missing libarchive support");
+ return NULL;
+#endif
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-archive.h b/fwupd-1.8.6/libfwupdplugin/fu-archive.h
new file mode 100644
index 0000000000000000000000000000000000000000..23a210b61096338fc1100a308cf1305ff7ea98d4
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-archive.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 Richard Hughes
+ * Copyright (C) 2022 Gaël PORTAY
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#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;
+
+/**
+ * FuArchiveFormat:
+ * @FU_ARCHIVE_FORMAT_UNKNOWN: unknown
+ * @FU_ARCHIVE_FORMAT_CPIO: ASCII cpio
+ * @FU_ARCHIVE_FORMAT_SHAR: shar
+ * @FU_ARCHIVE_FORMAT_TAR: tar
+ * @FU_ARCHIVE_FORMAT_USTAR: POSIX ustar
+ * @FU_ARCHIVE_FORMAT_PAX: restricted POSIX pax interchange
+ * @FU_ARCHIVE_FORMAT_GNUTAR: GNU tar
+ * @FU_ARCHIVE_FORMAT_ISO9660: ISO9660
+ * @FU_ARCHIVE_FORMAT_ZIP: ZIP
+ * @FU_ARCHIVE_FORMAT_AR: ar (BSD)
+ * @FU_ARCHIVE_FORMAT_AR_SVR4: ar (GNU/SVR4)
+ * @FU_ARCHIVE_FORMAT_MTREE: mtree
+ * @FU_ARCHIVE_FORMAT_RAW: raw
+ * @FU_ARCHIVE_FORMAT_XAR: xar
+ * @FU_ARCHIVE_FORMAT_7ZIP: 7-Zip
+ * @FU_ARCHIVE_FORMAT_WARC: WARC
+ *
+ * The archive format.
+ **/
+typedef enum {
+ FU_ARCHIVE_FORMAT_UNKNOWN, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_CPIO, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_SHAR, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_TAR, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_USTAR, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_PAX, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_GNUTAR, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_ISO9660, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_ZIP, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_AR, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_AR_SVR4, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_MTREE, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_RAW, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_XAR, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_7ZIP, /* Since: 1.8.1 */
+ FU_ARCHIVE_FORMAT_WARC, /* Since: 1.8.1 */
+} FuArchiveFormat;
+
+/**
+ * FuArchiveCompression:
+ * @FU_ARCHIVE_COMPRESSION_UNKNOWN: unknown
+ * @FU_ARCHIVE_COMPRESSION_NONE: none
+ * @FU_ARCHIVE_COMPRESSION_GZIP: Gzip (GNU Zip)
+ * @FU_ARCHIVE_COMPRESSION_BZIP2: Bzip2
+ * @FU_ARCHIVE_COMPRESSION_COMPRESS: compress (LZW)
+ * @FU_ARCHIVE_COMPRESSION_LZMA: LZMA
+ * @FU_ARCHIVE_COMPRESSION_XZ: XZ
+ * @FU_ARCHIVE_COMPRESSION_UU: Unix-to-Unix
+ * @FU_ARCHIVE_COMPRESSION_LZIP: LZip (LZMA)
+ * @FU_ARCHIVE_COMPRESSION_LRZIP: Long Range Zip (LZMA RZIP)
+ * @FU_ARCHIVE_COMPRESSION_LZOP: LZO
+ * @FU_ARCHIVE_COMPRESSION_GRZIP: GRZip
+ * @FU_ARCHIVE_COMPRESSION_LZ4: LZ4
+ * @FU_ARCHIVE_COMPRESSION_ZSTD: Zstd
+ *
+ * The archive compression.
+ **/
+typedef enum {
+ FU_ARCHIVE_COMPRESSION_UNKNOWN, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_NONE, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_GZIP, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_BZIP2, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_COMPRESS, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_LZMA, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_XZ, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_UU, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_LZIP, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_LRZIP, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_LZOP, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_GRZIP, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_LZ4, /* Since: 1.8.1 */
+ FU_ARCHIVE_COMPRESSION_ZSTD, /* Since: 1.8.1 */
+} FuArchiveCompression;
+
+/**
+ * FuArchiveIterateFunc:
+ * @self: a #FuArchive
+ * @filename: a filename
+ * @bytes: the blob referenced by @filename
+ * @user_data: user data
+ * @error: a #GError or NULL
+ *
+ * The archive iteration callback.
+ */
+typedef gboolean (*FuArchiveIterateFunc)(FuArchive *self,
+ const gchar *filename,
+ GBytes *bytes,
+ gpointer user_data,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+const gchar *
+fu_archive_format_to_string(FuArchiveFormat format) G_GNUC_WARN_UNUSED_RESULT;
+FuArchiveFormat
+fu_archive_format_from_string(const gchar *format) G_GNUC_WARN_UNUSED_RESULT;
+
+FuArchiveCompression
+fu_archive_compression_from_string(const gchar *compression) G_GNUC_WARN_UNUSED_RESULT;
+const gchar *
+fu_archive_compression_to_string(FuArchiveCompression compression) G_GNUC_WARN_UNUSED_RESULT;
+
+FuArchive *
+fu_archive_new(GBytes *data, FuArchiveFlags flags, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_archive_add_entry(FuArchive *self, const gchar *fn, GBytes *blob);
+GBytes *
+fu_archive_lookup_by_fn(FuArchive *self, const gchar *fn, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_archive_write(FuArchive *self,
+ FuArchiveFormat format,
+ FuArchiveCompression compression,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_archive_iterate(FuArchive *self,
+ FuArchiveIterateFunc callback,
+ gpointer user_data,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-backend-private.h b/fwupd-1.8.6/libfwupdplugin/fu-backend-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..497870fff14ce0541c96d678569be594dc2bac17
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-backend-private.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-backend.h"
+
+gboolean
+fu_backend_load(FuBackend *self,
+ JsonObject *json_object,
+ const gchar *tag,
+ FuBackendLoadFlags flags,
+ GError **error);
+gboolean
+fu_backend_save(FuBackend *self,
+ JsonBuilder *json_builder,
+ const gchar *tag,
+ FuBackendSaveFlags flags,
+ GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-backend.c b/fwupd-1.8.6/libfwupdplugin/fu-backend.c
new file mode 100644
index 0000000000000000000000000000000000000000..e8402228e74e9ee8b1b504ccfe4bea6adb1d3b7c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-backend.c
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuBackend"
+
+#include "config.h"
+
+#include "fu-backend-private.h"
+#include "fu-string.h"
+
+/**
+ * FuBackend:
+ *
+ * An device discovery backend, for instance USB, BlueZ or UDev.
+ *
+ * See also: [class@FuDevice]
+ */
+
+typedef struct {
+ FuContext *ctx;
+ gchar *name;
+ gboolean enabled;
+ gboolean done_setup;
+ gboolean can_invalidate;
+ GHashTable *devices; /* device_id : * FuDevice */
+ GThread *thread_init;
+} FuBackendPrivate;
+
+enum { SIGNAL_ADDED, SIGNAL_REMOVED, SIGNAL_CHANGED, SIGNAL_LAST };
+
+enum { PROP_0, PROP_NAME, PROP_CAN_INVALIDATE, PROP_CONTEXT, PROP_LAST };
+
+static guint signals[SIGNAL_LAST] = {0};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuBackend, fu_backend, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (fu_backend_get_instance_private(o))
+
+/**
+ * fu_backend_device_added:
+ * @self: a #FuBackend
+ * @device: a device
+ *
+ * Emits a signal that indicates the device has been added.
+ *
+ * Since: 1.6.1
+ **/
+void
+fu_backend_device_added(FuBackend *self, FuDevice *device)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_BACKEND(self));
+ g_return_if_fail(FU_IS_DEVICE(device));
+ g_return_if_fail(priv->thread_init == g_thread_self());
+
+ /* assign context if set */
+ if (priv->ctx != NULL)
+ fu_device_set_context(device, priv->ctx);
+
+ /* add */
+ g_hash_table_insert(priv->devices,
+ g_strdup(fu_device_get_backend_id(device)),
+ g_object_ref(device));
+ g_signal_emit(self, signals[SIGNAL_ADDED], 0, device);
+}
+
+/**
+ * fu_backend_device_removed:
+ * @self: a #FuBackend
+ * @device: a device
+ *
+ * Emits a signal that indicates the device has been removed.
+ *
+ * Since: 1.6.1
+ **/
+void
+fu_backend_device_removed(FuBackend *self, FuDevice *device)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_BACKEND(self));
+ g_return_if_fail(FU_IS_DEVICE(device));
+ g_return_if_fail(priv->thread_init == g_thread_self());
+ g_signal_emit(self, signals[SIGNAL_REMOVED], 0, device);
+ g_hash_table_remove(priv->devices, fu_device_get_backend_id(device));
+}
+
+/**
+ * fu_backend_device_changed:
+ * @self: a #FuBackend
+ * @device: a device
+ *
+ * Emits a signal that indicates the device has been changed.
+ *
+ * Since: 1.6.1
+ **/
+void
+fu_backend_device_changed(FuBackend *self, FuDevice *device)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_BACKEND(self));
+ g_return_if_fail(FU_IS_DEVICE(device));
+ g_return_if_fail(priv->thread_init == g_thread_self());
+ g_signal_emit(self, signals[SIGNAL_CHANGED], 0, device);
+}
+
+/**
+ * fu_backend_registered:
+ * @self: a #FuBackend
+ * @device: a device
+ *
+ * Calls the ->registered() vfunc for the backend. This allows the backend to perform shared
+ * backend actions on superclassed devices.
+ *
+ * Since: 1.7.4
+ **/
+void
+fu_backend_registered(FuBackend *self, FuDevice *device)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+ g_return_if_fail(FU_IS_BACKEND(self));
+ g_return_if_fail(FU_IS_DEVICE(device));
+ if (klass->registered != NULL)
+ klass->registered(self, device);
+}
+
+/**
+ * fu_backend_invalidate:
+ * @self: a #FuBackend
+ *
+ * Normally when calling [method@FuBackend.setup] multiple times it is only actually done once.
+ * Calling this method causes the next requests to [method@FuBackend.setup] to actually probe the
+ * hardware.
+ *
+ * Only subclassed backends setting `can-invalidate=TRUE` at construction time can use this
+ * method, as it is not always safe to call for backends shared between multiple plugins.
+ *
+ * This should be done in case the backing information source has changed, for instance if
+ * a platform subsystem has been updated.
+ *
+ * This also optionally calls the ->invalidate() vfunc for the backend. This allows the backend
+ * to perform shared backend actions on superclassed devices.
+ *
+ * Since: 1.8.0
+ **/
+void
+fu_backend_invalidate(FuBackend *self)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_BACKEND(self));
+ g_return_if_fail(priv->can_invalidate);
+
+ priv->done_setup = FALSE;
+ if (klass->invalidate != NULL)
+ klass->invalidate(self);
+}
+
+/**
+ * fu_backend_add_string:
+ * @self: a #FuBackend
+ * @idt: indent level
+ * @str: a string to append to
+ *
+ * Add backend-specific device metadata to an existing string.
+ *
+ * Since: 1.8.4
+ **/
+void
+fu_backend_add_string(FuBackend *self, guint idt, GString *str)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+
+ fu_string_append(str, idt, G_OBJECT_TYPE_NAME(self), "");
+ if (priv->name != NULL)
+ fu_string_append(str, idt + 1, "Name", priv->name);
+ fu_string_append_kb(str, idt + 1, "Enabled", priv->enabled);
+ fu_string_append_kb(str, idt + 1, "DoneSetup", priv->done_setup);
+ fu_string_append_kb(str, idt + 1, "CanInvalidate", priv->can_invalidate);
+
+ /* subclassed */
+ if (klass->to_string != NULL)
+ klass->to_string(self, idt, str);
+}
+
+/**
+ * fu_backend_setup:
+ * @self: a #FuBackend
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets up the backend ready for use, which typically calls the subclassed setup
+ * function. No devices should be added or removed at this point.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.6.1
+ **/
+gboolean
+fu_backend_setup(FuBackend *self, FuProgress *progress, GError **error)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FU_IS_BACKEND(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ if (priv->done_setup)
+ return TRUE;
+ if (klass->setup != NULL) {
+ if (!klass->setup(self, progress, error)) {
+ priv->enabled = FALSE;
+ return FALSE;
+ }
+ }
+ priv->done_setup = TRUE;
+ return TRUE;
+}
+
+/**
+ * fu_backend_load:
+ * @self: a #FuBackend
+ * @json_object: a #JsonObject
+ * @tag: a string backend tag, or %NULL
+ * @flags: %FuBackendLoadFlags, typically `FU_BACKEND_LOAD_FLAG_NONE`
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads the backend from a JSON object.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.5
+ **/
+gboolean
+fu_backend_load(FuBackend *self,
+ JsonObject *json_object,
+ const gchar *tag,
+ FuBackendLoadFlags flags,
+ GError **error)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_BACKEND(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* optional */
+ if (klass->load != NULL) {
+ if (!klass->load(self, json_object, tag, flags, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * fu_backend_save:
+ * @self: a #FuBackend
+ * @json_builder: a #JsonBuilder
+ * @tag: a string backend tag, or %NULL
+ * @flags: %FuBackendSaveFlags, typically `FU_BACKEND_SAVE_FLAG_NONE`
+ * @error: (nullable): optional return location for an error
+ *
+ * Saves the backend to a JSON builder.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.5
+ **/
+gboolean
+fu_backend_save(FuBackend *self,
+ JsonBuilder *json_builder,
+ const gchar *tag,
+ FuBackendSaveFlags flags,
+ GError **error)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_BACKEND(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* optional */
+ if (klass->save != NULL) {
+ if (!klass->save(self, json_builder, tag, flags, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * fu_backend_coldplug:
+ * @self: a #FuBackend
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * Adds devices using the subclassed backend. If [method@FuBackend.setup] has not
+ * already been called then it is run before this function automatically.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.6.1
+ **/
+gboolean
+fu_backend_coldplug(FuBackend *self, FuProgress *progress, GError **error)
+{
+ FuBackendClass *klass = FU_BACKEND_GET_CLASS(self);
+ g_return_val_if_fail(FU_IS_BACKEND(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ if (!fu_backend_setup(self, progress, error))
+ return FALSE;
+ if (klass->coldplug == NULL)
+ return TRUE;
+ return klass->coldplug(self, progress, error);
+}
+
+/**
+ * fu_backend_get_name:
+ * @self: a #FuBackend
+ *
+ * Return the name of the backend, which is normally set by the subclass.
+ *
+ * Returns: backend name
+ *
+ * Since: 1.6.1
+ **/
+const gchar *
+fu_backend_get_name(FuBackend *self)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_BACKEND(self), NULL);
+ return priv->name;
+}
+
+/**
+ * fu_backend_get_context:
+ * @self: a #FuBackend
+ *
+ * Gets the context for a backend.
+ *
+ * Returns: (transfer none): a #FuContext or %NULL if not set
+ *
+ * Since: 1.6.1
+ **/
+FuContext *
+fu_backend_get_context(FuBackend *self)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ return priv->ctx;
+}
+
+/**
+ * fu_backend_get_enabled:
+ * @self: a #FuBackend
+ *
+ * Return the boolean value of a key if it's been configured
+ *
+ * Returns: %TRUE if the backend is enabled
+ *
+ * Since: 1.6.1
+ **/
+gboolean
+fu_backend_get_enabled(FuBackend *self)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_BACKEND(self), FALSE);
+ return priv->enabled;
+}
+
+/**
+ * fu_backend_set_enabled:
+ * @self: a #FuBackend
+ * @enabled: enabled state
+ *
+ * Sets the backend enabled state.
+ *
+ * Since: 1.6.1
+ **/
+void
+fu_backend_set_enabled(FuBackend *self, gboolean enabled)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_BACKEND(self));
+ priv->enabled = FALSE;
+}
+
+/**
+ * fu_backend_lookup_by_id:
+ * @self: a #FuBackend
+ * @device_id: a DeviceID
+ *
+ * Gets a device previously added by the backend.
+ *
+ * Returns: (transfer none): device, or %NULL if not found
+ *
+ * Since: 1.6.1
+ **/
+FuDevice *
+fu_backend_lookup_by_id(FuBackend *self, const gchar *device_id)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_BACKEND(self), NULL);
+ return g_hash_table_lookup(priv->devices, device_id);
+}
+
+static gint
+fu_backend_get_devices_sort_cb(gconstpointer a, gconstpointer b)
+{
+ FuDevice *deva = *((FuDevice **)a);
+ FuDevice *devb = *((FuDevice **)b);
+ return g_strcmp0(fu_device_get_backend_id(deva), fu_device_get_backend_id(devb));
+}
+
+/**
+ * fu_backend_get_devices:
+ * @self: a #FuBackend
+ *
+ * Gets all the devices added by the backend.
+ *
+ * Returns: (transfer container) (element-type FuDevice): devices
+ *
+ * Since: 1.6.1
+ **/
+GPtrArray *
+fu_backend_get_devices(FuBackend *self)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GList) values = NULL;
+ g_autoptr(GPtrArray) devices = NULL;
+
+ g_return_val_if_fail(FU_IS_BACKEND(self), NULL);
+
+ devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ values = g_hash_table_get_values(priv->devices);
+ for (GList *l = values; l != NULL; l = l->next)
+ g_ptr_array_add(devices, g_object_ref(l->data));
+ g_ptr_array_sort(devices, fu_backend_get_devices_sort_cb);
+ return g_steal_pointer(&devices);
+}
+
+static void
+fu_backend_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FuBackend *self = FU_BACKEND(object);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string(value, priv->name);
+ break;
+ case PROP_CAN_INVALIDATE:
+ g_value_set_boolean(value, priv->can_invalidate);
+ break;
+ case PROP_CONTEXT:
+ g_value_set_object(value, priv->ctx);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_backend_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FuBackend *self = FU_BACKEND(object);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_NAME:
+ priv->name = g_value_dup_string(value);
+ break;
+ case PROP_CAN_INVALIDATE:
+ priv->can_invalidate = g_value_get_boolean(value);
+ break;
+ case PROP_CONTEXT:
+ g_set_object(&priv->ctx, g_value_get_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_backend_init(FuBackend *self)
+{
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ priv->enabled = TRUE;
+ priv->thread_init = g_thread_self();
+ priv->devices =
+ g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_object_unref);
+}
+
+static void
+fu_backend_dispose(GObject *object)
+{
+ FuBackend *self = FU_BACKEND(object);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ g_hash_table_remove_all(priv->devices);
+ G_OBJECT_CLASS(fu_backend_parent_class)->dispose(object);
+}
+
+static void
+fu_backend_finalize(GObject *object)
+{
+ FuBackend *self = FU_BACKEND(object);
+ FuBackendPrivate *priv = GET_PRIVATE(self);
+ if (priv->ctx != NULL)
+ g_object_unref(priv->ctx);
+ g_free(priv->name);
+ g_hash_table_unref(priv->devices);
+ G_OBJECT_CLASS(fu_backend_parent_class)->finalize(object);
+}
+
+static void
+fu_backend_class_init(FuBackendClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
+
+ object_class->get_property = fu_backend_get_property;
+ object_class->set_property = fu_backend_set_property;
+ object_class->finalize = fu_backend_finalize;
+ object_class->dispose = fu_backend_dispose;
+
+ /**
+ * FuBackend:name:
+ *
+ * The backend name.
+ *
+ * Since: 1.6.1
+ */
+ pspec =
+ g_param_spec_string("name",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_NAME, pspec);
+
+ /**
+ * FuBackend:can-invalidate:
+ *
+ * If the backend can be invalidated.
+ *
+ * Since: 1.8.0
+ */
+ pspec =
+ g_param_spec_boolean("can-invalidate",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_CAN_INVALIDATE, pspec);
+
+ /**
+ * FuBackend:context:
+ *
+ * The #FuContent to use.
+ *
+ * Since: 1.6.1
+ */
+ pspec =
+ g_param_spec_object("context",
+ NULL,
+ NULL,
+ FU_TYPE_CONTEXT,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_CONTEXT, pspec);
+
+ /**
+ * FuBackend::device-added:
+ * @self: the #FuBackend instance that emitted the signal
+ * @device: the #FuDevice
+ *
+ * The ::device-added signal is emitted when a device has been added.
+ *
+ * Since: 1.6.1
+ **/
+ signals[SIGNAL_ADDED] = g_signal_new("device-added",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ FU_TYPE_DEVICE);
+ /**
+ * FuBackend::device-removed:
+ * @self: the #FuBackend instance that emitted the signal
+ * @device: the #FuDevice
+ *
+ * The ::device-removed signal is emitted when a device has been removed.
+ *
+ * Since: 1.6.1
+ **/
+ signals[SIGNAL_REMOVED] = g_signal_new("device-removed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ FU_TYPE_DEVICE);
+ /**
+ * FuBackend::device-changed:
+ * @self: the #FuBackend instance that emitted the signal
+ * @device: the #FuDevice
+ *
+ * The ::device-changed signal is emitted when a device has been changed.
+ *
+ * Since: 1.6.1
+ **/
+ signals[SIGNAL_CHANGED] = g_signal_new("device-changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ FU_TYPE_DEVICE);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-backend.h b/fwupd-1.8.6/libfwupdplugin/fu-backend.h
new file mode 100644
index 0000000000000000000000000000000000000000..4233496ec5437342a925cf65948090afe59e3f13
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-backend.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fu-context.h"
+#include "fu-device.h"
+
+#define FU_TYPE_BACKEND (fu_backend_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuBackend, fu_backend, FU, BACKEND, GObject)
+
+typedef enum {
+ FU_BACKEND_LOAD_FLAG_NONE,
+} FuBackendLoadFlags;
+
+typedef enum {
+ FU_BACKEND_SAVE_FLAG_NONE,
+} FuBackendSaveFlags;
+
+struct _FuBackendClass {
+ GObjectClass parent_class;
+ /* signals */
+ gboolean (*setup)(FuBackend *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*coldplug)(FuBackend *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ void (*registered)(FuBackend *self, FuDevice *device);
+ void (*invalidate)(FuBackend *self);
+ void (*to_string)(FuBackend *self, guint indent, GString *str);
+ gboolean (*load)(FuBackend *self,
+ JsonObject *json_object,
+ const gchar *tag,
+ FuBackendLoadFlags flags,
+ GError **error);
+ gboolean (*save)(FuBackend *self,
+ JsonBuilder *json_builder,
+ const gchar *tag,
+ FuBackendSaveFlags flags,
+ GError **error);
+};
+
+const gchar *
+fu_backend_get_name(FuBackend *self);
+FuContext *
+fu_backend_get_context(FuBackend *self);
+gboolean
+fu_backend_get_enabled(FuBackend *self);
+void
+fu_backend_set_enabled(FuBackend *self, gboolean enabled);
+GPtrArray *
+fu_backend_get_devices(FuBackend *self);
+FuDevice *
+fu_backend_lookup_by_id(FuBackend *self, const gchar *device_id);
+gboolean
+fu_backend_setup(FuBackend *self, FuProgress *progress, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_backend_coldplug(FuBackend *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_backend_device_added(FuBackend *self, FuDevice *device);
+void
+fu_backend_device_removed(FuBackend *self, FuDevice *device);
+void
+fu_backend_device_changed(FuBackend *self, FuDevice *device);
+void
+fu_backend_registered(FuBackend *self, FuDevice *device);
+void
+fu_backend_invalidate(FuBackend *self);
+void
+fu_backend_add_string(FuBackend *self, guint idt, GString *str);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bios-settings-private.h b/fwupd-1.8.6/libfwupdplugin/fu-bios-settings-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0695b8ad68828332052652ed0b721d172cbb5f8
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bios-settings-private.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fu-bios-settings.h"
+
+gboolean
+fu_bios_settings_setup(FuBiosSettings *self, GError **error);
+
+GPtrArray *
+fu_bios_settings_get_all(FuBiosSettings *self);
+
+GVariant *
+fu_bios_settings_to_variant(FuBiosSettings *self, gboolean trusted);
+gboolean
+fu_bios_settings_from_json(FuBiosSettings *self, JsonNode *json_node, GError **error);
+gboolean
+fu_bios_settings_from_json_file(FuBiosSettings *self, const gchar *fn, GError **error);
+GHashTable *
+fu_bios_settings_to_hash_kv(FuBiosSettings *self);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bios-settings.c b/fwupd-1.8.6/libfwupdplugin/fu-bios-settings.c
new file mode 100644
index 0000000000000000000000000000000000000000..b06bbe47ffb19e0b8ff555a17bab957d6addce98
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bios-settings.c
@@ -0,0 +1,747 @@
+/*
+ * Copyright (C) 2022 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuBiosSettings"
+
+#include "config.h"
+
+#include
+
+#include "fwupd-bios-setting-private.h"
+#include "fwupd-error.h"
+
+#include "fu-bios-settings-private.h"
+#include "fu-path.h"
+#include "fu-string.h"
+
+struct _FuBiosSettings {
+ GObject parent_instance;
+ GHashTable *descriptions;
+ GHashTable *read_only;
+ GPtrArray *attrs;
+};
+
+G_DEFINE_TYPE(FuBiosSettings, fu_bios_settings, G_TYPE_OBJECT)
+
+static void
+fu_bios_settings_finalize(GObject *obj)
+{
+ FuBiosSettings *self = FU_BIOS_SETTINGS(obj);
+ g_ptr_array_unref(self->attrs);
+ g_hash_table_unref(self->descriptions);
+ g_hash_table_unref(self->read_only);
+ G_OBJECT_CLASS(fu_bios_settings_parent_class)->finalize(obj);
+}
+
+static void
+fu_bios_settings_class_init(FuBiosSettingsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fu_bios_settings_finalize;
+}
+
+static gboolean
+fu_bios_setting_get_key(FwupdBiosSetting *attr, const gchar *key, gchar **value_out, GError **error)
+{
+ g_autofree gchar *tmp = NULL;
+
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
+ g_return_val_if_fail(&value_out != NULL, FALSE);
+
+ tmp = g_build_filename(fwupd_bios_setting_get_path(attr), key, NULL);
+ if (!g_file_get_contents(tmp, value_out, NULL, error)) {
+ g_prefix_error(error, "failed to load %s: ", key);
+ return FALSE;
+ }
+ g_strchomp(*value_out);
+ return TRUE;
+}
+
+static gboolean
+fu_bios_setting_set_description(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
+{
+ g_autofree gchar *data = NULL;
+ const gchar *value;
+
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
+
+ /* Try ID, then name, and then key */
+ value = g_hash_table_lookup(self->descriptions, fwupd_bios_setting_get_id(attr));
+ if (value != NULL) {
+ fwupd_bios_setting_set_description(attr, value);
+ return TRUE;
+ }
+ value = g_hash_table_lookup(self->descriptions, fwupd_bios_setting_get_name(attr));
+ if (value != NULL) {
+ fwupd_bios_setting_set_description(attr, value);
+ return TRUE;
+ }
+ if (!fu_bios_setting_get_key(attr, "display_name", &data, error))
+ return FALSE;
+ fwupd_bios_setting_set_description(attr, data);
+
+ return TRUE;
+}
+
+static guint64
+fu_bios_setting_get_key_as_integer(FwupdBiosSetting *attr, const gchar *key, GError **error)
+{
+ g_autofree gchar *str = NULL;
+ guint64 tmp;
+
+ if (!fu_bios_setting_get_key(attr, key, &str, error))
+ return G_MAXUINT64;
+ if (!fu_strtoull(str, &tmp, 0, G_MAXUINT64, error)) {
+ g_prefix_error(error, "failed to convert %s to integer: ", key);
+ return G_MAXUINT64;
+ }
+ return tmp;
+}
+
+static gboolean
+fu_bios_setting_set_enumeration_attrs(FwupdBiosSetting *attr, GError **error)
+{
+ const gchar *delimiters[] = {",", ";", NULL};
+ g_autofree gchar *str = NULL;
+
+ if (!fu_bios_setting_get_key(attr, "possible_values", &str, error))
+ return FALSE;
+ for (guint j = 0; delimiters[j] != NULL; j++) {
+ g_auto(GStrv) vals = NULL;
+ if (g_strrstr(str, delimiters[j]) == NULL)
+ continue;
+ vals = fu_strsplit(str, strlen(str), delimiters[j], -1);
+ if (vals[0] != NULL)
+ fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_ENUMERATION);
+ for (guint i = 0; vals[i] != NULL && vals[i][0] != '\0'; i++)
+ fwupd_bios_setting_add_possible_value(attr, vals[i]);
+ }
+ return TRUE;
+}
+
+static gboolean
+fu_bios_setting_set_string_attrs(FwupdBiosSetting *attr, GError **error)
+{
+ guint64 tmp;
+
+ tmp = fu_bios_setting_get_key_as_integer(attr, "min_length", error);
+ if (tmp == G_MAXUINT64)
+ return FALSE;
+ fwupd_bios_setting_set_lower_bound(attr, tmp);
+ tmp = fu_bios_setting_get_key_as_integer(attr, "max_length", error);
+ if (tmp == G_MAXUINT64)
+ return FALSE;
+ fwupd_bios_setting_set_upper_bound(attr, tmp);
+ fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_STRING);
+ return TRUE;
+}
+
+static gboolean
+fu_bios_setting_set_integer_attrs(FwupdBiosSetting *attr, GError **error)
+{
+ guint64 tmp;
+
+ tmp = fu_bios_setting_get_key_as_integer(attr, "min_value", error);
+ if (tmp == G_MAXUINT64)
+ return FALSE;
+ fwupd_bios_setting_set_lower_bound(attr, tmp);
+ tmp = fu_bios_setting_get_key_as_integer(attr, "max_value", error);
+ if (tmp == G_MAXUINT64)
+ return FALSE;
+ fwupd_bios_setting_set_upper_bound(attr, tmp);
+ tmp = fu_bios_setting_get_key_as_integer(attr, "scalar_increment", error);
+ if (tmp == G_MAXUINT64)
+ return FALSE;
+ fwupd_bios_setting_set_scalar_increment(attr, tmp);
+ fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_INTEGER);
+ return TRUE;
+}
+
+static gboolean
+fu_bios_setting_set_current_value(FwupdBiosSetting *attr, GError **error)
+{
+ g_autofree gchar *str = NULL;
+
+ if (!fu_bios_setting_get_key(attr, "current_value", &str, error))
+ return FALSE;
+ fwupd_bios_setting_set_current_value(attr, str);
+ return TRUE;
+}
+
+#define LENOVO_POSSIBLE_NEEDLE "[Optional:"
+#define LENOVO_READ_ONLY_NEEDLE "[Status:ShowOnly]"
+#define LENOVO_EXCLUDED "[Excluded from boot order:"
+
+static void
+fu_bios_setting_set_read_only(FuBiosSettings *self, FwupdBiosSetting *attr)
+{
+ if (fwupd_bios_setting_get_kind(attr) == FWUPD_BIOS_SETTING_KIND_ENUMERATION) {
+ const gchar *value =
+ g_hash_table_lookup(self->read_only, fwupd_bios_setting_get_id(attr));
+ if (g_strcmp0(value, fwupd_bios_setting_get_current_value(attr)) == 0)
+ fwupd_bios_setting_set_read_only(attr, TRUE);
+ }
+}
+
+static gboolean
+fu_bios_setting_fixup_lenovo_thinklmi_bug(FwupdBiosSetting *attr, GError **error)
+{
+ const gchar *current_value = fwupd_bios_setting_get_current_value(attr);
+ const gchar *tmp;
+ g_autoptr(GString) str = NULL;
+ g_autoptr(GString) right_str = NULL;
+ g_auto(GStrv) vals = NULL;
+
+ if (g_getenv("FWUPD_BIOS_SETTING_VERBOSE") != NULL) {
+ g_debug("Processing %s: (%s)",
+ fwupd_bios_setting_get_name(attr),
+ fwupd_bios_setting_get_current_value(attr));
+ }
+
+ /* We have read only */
+ tmp = g_strrstr(current_value, LENOVO_READ_ONLY_NEEDLE);
+ if (tmp != NULL) {
+ fwupd_bios_setting_set_read_only(attr, TRUE);
+ str = g_string_new_len(current_value, tmp - current_value);
+ } else {
+ str = g_string_new(current_value);
+ }
+
+ /* empty string */
+ if (str->len == 0)
+ return TRUE;
+
+ /* split into left and right */
+ vals = fu_strsplit(str->str, str->len, ";", 2);
+
+ /* use left half for current value */
+ fwupd_bios_setting_set_current_value(attr, vals[0]);
+ if (vals[1] == NULL)
+ return TRUE;
+
+ /* use the right half to process further */
+ right_str = g_string_new(vals[1]);
+
+ /* Strip boot order exclusion info */
+ tmp = g_strrstr(right_str->str, LENOVO_EXCLUDED);
+ if (tmp != NULL)
+ g_string_truncate(str, tmp - right_str->str);
+
+ /* Look for possible values to populate */
+ tmp = g_strrstr(right_str->str, LENOVO_POSSIBLE_NEEDLE);
+ if (tmp != NULL) {
+ g_auto(GStrv) possible_vals = NULL;
+ g_string_erase(right_str, 0, strlen(LENOVO_POSSIBLE_NEEDLE));
+ possible_vals = fu_strsplit(right_str->str, right_str->len, ",", -1);
+ if (possible_vals[0] != NULL)
+ fwupd_bios_setting_set_kind(attr, FWUPD_BIOS_SETTING_KIND_ENUMERATION);
+ for (guint i = 0; possible_vals[i] != NULL && possible_vals[i][0] != '\0'; i++) {
+ /* last string */
+ if (possible_vals[i + 1] == NULL &&
+ g_strrstr(possible_vals[i], "]") != NULL) {
+ g_auto(GStrv) stripped_vals = fu_strsplit(possible_vals[i],
+ strlen(possible_vals[i]),
+ "]",
+ -1);
+ fwupd_bios_setting_add_possible_value(attr, stripped_vals[0]);
+ continue;
+ }
+ fwupd_bios_setting_add_possible_value(attr, possible_vals[i]);
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+fu_bios_settings_run_folder_fixups(FwupdBiosSetting *attr, GError **error)
+{
+ if (fwupd_bios_setting_get_kind(attr) == FWUPD_BIOS_SETTING_KIND_UNKNOWN)
+ return fu_bios_setting_fixup_lenovo_thinklmi_bug(attr, error);
+ return TRUE;
+}
+
+static gboolean
+fu_bios_setting_set_type(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
+{
+ gboolean kernel_bug = FALSE;
+ g_autofree gchar *data = NULL;
+ g_autoptr(GError) error_key = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
+ g_return_val_if_fail(FWUPD_IS_BIOS_SETTING(attr), FALSE);
+
+ /* lenovo thinklmi seems to be missing it even though it's mandatory :/ */
+ if (!fu_bios_setting_get_key(attr, "type", &data, &error_key)) {
+#if GLIB_CHECK_VERSION(2, 64, 0)
+ g_warning_once("KERNEL BUG: 'type' attribute not exported: (%s)",
+ error_key->message);
+#else
+ g_debug("KERNEL BUG: 'type' attribute not exported: (%s)", error_key->message);
+#endif
+ kernel_bug = TRUE;
+ }
+
+ if (g_strcmp0(data, "enumeration") == 0 || kernel_bug) {
+ if (!fu_bios_setting_set_enumeration_attrs(attr, &error_local)) {
+ if (g_getenv("FWUPD_BIOS_SETTING_VERBOSE") != NULL)
+ g_debug("failed to add enumeration attrs: %s",
+ error_local->message);
+ }
+ } else if (g_strcmp0(data, "integer") == 0) {
+ if (!fu_bios_setting_set_integer_attrs(attr, &error_local)) {
+ if (g_getenv("FWUPD_BIOS_SETTING_VERBOSE") != NULL)
+ g_debug("failed to add integer attrs: %s", error_local->message);
+ }
+ } else if (g_strcmp0(data, "string") == 0) {
+ if (!fu_bios_setting_set_string_attrs(attr, &error_local)) {
+ if (g_getenv("FWUPD_BIOS_SETTING_VERBOSE") != NULL)
+ g_debug("failed to add string attrs: %s", error_local->message);
+ }
+ }
+ return TRUE;
+}
+
+/* Special case attribute that is a file not a folder
+ * https://github.com/torvalds/linux/blob/v5.18/Documentation/ABI/testing/sysfs-class-firmware-attributes#L300
+ */
+static gboolean
+fu_bios_setting_set_file_attributes(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
+{
+ g_autofree gchar *value = NULL;
+
+ if (g_strcmp0(fwupd_bios_setting_get_name(attr), FWUPD_BIOS_SETTING_PENDING_REBOOT) != 0) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "%s attribute is not supported",
+ fwupd_bios_setting_get_name(attr));
+ return FALSE;
+ }
+ if (!fu_bios_setting_set_description(self, attr, error))
+ return FALSE;
+ if (!fu_bios_setting_get_key(attr, NULL, &value, error))
+ return FALSE;
+ fwupd_bios_setting_set_current_value(attr, value);
+ fwupd_bios_setting_set_read_only(attr, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+fu_bios_settings_set_folder_attributes(FuBiosSettings *self, FwupdBiosSetting *attr, GError **error)
+{
+ g_autoptr(GError) error_local = NULL;
+
+ if (!fu_bios_setting_set_type(self, attr, error))
+ return FALSE;
+ if (!fu_bios_setting_set_current_value(attr, error))
+ return FALSE;
+ if (!fu_bios_setting_set_description(self, attr, &error_local))
+ g_debug("%s", error_local->message);
+ if (!fu_bios_settings_run_folder_fixups(attr, error))
+ return FALSE;
+ fu_bios_setting_set_read_only(self, attr);
+ return TRUE;
+}
+
+static gboolean
+fu_bios_settings_populate_attribute(FuBiosSettings *self,
+ const gchar *driver,
+ const gchar *path,
+ const gchar *name,
+ GError **error)
+{
+ g_autoptr(FwupdBiosSetting) attr = NULL;
+ g_autofree gchar *id = NULL;
+
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
+ g_return_val_if_fail(name != NULL, FALSE);
+ g_return_val_if_fail(path != NULL, FALSE);
+ g_return_val_if_fail(driver != NULL, FALSE);
+
+ attr = fwupd_bios_setting_new(name, path);
+
+ id = g_strdup_printf("com.%s.%s", driver, name);
+ fwupd_bios_setting_set_id(attr, id);
+
+ if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ if (!fu_bios_settings_set_folder_attributes(self, attr, error))
+ return FALSE;
+ } else {
+ if (!fu_bios_setting_set_file_attributes(self, attr, error))
+ return FALSE;
+ }
+
+ g_ptr_array_add(self->attrs, g_object_ref(attr));
+
+ return TRUE;
+}
+
+static void
+fu_bios_settings_populate_descriptions(FuBiosSettings *self)
+{
+ g_return_if_fail(FU_IS_BIOS_SETTINGS(self));
+
+ g_hash_table_insert(self->descriptions,
+ g_strdup("pending_reboot"),
+ /* TRANSLATORS: description of a BIOS setting */
+ g_strdup(_("Settings will apply after system reboots")));
+ g_hash_table_insert(self->descriptions,
+ g_strdup("com.thinklmi.WindowsUEFIFirmwareUpdate"),
+ /* TRANSLATORS: description of a BIOS setting */
+ g_strdup(_("BIOS updates delivered via LVFS or Windows Update")));
+}
+
+static void
+fu_bios_settings_populate_read_only(FuBiosSettings *self)
+{
+ g_return_if_fail(FU_IS_BIOS_SETTINGS(self));
+
+ g_hash_table_insert(self->read_only,
+ g_strdup("com.thinklmi.SecureBoot"),
+ g_strdup(_("Enable")));
+ g_hash_table_insert(self->read_only,
+ g_strdup("com.dell-wmi-sysman.SecureBoot"),
+ g_strdup(_("Enabled")));
+}
+
+static void
+fu_bios_settings_combination_fixups(FuBiosSettings *self)
+{
+ FwupdBiosSetting *thinklmi_sb = fu_bios_settings_get_attr(self, "com.thinklmi.SecureBoot");
+ FwupdBiosSetting *thinklmi_3rd =
+ fu_bios_settings_get_attr(self, "com.thinklmi.Allow3rdPartyUEFICA");
+
+ if (thinklmi_sb != NULL && thinklmi_3rd != NULL) {
+ const gchar *val = fwupd_bios_setting_get_current_value(thinklmi_3rd);
+ if (g_strcmp0(val, "Disable") == 0) {
+ g_debug("Disabling changing %s since %s is %s",
+ fwupd_bios_setting_get_name(thinklmi_sb),
+ fwupd_bios_setting_get_name(thinklmi_3rd),
+ val);
+ fwupd_bios_setting_set_read_only(thinklmi_sb, TRUE);
+ }
+ }
+}
+
+/**
+ * fu_bios_settings_setup:
+ * @self: a #FuBiosSettings
+ *
+ * Clears all attributes and re-initializes them.
+ * Mostly used for the test suite, but could potentially be connected to udev
+ * events for drivers being loaded or unloaded too.
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fu_bios_settings_setup(FuBiosSettings *self, GError **error)
+{
+ guint count = 0;
+ g_autofree gchar *sysfsfwdir = NULL;
+ g_autoptr(GDir) class_dir = NULL;
+
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
+
+ if (self->attrs->len > 0) {
+ g_debug("re-initializing attributes");
+ g_ptr_array_set_size(self->attrs, 0);
+ }
+ if (g_hash_table_size(self->descriptions) == 0)
+ fu_bios_settings_populate_descriptions(self);
+
+ if (g_hash_table_size(self->read_only) == 0)
+ fu_bios_settings_populate_read_only(self);
+
+ sysfsfwdir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR_FW_ATTRIB);
+ class_dir = g_dir_open(sysfsfwdir, 0, error);
+ if (class_dir == NULL)
+ return FALSE;
+
+ do {
+ g_autofree gchar *path = NULL;
+ g_autoptr(GDir) driver_dir = NULL;
+ const gchar *driver = g_dir_read_name(class_dir);
+ if (driver == NULL)
+ break;
+ path = g_build_filename(sysfsfwdir, driver, "attributes", NULL);
+ if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ g_debug("skipping non-directory %s", path);
+ continue;
+ }
+ driver_dir = g_dir_open(path, 0, error);
+ if (driver_dir == NULL)
+ return FALSE;
+ do {
+ const gchar *name = g_dir_read_name(driver_dir);
+ g_autofree gchar *full_path = NULL;
+ g_autoptr(GError) error_local = NULL;
+ if (name == NULL)
+ break;
+ full_path = g_build_filename(path, name, NULL);
+ if (!fu_bios_settings_populate_attribute(self,
+ driver,
+ full_path,
+ name,
+ &error_local)) {
+ if (g_error_matches(error_local,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED)) {
+ g_debug("%s is not supported", name);
+ continue;
+ }
+ g_propagate_error(error, g_steal_pointer(&error_local));
+ return FALSE;
+ }
+ } while (++count);
+ } while (TRUE);
+ g_debug("loaded %u BIOS settings", count);
+
+ fu_bios_settings_combination_fixups(self);
+
+ return TRUE;
+}
+
+static void
+fu_bios_settings_init(FuBiosSettings *self)
+{
+ self->attrs = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ self->descriptions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ self->read_only = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+}
+
+/**
+ * fu_bios_settings_get_attr:
+ * @self: a #FuBiosSettings
+ * @val: the attribute ID or name to check for
+ *
+ * Returns: (transfer none): the attribute with the given ID or name or NULL if it doesn't exist.
+ *
+ * Since: 1.8.4
+ **/
+FwupdBiosSetting *
+fu_bios_settings_get_attr(FuBiosSettings *self, const gchar *val)
+{
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), NULL);
+ g_return_val_if_fail(val != NULL, NULL);
+
+ for (guint i = 0; i < self->attrs->len; i++) {
+ FwupdBiosSetting *attr = g_ptr_array_index(self->attrs, i);
+ const gchar *tmp_id = fwupd_bios_setting_get_id(attr);
+ const gchar *tmp_name = fwupd_bios_setting_get_name(attr);
+ if (g_strcmp0(val, tmp_id) == 0 || g_strcmp0(val, tmp_name) == 0)
+ return attr;
+ }
+ return NULL;
+}
+
+/**
+ * fu_bios_settings_get_all:
+ * @self: a #FuBiosSettings
+ *
+ * Gets all the attributes in the object.
+ *
+ * Returns: (transfer container) (element-type FwupdBiosSetting): attributes
+ *
+ * Since: 1.8.4
+ **/
+GPtrArray *
+fu_bios_settings_get_all(FuBiosSettings *self)
+{
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), NULL);
+ return g_ptr_array_ref(self->attrs);
+}
+
+/**
+ * fu_bios_settings_get_pending_reboot:
+ * @self: a #FuBiosSettings
+ * @result: (out): Whether a reboot is pending
+ * @error: (nullable): optional return location for an error
+ *
+ * Determines if the system will apply changes to attributes upon reboot
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fu_bios_settings_get_pending_reboot(FuBiosSettings *self, gboolean *result, GError **error)
+{
+ FwupdBiosSetting *attr;
+ g_autofree gchar *data = NULL;
+ guint64 val = 0;
+
+ g_return_val_if_fail(result != NULL, FALSE);
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), FALSE);
+
+ for (guint i = 0; i < self->attrs->len; i++) {
+ const gchar *tmp;
+
+ attr = g_ptr_array_index(self->attrs, i);
+ tmp = fwupd_bios_setting_get_name(attr);
+ if (g_strcmp0(tmp, FWUPD_BIOS_SETTING_PENDING_REBOOT) == 0)
+ break;
+ attr = NULL;
+ }
+
+ if (attr == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_FOUND,
+ "failed to find pending reboot attribute");
+ return FALSE;
+ }
+
+ /* refresh/re-read */
+ if (!fu_bios_setting_get_key(attr, NULL, &data, error))
+ return FALSE;
+ fwupd_bios_setting_set_current_value(attr, data);
+ if (!fu_strtoull(data, &val, 0, G_MAXUINT32, error))
+ return FALSE;
+
+ *result = (val == 1);
+
+ return TRUE;
+}
+
+/**
+ * fu_bios_settings_to_variant:
+ * @self: a #FuBiosSettings
+ * @trusted: whether the caller should receive trusted values
+ *
+ * Serializes the #FwupdBiosSetting objects.
+ *
+ * Returns: a #GVariant or %NULL
+ *
+ * Since: 1.8.4
+ **/
+GVariant *
+fu_bios_settings_to_variant(FuBiosSettings *self, gboolean trusted)
+{
+ GVariantBuilder builder;
+
+ g_return_val_if_fail(FU_IS_BIOS_SETTINGS(self), NULL);
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
+ for (guint i = 0; i < self->attrs->len; i++) {
+ FwupdBiosSetting *bios_setting = g_ptr_array_index(self->attrs, i);
+ g_variant_builder_add_value(&builder,
+ fwupd_bios_setting_to_variant(bios_setting, trusted));
+ }
+ return g_variant_new("(aa{sv})", &builder);
+}
+
+/**
+ * fu_bios_settings_from_json:
+ * @self: a #FuBiosSettings
+ * @json_node: a Json node to parse from
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads #FwupdBiosSetting objects from a JSON node.
+ *
+ * Returns: TRUE if the objects were imported
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fu_bios_settings_from_json(FuBiosSettings *self, JsonNode *json_node, GError **error)
+{
+ JsonArray *array;
+ JsonObject *obj;
+
+ /* sanity check */
+ if (!JSON_NODE_HOLDS_OBJECT(json_node)) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "not JSON object");
+ return FALSE;
+ }
+ obj = json_node_get_object(json_node);
+
+ /* this has to exist */
+ if (!json_object_has_member(obj, "BiosSettings")) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "no BiosSettings property in object");
+ return FALSE;
+ }
+ array = json_object_get_array_member(obj, "BiosSettings");
+ for (guint i = 0; i < json_array_get_length(array); i++) {
+ JsonNode *node_tmp = json_array_get_element(array, i);
+ g_autoptr(FwupdBiosSetting) attr = fwupd_bios_setting_new(NULL, NULL);
+ if (!fwupd_bios_setting_from_json(attr, node_tmp, error))
+ return FALSE;
+ g_ptr_array_add(self->attrs, g_steal_pointer(&attr));
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_bios_settings_from_json_file:
+ * @self: A #FuBiosSettings
+ * @fn: a path to a JSON file
+ * @error: (nullable): optional return location for an error
+ *
+ * Adds all BIOS attributes from a JSON filename
+ *
+ * Returns: TRUE for success, FALSE for failure
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fu_bios_settings_from_json_file(FuBiosSettings *self, const gchar *fn, GError **error)
+{
+ g_autofree gchar *data = NULL;
+ g_autoptr(JsonParser) parser = json_parser_new();
+
+ if (!g_file_get_contents(fn, &data, NULL, error))
+ return FALSE;
+ if (!json_parser_load_from_data(parser, data, -1, error)) {
+ g_prefix_error(error, "%s doesn't look like JSON data: ", fn);
+ return FALSE;
+ }
+ return fu_bios_settings_from_json(self, json_parser_get_root(parser), error);
+}
+
+/**
+ * fu_bios_settings_to_hash_kv:
+ * @self: A #FuBiosSettings
+ *
+ * Creates a #GHashTable with the name and current value of
+ * all BIOS settings.
+ *
+ * Returns: (transfer full): name/value pairs
+ * Since: 1.8.4
+ **/
+GHashTable *
+fu_bios_settings_to_hash_kv(FuBiosSettings *self)
+{
+ GHashTable *bios_settings = NULL;
+
+ g_return_val_if_fail(self != NULL, NULL);
+
+ bios_settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ for (guint i = 0; i < self->attrs->len; i++) {
+ FwupdBiosSetting *item_setting = g_ptr_array_index(self->attrs, i);
+ g_hash_table_insert(bios_settings,
+ g_strdup(fwupd_bios_setting_get_id(item_setting)),
+ g_strdup(fwupd_bios_setting_get_current_value(item_setting)));
+ }
+ return bios_settings;
+}
+
+/**
+ * fu_bios_settings_new:
+ *
+ * Returns: #FuBiosSettings
+ *
+ * Since: 1.8.4
+ **/
+FuBiosSettings *
+fu_bios_settings_new(void)
+{
+ return g_object_new(FU_TYPE_FIRMWARE_ATTRS, NULL);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bios-settings.h b/fwupd-1.8.6/libfwupdplugin/fu-bios-settings.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb39502ff7d8fd3a37752f36a1c9550083d6df91
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bios-settings.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#define FU_TYPE_FIRMWARE_ATTRS (fu_bios_settings_get_type())
+
+G_DECLARE_FINAL_TYPE(FuBiosSettings, fu_bios_settings, FU, BIOS_SETTINGS, GObject)
+
+FuBiosSettings *
+fu_bios_settings_new(void);
+gboolean
+fu_bios_settings_get_pending_reboot(FuBiosSettings *self, gboolean *result, GError **error);
+FwupdBiosSetting *
+fu_bios_settings_get_attr(FuBiosSettings *self, const gchar *val);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bluez-device.c b/fwupd-1.8.6/libfwupdplugin/fu-bluez-device.c
new file mode 100644
index 0000000000000000000000000000000000000000..31077e1285b581d112f47ba9a20cec991603cb9e
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bluez-device.c
@@ -0,0 +1,721 @@
+/*
+ * Copyright (C) 2021 Ricardo Cañuelo
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuBluezDevice"
+
+#include "config.h"
+
+#include
+
+#include "fu-bluez-device.h"
+#include "fu-common.h"
+#include "fu-device-private.h"
+#include "fu-firmware-common.h"
+#include "fu-string.h"
+
+#define DEFAULT_PROXY_TIMEOUT 5000
+
+/**
+ * FuBluezDevice:
+ *
+ * A BlueZ Bluetooth device.
+ *
+ * See also: [class@FuDevice]
+ */
+
+typedef struct {
+ GDBusObjectManager *object_manager;
+ GDBusProxy *proxy;
+ GHashTable *uuids; /* utf8 : FuBluezDeviceUuidHelper */
+} FuBluezDevicePrivate;
+
+typedef struct {
+ FuBluezDevice *self;
+ gchar *uuid;
+ gchar *path;
+ gulong signal_id;
+ GDBusProxy *proxy;
+} FuBluezDeviceUuidHelper;
+
+enum { PROP_0, PROP_OBJECT_MANAGER, PROP_PROXY, PROP_LAST };
+
+enum { SIGNAL_CHANGED, SIGNAL_LAST };
+
+static guint signals[SIGNAL_LAST] = {0};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuBluezDevice, fu_bluez_device, FU_TYPE_DEVICE)
+
+#define GET_PRIVATE(o) (fu_bluez_device_get_instance_private(o))
+
+static void
+fu_bluez_uuid_free(FuBluezDeviceUuidHelper *uuid_helper)
+{
+ if (uuid_helper->path != NULL)
+ g_free(uuid_helper->path);
+ if (uuid_helper->proxy != NULL)
+ g_object_unref(uuid_helper->proxy);
+ g_free(uuid_helper->uuid);
+ g_object_unref(uuid_helper->self);
+ g_free(uuid_helper);
+}
+
+/*
+ * Looks up a UUID in the FuBluezDevice uuids table.
+ */
+static FuBluezDeviceUuidHelper *
+fu_bluez_device_get_uuid_helper(FuBluezDevice *self, const gchar *uuid, GError **error)
+{
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ FuBluezDeviceUuidHelper *uuid_helper;
+
+ uuid_helper = g_hash_table_lookup(priv->uuids, uuid);
+ if (uuid_helper == NULL) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "UUID %s not supported",
+ uuid);
+ return NULL;
+ }
+
+ return uuid_helper;
+}
+
+static void
+fu_bluez_device_signal_cb(GDBusProxy *proxy,
+ GVariant *changed_properties,
+ const GStrv invalidated_properties,
+ FuBluezDeviceUuidHelper *uuid_helper)
+{
+ g_signal_emit(uuid_helper->self, signals[SIGNAL_CHANGED], 0, uuid_helper->uuid);
+}
+
+/*
+ * Builds the GDBusProxy of the BlueZ object identified by a UUID
+ * string. If the object doesn't have a dedicated proxy yet, this
+ * creates it and saves it in the FuBluezDeviceUuidHelper object.
+ *
+ * NOTE: Currently limited to GATT characteristics.
+ */
+static gboolean
+fu_bluez_device_ensure_uuid_helper_proxy(FuBluezDeviceUuidHelper *uuid_helper, GError **error)
+{
+ if (uuid_helper->proxy != NULL)
+ return TRUE;
+ uuid_helper->proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.bluez",
+ uuid_helper->path,
+ "org.bluez.GattCharacteristic1",
+ NULL,
+ error);
+ if (uuid_helper->proxy == NULL) {
+ g_prefix_error(error, "Failed to create GDBusProxy for uuid_helper: ");
+ return FALSE;
+ }
+ g_dbus_proxy_set_default_timeout(uuid_helper->proxy, DEFAULT_PROXY_TIMEOUT);
+ uuid_helper->signal_id = g_signal_connect(G_DBUS_PROXY(uuid_helper->proxy),
+ "g-properties-changed",
+ G_CALLBACK(fu_bluez_device_signal_cb),
+ uuid_helper);
+ if (uuid_helper->signal_id <= 0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "cannot connect to signal of UUID %s",
+ uuid_helper->uuid);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+fu_bluez_device_add_uuid_path(FuBluezDevice *self, const gchar *uuid, const gchar *path)
+{
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ FuBluezDeviceUuidHelper *uuid_helper;
+ g_return_if_fail(FU_IS_BLUEZ_DEVICE(self));
+ g_return_if_fail(uuid != NULL);
+ g_return_if_fail(path != NULL);
+
+ uuid_helper = g_new0(FuBluezDeviceUuidHelper, 1);
+ uuid_helper->self = g_object_ref(self);
+ uuid_helper->uuid = g_strdup(uuid);
+ uuid_helper->path = g_strdup(path);
+ g_hash_table_insert(priv->uuids, g_strdup(uuid), uuid_helper);
+}
+
+static void
+fu_bluez_device_set_modalias(FuBluezDevice *self, const gchar *modalias)
+{
+ gsize modaliaslen = strlen(modalias);
+ guint16 vid = 0x0;
+ guint16 pid = 0x0;
+ guint16 rev = 0x0;
+
+ g_return_if_fail(modalias != NULL);
+
+ /* usb:v0461p4EEFd0001 */
+ if (g_str_has_prefix(modalias, "usb:")) {
+ fu_firmware_strparse_uint16_safe(modalias, modaliaslen, 5, &vid, NULL);
+ fu_firmware_strparse_uint16_safe(modalias, modaliaslen, 10, &pid, NULL);
+ fu_firmware_strparse_uint16_safe(modalias, modaliaslen, 15, &rev, NULL);
+
+ /* bluetooth:v000ApFFFFdFFFF */
+ } else if (g_str_has_prefix(modalias, "bluetooth:")) {
+ fu_firmware_strparse_uint16_safe(modalias, modaliaslen, 11, &vid, NULL);
+ fu_firmware_strparse_uint16_safe(modalias, modaliaslen, 16, &pid, NULL);
+ fu_firmware_strparse_uint16_safe(modalias, modaliaslen, 21, &rev, NULL);
+ }
+
+ /* add generated IDs */
+ if (vid != 0x0)
+ fu_device_add_instance_u16(FU_DEVICE(self), "VID", vid);
+ if (pid != 0x0)
+ fu_device_add_instance_u16(FU_DEVICE(self), "PID", pid);
+ fu_device_add_instance_u16(FU_DEVICE(self), "REV", rev);
+ fu_device_build_instance_id_quirk(FU_DEVICE(self), NULL, "BLUETOOTH", "VID", NULL);
+ fu_device_build_instance_id(FU_DEVICE(self), NULL, "BLUETOOTH", "VID", "PID", NULL);
+ fu_device_build_instance_id(FU_DEVICE(self), NULL, "BLUETOOTH", "VID", "PID", "REV", NULL);
+
+ /* set vendor ID */
+ if (vid != 0x0) {
+ g_autofree gchar *vendor_id = g_strdup_printf("BLUETOOTH:%04X", vid);
+ fu_device_add_vendor_id(FU_DEVICE(self), vendor_id);
+ }
+
+ /* set version if the revision has been set */
+ if (rev != 0x0 &&
+ fu_device_get_version_format(FU_DEVICE(self)) == FWUPD_VERSION_FORMAT_UNKNOWN) {
+ g_autofree gchar *version = NULL;
+ version = fu_version_from_uint16(rev, FWUPD_VERSION_FORMAT_BCD);
+ fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_BCD);
+ fu_device_set_version(FU_DEVICE(self), version);
+ }
+}
+
+static void
+fu_bluez_device_to_string(FuDevice *device, guint idt, GString *str)
+{
+ FuBluezDevice *self = FU_BLUEZ_DEVICE(device);
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+
+ if (priv->uuids != NULL) {
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init(&iter, priv->uuids);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ FuBluezDeviceUuidHelper *uuid_helper = (FuBluezDeviceUuidHelper *)value;
+ fu_string_append(str, idt + 1, (const gchar *)key, uuid_helper->path);
+ }
+ }
+}
+
+/*
+ * Returns the value of a property of an object specified by its path as
+ * a GVariant, or NULL if the property wasn't found.
+ */
+static GVariant *
+fu_bluez_device_get_ble_property(const gchar *obj_path,
+ const gchar *iface,
+ const gchar *prop_name,
+ GError **error)
+{
+ g_autoptr(GDBusProxy) proxy = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.bluez",
+ obj_path,
+ iface,
+ NULL,
+ error);
+ if (proxy == NULL) {
+ g_prefix_error(error, "failed to connect to %s: ", iface);
+ return NULL;
+ }
+ g_dbus_proxy_set_default_timeout(proxy, DEFAULT_PROXY_TIMEOUT);
+ val = g_dbus_proxy_get_cached_property(proxy, prop_name);
+ if (val == NULL) {
+ g_prefix_error(error, "property %s not found in %s: ", prop_name, obj_path);
+ return NULL;
+ }
+
+ return g_steal_pointer(&val);
+}
+
+/*
+ * Returns the value of the string property of an object specified by
+ * its path, or NULL if the property wasn't found.
+ *
+ * The returned string must be freed using g_free().
+ */
+static gchar *
+fu_bluez_device_get_ble_string_property(const gchar *obj_path,
+ const gchar *iface,
+ const gchar *prop_name,
+ GError **error)
+{
+ g_autoptr(GVariant) val = NULL;
+ val = fu_bluez_device_get_ble_property(obj_path, iface, prop_name, error);
+ if (val == NULL)
+ return NULL;
+ return g_variant_dup_string(val, NULL);
+}
+
+/*
+ * Populates the {uuid_helper : object_path} entries of a device for all its
+ * characteristics.
+ *
+ * TODO: Extend to services and descriptors too?
+ */
+static void
+fu_bluez_device_add_device_uuids(FuBluezDevice *self)
+{
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ g_autolist(GDBusObject) obj_list = NULL;
+
+ obj_list = g_dbus_object_manager_get_objects(priv->object_manager);
+ for (GList *l = obj_list; l != NULL; l = l->next) {
+ GDBusObject *obj = G_DBUS_OBJECT(l->data);
+ g_autoptr(GDBusInterface) iface = NULL;
+ g_autoptr(GError) error_local = NULL;
+ g_autofree gchar *obj_uuid = NULL;
+ const gchar *obj_path = g_dbus_object_get_object_path(obj);
+
+ /* not us */
+ if (!g_str_has_prefix(g_dbus_object_get_object_path(obj),
+ g_dbus_proxy_get_object_path(priv->proxy)))
+ continue;
+
+ /*
+ * TODO: Currently restricted to getting UUIDs for
+ * characteristics only, as the only use case we're
+ * going to need for now is reading/writing
+ * characteristics.
+ */
+ iface = g_dbus_object_get_interface(obj, "org.bluez.GattCharacteristic1");
+ if (iface == NULL)
+ continue;
+ obj_uuid = fu_bluez_device_get_ble_string_property(obj_path,
+ "org.bluez.GattCharacteristic1",
+ "UUID",
+ &error_local);
+ if (obj_uuid == NULL) {
+ g_debug("failed to get property: %s", error_local->message);
+ continue;
+ }
+ fu_bluez_device_add_uuid_path(self, obj_uuid, obj_path);
+ }
+}
+
+static gboolean
+fu_bluez_device_setup(FuDevice *device, GError **error)
+{
+ FuBluezDevice *self = FU_BLUEZ_DEVICE(device);
+
+ fu_bluez_device_add_device_uuids(self);
+
+ return TRUE;
+}
+
+static gboolean
+fu_bluez_device_probe(FuDevice *device, GError **error)
+{
+ FuBluezDevice *self = FU_BLUEZ_DEVICE(device);
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GVariant) val_adapter = NULL;
+ g_autoptr(GVariant) val_address = NULL;
+ g_autoptr(GVariant) val_icon = NULL;
+ g_autoptr(GVariant) val_modalias = NULL;
+ g_autoptr(GVariant) val_name = NULL;
+
+ val_address = g_dbus_proxy_get_cached_property(priv->proxy, "Address");
+ if (val_address == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "No required BLE address");
+ return FALSE;
+ }
+ fu_device_set_logical_id(device, g_variant_get_string(val_address, NULL));
+ val_adapter = g_dbus_proxy_get_cached_property(priv->proxy, "Adapter");
+ if (val_adapter != NULL)
+ fu_device_set_physical_id(device, g_variant_get_string(val_adapter, NULL));
+ val_name = g_dbus_proxy_get_cached_property(priv->proxy, "Name");
+ if (val_name != NULL)
+ fu_device_set_name(device, g_variant_get_string(val_name, NULL));
+ val_icon = g_dbus_proxy_get_cached_property(priv->proxy, "Icon");
+ if (val_icon != NULL)
+ fu_device_add_icon(device, g_variant_get_string(val_name, NULL));
+ val_modalias = g_dbus_proxy_get_cached_property(priv->proxy, "Modalias");
+ if (val_modalias != NULL)
+ fu_bluez_device_set_modalias(self, g_variant_get_string(val_modalias, NULL));
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_bluez_device_read:
+ * @self: a #FuBluezDevice
+ * @uuid: the UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002`
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads from a UUID on the device.
+ *
+ * Returns: (transfer full): data, or %NULL for error
+ *
+ * Since: 1.5.7
+ **/
+GByteArray *
+fu_bluez_device_read(FuBluezDevice *self, const gchar *uuid, GError **error)
+{
+ FuBluezDeviceUuidHelper *uuid_helper;
+ guint8 byte;
+ g_autoptr(GByteArray) buf = g_byte_array_new();
+ g_autoptr(GVariantBuilder) builder = NULL;
+ g_autoptr(GVariantIter) iter = NULL;
+ g_autoptr(GVariant) val = NULL;
+
+ uuid_helper = fu_bluez_device_get_uuid_helper(self, uuid, error);
+ if (uuid_helper == NULL)
+ return NULL;
+ if (!fu_bluez_device_ensure_uuid_helper_proxy(uuid_helper, error))
+ return NULL;
+
+ /*
+ * Call the "ReadValue" method through the proxy synchronously.
+ *
+ * The method takes one argument: an array of dicts of
+ * {string:value} specifying the options (here the option is
+ * "offset":0.
+ * The result is a byte array.
+ */
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(builder, "{sv}", "offset", g_variant_new("q", 0));
+
+ val = g_dbus_proxy_call_sync(uuid_helper->proxy,
+ "ReadValue",
+ g_variant_new("(a{sv})", builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (val == NULL) {
+ g_prefix_error(error, "Failed to read GattCharacteristic1: ");
+ return NULL;
+ }
+ g_variant_get(val, "(ay)", &iter);
+ while (g_variant_iter_loop(iter, "y", &byte))
+ g_byte_array_append(buf, &byte, 1);
+
+ /* success */
+ return g_steal_pointer(&buf);
+}
+
+/**
+ * fu_bluez_device_read_string:
+ * @self: a #FuBluezDevice
+ * @uuid: the UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002`
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads a string from a UUID on the device.
+ *
+ * Returns: (transfer full): data, or %NULL for error
+ *
+ * Since: 1.5.7
+ **/
+gchar *
+fu_bluez_device_read_string(FuBluezDevice *self, const gchar *uuid, GError **error)
+{
+ GByteArray *buf = fu_bluez_device_read(self, uuid, error);
+ if (buf == NULL)
+ return NULL;
+ return (gchar *)g_byte_array_free(buf, FALSE);
+}
+
+/**
+ * fu_bluez_device_write:
+ * @self: a #FuBluezDevice
+ * @uuid: the UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002`
+ * @buf: data array
+ * @error: (nullable): optional return location for an error
+ *
+ * Writes to a UUID on the device.
+ *
+ * Returns: %TRUE if all the data was written
+ *
+ * Since: 1.5.7
+ **/
+gboolean
+fu_bluez_device_write(FuBluezDevice *self, const gchar *uuid, GByteArray *buf, GError **error)
+{
+ FuBluezDeviceUuidHelper *uuid_helper;
+ g_autoptr(GVariantBuilder) opt_builder = NULL;
+ g_autoptr(GVariantBuilder) val_builder = NULL;
+ g_autoptr(GVariant) ret = NULL;
+ GVariant *opt_variant = NULL;
+ GVariant *val_variant = NULL;
+
+ uuid_helper = fu_bluez_device_get_uuid_helper(self, uuid, error);
+ if (uuid_helper == NULL)
+ return FALSE;
+ if (!fu_bluez_device_ensure_uuid_helper_proxy(uuid_helper, error))
+ return FALSE;
+
+ /* build the value variant */
+ val_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ for (gsize i = 0; i < buf->len; i++)
+ g_variant_builder_add(val_builder, "y", buf->data[i]);
+ val_variant = g_variant_new("ay", val_builder);
+
+ /* build the options variant (offset = 0) */
+ opt_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(opt_builder, "{sv}", "offset", g_variant_new_uint16(0));
+ opt_variant = g_variant_new("a{sv}", opt_builder);
+
+ ret = g_dbus_proxy_call_sync(uuid_helper->proxy,
+ "WriteValue",
+ g_variant_new("(@ay@a{sv})", val_variant, opt_variant),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (ret == NULL) {
+ g_prefix_error(error, "Failed to write GattCharacteristic1: ");
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_bluez_device_notify_start:
+ * @self: a #FuBluezDevice
+ * @uuid: the UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002`
+ * @error: (nullable): optional return location for an error
+ *
+ * Enables notifications for property changes in a UUID (StartNotify
+ * method).
+ *
+ * Returns: %TRUE if the method call completed successfully.
+ *
+ * Since: 1.5.8
+ **/
+gboolean
+fu_bluez_device_notify_start(FuBluezDevice *self, const gchar *uuid, GError **error)
+{
+ FuBluezDeviceUuidHelper *uuid_helper;
+ g_autoptr(GVariant) retval = NULL;
+
+ uuid_helper = fu_bluez_device_get_uuid_helper(self, uuid, error);
+ if (uuid_helper == NULL)
+ return FALSE;
+ if (!fu_bluez_device_ensure_uuid_helper_proxy(uuid_helper, error))
+ return FALSE;
+ retval = g_dbus_proxy_call_sync(uuid_helper->proxy,
+ "StartNotify",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (retval == NULL) {
+ g_prefix_error(error, "Failed to enable notifications: ");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * fu_bluez_device_notify_stop:
+ * @self: a #FuBluezDevice
+ * @uuid: the UUID, e.g. `00cde35c-7062-11eb-9439-0242ac130002`
+ * @error: (nullable): optional return location for an error
+ *
+ * Disables notifications for property changes in a UUID (StopNotify
+ * method).
+ *
+ * Returns: %TRUE if the method call completed successfully.
+ *
+ * Since: 1.5.8
+ **/
+gboolean
+fu_bluez_device_notify_stop(FuBluezDevice *self, const gchar *uuid, GError **error)
+{
+ FuBluezDeviceUuidHelper *uuid_helper;
+ g_autoptr(GVariant) retval = NULL;
+
+ uuid_helper = fu_bluez_device_get_uuid_helper(self, uuid, error);
+ if (uuid_helper == NULL)
+ return FALSE;
+ if (!fu_bluez_device_ensure_uuid_helper_proxy(uuid_helper, error))
+ return FALSE;
+ retval = g_dbus_proxy_call_sync(uuid_helper->proxy,
+ "StopNotify",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (retval == NULL) {
+ g_prefix_error(error, "Failed to enable notifications: ");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+fu_bluez_device_incorporate(FuDevice *self, FuDevice *donor)
+{
+ FuBluezDevice *uself = FU_BLUEZ_DEVICE(self);
+ FuBluezDevice *udonor = FU_BLUEZ_DEVICE(donor);
+ FuBluezDevicePrivate *priv = GET_PRIVATE(uself);
+ FuBluezDevicePrivate *privdonor = GET_PRIVATE(udonor);
+
+ if (g_hash_table_size(priv->uuids) == 0) {
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init(&iter, privdonor->uuids);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ FuBluezDeviceUuidHelper *uuid_helper = (FuBluezDeviceUuidHelper *)value;
+ fu_bluez_device_add_uuid_path(uself, (const gchar *)key, uuid_helper->path);
+ }
+ }
+ if (priv->object_manager == NULL)
+ priv->object_manager = g_object_ref(privdonor->object_manager);
+ if (priv->proxy == NULL)
+ priv->proxy = g_object_ref(privdonor->proxy);
+}
+
+static void
+fu_bluez_device_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FuBluezDevice *self = FU_BLUEZ_DEVICE(object);
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_OBJECT_MANAGER:
+ g_value_set_object(value, priv->object_manager);
+ break;
+ case PROP_PROXY:
+ g_value_set_object(value, priv->proxy);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_bluez_device_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FuBluezDevice *self = FU_BLUEZ_DEVICE(object);
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_OBJECT_MANAGER:
+ priv->object_manager = g_value_dup_object(value);
+ break;
+ case PROP_PROXY:
+ priv->proxy = g_value_dup_object(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_bluez_device_finalize(GObject *object)
+{
+ FuBluezDevice *self = FU_BLUEZ_DEVICE(object);
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_hash_table_unref(priv->uuids);
+ g_object_unref(priv->proxy);
+ g_object_unref(priv->object_manager);
+ G_OBJECT_CLASS(fu_bluez_device_parent_class)->finalize(object);
+}
+
+static void
+fu_bluez_device_init(FuBluezDevice *self)
+{
+ FuBluezDevicePrivate *priv = GET_PRIVATE(self);
+ priv->uuids = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)fu_bluez_uuid_free);
+}
+
+static void
+fu_bluez_device_class_init(FuBluezDeviceClass *klass)
+{
+ FuDeviceClass *device_class = FU_DEVICE_CLASS(klass);
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
+
+ object_class->get_property = fu_bluez_device_get_property;
+ object_class->set_property = fu_bluez_device_set_property;
+ object_class->finalize = fu_bluez_device_finalize;
+ device_class->probe = fu_bluez_device_probe;
+ device_class->setup = fu_bluez_device_setup;
+ device_class->to_string = fu_bluez_device_to_string;
+ device_class->incorporate = fu_bluez_device_incorporate;
+
+ /**
+ * FuBluezDevice::changed:
+ * @self: the #FuBluezDevice instance that emitted the signal
+ * @uuid: the UUID that changed
+ *
+ * The ::changed signal is emitted when a service with a specific UUID changed.
+ *
+ * Since: 1.5.8
+ **/
+ signals[SIGNAL_CHANGED] = g_signal_new("changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ /**
+ * FuBluezDevice:object-manager:
+ *
+ * The object manager instance for all devices.
+ *
+ * Since: 1.5.8
+ */
+ pspec = g_param_spec_object("object-manager",
+ NULL,
+ NULL,
+ G_TYPE_DBUS_OBJECT_MANAGER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_OBJECT_MANAGER, pspec);
+
+ /**
+ * FuBluezDevice:proxy:
+ *
+ * The D-Bus proxy for the object.
+ *
+ * Since: 1.5.8
+ */
+ pspec = g_param_spec_object("proxy",
+ NULL,
+ NULL,
+ G_TYPE_DBUS_PROXY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PROXY, pspec);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bluez-device.h b/fwupd-1.8.6/libfwupdplugin/fu-bluez-device.h
new file mode 100644
index 0000000000000000000000000000000000000000..b2084aa1e5e5c384942bb74035e03ca224b8ead5
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bluez-device.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 Ricardo Cañuelo
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-device.h"
+
+#define FU_TYPE_BLUEZ_DEVICE (fu_bluez_device_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuBluezDevice, fu_bluez_device, FU, BLUEZ_DEVICE, FuDevice)
+
+struct _FuBluezDeviceClass {
+ FuDeviceClass parent_class;
+ gpointer __reserved[31];
+};
+
+GByteArray *
+fu_bluez_device_read(FuBluezDevice *self, const gchar *uuid, GError **error);
+gchar *
+fu_bluez_device_read_string(FuBluezDevice *self, const gchar *uuid, GError **error);
+gboolean
+fu_bluez_device_write(FuBluezDevice *self, const gchar *uuid, GByteArray *buf, GError **error);
+gboolean
+fu_bluez_device_notify_start(FuBluezDevice *self, const gchar *uuid, GError **error);
+gboolean
+fu_bluez_device_notify_stop(FuBluezDevice *self, const gchar *uuid, GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-byte-array.c b/fwupd-1.8.6/libfwupdplugin/fu-byte-array.c
new file mode 100644
index 0000000000000000000000000000000000000000..b581d50c06d990c9538e7c79e00eedf87dbbc032
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-byte-array.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include "fu-byte-array.h"
+#include "fu-common.h"
+#include "fu-mem.h"
+
+/**
+ * fu_byte_array_append_uint8:
+ * @array: a #GByteArray
+ * @data: value
+ *
+ * Adds a 8 bit integer to a byte array.
+ *
+ * Since: 1.3.1
+ **/
+void
+fu_byte_array_append_uint8(GByteArray *array, guint8 data)
+{
+ g_byte_array_append(array, &data, sizeof(data));
+}
+
+/**
+ * fu_byte_array_append_uint16:
+ * @array: a #GByteArray
+ * @data: value
+ * @endian: endian type, e.g. #G_LITTLE_ENDIAN
+ *
+ * Adds a 16 bit integer to a byte array.
+ *
+ * Since: 1.3.1
+ **/
+void
+fu_byte_array_append_uint16(GByteArray *array, guint16 data, FuEndianType endian)
+{
+ guint8 buf[2];
+ fu_memwrite_uint16(buf, data, endian);
+ g_byte_array_append(array, buf, sizeof(buf));
+}
+
+/**
+ * fu_byte_array_append_uint32:
+ * @array: a #GByteArray
+ * @data: value
+ * @endian: endian type, e.g. #G_LITTLE_ENDIAN
+ *
+ * Adds a 32 bit integer to a byte array.
+ *
+ * Since: 1.3.1
+ **/
+void
+fu_byte_array_append_uint32(GByteArray *array, guint32 data, FuEndianType endian)
+{
+ guint8 buf[4];
+ fu_memwrite_uint32(buf, data, endian);
+ g_byte_array_append(array, buf, sizeof(buf));
+}
+
+/**
+ * fu_byte_array_append_uint64:
+ * @array: a #GByteArray
+ * @data: value
+ * @endian: endian type, e.g. #G_LITTLE_ENDIAN
+ *
+ * Adds a 64 bit integer to a byte array.
+ *
+ * Since: 1.5.8
+ **/
+void
+fu_byte_array_append_uint64(GByteArray *array, guint64 data, FuEndianType endian)
+{
+ guint8 buf[8];
+ fu_memwrite_uint64(buf, data, endian);
+ g_byte_array_append(array, buf, sizeof(buf));
+}
+
+/**
+ * fu_byte_array_append_bytes:
+ * @array: a #GByteArray
+ * @bytes: data blob
+ *
+ * Adds the contents of a GBytes to a byte array.
+ *
+ * Since: 1.5.8
+ **/
+void
+fu_byte_array_append_bytes(GByteArray *array, GBytes *bytes)
+{
+ g_byte_array_append(array, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes));
+}
+
+/**
+ * fu_byte_array_set_size:
+ * @array: a #GByteArray
+ * @length: the new size of the GByteArray
+ * @data: the byte used to pad the array
+ *
+ * Sets the size of the GByteArray, expanding with @data as required.
+ *
+ * Since: 1.8.2
+ **/
+void
+fu_byte_array_set_size(GByteArray *array, guint length, guint8 data)
+{
+ guint oldlength = array->len;
+ g_byte_array_set_size(array, length);
+ if (length > oldlength)
+ memset(array->data + oldlength, data, length - oldlength);
+}
+
+/**
+ * fu_byte_array_align_up:
+ * @array: a #GByteArray
+ * @alignment: align to this power of 2
+ * @data: the byte used to pad the array
+ *
+ * Align a byte array length to a power of 2 boundary, where @alignment is the
+ * bit position to align to. If @alignment is zero then @array is unchanged.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_byte_array_align_up(GByteArray *array, guint8 alignment, guint8 data)
+{
+ fu_byte_array_set_size(array, fu_common_align_up(array->len, alignment), data);
+}
+
+/**
+ * fu_byte_array_compare:
+ * @buf1: a data blob
+ * @buf2: another #GByteArray
+ * @error: (nullable): optional return location for an error
+ *
+ * Compares two buffers for equality.
+ *
+ * Returns: %TRUE if @buf1 and @buf2 are identical
+ *
+ * Since: 1.8.0
+ **/
+gboolean
+fu_byte_array_compare(GByteArray *buf1, GByteArray *buf2, GError **error)
+{
+ g_return_val_if_fail(buf1 != NULL, FALSE);
+ g_return_val_if_fail(buf2 != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ return fu_memcmp_safe(buf1->data, buf1->len, buf2->data, buf2->len, error);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-byte-array.h b/fwupd-1.8.6/libfwupdplugin/fu-byte-array.h
new file mode 100644
index 0000000000000000000000000000000000000000..7733131cf180e69a91aa0f80f2c100867a6c9673
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-byte-array.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-common.h"
+
+void
+fu_byte_array_set_size(GByteArray *array, guint length, guint8 data);
+void
+fu_byte_array_align_up(GByteArray *array, guint8 alignment, guint8 data);
+void
+fu_byte_array_append_uint8(GByteArray *array, guint8 data);
+void
+fu_byte_array_append_uint16(GByteArray *array, guint16 data, FuEndianType endian);
+void
+fu_byte_array_append_uint32(GByteArray *array, guint32 data, FuEndianType endian);
+void
+fu_byte_array_append_uint64(GByteArray *array, guint64 data, FuEndianType endian);
+void
+fu_byte_array_append_bytes(GByteArray *array, GBytes *bytes);
+gboolean
+fu_byte_array_compare(GByteArray *buf1, GByteArray *buf2, GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bytes.c b/fwupd-1.8.6/libfwupdplugin/fu-bytes.c
new file mode 100644
index 0000000000000000000000000000000000000000..416a5a58b1c915e435560b6ad616d3104d93b4e9
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bytes.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#ifdef HAVE_GIO_UNIX
+#include
+#endif
+
+#include "fwupd-error.h"
+
+#include "fu-bytes.h"
+#include "fu-common.h"
+#include "fu-mem.h"
+
+/**
+ * fu_bytes_set_contents:
+ * @filename: a filename
+ * @bytes: data to write
+ * @error: (nullable): optional return location for an error
+ *
+ * Writes a blob of data to a filename, creating the parent directories as
+ * required.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.8.2
+ **/
+gboolean
+fu_bytes_set_contents(const gchar *filename, GBytes *bytes, GError **error)
+{
+ const gchar *data;
+ gsize size;
+ g_autoptr(GFile) file = NULL;
+ g_autoptr(GFile) file_parent = NULL;
+
+ g_return_val_if_fail(filename != NULL, FALSE);
+ g_return_val_if_fail(bytes != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ file = g_file_new_for_path(filename);
+ file_parent = g_file_get_parent(file);
+ if (!g_file_query_exists(file_parent, NULL)) {
+ if (!g_file_make_directory_with_parents(file_parent, NULL, error))
+ return FALSE;
+ }
+ data = g_bytes_get_data(bytes, &size);
+ g_debug("writing %s with %" G_GSIZE_FORMAT " bytes", filename, size);
+ return g_file_set_contents(filename, data, size, error);
+}
+
+/**
+ * fu_bytes_get_contents:
+ * @filename: a filename
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads a blob of data from a file.
+ *
+ * Returns: a #GBytes, or %NULL for failure
+ *
+ * Since: 1.8.2
+ **/
+GBytes *
+fu_bytes_get_contents(const gchar *filename, GError **error)
+{
+ gchar *data = NULL;
+ gsize len = 0;
+
+ g_return_val_if_fail(filename != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ if (!g_file_get_contents(filename, &data, &len, error))
+ return NULL;
+ g_debug("reading %s with %" G_GSIZE_FORMAT " bytes", filename, len);
+ return g_bytes_new_take(data, len);
+}
+
+/**
+ * fu_bytes_get_contents_fd:
+ * @fd: a file descriptor
+ * @count: the maximum number of bytes to read
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads a blob from a specific file descriptor.
+ *
+ * Note: this will close the fd when done
+ *
+ * Returns: (transfer full): a #GBytes, or %NULL
+ *
+ * Since: 1.8.2
+ **/
+GBytes *
+fu_bytes_get_contents_fd(gint fd, gsize count, GError **error)
+{
+#ifdef HAVE_GIO_UNIX
+ g_autoptr(GInputStream) stream = NULL;
+
+ g_return_val_if_fail(fd > 0, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* read the entire fd to a data blob */
+ stream = g_unix_input_stream_new(fd, TRUE);
+ return fu_bytes_get_contents_stream(stream, count, error);
+#else
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "Not supported as is unavailable");
+ return NULL;
+#endif
+}
+
+/**
+ * fu_bytes_get_contents_stream:
+ * @stream: input stream
+ * @count: the maximum number of bytes to read
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads a blob from a specific input stream.
+ *
+ * Returns: (transfer full): a #GBytes, or %NULL
+ *
+ * Since: 1.8.2
+ **/
+GBytes *
+fu_bytes_get_contents_stream(GInputStream *stream, gsize count, GError **error)
+{
+ guint8 tmp[0x8000] = {0x0};
+ g_autoptr(GByteArray) buf = g_byte_array_new();
+ g_autoptr(GError) error_local = NULL;
+
+ g_return_val_if_fail(G_IS_INPUT_STREAM(stream), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* this is invalid */
+ if (count == 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "A maximum read size must be specified");
+ return NULL;
+ }
+
+ /* read from stream in 32kB chunks */
+ while (TRUE) {
+ gssize sz;
+ sz = g_input_stream_read(stream, tmp, sizeof(tmp), NULL, &error_local);
+ if (sz == 0)
+ break;
+ if (sz < 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ error_local->message);
+ return NULL;
+ }
+ g_byte_array_append(buf, tmp, sz);
+ if (buf->len > count) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "cannot read from fd: 0x%x > 0x%x",
+ buf->len,
+ (guint)count);
+ return NULL;
+ }
+ }
+ return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+}
+
+/**
+ * fu_bytes_align:
+ * @bytes: data blob
+ * @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.8.2
+ **/
+GBytes *
+fu_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_bytes_is_empty:
+ * @bytes: data blob
+ *
+ * Checks if a byte array are just empty (0xff) bytes.
+ *
+ * Returns: %TRUE if @bytes is empty
+ *
+ * Since: 1.8.2
+ **/
+gboolean
+fu_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_bytes_compare:
+ * @bytes1: a data blob
+ * @bytes2: another #GBytes
+ * @error: (nullable): optional return location for an error
+ *
+ * Compares the buffers for equality.
+ *
+ * Returns: %TRUE if @bytes1 and @bytes2 are identical
+ *
+ * Since: 1.8.2
+ **/
+gboolean
+fu_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);
+
+ buf1 = g_bytes_get_data(bytes1, &bufsz1);
+ buf2 = g_bytes_get_data(bytes2, &bufsz2);
+ return fu_memcmp_safe(buf1, bufsz1, buf2, bufsz2, error);
+}
+
+/**
+ * fu_bytes_pad:
+ * @bytes: data blob
+ * @sz: the desired size in bytes
+ *
+ * Pads a GBytes to a minimum @sz with `0xff`.
+ *
+ * Returns: (transfer full): a data blob
+ *
+ * Since: 1.8.2
+ **/
+GBytes *
+fu_bytes_pad(GBytes *bytes, gsize sz)
+{
+ gsize bytes_sz;
+
+ g_return_val_if_fail(bytes != NULL, NULL);
+ g_return_val_if_fail(sz != 0, 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);
+ }
+
+ /* not required */
+ return g_bytes_ref(bytes);
+}
+
+/**
+ * fu_bytes_new_offset:
+ * @bytes: data blob
+ * @offset: where subsection starts at
+ * @length: length of subsection
+ * @error: (nullable): optional return location for an error
+ *
+ * Creates a #GBytes which is a subsection of another #GBytes.
+ *
+ * Returns: (transfer full): a #GBytes, or #NULL if range is invalid
+ *
+ * Since: 1.8.2
+ **/
+GBytes *
+fu_bytes_new_offset(GBytes *bytes, gsize offset, gsize length, GError **error)
+{
+ g_return_val_if_fail(bytes != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* sanity check */
+ if (offset + length < length || offset + length > g_bytes_get_size(bytes)) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "cannot create bytes @0x%02x for 0x%02x "
+ "as buffer only 0x%04x bytes in size",
+ (guint)offset,
+ (guint)length,
+ (guint)g_bytes_get_size(bytes));
+ return NULL;
+ }
+ return g_bytes_new_from_bytes(bytes, offset, length);
+}
+
+/**
+ * fu_bytes_get_data_safe:
+ * @bytes: data blob
+ * @bufsz: (out) (optional): location to return size of byte data
+ * @error: (nullable): optional return location for an error
+ *
+ * Get the byte data in the #GBytes. This data should not be modified.
+ * This function will always return the same pointer for a given #GBytes.
+ *
+ * If the size of @bytes is zero, then %NULL is returned and the @error is set,
+ * which differs in behavior to that of g_bytes_get_data().
+ *
+ * This may be useful when calling g_mapped_file_new() on a zero-length file.
+ *
+ * Returns: a pointer to the byte data, or %NULL.
+ *
+ * Since: 1.6.0
+ **/
+const guint8 *
+fu_bytes_get_data_safe(GBytes *bytes, gsize *bufsz, GError **error)
+{
+ const guint8 *buf = g_bytes_get_data(bytes, bufsz);
+ if (buf == NULL) {
+ g_set_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "invalid data");
+ return NULL;
+ }
+ return buf;
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-bytes.h b/fwupd-1.8.6/libfwupdplugin/fu-bytes.h
new file mode 100644
index 0000000000000000000000000000000000000000..687e4792cebe6eb9b2635c65b07f2be29f76fc15
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-bytes.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+gboolean
+fu_bytes_set_contents(const gchar *filename,
+ GBytes *bytes,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_bytes_get_contents(const gchar *filename, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_bytes_get_contents_stream(GInputStream *stream,
+ gsize count,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_bytes_get_contents_fd(gint fd, gsize count, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_bytes_align(GBytes *bytes, gsize blksz, gchar padval);
+const guint8 *
+fu_bytes_get_data_safe(GBytes *bytes, gsize *bufsz, GError **error);
+gboolean
+fu_bytes_is_empty(GBytes *bytes);
+gboolean
+fu_bytes_compare(GBytes *bytes1, GBytes *bytes2, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_bytes_pad(GBytes *bytes, gsize sz);
+GBytes *
+fu_bytes_new_offset(GBytes *bytes, gsize offset, gsize length, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cabinet.c b/fwupd-1.8.6/libfwupdplugin/fu-cabinet.c
new file mode 100644
index 0000000000000000000000000000000000000000..733cf418a016918e495d28f898ed10fdcc38585c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cabinet.c
@@ -0,0 +1,1141 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCabinet"
+
+#include "config.h"
+
+#include
+#include
+
+#include "fwupd-common.h"
+#include "fwupd-enums.h"
+#include "fwupd-error.h"
+
+#include "fu-cabinet.h"
+#include "fu-common.h"
+#include "fu-string.h"
+
+/**
+ * FuCabinet:
+ *
+ * Cabinet archive parser and writer.
+ *
+ * See also: [class@FuArchive]
+ */
+
+struct _FuCabinet {
+ GObject parent_instance;
+ guint64 size_max;
+ GCabCabinet *gcab_cabinet;
+ gchar *container_checksum;
+ gchar *container_checksum_alt;
+ XbBuilder *builder;
+ XbSilo *silo;
+ JcatContext *jcat_context;
+ JcatFile *jcat_file;
+};
+
+G_DEFINE_TYPE(FuCabinet, fu_cabinet, G_TYPE_OBJECT)
+
+static void
+fu_cabinet_finalize(GObject *obj)
+{
+ FuCabinet *self = FU_CABINET(obj);
+ if (self->silo != NULL)
+ g_object_unref(self->silo);
+ if (self->builder != NULL)
+ g_object_unref(self->builder);
+ g_free(self->container_checksum);
+ g_free(self->container_checksum_alt);
+ g_object_unref(self->gcab_cabinet);
+ g_object_unref(self->jcat_context);
+ g_object_unref(self->jcat_file);
+ G_OBJECT_CLASS(fu_cabinet_parent_class)->finalize(obj);
+}
+
+static void
+fu_cabinet_class_init(FuCabinetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fu_cabinet_finalize;
+}
+
+static void
+fu_cabinet_init(FuCabinet *self)
+{
+ self->size_max = 1024 * 1024 * 100;
+ self->gcab_cabinet = gcab_cabinet_new();
+ self->builder = xb_builder_new();
+ self->jcat_file = jcat_file_new();
+ self->jcat_context = jcat_context_new();
+}
+
+/**
+ * fu_cabinet_set_size_max:
+ * @self: a #FuCabinet
+ * @size_max: size in bytes
+ *
+ * Sets the maximum size of the decompressed cabinet file.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_cabinet_set_size_max(FuCabinet *self, guint64 size_max)
+{
+ g_return_if_fail(FU_IS_CABINET(self));
+ self->size_max = size_max;
+}
+
+/**
+ * fu_cabinet_set_jcat_context: (skip):
+ * @self: a #FuCabinet
+ * @jcat_context: (nullable): a Jcat context
+ *
+ * Sets the Jcat context, which is used for setting the trust flags on the
+ * each release in the archive.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_cabinet_set_jcat_context(FuCabinet *self, JcatContext *jcat_context)
+{
+ g_return_if_fail(FU_IS_CABINET(self));
+ g_return_if_fail(JCAT_IS_CONTEXT(jcat_context));
+ g_set_object(&self->jcat_context, jcat_context);
+}
+
+/**
+ * fu_cabinet_get_silo: (skip):
+ * @self: a #FuCabinet
+ *
+ * Gets the silo that represents the superset metadata of all the metainfo files
+ * found in the archive.
+ *
+ * Returns: (transfer full): a #XbSilo, or %NULL if the archive has not been parsed
+ *
+ * Since: 1.4.0
+ **/
+XbSilo *
+fu_cabinet_get_silo(FuCabinet *self)
+{
+ g_return_val_if_fail(FU_IS_CABINET(self), NULL);
+ if (self->silo == NULL)
+ return NULL;
+ return g_object_ref(self->silo);
+}
+
+static GCabFile *
+fu_cabinet_get_file_by_name(FuCabinet *self, const gchar *basename)
+{
+ GPtrArray *folders = gcab_cabinet_get_folders(self->gcab_cabinet);
+ for (guint i = 0; i < folders->len; i++) {
+ GCabFolder *cabfolder = GCAB_FOLDER(g_ptr_array_index(folders, i));
+ GCabFile *cabfile = gcab_folder_get_file_by_name(cabfolder, basename);
+ if (cabfile != NULL)
+ return cabfile;
+ }
+ return NULL;
+}
+
+/**
+ * fu_cabinet_add_file:
+ * @self: a #FuCabinet
+ * @basename: filename
+ * @data: file data
+ *
+ * Adds a file to the silo.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_cabinet_add_file(FuCabinet *self, const gchar *basename, GBytes *data)
+{
+ GPtrArray *folders;
+ GCabFile *gcab_file_old;
+ g_autoptr(GCabFolder) gcab_folder = NULL;
+ g_autoptr(GCabFile) gcab_file = NULL;
+
+ g_return_if_fail(FU_IS_CABINET(self));
+ g_return_if_fail(basename != NULL);
+ g_return_if_fail(data != NULL);
+
+ /* existing file? */
+ gcab_file_old = fu_cabinet_get_file_by_name(self, basename);
+ if (gcab_file_old != NULL) {
+#ifdef HAVE_GCAB_FILE_SET_BYTES
+ gcab_file_set_bytes(gcab_file_old, data);
+#else
+ g_object_set(gcab_file_old, "bytes", data, NULL);
+#endif
+ return;
+ }
+
+ /* new file, in a possibly new folder */
+ folders = gcab_cabinet_get_folders(self->gcab_cabinet);
+ if (folders->len == 0) {
+ gcab_folder = gcab_folder_new(GCAB_COMPRESSION_NONE);
+ gcab_cabinet_add_folder(self->gcab_cabinet, gcab_folder, NULL);
+ } else {
+ gcab_folder = g_object_ref(GCAB_FOLDER(g_ptr_array_index(folders, 0)));
+ }
+ gcab_file = gcab_file_new_with_bytes(basename, data);
+ gcab_folder_add_file(gcab_folder, gcab_file, FALSE, NULL, NULL);
+}
+
+/**
+ * fu_cabinet_get_file:
+ * @self: a #FuCabinet
+ * @basename: filename
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets a file from the archive.
+ *
+ * Returns: (transfer full): a #GBytes, or %NULL if the file does not exist
+ *
+ * Since: 1.6.0
+ **/
+GBytes *
+fu_cabinet_get_file(FuCabinet *self, const gchar *basename, GError **error)
+{
+ GCabFile *cabfile;
+ GBytes *blob;
+
+ g_return_val_if_fail(FU_IS_CABINET(self), NULL);
+ g_return_val_if_fail(basename != NULL, NULL);
+
+ cabfile = fu_cabinet_get_file_by_name(self, basename);
+ if (cabfile == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "cannot find %s in archive",
+ basename);
+ return NULL;
+ }
+ blob = gcab_file_get_bytes(cabfile);
+ if (blob == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no GBytes from GCabFile firmware");
+ return NULL;
+ }
+ return g_bytes_ref(blob);
+}
+
+/* sets the firmware and signature blobs on XbNode */
+static gboolean
+fu_cabinet_parse_release(FuCabinet *self, XbNode *release, GError **error)
+{
+ GCabFile *cabfile;
+ GBytes *blob;
+ const gchar *csum_filename = NULL;
+ g_autofree gchar *basename = NULL;
+ g_autoptr(XbNode) artifact = NULL;
+ g_autoptr(XbNode) csum_tmp = NULL;
+ g_autoptr(XbNode) metadata_trust = NULL;
+ g_autoptr(XbNode) nsize = NULL;
+ g_autoptr(JcatItem) item = NULL;
+ g_autoptr(GBytes) release_flags_blob = NULL;
+ FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE;
+
+ /* we set this with XbBuilderSource before the silo was created */
+ metadata_trust = xb_node_query_first(release, "../../info/metadata_trust", NULL);
+ if (metadata_trust != NULL)
+ release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_METADATA;
+
+ /* look for source artifact first */
+ artifact = xb_node_query_first(release, "artifacts/artifact[@type='source']", NULL);
+ if (artifact != NULL) {
+ csum_filename = xb_node_query_text(artifact, "filename", NULL);
+ csum_tmp = xb_node_query_first(artifact, "checksum[@type='sha256']", NULL);
+ if (csum_tmp == NULL)
+ csum_tmp = xb_node_query_first(artifact, "checksum", NULL);
+ } else {
+ 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(csum_filename);
+ cabfile = fu_cabinet_get_file_by_name(self, basename);
+ if (cabfile == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "cannot find %s in archive",
+ basename);
+ return FALSE;
+ }
+ blob = gcab_file_get_bytes(cabfile);
+ if (blob == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no GBytes from GCabFile firmware");
+ return FALSE;
+ }
+
+ /* set the blob */
+ xb_node_set_data(release, "fwupd::FirmwareBlob", blob);
+
+ /* 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 = 0;
+ if (!fu_strtoull(xb_node_get_text(nsize), &size, 0, G_MAXSIZE, error))
+ return FALSE;
+ 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 */
+ if (csum_tmp != NULL && xb_node_get_text(csum_tmp) != NULL) {
+ const gchar *checksum_old = xb_node_get_text(csum_tmp);
+ GChecksumType checksum_type = fwupd_checksum_guess_kind(checksum_old);
+ g_autofree gchar *checksum = NULL;
+ checksum = g_compute_checksum_for_bytes(checksum_type, blob);
+ if (g_strcmp0(checksum, checksum_old) != 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;
+ }
+ }
+
+ /* find out if the payload is signed, falling back to detached */
+ item = jcat_file_get_item_by_id(self->jcat_file, basename, NULL);
+ if (item != NULL) {
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) results = NULL;
+ results = jcat_context_verify_item(self->jcat_context,
+ blob,
+ item,
+ JCAT_VERIFY_FLAG_REQUIRE_CHECKSUM |
+ JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE,
+ &error_local);
+ if (results == NULL) {
+ g_debug("failed to verify payload %s: %s", basename, error_local->message);
+ } else {
+ g_debug("verified payload %s: %u", basename, results->len);
+ release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD;
+ }
+
+ /* legacy GPG detached signature */
+ } else {
+ g_autofree gchar *basename_sig = NULL;
+ basename_sig = g_strdup_printf("%s.asc", basename);
+ cabfile = fu_cabinet_get_file_by_name(self, basename_sig);
+ if (cabfile != NULL) {
+ GBytes *data_sig;
+ g_autoptr(JcatResult) jcat_result = NULL;
+ g_autoptr(JcatBlob) jcat_blob = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ data_sig = gcab_file_get_bytes(cabfile);
+ if (data_sig == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no GBytes from GCabFile %s",
+ basename_sig);
+ return FALSE;
+ }
+ jcat_blob = jcat_blob_new(JCAT_BLOB_KIND_GPG, data_sig);
+ jcat_result = jcat_context_verify_blob(self->jcat_context,
+ blob,
+ jcat_blob,
+ JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE,
+ &error_local);
+ if (jcat_result == NULL) {
+ g_debug("failed to verify payload %s using detached: %s",
+ basename,
+ error_local->message);
+ } else {
+ g_debug("verified payload %s using detached", basename);
+ release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD;
+ }
+ }
+ }
+
+ /* this means we can get the data from fu_keyring_get_release_flags */
+ release_flags_blob = g_bytes_new(&release_flags, sizeof(release_flags));
+ xb_node_set_data(release, "fwupd::ReleaseFlags", release_flags_blob);
+
+ /* success */
+ return TRUE;
+}
+
+static gint
+fu_cabinet_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_cabinet_sort_priority_cb(XbBuilderFixup *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+ xb_builder_node_sort_children(bn, fu_cabinet_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,
+ const gchar *attr2_name,
+ const gchar *attr2_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, attr_name), attr_value) != 0)
+ continue;
+ if (g_strcmp0(xb_builder_node_get_attr(bc, attr2_name), attr2_value) == 0)
+ return g_object_ref(bc);
+ }
+ return NULL;
+}
+
+static void
+fu_cabinet_ensure_container_checksum(XbBuilderNode *bn, const gchar *type, const gchar *checksum)
+{
+ g_autoptr(XbBuilderNode) csum = NULL;
+
+ /* verify it exists */
+ csum = _xb_builder_node_get_child_by_element_attr(bn,
+ "checksum",
+ "type",
+ type,
+ "target",
+ "container");
+ if (csum == NULL) {
+ csum = xb_builder_node_insert(bn,
+ "checksum",
+ "type",
+ type,
+ "target",
+ "container",
+ NULL);
+ }
+
+ /* verify it is correct */
+ if (g_strcmp0(xb_builder_node_get_text(csum), checksum) != 0) {
+ if (xb_builder_node_get_text(csum) != NULL) {
+ g_warning("invalid container checksum %s, fixing up to %s",
+ xb_builder_node_get_text(csum),
+ checksum);
+ }
+ xb_builder_node_set_text(csum, checksum, -1);
+ }
+}
+
+static gboolean
+fu_cabinet_ensure_container_checksum_cb(XbBuilderFixup *builder_fixup,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+ FuCabinet *self = FU_CABINET(user_data);
+
+ /* not us */
+ if (g_strcmp0(xb_builder_node_get_element(bn), "release") != 0)
+ return TRUE;
+
+ fu_cabinet_ensure_container_checksum(bn, "sha1", self->container_checksum);
+ fu_cabinet_ensure_container_checksum(bn, "sha256", self->container_checksum_alt);
+ return TRUE;
+}
+
+static void
+fu_cabinet_fixup_checksum_children(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 (attr_value == NULL ||
+ g_strcmp0(xb_builder_node_get_attr(bc, attr_name), attr_value) == 0) {
+ const gchar *tmp = xb_builder_node_get_text(bc);
+ if (tmp != NULL) {
+ g_autofree gchar *lowercase = g_ascii_strdown(tmp, -1);
+ xb_builder_node_set_text(bc, lowercase, -1);
+ }
+ }
+ }
+}
+
+static gboolean
+fu_cabinet_set_lowercase_checksum_cb(XbBuilderFixup *builder_fixup,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+ if (g_strcmp0(xb_builder_node_get_element(bn), "artifact") == 0)
+ /* don't care whether it's sha256, sha1 or something else so don't check for
+ * specific value */
+ fu_cabinet_fixup_checksum_children(bn, "checksum", "type", NULL);
+ else if (g_strcmp0(xb_builder_node_get_element(bn), "release") == 0)
+ fu_cabinet_fixup_checksum_children(bn, "checksum", "target", "content");
+
+ return TRUE;
+}
+
+static gboolean
+fu_cabinet_fixup_strip_inner_text_cb(XbBuilderFixup *self,
+ XbBuilderNode *bn,
+ gpointer user_data,
+ GError **error)
+{
+#if LIBXMLB_CHECK_VERSION(0, 3, 4)
+ if (xb_builder_node_get_first_child(bn) == NULL)
+ xb_builder_node_add_flag(bn, XB_BUILDER_NODE_FLAG_STRIP_TEXT);
+#endif
+ return TRUE;
+}
+
+/* adds each GCabFile to the silo */
+static gboolean
+fu_cabinet_build_silo_file(FuCabinet *self,
+ GCabFile *cabfile,
+ FwupdReleaseFlags release_flags,
+ GError **error)
+{
+ GBytes *blob;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(XbBuilderSource) source = xb_builder_source_new();
+ g_autoptr(XbBuilderNode) bn_info = xb_builder_node_new("info");
+
+ /* indicate the metainfo file was signed */
+ if (release_flags & FWUPD_RELEASE_FLAG_TRUSTED_METADATA)
+ xb_builder_node_insert_text(bn_info, "metadata_trust", NULL, NULL);
+ xb_builder_node_insert_text(bn_info, "filename", gcab_file_get_name(cabfile), NULL);
+ xb_builder_source_set_info(source, bn_info);
+
+ /* rewrite to be under a components root */
+ xb_builder_source_set_prefix(source, "components");
+
+ /* parse file */
+ blob = gcab_file_get_bytes(cabfile);
+ if (blob == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no GBytes from GCabFile");
+ return FALSE;
+ }
+ if (!xb_builder_source_load_bytes(source,
+ blob,
+ XB_BUILDER_SOURCE_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;
+ }
+ xb_builder_import_source(self->builder, source);
+
+ /* success */
+ return TRUE;
+}
+
+static gboolean
+fu_cabinet_build_silo_metainfo(FuCabinet *self, GCabFile *cabfile, GError **error)
+{
+ FwupdReleaseFlags release_flags = FWUPD_RELEASE_FLAG_NONE;
+ const gchar *fn = gcab_file_get_extract_name(cabfile);
+ g_autoptr(JcatItem) item = NULL;
+
+ /* validate against the Jcat file */
+ item = jcat_file_get_item_by_id(self->jcat_file, fn, NULL);
+ if (item == NULL) {
+ g_debug("failed to verify %s: no JcatItem", fn);
+ } else {
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) results = NULL;
+ results = jcat_context_verify_item(self->jcat_context,
+ gcab_file_get_bytes(cabfile),
+ item,
+ JCAT_VERIFY_FLAG_REQUIRE_CHECKSUM |
+ JCAT_VERIFY_FLAG_REQUIRE_SIGNATURE,
+ &error_local);
+ if (results == NULL) {
+ g_debug("failed to verify %s: %s", fn, error_local->message);
+ } else {
+ g_debug("verified metadata %s: %u", fn, results->len);
+ release_flags |= FWUPD_RELEASE_FLAG_TRUSTED_METADATA;
+ }
+ }
+
+ /* actually parse the XML now */
+ g_debug("processing file: %s", fn);
+ if (!fu_cabinet_build_silo_file(self, cabfile, release_flags, error)) {
+ g_prefix_error(error,
+ "%s could not be loaded: ",
+ gcab_file_get_extract_name(cabfile));
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/* load the firmware.jcat files if included */
+static gboolean
+fu_cabinet_build_jcat_folder(FuCabinet *self, GCabFolder *cabfolder, GError **error)
+{
+ g_autoptr(GSList) cabfiles = gcab_folder_get_files(cabfolder);
+ for (GSList *l = cabfiles; l != NULL; l = l->next) {
+ GCabFile *cabfile = GCAB_FILE(l->data);
+ const gchar *fn = gcab_file_get_extract_name(cabfile);
+ if (g_str_has_suffix(fn, ".jcat")) {
+ GBytes *data_jcat = gcab_file_get_bytes(cabfile);
+ g_autoptr(GInputStream) istream = NULL;
+ istream = g_memory_input_stream_new_from_bytes(data_jcat);
+ if (!jcat_file_import_stream(self->jcat_file,
+ istream,
+ JCAT_IMPORT_FLAG_NONE,
+ NULL,
+ error))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/* adds each GCabFolder to the silo */
+static gboolean
+fu_cabinet_build_silo_folder(FuCabinet *self, GCabFolder *cabfolder, GError **error)
+{
+ g_autoptr(GSList) cabfiles = gcab_folder_get_files(cabfolder);
+ for (GSList *l = cabfiles; l != NULL; l = l->next) {
+ GCabFile *cabfile = GCAB_FILE(l->data);
+ const gchar *fn = gcab_file_get_extract_name(cabfile);
+ if (!g_str_has_suffix(fn, ".metainfo.xml"))
+ continue;
+ if (!fu_cabinet_build_silo_metainfo(self, cabfile, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+fu_cabinet_build_silo(FuCabinet *self, GBytes *data, GError **error)
+{
+ GPtrArray *folders;
+ g_autoptr(XbBuilderFixup) fixup1 = NULL;
+ g_autoptr(XbBuilderFixup) fixup2 = NULL;
+ g_autoptr(XbBuilderFixup) fixup3 = NULL;
+ g_autoptr(XbBuilderFixup) fixup4 = NULL;
+
+ /* verbose profiling */
+ if (g_getenv("FWUPD_XMLB_VERBOSE") != NULL) {
+ xb_builder_set_profile_flags(self->builder,
+ XB_SILO_PROFILE_FLAG_XPATH |
+ XB_SILO_PROFILE_FLAG_DEBUG);
+ }
+
+ /* load Jcat */
+ folders = gcab_cabinet_get_folders(self->gcab_cabinet);
+ if (self->jcat_context != NULL) {
+ for (guint i = 0; i < folders->len; i++) {
+ GCabFolder *cabfolder = GCAB_FOLDER(g_ptr_array_index(folders, i));
+ if (!fu_cabinet_build_jcat_folder(self, cabfolder, error))
+ return FALSE;
+ }
+ }
+
+ /* adds each metainfo file to the silo */
+ for (guint i = 0; i < folders->len; i++) {
+ GCabFolder *cabfolder = GCAB_FOLDER(g_ptr_array_index(folders, i));
+ if (!fu_cabinet_build_silo_folder(self, cabfolder, error))
+ return FALSE;
+ }
+
+ /* sort the components by priority */
+ fixup1 = xb_builder_fixup_new("OrderByPriority", fu_cabinet_sort_priority_cb, NULL, NULL);
+ xb_builder_fixup_set_max_depth(fixup1, 0);
+ xb_builder_add_fixup(self->builder, fixup1);
+
+ /* ensure the container checksum is always set */
+ fixup2 = xb_builder_fixup_new("EnsureContainerChecksum",
+ fu_cabinet_ensure_container_checksum_cb,
+ self,
+ NULL);
+ xb_builder_add_fixup(self->builder, fixup2);
+
+ fixup3 = xb_builder_fixup_new("LowerCaseCheckSum",
+ fu_cabinet_set_lowercase_checksum_cb,
+ self,
+ NULL);
+ xb_builder_add_fixup(self->builder, fixup3);
+
+ /* strip inner nodes without children */
+ fixup4 = xb_builder_fixup_new("TextStripInner",
+ fu_cabinet_fixup_strip_inner_text_cb,
+ self,
+ NULL);
+ xb_builder_add_fixup(self->builder, fixup4);
+
+ /* did we get any valid files */
+ self->silo = xb_builder_compile(self->builder,
+#if LIBXMLB_CHECK_VERSION(0, 3, 4)
+ XB_BUILDER_COMPILE_FLAG_SINGLE_ROOT,
+#else
+ XB_BUILDER_COMPILE_FLAG_NONE,
+#endif
+ NULL,
+ error);
+ if (self->silo == NULL)
+ return FALSE;
+
+ /* success */
+ return TRUE;
+}
+
+typedef struct {
+ FuCabinet *self;
+ guint64 size_total;
+ GError *error;
+} FuCabinetDecompressHelper;
+
+static gboolean
+fu_cabinet_decompress_file_cb(GCabFile *file, gpointer user_data)
+{
+ FuCabinetDecompressHelper *helper = (FuCabinetDecompressHelper *)user_data;
+ FuCabinet *self = FU_CABINET(helper->self);
+ g_autofree gchar *basename = NULL;
+ g_autofree gchar *name = NULL;
+
+ /* already failed */
+ if (helper->error != NULL)
+ return FALSE;
+
+ /* check the size of the compressed file */
+ if (gcab_file_get_size(file) > self->size_max) {
+ g_autofree gchar *sz_val = g_format_size(gcab_file_get_size(file));
+ g_autofree gchar *sz_max = g_format_size(self->size_max);
+ g_set_error(&helper->error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "file %s was too large (%s, limit %s)",
+ gcab_file_get_name(file),
+ sz_val,
+ sz_max);
+ return FALSE;
+ }
+
+ /* check the total size of all the compressed files */
+ helper->size_total += gcab_file_get_size(file);
+ if (helper->size_total > self->size_max) {
+ g_autofree gchar *sz_val = g_format_size(helper->size_total);
+ g_autofree gchar *sz_max = g_format_size(self->size_max);
+ g_set_error(&helper->error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "uncompressed data too large (%s, limit %s)",
+ sz_val,
+ sz_max);
+ return FALSE;
+ }
+
+ /* convert to UNIX paths */
+ name = g_strdup(gcab_file_get_name(file));
+ g_strdelimit(name, "\\", '/');
+
+ /* ignore the dirname completely */
+ basename = g_path_get_basename(name);
+ gcab_file_set_extract_name(file, basename);
+ return TRUE;
+}
+
+static gboolean
+fu_cabinet_decompress(FuCabinet *self, GBytes *data, GError **error)
+{
+ FuCabinetDecompressHelper helper = {
+ .self = self,
+ .size_total = 0,
+ .error = NULL,
+ };
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GInputStream) istream = NULL;
+
+ /* load from a seekable stream */
+ istream = g_memory_input_stream_new_from_bytes(data);
+ if (!gcab_cabinet_load(self->gcab_cabinet, istream, NULL, error))
+ return FALSE;
+
+ /* check the size is sane */
+ if (gcab_cabinet_get_size(self->gcab_cabinet) > self->size_max) {
+ g_autofree gchar *sz_val = g_format_size(gcab_cabinet_get_size(self->gcab_cabinet));
+ g_autofree gchar *sz_max = g_format_size(self->size_max);
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "archive too large (%s, limit %s)",
+ sz_val,
+ sz_max);
+ return FALSE;
+ }
+
+ /* decompress the file to memory */
+ if (!gcab_cabinet_extract_simple(self->gcab_cabinet,
+ NULL,
+ fu_cabinet_decompress_file_cb,
+ &helper,
+ NULL,
+ &error_local)) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ error_local->message);
+ return FALSE;
+ }
+
+ /* the file callback set an error */
+ if (helper.error != NULL) {
+ g_propagate_error(error, helper.error);
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_cabinet_export:
+ * @self: a #FuCabinet
+ * @flags: export flags, e.g. %FU_CABINET_EXPORT_FLAG_NONE
+ * @error: (nullable): optional return location for an error
+ *
+ * Exports the cabinet archive.
+ *
+ * Returns: (transfer full): a data blob
+ *
+ * Since: 1.6.0
+ **/
+GBytes *
+fu_cabinet_export(FuCabinet *self, FuCabinetExportFlags flags, GError **error)
+{
+ g_autoptr(GOutputStream) op = NULL;
+ op = g_memory_output_stream_new_resizable();
+ if (!gcab_cabinet_write_simple(self->gcab_cabinet,
+ op,
+ NULL,
+ NULL, /* progress */
+ NULL,
+ error))
+ return NULL;
+ if (!g_output_stream_close(op, NULL, error))
+ return NULL;
+ return g_memory_output_stream_steal_as_bytes(G_MEMORY_OUTPUT_STREAM(op));
+}
+
+static gboolean
+fu_cabinet_sign_filename(FuCabinet *self,
+ const gchar *filename,
+ JcatEngine *jcat_engine,
+ JcatFile *jcat_file,
+ GBytes *cert,
+ GBytes *privkey,
+ GError **error)
+{
+ g_autoptr(GBytes) source_blob = NULL;
+ g_autoptr(JcatBlob) jcat_blob = NULL;
+ g_autoptr(JcatItem) jcat_item = NULL;
+
+ /* sign the file using the engine */
+ source_blob = fu_cabinet_get_file(self, filename, error);
+ if (source_blob == NULL)
+ return FALSE;
+ jcat_item = jcat_file_get_item_by_id(jcat_file, filename, NULL);
+ if (jcat_item == NULL) {
+ jcat_item = jcat_item_new(filename);
+ jcat_file_add_item(jcat_file, jcat_item);
+ }
+ jcat_blob = jcat_engine_pubkey_sign(jcat_engine,
+ source_blob,
+ cert,
+ privkey,
+ JCAT_SIGN_FLAG_ADD_TIMESTAMP | JCAT_SIGN_FLAG_ADD_CERT,
+ error);
+ if (jcat_blob == NULL)
+ return FALSE;
+ jcat_item_add_blob(jcat_item, jcat_blob);
+ return TRUE;
+}
+
+static gboolean
+fu_cabinet_sign_enumerate_metainfo(FuCabinet *self, GPtrArray *files, GError **error)
+{
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) nodes = NULL;
+ g_autoptr(XbSilo) silo = fu_cabinet_get_silo(self);
+
+ /* get all the firmware referenced by the metainfo files */
+ nodes = xb_silo_query(silo,
+ "components/component[@type='firmware']/info/filename",
+ 0,
+ &error_local);
+ if (nodes == NULL) {
+ if (g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT) ||
+ g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ g_debug("ignoring: %s", error_local->message);
+ g_ptr_array_add(files, g_strdup("firmware.metainfo.xml"));
+ } else {
+ g_propagate_error(error, g_steal_pointer(&error_local));
+ return FALSE;
+ }
+ } else {
+ for (guint i = 0; i < nodes->len; i++) {
+ XbNode *n = g_ptr_array_index(nodes, i);
+ g_debug("adding: %s", xb_node_get_text(n));
+ g_ptr_array_add(files, g_strdup(xb_node_get_text(n)));
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static gboolean
+fu_cabinet_sign_enumerate_firmware(FuCabinet *self, GPtrArray *files, GError **error)
+{
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) nodes = NULL;
+ g_autoptr(XbSilo) silo = fu_cabinet_get_silo(self);
+
+ nodes = xb_silo_query(silo,
+ "components/component[@type='firmware']/releases/"
+ "release/checksum[@target='content']",
+ 0,
+ &error_local);
+ if (nodes == NULL) {
+ if (g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT) ||
+ g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ g_debug("ignoring: %s", error_local->message);
+ g_ptr_array_add(files, g_strdup("firmware.bin"));
+ } else {
+ g_propagate_error(error, g_steal_pointer(&error_local));
+ return FALSE;
+ }
+ } else {
+ for (guint i = 0; i < nodes->len; i++) {
+ XbNode *n = g_ptr_array_index(nodes, i);
+ g_debug("adding: %s", xb_node_get_attr(n, "filename"));
+ g_ptr_array_add(files, g_strdup(xb_node_get_attr(n, "filename")));
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_cabinet_sign:
+ * @self: a #FuCabinet
+ * @cert: a PCKS#7 certificate
+ * @privkey: a private key
+ * @flags: signing flags, e.g. %FU_CABINET_SIGN_FLAG_NONE
+ * @error: (nullable): optional return location for an error
+ *
+ * Sign the cabinet archive using JCat.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.6.0
+ **/
+gboolean
+fu_cabinet_sign(FuCabinet *self,
+ GBytes *cert,
+ GBytes *privkey,
+ FuCabinetSignFlags flags,
+ GError **error)
+{
+ g_autoptr(GBytes) new_bytes = NULL;
+ g_autoptr(GBytes) old_bytes = NULL;
+ g_autoptr(GOutputStream) ostr = NULL;
+ g_autoptr(GPtrArray) filenames = g_ptr_array_new_with_free_func(g_free);
+ g_autoptr(JcatContext) jcat_context = jcat_context_new();
+ g_autoptr(JcatEngine) jcat_engine = NULL;
+ g_autoptr(JcatFile) jcat_file = jcat_file_new();
+
+ /* load existing .jcat file if it exists */
+ old_bytes = fu_cabinet_get_file(self, "firmware.jcat", NULL);
+ if (old_bytes != NULL) {
+ g_autoptr(GInputStream) istr = NULL;
+ istr = g_memory_input_stream_new_from_bytes(old_bytes);
+ if (!jcat_file_import_stream(jcat_file, istr, JCAT_IMPORT_FLAG_NONE, NULL, error))
+ return FALSE;
+ }
+
+ /* get all the metainfo.xml and firmware.bin files */
+ if (!fu_cabinet_sign_enumerate_metainfo(self, filenames, error))
+ return FALSE;
+ if (!fu_cabinet_sign_enumerate_firmware(self, filenames, error))
+ return FALSE;
+
+ /* sign all the files */
+ jcat_engine = jcat_context_get_engine(jcat_context, JCAT_BLOB_KIND_PKCS7, error);
+ if (jcat_engine == NULL)
+ return FALSE;
+ for (guint i = 0; i < filenames->len; i++) {
+ const gchar *filename = g_ptr_array_index(filenames, i);
+ if (!fu_cabinet_sign_filename(self,
+ filename,
+ jcat_engine,
+ jcat_file,
+ cert,
+ privkey,
+ error))
+ return FALSE;
+ }
+
+ /* export new JCat file and add it to the archive */
+ ostr = g_memory_output_stream_new_resizable();
+ if (!jcat_file_export_stream(jcat_file, ostr, JCAT_EXPORT_FLAG_NONE, NULL, error))
+ return FALSE;
+ new_bytes = g_memory_output_stream_steal_as_bytes(G_MEMORY_OUTPUT_STREAM(ostr));
+ fu_cabinet_add_file(self, "firmware.jcat", new_bytes);
+ return TRUE;
+}
+
+/**
+ * fu_cabinet_parse:
+ * @self: a #FuCabinet
+ * @data: cabinet archive
+ * @flags: parse flags, e.g. %FU_CABINET_PARSE_FLAG_NONE
+ * @error: (nullable): optional return location for an error
+ *
+ * Parses the cabinet archive.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.0
+ **/
+gboolean
+fu_cabinet_parse(FuCabinet *self, GBytes *data, FuCabinetParseFlags flags, GError **error)
+{
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) components = NULL;
+ g_autoptr(XbQuery) query = NULL;
+
+ g_return_val_if_fail(FU_IS_CABINET(self), FALSE);
+ g_return_val_if_fail(data != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail(self->silo == NULL, FALSE);
+
+ /* decompress */
+ if (!fu_cabinet_decompress(self, data, error))
+ return FALSE;
+
+ /* build xmlb silo */
+ self->container_checksum = g_compute_checksum_for_bytes(G_CHECKSUM_SHA1, data);
+ self->container_checksum_alt = g_compute_checksum_for_bytes(G_CHECKSUM_SHA256, data);
+ if (!fu_cabinet_build_silo(self, data, error))
+ return FALSE;
+
+ /* sanity check */
+ components =
+ xb_silo_query(self->silo, "components/component[@type='firmware']", 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 FALSE;
+ }
+
+ /* prepare query */
+ query = xb_query_new_full(self->silo,
+ "releases/release",
+#if LIBXMLB_CHECK_VERSION(0, 2, 0)
+ XB_QUERY_FLAG_FORCE_NODE_CACHE,
+#else
+ XB_QUERY_FLAG_NONE,
+#endif
+ error);
+ if (query == NULL)
+ return FALSE;
+
+ /* 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_full(component, query, &error_local);
+ if (releases == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no releases in metainfo file: %s",
+ error_local->message);
+ return FALSE;
+ }
+ 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_cabinet_parse_release(self, rel, error))
+ return FALSE;
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_cabinet_new:
+ *
+ * Returns: a #FuCabinet
+ *
+ * Since: 1.4.0
+ **/
+FuCabinet *
+fu_cabinet_new(void)
+{
+ return g_object_new(FU_TYPE_CABINET, NULL);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cabinet.h b/fwupd-1.8.6/libfwupdplugin/fu-cabinet.h
new file mode 100644
index 0000000000000000000000000000000000000000..45fa1dff4da32434182bb0180ce903578caafc59
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cabinet.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+#include
+
+#define FU_TYPE_CABINET (fu_cabinet_get_type())
+
+G_DECLARE_FINAL_TYPE(FuCabinet, fu_cabinet, FU, CABINET, GObject)
+
+/**
+ * FuCabinetParseFlags:
+ * @FU_CABINET_PARSE_FLAG_NONE: No flags set
+ *
+ * The flags to use when loading the cabinet.
+ **/
+typedef enum {
+ FU_CABINET_PARSE_FLAG_NONE = 0,
+ /*< private >*/
+ FU_CABINET_PARSE_FLAG_LAST
+} FuCabinetParseFlags;
+
+/**
+ * FuCabinetExportFlags:
+ * @FU_CABINET_EXPORT_FLAG_NONE: No flags set
+ *
+ * The flags to use when exporting the archive.
+ **/
+typedef enum {
+ FU_CABINET_EXPORT_FLAG_NONE = 0,
+ /*< private >*/
+ FU_CABINET_EXPORT_FLAG_LAST
+} FuCabinetExportFlags;
+
+/**
+ * FuCabinetSignFlags:
+ * @FU_CABINET_SIGN_FLAG_NONE: No flags set
+ *
+ * The flags to use when signing the archive.
+ **/
+typedef enum {
+ FU_CABINET_SIGN_FLAG_NONE = 0,
+ /*< private >*/
+ FU_CABINET_SIGN_FLAG_LAST
+} FuCabinetSignFlags;
+
+FuCabinet *
+fu_cabinet_new(void);
+void
+fu_cabinet_set_size_max(FuCabinet *self, guint64 size_max);
+void
+fu_cabinet_set_jcat_context(FuCabinet *self, JcatContext *jcat_context);
+gboolean
+fu_cabinet_parse(FuCabinet *self, GBytes *data, FuCabinetParseFlags flags, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_cabinet_sign(FuCabinet *self,
+ GBytes *cert,
+ GBytes *privkey,
+ FuCabinetSignFlags flags,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_cabinet_add_file(FuCabinet *self, const gchar *basename, GBytes *data);
+GBytes *
+fu_cabinet_get_file(FuCabinet *self, const gchar *basename, GError **error);
+GBytes *
+fu_cabinet_export(FuCabinet *self,
+ FuCabinetExportFlags flags,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+XbSilo *
+fu_cabinet_get_silo(FuCabinet *self);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfi-device.c b/fwupd-1.8.6/libfwupdplugin/fu-cfi-device.c
new file mode 100644
index 0000000000000000000000000000000000000000..5a7ce990c866762fe77405aa4c2934560948f05c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfi-device.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCfiDevice"
+
+#include "config.h"
+
+#include "fu-cfi-device.h"
+#include "fu-quirks.h"
+#include "fu-string.h"
+
+/**
+ * FuCfiDevice:
+ *
+ * A chip conforming to the Common Flash Memory Interface, typically a SPI flash chip.
+ *
+ * Where required, the quirks instance IDs will be added in ->setup().
+ *
+ * The defaults are set as follows, and can be overridden in quirk files:
+ *
+ * * `PageSize`: 0x100
+ * * `SectorSize`: 0x1000
+ * * `BlockSize`: 0x10000
+ *
+ * See also: [class@FuDevice]
+ */
+
+typedef struct {
+ gchar *flash_id;
+ guint8 cmd_read_id_sz;
+ guint32 page_size;
+ guint32 sector_size;
+ guint32 block_size;
+ FuCfiDeviceCmd cmds[FU_CFI_DEVICE_CMD_LAST];
+} FuCfiDevicePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuCfiDevice, fu_cfi_device, FU_TYPE_DEVICE)
+enum { PROP_0, PROP_FLASH_ID, PROP_LAST };
+
+#define GET_PRIVATE(o) (fu_cfi_device_get_instance_private(o))
+
+#define FU_CFI_DEVICE_PAGE_SIZE_DEFAULT 0x100
+#define FU_CFI_DEVICE_SECTOR_SIZE_DEFAULT 0x1000
+#define FU_CFI_DEVICE_BLOCK_SIZE_DEFAULT 0x10000
+
+static const gchar *
+fu_cfi_device_cmd_to_string(FuCfiDeviceCmd cmd)
+{
+ if (cmd == FU_CFI_DEVICE_CMD_READ_ID)
+ return "ReadId";
+ if (cmd == FU_CFI_DEVICE_CMD_PAGE_PROG)
+ return "PageProg";
+ if (cmd == FU_CFI_DEVICE_CMD_CHIP_ERASE)
+ return "ChipErase";
+ if (cmd == FU_CFI_DEVICE_CMD_READ_DATA)
+ return "ReadData";
+ if (cmd == FU_CFI_DEVICE_CMD_READ_STATUS)
+ return "ReadStatus";
+ if (cmd == FU_CFI_DEVICE_CMD_SECTOR_ERASE)
+ return "SectorErase";
+ if (cmd == FU_CFI_DEVICE_CMD_WRITE_EN)
+ return "WriteEn";
+ if (cmd == FU_CFI_DEVICE_CMD_WRITE_STATUS)
+ return "WriteStatus";
+ if (cmd == FU_CFI_DEVICE_CMD_BLOCK_ERASE)
+ return "BlockErase";
+ return NULL;
+}
+
+/**
+ * fu_cfi_device_get_size:
+ * @self: a #FuCfiDevice
+ *
+ * Gets the chip maximum size.
+ *
+ * This is typically set with the `FirmwareSizeMax` quirk key.
+ *
+ * Returns: size in bytes, or 0 if unknown
+ *
+ * Since: 1.7.1
+ **/
+guint64
+fu_cfi_device_get_size(FuCfiDevice *self)
+{
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), G_MAXUINT64);
+ return fu_device_get_firmware_size_max(FU_DEVICE(self));
+}
+
+/**
+ * fu_cfi_device_set_size:
+ * @self: a #FuCfiDevice
+ * @size: maximum size in bytes, or 0 if unknown
+ *
+ * Sets the chip maximum size.
+ *
+ * Since: 1.7.1
+ **/
+void
+fu_cfi_device_set_size(FuCfiDevice *self, guint64 size)
+{
+ g_return_if_fail(FU_IS_CFI_DEVICE(self));
+ fu_device_set_firmware_size_max(FU_DEVICE(self), size);
+}
+
+/**
+ * fu_cfi_device_get_flash_id:
+ * @self: a #FuCfiDevice
+ *
+ * Gets the chip ID used to identify the device.
+ *
+ * Returns: the ID, or %NULL
+ *
+ * Since: 1.7.1
+ **/
+const gchar *
+fu_cfi_device_get_flash_id(FuCfiDevice *self)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), NULL);
+ return priv->flash_id;
+}
+
+/**
+ * fu_cfi_device_set_flash_id:
+ * @self: a #FuCfiDevice
+ * @flash_id: (nullable): The chip ID
+ *
+ * Sets the chip ID used to identify the device.
+ *
+ * Since: 1.7.1
+ **/
+void
+fu_cfi_device_set_flash_id(FuCfiDevice *self, const gchar *flash_id)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFI_DEVICE(self));
+ if (g_strcmp0(flash_id, priv->flash_id) == 0)
+ return;
+ g_free(priv->flash_id);
+ priv->flash_id = g_strdup(flash_id);
+}
+
+static void
+fu_cfi_device_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FuCfiDevice *self = FU_CFI_DEVICE(object);
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_FLASH_ID:
+ g_value_set_object(value, priv->flash_id);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_cfi_device_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FuCfiDevice *self = FU_CFI_DEVICE(object);
+ switch (prop_id) {
+ case PROP_FLASH_ID:
+ fu_cfi_device_set_flash_id(self, g_value_get_string(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_cfi_device_finalize(GObject *object)
+{
+ FuCfiDevice *self = FU_CFI_DEVICE(object);
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_free(priv->flash_id);
+ G_OBJECT_CLASS(fu_cfi_device_parent_class)->finalize(object);
+}
+
+static gboolean
+fu_cfi_device_setup(FuDevice *device, GError **error)
+{
+ gsize flash_idsz = 0;
+ FuCfiDevice *self = FU_CFI_DEVICE(device);
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+
+ /* sanity check */
+ if (priv->flash_id != NULL)
+ flash_idsz = strlen(priv->flash_id);
+ if (flash_idsz == 0 || flash_idsz % 2 != 0) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "not a valid flash-id");
+ return FALSE;
+ }
+
+ /* typically this will add quirk strings of 2, 4, then 6 bytes */
+ for (guint i = 0; i < flash_idsz; i += 2) {
+ g_autofree gchar *flash_id = g_strndup(priv->flash_id, i + 2);
+ fu_device_add_instance_str(device, "FLASHID", flash_id);
+ if (!fu_device_build_instance_id_quirk(device, error, "CFI", "FLASHID", NULL))
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_cfi_device_get_cmd:
+ * @self: a #FuCfiDevice
+ * @cmd: a #FuCfiDeviceCmd, e.g. %FU_CFI_DEVICE_CMD_CHIP_ERASE
+ * @value: the API command value to use
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the self vendor code.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.7.1
+ **/
+gboolean
+fu_cfi_device_get_cmd(FuCfiDevice *self, FuCfiDeviceCmd cmd, guint8 *value, GError **error)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ if (cmd >= FU_CFI_DEVICE_CMD_LAST) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "CFI cmd invalid");
+ return FALSE;
+ }
+ if (priv->cmds[cmd] == 0x0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "No defined CFI cmd for %s",
+ fu_cfi_device_cmd_to_string(cmd));
+ return FALSE;
+ }
+ if (value != NULL)
+ *value = priv->cmds[cmd];
+ return TRUE;
+}
+
+/**
+ * fu_cfi_device_get_page_size:
+ * @self: a #FuCfiDevice
+ *
+ * Gets the chip page size. This is typically the largest writable block size.
+ *
+ * This is typically set with the `CfiDevicePageSize` quirk key.
+ *
+ * Returns: page size in bytes
+ *
+ * Since: 1.7.3
+ **/
+guint32
+fu_cfi_device_get_page_size(FuCfiDevice *self)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), G_MAXUINT32);
+ return priv->page_size;
+}
+
+/**
+ * fu_cfi_device_set_page_size:
+ * @self: a #FuCfiDevice
+ * @page_size: page size in bytes, or 0 if unknown
+ *
+ * Sets the chip page size. This is typically the largest writable block size.
+ *
+ * Since: 1.7.3
+ **/
+void
+fu_cfi_device_set_page_size(FuCfiDevice *self, guint32 page_size)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFI_DEVICE(self));
+ priv->page_size = page_size;
+}
+
+/**
+ * fu_cfi_device_get_sector_size:
+ * @self: a #FuCfiDevice
+ *
+ * Gets the chip sector size. This is typically the smallest erasable page size.
+ *
+ * This is typically set with the `CfiDeviceSectorSize` quirk key.
+ *
+ * Returns: sector size in bytes
+ *
+ * Since: 1.7.3
+ **/
+guint32
+fu_cfi_device_get_sector_size(FuCfiDevice *self)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), G_MAXUINT32);
+ return priv->sector_size;
+}
+
+/**
+ * fu_cfi_device_set_block_size:
+ * @self: a #FuCfiDevice
+ * @block_size: block size in bytes, or 0 if unknown
+ *
+ * Sets the chip block size. This is typically the largest erasable chunk size.
+ *
+ * Since: 1.7.4
+ **/
+void
+fu_cfi_device_set_block_size(FuCfiDevice *self, guint32 block_size)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFI_DEVICE(self));
+ priv->block_size = block_size;
+}
+
+/**
+ * fu_cfi_device_get_block_size:
+ * @self: a #FuCfiDevice
+ *
+ * Gets the chip block size. This is typically the largest erasable block size.
+ *
+ * This is typically set with the `CfiDeviceBlockSize` quirk key.
+ *
+ * Returns: block size in bytes
+ *
+ * Since: 1.7.4
+ **/
+guint32
+fu_cfi_device_get_block_size(FuCfiDevice *self)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), G_MAXUINT32);
+ return priv->block_size;
+}
+
+/**
+ * fu_cfi_device_set_sector_size:
+ * @self: a #FuCfiDevice
+ * @sector_size: sector size in bytes, or 0 if unknown
+ *
+ * Sets the chip sector size. This is typically the smallest erasable page size.
+ *
+ * Since: 1.7.3
+ **/
+void
+fu_cfi_device_set_sector_size(FuCfiDevice *self, guint32 sector_size)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFI_DEVICE(self));
+ priv->sector_size = sector_size;
+}
+
+static gboolean
+fu_cfi_device_set_quirk_kv(FuDevice *device, const gchar *key, const gchar *value, GError **error)
+{
+ FuCfiDevice *self = FU_CFI_DEVICE(device);
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ guint64 tmp;
+
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_READ_ID) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_READ_ID] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_READ_ID_SZ) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmd_read_id_sz = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_CHIP_ERASE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_CHIP_ERASE] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_BLOCK_ERASE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_BLOCK_ERASE] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_SECTOR_ERASE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_SECTOR_ERASE] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_WRITE_STATUS) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_WRITE_STATUS] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_PAGE_PROG) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_PAGE_PROG] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_READ_DATA) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_READ_DATA] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_READ_STATUS) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_READ_STATUS] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_CMD_WRITE_EN) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ priv->cmds[FU_CFI_DEVICE_CMD_WRITE_EN] = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_PAGE_SIZE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT32, error))
+ return FALSE;
+ priv->page_size = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_SECTOR_SIZE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT32, error))
+ return FALSE;
+ priv->sector_size = tmp;
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_CFI_DEVICE_BLOCK_SIZE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT32, error))
+ return FALSE;
+ priv->block_size = tmp;
+ return TRUE;
+ }
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "quirk key not supported");
+ return FALSE;
+}
+
+static void
+fu_cfi_device_to_string(FuDevice *device, guint idt, GString *str)
+{
+ FuCfiDevice *self = FU_CFI_DEVICE(device);
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ fu_string_append(str, idt, "FlashId", priv->flash_id);
+ for (guint i = 0; i < FU_CFI_DEVICE_CMD_LAST; i++) {
+ fu_string_append_kx(str, idt, fu_cfi_device_cmd_to_string(i), priv->cmds[i]);
+ }
+ if (priv->page_size > 0)
+ fu_string_append_kx(str, idt, "PageSize", priv->page_size);
+ if (priv->sector_size > 0)
+ fu_string_append_kx(str, idt, "SectorSize", priv->sector_size);
+ if (priv->block_size > 0)
+ fu_string_append_kx(str, idt, "BlockSize", priv->block_size);
+}
+
+/**
+ * fu_cfi_device_chip_select:
+ * @self: a #FuCfiDevice
+ * @value: boolean
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets the chip select value.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.8.0
+ **/
+gboolean
+fu_cfi_device_chip_select(FuCfiDevice *self, gboolean value, GError **error)
+{
+ FuCfiDeviceClass *klass = FU_CFI_DEVICE_GET_CLASS(self);
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ if (klass->chip_select == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "chip select is not implemented on this device");
+ return FALSE;
+ }
+ return klass->chip_select(self, value, error);
+}
+
+static gboolean
+fu_cfi_device_chip_select_assert(GObject *device, GError **error)
+{
+ return fu_cfi_device_chip_select(FU_CFI_DEVICE(device), TRUE, error);
+}
+
+static gboolean
+fu_cfi_device_chip_select_deassert(GObject *device, GError **error)
+{
+ return fu_cfi_device_chip_select(FU_CFI_DEVICE(device), FALSE, error);
+}
+
+/**
+ * fu_cfi_device_chip_select_locker_new:
+ * @self: a #FuCfiDevice
+ *
+ * Creates a custom device locker that asserts and deasserts the chip select signal.
+ *
+ * Returns: (transfer full): (nullable): a #FuDeviceLocker
+ *
+ * Since: 1.8.0
+ **/
+FuDeviceLocker *
+fu_cfi_device_chip_select_locker_new(FuCfiDevice *self, GError **error)
+{
+ g_return_val_if_fail(FU_IS_CFI_DEVICE(self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+ return fu_device_locker_new_full(self,
+ fu_cfi_device_chip_select_assert,
+ fu_cfi_device_chip_select_deassert,
+ error);
+}
+
+static void
+fu_cfi_device_init(FuCfiDevice *self)
+{
+ FuCfiDevicePrivate *priv = GET_PRIVATE(self);
+ priv->page_size = FU_CFI_DEVICE_PAGE_SIZE_DEFAULT;
+ priv->sector_size = FU_CFI_DEVICE_SECTOR_SIZE_DEFAULT;
+ priv->block_size = FU_CFI_DEVICE_BLOCK_SIZE_DEFAULT;
+ priv->cmds[FU_CFI_DEVICE_CMD_WRITE_STATUS] = 0x01;
+ priv->cmds[FU_CFI_DEVICE_CMD_PAGE_PROG] = 0x02;
+ priv->cmds[FU_CFI_DEVICE_CMD_READ_DATA] = 0x03;
+ priv->cmds[FU_CFI_DEVICE_CMD_READ_STATUS] = 0x05;
+ priv->cmds[FU_CFI_DEVICE_CMD_WRITE_EN] = 0x06;
+ priv->cmds[FU_CFI_DEVICE_CMD_SECTOR_ERASE] = 0x20;
+ priv->cmds[FU_CFI_DEVICE_CMD_CHIP_ERASE] = 0x60;
+ priv->cmds[FU_CFI_DEVICE_CMD_READ_ID] = 0x9f;
+ fu_device_set_summary(FU_DEVICE(self), "CFI flash chip");
+}
+
+static void
+fu_cfi_device_class_init(FuCfiDeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
+ GParamSpec *pspec;
+
+ object_class->finalize = fu_cfi_device_finalize;
+ object_class->get_property = fu_cfi_device_get_property;
+ object_class->set_property = fu_cfi_device_set_property;
+ klass_device->setup = fu_cfi_device_setup;
+ klass_device->to_string = fu_cfi_device_to_string;
+ klass_device->set_quirk_kv = fu_cfi_device_set_quirk_kv;
+
+ /**
+ * FuCfiDevice:flash-id:
+ *
+ * The CCI JEDEC flash ID.
+ *
+ * Since: 1.7.1
+ */
+ pspec = g_param_spec_string("flash-id",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_FLASH_ID, pspec);
+}
+
+/**
+ * fu_cfi_device_new:
+ * @ctx: a #FuContext
+ *
+ * Creates a new #FuCfiDevice.
+ *
+ * Returns: (transfer full): a #FuCfiDevice
+ *
+ * Since: 1.7.1
+ **/
+FuCfiDevice *
+fu_cfi_device_new(FuContext *ctx, const gchar *flash_id)
+{
+ return g_object_new(FU_TYPE_CFI_DEVICE, "context", ctx, "flash-id", flash_id, NULL);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfi-device.h b/fwupd-1.8.6/libfwupdplugin/fu-cfi-device.h
new file mode 100644
index 0000000000000000000000000000000000000000..08dd4dfdb3b871546c5115b24dfaff0f1ad18d4e
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfi-device.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-device.h"
+
+#define FU_TYPE_CFI_DEVICE (fu_cfi_device_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuCfiDevice, fu_cfi_device, FU, CFI_DEVICE, FuDevice)
+
+struct _FuCfiDeviceClass {
+ FuDeviceClass parent_class;
+ gboolean (*chip_select)(FuCfiDevice *self, gboolean value, GError **error);
+ gpointer __reserved[30];
+};
+
+/**
+ * FuCfiDeviceCmd:
+ * @FU_CFI_DEVICE_CMD_READ_ID: Read the chip ID
+ * @FU_CFI_DEVICE_CMD_PAGE_PROG: Page program
+ * @FU_CFI_DEVICE_CMD_CHIP_ERASE: Whole chip erase
+ * @FU_CFI_DEVICE_CMD_READ_DATA: Read data
+ * @FU_CFI_DEVICE_CMD_READ_STATUS: Read status
+ * @FU_CFI_DEVICE_CMD_SECTOR_ERASE: Sector erase
+ * @FU_CFI_DEVICE_CMD_WRITE_EN: Write enable
+ * @FU_CFI_DEVICE_CMD_WRITE_STATUS: Write status
+ * @FU_CFI_DEVICE_CMD_BLOCK_ERASE: Block erase
+ *
+ * Commands used when calling fu_cfi_device_get_cmd().
+ **/
+typedef enum {
+ FU_CFI_DEVICE_CMD_READ_ID,
+ FU_CFI_DEVICE_CMD_PAGE_PROG,
+ FU_CFI_DEVICE_CMD_CHIP_ERASE,
+ FU_CFI_DEVICE_CMD_READ_DATA,
+ FU_CFI_DEVICE_CMD_READ_STATUS,
+ FU_CFI_DEVICE_CMD_SECTOR_ERASE,
+ FU_CFI_DEVICE_CMD_WRITE_EN,
+ FU_CFI_DEVICE_CMD_WRITE_STATUS,
+ FU_CFI_DEVICE_CMD_BLOCK_ERASE,
+ /*< private >*/
+ FU_CFI_DEVICE_CMD_LAST
+} FuCfiDeviceCmd;
+
+FuCfiDevice *
+fu_cfi_device_new(FuContext *ctx, const gchar *flash_id);
+const gchar *
+fu_cfi_device_get_flash_id(FuCfiDevice *self);
+void
+fu_cfi_device_set_flash_id(FuCfiDevice *self, const gchar *flash_id);
+guint64
+fu_cfi_device_get_size(FuCfiDevice *self);
+void
+fu_cfi_device_set_size(FuCfiDevice *self, guint64 size);
+guint32
+fu_cfi_device_get_page_size(FuCfiDevice *self);
+void
+fu_cfi_device_set_page_size(FuCfiDevice *self, guint32 page_size);
+guint32
+fu_cfi_device_get_sector_size(FuCfiDevice *self);
+void
+fu_cfi_device_set_sector_size(FuCfiDevice *self, guint32 sector_size);
+guint32
+fu_cfi_device_get_block_size(FuCfiDevice *self);
+void
+fu_cfi_device_set_block_size(FuCfiDevice *self, guint32 block_size);
+gboolean
+fu_cfi_device_get_cmd(FuCfiDevice *self, FuCfiDeviceCmd cmd, guint8 *value, GError **error);
+
+gboolean
+fu_cfi_device_chip_select(FuCfiDevice *self, gboolean value, GError **error);
+FuDeviceLocker *
+fu_cfi_device_chip_select_locker_new(FuCfiDevice *self, GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfu-common.c b/fwupd-1.8.6/libfwupdplugin/fu-cfu-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a9988be2304f4455a8bc3193d6277238b076588
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfu-common.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 Michael Cheng
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fu-cfu-common.h"
+
+/**
+ * fu_cfu_device_reject_to_string:
+ * @val: an enumerated value, e.g. %FU_CFU_DEVICE_REJECT_OLD_FIRMWARE
+ *
+ * Converts an enumerated reject type to a string.
+ *
+ * Returns: a string, or `unknown` for invalid
+ *
+ * Since: 1.7.0
+ **/
+const gchar *
+fu_cfu_device_reject_to_string(guint8 val)
+{
+ if (val == FU_CFU_DEVICE_REJECT_OLD_FIRMWARE)
+ return "old-firmware";
+ if (val == FU_CFU_DEVICE_REJECT_INV_COMPONENT)
+ return "inv-component";
+ if (val == FU_CFU_DEVICE_REJECT_SWAP_PENDING)
+ return "swap-pending";
+ if (val == FU_CFU_DEVICE_REJECT_WRONG_BANK)
+ return "wrong-bank";
+ if (val == FU_CFU_DEVICE_REJECT_SIGN_RULE)
+ return "sign-rule";
+ if (val == FU_CFU_DEVICE_REJECT_VER_RELEASE_DEBUG)
+ return "ver-release-debug";
+ if (val == FU_CFU_DEVICE_REJECT_DEBUG_SAME_VERSION)
+ return "debug-same-version";
+ return "unknown";
+}
+
+/**
+ * fu_cfu_device_offer_to_string:
+ * @val: an enumerated value, e.g. %FU_CFU_DEVICE_OFFER_ACCEPT
+ *
+ * Converts an enumerated offer type to a string.
+ *
+ * Returns: a string, or `unknown` for invalid
+ *
+ * Since: 1.7.0
+ **/
+const gchar *
+fu_cfu_device_offer_to_string(guint8 val)
+{
+ if (val == FU_CFU_DEVICE_OFFER_SKIP)
+ return "skip";
+ if (val == FU_CFU_DEVICE_OFFER_ACCEPT)
+ return "accept";
+ if (val == FU_CFU_DEVICE_OFFER_REJECT)
+ return "reject";
+ if (val == FU_CFU_DEVICE_OFFER_BUSY)
+ return "busy";
+ if (val == FU_CFU_DEVICE_OFFER_COMMAND)
+ return "command";
+ if (val == FU_CFU_DEVICE_OFFER_NOT_SUPPORTED)
+ return "not-supported";
+ return "unknown";
+}
+
+/**
+ * fu_cfu_device_status_to_string:
+ * @val: an enumerated value, e.g. %FU_CFU_DEVICE_OFFER_ACCEPT
+ *
+ * Converts an enumerated status type to a string.
+ *
+ * Returns: a string, or `unknown` for invalid
+ *
+ * Since: 1.7.0
+ **/
+const gchar *
+fu_cfu_device_status_to_string(guint8 val)
+{
+ if (val == FU_CFU_DEVICE_STATUS_SUCCESS)
+ return "success";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_PREPARE)
+ return "error-prepare";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_WRITE)
+ return "error-write";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_COMPLETE)
+ return "error-complete";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_VERIFY)
+ return "error-verify";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_CRC)
+ return "error-crc";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_SIGNATURE)
+ return "error-signature";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_VERSION)
+ return "error-version";
+ if (val == FU_CFU_DEVICE_STATUS_SWAP_PENDING)
+ return "swap-pending";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_INVALID_ADDR)
+ return "error-invalid-address";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_NO_OFFER)
+ return "error-no-offer";
+ if (val == FU_CFU_DEVICE_STATUS_ERROR_INVALID)
+ return "error-invalid";
+ return "unknown";
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfu-common.h b/fwupd-1.8.6/libfwupdplugin/fu-cfu-common.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c94524a5224d4b7b218feb8a14c720a16ed4f66
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfu-common.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 Michael Cheng
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#define FU_CFU_DEVICE_OFFER_SKIP 0x00
+#define FU_CFU_DEVICE_OFFER_ACCEPT 0x01
+#define FU_CFU_DEVICE_OFFER_REJECT 0x02
+#define FU_CFU_DEVICE_OFFER_BUSY 0x03
+#define FU_CFU_DEVICE_OFFER_COMMAND 0x04
+#define FU_CFU_DEVICE_OFFER_NOT_SUPPORTED 0xFF
+
+#define FU_CFU_DEVICE_FLAG_FIRST_BLOCK 0x80
+#define FU_CFU_DEVICE_FLAG_LAST_BLOCK 0x40
+
+#define FU_CFU_DEVICE_STATUS_SUCCESS 0x00
+#define FU_CFU_DEVICE_STATUS_ERROR_PREPARE 0x01
+#define FU_CFU_DEVICE_STATUS_ERROR_WRITE 0x02
+#define FU_CFU_DEVICE_STATUS_ERROR_COMPLETE 0x03
+#define FU_CFU_DEVICE_STATUS_ERROR_VERIFY 0x04
+#define FU_CFU_DEVICE_STATUS_ERROR_CRC 0x05
+#define FU_CFU_DEVICE_STATUS_ERROR_SIGNATURE 0x06
+#define FU_CFU_DEVICE_STATUS_ERROR_VERSION 0x07
+#define FU_CFU_DEVICE_STATUS_SWAP_PENDING 0x08
+#define FU_CFU_DEVICE_STATUS_ERROR_INVALID_ADDR 0x09
+#define FU_CFU_DEVICE_STATUS_ERROR_NO_OFFER 0x0A
+#define FU_CFU_DEVICE_STATUS_ERROR_INVALID 0x0B
+
+#define FU_CFU_DEVICE_REJECT_OLD_FIRMWARE 0x00
+#define FU_CFU_DEVICE_REJECT_INV_COMPONENT 0x01
+#define FU_CFU_DEVICE_REJECT_SWAP_PENDING 0x02
+#define FU_CFU_DEVICE_REJECT_WRONG_BANK 0x04
+#define FU_CFU_DEVICE_REJECT_SIGN_RULE 0xE0
+#define FU_CFU_DEVICE_REJECT_VER_RELEASE_DEBUG 0xE1
+#define FU_CFU_DEVICE_REJECT_DEBUG_SAME_VERSION 0xE2
+
+const gchar *
+fu_cfu_device_reject_to_string(guint8 val);
+const gchar *
+fu_cfu_device_status_to_string(guint8 val);
+const gchar *
+fu_cfu_device_offer_to_string(guint8 val);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfu-offer.c b/fwupd-1.8.6/libfwupdplugin/fu-cfu-offer.c
new file mode 100644
index 0000000000000000000000000000000000000000..88780b336a2d596ce18379adf94e32e5ff9b33d1
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfu-offer.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuFirmware"
+
+#include "config.h"
+
+#include "fu-byte-array.h"
+#include "fu-cfu-offer.h"
+#include "fu-common.h"
+#include "fu-mem.h"
+#include "fu-string.h"
+
+/**
+ * FuCfuOffer:
+ *
+ * A CFU offer. This is a 16 byte blob which contains enough data for the device to either accept
+ * or refuse a firmware payload. The offer may be loaded from disk, network, or even constructed
+ * manually. There is much left to how the specific firmware implements CFU, and it's expected
+ * that multiple different plugins will use this offer in different ways.
+ *
+ * Documented: https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification
+ *
+ * See also: [class@FuFirmware]
+ */
+
+typedef struct {
+ guint8 segment_number;
+ gboolean force_immediate_reset;
+ gboolean force_ignore_version;
+ guint8 component_id;
+ guint8 token;
+ guint32 hw_variant;
+ guint8 protocol_revision;
+ guint8 bank;
+ guint8 milestone;
+ guint16 product_id;
+} FuCfuOfferPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuCfuOffer, fu_cfu_offer, FU_TYPE_FIRMWARE)
+#define GET_PRIVATE(o) (fu_cfu_offer_get_instance_private(o))
+
+static void
+fu_cfu_offer_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
+{
+ FuCfuOffer *self = FU_CFU_OFFER(firmware);
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ fu_xmlb_builder_insert_kx(bn, "segment_number", priv->segment_number);
+ fu_xmlb_builder_insert_kb(bn, "force_immediate_reset", priv->force_immediate_reset);
+ fu_xmlb_builder_insert_kb(bn, "force_ignore_version", priv->force_ignore_version);
+ fu_xmlb_builder_insert_kx(bn, "component_id", priv->component_id);
+ fu_xmlb_builder_insert_kx(bn, "token", priv->token);
+ fu_xmlb_builder_insert_kx(bn, "hw_variant", priv->hw_variant);
+ fu_xmlb_builder_insert_kx(bn, "protocol_revision", priv->protocol_revision);
+ fu_xmlb_builder_insert_kx(bn, "bank", priv->bank);
+ fu_xmlb_builder_insert_kx(bn, "milestone", priv->milestone);
+ fu_xmlb_builder_insert_kx(bn, "product_id", priv->product_id);
+}
+
+/**
+ * fu_cfu_offer_get_segment_number:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the part of the firmware that is being transferred.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint8
+fu_cfu_offer_get_segment_number(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->segment_number;
+}
+
+/**
+ * fu_cfu_offer_get_force_immediate_reset:
+ * @self: a #FuCfuOffer
+ *
+ * Gets if the in-situ firmware should reset into the new firmware immediately, rather than waiting
+ * for the next time the device is replugged.
+ *
+ * Returns: boolean
+ *
+ * Since: 1.7.0
+ **/
+gboolean
+fu_cfu_offer_get_force_immediate_reset(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), FALSE);
+ return priv->force_immediate_reset;
+}
+
+/**
+ * fu_cfu_offer_get_force_ignore_version:
+ * @self: a #FuCfuOffer
+ *
+ * Gets if the in-situ firmware should ignore version mismatch (e.g. downgrade).
+ *
+ * Returns: boolean
+ *
+ * Since: 1.7.0
+ **/
+gboolean
+fu_cfu_offer_get_force_ignore_version(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), FALSE);
+ return priv->force_ignore_version;
+}
+
+/**
+ * fu_cfu_offer_get_component_id:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the component in the device to apply the firmware update.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint8
+fu_cfu_offer_get_component_id(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->component_id;
+}
+
+/**
+ * fu_cfu_offer_get_token:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the token to identify the user specific software making the offer.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint8
+fu_cfu_offer_get_token(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->token;
+}
+
+/**
+ * fu_cfu_offer_get_hw_variant:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the hardware variant bitmask corresponding with compatible firmware.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint32
+fu_cfu_offer_get_hw_variant(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->hw_variant;
+}
+
+/**
+ * fu_cfu_offer_get_protocol_revision:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the CFU protocol version.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint8
+fu_cfu_offer_get_protocol_revision(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->protocol_revision;
+}
+
+/**
+ * fu_cfu_offer_get_bank:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the bank register, used if multiple banks are supported.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint8
+fu_cfu_offer_get_bank(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->bank;
+}
+
+/**
+ * fu_cfu_offer_get_milestone:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the milestone, which can be used as a version for example EV1, EVT etc.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint8
+fu_cfu_offer_get_milestone(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->milestone;
+}
+
+/**
+ * fu_cfu_offer_get_product_id:
+ * @self: a #FuCfuOffer
+ *
+ * Gets the product ID for this CFU image.
+ *
+ * Returns: integer
+ *
+ * Since: 1.7.0
+ **/
+guint16
+fu_cfu_offer_get_product_id(FuCfuOffer *self)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CFU_OFFER(self), 0x0);
+ return priv->product_id;
+}
+
+/**
+ * fu_cfu_offer_set_segment_number:
+ * @self: a #FuCfuOffer
+ * @segment_number: integer
+ *
+ * Sets the part of the firmware that is being transferred.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_segment_number(FuCfuOffer *self, guint8 segment_number)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->segment_number = segment_number;
+}
+
+/**
+ * fu_cfu_offer_set_force_immediate_reset:
+ * @self: a #FuCfuOffer
+ * @force_immediate_reset: boolean
+ *
+ * Sets if the in-situ firmware should reset into the new firmware immediately, rather than waiting
+ * for the next time the device is replugged.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_force_immediate_reset(FuCfuOffer *self, gboolean force_immediate_reset)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->force_immediate_reset = force_immediate_reset;
+}
+
+/**
+ * fu_cfu_offer_set_force_ignore_version:
+ * @self: a #FuCfuOffer
+ * @force_ignore_version: boolean
+ *
+ * Sets if the in-situ firmware should ignore version mismatch (e.g. downgrade).
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_force_ignore_version(FuCfuOffer *self, gboolean force_ignore_version)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->force_ignore_version = force_ignore_version;
+}
+
+/**
+ * fu_cfu_offer_set_component_id:
+ * @self: a #FuCfuOffer
+ * @component_id: integer
+ *
+ * Sets the component in the device to apply the firmware update.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_component_id(FuCfuOffer *self, guint8 component_id)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->component_id = component_id;
+}
+
+/**
+ * fu_cfu_offer_set_token:
+ * @self: a #FuCfuOffer
+ * @token: integer
+ *
+ * Sets the token to identify the user specific software making the offer.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_token(FuCfuOffer *self, guint8 token)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->token = token;
+}
+
+/**
+ * fu_cfu_offer_set_hw_variant:
+ * @self: a #FuCfuOffer
+ * @hw_variant: integer
+ *
+ * Sets the hardware variant bitmask corresponding with compatible firmware.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_hw_variant(FuCfuOffer *self, guint32 hw_variant)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->hw_variant = hw_variant;
+}
+
+/**
+ * fu_cfu_offer_set_protocol_revision:
+ * @self: a #FuCfuOffer
+ * @protocol_revision: integer
+ *
+ * Sets the CFU protocol version.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_protocol_revision(FuCfuOffer *self, guint8 protocol_revision)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ g_return_if_fail(protocol_revision <= 0b1111);
+ priv->protocol_revision = protocol_revision;
+}
+
+/**
+ * fu_cfu_offer_set_bank:
+ * @self: a #FuCfuOffer
+ * @bank: integer
+ *
+ * Sets bank register, used if multiple banks are supported.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_bank(FuCfuOffer *self, guint8 bank)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ g_return_if_fail(bank <= 0b11);
+ priv->bank = bank;
+}
+
+/**
+ * fu_cfu_offer_set_milestone:
+ * @self: a #FuCfuOffer
+ * @milestone: integer
+ *
+ * Sets the milestone, which can be used as a version for example EV1, EVT etc.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_milestone(FuCfuOffer *self, guint8 milestone)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ g_return_if_fail(milestone <= 0b111);
+ priv->milestone = milestone;
+}
+
+/**
+ * fu_cfu_offer_set_product_id:
+ * @self: a #FuCfuOffer
+ * @product_id: integer
+ *
+ * Sets the product ID for this CFU image.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_cfu_offer_set_product_id(FuCfuOffer *self, guint16 product_id)
+{
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CFU_OFFER(self));
+ priv->product_id = product_id;
+}
+
+static gboolean
+fu_cfu_offer_parse(FuFirmware *firmware,
+ GBytes *fw,
+ gsize offset,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ FuCfuOffer *self = FU_CFU_OFFER(firmware);
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ gsize bufsz = 0;
+ guint8 tmp = 0;
+ guint32 tmp32 = 0;
+ const guint8 *buf = g_bytes_get_data(fw, &bufsz);
+
+ /* component info */
+ if (!fu_memread_uint8_safe(buf, bufsz, 0x0, &priv->segment_number, error))
+ return FALSE;
+ if (!fu_memread_uint8_safe(buf, bufsz, 0x1, &tmp, error))
+ return FALSE;
+ priv->force_ignore_version = (tmp & 0b1) > 0;
+ priv->force_immediate_reset = (tmp & 0b10) > 0;
+ if (!fu_memread_uint8_safe(buf, bufsz, 0x2, &priv->component_id, error))
+ return FALSE;
+ if (!fu_memread_uint8_safe(buf, bufsz, 0x3, &priv->token, error))
+ return FALSE;
+
+ /* version */
+ if (!fu_memread_uint32_safe(buf, bufsz, 0x4, &tmp32, G_LITTLE_ENDIAN, error))
+ return FALSE;
+ fu_firmware_set_version_raw(firmware, tmp32);
+ if (!fu_memread_uint32_safe(buf, bufsz, 0x8, &priv->hw_variant, G_LITTLE_ENDIAN, error))
+ return FALSE;
+
+ /* product info */
+ if (!fu_memread_uint8_safe(buf, bufsz, 0xC, &tmp, error))
+ return FALSE;
+ priv->protocol_revision = (tmp >> 4) & 0b1111;
+ priv->bank = (tmp >> 2) & 0b11;
+ if (!fu_memread_uint8_safe(buf, bufsz, 0xD, &tmp, error))
+ return FALSE;
+ priv->milestone = (tmp >> 5) & 0b111;
+ if (!fu_memread_uint16_safe(buf, bufsz, 0xE, &priv->product_id, G_LITTLE_ENDIAN, error))
+ return FALSE;
+
+ /* success */
+ return TRUE;
+}
+
+static GBytes *
+fu_cfu_offer_write(FuFirmware *firmware, GError **error)
+{
+ FuCfuOffer *self = FU_CFU_OFFER(firmware);
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GByteArray) buf = g_byte_array_new();
+
+ /* component info */
+ fu_byte_array_append_uint8(buf, priv->segment_number);
+ fu_byte_array_append_uint8(buf,
+ priv->force_ignore_version | (priv->force_immediate_reset << 1));
+ fu_byte_array_append_uint8(buf, priv->component_id);
+ fu_byte_array_append_uint8(buf, priv->token);
+
+ /* version */
+ fu_byte_array_append_uint32(buf, fu_firmware_get_version_raw(firmware), G_LITTLE_ENDIAN);
+ fu_byte_array_append_uint32(buf, priv->hw_variant, G_LITTLE_ENDIAN);
+
+ /* product info */
+ fu_byte_array_append_uint8(buf, (priv->protocol_revision << 4) | (priv->bank << 2));
+ fu_byte_array_append_uint8(buf, priv->milestone << 5);
+ fu_byte_array_append_uint16(buf, priv->product_id, G_LITTLE_ENDIAN);
+
+ /* success */
+ return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+}
+
+static gboolean
+fu_cfu_offer_build(FuFirmware *firmware, XbNode *n, GError **error)
+{
+ FuCfuOffer *self = FU_CFU_OFFER(firmware);
+ FuCfuOfferPrivate *priv = GET_PRIVATE(self);
+ guint64 tmp;
+ const gchar *tmpb;
+
+ /* optional properties */
+ tmp = xb_node_query_text_as_uint(n, "segment_number", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
+ priv->segment_number = tmp;
+ tmpb = xb_node_query_text(n, "force_immediate_reset", NULL);
+ if (tmpb != NULL) {
+ if (!fu_strtobool(tmpb, &priv->force_immediate_reset, error))
+ return FALSE;
+ }
+ tmpb = xb_node_query_text(n, "force_ignore_version", NULL);
+ if (tmpb != NULL) {
+ if (!fu_strtobool(tmpb, &priv->force_ignore_version, error))
+ return FALSE;
+ }
+ tmp = xb_node_query_text_as_uint(n, "component_id", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
+ priv->component_id = tmp;
+ tmp = xb_node_query_text_as_uint(n, "token", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
+ priv->token = tmp;
+ tmp = xb_node_query_text_as_uint(n, "hw_variant", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32)
+ priv->hw_variant = tmp;
+ tmp = xb_node_query_text_as_uint(n, "protocol_revision", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
+ priv->protocol_revision = tmp;
+ tmp = xb_node_query_text_as_uint(n, "bank", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
+ priv->bank = tmp;
+ tmp = xb_node_query_text_as_uint(n, "milestone", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8)
+ priv->milestone = tmp;
+ tmp = xb_node_query_text_as_uint(n, "product_id", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16)
+ priv->product_id = tmp;
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fu_cfu_offer_init(FuCfuOffer *self)
+{
+ fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_VID_PID);
+}
+
+static void
+fu_cfu_offer_class_init(FuCfuOfferClass *klass)
+{
+ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
+ klass_firmware->export = fu_cfu_offer_export;
+ klass_firmware->parse = fu_cfu_offer_parse;
+ klass_firmware->write = fu_cfu_offer_write;
+ klass_firmware->build = fu_cfu_offer_build;
+}
+
+/**
+ * fu_cfu_offer_new:
+ *
+ * Creates a new #FuFirmware for a CFU offer
+ *
+ * Since: 1.7.0
+ **/
+FuFirmware *
+fu_cfu_offer_new(void)
+{
+ return FU_FIRMWARE(g_object_new(FU_TYPE_CFU_OFFER, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfu-offer.h b/fwupd-1.8.6/libfwupdplugin/fu-cfu-offer.h
new file mode 100644
index 0000000000000000000000000000000000000000..601d2635a1b73e30d06b71c0e1928535351dbd1b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfu-offer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-firmware.h"
+
+#define FU_TYPE_CFU_OFFER (fu_cfu_offer_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuCfuOffer, fu_cfu_offer, FU, CFU_OFFER, FuFirmware)
+
+struct _FuCfuOfferClass {
+ FuFirmwareClass parent_class;
+};
+
+FuFirmware *
+fu_cfu_offer_new(void);
+guint8
+fu_cfu_offer_get_segment_number(FuCfuOffer *self);
+gboolean
+fu_cfu_offer_get_force_immediate_reset(FuCfuOffer *self);
+gboolean
+fu_cfu_offer_get_force_ignore_version(FuCfuOffer *self);
+guint8
+fu_cfu_offer_get_component_id(FuCfuOffer *self);
+guint8
+fu_cfu_offer_get_token(FuCfuOffer *self);
+guint32
+fu_cfu_offer_get_hw_variant(FuCfuOffer *self);
+guint8
+fu_cfu_offer_get_protocol_revision(FuCfuOffer *self);
+guint8
+fu_cfu_offer_get_bank(FuCfuOffer *self);
+guint8
+fu_cfu_offer_get_milestone(FuCfuOffer *self);
+guint16
+fu_cfu_offer_get_product_id(FuCfuOffer *self);
+
+void
+fu_cfu_offer_set_segment_number(FuCfuOffer *self, guint8 segment_number);
+void
+fu_cfu_offer_set_force_immediate_reset(FuCfuOffer *self, gboolean force_immediate_reset);
+void
+fu_cfu_offer_set_force_ignore_version(FuCfuOffer *self, gboolean force_ignore_version);
+void
+fu_cfu_offer_set_component_id(FuCfuOffer *self, guint8 component_id);
+void
+fu_cfu_offer_set_token(FuCfuOffer *self, guint8 token);
+void
+fu_cfu_offer_set_hw_variant(FuCfuOffer *self, guint32 hw_variant);
+void
+fu_cfu_offer_set_protocol_revision(FuCfuOffer *self, guint8 protocol_revision);
+void
+fu_cfu_offer_set_bank(FuCfuOffer *self, guint8 bank);
+void
+fu_cfu_offer_set_milestone(FuCfuOffer *self, guint8 milestone);
+void
+fu_cfu_offer_set_product_id(FuCfuOffer *self, guint16 product_id);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfu-payload.c b/fwupd-1.8.6/libfwupdplugin/fu-cfu-payload.c
new file mode 100644
index 0000000000000000000000000000000000000000..eec5a5e5c54f7267f257710c482a1dd5a23a2ff7
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfu-payload.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuFirmware"
+
+#include "config.h"
+
+#include "fu-byte-array.h"
+#include "fu-bytes.h"
+#include "fu-cfu-payload.h"
+#include "fu-common.h"
+#include "fu-mem.h"
+
+/**
+ * FuCfuPayload:
+ *
+ * A CFU payload. This contains of a variable number of blocks, each containing the address, size
+ * and the chunk data. The chunks do not have to be the same size, and the address ranges do not
+ * have to be continuous.
+ *
+ * Documented: https://docs.microsoft.com/en-us/windows-hardware/drivers/cfu/cfu-specification
+ *
+ * See also: [class@FuFirmware]
+ */
+
+G_DEFINE_TYPE(FuCfuPayload, fu_cfu_payload, FU_TYPE_FIRMWARE)
+
+static gboolean
+fu_cfu_payload_parse(FuFirmware *firmware,
+ GBytes *fw,
+ gsize offset,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ gsize bufsz = 0;
+ const guint8 *buf = g_bytes_get_data(fw, &bufsz);
+
+ /* process into chunks */
+ while (offset < bufsz) {
+ guint32 chunk_addr = 0;
+ guint8 chunk_size = 0;
+ g_autoptr(FuChunk) chk = NULL;
+ g_autoptr(GBytes) blob = NULL;
+
+ /* read chunk header */
+ if (!fu_memread_uint32_safe(buf,
+ bufsz,
+ offset,
+ &chunk_addr,
+ G_LITTLE_ENDIAN,
+ error))
+ return FALSE;
+ if (!fu_memread_uint8_safe(buf, bufsz, offset + 0x4, &chunk_size, error))
+ return FALSE;
+ offset += 0x5;
+ blob = fu_bytes_new_offset(fw, offset, chunk_size, error);
+ if (blob == NULL)
+ return FALSE;
+ chk = fu_chunk_bytes_new(blob);
+ fu_chunk_set_address(chk, chunk_addr);
+ fu_firmware_add_chunk(firmware, chk);
+
+ /* next! */
+ offset += chunk_size;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static GBytes *
+fu_cfu_payload_write(FuFirmware *firmware, GError **error)
+{
+ g_autoptr(GByteArray) buf = g_byte_array_new();
+ g_autoptr(GPtrArray) chunks = NULL;
+
+ chunks = fu_firmware_get_chunks(firmware, error);
+ if (chunks == NULL)
+ return NULL;
+ for (guint i = 0; i < chunks->len; i++) {
+ FuChunk *chk = g_ptr_array_index(chunks, i);
+ fu_byte_array_append_uint32(buf, fu_chunk_get_address(chk), G_LITTLE_ENDIAN);
+ fu_byte_array_append_uint8(buf, fu_chunk_get_data_sz(chk));
+ g_byte_array_append(buf, fu_chunk_get_data(chk), fu_chunk_get_data_sz(chk));
+ }
+ return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+}
+
+static void
+fu_cfu_payload_init(FuCfuPayload *self)
+{
+}
+
+static void
+fu_cfu_payload_class_init(FuCfuPayloadClass *klass)
+{
+ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
+ klass_firmware->parse = fu_cfu_payload_parse;
+ klass_firmware->write = fu_cfu_payload_write;
+}
+
+/**
+ * fu_cfu_payload_new:
+ *
+ * Creates a new #FuFirmware for a CFU payload
+ *
+ * Since: 1.7.0
+ **/
+FuFirmware *
+fu_cfu_payload_new(void)
+{
+ return FU_FIRMWARE(g_object_new(FU_TYPE_CFU_PAYLOAD, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-cfu-payload.h b/fwupd-1.8.6/libfwupdplugin/fu-cfu-payload.h
new file mode 100644
index 0000000000000000000000000000000000000000..5dd6e2e6b20ee6653eb4d7077be1fe93cf07cd9c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-cfu-payload.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-firmware.h"
+
+#define FU_TYPE_CFU_PAYLOAD (fu_cfu_payload_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuCfuPayload, fu_cfu_payload, FU, CFU_PAYLOAD, FuFirmware)
+
+struct _FuCfuPayloadClass {
+ FuFirmwareClass parent_class;
+};
+
+FuFirmware *
+fu_cfu_payload_new(void);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-chunk-private.h b/fwupd-1.8.6/libfwupdplugin/fu-chunk-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e941afdd63c34d4faa8c3f99888c0fe0cd4ba84
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-chunk-private.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fu-chunk.h"
+#include "fu-firmware.h"
+
+void
+fu_chunk_export(FuChunk *self, FuFirmwareExportFlags flags, XbBuilderNode *bn);
+gboolean
+fu_chunk_build(FuChunk *self, XbNode *n, GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-chunk.c b/fwupd-1.8.6/libfwupdplugin/fu-chunk.c
new file mode 100644
index 0000000000000000000000000000000000000000..88be1624eedf5bd6e2d29923b055a3d70bf7b7f6
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-chunk.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuChunk"
+
+#include "config.h"
+
+#include
+
+#include "fu-bytes.h"
+#include "fu-chunk-private.h"
+#include "fu-common.h"
+#include "fu-string.h"
+
+/**
+ * FuChunk:
+ *
+ * A optionally mutable packet of chunked data with address, page and index.
+ */
+
+struct _FuChunk {
+ GObject parent_instance;
+ guint32 idx;
+ guint32 page;
+ guint32 address;
+ const guint8 *data;
+ guint32 data_sz;
+ gboolean is_mutable;
+ GBytes *bytes;
+};
+
+G_DEFINE_TYPE(FuChunk, fu_chunk, G_TYPE_OBJECT)
+
+/**
+ * fu_chunk_set_idx:
+ * @self: a #FuChunk
+ * @idx: index, starting at 0
+ *
+ * Sets the index of the chunk.
+ *
+ * Since: 1.5.6
+ **/
+void
+fu_chunk_set_idx(FuChunk *self, guint32 idx)
+{
+ g_return_if_fail(FU_IS_CHUNK(self));
+ self->idx = idx;
+}
+
+/**
+ * fu_chunk_get_idx:
+ * @self: a #FuChunk
+ *
+ * Gets the index of the chunk.
+ *
+ * Returns: index
+ *
+ * Since: 1.5.6
+ **/
+guint32
+fu_chunk_get_idx(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), G_MAXUINT32);
+ return self->idx;
+}
+
+/**
+ * fu_chunk_set_page:
+ * @self: a #FuChunk
+ * @page: page number, starting at 0
+ *
+ * Sets the page of the chunk.
+ *
+ * Since: 1.5.6
+ **/
+void
+fu_chunk_set_page(FuChunk *self, guint32 page)
+{
+ g_return_if_fail(FU_IS_CHUNK(self));
+ self->page = page;
+}
+
+/**
+ * fu_chunk_get_page:
+ * @self: a #FuChunk
+ *
+ * Gets the page of the chunk.
+ *
+ * Returns: page
+ *
+ * Since: 1.5.6
+ **/
+guint32
+fu_chunk_get_page(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), G_MAXUINT32);
+ return self->page;
+}
+
+/**
+ * fu_chunk_set_address:
+ * @self: a #FuChunk
+ * @address: memory address
+ *
+ * Sets the address of the chunk.
+ *
+ * Since: 1.5.6
+ **/
+void
+fu_chunk_set_address(FuChunk *self, guint32 address)
+{
+ g_return_if_fail(FU_IS_CHUNK(self));
+ self->address = address;
+}
+
+/**
+ * fu_chunk_get_address:
+ * @self: a #FuChunk
+ *
+ * Gets the address of the chunk.
+ *
+ * Returns: address
+ *
+ * Since: 1.5.6
+ **/
+guint32
+fu_chunk_get_address(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), G_MAXUINT32);
+ return self->address;
+}
+
+/**
+ * fu_chunk_get_data:
+ * @self: a #FuChunk
+ *
+ * Gets the data of the chunk.
+ *
+ * Returns: bytes
+ *
+ * Since: 1.5.6
+ **/
+const guint8 *
+fu_chunk_get_data(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), NULL);
+ return self->data;
+}
+
+/**
+ * fu_chunk_get_data_out:
+ * @self: a #FuChunk
+ *
+ * Gets the mutable data of the chunk.
+ *
+ * WARNING: At the moment fu_chunk_get_data_out() returns the same data as
+ * fu_chunk_get_data() in all cases. The caller should verify the data passed to
+ * fu_chunk_array_new() is also writable (i.e. not `const` or `mmap`) before
+ * using this function.
+ *
+ * Returns: (transfer none): bytes
+ *
+ * Since: 1.5.6
+ **/
+guint8 *
+fu_chunk_get_data_out(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), NULL);
+
+ /* warn, but allow to proceed */
+ if (!self->is_mutable) {
+ g_critical("calling fu_chunk_get_data_out() from immutable chunk");
+ self->is_mutable = TRUE;
+ }
+ return (guint8 *)self->data;
+}
+
+/**
+ * fu_chunk_get_data_sz:
+ * @self: a #FuChunk
+ *
+ * Gets the data size of the chunk.
+ *
+ * Returns: size in bytes
+ *
+ * Since: 1.5.6
+ **/
+guint32
+fu_chunk_get_data_sz(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), G_MAXUINT32);
+ return self->data_sz;
+}
+
+/**
+ * fu_chunk_set_bytes:
+ * @self: a #FuChunk
+ * @bytes: (nullable): data
+ *
+ * Sets the data to use for the chunk.
+ *
+ * Since: 1.5.6
+ **/
+void
+fu_chunk_set_bytes(FuChunk *self, GBytes *bytes)
+{
+ g_return_if_fail(FU_IS_CHUNK(self));
+
+ /* not changed */
+ if (self->bytes == bytes)
+ return;
+
+ if (self->bytes != NULL) {
+ g_bytes_unref(self->bytes);
+ self->bytes = NULL;
+ }
+ if (bytes != NULL) {
+ self->bytes = g_bytes_ref(bytes);
+ self->data = g_bytes_get_data(bytes, NULL);
+ self->data_sz = g_bytes_get_size(bytes);
+ }
+}
+
+/**
+ * fu_chunk_get_bytes:
+ * @self: a #FuChunk
+ *
+ * Gets the data of the chunk.
+ *
+ * Returns: (transfer full): data
+ *
+ * Since: 1.5.6
+ **/
+GBytes *
+fu_chunk_get_bytes(FuChunk *self)
+{
+ g_return_val_if_fail(FU_IS_CHUNK(self), NULL);
+ if (self->bytes != NULL)
+ return g_bytes_ref(self->bytes);
+ return g_bytes_new_static(self->data, self->data_sz);
+}
+
+/**
+ * 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.
+ *
+ * Returns: (transfer full): a #FuChunk
+ *
+ * Since: 1.1.2
+ **/
+FuChunk *
+fu_chunk_new(guint32 idx, guint32 page, guint32 address, const guint8 *data, guint32 data_sz)
+{
+ FuChunk *self = g_object_new(FU_TYPE_CHUNK, NULL);
+ self->idx = idx;
+ self->page = page;
+ self->address = address;
+ self->data = data;
+ self->data_sz = data_sz;
+ return self;
+}
+
+/**
+ * fu_chunk_bytes_new:
+ * @bytes: (nullable): data
+ *
+ * Creates a new packet of data.
+ *
+ * Returns: (transfer full): a #FuChunk
+ *
+ * Since: 1.5.6
+ **/
+FuChunk *
+fu_chunk_bytes_new(GBytes *bytes)
+{
+ FuChunk *self = g_object_new(FU_TYPE_CHUNK, NULL);
+ fu_chunk_set_bytes(self, bytes);
+ return self;
+}
+
+void
+fu_chunk_export(FuChunk *self, FuFirmwareExportFlags flags, XbBuilderNode *bn)
+{
+ fu_xmlb_builder_insert_kx(bn, "idx", self->idx);
+ fu_xmlb_builder_insert_kx(bn, "page", self->page);
+ fu_xmlb_builder_insert_kx(bn, "addr", self->address);
+ if (self->data != NULL) {
+ g_autofree gchar *datastr = NULL;
+ g_autofree gchar *dataszstr = g_strdup_printf("0x%x", (guint)self->data_sz);
+ if (flags & FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA) {
+ datastr = fu_strsafe((const gchar *)self->data, MIN(self->data_sz, 16));
+ } else {
+ datastr = g_base64_encode(self->data, self->data_sz);
+ }
+ xb_builder_node_insert_text(bn, "data", datastr, "size", dataszstr, NULL);
+ }
+}
+
+/**
+ * fu_chunk_to_string:
+ * @self: a #FuChunk
+ *
+ * Converts the chunked packet to a string representation.
+ *
+ * Returns: (transfer full): a string
+ *
+ * Since: 1.1.2
+ **/
+gchar *
+fu_chunk_to_string(FuChunk *self)
+{
+ g_autoptr(XbBuilderNode) bn = xb_builder_node_new("chunk");
+ fu_chunk_export(self, FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA, bn);
+ return xb_builder_node_export(bn,
+ XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE |
+#if LIBXMLB_CHECK_VERSION(0, 2, 2)
+ XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY |
+#endif
+ XB_NODE_EXPORT_FLAG_FORMAT_INDENT,
+ NULL);
+}
+
+/**
+ * fu_chunk_array_to_string:
+ * @chunks: (element-type FuChunk): array of chunks
+ *
+ * Converts all the chunked packets in an array to a string representation.
+ *
+ * Returns: (transfer full): a string
+ *
+ * Since: 1.0.1
+ **/
+gchar *
+fu_chunk_array_to_string(GPtrArray *chunks)
+{
+ g_autoptr(XbBuilderNode) bn = xb_builder_node_new("chunks");
+ for (guint i = 0; i < chunks->len; i++) {
+ FuChunk *chk = g_ptr_array_index(chunks, i);
+ g_autoptr(XbBuilderNode) bc = xb_builder_node_insert(bn, "chunk", NULL);
+ fu_chunk_export(chk, FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA, bc);
+ }
+ return xb_builder_node_export(bn,
+ XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE |
+#if LIBXMLB_CHECK_VERSION(0, 2, 2)
+ XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY |
+#endif
+ XB_NODE_EXPORT_FLAG_FORMAT_INDENT,
+ NULL);
+}
+
+/**
+ * fu_chunk_array_mutable_new:
+ * @data: a mutable blob of memory
+ * @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 mutable blob of memory into packets, ensuring each packet does not
+ * cross a package boundary and is less that a specific transfer size.
+ *
+ * Returns: (transfer container) (element-type FuChunk): array of packets
+ *
+ * Since: 1.5.6
+ **/
+GPtrArray *
+fu_chunk_array_mutable_new(guint8 *data,
+ guint32 data_sz,
+ guint32 addr_start,
+ guint32 page_sz,
+ guint32 packet_sz)
+{
+ GPtrArray *chunks;
+
+ g_return_val_if_fail(data != NULL, NULL);
+ g_return_val_if_fail(data_sz > 0, NULL);
+
+ chunks = fu_chunk_array_new(data, data_sz, addr_start, page_sz, packet_sz);
+ if (chunks == NULL)
+ return NULL;
+ for (guint i = 0; i < chunks->len; i++) {
+ FuChunk *chk = g_ptr_array_index(chunks, i);
+ chk->is_mutable = TRUE;
+ }
+ return chunks;
+}
+
+/**
+ * fu_chunk_array_new:
+ * @data: (nullable): an optional linear blob of memory
+ * @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.
+ *
+ * Returns: (transfer container) (element-type FuChunk): array of packets
+ *
+ * Since: 1.1.2
+ **/
+GPtrArray *
+fu_chunk_array_new(const guint8 *data,
+ guint32 data_sz,
+ guint32 addr_start,
+ guint32 page_sz,
+ guint32 packet_sz)
+{
+ GPtrArray *chunks = NULL;
+ guint32 page_old = G_MAXUINT32;
+ guint32 idx;
+ guint32 last_flush = 0;
+
+ chunks = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ if (data_sz == 0)
+ return chunks;
+ 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(chunks,
+ fu_chunk_new(chunks->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(chunks,
+ fu_chunk_new(chunks->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(chunks,
+ fu_chunk_new(chunks->len,
+ page,
+ address_offset,
+ data_offset,
+ data_sz - last_flush));
+ }
+ return chunks;
+}
+
+/**
+ * fu_chunk_array_new_from_bytes:
+ * @blob: data
+ * @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.
+ *
+ * Returns: (transfer container) (element-type FuChunk): array of packets
+ *
+ * Since: 1.1.2
+ **/
+GPtrArray *
+fu_chunk_array_new_from_bytes(GBytes *blob, guint32 addr_start, guint32 page_sz, guint32 packet_sz)
+{
+ GPtrArray *chunks;
+ gsize sz;
+ const guint8 *data = g_bytes_get_data(blob, &sz);
+
+ chunks = fu_chunk_array_new(data, (guint32)sz, addr_start, page_sz, packet_sz);
+ for (guint i = 0; i < chunks->len; i++) {
+ FuChunk *chk = g_ptr_array_index(chunks, i);
+ chk->bytes = fu_bytes_new_offset(blob, chk->data - data, chk->data_sz, NULL);
+ }
+ return chunks;
+}
+
+/* private */
+gboolean
+fu_chunk_build(FuChunk *self, XbNode *n, GError **error)
+{
+ guint64 tmp;
+ g_autoptr(XbNode) data = NULL;
+
+ g_return_val_if_fail(FU_IS_CHUNK(self), FALSE);
+ g_return_val_if_fail(XB_IS_NODE(n), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* optional properties */
+ tmp = xb_node_query_text_as_uint(n, "idx", NULL);
+ if (tmp != G_MAXUINT64)
+ self->idx = tmp;
+ tmp = xb_node_query_text_as_uint(n, "page", NULL);
+ if (tmp != G_MAXUINT64)
+ self->page = tmp;
+ tmp = xb_node_query_text_as_uint(n, "addr", NULL);
+ if (tmp != G_MAXUINT64)
+ self->address = tmp;
+ data = xb_node_query_first(n, "data", NULL);
+ if (data != NULL && xb_node_get_text(data) != NULL) {
+ gsize bufsz = 0;
+ g_autofree guchar *buf = NULL;
+ g_autoptr(GBytes) blob = NULL;
+ buf = g_base64_decode(xb_node_get_text(data), &bufsz);
+ blob = g_bytes_new(buf, bufsz);
+ fu_chunk_set_bytes(self, blob);
+ } else if (data != NULL) {
+ g_autoptr(GBytes) blob = NULL;
+ blob = g_bytes_new(NULL, 0);
+ fu_chunk_set_bytes(self, blob);
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fu_chunk_finalize(GObject *object)
+{
+ FuChunk *self = FU_CHUNK(object);
+ if (self->bytes != NULL)
+ g_bytes_unref(self->bytes);
+ G_OBJECT_CLASS(fu_chunk_parent_class)->finalize(object);
+}
+
+static void
+fu_chunk_class_init(FuChunkClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fu_chunk_finalize;
+}
+
+static void
+fu_chunk_init(FuChunk *self)
+{
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-chunk.h b/fwupd-1.8.6/libfwupdplugin/fu-chunk.h
new file mode 100644
index 0000000000000000000000000000000000000000..f73322193717f94706824bb68a8513cf432b0399
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-chunk.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#define FU_TYPE_CHUNK (fu_chunk_get_type())
+
+G_DECLARE_FINAL_TYPE(FuChunk, fu_chunk, FU, CHUNK, GObject)
+
+FuChunk *
+fu_chunk_bytes_new(GBytes *bytes);
+void
+fu_chunk_set_idx(FuChunk *self, guint32 idx);
+guint32
+fu_chunk_get_idx(FuChunk *self);
+void
+fu_chunk_set_page(FuChunk *self, guint32 page);
+guint32
+fu_chunk_get_page(FuChunk *self);
+void
+fu_chunk_set_address(FuChunk *self, guint32 address);
+guint32
+fu_chunk_get_address(FuChunk *self);
+const guint8 *
+fu_chunk_get_data(FuChunk *self);
+guint8 *
+fu_chunk_get_data_out(FuChunk *self);
+guint32
+fu_chunk_get_data_sz(FuChunk *self);
+void
+fu_chunk_set_bytes(FuChunk *self, GBytes *bytes);
+GBytes *
+fu_chunk_get_bytes(FuChunk *self);
+
+FuChunk *
+fu_chunk_new(guint32 idx, guint32 page, guint32 address, const guint8 *data, guint32 data_sz);
+gchar *
+fu_chunk_to_string(FuChunk *self);
+
+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_mutable_new(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);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common-darwin.c b/fwupd-1.8.6/libfwupdplugin/fu-common-darwin.c
new file mode 100644
index 0000000000000000000000000000000000000000..f5faa5c02f83a17f251d311a1d1e17756e7a7831
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-darwin.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include
+#include
+
+#include "fu-common-private.h"
+
+GPtrArray *
+fu_common_get_block_devices(GError **error)
+{
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "getting block devices is not supported on Darwin");
+ return NULL;
+}
+
+gboolean
+fu_path_fnmatch_impl(const gchar *pattern, const gchar *str)
+{
+ return fnmatch(pattern, str, FNM_NOESCAPE) == 0;
+}
+
+guint64
+fu_common_get_memory_size_impl(void)
+{
+ gint mib[] = {CTL_HW, HW_MEMSIZE};
+ gint64 physical_memory = 0;
+ gsize length = sizeof(physical_memory);
+ sysctl(mib, 2, &physical_memory, &length, NULL, 0);
+ return (guint64)physical_memory;
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common-freebsd.c b/fwupd-1.8.6/libfwupdplugin/fu-common-freebsd.c
new file mode 100644
index 0000000000000000000000000000000000000000..7ec040ac33f7be94ee11c363bbbf64e46bfe83ac
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-freebsd.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 Sergii Dmytruk
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include
+#include
+#include
+
+#ifdef HAVE_FNMATCH_H
+#include
+#endif
+
+#include "fu-common-private.h"
+#include "fu-path-private.h"
+
+/* bsdisks doesn't provide Manager object */
+#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2"
+#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager"
+#define UDISKS_BLOCK_DEVICE_PATH "/org/freedesktop/UDisks2/block_devices/"
+
+GPtrArray *
+fu_common_get_block_devices(GError **error)
+{
+ GVariant *ifaces;
+ const size_t device_path_len = strlen(UDISKS_BLOCK_DEVICE_PATH);
+ const gchar *obj;
+ g_autoptr(GVariant) output = NULL;
+ g_autoptr(GDBusProxy) proxy = NULL;
+ g_autoptr(GPtrArray) devices = NULL;
+ g_autoptr(GVariantIter) obj_iter = NULL;
+ g_autoptr(GDBusConnection) connection = NULL;
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error);
+ if (connection == NULL) {
+ g_prefix_error(error, "failed to get system bus: ");
+ return NULL;
+ }
+ proxy = g_dbus_proxy_new_sync(connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ UDISKS_DBUS_SERVICE,
+ UDISKS_DBUS_PATH,
+ UDISKS_DBUS_MANAGER_INTERFACE,
+ NULL,
+ error);
+ if (proxy == NULL) {
+ g_prefix_error(error, "failed to find %s: ", UDISKS_DBUS_SERVICE);
+ return NULL;
+ }
+
+ devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ output = g_dbus_proxy_call_sync(proxy,
+ "GetManagedObjects",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (output == NULL) {
+ if (error != NULL)
+ g_dbus_error_strip_remote_error(*error);
+ g_prefix_error(error,
+ "failed to call %s.%s(): ",
+ UDISKS_DBUS_MANAGER_INTERFACE,
+ "GetManagedObjects");
+ return NULL;
+ }
+
+ g_variant_get(output, "(a{oa{sa{sv}}})", &obj_iter);
+ while (g_variant_iter_next(obj_iter, "{&o@a{sa{sv}}}", &obj, &ifaces)) {
+ const gchar *iface;
+ GVariant *props;
+ GVariantIter iface_iter;
+
+ if (strncmp(obj, UDISKS_BLOCK_DEVICE_PATH, device_path_len) != 0)
+ continue;
+
+ g_variant_iter_init(&iface_iter, ifaces);
+ while (g_variant_iter_next(&iface_iter, "{&s@a{sv}}", &iface, &props)) {
+ g_autoptr(GDBusProxy) proxy_blk = NULL;
+
+ g_variant_unref(props);
+
+ if (strcmp(iface, UDISKS_DBUS_INTERFACE_BLOCK) != 0)
+ continue;
+
+ proxy_blk = g_dbus_proxy_new_sync(connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ UDISKS_DBUS_SERVICE,
+ obj,
+ UDISKS_DBUS_INTERFACE_BLOCK,
+ NULL,
+ error);
+ if (proxy_blk == NULL) {
+ g_prefix_error(error,
+ "failed to initialize d-bus proxy for %s: ",
+ obj);
+ return NULL;
+ }
+ g_ptr_array_add(devices, g_steal_pointer(&proxy_blk));
+ }
+ g_variant_unref(ifaces);
+ }
+ return g_steal_pointer(&devices);
+}
+
+gboolean
+fu_path_fnmatch_impl(const gchar *pattern, const gchar *str)
+{
+#ifdef HAVE_FNMATCH_H
+ return fnmatch(pattern, str, FNM_NOESCAPE) == 0;
+#else
+ return g_strcmp0(pattern, str) == 0;
+#endif
+}
+
+guint64
+fu_common_get_memory_size_impl(void)
+{
+ return (guint64)sysconf(_SC_PHYS_PAGES) * (guint64)sysconf(_SC_PAGE_SIZE);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common-guid.c b/fwupd-1.8.6/libfwupdplugin/fu-common-guid.c
new file mode 100644
index 0000000000000000000000000000000000000000..953f4abb32244ef2084c8f7f38bf25622a788b1c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-guid.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#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 --git a/fwupd-1.8.6/libfwupdplugin/fu-common-guid.h b/fwupd-1.8.6/libfwupdplugin/fu-common-guid.h
new file mode 100644
index 0000000000000000000000000000000000000000..b07c2da3553e32e600a1bcc70824c67fbd1edcd8
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-guid.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+gboolean
+fu_common_guid_is_plausible(const guint8 *buf);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common-linux.c b/fwupd-1.8.6/libfwupdplugin/fu-common-linux.c
new file mode 100644
index 0000000000000000000000000000000000000000..ed1ad34e27ce27aee0750930acf8167b4be69447
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-linux.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include
+#include
+
+#ifdef HAVE_FNMATCH_H
+#include
+#endif
+
+#include "fu-common-private.h"
+#include "fu-path-private.h"
+
+#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager"
+#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager"
+
+GPtrArray *
+fu_common_get_block_devices(GError **error)
+{
+ GVariantBuilder builder;
+ const gchar *obj;
+ g_autoptr(GVariant) output = NULL;
+ g_autoptr(GDBusProxy) proxy = NULL;
+ g_autoptr(GPtrArray) devices = NULL;
+ g_autoptr(GVariantIter) obj_iter = NULL;
+ g_autoptr(GDBusConnection) connection = NULL;
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error);
+ if (connection == NULL) {
+ g_prefix_error(error, "failed to get system bus: ");
+ return NULL;
+ }
+ proxy = g_dbus_proxy_new_sync(connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ UDISKS_DBUS_SERVICE,
+ UDISKS_DBUS_PATH,
+ UDISKS_DBUS_MANAGER_INTERFACE,
+ NULL,
+ error);
+ if (proxy == NULL) {
+ g_prefix_error(error, "failed to find %s: ", UDISKS_DBUS_SERVICE);
+ return NULL;
+ }
+
+ devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+ output = g_dbus_proxy_call_sync(proxy,
+ "GetBlockDevices",
+ g_variant_new("(a{sv})", &builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (output == NULL) {
+ if (error != NULL)
+ g_dbus_error_strip_remote_error(*error);
+ g_prefix_error(error,
+ "failed to call %s.%s(): ",
+ UDISKS_DBUS_MANAGER_INTERFACE,
+ "GetBlockDevices");
+ return NULL;
+ }
+
+ g_variant_get(output, "(ao)", &obj_iter);
+ while (g_variant_iter_next(obj_iter, "&o", &obj)) {
+ g_autoptr(GDBusProxy) proxy_blk = NULL;
+ proxy_blk = g_dbus_proxy_new_sync(connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ UDISKS_DBUS_SERVICE,
+ obj,
+ UDISKS_DBUS_INTERFACE_BLOCK,
+ NULL,
+ error);
+ if (proxy_blk == NULL) {
+ g_prefix_error(error, "failed to initialize d-bus proxy for %s: ", obj);
+ return NULL;
+ }
+ g_ptr_array_add(devices, g_steal_pointer(&proxy_blk));
+ }
+ return g_steal_pointer(&devices);
+}
+
+gboolean
+fu_path_fnmatch_impl(const gchar *pattern, const gchar *str)
+{
+#ifdef HAVE_FNMATCH_H
+ return fnmatch(pattern, str, FNM_NOESCAPE) == 0;
+#else
+ return g_strcmp0(pattern, str) == 0;
+#endif
+}
+
+guint64
+fu_common_get_memory_size_impl(void)
+{
+ return (guint64)sysconf(_SC_PHYS_PAGES) * (guint64)sysconf(_SC_PAGE_SIZE);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common-private.h b/fwupd-1.8.6/libfwupdplugin/fu-common-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..a493668c87a9ec86e7a2332158780d2081ea6ddf
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-private.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-common.h"
+
+#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2"
+#define UDISKS_DBUS_INTERFACE_PARTITION "org.freedesktop.UDisks2.Partition"
+#define UDISKS_DBUS_INTERFACE_FILESYSTEM "org.freedesktop.UDisks2.Filesystem"
+#define UDISKS_DBUS_INTERFACE_BLOCK "org.freedesktop.UDisks2.Block"
+
+GPtrArray *
+fu_common_get_block_devices(GError **error);
+guint64
+fu_common_get_memory_size_impl(void);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common-windows.c b/fwupd-1.8.6/libfwupdplugin/fu-common-windows.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd3e72999c20cf47bbd29cceffa3e3f59036941c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common-windows.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include
+#include
+#include
+
+#include "fu-common-private.h"
+#include "fu-path-private.h"
+
+GPtrArray *
+fu_common_get_block_devices(GError **error)
+{
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "getting block devices is not supported on Windows");
+ return NULL;
+}
+
+gboolean
+fu_path_fnmatch_impl(const gchar *pattern, const gchar *str)
+{
+ g_return_val_if_fail(pattern != NULL, FALSE);
+ g_return_val_if_fail(str != NULL, FALSE);
+ return PathMatchSpecA(str, pattern);
+}
+
+guint64
+fu_common_get_memory_size_impl(void)
+{
+ MEMORYSTATUSEX status;
+ status.dwLength = sizeof(status);
+ GlobalMemoryStatusEx(&status);
+ return (guint64)status.ullTotalPhys;
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common.c b/fwupd-1.8.6/libfwupdplugin/fu-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..00b099fbd151dd0353e8b1da5786ac35ccf675c4
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#ifdef HAVE_CPUID_H
+#include
+#endif
+
+#include "fu-common-private.h"
+#include "fu-firmware.h"
+#include "fu-string.h"
+
+/**
+ * fu_cpuid:
+ * @leaf: the CPUID level, now called the 'leaf' by Intel
+ * @eax: (out) (nullable): EAX register
+ * @ebx: (out) (nullable): EBX register
+ * @ecx: (out) (nullable): ECX register
+ * @edx: (out) (nullable): EDX register
+ * @error: (nullable): optional return location for an error
+ *
+ * Calls CPUID and returns the registers for the given leaf.
+ *
+ * Returns: %TRUE if the registers are set.
+ *
+ * Since: 1.8.2
+ **/
+gboolean
+fu_cpuid(guint32 leaf, guint32 *eax, guint32 *ebx, guint32 *ecx, guint32 *edx, GError **error)
+{
+#ifdef HAVE_CPUID_H
+ guint eax_tmp = 0;
+ guint ebx_tmp = 0;
+ guint ecx_tmp = 0;
+ guint edx_tmp = 0;
+
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* get vendor */
+ __get_cpuid_count(leaf, 0x0, &eax_tmp, &ebx_tmp, &ecx_tmp, &edx_tmp);
+ if (eax != NULL)
+ *eax = eax_tmp;
+ if (ebx != NULL)
+ *ebx = ebx_tmp;
+ if (ecx != NULL)
+ *ecx = ecx_tmp;
+ if (edx != NULL)
+ *edx = edx_tmp;
+ return TRUE;
+#else
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "no support");
+ return FALSE;
+#endif
+}
+
+/**
+ * fu_cpu_get_vendor:
+ *
+ * Uses CPUID to discover the CPU vendor.
+ *
+ * Returns: a CPU vendor, e.g. %FU_CPU_VENDOR_AMD if the vendor was AMD.
+ *
+ * Since: 1.8.2
+ **/
+FuCpuVendor
+fu_cpu_get_vendor(void)
+{
+#ifdef HAVE_CPUID_H
+ guint ebx = 0;
+ guint ecx = 0;
+ guint edx = 0;
+
+ if (fu_cpuid(0x0, NULL, &ebx, &ecx, &edx, NULL)) {
+ if (ebx == signature_INTEL_ebx && edx == signature_INTEL_edx &&
+ ecx == signature_INTEL_ecx) {
+ return FU_CPU_VENDOR_INTEL;
+ }
+ if (ebx == signature_AMD_ebx && edx == signature_AMD_edx &&
+ ecx == signature_AMD_ecx) {
+ return FU_CPU_VENDOR_AMD;
+ }
+ }
+#endif
+
+ /* failed */
+ return FU_CPU_VENDOR_UNKNOWN;
+}
+
+/**
+ * fu_common_is_live_media:
+ *
+ * Checks if the user is running from a live media using various heuristics.
+ *
+ * Returns: %TRUE if live
+ *
+ * Since: 1.4.6
+ **/
+gboolean
+fu_common_is_live_media(void)
+{
+ gsize bufsz = 0;
+ g_autofree gchar *buf = NULL;
+ g_auto(GStrv) tokens = NULL;
+ const gchar *args[] = {
+ "rd.live.image",
+ "boot=live",
+ NULL, /* last entry */
+ };
+ if (g_file_test("/cdrom/.disk/info", G_FILE_TEST_EXISTS))
+ return TRUE;
+ if (!g_file_get_contents("/proc/cmdline", &buf, &bufsz, NULL))
+ return FALSE;
+ if (bufsz == 0)
+ return FALSE;
+ tokens = fu_strsplit(buf, bufsz - 1, " ", -1);
+ for (guint i = 0; args[i] != NULL; i++) {
+ if (g_strv_contains((const gchar *const *)tokens, args[i]))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fu_common_get_memory_size:
+ *
+ * Returns the size of physical memory.
+ *
+ * Returns: bytes
+ *
+ * Since: 1.5.6
+ **/
+guint64
+fu_common_get_memory_size(void)
+{
+ return fu_common_get_memory_size_impl();
+}
+
+/**
+ * fu_common_check_full_disk_encryption:
+ * @error: (nullable): optional return location for an error
+ *
+ * Checks that all FDE volumes are not going to be affected by a firmware update. If unsure,
+ * return with failure and let the user decide.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.7.1
+ **/
+gboolean
+fu_common_check_full_disk_encryption(GError **error)
+{
+ g_autoptr(GPtrArray) devices = NULL;
+
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ devices = fu_common_get_block_devices(error);
+ if (devices == NULL)
+ return FALSE;
+ for (guint i = 0; i < devices->len; i++) {
+ GDBusProxy *proxy = g_ptr_array_index(devices, i);
+ g_autoptr(GVariant) id_type = g_dbus_proxy_get_cached_property(proxy, "IdType");
+ g_autoptr(GVariant) device = g_dbus_proxy_get_cached_property(proxy, "Device");
+ if (id_type == NULL || device == NULL)
+ continue;
+ if (g_strcmp0(g_variant_get_string(id_type, NULL), "BitLocker") == 0) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_WOULD_BLOCK,
+ "%s device %s is encrypted",
+ g_variant_get_string(id_type, NULL),
+ g_variant_get_bytestring(device));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * fu_common_align_up:
+ * @value: value to align
+ * @alignment: align to this power of 2, where 0x1F is the maximum value of 2GB
+ *
+ * Align a value to a power of 2 boundary, where @alignment is the bit position
+ * to align to. If @alignment is zero then @value is always returned unchanged.
+ *
+ * Returns: aligned value, which will be the same as @value if already aligned,
+ * or %G_MAXSIZE if the value would overflow
+ *
+ * Since: 1.6.0
+ **/
+gsize
+fu_common_align_up(gsize value, guint8 alignment)
+{
+ gsize value_new;
+ gsize mask = (gsize)1 << alignment;
+
+ g_return_val_if_fail(alignment <= FU_FIRMWARE_ALIGNMENT_2G, G_MAXSIZE);
+
+ /* no alignment required */
+ if ((value & (mask - 1)) == 0)
+ return value;
+
+ /* increment up to the next alignment value */
+ value_new = value + mask;
+ value_new &= ~(mask - 1);
+
+ /* overflow */
+ if (value_new < value)
+ return G_MAXSIZE;
+
+ /* success */
+ return value_new;
+}
+
+/**
+ * fu_battery_state_to_string:
+ * @battery_state: a battery state, e.g. %FU_BATTERY_STATE_FULLY_CHARGED
+ *
+ * Converts an enumerated type to a string.
+ *
+ * Returns: a string, or %NULL for invalid
+ *
+ * Since: 1.6.0
+ **/
+const gchar *
+fu_battery_state_to_string(FuBatteryState battery_state)
+{
+ if (battery_state == FU_BATTERY_STATE_UNKNOWN)
+ return "unknown";
+ if (battery_state == FU_BATTERY_STATE_CHARGING)
+ return "charging";
+ if (battery_state == FU_BATTERY_STATE_DISCHARGING)
+ return "discharging";
+ if (battery_state == FU_BATTERY_STATE_EMPTY)
+ return "empty";
+ if (battery_state == FU_BATTERY_STATE_FULLY_CHARGED)
+ return "fully-charged";
+ return NULL;
+}
+
+/**
+ * fu_lid_state_to_string:
+ * @lid_state: a battery state, e.g. %FU_LID_STATE_CLOSED
+ *
+ * Converts an enumerated type to a string.
+ *
+ * Returns: a string, or %NULL for invalid
+ *
+ * Since: 1.7.4
+ **/
+const gchar *
+fu_lid_state_to_string(FuLidState lid_state)
+{
+ if (lid_state == FU_LID_STATE_UNKNOWN)
+ return "unknown";
+ if (lid_state == FU_LID_STATE_OPEN)
+ return "open";
+ if (lid_state == FU_LID_STATE_CLOSED)
+ return "closed";
+ return NULL;
+}
+
+/**
+ * fu_xmlb_builder_insert_kv:
+ * @bn: #XbBuilderNode
+ * @key: string key
+ * @value: string value
+ *
+ * Convenience function to add an XML node with a string value. If @value is %NULL
+ * then no member is added.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_xmlb_builder_insert_kv(XbBuilderNode *bn, const gchar *key, const gchar *value)
+{
+ if (value == NULL)
+ return;
+ xb_builder_node_insert_text(bn, key, value, NULL);
+}
+
+/**
+ * fu_xmlb_builder_insert_kx:
+ * @bn: #XbBuilderNode
+ * @key: string key
+ * @value: integer value
+ *
+ * Convenience function to add an XML node with an integer value. If @value is 0
+ * then no member is added.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_xmlb_builder_insert_kx(XbBuilderNode *bn, const gchar *key, guint64 value)
+{
+ g_autofree gchar *value_hex = NULL;
+ if (value == 0)
+ return;
+ value_hex = g_strdup_printf("0x%x", (guint)value);
+ xb_builder_node_insert_text(bn, key, value_hex, NULL);
+}
+
+/**
+ * fu_xmlb_builder_insert_kb:
+ * @bn: #XbBuilderNode
+ * @key: string key
+ * @value: boolean value
+ *
+ * Convenience function to add an XML node with a boolean value.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_xmlb_builder_insert_kb(XbBuilderNode *bn, const gchar *key, gboolean value)
+{
+ xb_builder_node_insert_text(bn, key, value ? "true" : "false", NULL);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-common.h b/fwupd-1.8.6/libfwupdplugin/fu-common.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d4ef8fcbd158e8b44f99c362c7bc1ae935d092d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-common.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+/**
+ * FuEndianType:
+ *
+ * The endian type, e.g. %G_LITTLE_ENDIAN
+ **/
+typedef guint FuEndianType;
+
+/**
+ * FuCpuVendor:
+ * @FU_CPU_VENDOR_UNKNOWN: Unknown
+ * @FU_CPU_VENDOR_INTEL: Intel
+ * @FU_CPU_VENDOR_AMD: AMD
+ *
+ * The CPU vendor.
+ **/
+typedef enum {
+ FU_CPU_VENDOR_UNKNOWN,
+ FU_CPU_VENDOR_INTEL,
+ FU_CPU_VENDOR_AMD,
+ /*< private >*/
+ FU_CPU_VENDOR_LAST
+} FuCpuVendor;
+
+/**
+ * FuBatteryState:
+ * @FU_BATTERY_STATE_UNKNOWN: Unknown
+ * @FU_BATTERY_STATE_CHARGING: Charging
+ * @FU_BATTERY_STATE_DISCHARGING: Discharging
+ * @FU_BATTERY_STATE_EMPTY: Empty
+ * @FU_BATTERY_STATE_FULLY_CHARGED: Fully charged
+ *
+ * The device battery state.
+ **/
+typedef enum {
+ FU_BATTERY_STATE_UNKNOWN,
+ FU_BATTERY_STATE_CHARGING,
+ FU_BATTERY_STATE_DISCHARGING,
+ FU_BATTERY_STATE_EMPTY,
+ FU_BATTERY_STATE_FULLY_CHARGED,
+ /*< private >*/
+ FU_BATTERY_STATE_LAST
+} FuBatteryState;
+
+/**
+ * FuLidState:
+ * @FU_LID_STATE_UNKNOWN: Unknown
+ * @FU_LID_STATE_OPEN: Charging
+ * @FU_LID_STATE_CLOSED: Discharging
+ *
+ * The device lid state.
+ **/
+typedef enum {
+ FU_LID_STATE_UNKNOWN,
+ FU_LID_STATE_OPEN,
+ FU_LID_STATE_CLOSED,
+ /*< private >*/
+ FU_LID_STATE_LAST
+} FuLidState;
+
+gboolean
+fu_cpuid(guint32 leaf, guint32 *eax, guint32 *ebx, guint32 *ecx, guint32 *edx, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+FuCpuVendor
+fu_cpu_get_vendor(void);
+gboolean
+fu_common_is_live_media(void);
+guint64
+fu_common_get_memory_size(void);
+gboolean
+fu_common_check_full_disk_encryption(GError **error);
+
+gsize
+fu_common_align_up(gsize value, guint8 alignment);
+const gchar *
+fu_battery_state_to_string(FuBatteryState battery_state);
+const gchar *
+fu_lid_state_to_string(FuLidState lid_state);
+
+void
+fu_xmlb_builder_insert_kv(XbBuilderNode *bn, const gchar *key, const gchar *value);
+void
+fu_xmlb_builder_insert_kx(XbBuilderNode *bn, const gchar *key, guint64 value);
+void
+fu_xmlb_builder_insert_kb(XbBuilderNode *bn, const gchar *key, gboolean value);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-context-private.h b/fwupd-1.8.6/libfwupdplugin/fu-context-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e14bbd166ba7191d2e7a2a5e6bb95ff805b02dd
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-context-private.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-context.h"
+#include "fu-hwids.h"
+#include "fu-quirks.h"
+#include "fu-volume.h"
+
+FuContext *
+fu_context_new(void);
+gboolean
+fu_context_reload_bios_settings(FuContext *self, GError **error);
+gboolean
+fu_context_load_hwinfo(FuContext *self, GError **error);
+gboolean
+fu_context_load_quirks(FuContext *self, FuQuirksLoadFlags flags, GError **error);
+void
+fu_context_set_runtime_versions(FuContext *self, GHashTable *runtime_versions);
+void
+fu_context_set_compile_versions(FuContext *self, GHashTable *compile_versions);
+void
+fu_context_add_firmware_gtype(FuContext *self, const gchar *id, GType gtype);
+GPtrArray *
+fu_context_get_firmware_gtype_ids(FuContext *self);
+GType
+fu_context_get_firmware_gtype_by_id(FuContext *self, const gchar *id);
+void
+fu_context_add_udev_subsystem(FuContext *self, const gchar *subsystem);
+GPtrArray *
+fu_context_get_udev_subsystems(FuContext *self);
+void
+fu_context_add_esp_volume(FuContext *self, FuVolume *volume);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-context.c b/fwupd-1.8.6/libfwupdplugin/fu-context.c
new file mode 100644
index 0000000000000000000000000000000000000000..093a591ad3fadcbab156f34d44c55f5d1b2a903b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-context.c
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuContext"
+
+#include "config.h"
+
+#include "fu-bios-settings-private.h"
+#include "fu-context-private.h"
+#include "fu-hwids.h"
+#include "fu-smbios-private.h"
+#include "fu-volume-private.h"
+
+/**
+ * FuContext:
+ *
+ * A context that represents the shared system state. This object is shared
+ * between the engine, the plugins and the devices.
+ */
+
+typedef struct {
+ FuContextFlags flags;
+ FuHwids *hwids;
+ FuSmbios *smbios;
+ FuQuirks *quirks;
+ GHashTable *runtime_versions;
+ GHashTable *compile_versions;
+ GPtrArray *udev_subsystems;
+ GPtrArray *esp_volumes;
+ GHashTable *firmware_gtypes;
+ GHashTable *hwid_flags; /* str: */
+ FuBatteryState battery_state;
+ FuLidState lid_state;
+ guint battery_level;
+ guint battery_threshold;
+ FuBiosSettings *host_bios_settings;
+} FuContextPrivate;
+
+enum { SIGNAL_SECURITY_CHANGED, SIGNAL_LAST };
+
+enum {
+ PROP_0,
+ PROP_BATTERY_STATE,
+ PROP_LID_STATE,
+ PROP_BATTERY_LEVEL,
+ PROP_BATTERY_THRESHOLD,
+ PROP_LAST
+};
+
+static guint signals[SIGNAL_LAST] = {0};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuContext, fu_context, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) (fu_context_get_instance_private(o))
+
+/**
+ * fu_context_get_smbios_string:
+ * @self: a #FuContext
+ * @structure_type: a SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
+ * @offset: a SMBIOS offset
+ *
+ * Gets a hardware SMBIOS string.
+ *
+ * The @type and @offset can be referenced from the DMTF SMBIOS specification:
+ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 1.6.0
+ **/
+const gchar *
+fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offset)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ return fu_smbios_get_string(priv->smbios, structure_type, offset, NULL);
+}
+
+/**
+ * fu_context_get_smbios_data:
+ * @self: a #FuContext
+ * @structure_type: a SMBIOS structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
+ *
+ * Gets a hardware SMBIOS data.
+ *
+ * Returns: (transfer full): a #GBytes, or %NULL
+ *
+ * Since: 1.6.0
+ **/
+GBytes *
+fu_context_get_smbios_data(FuContext *self, guint8 structure_type)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ return fu_smbios_get_data(priv->smbios, structure_type, NULL);
+}
+
+/**
+ * fu_context_get_smbios_integer:
+ * @self: a #FuContext
+ * @type: a structure type, e.g. %FU_SMBIOS_STRUCTURE_TYPE_BIOS
+ * @offset: a structure offset
+ *
+ * Reads an integer value from the SMBIOS string table of a specific structure.
+ *
+ * The @type and @offset can be referenced from the DMTF SMBIOS specification:
+ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
+ *
+ * Returns: an integer, or %G_MAXUINT if invalid or not found
+ *
+ * Since: 1.6.0
+ **/
+guint
+fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
+ return fu_smbios_get_integer(priv->smbios, type, offset, NULL);
+}
+
+/**
+ * fu_context_reload_bios_settings:
+ * @self: a #FuContext
+ * @error: (nullable): optional return location for an error
+ *
+ * Refreshes the list of firmware attributes on the system.
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fu_context_reload_bios_settings(FuContext *self, GError **error)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ return fu_bios_settings_setup(priv->host_bios_settings, error);
+}
+
+/**
+ * fu_context_get_bios_settings:
+ * @self: a #FuContext
+ *
+ * Returns all the firmware attributes defined in the system.
+ *
+ * Returns: (transfer full): A #FuBiosSettings
+ *
+ * Since: 1.8.4
+ **/
+FuBiosSettings *
+fu_context_get_bios_settings(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ return g_object_ref(priv->host_bios_settings);
+}
+
+/**
+ * fu_context_get_bios_setting:
+ * @self: a #FuContext
+ * @name: a BIOS setting title, e.g. `BootOrderLock`
+ *
+ * Finds out if a system supports a given BIOS setting.
+ *
+ * Returns: (transfer none): #FwupdBiosSetting if the attr exists.
+ *
+ * Since: 1.8.4
+ **/
+FwupdBiosSetting *
+fu_context_get_bios_setting(FuContext *self, const gchar *name)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+ return fu_bios_settings_get_attr(priv->host_bios_settings, name);
+}
+
+/**
+ * fu_context_get_bios_setting_pending_reboot:
+ * @self: a #FuContext
+ *
+ * Determine if updates to BIOS settings are pending until next boot.
+ *
+ * Returns: %TRUE if updates are pending.
+ *
+ * Since: 1.8.4
+ **/
+gboolean
+fu_context_get_bios_setting_pending_reboot(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ gboolean ret;
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ fu_bios_settings_get_pending_reboot(priv->host_bios_settings, &ret, NULL);
+ return ret;
+}
+
+/**
+ * fu_context_has_hwid_guid:
+ * @self: a #FuContext
+ * @guid: a GUID, e.g. `059eb22d-6dc7-59af-abd3-94bbe017f67c`
+ *
+ * Finds out if a hardware GUID exists.
+ *
+ * Returns: %TRUE if the GUID exists
+ *
+ * Since: 1.6.0
+ **/
+gboolean
+fu_context_has_hwid_guid(FuContext *self, const gchar *guid)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ return fu_hwids_has_guid(priv->hwids, guid);
+}
+
+/**
+ * fu_context_get_hwid_guids:
+ * @self: a #FuContext
+ *
+ * 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 utf8): an array of GUIDs
+ *
+ * Since: 1.6.0
+ **/
+GPtrArray *
+fu_context_get_hwid_guids(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ return fu_hwids_get_guids(priv->hwids);
+}
+
+/**
+ * fu_context_get_hwid_value:
+ * @self: a #FuContext
+ * @key: a DMI ID, e.g. `BiosVersion`
+ *
+ * Gets the cached value for one specific key that is valid ASCII and suitable
+ * for display.
+ *
+ * Returns: the string, e.g. `1.2.3`, or %NULL if not found
+ *
+ * Since: 1.6.0
+ **/
+const gchar *
+fu_context_get_hwid_value(FuContext *self, const gchar *key)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+ return fu_hwids_get_value(priv->hwids, key);
+}
+
+/**
+ * fu_context_get_hwid_replace_value:
+ * @self: a #FuContext
+ * @keys: a key, e.g. `HardwareID-3` or %FU_HWIDS_KEY_PRODUCT_SKU
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the replacement value for a specific key. All hardware IDs on a
+ * specific system can be shown using the `fwupdmgr hwids` command.
+ *
+ * Returns: (transfer full): a string, or %NULL for error.
+ *
+ * Since: 1.6.0
+ **/
+gchar *
+fu_context_get_hwid_replace_value(FuContext *self, const gchar *keys, GError **error)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ g_return_val_if_fail(keys != NULL, NULL);
+ return fu_hwids_get_replace_values(priv->hwids, keys, error);
+}
+
+/**
+ * fu_context_add_runtime_version:
+ * @self: a #FuContext
+ * @component_id: an AppStream component id, e.g. `org.gnome.Software`
+ * @version: a version string, e.g. `1.2.3`
+ *
+ * Sets a runtime version of a specific dependency.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_add_runtime_version(FuContext *self, const gchar *component_id, const gchar *version)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(component_id != NULL);
+ g_return_if_fail(version != NULL);
+
+ if (priv->runtime_versions == NULL)
+ return;
+ g_hash_table_insert(priv->runtime_versions, g_strdup(component_id), g_strdup(version));
+}
+
+/**
+ * fu_context_set_runtime_versions:
+ * @self: a #FuContext
+ * @runtime_versions: (element-type utf8 utf8): dictionary of versions
+ *
+ * Sets the runtime versions for a plugin.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_set_runtime_versions(FuContext *self, GHashTable *runtime_versions)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(runtime_versions != NULL);
+ priv->runtime_versions = g_hash_table_ref(runtime_versions);
+}
+
+/**
+ * fu_context_add_compile_version:
+ * @self: a #FuContext
+ * @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.6.0
+ **/
+void
+fu_context_add_compile_version(FuContext *self, const gchar *component_id, const gchar *version)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(component_id != NULL);
+ g_return_if_fail(version != NULL);
+
+ if (priv->compile_versions == NULL)
+ return;
+ g_hash_table_insert(priv->compile_versions, g_strdup(component_id), g_strdup(version));
+}
+
+/**
+ * fu_context_set_compile_versions:
+ * @self: a #FuContext
+ * @compile_versions: (element-type utf8 utf8): dictionary of versions
+ *
+ * Sets the compile time versions for a plugin.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_set_compile_versions(FuContext *self, GHashTable *compile_versions)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(compile_versions != NULL);
+ priv->compile_versions = g_hash_table_ref(compile_versions);
+}
+
+/**
+ * fu_context_add_udev_subsystem:
+ * @self: a #FuContext
+ * @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()
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_add_udev_subsystem(FuContext *self, const gchar *subsystem)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(subsystem != NULL);
+
+ 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));
+}
+
+/**
+ * fu_context_get_udev_subsystems:
+ * @self: a #FuContext
+ *
+ * Gets the udev subsystems required by all plugins.
+ *
+ * Returns: (transfer none) (element-type utf8): List of subsystems
+ *
+ * Since: 1.6.0
+ **/
+GPtrArray *
+fu_context_get_udev_subsystems(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ return priv->udev_subsystems;
+}
+
+/**
+ * fu_context_add_firmware_gtype:
+ * @self: a #FuContext
+ * @id: (nullable): an optional string describing the type, e.g. `ihex`
+ * @gtype: a #GType e.g. `FU_TYPE_FOO_FIRMWARE`
+ *
+ * Adds a firmware #GType which is used when creating devices. If @id is not
+ * specified then it is guessed using the #GType name.
+ *
+ * Plugins can use this method only in fu_plugin_init()
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_add_firmware_gtype(FuContext *self, const gchar *id, GType gtype)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(id != NULL);
+ g_return_if_fail(gtype != G_TYPE_INVALID);
+ g_type_ensure(gtype);
+ g_hash_table_insert(priv->firmware_gtypes, g_strdup(id), GSIZE_TO_POINTER(gtype));
+}
+
+/**
+ * fu_context_get_firmware_gtype_by_id:
+ * @self: a #FuContext
+ * @id: an string describing the type, e.g. `ihex`
+ *
+ * Returns the #GType using the firmware @id.
+ *
+ * Returns: a #GType, or %G_TYPE_INVALID
+ *
+ * Since: 1.6.0
+ **/
+GType
+fu_context_get_firmware_gtype_by_id(FuContext *self, const gchar *id)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), G_TYPE_INVALID);
+ g_return_val_if_fail(id != NULL, G_TYPE_INVALID);
+ return GPOINTER_TO_SIZE(g_hash_table_lookup(priv->firmware_gtypes, id));
+}
+
+static gint
+fu_context_gtypes_sort_cb(gconstpointer a, gconstpointer b)
+{
+ const gchar *stra = *((const gchar **)a);
+ const gchar *strb = *((const gchar **)b);
+ return g_strcmp0(stra, strb);
+}
+
+/**
+ * fu_context_get_firmware_gtype_ids:
+ * @self: a #FuContext
+ *
+ * Returns all the firmware #GType IDs.
+ *
+ * Returns: (transfer none) (element-type utf8): List of subsystems
+ *
+ * Since: 1.6.0
+ **/
+GPtrArray *
+fu_context_get_firmware_gtype_ids(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ GPtrArray *firmware_gtypes = g_ptr_array_new_with_free_func(g_free);
+ g_autoptr(GList) keys = g_hash_table_get_keys(priv->firmware_gtypes);
+
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+
+ for (GList *l = keys; l != NULL; l = l->next) {
+ const gchar *id = l->data;
+ g_ptr_array_add(firmware_gtypes, g_strdup(id));
+ }
+ g_ptr_array_sort(firmware_gtypes, fu_context_gtypes_sort_cb);
+ return firmware_gtypes;
+}
+
+/**
+ * fu_context_add_quirk_key:
+ * @self: a #FuContext
+ * @key: a quirk string, e.g. `DfuVersion`
+ *
+ * Adds a possible quirk key. If added by a plugin it should be namespaced
+ * using the plugin name, where possible.
+ *
+ * Plugins can use this method only in fu_plugin_init()
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_add_quirk_key(FuContext *self, const gchar *key)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(key != NULL);
+ if (priv->quirks == NULL)
+ return;
+ fu_quirks_add_possible_key(priv->quirks, key);
+}
+
+/**
+ * fu_context_lookup_quirk_by_id:
+ * @self: a #FuContext
+ * @guid: GUID to lookup
+ * @key: an ID to match the entry, e.g. `Summary`
+ *
+ * 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.6.0
+ **/
+const gchar *
+fu_context_lookup_quirk_by_id(FuContext *self, const gchar *guid, const gchar *key)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ g_return_val_if_fail(guid != NULL, NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
+ /* exact ID */
+ return fu_quirks_lookup_by_id(priv->quirks, guid, key);
+}
+
+/**
+ * fu_context_lookup_quirk_by_id_iter:
+ * @self: a #FuContext
+ * @guid: GUID to lookup
+ * @iter_cb: (scope async): a function to call for each result
+ * @user_data: user data passed to @iter_cb
+ *
+ * Looks up all entries in the hardware database using a GUID value.
+ *
+ * Returns: %TRUE if the ID was found, and @iter was called
+ *
+ * Since: 1.6.0
+ **/
+gboolean
+fu_context_lookup_quirk_by_id_iter(FuContext *self,
+ const gchar *guid,
+ FuContextLookupIter iter_cb,
+ gpointer user_data)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ g_return_val_if_fail(guid != NULL, FALSE);
+ g_return_val_if_fail(iter_cb != NULL, FALSE);
+ return fu_quirks_lookup_by_id_iter(priv->quirks, guid, (FuQuirksIter)iter_cb, user_data);
+}
+
+/**
+ * fu_context_security_changed:
+ * @self: a #FuContext
+ *
+ * Informs the daemon that the HSI state may have changed.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_security_changed(FuContext *self)
+{
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_signal_emit(self, signals[SIGNAL_SECURITY_CHANGED], 0);
+}
+
+/**
+ * fu_context_load_hwinfo:
+ * @self: a #FuContext
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads all hardware information parts of the context.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.6.0
+ **/
+gboolean
+fu_context_load_hwinfo(FuContext *self, GError **error)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ GPtrArray *guids;
+ g_autoptr(GError) error_smbios = NULL;
+ g_autoptr(GError) error_hwids = NULL;
+ g_autoptr(GError) error_bios_settings = NULL;
+
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ if (!fu_smbios_setup(priv->smbios, &error_smbios))
+ g_warning("Failed to load SMBIOS: %s", error_smbios->message);
+ if (!fu_hwids_setup(priv->hwids, priv->smbios, &error_hwids))
+ g_warning("Failed to load HWIDs: %s", error_hwids->message);
+
+ /* set the hwid flags */
+ guids = fu_context_get_hwid_guids(self);
+ for (guint i = 0; i < guids->len; i++) {
+ const gchar *guid = g_ptr_array_index(guids, i);
+ const gchar *value;
+
+ /* does prefixed quirk exist */
+ value = fu_context_lookup_quirk_by_id(self, guid, FU_QUIRKS_FLAGS);
+ if (value != NULL) {
+ g_auto(GStrv) values = g_strsplit(value, ",", -1);
+ for (guint j = 0; values[j] != NULL; j++)
+ g_hash_table_add(priv->hwid_flags, g_strdup(values[j]));
+ }
+ }
+
+ fu_context_add_udev_subsystem(self, "firmware-attributes");
+ if (!fu_context_reload_bios_settings(self, &error_bios_settings))
+ g_debug("%s", error_bios_settings->message);
+
+ /* always */
+ return TRUE;
+}
+
+/**
+ * fu_context_has_hwid_flag:
+ * @self: a #FuContext
+ * @flag: flag, e.g. `use-legacy-bootmgr-desc`
+ *
+ * Returns if a HwId custom flag exists, typically added from a DMI quirk.
+ *
+ * Returns: %TRUE if the flag exists
+ *
+ * Since: 1.7.2
+ **/
+gboolean
+fu_context_has_hwid_flag(FuContext *self, const gchar *flag)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ g_return_val_if_fail(flag != NULL, FALSE);
+ return g_hash_table_lookup(priv->hwid_flags, flag) != NULL;
+}
+
+/**
+ * fu_context_load_quirks:
+ * @self: a #FuContext
+ * @flags: quirks load flags, e.g. %FU_QUIRKS_LOAD_FLAG_READONLY_FS
+ * @error: (nullable): optional return location for an error
+ *
+ * Loads all quirks into the context.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.6.0
+ **/
+gboolean
+fu_context_load_quirks(FuContext *self, FuQuirksLoadFlags flags, GError **error)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GError) error_local = NULL;
+
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* rebuild silo if required */
+ if (!fu_quirks_load(priv->quirks, flags, &error_local))
+ g_warning("Failed to load quirks: %s", error_local->message);
+
+ /* always */
+ return TRUE;
+}
+
+/**
+ * fu_context_get_battery_state:
+ * @self: a #FuContext
+ *
+ * Gets if the system is on battery power, e.g. UPS or laptop battery.
+ *
+ * Returns: a battery state, e.g. %FU_BATTERY_STATE_DISCHARGING
+ *
+ * Since: 1.6.0
+ **/
+FuBatteryState
+fu_context_get_battery_state(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ return priv->battery_state;
+}
+
+/**
+ * fu_context_set_battery_state:
+ * @self: a #FuContext
+ * @battery_state: a battery state, e.g. %FU_BATTERY_STATE_DISCHARGING
+ *
+ * Sets if the system is on battery power, e.g. UPS or laptop battery.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_set_battery_state(FuContext *self, FuBatteryState battery_state)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ if (priv->battery_state == battery_state)
+ return;
+ priv->battery_state = battery_state;
+ g_debug("battery state now %s", fu_battery_state_to_string(battery_state));
+ g_object_notify(G_OBJECT(self), "battery-state");
+}
+
+/**
+ * fu_context_get_lid_state:
+ * @self: a #FuContext
+ *
+ * Gets the laptop lid state, if applicable.
+ *
+ * Returns: a battery state, e.g. %FU_LID_STATE_CLOSED
+ *
+ * Since: 1.7.4
+ **/
+FuLidState
+fu_context_get_lid_state(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
+ return priv->lid_state;
+}
+
+/**
+ * fu_context_set_lid_state:
+ * @self: a #FuContext
+ * @lid_state: a battery state, e.g. %FU_LID_STATE_CLOSED
+ *
+ * Sets the laptop lid state, if applicable.
+ *
+ * Since: 1.7.4
+ **/
+void
+fu_context_set_lid_state(FuContext *self, FuLidState lid_state)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ if (priv->lid_state == lid_state)
+ return;
+ priv->lid_state = lid_state;
+ g_debug("lid state now %s", fu_lid_state_to_string(lid_state));
+ g_object_notify(G_OBJECT(self), "lid-state");
+}
+
+/**
+ * fu_context_get_battery_level:
+ * @self: a #FuContext
+ *
+ * Gets the system battery level in percent.
+ *
+ * Returns: percentage value, or %FWUPD_BATTERY_LEVEL_INVALID for unknown
+ *
+ * Since: 1.6.0
+ **/
+guint
+fu_context_get_battery_level(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
+ return priv->battery_level;
+}
+
+/**
+ * fu_context_set_battery_level:
+ * @self: a #FuContext
+ * @battery_level: value
+ *
+ * Sets the system battery level in percent.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_set_battery_level(FuContext *self, guint battery_level)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(battery_level <= FWUPD_BATTERY_LEVEL_INVALID);
+ if (priv->battery_level == battery_level)
+ return;
+ priv->battery_level = battery_level;
+ g_debug("battery level now %u", battery_level);
+ g_object_notify(G_OBJECT(self), "battery-level");
+}
+
+/**
+ * fu_context_get_battery_threshold:
+ * @self: a #FuContext
+ *
+ * Gets the system battery threshold in percent.
+ *
+ * Returns: percentage value, or %FWUPD_BATTERY_LEVEL_INVALID for unknown
+ *
+ * Since: 1.6.0
+ **/
+guint
+fu_context_get_battery_threshold(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_CONTEXT(self), G_MAXUINT);
+ return priv->battery_threshold;
+}
+
+/**
+ * fu_context_set_battery_threshold:
+ * @self: a #FuContext
+ * @battery_threshold: value
+ *
+ * Sets the system battery threshold in percent.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_context_set_battery_threshold(FuContext *self, guint battery_threshold)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(battery_threshold <= FWUPD_BATTERY_LEVEL_INVALID);
+ if (priv->battery_threshold == battery_threshold)
+ return;
+ priv->battery_threshold = battery_threshold;
+ g_debug("battery threshold now %u", battery_threshold);
+ g_object_notify(G_OBJECT(self), "battery-threshold");
+}
+
+/**
+ * fu_context_add_flag:
+ * @context: a #FuContext
+ * @flag: the context flag
+ *
+ * Adds a specific flag to the context.
+ *
+ * Since: 1.8.5
+ **/
+void
+fu_context_add_flag(FuContext *context, FuContextFlags flag)
+{
+ FuContextPrivate *priv = GET_PRIVATE(context);
+ g_return_if_fail(FU_IS_CONTEXT(context));
+ priv->flags |= flag;
+}
+
+/**
+ * fu_context_has_flag:
+ * @context: a #FuContext
+ * @flag: the context flag
+ *
+ * Finds if the context has a specific flag.
+ *
+ * Returns: %TRUE if the flag is set
+ *
+ * Since: 1.8.5
+ **/
+gboolean
+fu_context_has_flag(FuContext *context, FuContextFlags flag)
+{
+ FuContextPrivate *priv = GET_PRIVATE(context);
+ g_return_val_if_fail(FU_IS_CONTEXT(context), FALSE);
+ return (priv->flags & flag) > 0;
+}
+
+/**
+ * fu_context_add_esp_volume:
+ * @self: a #FuContext
+ * @volume: a #FuVolume
+ *
+ * Adds an ESP volume location.
+ *
+ * Since: 1.8.5
+ **/
+void
+fu_context_add_esp_volume(FuContext *self, FuVolume *volume)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_CONTEXT(self));
+ g_return_if_fail(FU_IS_VOLUME(volume));
+
+ /* check for dupes */
+ for (guint i = 0; i < priv->esp_volumes->len; i++) {
+ FuVolume *volume_tmp = g_ptr_array_index(priv->esp_volumes, i);
+ if (g_strcmp0(fu_volume_get_id(volume_tmp), fu_volume_get_id(volume)) == 0) {
+ g_debug("not adding duplicate volume %s", fu_volume_get_id(volume));
+ return;
+ }
+ }
+
+ /* add */
+ g_ptr_array_add(priv->esp_volumes, g_object_ref(volume));
+}
+
+/**
+ * fu_context_get_esp_volumes:
+ * @self: a #FuContext
+ * @error: (nullable): optional return location for an error
+ *
+ * Finds all volumes that could be an ESP.
+ *
+ * The volumes are cached and so subsequent calls to this function will be much faster.
+ *
+ * Returns: (transfer container) (element-type FuVolume): a #GPtrArray, or %NULL if no ESP was found
+ *
+ * Since: 1.8.5
+ **/
+GPtrArray *
+fu_context_get_esp_volumes(FuContext *self, GError **error)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ const gchar *path_tmp;
+ g_autoptr(GError) error_bdp = NULL;
+ g_autoptr(GError) error_esp = NULL;
+ g_autoptr(GPtrArray) volumes_bdp = NULL;
+ g_autoptr(GPtrArray) volumes_esp = NULL;
+
+ g_return_val_if_fail(FU_IS_CONTEXT(self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* cached result */
+ if (priv->esp_volumes->len > 0)
+ return g_ptr_array_ref(priv->esp_volumes);
+
+ /* for the test suite use local directory for ESP */
+ path_tmp = g_getenv("FWUPD_UEFI_ESP_PATH");
+ if (path_tmp != NULL) {
+ g_autoptr(FuVolume) vol = fu_volume_new_from_mount_path(path_tmp);
+ fu_context_add_esp_volume(self, vol);
+ return g_ptr_array_ref(priv->esp_volumes);
+ }
+
+ /* ESP */
+ volumes_esp = fu_volume_new_by_kind(FU_VOLUME_KIND_ESP, &error_esp);
+ if (volumes_esp == NULL) {
+ g_debug("%s", error_esp->message);
+ } else {
+ for (guint i = 0; i < volumes_esp->len; i++) {
+ FuVolume *vol = g_ptr_array_index(volumes_esp, i);
+ fu_context_add_esp_volume(self, vol);
+ }
+ }
+
+ /* BDP */
+ volumes_bdp = fu_volume_new_by_kind(FU_VOLUME_KIND_BDP, &error_bdp);
+ if (volumes_bdp == NULL) {
+ g_debug("%s", error_bdp->message);
+ } else {
+ for (guint i = 0; i < volumes_bdp->len; i++) {
+ FuVolume *vol = g_ptr_array_index(volumes_bdp, i);
+ g_autofree gchar *type = fu_volume_get_id_type(vol);
+ if (g_strcmp0(type, "vfat") != 0)
+ continue;
+ if (!fu_volume_is_internal(vol))
+ continue;
+ fu_context_add_esp_volume(self, vol);
+ }
+ }
+
+ /* nothing found */
+ if (priv->esp_volumes->len == 0) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No ESP or BDP found");
+ return NULL;
+ }
+
+ /* success */
+ return g_ptr_array_ref(priv->esp_volumes);
+}
+
+static void
+fu_context_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FuContext *self = FU_CONTEXT(object);
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_BATTERY_STATE:
+ g_value_set_uint(value, priv->battery_state);
+ break;
+ case PROP_LID_STATE:
+ g_value_set_uint(value, priv->lid_state);
+ break;
+ case PROP_BATTERY_LEVEL:
+ g_value_set_uint(value, priv->battery_level);
+ break;
+ case PROP_BATTERY_THRESHOLD:
+ g_value_set_uint(value, priv->battery_threshold);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_context_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FuContext *self = FU_CONTEXT(object);
+ switch (prop_id) {
+ case PROP_BATTERY_STATE:
+ fu_context_set_battery_state(self, g_value_get_uint(value));
+ break;
+ case PROP_LID_STATE:
+ fu_context_set_lid_state(self, g_value_get_uint(value));
+ break;
+ case PROP_BATTERY_LEVEL:
+ fu_context_set_battery_level(self, g_value_get_uint(value));
+ break;
+ case PROP_BATTERY_THRESHOLD:
+ fu_context_set_battery_threshold(self, g_value_get_uint(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_context_finalize(GObject *object)
+{
+ FuContext *self = FU_CONTEXT(object);
+ FuContextPrivate *priv = GET_PRIVATE(self);
+
+ 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_object_unref(priv->hwids);
+ g_hash_table_unref(priv->hwid_flags);
+ g_object_unref(priv->quirks);
+ g_object_unref(priv->smbios);
+ g_object_unref(priv->host_bios_settings);
+ g_hash_table_unref(priv->firmware_gtypes);
+ g_ptr_array_unref(priv->udev_subsystems);
+ g_ptr_array_unref(priv->esp_volumes);
+
+ G_OBJECT_CLASS(fu_context_parent_class)->finalize(object);
+}
+
+static void
+fu_context_class_init(FuContextClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
+
+ object_class->get_property = fu_context_get_property;
+ object_class->set_property = fu_context_set_property;
+
+ /**
+ * FuContext:battery-state:
+ *
+ * The system battery state.
+ *
+ * Since: 1.6.0
+ */
+ pspec = g_param_spec_uint("battery-state",
+ NULL,
+ NULL,
+ FU_BATTERY_STATE_UNKNOWN,
+ FU_BATTERY_STATE_LAST,
+ FU_BATTERY_STATE_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_STATE, pspec);
+
+ /**
+ * FuContext:lid-state:
+ *
+ * The system lid state.
+ *
+ * Since: 1.7.4
+ */
+ pspec = g_param_spec_uint("lid-state",
+ NULL,
+ NULL,
+ FU_LID_STATE_UNKNOWN,
+ FU_LID_STATE_LAST,
+ FU_LID_STATE_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_LID_STATE, pspec);
+
+ /**
+ * FuContext:battery-level:
+ *
+ * The system battery level in percent.
+ *
+ * Since: 1.6.0
+ */
+ pspec = g_param_spec_uint("battery-level",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_LEVEL, pspec);
+
+ /**
+ * FuContext:battery-threshold:
+ *
+ * The system battery threshold in percent.
+ *
+ * Since: 1.6.0
+ */
+ pspec = g_param_spec_uint("battery-threshold",
+ NULL,
+ NULL,
+ 0,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ FWUPD_BATTERY_LEVEL_INVALID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BATTERY_THRESHOLD, pspec);
+
+ /**
+ * FuContext::security-changed:
+ * @self: the #FuContext instance that emitted the signal
+ *
+ * The ::security-changed signal is emitted when some system state has changed that could
+ * have affected the security level.
+ *
+ * Since: 1.6.0
+ **/
+ signals[SIGNAL_SECURITY_CHANGED] =
+ g_signal_new("security-changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FuContextClass, security_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ object_class->finalize = fu_context_finalize;
+}
+
+static void
+fu_context_init(FuContext *self)
+{
+ FuContextPrivate *priv = GET_PRIVATE(self);
+ priv->battery_level = FWUPD_BATTERY_LEVEL_INVALID;
+ priv->battery_threshold = FWUPD_BATTERY_LEVEL_INVALID;
+ priv->smbios = fu_smbios_new();
+ priv->hwids = fu_hwids_new();
+ priv->hwid_flags = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ priv->udev_subsystems = g_ptr_array_new_with_free_func(g_free);
+ priv->firmware_gtypes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ priv->quirks = fu_quirks_new();
+ priv->host_bios_settings = fu_bios_settings_new();
+ priv->esp_volumes = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+}
+
+/**
+ * fu_context_new:
+ *
+ * Creates a new #FuContext
+ *
+ * Returns: (transfer full): the object
+ *
+ * Since: 1.6.0
+ **/
+FuContext *
+fu_context_new(void)
+{
+ return FU_CONTEXT(g_object_new(FU_TYPE_CONTEXT, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-context.h b/fwupd-1.8.6/libfwupdplugin/fu-context.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f05fb9d0cc666445012353d73b8ca32ebe840d7
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-context.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fu-bios-settings.h"
+#include "fu-common.h"
+
+#define FU_TYPE_CONTEXT (fu_context_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuContext, fu_context, FU, CONTEXT, GObject)
+
+struct _FuContextClass {
+ GObjectClass parent_class;
+ /* signals */
+ void (*security_changed)(FuContext *self);
+};
+
+/**
+ * FuContextLookupIter:
+ * @self: a #FuContext
+ * @key: a key
+ * @value: a value
+ * @user_data: user data
+ *
+ * The context lookup iteration callback.
+ */
+typedef void (*FuContextLookupIter)(FuContext *self,
+ const gchar *key,
+ const gchar *value,
+ gpointer user_data);
+
+/**
+ * FU_CONTEXT_FLAG_NONE:
+ *
+ * No flags set.
+ *
+ * Since: 1.8.5
+ **/
+#define FU_CONTEXT_FLAG_NONE (0u)
+
+/**
+ * FU_CONTEXT_FLAG_SAVE_EVENTS:
+ *
+ * Save events so that they can be replayed to emulate devices.
+ *
+ * Since: 1.8.5
+ **/
+#define FU_CONTEXT_FLAG_SAVE_EVENTS (1u << 0)
+
+/**
+ * FuContextFlags:
+ *
+ * The context flags.
+ **/
+typedef guint64 FuContextFlags;
+
+void
+fu_context_add_flag(FuContext *context, FuContextFlags flag);
+gboolean
+fu_context_has_flag(FuContext *context, FuContextFlags flag);
+
+const gchar *
+fu_context_get_smbios_string(FuContext *self, guint8 structure_type, guint8 offset);
+guint
+fu_context_get_smbios_integer(FuContext *self, guint8 type, guint8 offset);
+GBytes *
+fu_context_get_smbios_data(FuContext *self, guint8 structure_type);
+gboolean
+fu_context_has_hwid_guid(FuContext *self, const gchar *guid);
+GPtrArray *
+fu_context_get_hwid_guids(FuContext *self);
+gboolean
+fu_context_has_hwid_flag(FuContext *self, const gchar *flag);
+const gchar *
+fu_context_get_hwid_value(FuContext *self, const gchar *key);
+gchar *
+fu_context_get_hwid_replace_value(FuContext *self,
+ const gchar *keys,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_context_add_runtime_version(FuContext *self, const gchar *component_id, const gchar *version);
+void
+fu_context_add_compile_version(FuContext *self, const gchar *component_id, const gchar *version);
+const gchar *
+fu_context_lookup_quirk_by_id(FuContext *self, const gchar *guid, const gchar *key);
+gboolean
+fu_context_lookup_quirk_by_id_iter(FuContext *self,
+ const gchar *guid,
+ FuContextLookupIter iter_cb,
+ gpointer user_data);
+void
+fu_context_add_quirk_key(FuContext *self, const gchar *key);
+void
+fu_context_security_changed(FuContext *self);
+
+FuBatteryState
+fu_context_get_battery_state(FuContext *self);
+void
+fu_context_set_battery_state(FuContext *self, FuBatteryState battery_state);
+FuLidState
+fu_context_get_lid_state(FuContext *self);
+void
+fu_context_set_lid_state(FuContext *self, FuLidState lid_state);
+guint
+fu_context_get_battery_level(FuContext *self);
+void
+fu_context_set_battery_level(FuContext *self, guint battery_level);
+guint
+fu_context_get_battery_threshold(FuContext *self);
+void
+fu_context_set_battery_threshold(FuContext *self, guint battery_threshold);
+
+FuBiosSettings *
+fu_context_get_bios_settings(FuContext *self);
+gboolean
+fu_context_get_bios_setting_pending_reboot(FuContext *self);
+FwupdBiosSetting *
+fu_context_get_bios_setting(FuContext *self, const gchar *name);
+
+GPtrArray *
+fu_context_get_esp_volumes(FuContext *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-coswid-common.c b/fwupd-1.8.6/libfwupdplugin/fu-coswid-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ebc6d863a7970abe4323d177e292b473007479a
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-coswid-common.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fu-coswid-common.h"
+
+FuCoswidEntityRole
+fu_coswid_entity_role_from_string(const gchar *val)
+{
+ if (g_strcmp0(val, "tag-creator") == 0)
+ return FU_COSWID_ENTITY_ROLE_TAG_CREATOR;
+ if (g_strcmp0(val, "software-creator") == 0)
+ return FU_COSWID_ENTITY_ROLE_SOFTWARE_CREATOR;
+ if (g_strcmp0(val, "aggregator") == 0)
+ return FU_COSWID_ENTITY_ROLE_AGGREGATOR;
+ if (g_strcmp0(val, "distributor") == 0)
+ return FU_COSWID_ENTITY_ROLE_DISTRIBUTOR;
+ if (g_strcmp0(val, "licensor") == 0)
+ return FU_COSWID_ENTITY_ROLE_LICENSOR;
+ if (g_strcmp0(val, "maintainer") == 0)
+ return FU_COSWID_ENTITY_ROLE_MAINTAINER;
+ return FU_COSWID_ENTITY_ROLE_UNKNOWN;
+}
+
+const gchar *
+fu_coswid_entity_role_to_string(FuCoswidEntityRole val)
+{
+ if (val == FU_COSWID_ENTITY_ROLE_TAG_CREATOR)
+ return "tag-creator";
+ if (val == FU_COSWID_ENTITY_ROLE_SOFTWARE_CREATOR)
+ return "software-creator";
+ if (val == FU_COSWID_ENTITY_ROLE_AGGREGATOR)
+ return "aggregator";
+ if (val == FU_COSWID_ENTITY_ROLE_DISTRIBUTOR)
+ return "distributor";
+ if (val == FU_COSWID_ENTITY_ROLE_LICENSOR)
+ return "licensor";
+ if (val == FU_COSWID_ENTITY_ROLE_MAINTAINER)
+ return "maintainer";
+ return NULL;
+}
+
+FuCoswidLinkRel
+fu_coswid_link_rel_from_string(const gchar *val)
+{
+ if (g_strcmp0(val, "license") == 0)
+ return FU_COSWID_LINK_REL_LICENSE;
+ if (g_strcmp0(val, "compiler") == 0)
+ return FU_COSWID_LINK_REL_COMPILER;
+ if (g_strcmp0(val, "ancestor") == 0)
+ return FU_COSWID_LINK_REL_ANCESTOR;
+ if (g_strcmp0(val, "component") == 0)
+ return FU_COSWID_LINK_REL_COMPONENT;
+ if (g_strcmp0(val, "feature") == 0)
+ return FU_COSWID_LINK_REL_FEATURE;
+ if (g_strcmp0(val, "installationmedia") == 0)
+ return FU_COSWID_LINK_REL_INSTALLATIONMEDIA;
+ if (g_strcmp0(val, "packageinstaller") == 0)
+ return FU_COSWID_LINK_REL_PACKAGEINSTALLER;
+ if (g_strcmp0(val, "parent") == 0)
+ return FU_COSWID_LINK_REL_PARENT;
+ if (g_strcmp0(val, "patches") == 0)
+ return FU_COSWID_LINK_REL_PATCHES;
+ if (g_strcmp0(val, "requires") == 0)
+ return FU_COSWID_LINK_REL_REQUIRES;
+ if (g_strcmp0(val, "see-also") == 0)
+ return FU_COSWID_LINK_REL_SEE_ALSO;
+ if (g_strcmp0(val, "supersedes") == 0)
+ return FU_COSWID_LINK_REL_SUPERSEDES;
+ if (g_strcmp0(val, "supplemental") == 0)
+ return FU_COSWID_LINK_REL_SUPPLEMENTAL;
+ return FU_COSWID_LINK_REL_UNKNOWN;
+}
+
+const gchar *
+fu_coswid_link_rel_to_string(FuCoswidLinkRel val)
+{
+ if (val == FU_COSWID_LINK_REL_LICENSE)
+ return "license";
+ if (val == FU_COSWID_LINK_REL_COMPILER)
+ return "compiler";
+ if (val == FU_COSWID_LINK_REL_ANCESTOR)
+ return "ancestor";
+ if (val == FU_COSWID_LINK_REL_COMPONENT)
+ return "component";
+ if (val == FU_COSWID_LINK_REL_FEATURE)
+ return "feature";
+ if (val == FU_COSWID_LINK_REL_INSTALLATIONMEDIA)
+ return "installationmedia";
+ if (val == FU_COSWID_LINK_REL_PACKAGEINSTALLER)
+ return "packageinstaller";
+ if (val == FU_COSWID_LINK_REL_PARENT)
+ return "parent";
+ if (val == FU_COSWID_LINK_REL_PATCHES)
+ return "patches";
+ if (val == FU_COSWID_LINK_REL_REQUIRES)
+ return "requires";
+ if (val == FU_COSWID_LINK_REL_SEE_ALSO)
+ return "see-also";
+ if (val == FU_COSWID_LINK_REL_SUPERSEDES)
+ return "supersedes";
+ if (val == FU_COSWID_LINK_REL_SUPPLEMENTAL)
+ return "supplemental";
+ return NULL;
+}
+
+FuCoswidVersionScheme
+fu_coswid_version_scheme_from_string(const gchar *val)
+{
+ if (g_strcmp0(val, "multipartnumeric") == 0)
+ return FU_COSWID_VERSION_SCHEME_MULTIPARTNUMERIC;
+ if (g_strcmp0(val, "multipartnumeric-suffix") == 0)
+ return FU_COSWID_VERSION_SCHEME_MULTIPARTNUMERIC_SUFFIX;
+ if (g_strcmp0(val, "alphanumeric") == 0)
+ return FU_COSWID_VERSION_SCHEME_ALPHANUMERIC;
+ if (g_strcmp0(val, "decimal") == 0)
+ return FU_COSWID_VERSION_SCHEME_DECIMAL;
+ if (g_strcmp0(val, "semver") == 0)
+ return FU_COSWID_VERSION_SCHEME_SEMVER;
+ return FU_COSWID_VERSION_SCHEME_UNKNOWN;
+}
+
+const gchar *
+fu_coswid_version_scheme_to_string(FuCoswidVersionScheme val)
+{
+ if (val == FU_COSWID_VERSION_SCHEME_MULTIPARTNUMERIC)
+ return "multipartnumeric";
+ if (val == FU_COSWID_VERSION_SCHEME_MULTIPARTNUMERIC_SUFFIX)
+ return "multipartnumeric-suffix";
+ if (val == FU_COSWID_VERSION_SCHEME_ALPHANUMERIC)
+ return "alphanumeric";
+ if (val == FU_COSWID_VERSION_SCHEME_DECIMAL)
+ return "decimal";
+ if (val == FU_COSWID_VERSION_SCHEME_SEMVER)
+ return "semver";
+ return NULL;
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-coswid-common.h b/fwupd-1.8.6/libfwupdplugin/fu-coswid-common.h
new file mode 100644
index 0000000000000000000000000000000000000000..7906ce20ca31ab303ba49477e719f8d2843fa3ca
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-coswid-common.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+typedef enum {
+ FU_COSWID_TAG_TAG_ID,
+ FU_COSWID_TAG_SOFTWARE_NAME,
+ FU_COSWID_TAG_ENTITY,
+ FU_COSWID_TAG_EVIDENCE,
+ FU_COSWID_TAG_LINK,
+ FU_COSWID_TAG_SOFTWARE_META,
+ FU_COSWID_TAG_PAYLOAD,
+ FU_COSWID_TAG_HASH,
+ FU_COSWID_TAG_CORPUS,
+ FU_COSWID_TAG_PATCH,
+ FU_COSWID_TAG_MEDIA,
+ FU_COSWID_TAG_SUPPLEMENTAL,
+ FU_COSWID_TAG_TAG_VERSION,
+ FU_COSWID_TAG_SOFTWARE_VERSION,
+ FU_COSWID_TAG_VERSION_SCHEME,
+ FU_COSWID_TAG_LANG,
+ FU_COSWID_TAG_DIRECTORY,
+ FU_COSWID_TAG_FILE,
+ FU_COSWID_TAG_PROCESS,
+ FU_COSWID_TAG_RESOURCE,
+ FU_COSWID_TAG_SIZE,
+ FU_COSWID_TAG_FILE_VERSION,
+ FU_COSWID_TAG_KEY,
+ FU_COSWID_TAG_LOCATION,
+ FU_COSWID_TAG_FS_NAME,
+ FU_COSWID_TAG_ROOT,
+ FU_COSWID_TAG_PATH_ELEMENTS,
+ FU_COSWID_TAG_PROCESS_NAME,
+ FU_COSWID_TAG_PID,
+ FU_COSWID_TAG_TYPE,
+ FU_COSWID_TAG_MISSING30, /* not in the spec! */
+ FU_COSWID_TAG_ENTITY_NAME,
+ FU_COSWID_TAG_REG_ID,
+ FU_COSWID_TAG_ROLE,
+ FU_COSWID_TAG_THUMBPRINT,
+ FU_COSWID_TAG_DATE,
+ FU_COSWID_TAG_DEVICE_ID,
+ FU_COSWID_TAG_ARTIFACT,
+ FU_COSWID_TAG_HREF,
+ FU_COSWID_TAG_OWNERSHIP,
+ FU_COSWID_TAG_REL,
+ FU_COSWID_TAG_MEDIA_TYPE,
+ FU_COSWID_TAG_USE,
+ FU_COSWID_TAG_ACTIVATION_STATUS,
+ FU_COSWID_TAG_CHANNEL_TYPE,
+ FU_COSWID_TAG_COLLOQUIAL_VERSION,
+ FU_COSWID_TAG_DESCRIPTION,
+ FU_COSWID_TAG_EDITION,
+ FU_COSWID_TAG_ENTITLEMENT_DATA_REQUIRED,
+ FU_COSWID_TAG_ENTITLEMENT_KEY,
+ FU_COSWID_TAG_GENERATOR,
+ FU_COSWID_TAG_PERSISTENT_ID,
+ FU_COSWID_TAG_PRODUCT,
+ FU_COSWID_TAG_PRODUCT_FAMILY,
+ FU_COSWID_TAG_REVISION,
+ FU_COSWID_TAG_SUMMARY,
+ FU_COSWID_TAG_UNSPSC_CODE,
+ FU_COSWID_TAG_UNSPSC_VERSION,
+} FuCoswidTag;
+
+typedef enum {
+ FU_COSWID_VERSION_SCHEME_UNKNOWN,
+ FU_COSWID_VERSION_SCHEME_MULTIPARTNUMERIC,
+ FU_COSWID_VERSION_SCHEME_MULTIPARTNUMERIC_SUFFIX,
+ FU_COSWID_VERSION_SCHEME_ALPHANUMERIC,
+ FU_COSWID_VERSION_SCHEME_DECIMAL,
+ FU_COSWID_VERSION_SCHEME_SEMVER = 16384,
+} FuCoswidVersionScheme;
+
+typedef enum {
+ FU_COSWID_LINK_REL_LICENSE = -2,
+ FU_COSWID_LINK_REL_COMPILER = -1,
+ FU_COSWID_LINK_REL_UNKNOWN = 0,
+ FU_COSWID_LINK_REL_ANCESTOR = 1,
+ FU_COSWID_LINK_REL_COMPONENT = 2,
+ FU_COSWID_LINK_REL_FEATURE = 3,
+ FU_COSWID_LINK_REL_INSTALLATIONMEDIA = 4,
+ FU_COSWID_LINK_REL_PACKAGEINSTALLER = 5,
+ FU_COSWID_LINK_REL_PARENT = 6,
+ FU_COSWID_LINK_REL_PATCHES = 7,
+ FU_COSWID_LINK_REL_REQUIRES = 8,
+ FU_COSWID_LINK_REL_SEE_ALSO = 9,
+ FU_COSWID_LINK_REL_SUPERSEDES = 10,
+ FU_COSWID_LINK_REL_SUPPLEMENTAL = 11,
+} FuCoswidLinkRel;
+
+typedef enum {
+ FU_COSWID_ENTITY_ROLE_UNKNOWN,
+ FU_COSWID_ENTITY_ROLE_TAG_CREATOR,
+ FU_COSWID_ENTITY_ROLE_SOFTWARE_CREATOR,
+ FU_COSWID_ENTITY_ROLE_AGGREGATOR,
+ FU_COSWID_ENTITY_ROLE_DISTRIBUTOR,
+ FU_COSWID_ENTITY_ROLE_LICENSOR,
+ FU_COSWID_ENTITY_ROLE_MAINTAINER,
+} FuCoswidEntityRole;
+
+FuCoswidEntityRole
+fu_coswid_entity_role_from_string(const gchar *val);
+const gchar *
+fu_coswid_entity_role_to_string(FuCoswidEntityRole val);
+FuCoswidLinkRel
+fu_coswid_link_rel_from_string(const gchar *val);
+const gchar *
+fu_coswid_link_rel_to_string(FuCoswidLinkRel val);
+FuCoswidVersionScheme
+fu_coswid_version_scheme_from_string(const gchar *val);
+const gchar *
+fu_coswid_version_scheme_to_string(FuCoswidVersionScheme val);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-coswid-firmware.c b/fwupd-1.8.6/libfwupdplugin/fu-coswid-firmware.c
new file mode 100644
index 0000000000000000000000000000000000000000..87fa75970ffd080e21e927956d298e7aaedac3c0
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-coswid-firmware.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuFirmware"
+
+#include "config.h"
+
+#ifdef HAVE_CBOR
+#include
+#endif
+
+#include "fu-common.h"
+#include "fu-coswid-common.h"
+#include "fu-coswid-firmware.h"
+
+/**
+ * FuCoswidFirmware:
+ *
+ * A coSWID SWID section.
+ *
+ * See also: [class@FuCoswidFirmware]
+ */
+
+typedef struct {
+ gchar *product;
+ gchar *summary;
+ gchar *colloquial_version;
+ FuCoswidVersionScheme version_scheme;
+ GPtrArray *links; /* of FuCoswidFirmwareLink */
+ GPtrArray *entities; /* of FuCoswidFirmwareEntity */
+} FuCoswidFirmwarePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuCoswidFirmware, fu_coswid_firmware, FU_TYPE_FIRMWARE)
+#define GET_PRIVATE(o) (fu_coswid_firmware_get_instance_private(o))
+
+typedef struct {
+ gchar *name;
+ gchar *regid;
+ FuCoswidEntityRole roles[6];
+} FuCoswidFirmwareEntity;
+
+typedef struct {
+ gchar *href;
+ FuCoswidLinkRel rel;
+} FuCoswidFirmwareLink;
+
+static void
+fu_coswid_firmware_entity_free(FuCoswidFirmwareEntity *entity)
+{
+ g_free(entity->name);
+ g_free(entity->regid);
+ g_free(entity);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCoswidFirmwareEntity, fu_coswid_firmware_entity_free)
+
+static void
+fu_coswid_firmware_link_free(FuCoswidFirmwareLink *link)
+{
+ g_free(link->href);
+ g_free(link);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCoswidFirmwareLink, fu_coswid_firmware_link_free)
+
+#ifdef HAVE_CBOR
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(cbor_item_t, cbor_intermediate_decref)
+
+static gchar *
+fu_coswid_firmware_strndup(cbor_item_t *item)
+{
+ if (!cbor_string_is_definite(item))
+ return NULL;
+ return g_strndup((const gchar *)cbor_string_handle(item), cbor_string_length(item));
+}
+
+static gboolean
+fu_coswid_firmware_parse_meta(FuCoswidFirmware *self, cbor_item_t *item, GError **error)
+{
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ struct cbor_pair *pairs = cbor_map_handle(item);
+
+ for (gsize i = 0; i < cbor_map_size(item); i++) {
+ FuCoswidTag tag_id = cbor_get_uint8(pairs[i].key);
+ if (tag_id == FU_COSWID_TAG_SUMMARY) {
+ priv->summary = fu_coswid_firmware_strndup(pairs[i].value);
+ } else if (tag_id == FU_COSWID_TAG_COLLOQUIAL_VERSION) {
+ priv->colloquial_version = fu_coswid_firmware_strndup(pairs[i].value);
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static gboolean
+fu_coswid_firmware_parse_link(FuCoswidFirmware *self, cbor_item_t *item, GError **error)
+{
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ struct cbor_pair *pairs = cbor_map_handle(item);
+ g_autoptr(FuCoswidFirmwareLink) link = g_new0(FuCoswidFirmwareLink, 1);
+
+ for (gsize i = 0; i < cbor_map_size(item); i++) {
+ FuCoswidTag tag_id = cbor_get_uint8(pairs[i].key);
+ if (tag_id == FU_COSWID_TAG_HREF) {
+ link->href = fu_coswid_firmware_strndup(pairs[i].value);
+ } else if (tag_id == FU_COSWID_TAG_REL) {
+ if (cbor_isa_negint(pairs[i].value))
+ link->rel = (-1) - cbor_get_uint8(pairs[i].value);
+ else
+ link->rel = cbor_get_uint8(pairs[i].value);
+ }
+ }
+
+ /* success */
+ g_ptr_array_add(priv->links, g_steal_pointer(&link));
+ return TRUE;
+}
+
+static gboolean
+fu_coswid_firmware_parse_entity(FuCoswidFirmware *self, cbor_item_t *item, GError **error)
+{
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ struct cbor_pair *pairs = cbor_map_handle(item);
+ guint entity_role_cnt = 0;
+ g_autoptr(FuCoswidFirmwareEntity) entity = g_new0(FuCoswidFirmwareEntity, 1);
+
+ for (gsize i = 0; i < cbor_map_size(item); i++) {
+ FuCoswidTag tag_id = cbor_get_uint8(pairs[i].key);
+ if (tag_id == FU_COSWID_TAG_ENTITY_NAME) {
+ entity->name = fu_coswid_firmware_strndup(pairs[i].value);
+ } else if (tag_id == FU_COSWID_TAG_REG_ID) {
+ entity->regid = fu_coswid_firmware_strndup(pairs[i].value);
+ } else if (tag_id == FU_COSWID_TAG_ROLE) {
+ for (guint j = 0; j < cbor_array_size(pairs[i].value); j++) {
+ g_autoptr(cbor_item_t) value = cbor_array_get(pairs[i].value, j);
+ FuCoswidEntityRole role = cbor_get_uint8(value);
+ if (entity_role_cnt >= G_N_ELEMENTS(entity->roles)) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "too many roles");
+ return FALSE;
+ }
+ entity->roles[entity_role_cnt++] = role;
+ }
+ }
+ }
+
+ /* success */
+ g_ptr_array_add(priv->entities, g_steal_pointer(&entity));
+ return TRUE;
+}
+#endif
+
+static gboolean
+fu_coswid_firmware_parse(FuFirmware *firmware,
+ GBytes *fw,
+ gsize offset,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+#ifdef HAVE_CBOR
+ FuCoswidFirmware *self = FU_COSWID_FIRMWARE(firmware);
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ struct cbor_load_result result = {0x0};
+ struct cbor_pair *pairs = NULL;
+ g_autoptr(cbor_item_t) item = NULL;
+
+ item = cbor_load(g_bytes_get_data(fw, NULL), g_bytes_get_size(fw), &result);
+ if (item == NULL) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "failed to parse CBOR at offset 0x%x: 0x%x",
+ (guint)result.error.position,
+ result.error.code);
+ return FALSE;
+ }
+ fu_firmware_set_size(firmware, result.read);
+
+ /* pretty-print the result */
+ if (g_getenv("FWUPD_CBOR_VERBOSE") != NULL) {
+ cbor_describe(item, stdout);
+ fflush(stdout);
+ }
+
+ /* parse out anything interesting */
+ pairs = cbor_map_handle(item);
+ for (gsize i = 0; i < cbor_map_size(item); i++) {
+ FuCoswidTag tag_id = cbor_get_uint8(pairs[i].key);
+
+ /* identity can be specified as a string or in binary */
+ if (tag_id == FU_COSWID_TAG_TAG_ID) {
+ g_autofree gchar *str = NULL;
+ if (cbor_isa_string(pairs[i].value)) {
+ str = fu_coswid_firmware_strndup(pairs[i].value);
+ } else if (cbor_isa_bytestring(pairs[i].value) &&
+ cbor_bytestring_length(pairs[i].value) == 16) {
+ str = fwupd_guid_to_string(
+ (const fwupd_guid_t *)cbor_bytestring_handle(pairs[i].value),
+ FWUPD_GUID_FLAG_NONE);
+ }
+ if (str != NULL)
+ fu_firmware_set_id(firmware, str);
+ } else if (tag_id == FU_COSWID_TAG_SOFTWARE_NAME) {
+ priv->product = fu_coswid_firmware_strndup(pairs[i].value);
+ } else if (tag_id == FU_COSWID_TAG_SOFTWARE_VERSION) {
+ g_autofree gchar *str = fu_coswid_firmware_strndup(pairs[i].value);
+ fu_firmware_set_version(firmware, str);
+ } else if (tag_id == FU_COSWID_TAG_VERSION_SCHEME) {
+ priv->version_scheme = cbor_get_uint16(pairs[i].value);
+ } else if (tag_id == FU_COSWID_TAG_SOFTWARE_META) {
+ if (!fu_coswid_firmware_parse_meta(self, pairs[i].value, error))
+ return FALSE;
+ } else if (tag_id == FU_COSWID_TAG_LINK) {
+ for (guint j = 0; j < cbor_array_size(pairs[i].value); j++) {
+ g_autoptr(cbor_item_t) value = cbor_array_get(pairs[i].value, j);
+ if (!fu_coswid_firmware_parse_link(self, value, error))
+ return FALSE;
+ }
+ } else if (tag_id == FU_COSWID_TAG_ENTITY) {
+ for (guint j = 0; j < cbor_array_size(pairs[i].value); j++) {
+ g_autoptr(cbor_item_t) value = cbor_array_get(pairs[i].value, j);
+ if (!fu_coswid_firmware_parse_entity(self, value, error))
+ return FALSE;
+ }
+ }
+ }
+
+ /* success */
+ return TRUE;
+#else
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "not compiled with CBOR support");
+ return FALSE;
+#endif
+}
+
+#ifdef HAVE_CBOR
+static void
+fu_coswid_firmware_write_tag_string(cbor_item_t *root, FuCoswidTag tag, const gchar *item)
+{
+ g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
+ g_autoptr(cbor_item_t) val = cbor_build_string(item);
+ cbor_map_add(root, (struct cbor_pair){.key = key, .value = val});
+}
+
+static void
+fu_coswid_firmware_write_tag_bool(cbor_item_t *root, FuCoswidTag tag, gboolean item)
+{
+ g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
+ g_autoptr(cbor_item_t) val = cbor_build_bool(item);
+ cbor_map_add(root, (struct cbor_pair){.key = key, .value = val});
+}
+
+static void
+fu_coswid_firmware_write_tag_uint16(cbor_item_t *root, FuCoswidTag tag, guint16 item)
+{
+ g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
+ g_autoptr(cbor_item_t) val = cbor_build_uint16(item);
+ cbor_map_add(root, (struct cbor_pair){.key = key, .value = val});
+}
+
+static void
+fu_coswid_firmware_write_tag_int8(cbor_item_t *root, FuCoswidTag tag, gint8 item)
+{
+ g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
+ g_autoptr(cbor_item_t) val = cbor_new_int8();
+ if (item >= 0) {
+ cbor_set_uint8(val, item);
+ } else {
+ cbor_set_uint8(val, 0xFF - item);
+ cbor_mark_negint(val);
+ }
+ cbor_map_add(root, (struct cbor_pair){.key = key, .value = val});
+}
+
+static void
+fu_coswid_firmware_write_tag_item(cbor_item_t *root, FuCoswidTag tag, cbor_item_t *item)
+{
+ g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
+ cbor_map_add(root, (struct cbor_pair){.key = key, .value = item});
+}
+#endif
+
+static GBytes *
+fu_coswid_firmware_write(FuFirmware *firmware, GError **error)
+{
+#ifdef HAVE_CBOR
+ FuCoswidFirmware *self = FU_COSWID_FIRMWARE(firmware);
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ gsize buflen;
+ gsize bufsz = 0;
+ g_autofree guchar *buf = NULL;
+ g_autoptr(cbor_item_t) root = cbor_new_indefinite_map();
+ g_autoptr(cbor_item_t) item_meta = cbor_new_indefinite_map();
+
+ /* preallocate the map structure */
+ fu_coswid_firmware_write_tag_string(root, FU_COSWID_TAG_LANG, "en-US");
+ if (fu_firmware_get_id(firmware) != NULL) {
+ fu_coswid_firmware_write_tag_string(root,
+ FU_COSWID_TAG_TAG_ID,
+ fu_firmware_get_id(firmware));
+ }
+ fu_coswid_firmware_write_tag_bool(root, FU_COSWID_TAG_CORPUS, TRUE);
+ if (priv->product != NULL) {
+ fu_coswid_firmware_write_tag_string(root,
+ FU_COSWID_TAG_SOFTWARE_NAME,
+ priv->product);
+ }
+ if (fu_firmware_get_version(firmware) != NULL) {
+ fu_coswid_firmware_write_tag_string(root,
+ FU_COSWID_TAG_SOFTWARE_VERSION,
+ fu_firmware_get_version(firmware));
+ }
+ if (priv->version_scheme != FU_COSWID_VERSION_SCHEME_UNKNOWN) {
+ fu_coswid_firmware_write_tag_uint16(root,
+ FU_COSWID_TAG_VERSION_SCHEME,
+ priv->version_scheme);
+ }
+ fu_coswid_firmware_write_tag_item(root, FU_COSWID_TAG_SOFTWARE_META, item_meta);
+ fu_coswid_firmware_write_tag_string(item_meta, FU_COSWID_TAG_GENERATOR, PACKAGE_NAME);
+ if (priv->summary != NULL) {
+ fu_coswid_firmware_write_tag_string(item_meta,
+ FU_COSWID_TAG_SUMMARY,
+ priv->summary);
+ }
+ if (priv->colloquial_version != NULL) {
+ fu_coswid_firmware_write_tag_string(item_meta,
+ FU_COSWID_TAG_COLLOQUIAL_VERSION,
+ priv->colloquial_version);
+ }
+
+ /* add entities */
+ if (priv->entities->len > 0) {
+ g_autoptr(cbor_item_t) item_entities = cbor_new_indefinite_array();
+ for (guint i = 0; i < priv->entities->len; i++) {
+ FuCoswidFirmwareEntity *entity = g_ptr_array_index(priv->entities, i);
+ g_autoptr(cbor_item_t) item_entity = cbor_new_indefinite_map();
+ g_autoptr(cbor_item_t) item_roles = cbor_new_indefinite_array();
+ if (entity->name != NULL) {
+ fu_coswid_firmware_write_tag_string(item_entity,
+ FU_COSWID_TAG_ENTITY_NAME,
+ entity->name);
+ }
+ if (entity->regid != NULL) {
+ fu_coswid_firmware_write_tag_string(item_entity,
+ FU_COSWID_TAG_REG_ID,
+ entity->regid);
+ }
+ for (guint j = 0; entity->roles[j] != FU_COSWID_ENTITY_ROLE_UNKNOWN; j++) {
+ g_autoptr(cbor_item_t) item_role =
+ cbor_build_uint8(entity->roles[j]);
+ cbor_array_push(item_roles, item_role);
+ }
+ fu_coswid_firmware_write_tag_item(item_entity,
+ FU_COSWID_TAG_ROLE,
+ item_roles);
+ cbor_array_push(item_entities, item_entity);
+ }
+ fu_coswid_firmware_write_tag_item(root, FU_COSWID_TAG_ENTITY, item_entities);
+ }
+
+ /* add links */
+ if (priv->links->len > 0) {
+ g_autoptr(cbor_item_t) item_links = cbor_new_indefinite_array();
+ for (guint i = 0; i < priv->links->len; i++) {
+ FuCoswidFirmwareLink *link = g_ptr_array_index(priv->links, i);
+ g_autoptr(cbor_item_t) item_link = cbor_new_indefinite_map();
+ if (link->href != NULL) {
+ fu_coswid_firmware_write_tag_string(item_link,
+ FU_COSWID_TAG_HREF,
+ link->href);
+ }
+ fu_coswid_firmware_write_tag_int8(item_link, FU_COSWID_TAG_REL, link->rel);
+ cbor_array_push(item_links, item_link);
+ }
+ fu_coswid_firmware_write_tag_item(root, FU_COSWID_TAG_LINK, item_links);
+ }
+
+ /* serialize */
+ buflen = cbor_serialize_alloc(root, &buf, &bufsz);
+ if (buflen > bufsz) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "CBOR allocation failure");
+ return NULL;
+ }
+ return g_bytes_new(buf, buflen);
+#else
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "not compiled with CBOR support");
+ return NULL;
+#endif
+}
+
+static gboolean
+fu_coswid_firmware_build_entity(FuCoswidFirmware *self, XbNode *n, GError **error)
+{
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ const gchar *tmp;
+ guint entity_role_cnt = 0;
+ FuCoswidEntityRole role;
+ g_autoptr(GPtrArray) roles = NULL;
+ g_autoptr(FuCoswidFirmwareEntity) entity = g_new0(FuCoswidFirmwareEntity, 1);
+
+ /* these are required */
+ tmp = xb_node_query_text(n, "name", error);
+ if (tmp == NULL)
+ return FALSE;
+ entity->name = g_strdup(tmp);
+ tmp = xb_node_query_text(n, "regid", error);
+ if (tmp == NULL)
+ return FALSE;
+ entity->regid = g_strdup(tmp);
+
+ /* optional */
+ roles = xb_node_query(n, "role", 0, NULL);
+ if (roles != NULL) {
+ for (guint i = 0; i < roles->len; i++) {
+ XbNode *c = g_ptr_array_index(roles, i);
+ tmp = xb_node_get_text(c);
+ role = fu_coswid_entity_role_from_string(tmp);
+ if (role == FU_COSWID_ENTITY_ROLE_UNKNOWN) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "failed to parse entity role %s",
+ tmp);
+ return FALSE;
+ }
+ if (entity_role_cnt >= G_N_ELEMENTS(entity->roles)) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "too many roles");
+ return FALSE;
+ }
+ entity->roles[entity_role_cnt++] = role;
+ }
+ }
+
+ /* success */
+ g_ptr_array_add(priv->entities, g_steal_pointer(&entity));
+ return TRUE;
+}
+
+static gboolean
+fu_coswid_firmware_build_link(FuCoswidFirmware *self, XbNode *n, GError **error)
+{
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ const gchar *tmp;
+ g_autoptr(FuCoswidFirmwareLink) link = g_new0(FuCoswidFirmwareLink, 1);
+
+ /* required */
+ tmp = xb_node_query_text(n, "href", error);
+ if (tmp == NULL)
+ return FALSE;
+ link->href = g_strdup(tmp);
+
+ /* optional */
+ tmp = xb_node_query_text(n, "rel", NULL);
+ if (tmp != NULL) {
+ link->rel = fu_coswid_link_rel_from_string(tmp);
+ if (link->rel == FU_COSWID_LINK_REL_UNKNOWN) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "failed to parse link rel %s",
+ tmp);
+ return FALSE;
+ }
+ }
+
+ /* success */
+ g_ptr_array_add(priv->links, g_steal_pointer(&link));
+ return TRUE;
+}
+
+static gboolean
+fu_coswid_firmware_build(FuFirmware *firmware, XbNode *n, GError **error)
+{
+ FuCoswidFirmware *self = FU_COSWID_FIRMWARE(firmware);
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ const gchar *tmp;
+ g_autoptr(GPtrArray) links = NULL;
+ g_autoptr(GPtrArray) entities = NULL;
+
+ /* simple properties */
+ tmp = xb_node_query_text(n, "product", NULL);
+ if (tmp != NULL)
+ priv->product = g_strdup(tmp);
+ tmp = xb_node_query_text(n, "summary", NULL);
+ if (tmp != NULL)
+ priv->summary = g_strdup(tmp);
+ tmp = xb_node_query_text(n, "colloquial_version", NULL);
+ if (tmp != NULL)
+ priv->colloquial_version = g_strdup(tmp);
+
+ tmp = xb_node_query_text(n, "version_scheme", NULL);
+ if (tmp != NULL) {
+ priv->version_scheme = fu_coswid_version_scheme_from_string(tmp);
+ if (priv->version_scheme == FU_COSWID_VERSION_SCHEME_UNKNOWN) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "failed to parse version_scheme %s",
+ tmp);
+ return FALSE;
+ }
+ }
+
+ /* multiple links allowed */
+ links = xb_node_query(n, "link", 0, NULL);
+ if (links != NULL) {
+ for (guint i = 0; i < links->len; i++) {
+ XbNode *c = g_ptr_array_index(links, i);
+ if (!fu_coswid_firmware_build_link(self, c, error))
+ return FALSE;
+ }
+ }
+
+ /* multiple entities allowed */
+ entities = xb_node_query(n, "entity", 0, NULL);
+ if (entities != NULL) {
+ for (guint i = 0; i < entities->len; i++) {
+ XbNode *c = g_ptr_array_index(entities, i);
+ if (!fu_coswid_firmware_build_entity(self, c, error))
+ return FALSE;
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fu_coswid_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
+{
+ FuCoswidFirmware *self = FU_COSWID_FIRMWARE(firmware);
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ if (priv->version_scheme != FU_COSWID_VERSION_SCHEME_UNKNOWN) {
+ fu_xmlb_builder_insert_kv(bn,
+ "version_scheme",
+ fu_coswid_version_scheme_to_string(priv->version_scheme));
+ }
+ fu_xmlb_builder_insert_kv(bn, "product", priv->product);
+ fu_xmlb_builder_insert_kv(bn, "summary", priv->summary);
+ fu_xmlb_builder_insert_kv(bn, "colloquial_version", priv->colloquial_version);
+ for (guint i = 0; i < priv->links->len; i++) {
+ FuCoswidFirmwareLink *link = g_ptr_array_index(priv->links, i);
+ g_autoptr(XbBuilderNode) bc = xb_builder_node_insert(bn, "link", NULL);
+ fu_xmlb_builder_insert_kv(bc, "href", link->href);
+ if (link->rel != FU_COSWID_LINK_REL_UNKNOWN) {
+ fu_xmlb_builder_insert_kv(bc,
+ "rel",
+ fu_coswid_link_rel_to_string(link->rel));
+ }
+ }
+ for (guint i = 0; i < priv->entities->len; i++) {
+ FuCoswidFirmwareEntity *entity = g_ptr_array_index(priv->entities, i);
+ g_autoptr(XbBuilderNode) bc = xb_builder_node_insert(bn, "entity", NULL);
+ fu_xmlb_builder_insert_kv(bc, "name", entity->name);
+ fu_xmlb_builder_insert_kv(bc, "regid", entity->regid);
+ for (guint j = 0; entity->roles[j] != FU_COSWID_ENTITY_ROLE_UNKNOWN; j++) {
+ fu_xmlb_builder_insert_kv(
+ bc,
+ "role",
+ fu_coswid_entity_role_to_string(entity->roles[j]));
+ }
+ }
+}
+
+static void
+fu_coswid_firmware_init(FuCoswidFirmware *self)
+{
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+ priv->version_scheme = FU_COSWID_VERSION_SCHEME_SEMVER;
+ priv->links = g_ptr_array_new_with_free_func((GDestroyNotify)fu_coswid_firmware_link_free);
+ priv->entities =
+ g_ptr_array_new_with_free_func((GDestroyNotify)fu_coswid_firmware_entity_free);
+}
+
+static void
+fu_coswid_firmware_finalize(GObject *object)
+{
+ FuCoswidFirmware *self = FU_COSWID_FIRMWARE(object);
+ FuCoswidFirmwarePrivate *priv = GET_PRIVATE(self);
+
+ g_free(priv->product);
+ g_free(priv->summary);
+ g_free(priv->colloquial_version);
+ g_ptr_array_unref(priv->links);
+ g_ptr_array_unref(priv->entities);
+
+ G_OBJECT_CLASS(fu_coswid_firmware_parent_class)->finalize(object);
+}
+
+static void
+fu_coswid_firmware_class_init(FuCoswidFirmwareClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
+ object_class->finalize = fu_coswid_firmware_finalize;
+ klass_firmware->parse = fu_coswid_firmware_parse;
+ klass_firmware->write = fu_coswid_firmware_write;
+ klass_firmware->build = fu_coswid_firmware_build;
+ klass_firmware->export = fu_coswid_firmware_export;
+}
+
+/**
+ * fu_coswid_firmware_new:
+ *
+ * Creates a new #FuFirmware of sub type coSWID
+ *
+ * Since: 1.8.0
+ **/
+FuFirmware *
+fu_coswid_firmware_new(void)
+{
+ return FU_FIRMWARE(g_object_new(FU_TYPE_COSWID_FIRMWARE, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-coswid-firmware.h b/fwupd-1.8.6/libfwupdplugin/fu-coswid-firmware.h
new file mode 100644
index 0000000000000000000000000000000000000000..fc64f0b0bcaf9b54915cc294cb6108aaf44fd085
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-coswid-firmware.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-firmware.h"
+
+#define FU_TYPE_COSWID_FIRMWARE (fu_coswid_firmware_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuCoswidFirmware, fu_coswid_firmware, FU, COSWID_FIRMWARE, FuFirmware)
+
+struct _FuCoswidFirmwareClass {
+ FuFirmwareClass parent_class;
+};
+
+FuFirmware *
+fu_coswid_firmware_new(void);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-crc.c b/fwupd-1.8.6/libfwupdplugin/fu-crc.c
new file mode 100644
index 0000000000000000000000000000000000000000..9502b1d18012eaba4f50652fd39659d2a74c9961
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-crc.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include "fu-crc.h"
+
+/**
+ * fu_crc8_full:
+ * @buf: memory buffer
+ * @bufsz: size of @buf
+ * @crc_init: initial CRC value, typically 0x00
+ * @polynomial: CRC polynomial, e.g. 0x07 for CCITT
+ *
+ * Returns the cyclic redundancy check value for the given memory buffer.
+ *
+ * Returns: CRC value
+ *
+ * Since: 1.8.2
+ **/
+guint8
+fu_crc8_full(const guint8 *buf, gsize bufsz, guint8 crc_init, guint8 polynomial)
+{
+ guint32 crc = crc_init;
+ for (gsize j = bufsz; j > 0; j--) {
+ crc ^= (*(buf++) << 8);
+ for (guint32 i = 8; i; i--) {
+ if (crc & 0x8000)
+ crc ^= ((polynomial | 0x100) << 7);
+ crc <<= 1;
+ }
+ }
+ return ~((guint8)(crc >> 8));
+}
+
+/**
+ * fu_crc8:
+ * @buf: memory buffer
+ * @bufsz: size of @buf
+ *
+ * Returns the cyclic redundancy check value for the given memory buffer.
+ *
+ * Returns: CRC value
+ *
+ * Since: 1.8.2
+ **/
+guint8
+fu_crc8(const guint8 *buf, gsize bufsz)
+{
+ return fu_crc8_full(buf, bufsz, 0x00, 0x07);
+}
+
+/**
+ * fu_crc16_full:
+ * @buf: memory buffer
+ * @bufsz: size of @buf
+ * @crc: initial CRC value, typically 0xFFFF
+ * @polynomial: CRC polynomial, typically 0xA001 for IBM or 0x1021 for CCITT
+ *
+ * Returns the cyclic redundancy check value for the given memory buffer.
+ *
+ * Returns: CRC value
+ *
+ * Since: 1.8.2
+ **/
+guint16
+fu_crc16_full(const guint8 *buf, gsize bufsz, guint16 crc, guint16 polynomial)
+{
+ for (gsize len = bufsz; len > 0; len--) {
+ crc = (guint16)(crc ^ (*buf++));
+ for (guint8 i = 0; i < 8; i++) {
+ if (crc & 0x1) {
+ crc = (crc >> 1) ^ polynomial;
+ } else {
+ crc >>= 1;
+ }
+ }
+ }
+ return ~crc;
+}
+
+/**
+ * fu_crc16:
+ * @buf: memory buffer
+ * @bufsz: size of @buf
+ *
+ * Returns the CRC-16-IBM cyclic redundancy value for the given memory buffer.
+ *
+ * Returns: CRC value
+ *
+ * Since: 1.8.2
+ **/
+guint16
+fu_crc16(const guint8 *buf, gsize bufsz)
+{
+ return fu_crc16_full(buf, bufsz, 0xFFFF, 0xA001);
+}
+
+/**
+ * fu_crc32_full:
+ * @buf: memory buffer
+ * @bufsz: size of @buf
+ * @crc: initial CRC value, typically 0xFFFFFFFF
+ * @polynomial: CRC polynomial, typically 0xEDB88320
+ *
+ * Returns the cyclic redundancy check value for the given memory buffer.
+ *
+ * Returns: CRC value
+ *
+ * Since: 1.8.2
+ **/
+guint32
+fu_crc32_full(const guint8 *buf, gsize bufsz, guint32 crc, guint32 polynomial)
+{
+ for (guint32 idx = 0; idx < bufsz; idx++) {
+ guint8 data = *buf++;
+ crc = crc ^ data;
+ for (guint32 bit = 0; bit < 8; bit++) {
+ guint32 mask = -(crc & 1);
+ crc = (crc >> 1) ^ (polynomial & mask);
+ }
+ }
+ return ~crc;
+}
+
+/**
+ * fu_crc32:
+ * @buf: memory buffer
+ * @bufsz: size of @buf
+ *
+ * Returns the cyclic redundancy check value for the given memory buffer.
+ *
+ * Returns: CRC value
+ *
+ * Since: 1.8.2
+ **/
+guint32
+fu_crc32(const guint8 *buf, gsize bufsz)
+{
+ return fu_crc32_full(buf, bufsz, 0xFFFFFFFF, 0xEDB88320);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-crc.h b/fwupd-1.8.6/libfwupdplugin/fu-crc.h
new file mode 100644
index 0000000000000000000000000000000000000000..49cdb6e4044a71c91c7f4fd8adc627bf85de73d5
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-crc.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-common.h"
+
+guint8
+fu_crc8(const guint8 *buf, gsize bufsz);
+guint8
+fu_crc8_full(const guint8 *buf, gsize bufsz, guint8 crc_init, guint8 polynomial);
+guint16
+fu_crc16(const guint8 *buf, gsize bufsz);
+guint16
+fu_crc16_full(const guint8 *buf, gsize bufsz, guint16 crc, guint16 polynomial);
+guint32
+fu_crc32(const guint8 *buf, gsize bufsz);
+guint32
+fu_crc32_full(const guint8 *buf, gsize bufsz, guint32 crc, guint32 polynomial);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-deprecated.h b/fwupd-1.8.6/libfwupdplugin/fu-deprecated.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3671517a3f4125927ea8d6644c498e100b5067b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-deprecated.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+G_BEGIN_DECLS
+
+/* indeed, nothing */
+
+G_END_DECLS
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-device-locker.c b/fwupd-1.8.6/libfwupdplugin/fu-device-locker.c
new file mode 100644
index 0000000000000000000000000000000000000000..d53ed34ebca42a5f5eb8b28231c0781e9e86181d
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-device-locker.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuDeviceLocker"
+
+#include "config.h"
+
+#include
+#ifdef HAVE_GUSB
+#include
+#endif
+
+#include "fu-device-locker.h"
+#include "fu-usb-device.h"
+
+/**
+ * FuDeviceLocker:
+ *
+ * Easily close a shared resource (such as a device) when an object goes out of
+ * scope.
+ *
+ * See also: [class@FuDevice]
+ */
+
+struct _FuDeviceLocker {
+ GObject parent_instance;
+ GObject *device;
+ gboolean device_open;
+ FuDeviceLockerFunc open_func;
+ FuDeviceLockerFunc close_func;
+};
+
+G_DEFINE_TYPE(FuDeviceLocker, fu_device_locker, G_TYPE_OBJECT)
+
+static void
+fu_device_locker_finalize(GObject *obj)
+{
+ FuDeviceLocker *self = FU_DEVICE_LOCKER(obj);
+
+ /* close device */
+ if (self->device_open) {
+ g_autoptr(GError) error = NULL;
+ if (!self->close_func(self->device, &error))
+ g_warning("failed to close device: %s", error->message);
+ }
+ if (self->device != NULL)
+ g_object_unref(self->device);
+ G_OBJECT_CLASS(fu_device_locker_parent_class)->finalize(obj);
+}
+
+static void
+fu_device_locker_class_init(FuDeviceLockerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = fu_device_locker_finalize;
+}
+
+static void
+fu_device_locker_init(FuDeviceLocker *self)
+{
+}
+
+/**
+ * fu_device_locker_close:
+ * @self: a #FuDeviceLocker
+ * @error: (nullable): optional return location for an error
+ *
+ * Closes the locker before it gets cleaned up.
+ *
+ * This function can be used to manually close a device managed by a locker,
+ * and allows the caller to properly handle the error.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.4.0
+ **/
+gboolean
+fu_device_locker_close(FuDeviceLocker *self, GError **error)
+{
+ g_autoptr(GError) error_local = NULL;
+ g_return_val_if_fail(FU_IS_DEVICE_LOCKER(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+ if (!self->device_open)
+ return TRUE;
+ if (!self->close_func(self->device, &error_local)) {
+#ifdef HAVE_GUSB
+ if (g_error_matches(error_local,
+ G_USB_DEVICE_ERROR,
+ G_USB_DEVICE_ERROR_NO_DEVICE)) {
+ g_debug("ignoring: %s", error_local->message);
+ return TRUE;
+ } else {
+ g_propagate_error(error, g_steal_pointer(&error_local));
+ return FALSE;
+ }
+#else
+ g_propagate_error(error, g_steal_pointer(&error_local));
+ return FALSE;
+#endif
+ }
+ self->device_open = FALSE;
+ return TRUE;
+}
+
+/**
+ * fu_device_locker_new:
+ * @device: a #GObject
+ * @error: (nullable): optional return location for an error
+ *
+ * Opens the device for use. When the #FuDeviceLocker is deallocated the device
+ * will be closed and any error will just be directed to the console.
+ * This object is typically called using g_autoptr() but the device can also be
+ * 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 #FuDevice then
+ * this function will not work.
+ *
+ * For custom objects please use fu_device_locker_new_full().
+ *
+ * NOTE: If the @open_func failed then the @close_func will not be called.
+ *
+ * Think of this object as the device ownership.
+ *
+ * Returns: a device locker, or %NULL if the @open_func failed.
+ *
+ * Since: 1.0.0
+ **/
+FuDeviceLocker *
+fu_device_locker_new(gpointer device, GError **error)
+{
+ g_return_val_if_fail(device != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+#ifdef HAVE_GUSB
+ /* GUsbDevice */
+ if (G_USB_IS_DEVICE(device)) {
+ return fu_device_locker_new_full(device,
+ (FuDeviceLockerFunc)g_usb_device_open,
+ (FuDeviceLockerFunc)g_usb_device_close,
+ error);
+ }
+#endif
+
+ /* FuDevice */
+ if (FU_IS_DEVICE(device)) {
+ return fu_device_locker_new_full(device,
+ (FuDeviceLockerFunc)fu_device_open,
+ (FuDeviceLockerFunc)fu_device_close,
+ error);
+ }
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "device object type not supported");
+ return NULL;
+}
+
+/**
+ * fu_device_locker_new_full:
+ * @device: a #GObject
+ * @open_func: (scope async): a function to open the device
+ * @close_func: (scope async): a function to close the device
+ * @error: (nullable): optional return location for an error
+ *
+ * Opens the device for use. When the #FuDeviceLocker is deallocated the device
+ * will be closed and any error will just be directed to the console.
+ * This object is typically called using g_autoptr() but the device can also be
+ * manually closed using g_clear_object().
+ *
+ * NOTE: If the @open_func failed then the @close_func will not be called.
+ *
+ * Think of this object as the device ownership.
+ *
+ * Returns: a device locker, or %NULL if the @open_func failed.
+ *
+ * Since: 1.0.0
+ **/
+FuDeviceLocker *
+fu_device_locker_new_full(gpointer device,
+ FuDeviceLockerFunc open_func,
+ FuDeviceLockerFunc close_func,
+ GError **error)
+{
+ g_autoptr(FuDeviceLocker) self = NULL;
+
+ g_return_val_if_fail(device != NULL, NULL);
+ g_return_val_if_fail(open_func != NULL, NULL);
+ g_return_val_if_fail(close_func != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* create object */
+ self = g_object_new(FU_TYPE_DEVICE_LOCKER, NULL);
+ self->device = g_object_ref(device);
+ self->open_func = open_func;
+ self->close_func = close_func;
+
+ /* open device */
+ if (!self->open_func(device, error)) {
+ g_autoptr(GError) error_local = NULL;
+ if (!self->close_func(device, &error_local)) {
+ if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) {
+ g_debug("ignoring close error on aborted open: %s",
+ error_local->message);
+ }
+ }
+ return NULL;
+ }
+
+ /* success */
+ self->device_open = TRUE;
+ return g_steal_pointer(&self);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-device-locker.h b/fwupd-1.8.6/libfwupdplugin/fu-device-locker.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa92534a48aa0c4409424e1baf3a64efe39ed4b1
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-device-locker.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#define FU_TYPE_DEVICE_LOCKER (fu_device_locker_get_type())
+
+G_DECLARE_FINAL_TYPE(FuDeviceLocker, fu_device_locker, FU, DEVICE_LOCKER, GObject)
+
+/**
+ * FuDeviceLockerFunc:
+ *
+ * Callback to use when opening and closing using [ctor@DeviceLocker.new_full].
+ **/
+typedef gboolean (*FuDeviceLockerFunc)(GObject *device, GError **error);
+
+FuDeviceLocker *
+fu_device_locker_new(gpointer device, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+FuDeviceLocker *
+fu_device_locker_new_full(gpointer device,
+ FuDeviceLockerFunc open_func,
+ FuDeviceLockerFunc close_func,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_locker_close(FuDeviceLocker *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-device-metadata.h b/fwupd-1.8.6/libfwupdplugin/fu-device-metadata.h
new file mode 100644
index 0000000000000000000000000000000000000000..edce705238c358a79d9eb08c479894baf1826dc6
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-device-metadata.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 Mario Limonciello
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+/**
+ * FU_DEVICE_METADATA_TBT_IS_SAFE_MODE:
+ *
+ * If the Thunderbolt hardware is stuck in safe mode.
+ * Consumed by the thunderbolt plugin.
+ */
+#define FU_DEVICE_METADATA_TBT_IS_SAFE_MODE "Thunderbolt::IsSafeMode"
+
+/**
+ * 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 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_UEFI_CAPSULE_FLAGS "UefiCapsuleFlags"
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-device-private.h b/fwupd-1.8.6/libfwupdplugin/fu-device-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c6d56ab2145b55c08aa403ffb5842d79f094d3b
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-device-private.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+#include
+
+#define fu_device_set_plugin(d, v) fwupd_device_set_plugin(FWUPD_DEVICE(d), v)
+
+const gchar *
+fu_device_internal_flag_to_string(FuDeviceInternalFlags flag);
+FuDeviceInternalFlags
+fu_device_internal_flag_from_string(const gchar *flag);
+
+GPtrArray *
+fu_device_get_parent_guids(FuDevice *self);
+gboolean
+fu_device_has_parent_guid(FuDevice *self, const gchar *guid);
+GPtrArray *
+fu_device_get_parent_physical_ids(FuDevice *self);
+gboolean
+fu_device_has_parent_physical_id(FuDevice *self, const gchar *physical_id);
+void
+fu_device_set_parent(FuDevice *self, FuDevice *parent);
+gint
+fu_device_get_order(FuDevice *self);
+void
+fu_device_set_order(FuDevice *self, gint order);
+const gchar *
+fu_device_get_update_request_id(FuDevice *self);
+void
+fu_device_set_update_request_id(FuDevice *self, const gchar *update_request_id);
+void
+fu_device_set_alternate(FuDevice *self, FuDevice *alternate);
+gboolean
+fu_device_ensure_id(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_device_incorporate_from_component(FuDevice *device, XbNode *component);
+void
+fu_device_convert_instance_ids(FuDevice *self);
+gchar *
+fu_device_get_guids_as_str(FuDevice *self);
+GPtrArray *
+fu_device_get_possible_plugins(FuDevice *self);
+void
+fu_device_add_possible_plugin(FuDevice *self, const gchar *plugin);
+guint
+fu_device_get_request_cnt(FuDevice *self, FwupdRequestKind request_kind);
+guint64
+fu_device_get_private_flags(FuDevice *self);
+void
+fu_device_set_private_flags(FuDevice *self, guint64 flag);
+void
+fu_device_set_progress(FuDevice *self, FuProgress *progress);
+FuDeviceInternalFlags
+fu_device_get_internal_flags(FuDevice *self);
+void
+fu_device_set_internal_flags(FuDevice *self, FuDeviceInternalFlags flags);
+gboolean
+fu_device_set_quirk_kv(FuDevice *self, const gchar *key, const gchar *value, GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-device.c b/fwupd-1.8.6/libfwupdplugin/fu-device.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c62d588c213c8591d0c15c8c838321892fa6be5
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-device.c
@@ -0,0 +1,5800 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuDevice"
+
+#include "config.h"
+
+#include
+#include
+
+#include "fwupd-common.h"
+#include "fwupd-device-private.h"
+
+#include "fu-common.h"
+#include "fu-device-private.h"
+#include "fu-mutex.h"
+#include "fu-quirks.h"
+#include "fu-security-attr.h"
+#include "fu-string.h"
+#include "fu-version-common.h"
+
+#define FU_DEVICE_RETRY_OPEN_COUNT 5
+#define FU_DEVICE_RETRY_OPEN_DELAY 500 /* ms */
+
+/**
+ * FuDevice:
+ *
+ * A physical or logical device that is exported to the daemon.
+ *
+ * See also: [class@FuDeviceLocker], [class@Fwupd.Device]
+ */
+
+static void
+fu_device_finalize(GObject *object);
+static void
+fu_device_inhibit_full(FuDevice *self,
+ FwupdDeviceProblem problem,
+ const gchar *inhibit_id,
+ const gchar *reason);
+
+typedef struct {
+ gchar *alternate_id;
+ gchar *equivalent_id;
+ gchar *physical_id;
+ gchar *logical_id;
+ gchar *backend_id;
+ gchar *update_request_id;
+ gchar *proxy_guid;
+ FuDevice *alternate;
+ FuDevice *proxy; /* noref */
+ FuContext *ctx;
+ GHashTable *inhibits; /* (nullable) */
+ GHashTable *metadata; /* (nullable) */
+ GRWLock metadata_mutex;
+ GPtrArray *parent_guids;
+ GRWLock parent_guids_mutex;
+ GPtrArray *parent_physical_ids; /* (nullable) */
+ guint remove_delay; /* ms */
+ guint acquiesce_delay; /* ms */
+ guint request_cnts[FWUPD_REQUEST_KIND_LAST];
+ gint order;
+ guint priority;
+ guint poll_id;
+ gint poll_locker_cnt;
+ gboolean done_probe;
+ gboolean done_setup;
+ gboolean device_id_valid;
+ guint64 size_min;
+ guint64 size_max;
+ gint open_refcount; /* atomic */
+ GType specialized_gtype;
+ GType firmware_gtype;
+ GPtrArray *possible_plugins;
+ GPtrArray *retry_recs; /* of FuDeviceRetryRecovery */
+ guint retry_delay;
+ FuDeviceInternalFlags internal_flags;
+ guint64 private_flags;
+ GPtrArray *private_flag_items; /* (nullable) */
+ gchar *custom_flags;
+ gulong notify_flags_handler_id;
+ GHashTable *instance_hash;
+ GPtrArray *backend_tags; /* of utf-8 */
+} FuDevicePrivate;
+
+typedef struct {
+ GQuark domain;
+ gint code;
+ FuDeviceRetryFunc recovery_func;
+} FuDeviceRetryRecovery;
+
+typedef struct {
+ FwupdDeviceProblem problem;
+ gchar *inhibit_id;
+ gchar *reason;
+} FuDeviceInhibit;
+
+enum {
+ PROP_0,
+ PROP_PHYSICAL_ID,
+ PROP_LOGICAL_ID,
+ PROP_BACKEND_ID,
+ PROP_CONTEXT,
+ PROP_PROXY,
+ PROP_PARENT,
+ PROP_BACKEND_TAGS,
+ PROP_LAST
+};
+
+enum { SIGNAL_CHILD_ADDED, SIGNAL_CHILD_REMOVED, SIGNAL_REQUEST, SIGNAL_LAST };
+
+static guint signals[SIGNAL_LAST] = {0};
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuDevice, fu_device, FWUPD_TYPE_DEVICE)
+#define GET_PRIVATE(o) (fu_device_get_instance_private(o))
+
+static void
+fu_device_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FuDevice *self = FU_DEVICE(object);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ switch (prop_id) {
+ case PROP_PHYSICAL_ID:
+ g_value_set_string(value, priv->physical_id);
+ break;
+ case PROP_LOGICAL_ID:
+ g_value_set_string(value, priv->logical_id);
+ break;
+ case PROP_BACKEND_ID:
+ g_value_set_string(value, priv->backend_id);
+ break;
+ case PROP_CONTEXT:
+ g_value_set_object(value, priv->ctx);
+ break;
+ case PROP_PROXY:
+ g_value_set_object(value, priv->proxy);
+ break;
+ case PROP_PARENT:
+ g_value_set_object(value, fu_device_get_parent(self));
+ break;
+ case PROP_BACKEND_TAGS:
+ g_value_set_boxed(value, priv->backend_tags);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+fu_device_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FuDevice *self = FU_DEVICE(object);
+ switch (prop_id) {
+ case PROP_PHYSICAL_ID:
+ fu_device_set_physical_id(self, g_value_get_string(value));
+ break;
+ case PROP_LOGICAL_ID:
+ fu_device_set_logical_id(self, g_value_get_string(value));
+ break;
+ case PROP_BACKEND_ID:
+ fu_device_set_backend_id(self, g_value_get_string(value));
+ break;
+ case PROP_CONTEXT:
+ fu_device_set_context(self, g_value_get_object(value));
+ break;
+ case PROP_PROXY:
+ fu_device_set_proxy(self, g_value_get_object(value));
+ break;
+ case PROP_PARENT:
+ fu_device_set_parent(self, g_value_get_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * fu_device_internal_flag_to_string:
+ * @flag: an internal device flag, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON
+ *
+ * Converts an internal device flag to a string.
+ *
+ * Returns: identifier string
+ *
+ * Since: 1.5.5
+ **/
+const gchar *
+fu_device_internal_flag_to_string(FuDeviceInternalFlags flag)
+{
+ if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON)
+ return "md-set-icon";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME)
+ return "md-set-name";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY)
+ return "md-set-name-category";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT)
+ return "md-set-verfmt";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED)
+ return "only-supported";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS)
+ return "no-auto-instance-ids";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)
+ return "ensure-semver";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN)
+ return "retry-open";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID)
+ return "replug-match-guid";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_INHERIT_ACTIVATION)
+ return "inherit-activation";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_IS_OPEN)
+ return "is-open";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_NO_SERIAL_NUMBER)
+ return "no-serial-number";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_AUTO_PARENT_CHILDREN)
+ return "auto-parent-children";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_ATTACH_EXTRA_RESET)
+ return "attach-extra-reset";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN)
+ return "inhibit-children";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE_CHILDREN)
+ return "no-auto-remove-children";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN)
+ return "use-parent-for-open";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_BATTERY)
+ return "use-parent-for-battery";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_USE_PROXY_FALLBACK)
+ return "use-proxy-fallback";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE)
+ return "no-auto-remove";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_VENDOR)
+ return "md-set-vendor";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_NO_LID_CLOSED)
+ return "no-lid-closed";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_NO_PROBE)
+ return "no-probe";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_MD_SET_SIGNED)
+ return "md-set-signed";
+ if (flag == FU_DEVICE_INTERNAL_AUTO_PAUSE_POLLING)
+ return "auto-pause-polling";
+ if (flag == FU_DEVICE_INTERNAL_FLAG_ONLY_WAIT_FOR_REPLUG)
+ return "only-wait-for-replug";
+ return NULL;
+}
+
+/**
+ * fu_device_internal_flag_from_string:
+ * @flag: a string, e.g. `md-set-icon`
+ *
+ * Converts a string to an internal device flag.
+ *
+ * Returns: enumerated value
+ *
+ * Since: 1.5.5
+ **/
+FuDeviceInternalFlags
+fu_device_internal_flag_from_string(const gchar *flag)
+{
+ if (g_strcmp0(flag, "md-set-icon") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON;
+ if (g_strcmp0(flag, "md-set-name") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME;
+ if (g_strcmp0(flag, "md-set-name-category") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY;
+ if (g_strcmp0(flag, "md-set-verfmt") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT;
+ if (g_strcmp0(flag, "only-supported") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED;
+ if (g_strcmp0(flag, "no-auto-instance-ids") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS;
+ if (g_strcmp0(flag, "ensure-semver") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER;
+ if (g_strcmp0(flag, "retry-open") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN;
+ if (g_strcmp0(flag, "replug-match-guid") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID;
+ if (g_strcmp0(flag, "inherit-activation") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_INHERIT_ACTIVATION;
+ if (g_strcmp0(flag, "is-open") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_IS_OPEN;
+ if (g_strcmp0(flag, "no-serial-number") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_NO_SERIAL_NUMBER;
+ if (g_strcmp0(flag, "auto-parent-children") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_AUTO_PARENT_CHILDREN;
+ if (g_strcmp0(flag, "attach-extra-reset") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_ATTACH_EXTRA_RESET;
+ if (g_strcmp0(flag, "inhibit-children") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN;
+ if (g_strcmp0(flag, "no-auto-remove-children") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE_CHILDREN;
+ if (g_strcmp0(flag, "use-parent-for-open") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN;
+ if (g_strcmp0(flag, "use-parent-for-battery") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_BATTERY;
+ if (g_strcmp0(flag, "use-proxy-fallback") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_USE_PROXY_FALLBACK;
+ if (g_strcmp0(flag, "no-auto-remove") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE;
+ if (g_strcmp0(flag, "md-set-vendor") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_MD_SET_VENDOR;
+ if (g_strcmp0(flag, "no-lid-closed") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_NO_LID_CLOSED;
+ if (g_strcmp0(flag, "no-probe") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_NO_PROBE;
+ if (g_strcmp0(flag, "md-set-signed") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_MD_SET_SIGNED;
+ if (g_strcmp0(flag, "auto-pause-polling") == 0)
+ return FU_DEVICE_INTERNAL_AUTO_PAUSE_POLLING;
+ if (g_strcmp0(flag, "only-wait-for-replug") == 0)
+ return FU_DEVICE_INTERNAL_FLAG_ONLY_WAIT_FOR_REPLUG;
+ return FU_DEVICE_INTERNAL_FLAG_UNKNOWN;
+}
+
+/**
+ * fu_device_add_internal_flag:
+ * @self: a #FuDevice
+ * @flag: an internal device flag, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON
+ *
+ * Adds a private flag that stays internal to the engine and is not leaked to the client.
+ *
+ * Since: 1.5.5
+ **/
+void
+fu_device_add_internal_flag(FuDevice *self, FuDeviceInternalFlags flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->internal_flags |= flag;
+}
+
+/**
+ * fu_device_remove_internal_flag:
+ * @self: a #FuDevice
+ * @flag: an internal device flag, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON
+ *
+ * Removes a private flag that stays internal to the engine and is not leaked to the client.
+ *
+ * Since: 1.5.5
+ **/
+void
+fu_device_remove_internal_flag(FuDevice *self, FuDeviceInternalFlags flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->internal_flags &= ~flag;
+}
+
+/**
+ * fu_device_has_internal_flag:
+ * @self: a #FuDevice
+ * @flag: an internal device flag, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON
+ *
+ * Tests for a private flag that stays internal to the engine and is not leaked to the client.
+ *
+ * Since: 1.5.5
+ **/
+gboolean
+fu_device_has_internal_flag(FuDevice *self, FuDeviceInternalFlags flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ return (priv->internal_flags & flag) > 0;
+}
+/**
+ * fu_device_get_internal_flags:
+ * @self: a #FuDevice
+ *
+ * Gets all the internal flags.
+ *
+ * Returns: flags, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON
+ *
+ * Since: 1.7.1
+ **/
+FuDeviceInternalFlags
+fu_device_get_internal_flags(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_UNKNOWN);
+ return priv->internal_flags;
+}
+
+/**
+ * fu_device_set_internal_flags:
+ * @self: a #FuDevice
+ * @flags: internal device flags, e.g. %FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON
+ *
+ * Sets the internal flags.
+ *
+ * Since: 1.7.1
+ **/
+void
+fu_device_set_internal_flags(FuDevice *self, FuDeviceInternalFlags flags)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->internal_flags = flags;
+}
+
+/**
+ * fu_device_add_private_flag:
+ * @self: a #FuDevice
+ * @flag: a device flag
+ *
+ * Adds a private flag that can be used by the plugin for any purpose.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_add_private_flag(FuDevice *self, guint64 flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->private_flags |= flag;
+}
+
+/**
+ * fu_device_remove_private_flag:
+ * @self: a #FuDevice
+ * @flag: a device flag
+ *
+ * Removes a private flag that can be used by the plugin for any purpose.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_remove_private_flag(FuDevice *self, guint64 flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->private_flags &= ~flag;
+}
+
+/**
+ * fu_device_has_private_flag:
+ * @self: a #FuDevice
+ * @flag: a device flag
+ *
+ * Tests for a private flag that can be used by the plugin for any purpose.
+ *
+ * Since: 1.6.2
+ **/
+gboolean
+fu_device_has_private_flag(FuDevice *self, guint64 flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ return (priv->private_flags & flag) > 0;
+}
+
+/**
+ * fu_device_get_private_flags:
+ * @self: a #FuDevice
+ *
+ * Returns all the private flags that can be used by the plugin for any purpose.
+ *
+ * Returns: flags
+ *
+ * Since: 1.6.2
+ **/
+guint64
+fu_device_get_private_flags(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), G_MAXUINT64);
+ return priv->private_flags;
+}
+
+/**
+ * fu_device_get_request_cnt:
+ * @self: a #FuDevice
+ * @request_kind: the type of request
+ *
+ * Returns the number of requests of a specific kind. This function is only
+ * useful to the daemon, which uses it to synthesize artificial events for
+ * plugins not yet ported to [class@Fwupd.Request].
+ *
+ * Returns: integer, usually 0
+ *
+ * Since: 1.6.2
+ **/
+guint
+fu_device_get_request_cnt(FuDevice *self, FwupdRequestKind request_kind)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), G_MAXUINT);
+ g_return_val_if_fail(request_kind < FWUPD_REQUEST_KIND_LAST, G_MAXUINT);
+ return priv->request_cnts[request_kind];
+}
+
+/**
+ * fu_device_set_private_flags:
+ * @self: a #FuDevice
+ * @flag: flags
+ *
+ * Sets private flags that can be used by the plugin for any purpose.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_set_private_flags(FuDevice *self, guint64 flag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->private_flags = flag;
+}
+
+/**
+ * fu_device_get_possible_plugins:
+ * @self: a #FuDevice
+ *
+ * Gets the list of possible plugin names, typically added from quirk files.
+ *
+ * Returns: (element-type utf8) (transfer container): plugin names
+ *
+ * Since: 1.3.3
+ **/
+GPtrArray *
+fu_device_get_possible_plugins(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ return g_ptr_array_ref(priv->possible_plugins);
+}
+
+/**
+ * fu_device_add_possible_plugin:
+ * @self: a #FuDevice
+ * @plugin: a plugin name, e.g. `dfu`
+ *
+ * Adds a plugin name to the list of plugins that *might* be able to handle this
+ * device. This is tyically called from a quirk handler.
+ *
+ * Duplicate plugin names are ignored.
+ *
+ * Since: 1.5.1
+ **/
+void
+fu_device_add_possible_plugin(FuDevice *self, const gchar *plugin)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(plugin != NULL);
+
+ /* add if it does not already exist */
+#if GLIB_CHECK_VERSION(2, 54, 3)
+ if (g_ptr_array_find_with_equal_func(priv->possible_plugins, plugin, g_str_equal, NULL))
+ return;
+#endif
+ g_ptr_array_add(priv->possible_plugins, g_strdup(plugin));
+}
+
+/**
+ * fu_device_retry_add_recovery:
+ * @self: a #FuDevice
+ * @domain: a #GQuark, or %0 for all domains
+ * @code: a #GError code
+ * @func: (scope async) (nullable): a function to recover the device
+ *
+ * Sets the optional function to be called when fu_device_retry() fails, which
+ * is possibly a device reset.
+ *
+ * If @func is %NULL then recovery is not possible and an error is returned
+ * straight away.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_device_retry_add_recovery(FuDevice *self, GQuark domain, gint code, FuDeviceRetryFunc func)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ FuDeviceRetryRecovery *rec;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(domain != 0);
+
+ rec = g_new(FuDeviceRetryRecovery, 1);
+ rec->domain = domain;
+ rec->code = code;
+ rec->recovery_func = func;
+ g_ptr_array_add(priv->retry_recs, rec);
+}
+
+/**
+ * fu_device_retry_set_delay:
+ * @self: a #FuDevice
+ * @delay: delay in ms
+ *
+ * Sets the recovery delay between failed retries.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_device_retry_set_delay(FuDevice *self, guint delay)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->retry_delay = delay;
+}
+
+/**
+ * fu_device_retry_full:
+ * @self: a #FuDevice
+ * @func: (scope async): a function to execute
+ * @count: the number of tries to try the function
+ * @delay: the delay between each try in ms
+ * @user_data: (nullable): a helper to pass to @func
+ * @error: (nullable): optional return location for an error
+ *
+ * Calls a specific function a number of times, optionally handling the error
+ * with a reset action.
+ *
+ * If fu_device_retry_add_recovery() has not been used then all errors are
+ * considered non-fatal until the last try.
+ *
+ * If the reset function returns %FALSE, then the function returns straight away
+ * without processing any pending retries.
+ *
+ * Since: 1.5.5
+ **/
+gboolean
+fu_device_retry_full(FuDevice *self,
+ FuDeviceRetryFunc func,
+ guint count,
+ guint delay,
+ gpointer user_data,
+ GError **error)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(func != NULL, FALSE);
+ g_return_val_if_fail(count >= 1, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ for (guint i = 0;; i++) {
+ g_autoptr(GError) error_local = NULL;
+
+ /* delay */
+ if (i > 0 && delay > 0)
+ g_usleep(delay * 1000);
+
+ /* run function, if success return success */
+ if (func(self, user_data, &error_local))
+ break;
+
+ /* sanity check */
+ if (error_local == NULL) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "exec failed but no error set!");
+ return FALSE;
+ }
+
+ /* too many retries */
+ if (i >= count - 1) {
+ g_propagate_prefixed_error(error,
+ g_steal_pointer(&error_local),
+ "failed after %u retries: ",
+ count);
+ return FALSE;
+ }
+
+ /* show recoverable error on the console */
+ if (priv->retry_recs->len == 0) {
+ g_debug("failed on try %u of %u: %s", i + 1, count, error_local->message);
+ continue;
+ }
+
+ /* find the condition that matches */
+ for (guint j = 0; j < priv->retry_recs->len; j++) {
+ FuDeviceRetryRecovery *rec = g_ptr_array_index(priv->retry_recs, j);
+ if (g_error_matches(error_local, rec->domain, rec->code)) {
+ if (rec->recovery_func != NULL) {
+ if (!rec->recovery_func(self, user_data, error))
+ return FALSE;
+ } else {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "device recovery not possible");
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_device_retry:
+ * @self: a #FuDevice
+ * @func: (scope async): a function to execute
+ * @count: the number of tries to try the function
+ * @user_data: (nullable): a helper to pass to @func
+ * @error: (nullable): optional return location for an error
+ *
+ * Calls a specific function a number of times, optionally handling the error
+ * with a reset action.
+ *
+ * If fu_device_retry_add_recovery() has not been used then all errors are
+ * considered non-fatal until the last try.
+ *
+ * If the reset function returns %FALSE, then the function returns straight away
+ * without processing any pending retries.
+ *
+ * Since: 1.4.0
+ **/
+gboolean
+fu_device_retry(FuDevice *self,
+ FuDeviceRetryFunc func,
+ guint count,
+ gpointer user_data,
+ GError **error)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ return fu_device_retry_full(self, func, count, priv->retry_delay, user_data, error);
+}
+
+static gboolean
+fu_device_poll_locker_open_cb(GObject *device, GError **error)
+{
+ FuDevice *self = FU_DEVICE(device);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_atomic_int_inc(&priv->poll_locker_cnt);
+ return TRUE;
+}
+
+static gboolean
+fu_device_poll_locker_close_cb(GObject *device, GError **error)
+{
+ FuDevice *self = FU_DEVICE(device);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_atomic_int_dec_and_test(&priv->poll_locker_cnt);
+ return TRUE;
+}
+
+/**
+ * fu_device_poll_locker_new:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * Returns a device locker that prevents polling on the device. If there are no open poll lockers
+ * then the poll callback will be called.
+ *
+ * Use %FU_DEVICE_INTERNAL_AUTO_PAUSE_POLLING to opt into this functionality.
+ *
+ * Returns: (transfer full): a #FuDeviceLocker
+ *
+ * Since: 1.8.1
+ **/
+FuDeviceLocker *
+fu_device_poll_locker_new(FuDevice *self, GError **error)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ return fu_device_locker_new_full(self,
+ fu_device_poll_locker_open_cb,
+ fu_device_poll_locker_close_cb,
+ error);
+}
+
+/**
+ * fu_device_poll:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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;
+
+ /* device is being detached, written, read, or attached */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_AUTO_PAUSE_POLLING) &&
+ priv->poll_locker_cnt > 0) {
+ g_debug("ignoring poll callback as an action is in progress");
+ return G_SOURCE_CONTINUE;
+ }
+
+ 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
+ **/
+gint
+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: an 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, gint 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: an 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;
+}
+
+/**
+ * fu_device_get_equivalent_id:
+ * @self: a #FuDevice
+ *
+ * Gets any equivalent ID for a device
+ *
+ * Returns: (transfer none): a #gchar or NULL
+ *
+ * Since: 0.6.1
+ **/
+const gchar *
+fu_device_get_equivalent_id(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->equivalent_id;
+}
+
+/**
+ * fu_device_set_equivalent_id:
+ * @self: a #FuDevice
+ * @equivalent_id: (nullable): a string
+ *
+ * Sets any equivalent ID for a device
+ *
+ * Since: 0.6.1
+ **/
+void
+fu_device_set_equivalent_id(FuDevice *self, const gchar *equivalent_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->equivalent_id, equivalent_id) == 0)
+ return;
+
+ g_free(priv->equivalent_id);
+ priv->equivalent_id = g_strdup(equivalent_id);
+}
+
+/**
+ * fu_device_get_alternate_id:
+ * @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 device 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_id:
+ * @self: a #FuDevice
+ * @alternate_id: (nullable): Another #FuDevice ID
+ *
+ * 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));
+
+ /* not changed */
+ if (g_strcmp0(priv->alternate_id, alternate_id) == 0)
+ return;
+
+ 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 device or %NULL
+ *
+ * Since: 0.7.2
+ **/
+FuDevice *
+fu_device_get_alternate(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->alternate;
+}
+
+/**
+ * fu_device_set_alternate:
+ * @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 *self, FuDevice *alternate)
+{
+ 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 device or %NULL
+ *
+ * Since: 1.0.8
+ **/
+FuDevice *
+fu_device_get_parent(FuDevice *self)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return FU_DEVICE(fwupd_device_get_parent(FWUPD_DEVICE(self)));
+}
+
+/**
+ * fu_device_get_root:
+ * @self: a #FuDevice
+ *
+ * Gets the root parent device. A parent device is logically "above" the current
+ * device and this may be reflected in client tools.
+ *
+ * If there is no parent device defined, then @self is returned.
+ *
+ * Returns: (transfer full): a device
+ *
+ * Since: 1.4.0
+ **/
+FuDevice *
+fu_device_get_root(FuDevice *self)
+{
+ FuDevice *parent;
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ do {
+ parent = fu_device_get_parent(self);
+ if (parent != NULL)
+ self = parent;
+ } while (parent != NULL);
+ return g_object_ref(self);
+}
+
+static void
+fu_device_set_composite_id(FuDevice *self, const gchar *composite_id)
+{
+ GPtrArray *children;
+
+ /* subclassed simple setter */
+ fwupd_device_set_composite_id(FWUPD_DEVICE(self), composite_id);
+
+ /* all children */
+ children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child_tmp = g_ptr_array_index(children, i);
+ fu_device_set_composite_id(child_tmp, composite_id);
+ }
+}
+
+/**
+ * fu_device_set_parent:
+ * @self: a #FuDevice
+ * @parent: (nullable): a device
+ *
+ * Sets 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.
+ *
+ * Since: 1.0.8
+ **/
+void
+fu_device_set_parent(FuDevice *self, FuDevice *parent)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* debug */
+ if (parent != NULL) {
+ g_debug("setting parent of %s [%s] to be %s [%s]",
+ fu_device_get_name(self),
+ fu_device_get_id(self),
+ fu_device_get_name(parent),
+ fu_device_get_id(parent));
+ }
+
+ /* set the composite ID on the children and grandchildren */
+ if (parent != NULL)
+ fu_device_set_composite_id(self, fu_device_get_composite_id(parent));
+
+ /* if the parent has a context, make the child inherit it */
+ if (parent != NULL) {
+ if (fu_device_get_context(self) == NULL && fu_device_get_context(parent) != NULL)
+ fu_device_set_context(self, fu_device_get_context(parent));
+ }
+
+ fwupd_device_set_parent(FWUPD_DEVICE(self), FWUPD_DEVICE(parent));
+ g_object_notify(G_OBJECT(self), "parent");
+}
+
+/**
+ * fu_device_set_proxy:
+ * @self: a #FuDevice
+ * @proxy: a device
+ *
+ * Sets any proxy device. A proxy device can be used to perform an action on
+ * behalf of another device, for instance attach()ing it after a successful
+ * update.
+ *
+ * Since: 1.4.1
+ **/
+void
+fu_device_set_proxy(FuDevice *self, FuDevice *proxy)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* copy from proxy */
+ if (proxy != NULL) {
+ if (fu_device_get_context(self) == NULL && fu_device_get_context(proxy) != NULL)
+ fu_device_set_context(self, fu_device_get_context(proxy));
+ if (fu_device_get_physical_id(self) == NULL &&
+ fu_device_get_physical_id(proxy) != NULL)
+ fu_device_set_physical_id(self, fu_device_get_physical_id(proxy));
+ }
+
+ if (priv->proxy != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+ if (proxy != NULL)
+ g_object_add_weak_pointer(G_OBJECT(proxy), (gpointer *)&priv->proxy);
+ priv->proxy = proxy;
+ g_object_notify(G_OBJECT(self), "proxy");
+}
+
+/**
+ * fu_device_get_proxy:
+ * @self: a #FuDevice
+ *
+ * Gets any proxy device. A proxy device can be used to perform an action on
+ * behalf of another device, for instance attach()ing it after a successful
+ * update.
+ *
+ * The proxy object is not refcounted and if destroyed this function will then
+ * return %NULL.
+ *
+ * Returns: (transfer none): a device or %NULL
+ *
+ * Since: 1.4.1
+ **/
+FuDevice *
+fu_device_get_proxy(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->proxy;
+}
+
+/**
+ * fu_device_get_proxy_with_fallback:
+ * @self: a #FuDevice
+ *
+ * Gets the proxy device if %FU_DEVICE_INTERNAL_FLAG_USE_PROXY_FALLBACK is set, falling back to the
+ * device itself.
+ *
+ * Returns: (transfer none): a device
+ *
+ * Since: 1.6.2
+ **/
+FuDevice *
+fu_device_get_proxy_with_fallback(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_USE_PROXY_FALLBACK) &&
+ priv->proxy != NULL)
+ return priv->proxy;
+ return self;
+}
+
+/**
+ * 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)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return fwupd_device_get_children(FWUPD_DEVICE(self));
+}
+
+/**
+ * fu_device_get_backend_tags:
+ * @self: a #FuDevice
+ *
+ * Gets any backend tags.
+ *
+ * Returns: (transfer none) (element-type utf8): string tags
+ *
+ * Since: 1.8.5
+ **/
+GPtrArray *
+fu_device_get_backend_tags(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->backend_tags;
+}
+
+/**
+ * fu_device_add_backend_tag:
+ * @self: a #FuDevice
+ * @backend_tag: a tag, for example `bootloader` or `runtime-reload`
+ *
+ * Adds a backend tag, which allows the backend to identify the specific device for a specific
+ * phase. For instance, there might be a pre-update runtime, a bootloader and a post-update runtime
+ * and allowing tags to be saved to the backend object allows us to identify each version of
+ * the same physical device.
+ *
+ * Since: 1.8.5
+ **/
+void
+fu_device_add_backend_tag(FuDevice *self, const gchar *backend_tag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(backend_tag != NULL);
+ if (fu_device_has_backend_tag(self, backend_tag))
+ return;
+ g_ptr_array_add(priv->backend_tags, g_strdup(backend_tag));
+ g_object_notify(G_OBJECT(self), "backend-tags");
+}
+
+/**
+ * fu_device_has_backend_tag:
+ * @self: a #FuDevice
+ * @backend_tag: a tag, for example `bootloader` or `runtime-reload`
+ *
+ * Finds if the backend tag already exists.
+ *
+ * Returns: %TRUE if the backend tag exists
+ *
+ * Since: 1.8.5
+ **/
+gboolean
+fu_device_has_backend_tag(FuDevice *self, const gchar *backend_tag)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(backend_tag != NULL, FALSE);
+ for (guint i = 0; i < priv->backend_tags->len; i++) {
+ const gchar *backend_tag_tmp = g_ptr_array_index(priv->backend_tags, i);
+ if (g_strcmp0(backend_tag_tmp, backend_tag) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * 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);
+ FuDevicePrivate *priv_child = GET_PRIVATE(child);
+ GPtrArray *children;
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(FU_IS_DEVICE(child));
+
+ /* add if the child does not already exist */
+ fwupd_device_add_child(FWUPD_DEVICE(self), FWUPD_DEVICE(child));
+
+ /* propagate inhibits to children */
+ if (priv->inhibits != NULL &&
+ fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN)) {
+ g_autoptr(GList) values = g_hash_table_get_values(priv->inhibits);
+ for (GList *l = values; l != NULL; l = l->next) {
+ FuDeviceInhibit *inhibit = (FuDeviceInhibit *)l->data;
+ fu_device_inhibit_full(child,
+ inhibit->problem,
+ inhibit->inhibit_id,
+ inhibit->reason);
+ }
+ }
+
+ /* ensure the parent has the MAX() of the children's removal delay */
+ children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child_tmp = g_ptr_array_index(children, i);
+ guint remove_delay = fu_device_get_remove_delay(child_tmp);
+ if (remove_delay > priv->remove_delay) {
+ g_debug("setting remove delay to %ums as child is greater than %ums",
+ remove_delay,
+ priv->remove_delay);
+ priv->remove_delay = remove_delay;
+ }
+ }
+
+ /* ensure the parent has the MAX() of the children's acquiesce delay */
+ children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child_tmp = g_ptr_array_index(children, i);
+ guint acquiesce_delay = fu_device_get_acquiesce_delay(child_tmp);
+ if (acquiesce_delay > priv->acquiesce_delay) {
+ g_debug("setting acquiesce delay to %ums as child is greater than %ums",
+ acquiesce_delay,
+ priv->acquiesce_delay);
+ priv->acquiesce_delay = acquiesce_delay;
+ }
+ }
+
+ /* 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 (priv_child->backend_id == NULL && priv->backend_id != NULL)
+ fu_device_set_backend_id(child, priv->backend_id);
+ if (priv_child->ctx == NULL && priv->ctx != NULL)
+ fu_device_set_context(child, priv->ctx);
+ if (fu_device_get_vendor(child) == NULL)
+ fu_device_set_vendor(child, fu_device_get_vendor(self));
+ if (priv_child->remove_delay == 0 && priv->remove_delay != 0)
+ fu_device_set_remove_delay(child, priv->remove_delay);
+ if (priv_child->acquiesce_delay == 0 && priv->acquiesce_delay != 0)
+ fu_device_set_acquiesce_delay(child, priv->acquiesce_delay);
+ if (fu_device_get_vendor_ids(child)->len == 0) {
+ GPtrArray *vendor_ids = fu_device_get_vendor_ids(self);
+ for (guint i = 0; i < vendor_ids->len; i++) {
+ const gchar *vendor_id = g_ptr_array_index(vendor_ids, i);
+ fu_device_add_vendor_id(child, vendor_id);
+ }
+ }
+ 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 ID is converted */
+ if (!fu_device_ensure_id(child, &error))
+ g_warning("failed to ensure child: %s", error->message);
+
+ /* ensure the parent is also set on the child */
+ fu_device_set_parent(child, self);
+
+ /* signal to the plugin in case this is done after setup */
+ g_signal_emit(self, signals[SIGNAL_CHILD_ADDED], 0, child);
+}
+
+/**
+ * fu_device_remove_child:
+ * @self: a #FuDevice
+ * @child: Another #FuDevice
+ *
+ * Removes child device.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_remove_child(FuDevice *self, FuDevice *child)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(FU_IS_DEVICE(child));
+
+ /* proxy */
+ fwupd_device_remove_child(FWUPD_DEVICE(self), FWUPD_DEVICE(child));
+
+ /* signal to the plugin */
+ g_signal_emit(self, signals[SIGNAL_CHILD_REMOVED], 0, child);
+}
+
+/**
+ * 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(guid != NULL, 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(GRWLockWriterLocker) 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));
+}
+
+/**
+ * fu_device_get_parent_physical_ids:
+ * @self: a #FuDevice
+ *
+ * Gets any parent device IDs. If a device is added to the daemon that matches
+ * the physical ID added from fu_device_add_parent_physical_id() then this
+ * device is marked the parent of @self.
+ *
+ * Returns: (transfer none) (element-type utf8) (nullable): a list of IDs
+ *
+ * Since: 1.6.2
+ **/
+GPtrArray *
+fu_device_get_parent_physical_ids(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->parent_physical_ids;
+}
+
+/**
+ * fu_device_has_parent_physical_id:
+ * @self: a #FuDevice
+ * @physical_id: a device physical ID
+ *
+ * Searches the list of parent IDs for a string match.
+ *
+ * Returns: %TRUE if the parent ID exists
+ *
+ * Since: 1.6.2
+ **/
+gboolean
+fu_device_has_parent_physical_id(FuDevice *self, const gchar *physical_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(physical_id != NULL, FALSE);
+
+ if (priv->parent_physical_ids == NULL)
+ return FALSE;
+ for (guint i = 0; i < priv->parent_physical_ids->len; i++) {
+ const gchar *tmp = g_ptr_array_index(priv->parent_physical_ids, i);
+ if (g_strcmp0(tmp, physical_id) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * fu_device_add_parent_physical_id:
+ * @self: a #FuDevice
+ * @physical_id: a device physical ID
+ *
+ * Sets any parent device using the physical ID. An parent device is logically
+ * linked to the primary device in some way and can be added before or after @self.
+ *
+ * The IDs are searched in order, and so the order of adding IDs may be
+ * important if more than one parent device might match.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_add_parent_physical_id(FuDevice *self, const gchar *physical_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(physical_id != NULL);
+
+ /* ensure exists */
+ if (priv->parent_physical_ids == NULL)
+ priv->parent_physical_ids = g_ptr_array_new_with_free_func(g_free);
+
+ /* already present */
+ if (fu_device_has_parent_physical_id(self, physical_id))
+ return;
+ g_ptr_array_add(priv->parent_physical_ids, g_strdup(physical_id));
+}
+
+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, "context", priv->ctx, "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_inhibit_section(FuDevice *self, const gchar *value, GError **error)
+{
+ g_auto(GStrv) sections = NULL;
+
+ g_return_val_if_fail(value != NULL, FALSE);
+
+ /* sanity check */
+ sections = g_strsplit(value, ":", -1);
+ if (g_strv_length(sections) != 2) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "quirk key not supported, expected k1:v1[,k2:v2][,k3:]");
+ return FALSE;
+ }
+
+ /* allow empty string to unset quirk */
+ if (g_strcmp0(sections[1], "") != 0)
+ fu_device_inhibit(self, sections[0], sections[1]);
+ else
+ fu_device_uninhibit(self, sections[0]);
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_device_set_quirk_kv:
+ * @self: a #FuDevice
+ * @key: a string key
+ * @value: a string value
+ * @error: (nullable): optional return location for an error
+ *
+ * Sets a specific quirk on the device.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.8.5
+ **/
+gboolean
+fu_device_set_quirk_kv(FuDevice *self, const gchar *key, const gchar *value, GError **error)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ guint64 tmp;
+
+ g_return_val_if_fail(FU_IS_DEVICE(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);
+
+ if (g_strcmp0(key, FU_QUIRKS_PLUGIN) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_possible_plugin(self, sections[i]);
+ 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_BRANCH) == 0) {
+ fu_device_set_branch(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) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_vendor_id(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_PROTOCOL) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_protocol(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_ISSUE) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_issue(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_VERSION) == 0) {
+ fu_device_set_version(self, value);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_UPDATE_MESSAGE) == 0) {
+ fu_device_set_update_message(self, value);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_UPDATE_IMAGE) == 0) {
+ fu_device_set_update_image(self, value);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_ICON) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_icon(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_GUID) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_guid(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_COUNTERPART_GUID) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_counterpart_guid(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_PARENT_GUID) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++)
+ fu_device_add_parent_guid(self, sections[i]);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_PROXY_GUID) == 0) {
+ fu_device_set_proxy_guid(self, value);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_FIRMWARE_SIZE_MIN) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT64, error))
+ return FALSE;
+ fu_device_set_firmware_size_min(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_FIRMWARE_SIZE_MAX) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT64, error))
+ return FALSE;
+ fu_device_set_firmware_size_max(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_FIRMWARE_SIZE) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT64, error))
+ return FALSE;
+ fu_device_set_firmware_size(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_INSTALL_DURATION) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, 60 * 60 * 24, error))
+ return FALSE;
+ fu_device_set_install_duration(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_PRIORITY) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT8, error))
+ return FALSE;
+ fu_device_set_priority(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_BATTERY_THRESHOLD) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, 100, error))
+ return FALSE;
+ fu_device_set_battery_threshold(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_REMOVE_DELAY) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT, error))
+ return FALSE;
+ fu_device_set_remove_delay(self, tmp);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_ACQUIESCE_DELAY) == 0) {
+ if (!fu_strtoull(value, &tmp, 0, G_MAXUINT, error))
+ return FALSE;
+ fu_device_set_acquiesce_delay(self, tmp);
+ 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_INHIBIT) == 0) {
+ g_auto(GStrv) sections = g_strsplit(value, ",", -1);
+ for (guint i = 0; sections[i] != NULL; i++) {
+ if (!fu_device_set_quirk_inhibit_section(self, sections[i], error))
+ return FALSE;
+ }
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_GTYPE) == 0) {
+ if (priv->specialized_gtype != G_TYPE_INVALID) {
+ g_debug("already set GType to %s, ignoring %s",
+ g_type_name(priv->specialized_gtype),
+ value);
+ return TRUE;
+ }
+ priv->specialized_gtype = g_type_from_name(value);
+ return TRUE;
+ }
+ if (g_strcmp0(key, FU_QUIRKS_FIRMWARE_GTYPE) == 0) {
+ if (priv->firmware_gtype != G_TYPE_INVALID) {
+ g_debug("already set firmware GType to %s, ignoring %s",
+ g_type_name(priv->firmware_gtype),
+ value);
+ return TRUE;
+ }
+ priv->firmware_gtype = g_type_from_name(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;
+}
+
+/**
+ * fu_device_get_specialized_gtype:
+ * @self: a #FuDevice
+ *
+ * Gets the specialized type of the device
+ *
+ * Returns:#GType
+ *
+ * Since: 1.3.3
+ **/
+GType
+fu_device_get_specialized_gtype(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ return priv->specialized_gtype;
+}
+
+/**
+ * fu_device_get_firmware_gtype:
+ * @self: a #FuDevice
+ *
+ * Gets the default firmware type for the device.
+ *
+ * Returns: #GType
+ *
+ * Since: 1.7.2
+ **/
+GType
+fu_device_get_firmware_gtype(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ return priv->firmware_gtype;
+}
+
+/**
+ * fu_device_set_firmware_gtype:
+ * @self: a #FuDevice
+ * @firmware_gtype: a #GType
+ *
+ * Sets the default firmware type for the device.
+ *
+ * Since: 1.7.2
+ **/
+void
+fu_device_set_firmware_gtype(FuDevice *self, GType firmware_gtype)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ priv->firmware_gtype = firmware_gtype;
+}
+
+static void
+fu_device_quirks_iter_cb(FuContext *ctx, const gchar *key, const gchar *value, gpointer user_data)
+{
+ FuDevice *self = FU_DEVICE(user_data);
+ 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);
+ }
+ }
+}
+
+static void
+fu_device_add_guid_quirks(FuDevice *self, const gchar *guid)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ if (priv->ctx == NULL) {
+ g_autofree gchar *str = fu_device_to_string(self);
+ g_critical("no FuContext assigned for %s", str);
+ return;
+ }
+ fu_context_lookup_quirk_by_id_iter(priv->ctx, guid, fu_device_quirks_iter_cb, self);
+}
+
+/**
+ * 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, FuDeviceInstanceFlags flags)
+{
+ /* add the device GUID before adding additional GUIDs from quirks
+ * to ensure the bootloader GUID is listed after the runtime GUID */
+ if ((flags & FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS) == 0)
+ fwupd_device_add_guid(FWUPD_DEVICE(self), guid);
+ if ((flags & FU_DEVICE_INSTANCE_FLAG_NO_QUIRKS) == 0)
+ 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);
+}
+
+/**
+ * fu_device_add_instance_id_full:
+ * @self: a #FuDevice
+ * @instance_id: a instance ID, e.g. `WacomAES`
+ * @flags: instance ID flags
+ *
+ * Adds an instance ID with all parameters set
+ *
+ * Since: 1.2.9
+ **/
+void
+fu_device_add_instance_id_full(FuDevice *self,
+ const gchar *instance_id,
+ FuDeviceInstanceFlags flags)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_autofree gchar *guid = NULL;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(instance_id != 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, flags);
+ 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);
+ if ((flags & FU_DEVICE_INSTANCE_FLAG_NO_QUIRKS) == 0)
+ 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);
+
+ /* already done by ->setup(), so this must be ->registered() */
+ if (priv->done_setup)
+ fwupd_device_add_guid(FWUPD_DEVICE(self), guid);
+}
+
+/**
+ * fu_device_add_instance_id:
+ * @self: a #FuDevice
+ * @instance_id: the instance ID, 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:
+ * @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().
+ *
+ * Since: 0.7.2
+ **/
+void
+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_INSTANCE_FLAG_NONE);
+}
+
+/**
+ * fu_device_add_guid_full:
+ * @self: a #FuDevice
+ * @guid: a GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad`
+ * @flags: instance ID flags
+ *
+ * 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().
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_add_guid_full(FuDevice *self, const gchar *guid, FuDeviceInstanceFlags flags)
+{
+ 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_full(self, guid, flags);
+ return;
+ }
+ fu_device_add_guid_safe(self, guid, flags);
+}
+
+/**
+ * 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 (!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(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:
+ * @self: a #FuDevice
+ * @key: the key
+ *
+ * Gets an item of metadata from the device.
+ *
+ * Returns: a string value, or %NULL for unfound.
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+fu_device_get_metadata(FuDevice *self, const gchar *key)
+{
+ 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);
+ if (priv->metadata == NULL)
+ return NULL;
+ return g_hash_table_lookup(priv->metadata, key);
+}
+
+/**
+ * fu_device_get_metadata_boolean:
+ * @self: a #FuDevice
+ * @key: the key
+ *
+ * Gets an item of metadata from the device.
+ *
+ * Returns: a boolean value, or %FALSE for unfound or failure to parse.
+ *
+ * Since: 0.9.7
+ **/
+gboolean
+fu_device_get_metadata_boolean(FuDevice *self, const gchar *key)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ const gchar *tmp;
+ 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);
+
+ if (priv->metadata == NULL)
+ return FALSE;
+ tmp = g_hash_table_lookup(priv->metadata, key);
+ if (tmp == NULL)
+ return FALSE;
+ return g_strcmp0(tmp, "true") == 0;
+}
+
+/**
+ * fu_device_get_metadata_integer:
+ * @self: a #FuDevice
+ * @key: the key
+ *
+ * Gets an item of metadata from the device.
+ *
+ * Returns: an integer value, or %G_MAXUINT for unfound or failure to parse.
+ *
+ * Since: 0.9.7
+ **/
+guint
+fu_device_get_metadata_integer(FuDevice *self, const gchar *key)
+{
+ 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(self), G_MAXUINT);
+ g_return_val_if_fail(key != NULL, G_MAXUINT);
+ g_return_val_if_fail(locker != NULL, G_MAXUINT);
+
+ if (priv->metadata == NULL)
+ return G_MAXUINT;
+ tmp = g_hash_table_lookup(priv->metadata, key);
+ if (tmp == NULL)
+ return G_MAXUINT;
+ val = g_ascii_strtoull(tmp, &endptr, 10);
+ if (endptr != NULL && endptr[0] != '\0')
+ return G_MAXUINT;
+ if (val > G_MAXUINT)
+ return G_MAXUINT;
+ return (guint)val;
+}
+
+/**
+ * fu_device_remove_metadata:
+ * @self: a #FuDevice
+ * @key: the key
+ *
+ * Removes an item of metadata on the device.
+ *
+ * Since: 1.3.3
+ **/
+void
+fu_device_remove_metadata(FuDevice *self, const gchar *key)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GRWLockWriterLocker) 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(locker != NULL);
+ if (priv->metadata == NULL)
+ return;
+ g_hash_table_remove(priv->metadata, key);
+}
+
+/**
+ * fu_device_set_metadata:
+ * @self: a #FuDevice
+ * @key: the key
+ * @value: the string value
+ *
+ * Sets an item of metadata on the device.
+ *
+ * Since: 0.1.0
+ **/
+void
+fu_device_set_metadata(FuDevice *self, const gchar *key, const gchar *value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GRWLockWriterLocker) 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);
+ if (priv->metadata == NULL) {
+ priv->metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ }
+ g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
+}
+
+/**
+ * fu_device_set_metadata_boolean:
+ * @self: a #FuDevice
+ * @key: the key
+ * @value: the boolean value
+ *
+ * Sets an item of metadata on the device. When @value is set to %TRUE
+ * the actual stored value is `true`.
+ *
+ * Since: 0.9.7
+ **/
+void
+fu_device_set_metadata_boolean(FuDevice *self, const gchar *key, gboolean value)
+{
+ 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:
+ * @self: a #FuDevice
+ * @key: the key
+ * @value: the unsigned integer value
+ *
+ * Sets an item of metadata on the device. The integer is stored as a
+ * base-10 string internally.
+ *
+ * Since: 0.9.7
+ **/
+void
+fu_device_set_metadata_integer(FuDevice *self, const gchar *key, guint value)
+{
+ g_autofree gchar *tmp = g_strdup_printf("%u", value);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+
+ fu_device_set_metadata(self, key, tmp);
+}
+
+/* ensure the name does not have the vendor name as the prefix */
+static void
+fu_device_fixup_vendor_name(FuDevice *self)
+{
+ const gchar *name = fu_device_get_name(self);
+ const gchar *vendor = fu_device_get_vendor(self);
+ if (name != NULL && vendor != NULL) {
+ g_autofree gchar *name_up = g_utf8_strup(name, -1);
+ g_autofree gchar *vendor_up = g_utf8_strup(vendor, -1);
+ if (g_str_has_prefix(name_up, vendor_up)) {
+ gsize vendor_len = strlen(vendor);
+ g_autofree gchar *name1 = g_strdup(name + vendor_len);
+ g_autofree gchar *name2 = fu_strstrip(name1);
+ g_debug("removing vendor prefix of '%s' from '%s'", vendor, name);
+ fwupd_device_set_name(FWUPD_DEVICE(self), name2);
+ }
+ }
+}
+
+/**
+ * fu_device_set_vendor:
+ * @self: a #FuDevice
+ * @vendor: a device vendor
+ *
+ * Sets the vendor name on the device.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_set_vendor(FuDevice *self, const gchar *vendor)
+{
+ g_autofree gchar *vendor_safe = NULL;
+
+ /* trim any leading and trailing spaces */
+ if (vendor != NULL)
+ vendor_safe = fu_strstrip(vendor);
+
+ /* proxy */
+ fwupd_device_set_vendor(FWUPD_DEVICE(self), vendor_safe);
+ fu_device_fixup_vendor_name(self);
+}
+
+static gchar *
+fu_device_sanitize_name(const gchar *value)
+{
+ gboolean last_was_space = FALSE;
+ guint last_non_space = 0;
+ g_autoptr(GString) new = g_string_new(NULL);
+
+ /* add each printable char with maximum of one whitespace char */
+ for (guint i = 0; value[i] != '\0'; i++) {
+ const gchar tmp = value[i];
+ if (!g_ascii_isprint(tmp))
+ continue;
+ if (g_ascii_isspace(tmp) || tmp == '_') {
+ if (new->len == 0)
+ continue;
+ if (last_was_space)
+ continue;
+ last_was_space = TRUE;
+ g_string_append_c(new, ' ');
+ } else {
+ last_was_space = FALSE;
+ g_string_append_c(new, tmp);
+ last_non_space = new->len;
+ }
+ }
+ g_string_truncate(new, last_non_space);
+ fu_string_replace(new, "(TM)", "™");
+ fu_string_replace(new, "(R)", "");
+ if (new->len == 0)
+ return NULL;
+ return g_string_free(g_steal_pointer(&new), FALSE);
+}
+
+/**
+ * fu_device_set_name:
+ * @self: a #FuDevice
+ * @value: a device name
+ *
+ * Sets the name on the device. Any invalid parts will be converted or removed.
+ *
+ * Since: 0.7.1
+ **/
+void
+fu_device_set_name(FuDevice *self, const gchar *value)
+{
+ g_autofree gchar *value_safe = NULL;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(value != NULL);
+
+ /* overwriting? */
+ value_safe = fu_device_sanitize_name(value);
+ if (g_strcmp0(value_safe, fu_device_get_name(self)) == 0)
+ return;
+
+ /* changing */
+ 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_safe);
+ }
+
+ fwupd_device_set_name(FWUPD_DEVICE(self), value_safe);
+ fu_device_fixup_vendor_name(self);
+}
+
+/**
+ * fu_device_set_id:
+ * @self: a #FuDevice
+ * @id: a string, e.g. `tbt-port1`
+ *
+ * Sets the ID on the device. The ID should represent the *connection* of the
+ * device, so that any similar device plugged into a different slot will
+ * have a different @id string.
+ *
+ * The @id will be converted to a SHA1 hash if required before the device is
+ * added to the daemon, and plugins should not assume that the ID that is set
+ * here is the same as what is returned by fu_device_get_id().
+ *
+ * Since: 0.7.1
+ **/
+void
+fu_device_set_id(FuDevice *self, const gchar *id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ GPtrArray *children;
+ g_autofree gchar *id_hash = NULL;
+ g_autofree gchar *id_hash_old = g_strdup(fwupd_device_get_id(FWUPD_DEVICE(self)));
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(id != NULL);
+
+ /* allow sane device-id to be set directly */
+ if (fwupd_device_id_is_valid(id)) {
+ id_hash = g_strdup(id);
+ } else {
+ 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(self), id_hash);
+ priv->device_id_valid = TRUE;
+
+ /* ensure the parent ID is set */
+ children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *devtmp = g_ptr_array_index(children, i);
+ fwupd_device_set_parent_id(FWUPD_DEVICE(devtmp), id_hash);
+
+ /* update the composite ID of the child with the new ID if required; this will
+ * propagate to grandchildren and great-grandchildren as required */
+ if (id_hash_old != NULL &&
+ g_strcmp0(fu_device_get_composite_id(devtmp), id_hash_old) == 0)
+ fu_device_set_composite_id(devtmp, id_hash);
+ }
+}
+
+/**
+ * fu_device_set_version_format:
+ * @self: a #FuDevice
+ * @fmt: the version format, e.g. %FWUPD_VERSION_FORMAT_PLAIN
+ *
+ * Sets the device version format.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_device_set_version_format(FuDevice *self, FwupdVersionFormat fmt)
+{
+ /* same */
+ if (fu_device_get_version_format(self) == fmt)
+ return;
+ if (fu_device_get_version_format(self) != FWUPD_VERSION_FORMAT_UNKNOWN) {
+ g_debug("changing verfmt for %s: %s->%s",
+ fu_device_get_id(self),
+ fwupd_version_format_to_string(fu_device_get_version_format(self)),
+ fwupd_version_format_to_string(fmt));
+ }
+ fwupd_device_set_version_format(FWUPD_DEVICE(self), fmt);
+}
+
+/**
+ * fu_device_set_version:
+ * @self: a #FuDevice
+ * @version: (nullable): a string, e.g. `1.2.3`
+ *
+ * Sets the device version, sanitizing the string if required.
+ *
+ * Since: 1.2.9
+ **/
+void
+fu_device_set_version(FuDevice *self, const gchar *version)
+{
+ g_autofree gchar *version_safe = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* sanitize if required */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)) {
+ version_safe =
+ fu_version_ensure_semver(version, fu_device_get_version_format(self));
+ 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 (version_safe != NULL &&
+ !fu_version_verify_format(version_safe, fu_device_get_version_format(self), &error))
+ g_warning("%s", error->message);
+
+ /* if different */
+ if (g_strcmp0(fu_device_get_version(self), version_safe) != 0) {
+ if (fu_device_get_version(self) != NULL) {
+ g_debug("changing version for %s: %s->%s",
+ fu_device_get_id(self),
+ fu_device_get_version(self),
+ version_safe);
+ }
+ fwupd_device_set_version(FWUPD_DEVICE(self), version_safe);
+ }
+}
+
+/**
+ * fu_device_set_version_lowest:
+ * @self: a #FuDevice
+ * @version: (nullable): a string, e.g. `1.2.3`
+ *
+ * Sets the device lowest version, sanitizing the string if required.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_device_set_version_lowest(FuDevice *self, const gchar *version)
+{
+ g_autofree gchar *version_safe = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* sanitize if required */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)) {
+ version_safe =
+ fu_version_ensure_semver(version, fu_device_get_version_format(self));
+ 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 (version_safe != NULL &&
+ !fu_version_verify_format(version_safe, fu_device_get_version_format(self), &error))
+ g_warning("%s", error->message);
+
+ /* if different */
+ if (g_strcmp0(fu_device_get_version_lowest(self), version_safe) != 0) {
+ if (fu_device_get_version_lowest(self) != NULL) {
+ g_debug("changing version lowest for %s: %s->%s",
+ fu_device_get_id(self),
+ fu_device_get_version_lowest(self),
+ version_safe);
+ }
+ fwupd_device_set_version_lowest(FWUPD_DEVICE(self), version_safe);
+ }
+}
+
+/**
+ * fu_device_set_version_bootloader:
+ * @self: a #FuDevice
+ * @version: (nullable): a string, e.g. `1.2.3`
+ *
+ * Sets the device bootloader version, sanitizing the string if required.
+ *
+ * Since: 1.4.0
+ **/
+void
+fu_device_set_version_bootloader(FuDevice *self, const gchar *version)
+{
+ g_autofree gchar *version_safe = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* sanitize if required */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER)) {
+ version_safe =
+ fu_version_ensure_semver(version, fu_device_get_version_format(self));
+ 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 (version_safe != NULL &&
+ !fu_version_verify_format(version_safe, fu_device_get_version_format(self), &error))
+ g_warning("%s", error->message);
+
+ /* if different */
+ if (g_strcmp0(fu_device_get_version_bootloader(self), version_safe) != 0) {
+ if (fu_device_get_version_bootloader(self) != NULL) {
+ g_debug("changing version for %s: %s->%s",
+ fu_device_get_id(self),
+ fu_device_get_version_bootloader(self),
+ version_safe);
+ }
+ fwupd_device_set_version_bootloader(FWUPD_DEVICE(self), version_safe);
+ }
+}
+
+static void
+fu_device_inhibit_free(FuDeviceInhibit *inhibit)
+{
+ g_free(inhibit->inhibit_id);
+ g_free(inhibit->reason);
+ g_free(inhibit);
+}
+
+static void
+fu_device_ensure_inhibits(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ FwupdDeviceProblem problems = FWUPD_DEVICE_PROBLEM_NONE;
+ guint nr_inhibits = g_hash_table_size(priv->inhibits);
+
+ /* disable */
+ if (priv->notify_flags_handler_id != 0)
+ g_signal_handler_block(self, priv->notify_flags_handler_id);
+
+ /* was okay -> not okay */
+ if (nr_inhibits > 0) {
+ g_autofree gchar *reasons_str = NULL;
+ g_autoptr(GList) values = g_hash_table_get_values(priv->inhibits);
+ g_autoptr(GPtrArray) reasons = g_ptr_array_new();
+
+ /* updatable -> updatable-hidden -- which is required as devices might have
+ * inhibits and *not* be automatically updatable */
+ if (fu_device_has_flag(self, FWUPD_DEVICE_FLAG_UPDATABLE)) {
+ fu_device_remove_flag(self, FWUPD_DEVICE_FLAG_UPDATABLE);
+ fu_device_add_flag(self, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN);
+ }
+
+ /* update update error */
+ for (GList *l = values; l != NULL; l = l->next) {
+ FuDeviceInhibit *inhibit = (FuDeviceInhibit *)l->data;
+ g_ptr_array_add(reasons, inhibit->reason);
+ problems |= inhibit->problem;
+ }
+ reasons_str = fu_strjoin(", ", reasons);
+ fu_device_set_update_error(self, reasons_str);
+ } else {
+ if (fu_device_has_flag(self, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN)) {
+ fu_device_remove_flag(self, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN);
+ fu_device_add_flag(self, FWUPD_DEVICE_FLAG_UPDATABLE);
+ }
+ fu_device_set_update_error(self, NULL);
+ }
+
+ /* sync with baseclass */
+ fwupd_device_set_problems(FWUPD_DEVICE(self), problems);
+
+ /* enable */
+ if (priv->notify_flags_handler_id != 0)
+ g_signal_handler_unblock(self, priv->notify_flags_handler_id);
+}
+
+static gchar *
+fu_device_problem_to_inhibit_reason(FuDevice *self, guint64 device_problem)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ if (device_problem == FWUPD_DEVICE_PROBLEM_UNREACHABLE)
+ return g_strdup("Device is unreachable, or out of wireless range");
+ if (device_problem == FWUPD_DEVICE_PROBLEM_UPDATE_PENDING)
+ return g_strdup("Device is waiting for the update to be applied");
+ if (device_problem == FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER)
+ return g_strdup("Device requires AC power to be connected");
+ if (device_problem == FWUPD_DEVICE_PROBLEM_LID_IS_CLOSED)
+ return g_strdup("Device cannot be used while the lid is closed");
+ if (device_problem == FWUPD_DEVICE_PROBLEM_IS_EMULATED)
+ return g_strdup("Device is emulated");
+ if (device_problem == FWUPD_DEVICE_PROBLEM_MISSING_LICENSE)
+ return g_strdup("Device does not have the necessary license installed");
+ if (device_problem == FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW) {
+ if (priv->ctx == NULL)
+ return g_strdup("System power is too low to perform the update");
+ return g_strdup_printf(
+ "System power is too low to perform the update (%u%%, requires %u%%)",
+ fu_context_get_battery_level(priv->ctx),
+ fu_context_get_battery_threshold(priv->ctx));
+ }
+ if (device_problem == FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW) {
+ if (fu_device_get_battery_level(self) == FWUPD_BATTERY_LEVEL_INVALID ||
+ fu_device_get_battery_threshold(self) == FWUPD_BATTERY_LEVEL_INVALID) {
+ return g_strdup_printf("Device battery power is too low");
+ }
+ return g_strdup_printf("Device battery power is too low (%u%%, requires %u%%)",
+ fu_device_get_battery_level(self),
+ fu_device_get_battery_threshold(self));
+ }
+ return NULL;
+}
+
+static void
+fu_device_inhibit_full(FuDevice *self,
+ FwupdDeviceProblem problem,
+ const gchar *inhibit_id,
+ const gchar *reason)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ FuDeviceInhibit *inhibit;
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* lazy create as most devices will not need this */
+ if (priv->inhibits == NULL) {
+ priv->inhibits = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify)fu_device_inhibit_free);
+ }
+
+ /* can fallback */
+ if (inhibit_id == NULL)
+ inhibit_id = fwupd_device_problem_to_string(problem);
+
+ /* already exists */
+ inhibit = g_hash_table_lookup(priv->inhibits, inhibit_id);
+ if (inhibit != NULL)
+ return;
+
+ /* create new */
+ inhibit = g_new0(FuDeviceInhibit, 1);
+ inhibit->problem = problem;
+ inhibit->inhibit_id = g_strdup(inhibit_id);
+ if (reason != NULL) {
+ inhibit->reason = g_strdup(reason);
+ } else {
+ inhibit->reason = fu_device_problem_to_inhibit_reason(self, problem);
+ }
+ g_hash_table_insert(priv->inhibits, inhibit->inhibit_id, inhibit);
+
+ /* refresh */
+ fu_device_ensure_inhibits(self);
+
+ /* propagate to children */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN)) {
+ GPtrArray *children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child = g_ptr_array_index(children, i);
+ fu_device_inhibit(child, inhibit_id, reason);
+ }
+ }
+}
+
+/**
+ * fu_device_inhibit:
+ * @self: a #FuDevice
+ * @inhibit_id: an ID used for uninhibiting, e.g. `low-power`
+ * @reason: (nullable): a string, e.g. `Cannot update as foo [bar] needs reboot`
+ *
+ * Prevent the device from being updated, changing it from %FWUPD_DEVICE_FLAG_UPDATABLE
+ * to %FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN if not already inhibited.
+ *
+ * If the device already has an inhibit with the same @inhibit_id then the request
+ * is ignored.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_device_inhibit(FuDevice *self, const gchar *inhibit_id, const gchar *reason)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(inhibit_id != NULL);
+ fu_device_inhibit_full(self, FWUPD_DEVICE_PROBLEM_NONE, inhibit_id, reason);
+}
+
+/**
+ * fu_device_has_inhibit:
+ * @self: a #FuDevice
+ * @inhibit_id: an ID used for inhibiting, e.g. `low-power`
+ *
+ * Check if the device already has an inhibit with a specific ID.
+ *
+ * Returns: %TRUE if added
+ *
+ * Since: 1.8.0
+ **/
+gboolean
+fu_device_has_inhibit(FuDevice *self, const gchar *inhibit_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(inhibit_id != NULL, FALSE);
+
+ if (priv->inhibits == NULL)
+ return FALSE;
+ return g_hash_table_contains(priv->inhibits, inhibit_id);
+}
+
+/**
+ * fu_device_remove_problem:
+ * @self: a #FuDevice
+ * @problem: a #FwupdDeviceProblem, e.g. %FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
+ *
+ * Allow the device from being updated if there are no other inhibitors,
+ * changing it from %FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN to %FWUPD_DEVICE_FLAG_UPDATABLE.
+ *
+ * If the device already has no inhibit with the @inhibit_id then the request
+ * is ignored.
+ *
+ * Since: 1.8.1
+ **/
+void
+fu_device_remove_problem(FuDevice *self, FwupdDeviceProblem problem)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(problem != FWUPD_DEVICE_PROBLEM_UNKNOWN);
+ return fu_device_uninhibit(self, fwupd_device_problem_to_string(problem));
+}
+
+/**
+ * fu_device_add_problem:
+ * @self: a #FuDevice
+ * @problem: a #FwupdDeviceProblem, e.g. %FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
+ *
+ * Prevent the device from being updated, changing it from %FWUPD_DEVICE_FLAG_UPDATABLE
+ * to %FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN if not already inhibited.
+ *
+ * If the device already has an inhibit with the same @problem then the request
+ * is ignored.
+ *
+ * Since: 1.8.1
+ **/
+void
+fu_device_add_problem(FuDevice *self, FwupdDeviceProblem problem)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(problem != FWUPD_DEVICE_PROBLEM_UNKNOWN);
+ fu_device_inhibit_full(self, problem, NULL, NULL);
+}
+
+/**
+ * fu_device_uninhibit:
+ * @self: a #FuDevice
+ * @inhibit_id: an ID used for uninhibiting, e.g. `low-power`
+ *
+ * Allow the device from being updated if there are no other inhibitors,
+ * changing it from %FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN to %FWUPD_DEVICE_FLAG_UPDATABLE.
+ *
+ * If the device already has no inhibit with the @inhibit_id then the request
+ * is ignored.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_device_uninhibit(FuDevice *self, const gchar *inhibit_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(inhibit_id != NULL);
+
+ if (priv->inhibits == NULL)
+ return;
+ if (g_hash_table_remove(priv->inhibits, inhibit_id))
+ fu_device_ensure_inhibits(self);
+
+ /* propagate to children */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN)) {
+ GPtrArray *children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child = g_ptr_array_index(children, i);
+ fu_device_uninhibit(child, inhibit_id);
+ }
+ }
+}
+
+/**
+ * fu_device_ensure_id:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ 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 (priv->device_id_valid)
+ return TRUE;
+
+ /* nothing we can do! */
+ if (priv->physical_id == 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)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->logical_id;
+}
+
+/**
+ * fu_device_set_logical_id:
+ * @self: a #FuDevice
+ * @logical_id: a string, e.g. `dev2`
+ *
+ * Sets the logical ID on the device. This is designed to disambiguate devices
+ * with the same physical ID.
+ *
+ * Since: 1.1.2
+ **/
+void
+fu_device_set_logical_id(FuDevice *self, const gchar *logical_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->logical_id, logical_id) == 0)
+ return;
+
+ /* not allowed after ->probe() and ->setup() have completed */
+ if (priv->done_setup) {
+ g_warning("cannot change %s logical ID from %s to %s as "
+ "FuDevice->setup() has already completed",
+ fu_device_get_id(self),
+ priv->logical_id,
+ logical_id);
+ return;
+ }
+
+ g_free(priv->logical_id);
+ priv->logical_id = g_strdup(logical_id);
+ priv->device_id_valid = FALSE;
+ g_object_notify(G_OBJECT(self), "logical-id");
+}
+
+/**
+ * fu_device_get_backend_id:
+ * @self: a #FuDevice
+ *
+ * Gets the ID set for the device as recognized by the backend. This is typically
+ * a Linux sysfs path or USB platform ID. If unset, it also falls back to the
+ * physical ID as this may be the same value.
+ *
+ * Returns: a string value, or %NULL if never set.
+ *
+ * Since: 1.5.8
+ **/
+const gchar *
+fu_device_get_backend_id(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ if (priv->backend_id != NULL)
+ return priv->backend_id;
+ return priv->physical_id;
+}
+
+/**
+ * fu_device_set_backend_id:
+ * @self: a #FuDevice
+ * @backend_id: a string, e.g. `dev2`
+ *
+ * Sets the backend ID on the device. This is designed to disambiguate devices
+ * with the same physical ID. This is typically a Linux sysfs path or USB
+ * platform ID.
+ *
+ * Since: 1.5.8
+ **/
+void
+fu_device_set_backend_id(FuDevice *self, const gchar *backend_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->backend_id, backend_id) == 0)
+ return;
+
+ g_free(priv->backend_id);
+ priv->backend_id = g_strdup(backend_id);
+ priv->device_id_valid = FALSE;
+ g_object_notify(G_OBJECT(self), "backend-id");
+}
+
+/**
+ * fu_device_get_update_request_id:
+ * @self: a #FuDevice
+ *
+ * Gets the update request ID as specified from `LVFS::UpdateRequestId`.
+ *
+ * Returns: a string value, or %NULL if never set.
+ *
+ * Since: 1.8.6
+ **/
+const gchar *
+fu_device_get_update_request_id(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->update_request_id;
+}
+
+/**
+ * fu_device_set_update_request_id:
+ * @self: a #FuDevice
+ * @update_request_id: a string, e.g. `org.freedesktop.fwupd.request.do-not-power-off`
+ *
+ * Sets the update request ID as specified in `LVFS::UpdateRequestId`.
+ *
+ * Since: 1.8.6
+ **/
+void
+fu_device_set_update_request_id(FuDevice *self, const gchar *update_request_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->update_request_id, update_request_id) == 0)
+ return;
+
+ g_free(priv->update_request_id);
+ priv->update_request_id = g_strdup(update_request_id);
+}
+
+/**
+ * fu_device_get_proxy_guid:
+ * @self: a #FuDevice
+ *
+ * Gets the proxy GUID device, which which is set to let the engine match up the
+ * proxy between plugins.
+ *
+ * Returns: a string value, or %NULL if never set.
+ *
+ * Since: 1.4.1
+ **/
+const gchar *
+fu_device_get_proxy_guid(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->proxy_guid;
+}
+
+/**
+ * fu_device_set_proxy_guid:
+ * @self: a #FuDevice
+ * @proxy_guid: a string, e.g. `USB\VID_413C&PID_B06E&hub`
+ *
+ * Sets the GUID of the proxy device. The proxy device may update @self.
+ *
+ * Since: 1.4.1
+ **/
+void
+fu_device_set_proxy_guid(FuDevice *self, const gchar *proxy_guid)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* not changed */
+ if (g_strcmp0(priv->proxy_guid, proxy_guid) == 0)
+ return;
+
+ g_free(priv->proxy_guid);
+ priv->proxy_guid = g_strdup(proxy_guid);
+}
+
+/**
+ * fu_device_set_physical_id:
+ * @self: a #FuDevice
+ * @physical_id: a string that identifies the physical device connection
+ *
+ * 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.
+ *
+ * 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_physical_id(FuDevice *self, const gchar *physical_id)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(physical_id != NULL);
+
+ /* not changed */
+ if (g_strcmp0(priv->physical_id, physical_id) == 0)
+ return;
+
+ /* not allowed after ->probe() and ->setup() have completed */
+ if (priv->done_setup) {
+ g_warning("cannot change %s physical ID from %s to %s as "
+ "FuDevice->setup() has already completed",
+ fu_device_get_id(self),
+ priv->physical_id,
+ physical_id);
+ return;
+ }
+
+ g_free(priv->physical_id);
+ priv->physical_id = g_strdup(physical_id);
+ priv->device_id_valid = FALSE;
+ g_object_notify(G_OBJECT(self), "physical-id");
+}
+
+/**
+ * fu_device_get_physical_id:
+ * @self: a #FuDevice
+ *
+ * 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.1.2
+ **/
+const gchar *
+fu_device_get_physical_id(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->physical_id;
+}
+
+/**
+ * fu_device_remove_flag:
+ * @self: a #FuDevice
+ * @flag: a device flag
+ *
+ * Removes a device flag from the device.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_device_remove_flag(FuDevice *self, FwupdDeviceFlags flag)
+{
+ /* proxy */
+ fwupd_device_remove_flag(FWUPD_DEVICE(self), flag);
+
+ /* allow it to be updatable again */
+ if (flag & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)
+ fu_device_uninhibit(self, "needs-activation");
+ if (flag & FWUPD_DEVICE_FLAG_UNREACHABLE)
+ fu_device_uninhibit(self, "unreachable");
+}
+
+/**
+ * fu_device_add_flag:
+ * @self: a #FuDevice
+ * @flag: a device flag
+ *
+ * Adds a device flag to the device.
+ *
+ * Since: 0.1.0
+ **/
+void
+fu_device_add_flag(FuDevice *self, FwupdDeviceFlags flag)
+{
+ /* none is not used as an "exported" flag */
+ if (flag == FWUPD_DEVICE_FLAG_NONE)
+ return;
+
+ /* being both a bootloader and requiring a bootloader is invalid */
+ if (flag & FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER)
+ fu_device_remove_flag(self, FWUPD_DEVICE_FLAG_IS_BOOTLOADER);
+ if (flag & FWUPD_DEVICE_FLAG_IS_BOOTLOADER)
+ fu_device_remove_flag(self, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER);
+
+ /* being both a signed and unsigned is invalid */
+ if (flag & FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD)
+ fu_device_remove_flag(self, FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD);
+ if (flag & FWUPD_DEVICE_FLAG_UNSIGNED_PAYLOAD)
+ fu_device_remove_flag(self, FWUPD_DEVICE_FLAG_SIGNED_PAYLOAD);
+
+ /* one implies the other */
+ if (flag & FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE)
+ flag |= FWUPD_DEVICE_FLAG_CAN_VERIFY;
+ if (flag & FWUPD_DEVICE_FLAG_INSTALL_ALL_RELEASES)
+ flag |= FWUPD_DEVICE_FLAG_VERSION_CHECK_REQUIRED;
+ fwupd_device_add_flag(FWUPD_DEVICE(self), flag);
+
+ /* activatable devices shouldn't be allowed to update again until activated */
+ /* don't let devices be updated until activated */
+ if (flag & FWUPD_DEVICE_FLAG_NEEDS_ACTIVATION)
+ fu_device_inhibit(self, "needs-activation", "Pending activation");
+
+ /* do not let devices be updated until back in range */
+ if (flag & FWUPD_DEVICE_FLAG_UNREACHABLE)
+ fu_device_add_problem(self, FWUPD_DEVICE_PROBLEM_UNREACHABLE);
+}
+
+typedef struct {
+ guint64 value;
+ gchar *value_str;
+} FuDevicePrivateFlagItem;
+
+static void
+fu_device_private_flag_item_free(FuDevicePrivateFlagItem *item)
+{
+ g_free(item->value_str);
+ g_free(item);
+}
+
+static FuDevicePrivateFlagItem *
+fu_device_private_flag_item_find_by_str(FuDevice *self, const gchar *value_str)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ if (priv->private_flag_items == NULL)
+ return NULL;
+ for (guint i = 0; i < priv->private_flag_items->len; i++) {
+ FuDevicePrivateFlagItem *item = g_ptr_array_index(priv->private_flag_items, i);
+ if (g_strcmp0(item->value_str, value_str) == 0)
+ return item;
+ }
+ return NULL;
+}
+
+static FuDevicePrivateFlagItem *
+fu_device_private_flag_item_find_by_val(FuDevice *self, guint64 value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ if (priv->private_flag_items == NULL)
+ return NULL;
+ for (guint i = 0; i < priv->private_flag_items->len; i++) {
+ FuDevicePrivateFlagItem *item = g_ptr_array_index(priv->private_flag_items, i);
+ if (item->value == value)
+ return item;
+ }
+ return NULL;
+}
+
+/**
+ * fu_device_register_private_flag:
+ * @self: a #FuDevice
+ * @value: an integer value
+ * @value_str: a string that represents @value
+ *
+ * Registers a private device flag so that it can be set from quirk files.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_register_private_flag(FuDevice *self, guint64 value, const gchar *value_str)
+{
+ FuDevicePrivateFlagItem *item;
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(value != 0);
+ g_return_if_fail(value_str != NULL);
+
+ /* ensure exists */
+ if (priv->private_flag_items == NULL) {
+ priv->private_flag_items = g_ptr_array_new_with_free_func(
+ (GDestroyNotify)fu_device_private_flag_item_free);
+ }
+
+ /* sanity check */
+ item = fu_device_private_flag_item_find_by_val(self, value);
+ if (item != NULL) {
+ g_critical("already registered private %s flag with value: %s:0x%x",
+ G_OBJECT_TYPE_NAME(self),
+ value_str,
+ (guint)value);
+ return;
+ }
+ item = fu_device_private_flag_item_find_by_str(self, value_str);
+ if (item != NULL) {
+ g_critical("already registered private %s flag with string: %s:0x%x",
+ G_OBJECT_TYPE_NAME(self),
+ value_str,
+ (guint)value);
+ return;
+ }
+
+ /* add new */
+ item = g_new0(FuDevicePrivateFlagItem, 1);
+ item->value = value;
+ item->value_str = g_strdup(value_str);
+ g_ptr_array_add(priv->private_flag_items, item);
+}
+
+static void
+fu_device_set_custom_flag(FuDevice *self, const gchar *hint)
+{
+ FwupdDeviceFlags flag;
+ FuDevicePrivateFlagItem *item;
+ FuDeviceInternalFlags internal_flag;
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ /* is this a negated device flag */
+ if (g_str_has_prefix(hint, "~")) {
+ flag = fwupd_device_flag_from_string(hint + 1);
+ if (flag != FWUPD_DEVICE_FLAG_UNKNOWN) {
+ fu_device_remove_flag(self, flag);
+ return;
+ }
+ internal_flag = fu_device_internal_flag_from_string(hint + 1);
+ if (internal_flag != FU_DEVICE_INTERNAL_FLAG_UNKNOWN) {
+ fu_device_remove_internal_flag(self, internal_flag);
+ return;
+ }
+ item = fu_device_private_flag_item_find_by_str(self, hint + 1);
+ if (item != NULL) {
+ priv->private_flags &= ~item->value;
+ return;
+ }
+ return;
+ }
+
+ /* is this a known device flag */
+ flag = fwupd_device_flag_from_string(hint);
+ if (flag != FWUPD_DEVICE_FLAG_UNKNOWN) {
+ fu_device_add_flag(self, flag);
+ return;
+ }
+ internal_flag = fu_device_internal_flag_from_string(hint);
+ if (internal_flag != FU_DEVICE_INTERNAL_FLAG_UNKNOWN) {
+ fu_device_add_internal_flag(self, internal_flag);
+ return;
+ }
+ item = fu_device_private_flag_item_find_by_str(self, hint);
+ if (item != NULL) {
+ priv->private_flags |= item->value;
+ return;
+ }
+}
+
+/**
+ * fu_device_set_custom_flags:
+ * @self: a #FuDevice
+ * @custom_flags: a string
+ *
+ * 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.1.0
+ **/
+void
+fu_device_set_custom_flags(FuDevice *self, const gchar *custom_flags)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(custom_flags != NULL);
+
+ /* save what was set so we can use it for incorporating a superclass */
+ g_free(priv->custom_flags);
+ priv->custom_flags = g_strdup(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_get_custom_flags:
+ * @self: a #FuDevice
+ *
+ * Gets the custom flags for the device from the quirk system.
+ *
+ * Returns: a string value, or %NULL if never set.
+ *
+ * Since: 1.1.0
+ **/
+const gchar *
+fu_device_get_custom_flags(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->custom_flags;
+}
+
+/**
+ * fu_device_get_remove_delay:
+ * @self: a #FuDevice
+ *
+ * Returns the maximum delay expected when replugging the device going into
+ * bootloader mode.
+ *
+ * Returns: time in milliseconds
+ *
+ * Since: 1.0.2
+ **/
+guint
+fu_device_get_remove_delay(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), 0);
+ return priv->remove_delay;
+}
+
+/**
+ * fu_device_set_remove_delay:
+ * @self: a #FuDevice
+ * @remove_delay: the value in milliseconds
+ *
+ * Sets the amount of time a device is allowed to return in bootloader mode.
+ *
+ * NOTE: this should be less than 3000ms for devices that just have to reset
+ * and automatically re-enumerate, but significantly longer if it involves a
+ * user removing a cable, pressing several buttons and removing a cable.
+ * A suggested value for this would be 10,000ms.
+ *
+ * Since: 1.0.2
+ **/
+void
+fu_device_set_remove_delay(FuDevice *self, guint remove_delay)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->remove_delay = remove_delay;
+}
+
+/**
+ * fu_device_get_acquiesce_delay:
+ * @self: a #FuDevice
+ *
+ * Returns the time the daemon should wait for devices to finish hotplugging
+ * after the update has completed.
+ *
+ * Returns: time in milliseconds
+ *
+ * Since: 1.8.3
+ **/
+guint
+fu_device_get_acquiesce_delay(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), 0);
+ return priv->acquiesce_delay;
+}
+
+/**
+ * fu_device_set_acquiesce_delay:
+ * @self: a #FuDevice
+ * @acquiesce_delay: the value in milliseconds
+ *
+ * Sets the time the daemon should wait for devices to finish hotplugging
+ * after the update has completed.
+ *
+ * Devices subclassing from [class@FuUsbDevice] and [class@FuUdevDevice] use
+ * a value of 2,500ms, and other devices use 50ms by default. This can be also
+ * be set using `AcquiesceDelay=` in a quirk file.
+ *
+ * Since: 1.8.3
+ **/
+void
+fu_device_set_acquiesce_delay(FuDevice *self, guint acquiesce_delay)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ priv->acquiesce_delay = acquiesce_delay;
+}
+
+/**
+ * fu_device_set_update_state:
+ * @self: a #FuDevice
+ * @update_state: the state, e.g. %FWUPD_UPDATE_STATE_PENDING
+ *
+ * Sets the update state, clearing the update error as required.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_set_update_state(FuDevice *self, FwupdUpdateState update_state)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ if (update_state == FWUPD_UPDATE_STATE_SUCCESS ||
+ update_state == FWUPD_UPDATE_STATE_PENDING ||
+ update_state == FWUPD_UPDATE_STATE_NEEDS_REBOOT)
+ fu_device_set_update_error(self, NULL);
+ fwupd_device_set_update_state(FWUPD_DEVICE(self), update_state);
+}
+
+static void
+fu_device_ensure_battery_inhibit(FuDevice *self)
+{
+ if (fu_device_get_battery_level(self) == FWUPD_BATTERY_LEVEL_INVALID ||
+ fu_device_get_battery_level(self) >= fu_device_get_battery_threshold(self)) {
+ fu_device_remove_problem(self, FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW);
+ return;
+ }
+ fu_device_add_problem(self, FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW);
+}
+
+/**
+ * fu_device_get_battery_level:
+ * @self: a #FuDevice
+ *
+ * Returns the battery level.
+ *
+ * Returns: value in percent
+ *
+ * Since: 1.5.8
+ **/
+guint
+fu_device_get_battery_level(FuDevice *self)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), G_MAXUINT);
+
+ /* use the parent if the child is unset */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_BATTERY) &&
+ fwupd_device_get_battery_level(FWUPD_DEVICE(self)) == FWUPD_BATTERY_LEVEL_INVALID) {
+ FuDevice *parent = fu_device_get_parent(self);
+ if (parent != NULL)
+ return fu_device_get_battery_level(parent);
+ }
+ return fwupd_device_get_battery_level(FWUPD_DEVICE(self));
+}
+
+/**
+ * fu_device_set_battery_level:
+ * @self: a #FuDevice
+ * @battery_level: the percentage value
+ *
+ * Sets the battery level, or %FWUPD_BATTERY_LEVEL_INVALID.
+ *
+ * Setting this allows fwupd to show a warning if the device change is too low
+ * to perform the update.
+ *
+ * Since: 1.5.8
+ **/
+void
+fu_device_set_battery_level(FuDevice *self, guint battery_level)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(battery_level <= FWUPD_BATTERY_LEVEL_INVALID);
+ fwupd_device_set_battery_level(FWUPD_DEVICE(self), battery_level);
+ fu_device_ensure_battery_inhibit(self);
+}
+
+/**
+ * fu_device_get_battery_threshold:
+ * @self: a #FuDevice
+ *
+ * Returns the battery threshold under which a firmware update cannot be
+ * performed.
+ *
+ * If fu_device_set_battery_threshold() has not been used, a default value is
+ * used instead.
+ *
+ * Returns: value in percent
+ *
+ * Since: 1.6.0
+ **/
+guint
+fu_device_get_battery_threshold(FuDevice *self)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), FWUPD_BATTERY_LEVEL_INVALID);
+
+ /* use the parent if the child is unset */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_BATTERY) &&
+ fwupd_device_get_battery_threshold(FWUPD_DEVICE(self)) == FWUPD_BATTERY_LEVEL_INVALID) {
+ FuDevice *parent = fu_device_get_parent(self);
+ if (parent != NULL)
+ return fu_device_get_battery_threshold(parent);
+ }
+ return fwupd_device_get_battery_threshold(FWUPD_DEVICE(self));
+}
+
+/**
+ * fu_device_set_battery_threshold:
+ * @self: a #FuDevice
+ * @battery_threshold: the percentage value
+ *
+ * Sets the battery level, or %FWUPD_BATTERY_LEVEL_INVALID for the default.
+ *
+ * Setting this allows fwupd to show a warning if the device change is too low
+ * to perform the update.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_device_set_battery_threshold(FuDevice *self, guint battery_threshold)
+{
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(battery_threshold <= FWUPD_BATTERY_LEVEL_INVALID);
+ fwupd_device_set_battery_threshold(FWUPD_DEVICE(self), battery_threshold);
+ fu_device_ensure_battery_inhibit(self);
+}
+
+/**
+ * fu_device_add_string:
+ * @self: a #FuDevice
+ * @idt: indent level
+ * @str: a string to append to
+ *
+ * Add daemon-specific device metadata to an existing string.
+ *
+ * Since: 1.7.1
+ **/
+void
+fu_device_add_string(FuDevice *self, guint idt, GString *str)
+{
+ GPtrArray *children;
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_autofree gchar *tmp = NULL;
+ g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new(&priv->metadata_mutex);
+
+ g_return_if_fail(locker != NULL);
+
+ tmp = fwupd_device_to_string(FWUPD_DEVICE(self));
+ if (tmp != NULL && tmp[0] != '\0')
+ g_string_append(str, tmp);
+ if (priv->alternate_id != NULL)
+ fu_string_append(str, idt + 1, "AlternateId", priv->alternate_id);
+ if (priv->equivalent_id != NULL)
+ fu_string_append(str, idt + 1, "EquivalentId", priv->equivalent_id);
+ if (priv->physical_id != NULL)
+ fu_string_append(str, idt + 1, "PhysicalId", priv->physical_id);
+ if (priv->logical_id != NULL)
+ fu_string_append(str, idt + 1, "LogicalId", priv->logical_id);
+ if (priv->backend_id != NULL)
+ fu_string_append(str, idt + 1, "BackendId", priv->backend_id);
+ if (priv->update_request_id != NULL)
+ fu_string_append(str, idt + 1, "UpdateRequestId", priv->update_request_id);
+ if (priv->proxy != NULL)
+ fu_string_append(str, idt + 1, "ProxyId", fu_device_get_id(priv->proxy));
+ if (priv->proxy_guid != NULL)
+ fu_string_append(str, idt + 1, "ProxyGuid", priv->proxy_guid);
+ if (priv->remove_delay != 0)
+ fu_string_append_ku(str, idt + 1, "RemoveDelay", priv->remove_delay);
+ if (priv->acquiesce_delay != 0)
+ fu_string_append_ku(str, idt + 1, "AcquiesceDelay", priv->acquiesce_delay);
+ if (priv->custom_flags != NULL)
+ fu_string_append(str, idt + 1, "CustomFlags", priv->custom_flags);
+ if (priv->firmware_gtype != G_TYPE_INVALID) {
+ fu_string_append(str, idt + 1, "FirmwareGType", g_type_name(priv->firmware_gtype));
+ }
+ if (priv->size_min > 0) {
+ g_autofree gchar *sz = g_strdup_printf("%" G_GUINT64_FORMAT, priv->size_min);
+ fu_string_append(str, idt + 1, "FirmwareSizeMin", sz);
+ }
+ if (priv->size_max > 0) {
+ g_autofree gchar *sz = g_strdup_printf("%" G_GUINT64_FORMAT, priv->size_max);
+ fu_string_append(str, idt + 1, "FirmwareSizeMax", sz);
+ }
+ if (priv->order != G_MAXINT) {
+ g_autofree gchar *order = g_strdup_printf("%i", priv->order);
+ fu_string_append(str, idt + 1, "Order", order);
+ }
+ if (priv->priority > 0)
+ fu_string_append_ku(str, idt + 1, "Priority", priv->priority);
+ if (priv->metadata != NULL) {
+ g_autoptr(GList) 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);
+ fu_string_append(str, idt + 1, key, value);
+ }
+ }
+ for (guint i = 0; i < priv->possible_plugins->len; i++) {
+ const gchar *name = g_ptr_array_index(priv->possible_plugins, i);
+ fu_string_append(str, idt + 1, "PossiblePlugin", name);
+ }
+ if (priv->parent_physical_ids != NULL && priv->parent_physical_ids->len > 0) {
+ g_autofree gchar *flags = fu_strjoin(",", priv->parent_physical_ids);
+ fu_string_append(str, idt + 1, "ParentPhysicalIds", flags);
+ }
+ if (priv->internal_flags != FU_DEVICE_INTERNAL_FLAG_NONE) {
+ g_autoptr(GString) tmp2 = g_string_new("");
+ for (guint i = 0; i < 64; i++) {
+ if ((priv->internal_flags & ((guint64)1 << i)) == 0)
+ continue;
+ g_string_append_printf(tmp2,
+ "%s|",
+ fu_device_internal_flag_to_string((guint64)1 << i));
+ }
+ if (tmp2->len > 0)
+ g_string_truncate(tmp2, tmp2->len - 1);
+ fu_string_append(str, idt + 1, "InternalFlags", tmp2->str);
+ }
+ if (priv->private_flags > 0) {
+ g_autoptr(GPtrArray) tmpv = g_ptr_array_new();
+ g_autofree gchar *tmps = NULL;
+ for (guint64 i = 0; i < 64; i++) {
+ FuDevicePrivateFlagItem *item;
+ guint64 value = 1ull << i;
+ if ((priv->private_flags & value) == 0)
+ continue;
+ item = fu_device_private_flag_item_find_by_val(self, value);
+ if (item == NULL)
+ continue;
+ g_ptr_array_add(tmpv, item->value_str);
+ }
+ tmps = fu_strjoin(",", tmpv);
+ fu_string_append(str, idt + 1, "PrivateFlags", tmps);
+ }
+ if (priv->inhibits != NULL) {
+ g_autoptr(GList) values = g_hash_table_get_values(priv->inhibits);
+ for (GList *l = values; l != NULL; l = l->next) {
+ FuDeviceInhibit *inhibit = (FuDeviceInhibit *)l->data;
+ g_autofree gchar *val =
+ g_strdup_printf("[%s] %s", inhibit->inhibit_id, inhibit->reason);
+ fu_string_append(str, idt + 1, "Inhibit", val);
+ }
+ }
+
+ /* subclassed */
+ if (klass->to_string != NULL)
+ klass->to_string(self, idt + 1, str);
+
+ /* print children also */
+ children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child = g_ptr_array_index(children, i);
+ fu_device_add_string(child, idt + 1, str);
+ }
+}
+
+/**
+ * fu_device_to_string:
+ * @self: a #FuDevice
+ *
+ * This allows us to easily print the device, the release and the
+ * daemon-specific metadata.
+ *
+ * Returns: a string value, or %NULL for invalid.
+ *
+ * Since: 0.9.8
+ **/
+gchar *
+fu_device_to_string(FuDevice *self)
+{
+ GString *str = g_string_new(NULL);
+ fu_device_add_string(self, 0, str);
+ return g_string_free(str, FALSE);
+}
+
+/**
+ * fu_device_set_context:
+ * @self: a #FuDevice
+ * @ctx: (nullable): optional #FuContext
+ *
+ * Sets the optional context which may be useful to this device.
+ * This is typically set after the device has been created, but before
+ * the device has been opened or probed.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_device_set_context(FuDevice *self, FuContext *ctx)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(FU_IS_CONTEXT(ctx) || ctx == NULL);
+
+#ifndef SUPPORTED_BUILD
+ if (priv->ctx != NULL && ctx == NULL) {
+ g_critical("clearing device context for %s [%s]",
+ fu_device_get_name(self),
+ fu_device_get_id(self));
+ return;
+ }
+#endif
+
+ if (g_set_object(&priv->ctx, ctx))
+ g_object_notify(G_OBJECT(self), "context");
+}
+
+/**
+ * fu_device_get_context:
+ * @self: a #FuDevice
+ *
+ * Gets the context assigned for this device.
+ *
+ * Returns: (transfer none): the #FuContext object, or %NULL
+ *
+ * Since: 1.6.0
+ **/
+FuContext *
+fu_device_get_context(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ return priv->ctx;
+}
+
+/**
+ * fu_device_get_release_default:
+ * @self: a #FuDevice
+ *
+ * Gets the default release for the device, creating one if not found.
+ *
+ * Returns: (transfer none): the #FwupdRelease object
+ *
+ * Since: 1.0.5
+ **/
+FwupdRelease *
+fu_device_get_release_default(FuDevice *self)
+{
+ g_autoptr(FwupdRelease) rel = NULL;
+ 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(self), rel);
+ return rel;
+}
+
+/**
+ * fu_device_get_results:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * Gets the results of the last update operation on the device by calling a vfunc.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.6.2
+ **/
+gboolean
+fu_device_get_results(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->get_results == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "getting results not supported by device");
+ return FALSE;
+ }
+
+ /* call vfunc */
+ return klass->get_results(self, error);
+}
+
+/**
+ * fu_device_write_firmware:
+ * @self: a #FuDevice
+ * @fw: firmware blob
+ * @progress: a #FuProgress
+ * @flags: install flags, e.g. %FWUPD_INSTALL_FLAG_FORCE
+ * @error: (nullable): optional return location for an error
+ *
+ * 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,
+ FuProgress *progress,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(FuFirmware) firmware = NULL;
+ g_autofree gchar *str = NULL;
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), 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,
+ "writing firmware not supported by device");
+ return FALSE;
+ }
+
+ /* prepare (e.g. decompress) firmware */
+ fu_progress_set_status(progress, FWUPD_STATUS_DECOMPRESSING);
+ firmware = fu_device_prepare_firmware(self, fw, flags, error);
+ if (firmware == NULL)
+ return FALSE;
+ str = fu_firmware_to_string(firmware);
+ g_debug("installing onto %s:\n%s", fu_device_get_id(self), str);
+
+ /* call vfunc */
+ if (!klass->write_firmware(self, firmware, progress, flags, error))
+ return FALSE;
+
+ /* the device set an UpdateMessage (possibly from a quirk, or XML file)
+ * but did not do an event; guess something */
+ if (priv->request_cnts[FWUPD_REQUEST_KIND_POST] == 0 &&
+ fu_device_get_update_message(self) != NULL) {
+ const gchar *update_request_id = fu_device_get_update_request_id(self);
+ g_autoptr(FwupdRequest) request = fwupd_request_new();
+ fwupd_request_set_kind(request, FWUPD_REQUEST_KIND_POST);
+ if (update_request_id != NULL) {
+ fwupd_request_set_id(request, update_request_id);
+ fwupd_request_add_flag(request, FWUPD_REQUEST_FLAG_ALLOW_GENERIC_MESSAGE);
+ }
+ fwupd_request_set_message(request, fu_device_get_update_message(self));
+ fwupd_request_set_image(request, fu_device_get_update_image(self));
+ fu_device_emit_request(self, request);
+ }
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * fu_device_prepare_firmware:
+ * @self: a #FuDevice
+ * @fw: firmware blob
+ * @flags: install flags, e.g. %FWUPD_INSTALL_FLAG_FORCE
+ * @error: (nullable): optional return location for an error
+ *
+ * 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
+ **/
+FuFirmware *
+fu_device_prepare_firmware(FuDevice *self, GBytes *fw, FwupdInstallFlags flags, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_autoptr(FuFirmware) firmware = NULL;
+ g_autoptr(GBytes) fw_def = 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) {
+ firmware = klass->prepare_firmware(self, fw, flags, error);
+ if (firmware == NULL)
+ return NULL;
+ } else if (priv->firmware_gtype != G_TYPE_INVALID) {
+ firmware = g_object_new(priv->firmware_gtype, NULL);
+ if (!fu_firmware_parse(firmware, fw, flags, error))
+ return NULL;
+ } else {
+ firmware = fu_firmware_new_from_bytes(fw);
+ }
+
+ /* check size */
+ fw_def = fu_firmware_get_bytes(firmware, NULL);
+ if (fw_def != NULL) {
+ guint64 fw_sz = (guint64)g_bytes_get_size(fw_def);
+ if (priv->size_max > 0 && fw_sz > priv->size_max) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "firmware is 0x%04x bytes larger than the allowed "
+ "maximum size of 0x%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;
+ }
+ }
+
+ /* success */
+ return g_steal_pointer(&firmware);
+}
+
+/**
+ * fu_device_read_firmware:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads firmware from the device by calling a plugin-specific vfunc.
+ * The device subclass should try to ensure the firmware does not contain any
+ * serial numbers or user-configuration values and can be used to calculate the
+ * device checksum.
+ *
+ * The return value can be converted to a blob of memory using fu_firmware_write().
+ *
+ * Returns: (transfer full): a #FuFirmware, or %NULL for error
+ *
+ * Since: 1.0.8
+ **/
+FuFirmware *
+fu_device_read_firmware(FuDevice *self, FuProgress *progress, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ g_autoptr(GBytes) fw = NULL;
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* device does not support reading for verification CRCs */
+ if (!fu_device_has_flag(self, FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE)) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "reading firmware is not supported by device");
+ return NULL;
+ }
+
+ /* call vfunc */
+ if (klass->read_firmware != NULL)
+ return klass->read_firmware(self, progress, error);
+
+ /* use the default FuFirmware when only ->dump_firmware is provided */
+ fw = fu_device_dump_firmware(self, progress, error);
+ if (fw == NULL)
+ return NULL;
+ return fu_firmware_new_from_bytes(fw);
+}
+
+/**
+ * fu_device_dump_firmware:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * Reads the raw firmware image from the device by calling a plugin-specific
+ * vfunc. This raw firmware image may contain serial numbers or device-specific
+ * configuration but should be a byte-for-byte match compared to using an
+ * external SPI programmer.
+ *
+ * Returns: (transfer full): a #GBytes, or %NULL for error
+ *
+ * Since: 1.5.0
+ **/
+GBytes *
+fu_device_dump_firmware(FuDevice *self, FuProgress *progress, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* use the default FuFirmware when only ->dump_firmware is provided */
+ if (klass->dump_firmware == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "dumping firmware is not supported by device");
+ return NULL;
+ }
+
+ /* proxy */
+ return klass->dump_firmware(self, progress, error);
+}
+
+/**
+ * fu_device_detach:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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)
+{
+ g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
+ return fu_device_detach_full(self, progress, error);
+}
+
+/**
+ * fu_device_detach_full:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * Detaches a device from the application into bootloader mode.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.7.0
+ **/
+gboolean
+fu_device_detach_full(FuDevice *self, FuProgress *progress, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* no plugin-specific method */
+ if (klass->detach == NULL)
+ return TRUE;
+
+ /* call vfunc */
+ return klass->detach(self, progress, error);
+}
+
+/**
+ * fu_device_attach:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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)
+{
+ g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC);
+ return fu_device_attach_full(self, progress, error);
+}
+
+/**
+ * fu_device_attach_full:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * Attaches a device from the bootloader into application mode.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.7.0
+ **/
+gboolean
+fu_device_attach_full(FuDevice *self, FuProgress *progress, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* no plugin-specific method */
+ if (klass->attach == NULL)
+ return TRUE;
+
+ /* call vfunc */
+ return klass->attach(self, progress, error);
+}
+
+/**
+ * fu_device_reload:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * Reloads a device that has just gone from bootloader into application mode.
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.3.3
+ **/
+gboolean
+fu_device_reload(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->reload == NULL)
+ return TRUE;
+
+ /* call vfunc */
+ return klass->reload(self, error);
+}
+
+/**
+ * fu_device_prepare:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @flags: install flags
+ * @error: (nullable): optional return location for an error
+ *
+ * Prepares a device for update. A different plugin can handle each of
+ * FuDevice->prepare(), FuDevice->detach() and FuDevice->write_firmware().
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.3.3
+ **/
+gboolean
+fu_device_prepare(FuDevice *self, FuProgress *progress, FwupdInstallFlags flags, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* no plugin-specific method */
+ if (klass->prepare == NULL)
+ return TRUE;
+
+ /* call vfunc */
+ return klass->prepare(self, progress, flags, error);
+}
+
+/**
+ * fu_device_cleanup:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @flags: install flags
+ * @error: (nullable): optional return location for an error
+ *
+ * Cleans up a device after an update. A different plugin can handle each of
+ * FuDevice->write_firmware(), FuDevice->attach() and FuDevice->cleanup().
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 1.3.3
+ **/
+gboolean
+fu_device_cleanup(FuDevice *self, FuProgress *progress, FwupdInstallFlags flags, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* no plugin-specific method */
+ if (klass->cleanup == NULL)
+ return TRUE;
+
+ /* call vfunc */
+ return klass->cleanup(self, progress, flags, error);
+}
+
+static gboolean
+fu_device_open_cb(FuDevice *self, gpointer user_data, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ return klass->open(self, error);
+}
+
+static gboolean
+fu_device_open_internal(FuDevice *self, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ /* 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 (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN)) {
+ if (!fu_device_retry_full(self,
+ fu_device_open_cb,
+ FU_DEVICE_RETRY_OPEN_COUNT,
+ FU_DEVICE_RETRY_OPEN_DELAY,
+ NULL,
+ error))
+ return FALSE;
+ } else {
+ if (!klass->open(self, error))
+ return FALSE;
+ }
+ }
+
+ /* setup */
+ if (!fu_device_setup(self, error))
+ return FALSE;
+
+ /* ensure the device ID is still valid */
+ if (!fu_device_ensure_id(self, error))
+ return FALSE;
+
+ /* success */
+ fu_device_add_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_IS_OPEN);
+ return TRUE;
+}
+
+/**
+ * fu_device_open:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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.
+ *
+ * If the `->probe()`, `->open()` and `->setup()` actions all complete
+ * successfully the internal device flag %FU_DEVICE_INTERNAL_FLAG_IS_OPEN will
+ * be set.
+ *
+ * NOTE: It is important to still call fu_device_close() even if this function
+ * fails as the device may still be partially initialized.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.1.2
+ **/
+gboolean
+fu_device_open(FuDevice *self, GError **error)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* use parent */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN)) {
+ FuDevice *parent = fu_device_get_parent(self);
+ if (parent == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "no parent device");
+ return FALSE;
+ }
+ return fu_device_open_internal(parent, error);
+ }
+ return fu_device_open_internal(self, error);
+}
+
+static gboolean
+fu_device_close_internal(FuDevice *self, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ /* not yet open */
+ if (priv->open_refcount == 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOTHING_TO_DO,
+ "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 */
+ fu_device_remove_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_IS_OPEN);
+ return TRUE;
+}
+
+/**
+ * fu_device_close:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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.
+ *
+ * If the close action completed successfully the internal device flag
+ * %FU_DEVICE_INTERNAL_FLAG_IS_OPEN will be cleared.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.1.2
+ **/
+gboolean
+fu_device_close(FuDevice *self, GError **error)
+{
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* use parent */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN)) {
+ FuDevice *parent = fu_device_get_parent(self);
+ if (parent == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "no parent device");
+ return FALSE;
+ }
+ return fu_device_close_internal(parent, error);
+ }
+ return fu_device_close_internal(self, error);
+}
+
+/**
+ * fu_device_probe:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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;
+
+ /* device self-assigned */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_NO_PROBE)) {
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not probing");
+ return FALSE;
+ }
+
+ /* subclassed */
+ if (klass->probe != NULL) {
+ if (!klass->probe(self, error))
+ return FALSE;
+ }
+
+ /* vfunc skipped device */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_NO_PROBE)) {
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not probing");
+ return FALSE;
+ }
+
+ /* success */
+ priv->done_probe = TRUE;
+ return TRUE;
+}
+
+/**
+ * fu_device_rescan:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * Rescans a device, re-adding GUIDs or flags based on some hardware change.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 1.3.1
+ **/
+gboolean
+fu_device_rescan(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);
+
+ /* remove all GUIDs */
+ g_ptr_array_set_size(fu_device_get_instance_ids(self), 0);
+ g_ptr_array_set_size(fu_device_get_guids(self), 0);
+
+ /* subclassed */
+ if (klass->rescan != NULL) {
+ if (!klass->rescan(self, error)) {
+ fu_device_convert_instance_ids(self);
+ return FALSE;
+ }
+ }
+
+ fu_device_convert_instance_ids(self);
+ return TRUE;
+}
+
+/**
+ * fu_device_set_progress:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ *
+ * Sets steps on the progress object used to write firmware.
+ *
+ * Since: 1.7.0
+ **/
+void
+fu_device_set_progress(FuDevice *self, FuProgress *progress)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(FU_IS_PROGRESS(progress));
+
+ /* subclassed */
+ if (klass->set_progress == NULL)
+ return;
+ klass->set_progress(self, progress);
+}
+
+/**
+ * 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** %FU_DEVICE_INTERNAL_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)
+{
+ GPtrArray *instance_ids;
+
+ /* OEM specific hardware */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS))
+ return;
+ instance_ids = fwupd_device_get_instance_ids(FWUPD_DEVICE(self));
+ 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);
+ }
+}
+
+/**
+ * fu_device_setup:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * 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);
+ GPtrArray *children;
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* should have already been called */
+ if (!fu_device_probe(self, error))
+ return FALSE;
+
+ /* already done */
+ if (priv->done_setup)
+ return TRUE;
+
+ /* subclassed */
+ if (klass->setup != NULL) {
+ if (!klass->setup(self, error))
+ return FALSE;
+ }
+
+ /* vfunc skipped device */
+ if (fu_device_has_internal_flag(self, FU_DEVICE_INTERNAL_FLAG_NO_PROBE)) {
+ g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not probing");
+ return FALSE;
+ }
+
+ /* run setup on the children too (unless done already) */
+ children = fu_device_get_children(self);
+ for (guint i = 0; i < children->len; i++) {
+ FuDevice *child_tmp = g_ptr_array_index(children, i);
+ if (!fu_device_setup(child_tmp, error))
+ return FALSE;
+ }
+
+ /* convert the instance IDs to GUIDs */
+ fu_device_convert_instance_ids(self);
+
+ /* subclassed */
+ if (klass->ready != NULL) {
+ if (!klass->ready(self, error))
+ return FALSE;
+ }
+
+ priv->done_setup = TRUE;
+ return TRUE;
+}
+
+/**
+ * fu_device_activate:
+ * @self: a #FuDevice
+ * @progress: a #FuProgress
+ * @error: (nullable): optional return location for an error
+ *
+ * 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, FuProgress *progress, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(FU_IS_PROGRESS(progress), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* subclassed */
+ if (klass->activate != NULL) {
+ if (!klass->activate(self, progress, 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.
+ *
+ * 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_report_metadata_pre:
+ * @self: a #FuDevice
+ *
+ * Collects metadata that would be useful for debugging a failed update report.
+ *
+ * Returns: (transfer full) (nullable): a #GHashTable, or %NULL if there is no data
+ *
+ * Since: 1.5.0
+ **/
+GHashTable *
+fu_device_report_metadata_pre(FuDevice *self)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ g_autoptr(GHashTable) metadata = NULL;
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+
+ /* not implemented */
+ if (klass->report_metadata_pre == NULL)
+ return NULL;
+
+ /* metadata for all devices */
+ metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ klass->report_metadata_pre(self, metadata);
+ return g_steal_pointer(&metadata);
+}
+
+/**
+ * fu_device_report_metadata_post:
+ * @self: a #FuDevice
+ *
+ * Collects metadata that would be useful for debugging a failed update report.
+ *
+ * Returns: (transfer full) (nullable): a #GHashTable, or %NULL if there is no data
+ *
+ * Since: 1.5.0
+ **/
+GHashTable *
+fu_device_report_metadata_post(FuDevice *self)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+ g_autoptr(GHashTable) metadata = NULL;
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+
+ /* not implemented */
+ if (klass->report_metadata_post == NULL)
+ return NULL;
+
+ /* metadata for all devices */
+ metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ klass->report_metadata_post(self, metadata);
+ return g_steal_pointer(&metadata);
+}
+
+/**
+ * fu_device_add_security_attrs:
+ * @self: a #FuDevice
+ * @attrs: a security attribute
+ *
+ * Adds HSI security attributes.
+ *
+ * Since: 1.6.0
+ **/
+void
+fu_device_add_security_attrs(FuDevice *self, FuSecurityAttrs *attrs)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+
+ /* optional */
+ if (klass->add_security_attrs != NULL)
+ return klass->add_security_attrs(self, attrs);
+}
+
+/**
+ * fu_device_bind_driver:
+ * @self: a #FuDevice
+ * @subsystem: a subsystem string, e.g. `pci`
+ * @driver: a kernel module name, e.g. `tg3`
+ * @error: (nullable): optional return location for an error
+ *
+ * Binds a driver to the device, which normally means the kernel driver takes
+ * control of the hardware.
+ *
+ * Returns: %TRUE if driver was bound.
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fu_device_bind_driver(FuDevice *self, const gchar *subsystem, const gchar *driver, GError **error)
+{
+ FuDeviceClass *klass = FU_DEVICE_GET_CLASS(self);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(subsystem != NULL, FALSE);
+ g_return_val_if_fail(driver != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* not implemented */
+ if (klass->bind_driver == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "binding drivers is not supported by device");
+ return FALSE;
+ }
+
+ /* subclass */
+ return klass->bind_driver(self, subsystem, driver, error);
+}
+
+/**
+ * fu_device_unbind_driver:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ *
+ * Unbinds the driver from the device, which normally means the kernel releases
+ * the hardware so it can be used from userspace.
+ *
+ * If there is no driver bound then this function will return with success
+ * without actually doing anything.
+ *
+ * Returns: %TRUE if driver was unbound.
+ *
+ * Since: 1.5.0
+ **/
+gboolean
+fu_device_unbind_driver(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);
+
+ /* not implemented */
+ if (klass->unbind_driver == NULL) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "unbinding drivers is not supported by device");
+ return FALSE;
+ }
+
+ /* subclass */
+ return klass->unbind_driver(self, error);
+}
+
+static const gchar *
+fu_device_instance_lookup(FuDevice *self, const gchar *key)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ return g_hash_table_lookup(priv->instance_hash, key);
+}
+
+/**
+ * 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 *instance_ids = fu_device_get_instance_ids(donor);
+ GPtrArray *parent_guids = fu_device_get_parent_guids(donor);
+ GPtrArray *parent_physical_ids = fu_device_get_parent_physical_ids(donor);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ 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->physical_id == NULL && priv_donor->physical_id != NULL)
+ fu_device_set_physical_id(self, priv_donor->physical_id);
+ if (priv->logical_id == NULL && priv_donor->logical_id != NULL)
+ fu_device_set_logical_id(self, priv_donor->logical_id);
+ if (priv->backend_id == NULL && priv_donor->backend_id != NULL)
+ fu_device_set_backend_id(self, priv_donor->backend_id);
+ if (priv->update_request_id == NULL && priv_donor->update_request_id != NULL)
+ fu_device_set_update_request_id(self, priv_donor->update_request_id);
+ if (priv->proxy == NULL && priv_donor->proxy != NULL)
+ fu_device_set_proxy(self, priv_donor->proxy);
+ if (priv->proxy_guid == NULL && priv_donor->proxy_guid != NULL)
+ fu_device_set_proxy_guid(self, priv_donor->proxy_guid);
+ if (priv->custom_flags == NULL && priv_donor->custom_flags != NULL)
+ fu_device_set_custom_flags(self, priv_donor->custom_flags);
+ if (priv->ctx == NULL)
+ fu_device_set_context(self, fu_device_get_context(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);
+ if (parent_physical_ids != NULL) {
+ for (guint i = 0; i < parent_physical_ids->len; i++) {
+ const gchar *tmp = g_ptr_array_index(parent_physical_ids, i);
+ fu_device_add_parent_physical_id(self, tmp);
+ }
+ }
+ g_rw_lock_reader_lock(&priv_donor->metadata_mutex);
+ if (priv->metadata != NULL) {
+ g_hash_table_iter_init(&iter, priv_donor->metadata);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (fu_device_get_metadata(self, key) == NULL)
+ fu_device_set_metadata(self, key, value);
+ }
+ }
+ g_rw_lock_reader_unlock(&priv_donor->metadata_mutex);
+
+ /* probably not required, but seems safer */
+ for (guint i = 0; i < priv_donor->possible_plugins->len; i++) {
+ const gchar *possible_plugin = g_ptr_array_index(priv_donor->possible_plugins, i);
+ fu_device_add_possible_plugin(self, possible_plugin);
+ }
+
+ /* copy all instance ID keys if not already set */
+ g_hash_table_iter_init(&iter, priv_donor->instance_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (fu_device_instance_lookup(self, key) == NULL)
+ fu_device_add_instance_str(self, key, value);
+ }
+
+ /* now the base class, where all the interesting bits are */
+ fwupd_device_incorporate(FWUPD_DEVICE(self), FWUPD_DEVICE(donor));
+
+ /* set by the superclass */
+ if (fu_device_get_id(self) != NULL)
+ priv->device_id_valid = TRUE;
+
+ /* optional subclass */
+ if (klass->incorporate != NULL)
+ klass->incorporate(self, donor);
+
+ /* call the set_quirk_kv() vfunc for the superclassed object */
+ 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);
+ fu_device_add_guid_quirks(self, guid);
+ }
+}
+
+/**
+ * fu_device_incorporate_flag:
+ * @self: a #FuDevice
+ * @donor: another device
+ * @flag: device flags
+ *
+ * Copy the value of a specific flag from the donor object.
+ *
+ * Since: 1.3.5
+ **/
+void
+fu_device_incorporate_flag(FuDevice *self, FuDevice *donor, FwupdDeviceFlags flag)
+{
+ if (fu_device_has_flag(donor, flag) && !fu_device_has_flag(self, flag)) {
+ g_debug("donor set %s", fwupd_device_flag_to_string(flag));
+ fu_device_add_flag(self, flag);
+ } else if (!fu_device_has_flag(donor, flag) && fu_device_has_flag(self, flag)) {
+ g_debug("donor unset %s", fwupd_device_flag_to_string(flag));
+ fu_device_remove_flag(self, flag);
+ }
+}
+
+/**
+ * fu_device_incorporate_from_component: (skip):
+ * @device: a device
+ * @component: a Xmlb node
+ *
+ * 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);
+ tmp = xb_node_query_text(component, "custom/value[@key='LVFS::UpdateImage']", NULL);
+ if (tmp != NULL)
+ fwupd_device_set_update_image(FWUPD_DEVICE(self), tmp);
+}
+
+/**
+ * fu_device_emit_request:
+ * @self: a device
+ * @request: a request
+ *
+ * Emit a request from a plugin to the client.
+ *
+ * Since: 1.6.2
+ **/
+void
+fu_device_emit_request(FuDevice *self, FwupdRequest *request)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(FWUPD_IS_REQUEST(request));
+
+ /* sanity check */
+ if (fwupd_request_get_kind(request) == FWUPD_REQUEST_KIND_UNKNOWN) {
+ g_critical("a request must have an assigned kind");
+ return;
+ }
+ if (fwupd_request_get_id(request) == NULL) {
+ g_critical("a request must have an assigned ID");
+ return;
+ }
+ if (fwupd_request_get_kind(request) >= FWUPD_REQUEST_KIND_LAST) {
+ g_critical("invalid request kind");
+ return;
+ }
+
+ /* ensure set */
+ fwupd_request_set_device_id(request, fu_device_get_id(self));
+
+ /* for compatibility with older clients */
+ if (fwupd_request_get_kind(request) == FWUPD_REQUEST_KIND_POST) {
+ fu_device_set_update_message(self, fwupd_request_get_message(request));
+ fu_device_set_update_image(self, fwupd_request_get_image(request));
+ }
+
+ /* proxy to the engine */
+ g_signal_emit(self, signals[SIGNAL_REQUEST], 0, request);
+ priv->request_cnts[fwupd_request_get_kind(request)]++;
+}
+
+static void
+fu_device_flags_notify_cb(FuDevice *self, GParamSpec *pspec, gpointer user_data)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ /* we only inhibit when the flags contains UPDATABLE, and that might be discovered by
+ * probing the hardware *after* the battery level has been set */
+ if (priv->inhibits != NULL)
+ fu_device_ensure_inhibits(self);
+}
+
+/**
+ * fu_device_add_instance_str:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: (nullable): value
+ *
+ * Assign a value for the @key.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_str(FuDevice *self, const gchar *key, const gchar *value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash, g_strdup(key), g_strdup(value));
+}
+
+static gboolean
+fu_strsafe_instance_id_is_valid_char(gchar c)
+{
+ if (c == ' ')
+ return FALSE;
+ if (c == '_')
+ return FALSE;
+ if (c == '&')
+ return FALSE;
+ if (c == '/')
+ return FALSE;
+ if (c == '\\')
+ return FALSE;
+ return g_ascii_isprint(c);
+}
+
+/* NOTE: we can't use fu_strsafe as this behavior is now effectively ABI */
+static gchar *
+fu_common_instance_id_strsafe(const gchar *str)
+{
+ g_autoptr(GString) tmp = g_string_new(NULL);
+ gboolean has_content = FALSE;
+
+ /* sanity check */
+ if (str == NULL)
+ return NULL;
+
+ /* use - to replace problematic chars -- but only once per section */
+ for (guint i = 0; str[i] != '\0'; i++) {
+ gchar c = str[i];
+ if (!fu_strsafe_instance_id_is_valid_char(c)) {
+ if (has_content) {
+ g_string_append_c(tmp, '-');
+ has_content = FALSE;
+ }
+ } else {
+ g_string_append_c(tmp, c);
+ has_content = TRUE;
+ }
+ }
+
+ /* remove any trailing replacements */
+ if (tmp->len > 0 && tmp->str[tmp->len - 1] == '-')
+ g_string_truncate(tmp, tmp->len - 1);
+
+ /* nothing left! */
+ if (tmp->len == 0)
+ return NULL;
+
+ /* success */
+ return g_string_free(g_steal_pointer(&tmp), FALSE);
+}
+
+/**
+ * fu_device_add_instance_strsafe:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: (nullable): value
+ *
+ * Assign a sanitized value for the @key.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_strsafe(FuDevice *self, const gchar *key, const gchar *value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash,
+ g_strdup(key),
+ fu_common_instance_id_strsafe(value));
+}
+
+/**
+ * fu_device_add_instance_strup:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: (nullable): value
+ *
+ * Assign a uppercase value for the @key.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_strup(FuDevice *self, const gchar *key, const gchar *value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash,
+ g_strdup(key),
+ value != NULL ? g_utf8_strup(value, -1) : NULL);
+}
+
+/**
+ * fu_device_add_instance_u4:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: value
+ *
+ * Assign a value to the @key, which is padded as %1X.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_u4(FuDevice *self, const gchar *key, guint8 value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash, g_strdup(key), g_strdup_printf("%01X", value));
+}
+
+/**
+ * fu_device_add_instance_u8:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: value
+ *
+ * Assign a value to the @key, which is padded as %2X.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_u8(FuDevice *self, const gchar *key, guint8 value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash, g_strdup(key), g_strdup_printf("%02X", value));
+}
+
+/**
+ * fu_device_add_instance_u16:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: value
+ *
+ * Assign a value to the @key, which is padded as %4X.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_u16(FuDevice *self, const gchar *key, guint16 value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash, g_strdup(key), g_strdup_printf("%04X", value));
+}
+
+/**
+ * fu_device_add_instance_u32:
+ * @self: a #FuDevice
+ * @key: (not nullable): string
+ * @value: value
+ *
+ * Assign a value to the @key, which is padded as %8X.
+ *
+ * Since: 1.7.7
+ **/
+void
+fu_device_add_instance_u32(FuDevice *self, const gchar *key, guint32 value)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DEVICE(self));
+ g_return_if_fail(key != NULL);
+ g_hash_table_insert(priv->instance_hash, g_strdup(key), g_strdup_printf("%08X", value));
+}
+
+/**
+ * fu_device_build_instance_id:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ * @subsystem: (not nullable): subsystem, e.g. `NVME`
+ * @...: pairs of string key values, ending with %NULL
+ *
+ * Creates an instance ID from a prefix and some key values.
+ * If the key value cannot be found, the parent and then proxy is also queried.
+ *
+ * If any of the key values remain unset then no instance ID is added.
+ *
+ * fu_device_add_instance_str(dev, "VID", "1234");
+ * fu_device_add_instance_u16(dev, "PID", 5678);
+ * if (!fu_device_build_instance_id(dev, &error, "NVME", "VID", "PID", NULL))
+ * g_warning("failed to add ID: %s", error->message);
+ *
+ * Returns: %TRUE if the instance ID was added.
+ *
+ * Since: 1.7.7
+ **/
+gboolean
+fu_device_build_instance_id(FuDevice *self, GError **error, const gchar *subsystem, ...)
+{
+ FuDevice *parent = fu_device_get_parent(self);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ gboolean ret = TRUE;
+ va_list args;
+ g_autoptr(GString) str = g_string_new(subsystem);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(subsystem != NULL, FALSE);
+
+ va_start(args, subsystem);
+ for (guint i = 0;; i++) {
+ const gchar *key = va_arg(args, const gchar *);
+ const gchar *value;
+ if (key == NULL)
+ break;
+ value = fu_device_instance_lookup(self, key);
+ if (value == NULL && parent != NULL)
+ value = fu_device_instance_lookup(parent, key);
+ if (value == NULL && priv->proxy != NULL)
+ value = fu_device_instance_lookup(priv->proxy, key);
+ if (value == NULL) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "no value for %s",
+ key);
+ ret = FALSE;
+ break;
+ }
+ g_string_append(str, i == 0 ? "\\" : "&");
+ g_string_append_printf(str, "%s_%s", key, value);
+ }
+ va_end(args);
+
+ /* we set an error above */
+ if (!ret)
+ return FALSE;
+
+ /* success */
+ fu_device_add_instance_id(self, str->str);
+ return TRUE;
+}
+
+/**
+ * fu_device_build_instance_id_quirk:
+ * @self: a #FuDevice
+ * @error: (nullable): optional return location for an error
+ * @subsystem: (not nullable): subsystem, e.g. `NVME`
+ * @...: pairs of string key values, ending with %NULL
+ *
+ * Creates an quirk-only instance ID from a prefix and some key values. If any of the key values
+ * are unset then no instance ID is added.
+ *
+ * Returns: %TRUE if the instance ID was added.
+ *
+ * Since: 1.7.7
+ **/
+gboolean
+fu_device_build_instance_id_quirk(FuDevice *self, GError **error, const gchar *subsystem, ...)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ gboolean ret = TRUE;
+ va_list args;
+ g_autoptr(GString) str = g_string_new(subsystem);
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), FALSE);
+ g_return_val_if_fail(subsystem != NULL, FALSE);
+
+ va_start(args, subsystem);
+ for (guint i = 0;; i++) {
+ const gchar *key = va_arg(args, const gchar *);
+ const gchar *value;
+ if (key == NULL)
+ break;
+ value = g_hash_table_lookup(priv->instance_hash, key);
+ if (value == NULL) {
+ g_set_error(error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ "no value for %s",
+ key);
+ ret = FALSE;
+ break;
+ }
+ g_string_append(str, i == 0 ? "\\" : "&");
+ g_string_append_printf(str, "%s_%s", key, value);
+ }
+ va_end(args);
+
+ /* we set an error above */
+ if (!ret)
+ return FALSE;
+
+ /* success */
+ fu_device_add_instance_id_full(self, str->str, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS);
+ return TRUE;
+}
+
+/**
+ * fu_device_security_attr_new:
+ * @self: a #FuDevice
+ * @appstream_id: (nullable): the AppStream component ID, e.g. `com.intel.BiosGuard`
+ *
+ * Creates a new #FwupdSecurityAttr for this specific device.
+ *
+ * Returns: (transfer full): a #FwupdSecurityAttr
+ *
+ * Since: 1.8.4
+ **/
+FwupdSecurityAttr *
+fu_device_security_attr_new(FuDevice *self, const gchar *appstream_id)
+{
+ FuDevicePrivate *priv = fu_device_get_instance_private(self);
+ g_autoptr(FwupdSecurityAttr) attr = NULL;
+
+ g_return_val_if_fail(FU_IS_DEVICE(self), NULL);
+ g_return_val_if_fail(appstream_id != NULL, NULL);
+
+ attr = fu_security_attr_new(priv->ctx, appstream_id);
+ fwupd_security_attr_set_plugin(attr, fu_device_get_plugin(FU_DEVICE(self)));
+ fwupd_security_attr_add_guids(attr, fu_device_get_guids(FU_DEVICE(self)));
+ return g_steal_pointer(&attr);
+}
+
+static void
+fu_device_class_init(FuDeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
+ object_class->finalize = fu_device_finalize;
+ object_class->get_property = fu_device_get_property;
+ object_class->set_property = fu_device_set_property;
+
+ /**
+ * FuDevice::child-added:
+ * @self: the #FuDevice instance that emitted the signal
+ * @device: the #FuDevice child
+ *
+ * The ::child-added signal is emitted when a device has been added as a child.
+ *
+ * Since: 1.0.8
+ **/
+ signals[SIGNAL_CHILD_ADDED] = g_signal_new("child-added",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FuDeviceClass, child_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ FU_TYPE_DEVICE);
+ /**
+ * FuDevice::child-removed:
+ * @self: the #FuDevice instance that emitted the signal
+ * @device: the #FuDevice child
+ *
+ * The ::child-removed signal is emitted when a device has been removed as a child.
+ *
+ * Since: 1.0.8
+ **/
+ signals[SIGNAL_CHILD_REMOVED] = g_signal_new("child-removed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FuDeviceClass, child_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ FU_TYPE_DEVICE);
+ /**
+ * FuDevice::request:
+ * @self: the #FuDevice instance that emitted the signal
+ * @request: the #FwupdRequest
+ *
+ * The ::request signal is emitted when the device needs interactive action from the user.
+ *
+ * Since: 1.6.2
+ **/
+ signals[SIGNAL_REQUEST] = g_signal_new("request",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(FuDeviceClass, request),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ FWUPD_TYPE_REQUEST);
+
+ /**
+ * FuDevice:physical-id:
+ *
+ * The device physical ID.
+ *
+ * Since: 1.1.2
+ */
+ 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);
+
+ /**
+ * FuDevice:logical-id:
+ *
+ * The device logical ID.
+ *
+ * Since: 1.1.2
+ */
+ 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);
+
+ /**
+ * FuDevice:backend-id:
+ *
+ * The device backend ID.
+ *
+ * Since: 1.5.8
+ */
+ pspec = g_param_spec_string("backend-id",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BACKEND_ID, pspec);
+
+ /**
+ * FuDevice:context:
+ *
+ * The #FuContext to use.
+ *
+ * Since: 1.6.0
+ */
+ pspec = g_param_spec_object("context",
+ NULL,
+ NULL,
+ FU_TYPE_CONTEXT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_CONTEXT, pspec);
+
+ /**
+ * FuDevice:proxy:
+ *
+ * The device proxy to use.
+ *
+ * Since: 1.4.1
+ */
+ pspec = g_param_spec_object("proxy",
+ NULL,
+ NULL,
+ FU_TYPE_DEVICE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PROXY, pspec);
+
+ /**
+ * FuDevice:parent:
+ *
+ * The device parent.
+ *
+ * Since: 1.0.8
+ */
+ pspec = g_param_spec_object("parent",
+ NULL,
+ NULL,
+ FU_TYPE_DEVICE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_PARENT, pspec);
+
+ /**
+ * FuDevice:backend-tags:
+ *
+ * The device tags used for backend identification.
+ *
+ * Since: 1.5.8
+ */
+ pspec = g_param_spec_boxed("backend-tags",
+ NULL,
+ NULL,
+ G_TYPE_PTR_ARRAY,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME);
+ g_object_class_install_property(object_class, PROP_BACKEND_TAGS, pspec);
+}
+
+static void
+fu_device_init(FuDevice *self)
+{
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+ priv->order = G_MAXINT;
+ priv->parent_guids = g_ptr_array_new_with_free_func(g_free);
+ priv->possible_plugins = g_ptr_array_new_with_free_func(g_free);
+ priv->retry_recs = g_ptr_array_new_with_free_func(g_free);
+ priv->instance_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ priv->backend_tags = g_ptr_array_new_with_free_func(g_free);
+ priv->acquiesce_delay = 50; /* ms */
+ g_rw_lock_init(&priv->parent_guids_mutex);
+ g_rw_lock_init(&priv->metadata_mutex);
+ priv->notify_flags_handler_id = g_signal_connect(FWUPD_DEVICE(self),
+ "notify::flags",
+ G_CALLBACK(fu_device_flags_notify_cb),
+ NULL);
+}
+
+static void
+fu_device_finalize(GObject *object)
+{
+ FuDevice *self = FU_DEVICE(object);
+ FuDevicePrivate *priv = GET_PRIVATE(self);
+
+ g_rw_lock_clear(&priv->metadata_mutex);
+ g_rw_lock_clear(&priv->parent_guids_mutex);
+
+ if (priv->alternate != NULL)
+ g_object_unref(priv->alternate);
+ if (priv->proxy != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+ if (priv->ctx != NULL)
+ g_object_unref(priv->ctx);
+ if (priv->poll_id != 0)
+ g_source_remove(priv->poll_id);
+ if (priv->metadata != NULL)
+ g_hash_table_unref(priv->metadata);
+ if (priv->inhibits != NULL)
+ g_hash_table_unref(priv->inhibits);
+ if (priv->parent_physical_ids != NULL)
+ g_ptr_array_unref(priv->parent_physical_ids);
+ if (priv->private_flag_items != NULL)
+ g_ptr_array_unref(priv->private_flag_items);
+ g_ptr_array_unref(priv->parent_guids);
+ g_ptr_array_unref(priv->possible_plugins);
+ g_ptr_array_unref(priv->retry_recs);
+ g_ptr_array_unref(priv->backend_tags);
+ g_free(priv->alternate_id);
+ g_free(priv->equivalent_id);
+ g_free(priv->physical_id);
+ g_free(priv->logical_id);
+ g_free(priv->backend_id);
+ g_free(priv->update_request_id);
+ g_free(priv->proxy_guid);
+ g_free(priv->custom_flags);
+ g_hash_table_unref(priv->instance_hash);
+
+ G_OBJECT_CLASS(fu_device_parent_class)->finalize(object);
+}
+
+/**
+ * fu_device_new:
+ *
+ * Creates a new #Fudevice
+ *
+ * Since: 1.8.2
+ **/
+FuDevice *
+fu_device_new(FuContext *ctx)
+{
+ FuDevice *self = g_object_new(FU_TYPE_DEVICE, "context", ctx, NULL);
+ return FU_DEVICE(self);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-device.h b/fwupd-1.8.6/libfwupdplugin/fu-device.h
new file mode 100644
index 0000000000000000000000000000000000000000..845a055c833ab1d22b235c4c0d7c3732903ece69
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-device.h
@@ -0,0 +1,755 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+#include "fu-context.h"
+#include "fu-device-locker.h"
+#include "fu-firmware.h"
+#include "fu-progress.h"
+#include "fu-security-attrs.h"
+#include "fu-version-common.h"
+
+#define FU_TYPE_DEVICE (fu_device_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuDevice, fu_device, FU, DEVICE, FwupdDevice)
+
+struct _FuDeviceClass {
+ FwupdDeviceClass parent_class;
+#ifndef __GI_SCANNER__
+ void (*to_string)(FuDevice *self, guint indent, GString *str);
+ gboolean (*write_firmware)(FuDevice *self,
+ FuFirmware *firmware,
+ FuProgress *progress,
+ FwupdInstallFlags flags,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ FuFirmware *(*read_firmware)(FuDevice *self,
+ FuProgress *progress,
+ GError **error)G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*detach)(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*attach)(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*open)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*close)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*probe)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*rescan)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ FuFirmware *(*prepare_firmware)(FuDevice *self,
+ GBytes *fw,
+ FwupdInstallFlags flags,
+ GError **error)G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*set_quirk_kv)(FuDevice *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*setup)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ void (*incorporate)(FuDevice *self, FuDevice *donor);
+ gboolean (*poll)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*activate)(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*reload)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*prepare)(FuDevice *self,
+ FuProgress *progress,
+ FwupdInstallFlags flags,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*cleanup)(FuDevice *self,
+ FuProgress *progress,
+ FwupdInstallFlags flags,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ void (*report_metadata_pre)(FuDevice *self, GHashTable *metadata);
+ void (*report_metadata_post)(FuDevice *self, GHashTable *metadata);
+ gboolean (*bind_driver)(FuDevice *self,
+ const gchar *subsystem,
+ const gchar *driver,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ gboolean (*unbind_driver)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ GBytes *(*dump_firmware)(FuDevice *self,
+ FuProgress *progress,
+ GError **error)G_GNUC_WARN_UNUSED_RESULT;
+ void (*add_security_attrs)(FuDevice *self, FuSecurityAttrs *attrs);
+ gboolean (*ready)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ void (*child_added)(FuDevice *self, /* signal */
+ FuDevice *child);
+ void (*child_removed)(FuDevice *self, /* signal */
+ FuDevice *child);
+ void (*request)(FuDevice *self, /* signal */
+ FwupdRequest *request);
+ gboolean (*get_results)(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+ void (*set_progress)(FuDevice *self, FuProgress *progress);
+#endif
+};
+
+/**
+ * FuDeviceInstanceFlags:
+ * @FU_DEVICE_INSTANCE_FLAG_NONE: No flags set
+ * @FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS: Only use instance ID for quirk matching
+ * @FU_DEVICE_INSTANCE_FLAG_NO_QUIRKS: Do no 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,
+ FU_DEVICE_INSTANCE_FLAG_NO_QUIRKS = 1 << 1,
+ /*< private >*/
+ FU_DEVICE_INSTANCE_FLAG_LAST
+} FuDeviceInstanceFlags;
+
+/**
+ * FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE:
+ *
+ * The default removal delay for device re-enumeration taking into account a
+ * 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 10000 /* ms */
+
+/**
+ * FU_DEVICE_REMOVE_DELAY_USER_REPLUG:
+ *
+ * The default removal delay for device re-plug taking into account humans
+ * 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 40000 /* ms */
+
+/**
+ * FuDeviceRetryFunc:
+ * @self: a #FuDevice
+ * @user_data: user data
+ * @error: (nullable): optional return location for an error
+ *
+ * The device retry iteration callback.
+ *
+ * Returns: %TRUE on success
+ */
+typedef gboolean (*FuDeviceRetryFunc)(FuDevice *self,
+ gpointer user_data,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
+FuDevice *
+fu_device_new(FuContext *ctx);
+
+/* helpful casting macros */
+#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_has_vendor_id(d, v) fwupd_device_has_vendor_id(FWUPD_DEVICE(d), v)
+#define fu_device_has_protocol(d, v) fwupd_device_has_protocol(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_has_icon(d, v) fwupd_device_has_icon(FWUPD_DEVICE(d), v)
+#define fu_device_add_issue(d, v) fwupd_device_add_issue(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_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_branch(d, v) fwupd_device_set_branch(FWUPD_DEVICE(d), v)
+#define fu_device_set_update_message(d, v) fwupd_device_set_update_message(FWUPD_DEVICE(d), v)
+#define fu_device_set_update_image(d, v) fwupd_device_set_update_image(FWUPD_DEVICE(d), v)
+#define fu_device_set_update_error(d, v) fwupd_device_set_update_error(FWUPD_DEVICE(d), v)
+#define fu_device_add_vendor_id(d, v) fwupd_device_add_vendor_id(FWUPD_DEVICE(d), v)
+#define fu_device_add_protocol(d, v) fwupd_device_add_protocol(FWUPD_DEVICE(d), v)
+#define fu_device_set_version_raw(d, v) fwupd_device_set_version_raw(FWUPD_DEVICE(d), v)
+#define fu_device_set_version_lowest_raw(d, v) \
+ fwupd_device_set_version_lowest_raw(FWUPD_DEVICE(d), v)
+#define fu_device_set_version_bootloader_raw(d, v) \
+ fwupd_device_set_version_bootloader_raw(FWUPD_DEVICE(d), v)
+#define fu_device_set_version_build_date(d, v) \
+ fwupd_device_set_version_build_date(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))
+#define fu_device_get_modified(d) fwupd_device_get_modified(FWUPD_DEVICE(d))
+#define fu_device_get_guids(d) fwupd_device_get_guids(FWUPD_DEVICE(d))
+#define fu_device_get_guid_default(d) fwupd_device_get_guid_default(FWUPD_DEVICE(d))
+#define fu_device_get_instance_ids(d) fwupd_device_get_instance_ids(FWUPD_DEVICE(d))
+#define fu_device_get_icons(d) fwupd_device_get_icons(FWUPD_DEVICE(d))
+#define fu_device_get_issues(d) fwupd_device_get_issues(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_branch(d) fwupd_device_get_branch(FWUPD_DEVICE(d))
+#define fu_device_get_id(d) fwupd_device_get_id(FWUPD_DEVICE(d))
+#define fu_device_get_composite_id(d) fwupd_device_get_composite_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))
+#define fu_device_get_update_state(d) fwupd_device_get_update_state(FWUPD_DEVICE(d))
+#define fu_device_get_update_message(d) fwupd_device_get_update_message(FWUPD_DEVICE(d))
+#define fu_device_get_update_image(d) fwupd_device_get_update_image(FWUPD_DEVICE(d))
+#define fu_device_get_vendor(d) fwupd_device_get_vendor(FWUPD_DEVICE(d))
+#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_version_raw(d) fwupd_device_get_version_raw(FWUPD_DEVICE(d))
+#define fu_device_get_version_lowest_raw(d) fwupd_device_get_version_lowest_raw(FWUPD_DEVICE(d))
+#define fu_device_get_version_bootloader_raw(d) \
+ fwupd_device_get_version_bootloader_raw(FWUPD_DEVICE(d))
+#define fu_device_get_version_build_date(d) fwupd_device_get_version_build_date(FWUPD_DEVICE(d))
+#define fu_device_get_vendor_ids(d) fwupd_device_get_vendor_ids(FWUPD_DEVICE(d))
+#define fu_device_get_protocols(d) fwupd_device_get_protocols(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))
+
+/**
+ * FuDeviceInternalFlags:
+ *
+ * The device internal flags.
+ **/
+typedef guint64 FuDeviceInternalFlags;
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NONE:
+ *
+ * No flags set.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NONE (0)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_UNKNOWN:
+ *
+ * Unknown flag value.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_UNKNOWN G_MAXUINT64
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS:
+ *
+ * Do not add instance IDs from the device baseclass.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NO_AUTO_INSTANCE_IDS (1ull << 0)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER:
+ *
+ * Ensure the version is a valid semantic version, e.g. numbers separated with dots.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_ENSURE_SEMVER (1ull << 1)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED:
+ *
+ * Only devices supported in the metadata will be opened
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_ONLY_SUPPORTED (1ull << 2)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME:
+ *
+ * Set the device name from the metadata `name` if available.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME (1ull << 3)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY:
+ *
+ * Set the device name from the metadata `category` if available.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_MD_SET_NAME_CATEGORY (1ull << 4)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT:
+ *
+ * Set the device version format from the metadata if available.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_MD_SET_VERFMT (1ull << 5)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON:
+ *
+ * Set the device icon from the metadata if available.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_MD_SET_ICON (1ull << 6)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN:
+ *
+ * Retry the device open up to 5 times if it fails.
+ *
+ * Since: 1.5.5
+ */
+#define FU_DEVICE_INTERNAL_FLAG_RETRY_OPEN (1ull << 7)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID:
+ *
+ * Match GUIDs on device replug where the physical and logical IDs will be different.
+ *
+ * Since: 1.5.8
+ */
+#define FU_DEVICE_INTERNAL_FLAG_REPLUG_MATCH_GUID (1ull << 8)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_INHERIT_ACTIVATION:
+ *
+ * Inherit activation status from the history database on startup.
+ *
+ * Since: 1.5.9
+ */
+#define FU_DEVICE_INTERNAL_FLAG_INHERIT_ACTIVATION (1ull << 9)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_IS_OPEN:
+ *
+ * The device opened successfully and ready to use.
+ *
+ * Since: 1.6.1
+ */
+#define FU_DEVICE_INTERNAL_FLAG_IS_OPEN (1ull << 10)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NO_SERIAL_NUMBER:
+ *
+ * Do not attempt to read the device serial number.
+ *
+ * Since: 1.6.2
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NO_SERIAL_NUMBER (1ull << 11)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_AUTO_PARENT_CHILDREN:
+ *
+ * Automatically assign the parent for children of this device.
+ *
+ * Since: 1.6.2
+ */
+#define FU_DEVICE_INTERNAL_FLAG_AUTO_PARENT_CHILDREN (1ull << 12)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_ATTACH_EXTRA_RESET:
+ *
+ * Device needs resetting twice for attach after the firmware update.
+ *
+ * Since: 1.6.2
+ */
+#define FU_DEVICE_INTERNAL_FLAG_ATTACH_EXTRA_RESET (1ull << 13)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN:
+ *
+ * Children of the device are inhibited by the parent.
+ *
+ * Since: 1.6.2
+ */
+#define FU_DEVICE_INTERNAL_FLAG_INHIBIT_CHILDREN (1ull << 14)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE_CHILDREN:
+ *
+ * Do not auto-remove clildren in the device list.
+ *
+ * Since: 1.6.2
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE_CHILDREN (1ull << 15)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN:
+ *
+ * Use parent to open and close the device.
+ *
+ * Since: 1.6.2
+ */
+#define FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN (1ull << 16)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_BATTERY:
+ *
+ * Use parent for the battery level and threshold.
+ *
+ * Since: 1.6.3
+ */
+#define FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_BATTERY (1ull << 17)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_USE_PROXY_FALLBACK:
+ *
+ * Use parent for the battery level and threshold.
+ *
+ * Since: 1.6.4
+ */
+#define FU_DEVICE_INTERNAL_FLAG_USE_PROXY_FALLBACK (1ull << 18)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE:
+ *
+ * The device is not auto removed.
+ *
+ * Since 1.7.3
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NO_AUTO_REMOVE (1llu << 19)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_MD_SET_VENDOR:
+ *
+ * Set the device vendor from the metadata `developer_name` if available.
+ *
+ * Since: 1.7.4
+ */
+#define FU_DEVICE_INTERNAL_FLAG_MD_SET_VENDOR (1ull << 20)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NO_LID_CLOSED:
+ *
+ * Do not allow updating when the laptop lid is closed.
+ *
+ * Since: 1.7.4
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NO_LID_CLOSED (1ull << 21)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_NO_PROBE:
+ *
+ * Do not probe this device.
+ *
+ * Since: 1.7.6
+ */
+#define FU_DEVICE_INTERNAL_FLAG_NO_PROBE (1ull << 22)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_MD_SET_SIGNED:
+ *
+ * Set the signed/unsigned payload from the metadata if available.
+ *
+ * Since: 1.7.6
+ */
+#define FU_DEVICE_INTERNAL_FLAG_MD_SET_SIGNED (1ull << 23)
+
+/**
+ * FU_DEVICE_INTERNAL_AUTO_PAUSE_POLLING:
+ *
+ * Pause polling when reading or writing to the device
+ *
+ * Since: 1.8.1
+ */
+#define FU_DEVICE_INTERNAL_AUTO_PAUSE_POLLING (1ull << 24)
+
+/**
+ * FU_DEVICE_INTERNAL_FLAG_ONLY_WAIT_FOR_REPLUG:
+ *
+ * Only use the device removal delay when explicitly waiting for a replug, rather than every time
+ * the device is removed.
+ *
+ * Since: 1.8.1
+ */
+#define FU_DEVICE_INTERNAL_FLAG_ONLY_WAIT_FOR_REPLUG (1ull << 25)
+
+/* accessors */
+gchar *
+fu_device_to_string(FuDevice *self);
+void
+fu_device_add_string(FuDevice *self, guint idt, GString *str);
+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 *self, const gchar *guid);
+void
+fu_device_add_guid_full(FuDevice *self, const gchar *guid, FuDeviceInstanceFlags flags);
+gboolean
+fu_device_has_guid(FuDevice *self, const gchar *guid);
+void
+fu_device_add_instance_id(FuDevice *self, const gchar *instance_id);
+void
+fu_device_add_instance_id_full(FuDevice *self,
+ const gchar *instance_id,
+ FuDeviceInstanceFlags flags);
+FuDevice *
+fu_device_get_alternate(FuDevice *self);
+FuDevice *
+fu_device_get_root(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_remove_child(FuDevice *self, FuDevice *child);
+void
+fu_device_add_parent_guid(FuDevice *self, const gchar *guid);
+void
+fu_device_add_parent_physical_id(FuDevice *self, const gchar *physical_id);
+void
+fu_device_add_counterpart_guid(FuDevice *self, const gchar *guid);
+FuDevice *
+fu_device_get_proxy(FuDevice *self);
+void
+fu_device_set_proxy(FuDevice *self, FuDevice *proxy);
+FuDevice *
+fu_device_get_proxy_with_fallback(FuDevice *self);
+const gchar *
+fu_device_get_metadata(FuDevice *self, const gchar *key);
+gboolean
+fu_device_get_metadata_boolean(FuDevice *self, const gchar *key);
+guint
+fu_device_get_metadata_integer(FuDevice *self, const gchar *key);
+void
+fu_device_remove_metadata(FuDevice *self, const gchar *key);
+void
+fu_device_set_metadata(FuDevice *self, const gchar *key, const gchar *value);
+void
+fu_device_set_metadata_boolean(FuDevice *self, const gchar *key, gboolean value);
+void
+fu_device_set_metadata_integer(FuDevice *self, const gchar *key, guint value);
+void
+fu_device_set_id(FuDevice *self, const gchar *id);
+void
+fu_device_set_version_format(FuDevice *self, FwupdVersionFormat fmt);
+void
+fu_device_set_version(FuDevice *self, const gchar *version);
+void
+fu_device_set_version_lowest(FuDevice *self, const gchar *version);
+void
+fu_device_set_version_bootloader(FuDevice *self, const gchar *version);
+void
+fu_device_add_backend_tag(FuDevice *self, const gchar *backend_tag);
+gboolean
+fu_device_has_backend_tag(FuDevice *self, const gchar *backend_tag);
+GPtrArray *
+fu_device_get_backend_tags(FuDevice *self);
+void
+fu_device_inhibit(FuDevice *self, const gchar *inhibit_id, const gchar *reason);
+void
+fu_device_uninhibit(FuDevice *self, const gchar *inhibit_id);
+void
+fu_device_add_problem(FuDevice *self, FwupdDeviceProblem problem);
+void
+fu_device_remove_problem(FuDevice *self, FwupdDeviceProblem problem);
+gboolean
+fu_device_has_inhibit(FuDevice *self, const gchar *inhibit_id);
+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_backend_id(FuDevice *self);
+void
+fu_device_set_backend_id(FuDevice *self, const gchar *backend_id);
+const gchar *
+fu_device_get_proxy_guid(FuDevice *self);
+void
+fu_device_set_proxy_guid(FuDevice *self, const gchar *proxy_guid);
+guint
+fu_device_get_priority(FuDevice *self);
+void
+fu_device_set_priority(FuDevice *self, guint priority);
+void
+fu_device_add_flag(FuDevice *self, FwupdDeviceFlags flag);
+void
+fu_device_remove_flag(FuDevice *self, FwupdDeviceFlags flag);
+const gchar *
+fu_device_get_custom_flags(FuDevice *self);
+void
+fu_device_set_custom_flags(FuDevice *self, const gchar *custom_flags);
+void
+fu_device_set_name(FuDevice *self, const gchar *value);
+void
+fu_device_set_vendor(FuDevice *self, const gchar *vendor);
+guint
+fu_device_get_remove_delay(FuDevice *self);
+void
+fu_device_set_remove_delay(FuDevice *self, guint remove_delay);
+guint
+fu_device_get_acquiesce_delay(FuDevice *self);
+void
+fu_device_set_acquiesce_delay(FuDevice *self, guint acquiesce_delay);
+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_battery_level(FuDevice *self);
+void
+fu_device_set_battery_level(FuDevice *self, guint battery_level);
+guint
+fu_device_get_battery_threshold(FuDevice *self);
+void
+fu_device_set_battery_threshold(FuDevice *self, guint battery_threshold);
+void
+fu_device_set_update_state(FuDevice *self, FwupdUpdateState update_state);
+void
+fu_device_set_context(FuDevice *self, FuContext *ctx);
+FuContext *
+fu_device_get_context(FuDevice *self);
+FwupdRelease *
+fu_device_get_release_default(FuDevice *self);
+GType
+fu_device_get_specialized_gtype(FuDevice *self);
+GType
+fu_device_get_firmware_gtype(FuDevice *self);
+void
+fu_device_set_firmware_gtype(FuDevice *self, GType firmware_gtype);
+void
+fu_device_add_internal_flag(FuDevice *self, FuDeviceInternalFlags flag);
+void
+fu_device_remove_internal_flag(FuDevice *self, FuDeviceInternalFlags flag);
+gboolean
+fu_device_has_internal_flag(FuDevice *self, FuDeviceInternalFlags flag);
+gboolean
+fu_device_get_results(FuDevice *self, GError **error);
+gboolean
+fu_device_write_firmware(FuDevice *self,
+ GBytes *fw,
+ FuProgress *progress,
+ FwupdInstallFlags flags,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+FuFirmware *
+fu_device_prepare_firmware(FuDevice *self, GBytes *fw, FwupdInstallFlags flags, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+FuFirmware *
+fu_device_read_firmware(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GBytes *
+fu_device_dump_firmware(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_attach(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_detach(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_attach_full(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_detach_full(FuDevice *self,
+ FuProgress *progress,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_reload(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_prepare(FuDevice *self, FuProgress *progress, FwupdInstallFlags flags, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_cleanup(FuDevice *self, FuProgress *progress, FwupdInstallFlags flags, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_device_incorporate(FuDevice *self, FuDevice *donor);
+void
+fu_device_incorporate_flag(FuDevice *self, FuDevice *donor, FwupdDeviceFlags flag);
+gboolean
+fu_device_open(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_close(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_probe(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_setup(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_rescan(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_activate(FuDevice *self, FuProgress *progress, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_device_probe_invalidate(FuDevice *self);
+gboolean
+fu_device_poll(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+void
+fu_device_set_poll_interval(FuDevice *self, guint interval);
+void
+fu_device_retry_set_delay(FuDevice *self, guint delay);
+void
+fu_device_retry_add_recovery(FuDevice *self, GQuark domain, gint code, FuDeviceRetryFunc func);
+gboolean
+fu_device_retry(FuDevice *self,
+ FuDeviceRetryFunc func,
+ guint count,
+ gpointer user_data,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_retry_full(FuDevice *self,
+ FuDeviceRetryFunc func,
+ guint count,
+ guint delay,
+ gpointer user_data,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_bind_driver(FuDevice *self, const gchar *subsystem, const gchar *driver, GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+gboolean
+fu_device_unbind_driver(FuDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+GHashTable *
+fu_device_report_metadata_pre(FuDevice *self);
+GHashTable *
+fu_device_report_metadata_post(FuDevice *self);
+void
+fu_device_add_security_attrs(FuDevice *self, FuSecurityAttrs *attrs);
+void
+fu_device_register_private_flag(FuDevice *self, guint64 value, const gchar *value_str);
+void
+fu_device_add_private_flag(FuDevice *self, guint64 flag);
+void
+fu_device_remove_private_flag(FuDevice *self, guint64 flag);
+gboolean
+fu_device_has_private_flag(FuDevice *self, guint64 flag);
+void
+fu_device_emit_request(FuDevice *self, FwupdRequest *request);
+FwupdSecurityAttr *
+fu_device_security_attr_new(FuDevice *self, const gchar *appstream_id);
+
+void
+fu_device_add_instance_str(FuDevice *self, const gchar *key, const gchar *value);
+void
+fu_device_add_instance_strsafe(FuDevice *self, const gchar *key, const gchar *value);
+void
+fu_device_add_instance_strup(FuDevice *self, const gchar *key, const gchar *value);
+void
+fu_device_add_instance_u4(FuDevice *self, const gchar *key, guint8 value);
+void
+fu_device_add_instance_u8(FuDevice *self, const gchar *key, guint8 value);
+void
+fu_device_add_instance_u16(FuDevice *self, const gchar *key, guint16 value);
+void
+fu_device_add_instance_u32(FuDevice *self, const gchar *key, guint32 value);
+gboolean
+fu_device_build_instance_id(FuDevice *self, GError **error, const gchar *subsystem, ...);
+gboolean
+fu_device_build_instance_id_quirk(FuDevice *self, GError **error, const gchar *subsystem, ...);
+FuDeviceLocker *
+fu_device_poll_locker_new(FuDevice *self, GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware-private.h b/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf5595b9c02809d15892b6b5959d26b4270d749c
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware-private.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-dfu-firmware.h"
+
+guint8
+fu_dfu_firmware_get_footer_len(FuDfuFirmware *self);
+GBytes *
+fu_dfu_firmware_append_footer(FuDfuFirmware *self, GBytes *contents, GError **error);
+gboolean
+fu_dfu_firmware_parse_footer(FuDfuFirmware *self,
+ GBytes *fw,
+ FwupdInstallFlags flags,
+ GError **error);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware.c b/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634600150a584fd6035547b102db90d25b88ad0
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2019 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuFirmware"
+
+#include "config.h"
+
+#include
+
+#include "fu-byte-array.h"
+#include "fu-bytes.h"
+#include "fu-common.h"
+#include "fu-crc.h"
+#include "fu-dfu-firmware-private.h"
+#include "fu-mem.h"
+
+/**
+ * FuDfuFirmware:
+ *
+ * A DFU firmware image.
+ *
+ * See also: [class@FuFirmware]
+ */
+
+typedef struct {
+ guint16 vid;
+ guint16 pid;
+ guint16 release;
+ guint16 dfu_version;
+ guint8 footer_len;
+} FuDfuFirmwarePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(FuDfuFirmware, fu_dfu_firmware, FU_TYPE_FIRMWARE)
+#define GET_PRIVATE(o) (fu_dfu_firmware_get_instance_private(o))
+
+static void
+fu_dfu_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
+{
+ FuDfuFirmware *self = FU_DFU_FIRMWARE(firmware);
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ fu_xmlb_builder_insert_kx(bn, "vendor", priv->vid);
+ fu_xmlb_builder_insert_kx(bn, "product", priv->pid);
+ fu_xmlb_builder_insert_kx(bn, "release", priv->release);
+ fu_xmlb_builder_insert_kx(bn, "dfu_version", priv->dfu_version);
+}
+
+/* private */
+guint8
+fu_dfu_firmware_get_footer_len(FuDfuFirmware *self)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DFU_FIRMWARE(self), 0x0);
+ return priv->footer_len;
+}
+
+/**
+ * fu_dfu_firmware_get_vid:
+ * @self: a #FuDfuFirmware
+ *
+ * Gets the vendor ID, or 0xffff for no restriction.
+ *
+ * Returns: integer
+ *
+ * Since: 1.3.3
+ **/
+guint16
+fu_dfu_firmware_get_vid(FuDfuFirmware *self)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DFU_FIRMWARE(self), 0x0);
+ return priv->vid;
+}
+
+/**
+ * fu_dfu_firmware_get_pid:
+ * @self: a #FuDfuFirmware
+ *
+ * Gets the product ID, or 0xffff for no restriction.
+ *
+ * Returns: integer
+ *
+ * Since: 1.3.3
+ **/
+guint16
+fu_dfu_firmware_get_pid(FuDfuFirmware *self)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DFU_FIRMWARE(self), 0x0);
+ return priv->pid;
+}
+
+/**
+ * fu_dfu_firmware_get_release:
+ * @self: a #FuDfuFirmware
+ *
+ * Gets the device ID, or 0xffff for no restriction.
+ *
+ * Returns: integer
+ *
+ * Since: 1.3.3
+ **/
+guint16
+fu_dfu_firmware_get_release(FuDfuFirmware *self)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DFU_FIRMWARE(self), 0x0);
+ return priv->release;
+}
+
+/**
+ * fu_dfu_firmware_get_version:
+ * @self: a #FuDfuFirmware
+ *
+ * Gets the file format version with is 0x0100 by default.
+ *
+ * Returns: integer
+ *
+ * Since: 1.3.3
+ **/
+guint16
+fu_dfu_firmware_get_version(FuDfuFirmware *self)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_val_if_fail(FU_IS_DFU_FIRMWARE(self), 0x0);
+ return priv->dfu_version;
+}
+
+/**
+ * fu_dfu_firmware_set_vid:
+ * @self: a #FuDfuFirmware
+ * @vid: vendor ID, or 0xffff if the firmware should match any vendor
+ *
+ * Sets the vendor ID.
+ *
+ * Since: 1.3.3
+ **/
+void
+fu_dfu_firmware_set_vid(FuDfuFirmware *self, guint16 vid)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DFU_FIRMWARE(self));
+ priv->vid = vid;
+}
+
+/**
+ * fu_dfu_firmware_set_pid:
+ * @self: a #FuDfuFirmware
+ * @pid: product ID, or 0xffff if the firmware should match any product
+ *
+ * Sets the product ID.
+ *
+ * Since: 1.3.3
+ **/
+void
+fu_dfu_firmware_set_pid(FuDfuFirmware *self, guint16 pid)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DFU_FIRMWARE(self));
+ priv->pid = pid;
+}
+
+/**
+ * fu_dfu_firmware_set_release:
+ * @self: a #FuDfuFirmware
+ * @release: release, or 0xffff if the firmware should match any release
+ *
+ * Sets the release for the dfu firmware.
+ *
+ * Since: 1.3.3
+ **/
+void
+fu_dfu_firmware_set_release(FuDfuFirmware *self, guint16 release)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DFU_FIRMWARE(self));
+ priv->release = release;
+}
+
+/**
+ * fu_dfu_firmware_set_version:
+ * @self: a #FuDfuFirmware
+ * @version: integer
+ *
+ * Sets the file format version.
+ *
+ * Since: 1.3.3
+ **/
+void
+fu_dfu_firmware_set_version(FuDfuFirmware *self, guint16 version)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ g_return_if_fail(FU_IS_DFU_FIRMWARE(self));
+ priv->dfu_version = version;
+}
+
+typedef struct __attribute__((packed)) {
+ guint16 release;
+ guint16 pid;
+ guint16 vid;
+ guint16 ver;
+ guint8 sig[3];
+ guint8 len;
+ guint32 crc;
+} FuDfuFirmwareFooter;
+
+static gboolean
+fu_dfu_firmware_check_magic(FuFirmware *firmware, GBytes *fw, gsize offset, GError **error)
+{
+ guint8 magic[3] = {0x0};
+
+ /* is a footer */
+ if (!fu_memcpy_safe(magic,
+ sizeof(magic),
+ 0x0, /* dst */
+ g_bytes_get_data(fw, NULL),
+ g_bytes_get_size(fw),
+ g_bytes_get_size(fw) - G_STRUCT_OFFSET(FuDfuFirmwareFooter, sig),
+ sizeof(magic),
+ error))
+ return FALSE;
+ if (memcmp(magic, "UFD", sizeof(magic)) != 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "no DFU signature");
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+gboolean
+fu_dfu_firmware_parse_footer(FuDfuFirmware *self,
+ GBytes *fw,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ FuDfuFirmwareFooter ftr;
+ gsize len;
+ guint32 crc;
+ guint32 crc_new;
+ const guint8 *data = g_bytes_get_data(fw, &len);
+
+ /* verify the checksum */
+ if (!fu_memcpy_safe((guint8 *)&ftr,
+ sizeof(FuDfuFirmwareFooter),
+ 0x0, /* dst */
+ data,
+ len,
+ len - sizeof(FuDfuFirmwareFooter), /* src */
+ sizeof(FuDfuFirmwareFooter),
+ error)) {
+ g_prefix_error(error, "failed to read magic: ");
+ return FALSE;
+ }
+ crc = GUINT32_FROM_LE(ftr.crc);
+ if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) {
+ crc_new = ~fu_crc32(data, len - 4);
+ if (crc != crc_new) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "CRC failed, expected %04x, got %04x",
+ crc_new,
+ GUINT32_FROM_LE(ftr.crc));
+ return FALSE;
+ }
+ }
+
+ /* set from footer */
+ priv->vid = GUINT16_FROM_LE(ftr.vid);
+ priv->pid = GUINT16_FROM_LE(ftr.pid);
+ priv->release = GUINT16_FROM_LE(ftr.release);
+ priv->dfu_version = GUINT16_FROM_LE(ftr.ver);
+ priv->footer_len = ftr.len;
+
+ /* check reported length */
+ if (priv->footer_len > len) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "reported footer size %04x larger than file %04x",
+ (guint)priv->footer_len,
+ (guint)len);
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static gboolean
+fu_dfu_firmware_parse(FuFirmware *firmware,
+ GBytes *fw,
+ gsize offset,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ FuDfuFirmware *self = FU_DFU_FIRMWARE(firmware);
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ gsize len = g_bytes_get_size(fw);
+ g_autoptr(GBytes) contents = NULL;
+
+ /* parse footer */
+ if (!fu_dfu_firmware_parse_footer(self, fw, flags, error))
+ return FALSE;
+
+ /* trim footer off */
+ contents = fu_bytes_new_offset(fw, 0, len - priv->footer_len, error);
+ if (contents == NULL)
+ return FALSE;
+ fu_firmware_set_bytes(firmware, contents);
+ return TRUE;
+}
+
+GBytes *
+fu_dfu_firmware_append_footer(FuDfuFirmware *self, GBytes *contents, GError **error)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ GByteArray *buf = g_byte_array_new();
+ const guint8 *blob;
+ gsize blobsz = 0;
+
+ /* add the raw firmware data */
+ blob = g_bytes_get_data(contents, &blobsz);
+ g_byte_array_append(buf, blob, blobsz);
+
+ /* append footer */
+ fu_byte_array_append_uint16(buf, priv->release, G_LITTLE_ENDIAN);
+ fu_byte_array_append_uint16(buf, priv->pid, G_LITTLE_ENDIAN);
+ fu_byte_array_append_uint16(buf, priv->vid, G_LITTLE_ENDIAN);
+ fu_byte_array_append_uint16(buf, priv->dfu_version, G_LITTLE_ENDIAN);
+ g_byte_array_append(buf, (const guint8 *)"UFD", 3);
+ fu_byte_array_append_uint8(buf, sizeof(FuDfuFirmwareFooter));
+ fu_byte_array_append_uint32(buf, ~fu_crc32(buf->data, buf->len), G_LITTLE_ENDIAN);
+ return g_byte_array_free_to_bytes(buf);
+}
+
+static GBytes *
+fu_dfu_firmware_write(FuFirmware *firmware, GError **error)
+{
+ FuDfuFirmware *self = FU_DFU_FIRMWARE(firmware);
+ g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware);
+ g_autoptr(GBytes) fw = NULL;
+
+ /* can only contain one image */
+ if (images->len > 1) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_NOT_SUPPORTED,
+ "DFU only supports writing one image");
+ return NULL;
+ }
+
+ /* add footer */
+ fw = fu_firmware_get_bytes_with_patches(firmware, error);
+ if (fw == NULL)
+ return NULL;
+ return fu_dfu_firmware_append_footer(self, fw, error);
+}
+
+static gboolean
+fu_dfu_firmware_build(FuFirmware *firmware, XbNode *n, GError **error)
+{
+ FuDfuFirmware *self = FU_DFU_FIRMWARE(firmware);
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ guint64 tmp;
+
+ /* optional properties */
+ tmp = xb_node_query_text_as_uint(n, "vendor", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16)
+ priv->vid = tmp;
+ tmp = xb_node_query_text_as_uint(n, "product", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16)
+ priv->pid = tmp;
+ tmp = xb_node_query_text_as_uint(n, "release", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16)
+ priv->release = tmp;
+ tmp = xb_node_query_text_as_uint(n, "dfu_version", NULL);
+ if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16)
+ priv->dfu_version = tmp;
+
+ /* success */
+ return TRUE;
+}
+
+static void
+fu_dfu_firmware_init(FuDfuFirmware *self)
+{
+ FuDfuFirmwarePrivate *priv = GET_PRIVATE(self);
+ priv->vid = 0xffff;
+ priv->pid = 0xffff;
+ priv->release = 0xffff;
+ priv->dfu_version = FU_DFU_FIRMARE_VERSION_DFU_1_0;
+ fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_CHECKSUM);
+ fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_VID_PID);
+}
+
+static void
+fu_dfu_firmware_class_init(FuDfuFirmwareClass *klass)
+{
+ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
+ klass_firmware->check_magic = fu_dfu_firmware_check_magic;
+ klass_firmware->export = fu_dfu_firmware_export;
+ klass_firmware->parse = fu_dfu_firmware_parse;
+ klass_firmware->write = fu_dfu_firmware_write;
+ klass_firmware->build = fu_dfu_firmware_build;
+}
+
+/**
+ * fu_dfu_firmware_new:
+ *
+ * Creates a new #FuFirmware of sub type Dfu
+ *
+ * Since: 1.3.3
+ **/
+FuFirmware *
+fu_dfu_firmware_new(void)
+{
+ return FU_FIRMWARE(g_object_new(FU_TYPE_DFU_FIRMWARE, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware.h b/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware.h
new file mode 100644
index 0000000000000000000000000000000000000000..97a9ee9a525463a8f9b6c3150a1fd5ffac045b5f
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dfu-firmware.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-firmware.h"
+
+#define FU_TYPE_DFU_FIRMWARE (fu_dfu_firmware_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuDfuFirmware, fu_dfu_firmware, FU, DFU_FIRMWARE, FuFirmware)
+
+struct _FuDfuFirmwareClass {
+ FuFirmwareClass parent_class;
+};
+
+/**
+ * FU_DFU_FIRMARE_VERSION_UNKNOWN:
+ *
+ * Unknown version of the DFU standard in BCD format.
+ *
+ * Since: 1.6.1
+ **/
+#define FU_DFU_FIRMARE_VERSION_UNKNOWN (0u)
+
+/**
+ * FU_DFU_FIRMARE_VERSION_DFU_1_0:
+ *
+ * The 1.0 version of the DFU standard in BCD format.
+ *
+ * Since: 1.6.1
+ **/
+#define FU_DFU_FIRMARE_VERSION_DFU_1_0 (0x0100)
+
+/**
+ * FU_DFU_FIRMARE_VERSION_DFU_1_1:
+ *
+ * The 1.1 version of the DFU standard in BCD format.
+ *
+ * Since: 1.6.1
+ **/
+#define FU_DFU_FIRMARE_VERSION_DFU_1_1 (0x0110)
+
+/**
+ * FU_DFU_FIRMARE_VERSION_DFUSE:
+ *
+ * The DfuSe version of the DFU standard in BCD format, defined by ST.
+ *
+ * Since: 1.6.1
+ **/
+#define FU_DFU_FIRMARE_VERSION_DFUSE (0x011a)
+
+/**
+ * FU_DFU_FIRMARE_VERSION_ATMEL_AVR:
+ *
+ * The Atmel AVR version of the DFU standard in BCD format.
+ *
+ * Since: 1.6.1
+ **/
+#define FU_DFU_FIRMARE_VERSION_ATMEL_AVR (0xff01)
+
+FuFirmware *
+fu_dfu_firmware_new(void);
+guint16
+fu_dfu_firmware_get_vid(FuDfuFirmware *self);
+guint16
+fu_dfu_firmware_get_pid(FuDfuFirmware *self);
+guint16
+fu_dfu_firmware_get_release(FuDfuFirmware *self);
+guint16
+fu_dfu_firmware_get_version(FuDfuFirmware *self);
+void
+fu_dfu_firmware_set_vid(FuDfuFirmware *self, guint16 vid);
+void
+fu_dfu_firmware_set_pid(FuDfuFirmware *self, guint16 pid);
+void
+fu_dfu_firmware_set_release(FuDfuFirmware *self, guint16 release);
+void
+fu_dfu_firmware_set_version(FuDfuFirmware *self, guint16 version);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dfuse-firmware.c b/fwupd-1.8.6/libfwupdplugin/fu-dfuse-firmware.c
new file mode 100644
index 0000000000000000000000000000000000000000..66bfea3597f60f4285155c8f81f0ab7c66c24fe2
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dfuse-firmware.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuFirmware"
+
+#include "config.h"
+
+#include
+
+#include "fu-byte-array.h"
+#include "fu-bytes.h"
+#include "fu-chunk-private.h"
+#include "fu-common.h"
+#include "fu-dfu-firmware-private.h"
+#include "fu-dfuse-firmware.h"
+#include "fu-mem.h"
+
+/**
+ * FuDfuseFirmware:
+ *
+ * A DfuSe firmware image.
+ *
+ * See also: [class@FuDfuFirmware]
+ */
+
+G_DEFINE_TYPE(FuDfuseFirmware, fu_dfuse_firmware, FU_TYPE_DFU_FIRMWARE)
+
+/* firmware: LE */
+typedef struct __attribute__((packed)) {
+ guint8 sig[5];
+ guint8 ver;
+ guint32 image_size;
+ guint8 targets;
+} DfuSeHdr;
+
+/* image: LE */
+typedef struct __attribute__((packed)) {
+ guint8 sig[6];
+ guint8 alt_setting;
+ guint32 target_named;
+ gchar target_name[255];
+ guint32 target_size;
+ guint32 chunks;
+} DfuSeImageHdr;
+
+/* element: LE */
+typedef struct __attribute__((packed)) {
+ guint32 address;
+ guint32 size;
+} DfuSeElementHdr;
+
+G_STATIC_ASSERT(sizeof(DfuSeHdr) == 11);
+G_STATIC_ASSERT(sizeof(DfuSeImageHdr) == 274);
+G_STATIC_ASSERT(sizeof(DfuSeElementHdr) == 8);
+
+static FuChunk *
+fu_firmware_image_chunk_parse(FuDfuseFirmware *self, GBytes *bytes, gsize *offset, GError **error)
+{
+ DfuSeElementHdr hdr = {0x0};
+ gsize bufsz = 0;
+ gsize ftrlen = fu_dfu_firmware_get_footer_len(FU_DFU_FIRMWARE(self));
+ const guint8 *buf = g_bytes_get_data(bytes, &bufsz);
+ g_autoptr(FuChunk) chk = NULL;
+ g_autoptr(GBytes) blob = NULL;
+
+ /* check size */
+ if (!fu_memcpy_safe((guint8 *)&hdr,
+ sizeof(hdr),
+ 0x0, /* dst */
+ buf,
+ bufsz - ftrlen,
+ *offset, /* src */
+ sizeof(hdr),
+ error))
+ return NULL;
+
+ /* create new chunk */
+ *offset += sizeof(hdr);
+ blob = fu_bytes_new_offset(bytes, *offset, GUINT32_FROM_LE(hdr.size), error);
+ if (blob == NULL)
+ return NULL;
+ chk = fu_chunk_bytes_new(blob);
+ fu_chunk_set_address(chk, GUINT32_FROM_LE(hdr.address));
+ *offset += fu_chunk_get_data_sz(chk);
+
+ /* success */
+ return g_steal_pointer(&chk);
+}
+
+static FuFirmware *
+fu_dfuse_firmware_image_parse(FuDfuseFirmware *self, GBytes *bytes, gsize *offset, GError **error)
+{
+ DfuSeImageHdr hdr = {0x0};
+ gsize bufsz = 0;
+ const guint8 *buf = g_bytes_get_data(bytes, &bufsz);
+ g_autoptr(FuFirmware) image = fu_firmware_new();
+
+ /* verify image signature */
+ if (!fu_memcpy_safe((guint8 *)&hdr,
+ sizeof(hdr),
+ 0x0, /* dst */
+ buf,
+ bufsz,
+ *offset, /* src */
+ sizeof(hdr),
+ error))
+ return NULL;
+ if (memcmp(hdr.sig, "Target", sizeof(hdr.sig)) != 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "invalid DfuSe target signature");
+ return NULL;
+ }
+
+ /* set properties */
+ fu_firmware_set_idx(image, hdr.alt_setting);
+ if (GUINT32_FROM_LE(hdr.target_named) == 0x01) {
+ g_autofree gchar *img_id = NULL;
+ img_id = g_strndup(hdr.target_name, sizeof(hdr.target_name));
+ fu_firmware_set_id(image, img_id);
+ }
+
+ /* no chunks */
+ if (hdr.chunks == 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "DfuSe image has no chunks");
+ return NULL;
+ }
+
+ /* parse chunks */
+ *offset += sizeof(hdr);
+ for (guint j = 0; j < GUINT32_FROM_LE(hdr.chunks); j++) {
+ g_autoptr(FuChunk) chk = NULL;
+ chk = fu_firmware_image_chunk_parse(self, bytes, offset, error);
+ if (chk == NULL)
+ return NULL;
+ fu_firmware_add_chunk(image, chk);
+ }
+
+ /* success */
+ return g_steal_pointer(&image);
+}
+
+static gboolean
+fu_dfuse_firmware_check_magic(FuFirmware *firmware, GBytes *fw, gsize offset, GError **error)
+{
+ guint8 magic[5] = {0x0};
+
+ if (!fu_memcpy_safe(magic,
+ sizeof(magic),
+ 0x0, /* dst */
+ g_bytes_get_data(fw, NULL),
+ g_bytes_get_size(fw),
+ offset, /* src */
+ sizeof(magic),
+ error)) {
+ g_prefix_error(error, "failed to read magic: ");
+ return FALSE;
+ }
+ if (memcmp(magic, "DfuSe", sizeof(magic)) != 0) {
+ g_set_error_literal(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INVALID_FILE,
+ "invalid DfuSe prefix");
+ return FALSE;
+ }
+
+ /* success */
+ return TRUE;
+}
+
+static gboolean
+fu_dfuse_firmware_parse(FuFirmware *firmware,
+ GBytes *fw,
+ gsize offset,
+ FwupdInstallFlags flags,
+ GError **error)
+{
+ FuDfuFirmware *dfu_firmware = FU_DFU_FIRMWARE(firmware);
+ gsize bufsz = 0;
+ guint32 image_size = 0;
+ guint8 targets = 0;
+ guint8 ver = 0;
+ const guint8 *buf = g_bytes_get_data(fw, &bufsz);
+
+ /* DFU footer first */
+ if (!fu_dfu_firmware_parse_footer(dfu_firmware, fw, flags, error))
+ return FALSE;
+
+ /* check the version */
+ if (!fu_memread_uint8_safe(buf,
+ bufsz,
+ offset + G_STRUCT_OFFSET(DfuSeHdr, ver),
+ &ver,
+ error))
+ return FALSE;
+ if (ver != 0x01) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "invalid DfuSe version, got %02x",
+ ver);
+ return FALSE;
+ }
+
+ /* check image size */
+ if (!fu_memread_uint32_safe(buf,
+ bufsz,
+ offset + G_STRUCT_OFFSET(DfuSeHdr, image_size),
+ &image_size,
+ G_LITTLE_ENDIAN,
+ error))
+ return FALSE;
+ if (image_size != bufsz - fu_dfu_firmware_get_footer_len(dfu_firmware)) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "invalid DfuSe image size, "
+ "got %" G_GUINT32_FORMAT ", "
+ "expected %" G_GSIZE_FORMAT,
+ image_size,
+ bufsz - fu_dfu_firmware_get_footer_len(dfu_firmware));
+ return FALSE;
+ }
+
+ /* parse the image targets */
+ if (!fu_memread_uint8_safe(buf,
+ bufsz,
+ offset + G_STRUCT_OFFSET(DfuSeHdr, targets),
+ &targets,
+ error))
+ return FALSE;
+ offset += sizeof(DfuSeHdr);
+ for (guint i = 0; i < targets; i++) {
+ g_autoptr(FuFirmware) image = NULL;
+ image =
+ fu_dfuse_firmware_image_parse(FU_DFUSE_FIRMWARE(firmware), fw, &offset, error);
+ if (image == NULL)
+ return FALSE;
+ fu_firmware_add_image(firmware, image);
+ }
+ return TRUE;
+}
+
+static GBytes *
+fu_firmware_chunk_write(FuChunk *chk)
+{
+ DfuSeElementHdr hdr = {0x0};
+ const guint8 *data = fu_chunk_get_data(chk);
+ gsize length = fu_chunk_get_data_sz(chk);
+ g_autoptr(GByteArray) buf = NULL;
+
+ buf = g_byte_array_sized_new(sizeof(DfuSeElementHdr) + length);
+ hdr.address = GUINT32_TO_LE(fu_chunk_get_address(chk));
+ hdr.size = GUINT32_TO_LE(length);
+ g_byte_array_append(buf, (const guint8 *)&hdr, sizeof(hdr));
+ g_byte_array_append(buf, data, length);
+ return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+}
+
+static GBytes *
+fu_dfuse_firmware_write_image(FuFirmware *image, GError **error)
+{
+ DfuSeImageHdr hdr = {0x0};
+ gsize totalsz = 0;
+ g_autoptr(GByteArray) buf = NULL;
+ g_autoptr(GPtrArray) blobs = NULL;
+ g_autoptr(GPtrArray) chunks = NULL;
+
+ /* get total size */
+ blobs = g_ptr_array_new_with_free_func((GDestroyNotify)g_bytes_unref);
+ chunks = fu_firmware_get_chunks(image, error);
+ if (chunks == NULL)
+ return NULL;
+ for (guint i = 0; i < chunks->len; i++) {
+ FuChunk *chk = g_ptr_array_index(chunks, i);
+ GBytes *bytes = fu_firmware_chunk_write(chk);
+ g_ptr_array_add(blobs, bytes);
+ totalsz += g_bytes_get_size(bytes);
+ }
+
+ /* mutable output buffer */
+ buf = g_byte_array_sized_new(sizeof(DfuSeImageHdr) + totalsz);
+
+ /* add prefix */
+ memcpy(hdr.sig, "Target", 6);
+ hdr.alt_setting = fu_firmware_get_idx(image);
+ if (fu_firmware_get_id(image) != NULL) {
+ hdr.target_named = GUINT32_TO_LE(0x01);
+ (void)g_strlcpy((gchar *)&hdr.target_name,
+ fu_firmware_get_id(image),
+ sizeof(hdr.target_name));
+ }
+ hdr.target_size = GUINT32_TO_LE(totalsz);
+ hdr.chunks = GUINT32_TO_LE(chunks->len);
+ g_byte_array_append(buf, (const guint8 *)&hdr, sizeof(hdr));
+
+ /* copy data */
+ for (guint i = 0; i < blobs->len; i++) {
+ GBytes *blob = g_ptr_array_index(blobs, i);
+ fu_byte_array_append_bytes(buf, blob);
+ }
+ return g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+}
+
+static GBytes *
+fu_dfuse_firmware_write(FuFirmware *firmware, GError **error)
+{
+ DfuSeHdr hdr = {0x0};
+ gsize totalsz = 0;
+ g_autoptr(GByteArray) buf = NULL;
+ g_autoptr(GBytes) blob_noftr = NULL;
+ g_autoptr(GPtrArray) blobs = NULL;
+ g_autoptr(GPtrArray) images = NULL;
+
+ /* create mutable output buffer */
+ blobs = g_ptr_array_new_with_free_func((GDestroyNotify)g_bytes_unref);
+ images = fu_firmware_get_images(FU_FIRMWARE(firmware));
+ for (guint i = 0; i < images->len; i++) {
+ FuFirmware *img = g_ptr_array_index(images, i);
+ g_autoptr(GBytes) blob = NULL;
+ blob = fu_dfuse_firmware_write_image(img, error);
+ if (blob == NULL)
+ return NULL;
+ totalsz += g_bytes_get_size(blob);
+ g_ptr_array_add(blobs, g_steal_pointer(&blob));
+ }
+ buf = g_byte_array_sized_new(sizeof(DfuSeHdr) + totalsz);
+
+ /* DfuSe header */
+ memcpy(hdr.sig, "DfuSe", 5);
+ hdr.ver = 0x01;
+ hdr.image_size = GUINT32_TO_LE(sizeof(hdr) + totalsz);
+ if (images->len > G_MAXUINT8) {
+ g_set_error(error,
+ FWUPD_ERROR,
+ FWUPD_ERROR_INTERNAL,
+ "too many (%u) images to write DfuSe file",
+ images->len);
+ return NULL;
+ }
+ hdr.targets = (guint8)images->len;
+ g_byte_array_append(buf, (const guint8 *)&hdr, sizeof(hdr));
+
+ /* copy images */
+ for (guint i = 0; i < blobs->len; i++) {
+ GBytes *blob = g_ptr_array_index(blobs, i);
+ fu_byte_array_append_bytes(buf, blob);
+ }
+
+ /* return blob */
+ blob_noftr = g_byte_array_free_to_bytes(g_steal_pointer(&buf));
+ return fu_dfu_firmware_append_footer(FU_DFU_FIRMWARE(firmware), blob_noftr, error);
+}
+
+static void
+fu_dfuse_firmware_init(FuDfuseFirmware *self)
+{
+ fu_dfu_firmware_set_version(FU_DFU_FIRMWARE(self), FU_DFU_FIRMARE_VERSION_DFUSE);
+}
+
+static void
+fu_dfuse_firmware_class_init(FuDfuseFirmwareClass *klass)
+{
+ FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS(klass);
+ klass_firmware->check_magic = fu_dfuse_firmware_check_magic;
+ klass_firmware->parse = fu_dfuse_firmware_parse;
+ klass_firmware->write = fu_dfuse_firmware_write;
+}
+
+/**
+ * fu_dfuse_firmware_new:
+ *
+ * Creates a new #FuFirmware of sub type DfuSe
+ *
+ * Since: 1.5.6
+ **/
+FuFirmware *
+fu_dfuse_firmware_new(void)
+{
+ return FU_FIRMWARE(g_object_new(FU_TYPE_DFUSE_FIRMWARE, NULL));
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dfuse-firmware.h b/fwupd-1.8.6/libfwupdplugin/fu-dfuse-firmware.h
new file mode 100644
index 0000000000000000000000000000000000000000..e98127daca979c3feb55135ce1e9bf92f8cf45ca
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dfuse-firmware.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include "fu-dfu-firmware.h"
+
+#define FU_TYPE_DFUSE_FIRMWARE (fu_dfuse_firmware_get_type())
+G_DECLARE_DERIVABLE_TYPE(FuDfuseFirmware, fu_dfuse_firmware, FU, DFUSE_FIRMWARE, FuDfuFirmware)
+
+struct _FuDfuseFirmwareClass {
+ FuDfuFirmwareClass parent_class;
+};
+
+FuFirmware *
+fu_dfuse_firmware_new(void);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dump.c b/fwupd-1.8.6/libfwupdplugin/fu-dump.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd8373c29d80b9538b6e1dd0c7f5cf1e8cd79962
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dump.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#define G_LOG_DOMAIN "FuCommon"
+
+#include "config.h"
+
+#include "fu-dump.h"
+
+/**
+ * fu_dump_full:
+ * @log_domain: (nullable): optional log domain, typically %G_LOG_DOMAIN
+ * @title: (nullable): optional prefix title
+ * @data: buffer to print
+ * @len: the size of @data
+ * @columns: break new lines after this many bytes
+ * @flags: dump flags, e.g. %FU_DUMP_FLAGS_SHOW_ASCII
+ *
+ * Dumps a raw buffer to the screen.
+ *
+ * Since: 1.8.2
+ **/
+void
+fu_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);
+ if (flags & FU_DUMP_FLAGS_SHOW_ASCII)
+ g_string_append(str, " ");
+ }
+ g_string_append(str, "\n───────┼");
+ for (gsize i = 0; i < columns; i++) {
+ g_string_append(str, "───");
+ if (flags & FU_DUMP_FLAGS_SHOW_ASCII)
+ 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_dump_raw:
+ * @log_domain: (nullable): optional log domain, typically %G_LOG_DOMAIN
+ * @title: (nullable): optional prefix title
+ * @data: buffer to print
+ * @len: the size of @data
+ *
+ * Dumps a raw buffer to the screen.
+ *
+ * Since: 1.8.2
+ **/
+void
+fu_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_dump_full(log_domain, title, data, len, 32, flags);
+}
+
+/**
+ * fu_dump_bytes:
+ * @log_domain: (nullable): optional log domain, typically %G_LOG_DOMAIN
+ * @title: (nullable): optional prefix title
+ * @bytes: data blob
+ *
+ * Dumps a byte buffer to the screen.
+ *
+ * Since: 1.8.2
+ **/
+void
+fu_dump_bytes(const gchar *log_domain, const gchar *title, GBytes *bytes)
+{
+ gsize len = 0;
+ const guint8 *data = g_bytes_get_data(bytes, &len);
+ fu_dump_raw(log_domain, title, data, len);
+}
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-dump.h b/fwupd-1.8.6/libfwupdplugin/fu-dump.h
new file mode 100644
index 0000000000000000000000000000000000000000..3908dfe9f631acb9b2083086d9b913569d4e3769
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-dump.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 Richard Hughes
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include
+
+/**
+ * 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;
+
+void
+fu_dump_raw(const gchar *log_domain, const gchar *title, const guint8 *data, gsize len);
+void
+fu_dump_full(const gchar *log_domain,
+ const gchar *title,
+ const guint8 *data,
+ gsize len,
+ guint columns,
+ FuDumpFlags flags);
+void
+fu_dump_bytes(const gchar *log_domain, const gchar *title, GBytes *bytes);
diff --git a/fwupd-1.8.6/libfwupdplugin/fu-efi-common.c b/fwupd-1.8.6/libfwupdplugin/fu-efi-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..b9397f67728294f8d7794c7da755a95eb217fda7
--- /dev/null
+++ b/fwupd-1.8.6/libfwupdplugin/fu-efi-common.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 Richard Hughes