1 Commits
Author SHA1 Message Date
Konrad Dybcio f803b4d573 meson.build: Set v1.1 version
Signed-off-by: Konrad Dybcio <konrad.dybcio@linaro.org>
2024-07-23 14:22:35 +02:00
20 changed files with 194 additions and 1302 deletions

No files matched your search

-147
View File
@@ -1,147 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Loosely based on the cdba project CI:
# https://github.com/linux-msm/cdba
#
name: "Builds"
on:
pull_request:
push:
schedule:
# Run at 1:01 PM, every Tuesday
- cron: '1 13 * * 2'
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
compiler: [gcc, clang]
# zstd and xz support are autodetected: the "enabled" variant installs
# the corresponding development package, the "disabled" one does not.
zstd: [enabled, disabled]
xz: [enabled, disabled]
container:
- alpine:latest
- archlinux:latest
- debian:testing
- debian:stable
- fedora:latest
- ubuntu:latest
- ubuntu:noble
exclude:
# zstd and xz ship in the Arch base image and cannot be removed, so
# the "disabled" builds cannot be exercised there.
- container: archlinux:latest
zstd: disabled
- container: archlinux:latest
xz: disabled
container:
image: ${{ matrix.container }}
env:
CC: ${{ matrix.compiler }}
ZSTD: ${{ matrix.zstd }}
XZ: ${{ matrix.xz }}
steps:
- name: Show OS
run: cat /etc/os-release
- name: Git checkout
uses: actions/checkout@v5
- name: Install additional packages
run: |
INSTALL=${{ matrix.container }}
INSTALL="${INSTALL%%:*}"
INSTALL="${INSTALL%%/*}"
./ci/$INSTALL.sh
- name: Compiler version
run: $CC --version
- name: Meson setup
run: meson setup --errorlogs --werror build .
- name: Compile
run: ninja -C build
- name: Verify zstd autodetection
run: ./ci/check-zstd.sh
- name: Verify xz autodetection
run: ./ci/check-xz.sh
- name: Install
run: ninja -C build install
android:
name: Android
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
abi: [arm64-v8a, armeabi-v7a, x86_64]
env:
NDK_VERSION: r27d
QRTR_REF: v1.2
API: "24"
ABI: ${{ matrix.abi }}
QRTR_SRC: ${{ github.workspace }}/qrtr
QRTR_PREFIX: ${{ github.workspace }}/qrtr-install/${{ matrix.abi }}
steps:
- name: Git checkout
uses: actions/checkout@v5
- name: Install build tools
run: |
sudo apt update
sudo apt install -y --no-install-recommends meson ninja-build pkg-config
- name: Cache Android NDK
id: ndk-cache
uses: actions/cache@v4
with:
path: android-ndk-${{ env.NDK_VERSION }}
key: ndk-${{ env.NDK_VERSION }}-linux
- name: Download Android NDK
if: steps.ndk-cache.outputs.cache-hit != 'true'
run: |
curl -sSLO https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-linux.zip
unzip -q android-ndk-${NDK_VERSION}-linux.zip
rm android-ndk-${NDK_VERSION}-linux.zip
- name: Cache libqrtr
id: qrtr-cache
uses: actions/cache@v4
with:
path: qrtr-install/${{ matrix.abi }}
key: qrtr-android-${{ matrix.abi }}-${{ env.QRTR_REF }}-ndk-${{ env.NDK_VERSION }}
- name: Checkout qrtr
if: steps.qrtr-cache.outputs.cache-hit != 'true'
uses: actions/checkout@v5
with:
repository: linux-msm/qrtr
ref: ${{ env.QRTR_REF }}
path: qrtr
- name: Build for Android
run: |
export ANDROID_NDK="$GITHUB_WORKSPACE/android-ndk-${NDK_VERSION}"
./ci/android.sh
-53
View File
@@ -1,53 +0,0 @@
# tqftpserv
The tqftpserv software is an implementation of a TFTP (Trivial File Transfer Protocol) server which runs on top of the AF_QIPCRTR (a.k.a QRTR) socket type.
The main purpose of tqftpserv is to serve files from the Linux file system to other processors on the Qualcomm SoCs as requested.
The protocol implemented here is (loosely) based on RFC 1350 including some extensions to the protocol.
In basic terms, the protocol supports RRQ (Read Request) and WRQ (Write Request) messages which read and write files respectively. A request can have some extra options, like `blksize` ior `wsize`. The meaning of those is documented in the `parse_options` function.
For reference, the proprietary implementation of this that is used on practically all Qualcomm-based Android devices is called "tftp_server".
## File paths
There's two different virtual paths prefixes that are supported:
* `/readonly/firmware/image/` for read-only files such as firmware files
* `/readwrite/` for read-write (temporary) files
Requests to those paths are "translated" (see `translate.c`) to paths in the Linux filesystem. In a regular setup readonly requests go to `/lib/firmware/` and readwrite requests go to `/tmp/tqftpserv/`.
Translating those readonly request paths tries to take into account custom Linux firmware paths, custom "firmware-name" paths for remoteprocs, .zstd compressed firmware and more. In case of doubt, please consult the source code.
For example on a QCM6490 Fairphone 5 smartphone the path for `/readonly/firmware/image/modem_pr/so/901_0_0.mbn` will be translated to `/lib/firmware/qcom/qcm6490/fairphone5/modem_pr/so/901_0_0.mbn`, based on the devicetree property `firmware-name = "qcom/qcm6490/fairphone5/modem.mbn";` in the modem/mpss DT node.
The actual paths that are used and requested are dependent on the TFTP clients, which is usually the firmware that is running on the Hexagon-based modem processor on the SoC.
## Example requests
The following are some example requests which are grabbed from the tqftpserv log during modem bootup.
* Write content to a file called "server_check.txt":
```
[TQFTP] WRQ: /readwrite/server_check.txt (octet)
```
* Read a file called "ota_firewall/ruleset" which does not exist:
```
[TQFTP] RRQ: /readwrite/ota_firewall/ruleset (mode=octet rsize=0 seek=0)
tqftpserv: failed to open ota_firewall/ruleset: No such file or directory
[TQFTP] unable to open /readwrite/ota_firewall/ruleset (2), reject
```
* Stat a file with the path "modem_pr/so/901_0_0.mbn", and then read it:
```
[TQFTP] RRQ: /readonly/firmware/image/modem_pr/so/901_0_0.mbn (mode=octet rsize=0 seek=0)
[TQFTP] Remote returned END OF TRANSFER: 9 - End of Transfer
[TQFTP] RRQ: /readonly/firmware/image/modem_pr/so/901_0_0.mbn (mode=octet rsize=52 seek=0)
```
In binary such a request can look like the following:
```
\0\1/readonly/firmware/image/modem_pr/so/901_0_0.mbn\0octet\0blksize\0007680\0timeoutms\0001000\0tsize\0000\0wsize\00010\0
```
-39
View File
@@ -1,39 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Install build dependencies on Alpine Linux.
set -ex
# build-base pulls in binutils (the linker/assembler) and the musl headers,
# which clang needs as well; add clang on top when it is the compiler.
PKGS_CC=""
case $CC in
clang*)
PKGS_CC="clang"
;;
esac
PKGS_ZSTD=""
if [ "$ZSTD" = "enabled" ]; then
PKGS_ZSTD="zstd-dev"
fi
PKGS_XZ=""
if [ "$XZ" = "enabled" ]; then
PKGS_XZ="xz-dev"
fi
apk add \
build-base \
pkgconf \
meson \
ninja \
qrtr-dev \
$PKGS_ZSTD \
$PKGS_XZ \
$PKGS_CC
echo "Install finished: $0"
-77
View File
@@ -1,77 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Cross-build tqftpserv (and its libqrtr dependency) for Android using the NDK.
#
# Expects the following environment variables:
# ABI - Android ABI (arm64-v8a, armeabi-v7a, x86_64)
# API - Android API level to target
# ANDROID_NDK - path to an unpacked Android NDK
# QRTR_SRC - path to a checked-out qrtr source tree
# QRTR_PREFIX - prefix into which libqrtr is (or was) installed
set -ex
TOOLCHAIN="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64"
case "$ABI" in
arm64-v8a)
CPU_FAMILY=aarch64
CPU=aarch64
TRIPLE=aarch64-linux-android
ELF_MACHINE=AArch64
;;
armeabi-v7a)
CPU_FAMILY=arm
CPU=armv7a
TRIPLE=armv7a-linux-androideabi
ELF_MACHINE=ARM
;;
x86_64)
CPU_FAMILY=x86_64
CPU=x86_64
TRIPLE=x86_64-linux-android
ELF_MACHINE=X86-64
;;
*)
echo "Unknown ABI '$ABI'" >&2
exit 1
;;
esac
# The per-ABI clang wrapper already selects the correct target and sysroot, so
# the cross file does not need to spell those out.
cat > android-cross.txt <<EOF
[binaries]
c = '$TOOLCHAIN/bin/${TRIPLE}${API}-clang'
ar = '$TOOLCHAIN/bin/llvm-ar'
strip = '$TOOLCHAIN/bin/llvm-strip'
pkg-config = 'pkg-config'
[host_machine]
system = 'android'
cpu_family = '$CPU_FAMILY'
cpu = '$CPU'
endian = 'little'
[properties]
pkg_config_libdir = '$QRTR_PREFIX/lib/pkgconfig'
EOF
cat android-cross.txt
# Build and install libqrtr, unless it was already restored from the cache.
if [ ! -f "$QRTR_PREFIX/lib/pkgconfig/qrtr.pc" ]; then
meson setup --cross-file android-cross.txt \
--prefix="$QRTR_PREFIX" --libdir=lib \
"$QRTR_SRC/build-$ABI" "$QRTR_SRC"
ninja -C "$QRTR_SRC/build-$ABI" install
fi
meson setup --errorlogs --werror --cross-file android-cross.txt build .
ninja -C build
# Confirm the resulting binary really is for the requested ABI.
"$TOOLCHAIN/bin/llvm-readelf" -h build/tqftpserv | grep -q "Machine:.*$ELF_MACHINE"
echo "Android build for $ABI ($ELF_MACHINE) succeeded"
-38
View File
@@ -1,38 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Install build dependencies on Arch Linux.
#
# qrtr is only packaged in the AUR, which is not available in the CI
# container, so build and install it from source.
set -ex
PKGS_CC="gcc"
case $CC in
clang*)
PKGS_CC="clang"
;;
esac
# zstd and xz (liblzma) ship as part of the Arch base image and cannot be
# removed, so there is no "disabled" variant to install here.
pacman -Syu --noconfirm \
pkgconf \
meson \
ninja \
git \
zstd \
xz \
$PKGS_CC
QRTR_SRC=$(mktemp -d)
git clone --depth 1 https://github.com/linux-msm/qrtr "$QRTR_SRC"
meson setup --prefix=/usr "$QRTR_SRC/build" "$QRTR_SRC"
ninja -C "$QRTR_SRC/build"
ninja -C "$QRTR_SRC/build" install
rm -rf "$QRTR_SRC"
echo "Install finished: $0"
-32
View File
@@ -1,32 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Verify that xz support was autodetected as expected: xz-decompress.c is
# only compiled when liblzma is available.
set -eu
OBJ=build/tqftpserv.p/xz-decompress.c.o
case "$XZ" in
enabled)
if [ ! -f "$OBJ" ]; then
echo "ERROR: expected xz support, but xz-decompress.c was not built"
exit 1
fi
;;
disabled)
if [ -f "$OBJ" ]; then
echo "ERROR: expected no xz support, but xz-decompress.c was built"
exit 1
fi
;;
*)
echo "ERROR: unexpected XZ value '$XZ'"
exit 1
;;
esac
echo "xz support check ($XZ) passed"
-32
View File
@@ -1,32 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Verify that zstd support was autodetected as expected: zstd-decompress.c is
# only compiled when libzstd is available.
set -eu
OBJ=build/tqftpserv.p/zstd-decompress.c.o
case "$ZSTD" in
enabled)
if [ ! -f "$OBJ" ]; then
echo "ERROR: expected zstd support, but zstd-decompress.c was not built"
exit 1
fi
;;
disabled)
if [ -f "$OBJ" ]; then
echo "ERROR: expected no zstd support, but zstd-decompress.c was built"
exit 1
fi
;;
*)
echo "ERROR: unexpected ZSTD value '$ZSTD'"
exit 1
;;
esac
echo "zstd support check ($ZSTD) passed"
-41
View File
@@ -1,41 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Install build dependencies on Debian and Ubuntu.
set -ex
apt update
# Some distros might pull tzdata which asks questions
export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true
PKGS_CC="build-essential"
case $CC in
clang*)
PKGS_CC="clang"
;;
esac
PKGS_ZSTD=""
if [ "$ZSTD" = "enabled" ]; then
PKGS_ZSTD="libzstd-dev"
fi
PKGS_XZ=""
if [ "$XZ" = "enabled" ]; then
PKGS_XZ="liblzma-dev"
fi
apt install -y --no-install-recommends \
pkg-config \
meson \
ninja-build \
libqrtr-dev \
$PKGS_ZSTD \
$PKGS_XZ \
$PKGS_CC
echo "Install finished: $0"
-36
View File
@@ -1,36 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#
# Install build dependencies on Fedora.
set -ex
PKGS_CC="gcc"
case $CC in
clang*)
PKGS_CC="clang"
;;
esac
PKGS_ZSTD=""
if [ "$ZSTD" = "enabled" ]; then
PKGS_ZSTD="libzstd-devel"
fi
PKGS_XZ=""
if [ "$XZ" = "enabled" ]; then
PKGS_XZ="xz-devel"
fi
dnf -y install \
pkgconf-pkg-config \
meson \
ninja-build \
qrtr-devel \
$PKGS_ZSTD \
$PKGS_XZ \
$PKGS_CC
echo "Install finished: $0"
-1
View File
@@ -1 +0,0 @@
debian.sh
+18 -43
View File
@@ -2,7 +2,7 @@
project('tqftpserv',
'c',
version: '1.1.1',
version: '1.1',
default_options: [
'warning_level=1',
'buildtype=release',
@@ -10,55 +10,30 @@ project('tqftpserv',
prefix = get_option('prefix')
if host_machine.system() == 'android'
add_project_arguments('-DANDROID', language : 'c')
zstd_dep = dependency('libzstd')
# Not required to build the executable, only to install unit file
systemd = dependency('systemd', required : false)
if systemd.found()
systemd_system_unit_dir = get_option('systemd-unit-prefix')
if systemd_system_unit_dir == ''
systemd_system_unit_dir = systemd.get_variable(
pkgconfig : 'systemdsystemunitdir',
pkgconfig_define: ['prefix', prefix])
endif
endif
qrtr_dep = dependency('qrtr')
tqftpserv_srcs = ['translate.c',
'tqftpserv.c']
tqftpserv_deps = []
xz_dep = dependency('liblzma', required : false)
if xz_dep.found()
add_project_arguments('-DHAVE_XZ', language : 'c')
tqftpserv_srcs += 'xz-decompress.c'
tqftpserv_deps += xz_dep
endif
zstd_dep = dependency('libzstd', required : false)
if zstd_dep.found()
add_project_arguments('-DHAVE_ZSTD', language : 'c')
tqftpserv_srcs += 'zstd-decompress.c'
tqftpserv_deps += zstd_dep
endif
# Not required to build the executable,
# only to automatically retrieve the install dir for unit files
systemd = dependency('systemd', required : false)
if get_option('systemd-unit-prefix') != ''
systemd_system_unit_dir = get_option('systemd-unit-prefix')
elif systemd.found()
systemd_system_unit_dir = systemd.get_variable(
pkgconfig : 'systemdsystemunitdir',
pkgconfig_define: ['prefix', prefix])
else
systemd_system_unit_dir = ''
endif
qrtr_dep = dependency('qrtr', required : false)
if not qrtr_dep.found()
# Support old libqrtr that does not ship a qrtr.pc pkg-config file.
cc = meson.get_compiler('c')
qrtr_dep = cc.find_library('qrtr', has_headers : 'libqrtr.h')
endif
tqftpserv_deps += qrtr_dep
'tqftpserv.c',
'zstd-decompress.c']
executable('tqftpserv',
tqftpserv_srcs,
dependencies : tqftpserv_deps,
dependencies : [qrtr_dep, zstd_dep],
install : true)
if systemd_system_unit_dir != ''
if systemd.found()
systemd_unit_conf = configuration_data()
systemd_unit_conf.set('prefix', prefix)
configure_file(
-20
View File
@@ -1,20 +0,0 @@
#!/usr/bin/sh
# Populate tqftp readwrite data from persist partition
set -eu
PERSIST_DEV="/dev/disk/by-partlabel/persist"
PERSIST_MOUNT="/mnt/persist"
TQFTPSERV_TMP="/var/lib/tqftpserv"
if [ -f $TQFTPSERV_TMP/readwrite_ready ]; then
exit 0
fi
mkdir -p $PERSIST_MOUNT
mount $PERSIST_DEV -o ro,noatime $PERSIST_MOUNT
mkdir -p $TQFTPSERV_TMP
cp -r $PERSIST_MOUNT/rfs/msm/mpss/* $TQFTPSERV_TMP/
touch $TQFTPSERV_TMP/readwrite_ready
umount $PERSIST_MOUNT
rmdir $PERSIST_MOUNT
-11
View File
@@ -1,11 +0,0 @@
[Unit]
Description= Populate tqftp readwrite data from persist partition
Requires=dev-disk-by\x2dpartlabel-persist.device
After=dev-disk-by\x2dpartlabel-persist.device
[Service]
Type=oneshot
ExecStart=@prefix@/bin/populate-readwrite.sh
[Install]
WantedBy=multi-user.target
+130 -509
View File
File diff suppressed because it is too large. Load diff
+3 -1
View File
@@ -1,10 +1,12 @@
[Unit]
Description=QRTR TFTP service
Requires=qrtr-ns.service
After=qrtr-ns.service
[Service]
ExecStart=@prefix@/bin/tqftpserv
Restart=always
StateDirectory=tqftpserv
[Install]
WantedBy=multi-user.target
+20 -68
View File
@@ -16,23 +16,17 @@
#include <unistd.h>
#include "translate.h"
#include "xz-decompress.h"
#include "zstd-decompress.h"
#define READONLY_PATH "/readonly/firmware/image/"
#define READWRITE_PATH "/readwrite/"
#define UPDATES_DIR "updates/"
#define READONLY_FW_BASE "/readonly/firmware/"
#define READONLY_MODEM_PATH READONLY_FW_BASE "modem_pr"
#define READONLY_VENDOR_PATH "/readonly/vendor/firmware/"
#define READONLY_VENDOR_MNT_PATH "/readonly/vendor/firmware_mnt/image/"
#ifndef ANDROID
#define FIRMWARE_BASE "/lib/firmware/"
#define TQFTPSERV_RW_DIR "/var/lib/tqftpserv"
#define TQFTPSERV_TMP "/tmp/tqftpserv"
#else
#define FIRMWARE_BASE "/vendor/firmware/"
#define TQFTPSERV_RW_DIR "/data/vendor/tmp/tqftpserv"
#define TQFTPSERV_TMP "/data/vendor/tmp/tqftpserv"
#endif
static int open_maybe_compressed(const char *path);
@@ -135,25 +129,17 @@ static int translate_readonly(const char *file)
}
/* now try with base path */
if (strlen(FIRMWARE_BASE) + strlen(UPDATES_DIR) + strlen(firmware_value) + 1 +
if (strlen(FIRMWARE_BASE) + strlen(firmware_value) + 1 +
strlen(file) + 1 > sizeof(path))
continue;
strcpy(path, FIRMWARE_BASE);
strcat(path, UPDATES_DIR);
strcat(path, firmware_path);
strcat(path, "/");
strcat(path, file);
fd = open_maybe_compressed(path);
if (fd < 0) {
strcpy(path, FIRMWARE_BASE);
strcat(path, firmware_path);
strcat(path, "/");
strcat(path, file);
fd = open_maybe_compressed(path);
}
if (fd >= 0)
break;
@@ -168,7 +154,7 @@ static int translate_readonly(const char *file)
}
/**
* translate_readwrite() - open "file" from the persistent readwrite directory
* translate_readwrite() - open "file" from a temporary directory
* @file: relative path of the requested file, with /readwrite/ stripped
* @flags: flags to be passed to open(2)
*
@@ -180,22 +166,15 @@ static int translate_readwrite(const char *file, int flags)
int ret;
int fd;
/* Reject directory traversal attempts */
if (strstr(file, "..")) {
warn("path traversal attempt rejected: %s", file);
errno = EACCES;
return -1;
}
ret = mkdir(TQFTPSERV_RW_DIR, 0700);
ret = mkdir(TQFTPSERV_TMP, 0700);
if (ret < 0 && errno != EEXIST) {
warn("failed to create tqftpserv readwrite directory");
warn("failed to create temporary tqftpserv directory");
return -1;
}
base = open(TQFTPSERV_RW_DIR, O_RDONLY | O_DIRECTORY);
base = open(TQFTPSERV_TMP, O_RDONLY | O_DIRECTORY);
if (base < 0) {
warn("failed to open tqftpserv readwrite directory");
warn("failed top open temporary tqftpserv directory");
return -1;
}
@@ -210,33 +189,23 @@ static int translate_readwrite(const char *file, int flags)
/**
* translate_open() - open file after translating path
*
* Strips /readonly/firmware/image/ and searches among remoteproc firmware.
* Strips /readonly/firmware/modem_pr and searches among remoteproc firmware
* using the modem_pr relative path (e.g., maps to READONLY_FW_BASE/<fw_dir>/modem_pr/...).
* Strips /readonly/vendor/firmware/ and /readonly/vendor/firmware_mnt/image/
* and searches among remoteproc firmware.
* Replaces /readwrite/ with a persistent directory.
* Strips /readonly/firmware/image and search among remoteproc firmware.
* Replaces /readwrite with a temporary directory.
*/
int translate_open(const char *path, int flags)
{
if (!strncmp(path, READONLY_PATH, strlen(READONLY_PATH)))
return translate_readonly(path + strlen(READONLY_PATH));
else if (!strncmp(path, READONLY_MODEM_PATH, strlen(READONLY_MODEM_PATH)))
return translate_readonly(path + strlen(READONLY_FW_BASE));
else if (!strncmp(path, READWRITE_PATH, strlen(READWRITE_PATH)))
return translate_readwrite(path + strlen(READWRITE_PATH), flags);
else if (!strncmp(path, READONLY_VENDOR_MNT_PATH, strlen(READONLY_VENDOR_MNT_PATH)))
return translate_readonly(path + strlen(READONLY_VENDOR_MNT_PATH));
else if (!strncmp(path, READONLY_VENDOR_PATH, strlen(READONLY_VENDOR_PATH)))
return translate_readonly(path + strlen(READONLY_VENDOR_PATH));
fprintf(stderr, "invalid path %s, rejecting\n", path);
errno = ENOENT;
return -1;
}
/* linux-firmware uses .xz as file extension */
#define XZ_EXTENSION ".xz"
/* linux-firmware uses .zst as file extension */
#define ZSTD_EXTENSION ".zst"
@@ -248,33 +217,16 @@ int translate_open(const char *path, int flags)
*/
static int open_maybe_compressed(const char *path)
{
char *path_with_extension = NULL;
int fd = -1;
int ret;
if (access(path, F_OK) == 0)
return open(path, O_RDONLY);
ret = asprintf(&path_with_extension, "%s%s", path, XZ_EXTENSION);
if (ret < 0)
return ret;
if (access(path_with_extension, F_OK) == 0)
fd = xz_decompress_file(path_with_extension);
free(path_with_extension);
if (fd != -1)
return fd;
ret = asprintf(&path_with_extension, "%s%s", path, ZSTD_EXTENSION);
if (ret < 0)
return ret;
if (access(path_with_extension, F_OK) == 0)
fd = zstd_decompress_file(path_with_extension);
free(path_with_extension);
if (access(path, F_OK) == 0) {
fd = open(path, O_RDONLY);
} else {
char *path_with_zstd_extension = NULL;
asprintf(&path_with_zstd_extension, "%s%s", path, ZSTD_EXTENSION);
fd = zstd_decompress_file(path_with_zstd_extension);
free(path_with_zstd_extension);
}
return fd;
}
-109
View File
@@ -1,109 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*
* Based on the code copyright by:
* Copyright (c) 2024, Stefan Hansson
* Copyright (c) 2024, Emil Velikov
*/
/* For memfd_create */
#define _GNU_SOURCE
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <lzma.h>
#include "xz-decompress.h"
/**
* xz_decompress_file() - decompress an xz-compressed file
* @filename: path to a file to decompress
*
* The xz format does not store the uncompressed size in an easily
* queryable header, so decode the stream incrementally and write the
* output to a memfd as it is produced.
*
* Return: opened fd on success, -1 on error
*/
int xz_decompress_file(const char *filename)
{
/* Figure out the size of the file. */
struct stat file_stat;
if (stat(filename, &file_stat) == -1) {
fprintf(stderr, "stat %s failed (%s)\n", filename, strerror(errno));
return -1;
}
const size_t file_size = file_stat.st_size;
const int input_file_fd = open(filename, O_RDONLY);
if (input_file_fd == -1) {
perror("open failed");
return -1;
}
void* const compressed_buffer = mmap(NULL, file_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, input_file_fd, 0);
if (compressed_buffer == MAP_FAILED) {
perror("mmap failed");
close(input_file_fd);
return -1;
}
close(input_file_fd);
lzma_stream strm = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX, 0);
if (ret != LZMA_OK) {
fprintf(stderr, "lzma_stream_decoder failed for %s (error %d)\n", filename, ret);
munmap(compressed_buffer, file_size);
return -1;
}
const int output_file_fd = memfd_create(filename, 0);
if (output_file_fd == -1) {
perror("memfd_create failed");
lzma_end(&strm);
munmap(compressed_buffer, file_size);
return -1;
}
uint8_t output_buffer[BUFSIZ];
strm.next_in = compressed_buffer;
strm.avail_in = file_size;
do {
strm.next_out = output_buffer;
strm.avail_out = sizeof(output_buffer);
ret = lzma_code(&strm, LZMA_FINISH);
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
fprintf(stderr, "lzma_code failed for %s (error %d)\n", filename, ret);
close(output_file_fd);
lzma_end(&strm);
munmap(compressed_buffer, file_size);
return -1;
}
const size_t produced = sizeof(output_buffer) - strm.avail_out;
if (write(output_file_fd, output_buffer, produced) != (ssize_t)produced) {
perror("write failed");
close(output_file_fd);
lzma_end(&strm);
munmap(compressed_buffer, file_size);
return -1;
}
} while (ret != LZMA_STREAM_END);
lzma_end(&strm);
munmap(compressed_buffer, file_size);
return output_file_fd;
}
-22
View File
@@ -1,22 +0,0 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef __XZ_DECOMPRESS_H__
#define __XZ_DECOMPRESS_H__
#include <stdbool.h>
#include <stdio.h>
#ifdef HAVE_XZ
int xz_decompress_file(const char *filename);
#else
static int xz_decompress_file(const char *filename)
{
fprintf(stderr, "Built without XZ support\n");
return -1;
}
#endif
#endif
+21 -14
View File
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2024, Stefan Hansson
* Copyright (c) 2024, Emil Velikov
*/
/* For memfd_create */
@@ -9,7 +8,6 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -19,6 +17,24 @@
#include "zstd-decompress.h"
static ZSTD_DCtx *zstd_context = NULL;
/**
* zstd_init() - set up state for decompression. Needs to be called before zstd_decompress_file()
*/
void zstd_init()
{
zstd_context = ZSTD_createDCtx();
}
/**
* zstd_free() - free state used for decompression. zstd_decompress_file() may not be called after this
*/
void zstd_free()
{
ZSTD_freeDCtx(zstd_context);
}
/**
* zstd_decompress_file() - decompress a zstd-compressed file
* @filename: path to a file to decompress
@@ -30,13 +46,13 @@ int zstd_decompress_file(const char *filename)
/* Figure out the size of the file. */
struct stat file_stat;
if (stat(filename, &file_stat) == -1) {
fprintf(stderr, "stat %s failed (%s)\n", filename, strerror(errno));
perror("stat failed");
return -1;
}
const size_t file_size = file_stat.st_size;
const int input_file_fd = open(filename, O_RDONLY);
const int input_file_fd = open(filename, 0);
if (input_file_fd == -1) {
perror("open failed");
return -1;
@@ -53,43 +69,34 @@ int zstd_decompress_file(const char *filename)
const unsigned long long decompressed_size = ZSTD_getFrameContentSize(compressed_buffer, file_size);
if (decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
fprintf(stderr, "Content size could not be determined for %s\n", filename);
munmap(compressed_buffer, file_size);
return -1;
}
if (decompressed_size == ZSTD_CONTENTSIZE_ERROR) {
fprintf(stderr, "Error getting content size for %s\n", filename);
munmap(compressed_buffer, file_size);
return -1;
}
void* const decompressed_buffer = malloc((size_t)decompressed_size);
if (decompressed_buffer == NULL) {
perror("malloc failed");
munmap(compressed_buffer, file_size);
return -1;
}
const size_t return_size = ZSTD_decompress(decompressed_buffer, decompressed_size, compressed_buffer, file_size);
const size_t return_size = ZSTD_decompressDCtx(zstd_context, decompressed_buffer, decompressed_size, compressed_buffer, file_size);
if (ZSTD_isError(return_size)) {
fprintf(stderr, "ZSTD_decompress failed: %s\n", ZSTD_getErrorName(return_size));
free(decompressed_buffer);
munmap(compressed_buffer, file_size);
return -1;
}
const int output_file_fd = memfd_create(filename, 0);
if (output_file_fd == -1) {
perror("memfd_create failed");
free(decompressed_buffer);
munmap(compressed_buffer, file_size);
return -1;
}
if (write(output_file_fd, decompressed_buffer, decompressed_size) != decompressed_size) {
perror("write failed");
close(output_file_fd);
free(decompressed_buffer);
munmap(compressed_buffer, file_size);
return -1;
}
+2 -9
View File
@@ -7,16 +7,9 @@
#define __ZSTD_DECOMPRESS_H__
#include <stdbool.h>
#include <stdio.h>
#ifdef HAVE_ZSTD
void zstd_init();
void zstd_free();
int zstd_decompress_file(const char *filename);
#else
static int zstd_decompress_file(const char *filename)
{
fprintf(stderr, "Built without ZSTD support\n");
return -1;
}
#endif
#endif