diff --git a/.github/scripts/strategy-matrix/generate.py b/.github/scripts/strategy-matrix/generate.py index 6f00c69416..6eccfcc6be 100755 --- a/.github/scripts/strategy-matrix/generate.py +++ b/.github/scripts/strategy-matrix/generate.py @@ -32,7 +32,32 @@ We will further set additional CMake arguments as follows: """ -def generate_strategy_matrix(all: bool, config: Config) -> list: +def build_config_name(os_entry: dict[str, str], platform: str, build_type: str) -> str: + parts = [os_entry["distro_name"]] + for key in ("distro_version", "compiler_name", "compiler_version"): + if value := os_entry[key]: + parts.append(value) + parts.append("arm64" if "arm64" in platform else "amd64") + parts.append(build_type.lower()) + return "-".join(parts) + + +def generate_packaging_matrix(config: Config) -> list[dict]: + """Emit one entry per os entry with `package: true`. Architecture is + hardcoded to linux/amd64 here (and the runner is hardcoded at the + workflow level) until arm64 packaging is ready. + """ + return [ + { + "artifact_name": f"xrpld-{build_config_name(os, 'linux/amd64', 'Release')}", + "os": os, + } + for os in config.os + if os.get("package", False) + ] + + +def generate_strategy_matrix(all: bool, config: Config) -> list[dict]: configurations = [] for architecture, os, build_type, cmake_args in itertools.product( config.architecture, config.os, config.build_type, config.cmake_args @@ -101,14 +126,15 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: continue # RHEL: - # - 9 using GCC 12: Debug on linux/amd64. + # - 9 using GCC 12: Debug and Release on linux/amd64 + # (Release is required for RPM packaging). # - 10 using Clang: Release on linux/amd64. if os["distro_name"] == "rhel": skip = True if os["distro_version"] == "9": if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" - and build_type == "Debug" + and build_type in ["Debug", "Release"] and architecture["platform"] == "linux/amd64" ): skip = False @@ -123,7 +149,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: continue # Ubuntu: - # - Jammy using GCC 12: Debug on linux/arm64. + # - Jammy using GCC 12: Debug on linux/arm64, Release on + # linux/amd64 (Release is required for DEB packaging). # - Noble using GCC 14: Release on linux/amd64. # - Noble using Clang 18: Debug on linux/amd64. # - Noble using Clang 19: Release on linux/arm64. @@ -136,6 +163,12 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: and architecture["platform"] == "linux/arm64" ): skip = False + if ( + f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" + and build_type == "Release" + and architecture["platform"] == "linux/amd64" + ): + skip = False elif os["distro_version"] == "noble": if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14" @@ -218,17 +251,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: # Generate a unique name for the configuration, e.g. macos-arm64-debug # or debian-bookworm-gcc-12-amd64-release. - config_name = os["distro_name"] - if (n := os["distro_version"]) != "": - config_name += f"-{n}" - if (n := os["compiler_name"]) != "": - config_name += f"-{n}" - if (n := os["compiler_version"]) != "": - config_name += f"-{n}" - config_name += ( - f"-{architecture['platform'][architecture['platform'].find('/')+1:]}" - ) - config_name += f"-{build_type.lower()}" + config_name = build_config_name(os, architecture["platform"], build_type) if "-Dcoverage=ON" in cmake_args: config_name += "-coverage" if "-Dunity=ON" in cmake_args: @@ -332,10 +355,19 @@ if __name__ == "__main__": required=False, type=Path, ) + parser.add_argument( + "-p", + "--packaging", + help="Emit the packaging matrix (derived from the 'package' field on os entries) instead of the build/test matrix.", + action="store_true", + ) args = parser.parse_args() matrix = [] - if args.config is None or args.config == "": + if args.packaging: + config_path = args.config if args.config else THIS_DIR / "linux.json" + matrix += generate_packaging_matrix(read_config(config_path)) + elif args.config is None or args.config == "": matrix += generate_strategy_matrix( args.all, read_config(THIS_DIR / "linux.json") ) diff --git a/.github/scripts/strategy-matrix/linux.json b/.github/scripts/strategy-matrix/linux.json index 1b9af523cb..4f090a81a3 100644 --- a/.github/scripts/strategy-matrix/linux.json +++ b/.github/scripts/strategy-matrix/linux.json @@ -127,7 +127,8 @@ "distro_version": "9", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "4c086b9" + "image_sha": "4c086b9", + "package": true }, { "distro_name": "rhel", @@ -169,7 +170,8 @@ "distro_version": "jammy", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "4c086b9" + "image_sha": "4c086b9", + "package": true }, { "distro_name": "ubuntu", diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index d95f3a6c00..ca715e0376 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -64,11 +64,13 @@ jobs: .github/workflows/reusable-build-test-config.yml .github/workflows/reusable-build-test.yml .github/workflows/reusable-clang-tidy.yml + .github/workflows/reusable-package.yml .github/workflows/reusable-strategy-matrix.yml .github/workflows/reusable-test.yml .github/workflows/reusable-upload-recipe.yml .clang-tidy .codecov.yml + cfg/** cmake/** conan/** external/** @@ -78,6 +80,10 @@ jobs: CMakeLists.txt conanfile.py conan.lock + LICENSE.md + package/** + README.md + - name: Check whether to run # This step determines whether the rest of the workflow should # run. The rest of the workflow will run if this job runs AND at @@ -134,6 +140,11 @@ jobs: secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + package: + needs: [should-run, build-test] + if: ${{ needs.should-run.outputs.go == 'true' }} + uses: ./.github/workflows/reusable-package.yml + upload-recipe: needs: - should-run @@ -168,6 +179,7 @@ jobs: - check-rename - clang-tidy - build-test + - package - upload-recipe - notify-clio runs-on: ubuntu-latest diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml index e570a0e119..b7517ccf11 100644 --- a/.github/workflows/on-tag.yml +++ b/.github/workflows/on-tag.yml @@ -1,5 +1,5 @@ -# This workflow uploads the libxrpl recipe to the Conan remote when a versioned -# tag is pushed. +# This workflow uploads the libxrpl recipe to the Conan remote and builds +# release packages when a versioned tag is pushed. name: Tag on: @@ -22,3 +22,22 @@ jobs: secrets: remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + + build-test: + if: ${{ github.repository == 'XRPLF/rippled' }} + uses: ./.github/workflows/reusable-build-test.yml + strategy: + fail-fast: true + matrix: + os: [linux] + with: + ccache_enabled: false + os: ${{ matrix.os }} + strategy_matrix: minimal + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + package: + if: ${{ github.repository == 'XRPLF/rippled' }} + needs: build-test + uses: ./.github/workflows/reusable-package.yml diff --git a/.github/workflows/on-trigger.yml b/.github/workflows/on-trigger.yml index 11d98bffb7..803ba3c87b 100644 --- a/.github/workflows/on-trigger.yml +++ b/.github/workflows/on-trigger.yml @@ -21,11 +21,13 @@ on: - ".github/workflows/reusable-build-test-config.yml" - ".github/workflows/reusable-build-test.yml" - ".github/workflows/reusable-clang-tidy.yml" + - ".github/workflows/reusable-package.yml" - ".github/workflows/reusable-strategy-matrix.yml" - ".github/workflows/reusable-test.yml" - ".github/workflows/reusable-upload-recipe.yml" - ".clang-tidy" - ".codecov.yml" + - "cfg/**" - "cmake/**" - "conan/**" - "external/**" @@ -35,6 +37,9 @@ on: - "CMakeLists.txt" - "conanfile.py" - "conan.lock" + - "LICENSE.md" + - "package/**" + - "README.md" # Run at 06:32 UTC on every day of the week from Monday through Friday. This # will force all dependencies to be rebuilt, which is useful to verify that @@ -95,3 +100,7 @@ jobs: secrets: remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }} + + package: + needs: build-test + uses: ./.github/workflows/reusable-package.yml diff --git a/.github/workflows/reusable-package.yml b/.github/workflows/reusable-package.yml new file mode 100644 index 0000000000..ad73cd8733 --- /dev/null +++ b/.github/workflows/reusable-package.yml @@ -0,0 +1,99 @@ +# Build Linux packages (DEB and RPM) from pre-built binary artifacts. +# Discovers which configurations to package from linux.json (os entries +# with "package": true) and fans out one job per entry. Today only +# linux/amd64 is emitted; the architecture is hardcoded both here +# (runner) and in generate.py. +name: Package + +on: + workflow_call: + inputs: + pkg_release: + description: "Package release number. Increment when repackaging the same executable." + required: false + type: string + default: "1" + +defaults: + run: + shell: bash + +env: + BUILD_DIR: build + +jobs: + generate-matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.generate.outputs.matrix }} + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: 3.13 + + - name: Generate packaging matrix + id: generate + working-directory: .github/scripts/strategy-matrix + run: | + ./generate.py --packaging --config=linux.json >> "${GITHUB_OUTPUT}" + + generate-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + sparse-checkout: | + .github/actions/generate-version + src/libxrpl/protocol/BuildInfo.cpp + - name: Generate version + id: version + uses: ./.github/actions/generate-version + + package: + needs: [generate-matrix, generate-version] + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} + name: "${{ matrix.artifact_name }}" + permissions: + contents: read + runs-on: ["self-hosted", "Linux", "X64", "heavy"] + container: ${{ format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) }} + timeout-minutes: 30 + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Download pre-built binary + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ matrix.artifact_name }} + path: ${{ env.BUILD_DIR }} + + - name: Make binary executable + run: chmod +x "${BUILD_DIR}/xrpld" + + - name: Build package + env: + PKG_VERSION: ${{ needs.generate-version.outputs.version }} + PKG_RELEASE: ${{ inputs.pkg_release }} + run: ./package/build_pkg.sh + + - name: Upload package artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + if: ${{ github.event.repository.visibility == 'public' }} + with: + name: ${{ matrix.artifact_name }}-pkg-${{ needs.generate-version.outputs.version }} + path: | + ${{ env.BUILD_DIR }}/debbuild/*.deb + ${{ env.BUILD_DIR }}/debbuild/*.ddeb + ${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm + if-no-files-found: error diff --git a/CMakeLists.txt b/CMakeLists.txt index 80ff8fec13..d315a5dcec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,7 @@ endif() include(XrplCore) include(XrplProtocolAutogen) include(XrplInstall) +include(XrplPackaging) include(XrplValidatorKeys) if(tests) diff --git a/cfg/validators-example.txt b/cfg/validators-example.txt index 384db924f4..d690a67501 100644 --- a/cfg/validators-example.txt +++ b/cfg/validators-example.txt @@ -28,7 +28,7 @@ # https://vl.ripple.com # https://unl.xrplf.org # http://127.0.0.1:8000 -# file:///etc/opt/xrpld/vl.txt +# file:///etc/xrpld/vl.txt # # [validator_list_keys] # diff --git a/cmake/XrplPackaging.cmake b/cmake/XrplPackaging.cmake new file mode 100644 index 0000000000..fe885c200c --- /dev/null +++ b/cmake/XrplPackaging.cmake @@ -0,0 +1,44 @@ +#[===================================================================[ + Linux packaging support: 'package' target. + + The packaging script (package/build_pkg.sh) installs to FHS-standard + paths (/usr/bin, /etc/xrpld, etc.) regardless of CMAKE_INSTALL_PREFIX, + so no prefix guard is needed here. +#]===================================================================] +if(NOT is_linux) + message(STATUS "Packaging not supported on non-Linux hosts") + return() +endif() + +if(NOT DEFINED pkg_release) + set(pkg_release 1) +endif() + +find_program(RPMBUILD_EXECUTABLE rpmbuild) +find_program(DPKG_BUILDPACKAGE_EXECUTABLE dpkg-buildpackage) + +if(NOT (RPMBUILD_EXECUTABLE OR DPKG_BUILDPACKAGE_EXECUTABLE)) + message( + STATUS + "Neither rpmbuild nor dpkg-buildpackage found; 'package' target not available" + ) + return() +endif() + +set(package_env + SRC_DIR=${CMAKE_SOURCE_DIR} + BUILD_DIR=${CMAKE_BINARY_DIR} + PKG_VERSION=${xrpld_version} + PKG_RELEASE=${pkg_release} +) + +add_custom_target( + package + COMMAND + ${CMAKE_COMMAND} -E env ${package_env} + ${CMAKE_SOURCE_DIR}/package/build_pkg.sh + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS xrpld + COMMENT "Building Linux package (deb/rpm inferred from host tooling)" + VERBATIM +) diff --git a/cspell.config.yaml b/cspell.config.yaml index bc56ef5d79..275df41f58 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -99,12 +99,15 @@ words: - desync - desynced - determ + - disablerepo - distro - doxyfile - dxrpl - enabled + - enablerepo - endmacro - exceptioned + - EXPECT_STREQ - Falco - fcontext - finalizers @@ -162,6 +165,7 @@ words: - Merkle - Metafuncton - misprediction + - missingok - mptbalance - MPTDEX - mptflags @@ -193,7 +197,9 @@ words: - NOLINT - NOLINTNEXTLINE - nonxrp + - noreplace - noripple + - notifempty - nudb - nullptr - nunl @@ -213,6 +219,7 @@ words: - preauthorize - preauthorizes - preclaim + - preun - protobuf - protos - ptrs @@ -247,12 +254,14 @@ words: - sfields - shamap - shamapitem + - shlibs - sidechain - SIGGOOD - sle - sles - soci - socidb + - SRPMS - sslws - statsd - STATSDCOLLECTOR @@ -280,8 +289,8 @@ words: - txn - txns - txs - - UBSAN - ubsan + - UBSAN - umant - unacquired - unambiguity @@ -318,7 +327,6 @@ words: - xbridge - xchain - ximinez - - EXPECT_STREQ - XMACRO - xrpkuwait - xrpl diff --git a/package/README.md b/package/README.md new file mode 100644 index 0000000000..2089e32e64 --- /dev/null +++ b/package/README.md @@ -0,0 +1,175 @@ +# Linux Packaging + +This directory contains all files needed to build RPM and Debian packages for `xrpld`. + +## Directory layout + +``` +package/ + build_pkg.sh Staging and build script (called by CMake targets and CI) + rpm/ + xrpld.spec RPM spec (xrpld_version/pkg_release passed via rpmbuild --define) + debian/ Debian control files (control, rules, install, links, conffiles, ...) + shared/ + xrpld.service systemd unit file (used by both RPM and DEB) + xrpld.sysusers sysusers.d config (used by both RPM and DEB) + xrpld.tmpfiles tmpfiles.d config (used by both RPM and DEB) + xrpld.logrotate logrotate config (installed to /etc/logrotate.d/xrpld) + update-xrpld auto-update script (installed to /usr/libexec/xrpld/, run by update-xrpld.timer) +``` + +## Prerequisites + +Packaging targets and their container images are declared in +[`.github/scripts/strategy-matrix/linux.json`](../.github/scripts/strategy-matrix/linux.json) +via a `"package": true` field on specific os entries. Today only +`linux/amd64` is emitted; the architecture is hardcoded in `generate.py` +and the workflow runner. The package format +(deb or rpm) is inferred at build time from the container's package manager +(`apt-get` -> deb, `dnf`/`yum` -> rpm). The image tag is composed as +`ghcr.io/xrplf/ci/{distro}-{version}:{compiler}-{cver}-sha-{image_sha}` — +the same scheme used by `reusable-build-test.yml`. Bump `image_sha` in +`linux.json` and both CI and local builds pick up the new image with no +workflow edits. + +| Package type | Image (derived from `linux.json`) | Tool required | +| ------------ | ---------------------------------------------------- | --------------------------------------------------------------- | +| RPM | `ghcr.io/xrplf/ci/rhel-9:gcc-12-sha-` | `rpmbuild` | +| DEB | `ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12-sha-` | `dpkg-buildpackage`, `debhelper (>= 13)`, `dh-sequence-systemd` | + +To print the exact image tags for the current `linux.json`: + +```bash +./.github/scripts/strategy-matrix/generate.py --packaging --config=.github/scripts/strategy-matrix/linux.json +``` + +## Building packages + +### Via CI + +Caller workflows (`on-pr.yml`, `on-tag.yml`, `on-trigger.yml`) call +`reusable-strategy-matrix.yml` with `mode: packaging` to generate the matrix of +`{artifact_name, os}` entries, then fan out to +`reusable-package.yml` per entry. That workflow downloads the pre-built `xrpld` +binary artifact, detects the package format from the container, and calls +`build_pkg.sh` directly — no CMake configure or build step is needed inside +the packaging job. + +### Locally (mirrors CI) + +With an `xrpld` binary already built at `build/xrpld`, run the packaging step +inside the same container CI uses. The image tag is derived from `linux.json` +so you don't need to hardcode a SHA. + +```bash +# From the repo root. Pick any image flagged with `"package": true` in +# linux.json; the package format is inferred from the container's package +# manager. Example for the rpm-producing image: +IMAGE=$(jq -r ' + .os | map(select(.package == true))[0] | + "ghcr.io/xrplf/ci/\(.distro_name)-\(.distro_version):\(.compiler_name)-\(.compiler_version)-sha-\(.image_sha)" +' .github/scripts/strategy-matrix/linux.json) + +VERSION=2.4.0-local +PKG_RELEASE=1 + +docker run --rm \ + -v "$(pwd):/src" \ + -w /src \ + "$IMAGE" \ + ./package/build_pkg.sh --pkg-version "$VERSION" --pkg-release "$PKG_RELEASE" + +# Output: +# build/debbuild/*.deb (DEB + dbgsym .ddeb) +# build/rpmbuild/RPMS/x86_64/*.rpm +``` + +### Via CMake (host-side target) + +If you run CMake configure on a host that has `rpmbuild` or `dpkg-buildpackage` +installed natively, you can use the CMake target directly — no container +needed, but the host toolchain replaces the pinned CI image: + +```bash +cmake \ + -Dxrpld=ON \ + -Dxrpld_version=2.4.0-local \ + -Dtests=OFF \ + .. + +cmake --build . --target package # deb on Debian/Ubuntu, rpm on RHEL +``` + +The `cmake/XrplPackaging.cmake` module defines the target only if at least one +of `rpmbuild` / `dpkg-buildpackage` is present; `build_pkg.sh` then infers the +package format from the host's package manager. The packaging script installs +to FHS-standard paths (`/usr/bin`, `/etc/xrpld`, etc.) regardless of +`CMAKE_INSTALL_PREFIX`. + +## How `build_pkg.sh` works + +`build_pkg.sh` accepts long-form flags, each of which can also be set via an +environment variable. Flags override env vars; env vars override the built-in +defaults. Run `./package/build_pkg.sh --help` for the same table: + +| Flag | Env var | Default | Purpose | +| -------------------------- | ------------------- | ----------------------------- | ----------------------------------- | +| `--src-dir DIR` | `SRC_DIR` | `$PWD` | repo root | +| `--build-dir DIR` | `BUILD_DIR` | `$PWD/build` | directory holding pre-built `xrpld` | +| `--pkg-version STR` | `PKG_VERSION` | parsed from `xrpld --version` | version string, e.g. `3.2.0-b1` | +| `--pkg-release N` | `PKG_RELEASE` | `1` | package release number | +| `--source-date-epoch SECS` | `SOURCE_DATE_EPOCH` | latest git commit ctime | reproducibility timestamp | + +The package format (`deb` or `rpm`) is inferred from the host's package +manager (`apt-get` -> deb, `dnf`/`yum` -> rpm). Hosts without one of those +fail early. + +Flags are for explicit invocation; environment variables are intended for +CMake/systemd/CI integration. The CI workflow and the CMake `package` target +both invoke `build_pkg.sh` with no flags, configuring it entirely via env +(see `cmake/XrplPackaging.cmake`). + +It resolves `SRC_DIR` and `BUILD_DIR` to absolute paths, then calls +`stage_common()` to copy the binary, config files, and shared support files +into the staging area, and invokes the platform build tool. + +### RPM + +1. Creates the standard `rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}` tree inside the build directory. +2. Copies `xrpld.spec` and all source files (binary, configs, service files) into `SOURCES/`. +3. Runs `rpmbuild -bb --define "xrpld_version ..." --define "pkg_release ..."`. The spec uses manual `install` commands to place files. +4. Output: `rpmbuild/RPMS/x86_64/xrpld-*.rpm` + +### DEB + +1. Creates a staging source tree at `debbuild/source/` inside the build directory. +2. Stages the binary, configs, `README.md`, and `LICENSE.md`. +3. Copies `package/debian/` control files into `debbuild/source/debian/`. +4. Copies shared service/sysusers/tmpfiles into `debian/` where `dh_installsystemd`, `dh_installsysusers`, and `dh_installtmpfiles` pick them up automatically. +5. Generates a minimal `debian/changelog` (pre-release versions use `~` instead of `-`). +6. Runs `dpkg-buildpackage -b --no-sign`. `debian/rules` uses manual `install` commands. +7. Output: `debbuild/*.deb` and `debbuild/*.ddeb` (dbgsym package) + +## Post-build verification + +```bash +# DEB +dpkg-deb -c debbuild/*.deb | grep -E 'systemd|sysusers|tmpfiles' +lintian -I debbuild/*.deb + +# RPM +rpm -qlp rpmbuild/RPMS/x86_64/*.rpm +``` + +## Reproducibility + +The following environment variables improve build reproducibility. They are not +set automatically by `build_pkg.sh`; set them manually if needed: + +```bash +export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) +export TZ=UTC +export LC_ALL=C.UTF-8 +export GZIP=-n +export DEB_BUILD_OPTIONS="noautodbgsym reproducible=+fixfilepath" +``` diff --git a/package/build_pkg.sh b/package/build_pkg.sh new file mode 100755 index 0000000000..c834951493 --- /dev/null +++ b/package/build_pkg.sh @@ -0,0 +1,192 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Build an RPM or Debian package from a pre-built xrpld binary. +# +# Flags override env vars; env vars override defaults. Env vars are intended +# for CMake/systemd/CI integration; flags are for explicit invocation. + +usage() { + cat <<'EOF' +Usage: build_pkg.sh [options] + +Options (each can also be set via the env var shown): + --src-dir DIR repo root [SRC_DIR; default: $PWD] + --build-dir DIR directory holding xrpld [BUILD_DIR; default: $PWD/build] + --pkg-version STR version, e.g. 3.2.0-b1 [PKG_VERSION; default: parsed from xrpld --version] + --pkg-release N package release number [PKG_RELEASE; default: 1] + --source-date-epoch SECS reproducibility timestamp [SOURCE_DATE_EPOCH; default: latest git commit ctime] + -h, --help show this help and exit +EOF +} + +need_arg() { + if [[ $# -lt 2 || "$2" == --* ]]; then + echo "Missing value for $1" >&2 + exit 2 + fi +} + +# Seed from env. CLI parsing below overrides these directly. +SRC_DIR="${SRC_DIR:-}" +BUILD_DIR="${BUILD_DIR:-}" +PKG_VERSION="${PKG_VERSION:-}" +PKG_RELEASE="${PKG_RELEASE:-}" +SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-}" + +while [[ $# -gt 0 ]]; do + case "$1" in + --src-dir) need_arg "$@"; SRC_DIR="$2"; shift 2 ;; + --build-dir) need_arg "$@"; BUILD_DIR="$2"; shift 2 ;; + --pkg-version) need_arg "$@"; PKG_VERSION="$2"; shift 2 ;; + --pkg-release) need_arg "$@"; PKG_RELEASE="$2"; shift 2 ;; + --source-date-epoch) need_arg "$@"; SOURCE_DATE_EPOCH="$2"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) + echo "Unknown argument: $1" >&2 + usage >&2 + exit 2 + ;; + esac +done + +SRC_DIR="$(cd "${SRC_DIR:-${PWD}}" && pwd)" +BUILD_DIR="$(cd "${BUILD_DIR:-${PWD}/build}" && pwd)" +PKG_RELEASE="${PKG_RELEASE:-1}" + +if [[ -z "${PKG_VERSION}" ]]; then + PKG_VERSION="$("${BUILD_DIR}/xrpld" --version | awk 'NR==1 {print $3; exit}')" +fi + +if [[ -z "${PKG_VERSION}" ]]; then + echo "PKG_VERSION is empty (not provided and could not be derived)." >&2 + exit 1 +fi + +VERSION="${PKG_VERSION}" + +if command -v apt-get >/dev/null 2>&1; then + pkg_type=deb +elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1; then + pkg_type=rpm +else + echo "Cannot infer pkg_type: no apt-get, dnf, or yum on PATH." >&2 + exit 1 +fi + +if [[ -z "${SOURCE_DATE_EPOCH}" ]]; then + if git -C "$SRC_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + SOURCE_DATE_EPOCH="$(git -C "$SRC_DIR" log -1 --format=%ct)" + else + SOURCE_DATE_EPOCH="$(date +%s)" + fi +fi + +export SOURCE_DATE_EPOCH +CHANGELOG_DATE="$(date -u -R -d "@$SOURCE_DATE_EPOCH")" + +# Split VERSION at the first '-' into base and optional pre-release suffix. +# Examples: "3.2.0" -> ("3.2.0", ""); "3.2.0-b1" -> ("3.2.0", "b1"). +VER_BASE="${VERSION%%-*}" +VER_SUFFIX="${VERSION#*-}" +[[ "${VER_SUFFIX}" == "${VERSION}" ]] && VER_SUFFIX="" + +# Reject multi-segment suffixes (e.g. "beta-1", "rc1-15-gabc123"). The RPM +# Release field forbids '-', and the convention here is single-token suffixes +# like b1 or rc2. Fail early with a clear message rather than letting either +# rpmbuild blow up or silently mangling dashes into dots. +if [[ "${VER_SUFFIX}" == *-* ]]; then + echo "build_pkg.sh: multi-segment pre-release in VERSION='${VERSION}' (suffix '${VER_SUFFIX}')." >&2 + echo "Use single-token suffixes like 3.2.0-b1 or 3.2.0-rc2." >&2 + exit 1 +fi + +SHARED="${SRC_DIR}/package/shared" +DEBIAN_DIR="${SRC_DIR}/package/debian" + +# Stage files that both packaging systems consume using the same filenames. +stage_common() { + local dest="$1" + mkdir -p "${dest}" + + cp "${BUILD_DIR}/xrpld" "${dest}/xrpld" + cp "${SRC_DIR}/cfg/xrpld-example.cfg" "${dest}/xrpld.cfg" + cp "${SRC_DIR}/cfg/validators-example.txt" "${dest}/validators.txt" + cp "${SRC_DIR}/LICENSE.md" "${dest}/LICENSE.md" + cp "${SRC_DIR}/README.md" "${dest}/README.md" + + cp "${SHARED}/xrpld.service" "${dest}/xrpld.service" + cp "${SHARED}/xrpld.sysusers" "${dest}/xrpld.sysusers" + cp "${SHARED}/xrpld.tmpfiles" "${dest}/xrpld.tmpfiles" + cp "${SHARED}/xrpld.logrotate" "${dest}/xrpld.logrotate" + cp "${SHARED}/update-xrpld" "${dest}/update-xrpld" + cp "${SHARED}/update-xrpld.service" "${dest}/update-xrpld.service" + cp "${SHARED}/update-xrpld.timer" "${dest}/update-xrpld.timer" + cp "${SHARED}/50-xrpld.preset" "${dest}/50-xrpld.preset" +} + +build_rpm() { + local topdir="${BUILD_DIR}/rpmbuild" + rm -rf "${topdir}" + mkdir -p "${topdir}"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} + + cp "${SRC_DIR}/package/rpm/xrpld.spec" "${topdir}/SPECS/xrpld.spec" + stage_common "${topdir}/SOURCES" + + # RPM Version can't contain '-'. A pre-release goes in Release with a + # leading "0." so 3.2.0-b1 sorts before the final 3.2.0-. + local rpm_release="${PKG_RELEASE}" + [[ -n "${VER_SUFFIX}" ]] && rpm_release="0.${VER_SUFFIX}.${PKG_RELEASE}" + + set -x + rpmbuild -bb \ + --define "_topdir ${topdir}" \ + --define "xrpld_version ${VER_BASE}" \ + --define "xrpld_release ${rpm_release}" \ + "${topdir}/SPECS/xrpld.spec" +} + +build_deb() { + local staging="${BUILD_DIR}/debbuild/source" + rm -rf "${staging}" + mkdir -p "${staging}" + + stage_common "${staging}" + cp -r "${DEBIAN_DIR}" "${staging}/debian" + + # Debhelper auto-discovers these only from debian/. + cp "${staging}/xrpld.service" "${staging}/debian/xrpld.service" + cp "${staging}/xrpld.sysusers" "${staging}/debian/xrpld.sysusers" + cp "${staging}/xrpld.tmpfiles" "${staging}/debian/xrpld.tmpfiles" + cp "${staging}/xrpld.logrotate" "${staging}/debian/xrpld.logrotate" + cp "${staging}/update-xrpld.service" "${staging}/debian/xrpld.update-xrpld.service" + cp "${staging}/update-xrpld.timer" "${staging}/debian/xrpld.update-xrpld.timer" + + # Debian '~' marks a pre-release; 3.2.0~b1 sorts before 3.2.0. + local deb_full_version="${VER_BASE}${VER_SUFFIX:+~${VER_SUFFIX}}-${PKG_RELEASE}" + + # Derive release channel from the version suffix: + # (none) -> stable (tagged release) + # b0 -> develop (develop-branch build) + # b, rc -> unstable (pre-release) + local deb_distribution + case "${VER_SUFFIX}" in + "") deb_distribution="stable" ;; + b0) deb_distribution="develop" ;; + *) deb_distribution="unstable" ;; + esac + + cat > "${staging}/debian/changelog" < ${CHANGELOG_DATE} +EOF + + chmod +x "${staging}/debian/rules" + + set -x + ( cd "${staging}" && dpkg-buildpackage -b --no-sign -d ) +} + +"build_${pkg_type}" diff --git a/package/debian/control b/package/debian/control new file mode 100644 index 0000000000..45d2acbbea --- /dev/null +++ b/package/debian/control @@ -0,0 +1,23 @@ +Source: xrpld +Section: net +Priority: optional +Maintainer: XRPL Foundation +Rules-Requires-Root: no +Build-Depends: + debhelper-compat (= 13) +Standards-Version: 4.7.0 +Homepage: https://github.com/XRPLF/rippled +Vcs-Git: https://github.com/XRPLF/rippled.git +Vcs-Browser: https://github.com/XRPLF/rippled + +Package: xrpld +Section: net +Priority: optional +Architecture: any +Depends: + ${shlibs:Depends}, + ${misc:Depends} +Description: XRP Ledger daemon + Reference implementation of the XRP Ledger protocol. + Participates in the peer-to-peer network, processes transactions, + and maintains a local ledger copy. diff --git a/package/debian/copyright b/package/debian/copyright new file mode 100644 index 0000000000..ddaa719e3a --- /dev/null +++ b/package/debian/copyright @@ -0,0 +1,18 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: rippled +Source: https://github.com/XRPLF/rippled + +Files: * +Copyright: 2011-present, the XRP Ledger developers +License: ISC + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + . + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/package/debian/rules b/package/debian/rules new file mode 100644 index 0000000000..0fae101358 --- /dev/null +++ b/package/debian/rules @@ -0,0 +1,27 @@ +#!/usr/bin/make -f + +export DH_VERBOSE = 1 + +%: + dh $@ + +override_dh_auto_configure override_dh_auto_build override_dh_auto_test: + @: + +override_dh_installsystemd: + dh_installsystemd --no-start xrpld.service + dh_installsystemd --name=update-xrpld --no-start update-xrpld.service update-xrpld.timer + +execute_before_dh_installtmpfiles: + dh_installsysusers + +override_dh_installsysusers: + +override_dh_install: + install -D -m 0755 xrpld debian/xrpld/usr/bin/xrpld + install -D -m 0644 xrpld.cfg debian/xrpld/etc/xrpld/xrpld.cfg + install -D -m 0644 validators.txt debian/xrpld/etc/xrpld/validators.txt + install -D -m 0755 update-xrpld debian/xrpld/usr/libexec/xrpld/update-xrpld + +override_dh_dwz: + @: diff --git a/package/debian/source/format b/package/debian/source/format new file mode 100644 index 0000000000..163aaf8d82 --- /dev/null +++ b/package/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/package/debian/xrpld.docs b/package/debian/xrpld.docs new file mode 100644 index 0000000000..1217b6db43 --- /dev/null +++ b/package/debian/xrpld.docs @@ -0,0 +1,2 @@ +README.md +LICENSE.md diff --git a/package/debian/xrpld.links b/package/debian/xrpld.links new file mode 100644 index 0000000000..10d34f5b8c --- /dev/null +++ b/package/debian/xrpld.links @@ -0,0 +1,2 @@ +# Legacy compat symlinks (remove next major release) +usr/bin/xrpld usr/local/bin/rippled diff --git a/package/rpm/xrpld.spec b/package/rpm/xrpld.spec new file mode 100644 index 0000000000..4933c724f7 --- /dev/null +++ b/package/rpm/xrpld.spec @@ -0,0 +1,100 @@ +Name: xrpld +Version: %{xrpld_version} +Release: %{xrpld_release}%{?dist} +Summary: XRP Ledger daemon + +License: ISC +URL: https://github.com/XRPLF/rippled + +ExclusiveArch: x86_64 aarch64 +BuildRequires: systemd-rpm-macros + +%undefine _debugsource_packages +%debug_package + +%build_mtime_policy clamp_to_source_date_epoch + +%{?systemd_requires} +%{?sysusers_requires_compat} + +%description +xrpld is the reference implementation of the XRP Ledger protocol. It +participates in the peer-to-peer XRP Ledger network, processes +transactions, and maintains the ledger database. + +%prep +: + +%build +: + +%install +install -Dm0755 %{_sourcedir}/xrpld %{buildroot}%{_bindir}/%{name} +install -Dm0644 %{_sourcedir}/xrpld.cfg %{buildroot}%{_sysconfdir}/%{name}/xrpld.cfg +install -Dm0644 %{_sourcedir}/validators.txt %{buildroot}%{_sysconfdir}/%{name}/validators.txt + +# systemd units, sysusers, tmpfiles, preset +install -Dm0644 %{_sourcedir}/xrpld.service %{buildroot}%{_unitdir}/xrpld.service +install -Dm0644 %{_sourcedir}/update-xrpld.service %{buildroot}%{_unitdir}/update-xrpld.service +install -Dm0644 %{_sourcedir}/update-xrpld.timer %{buildroot}%{_unitdir}/update-xrpld.timer +install -Dm0644 %{_sourcedir}/xrpld.sysusers %{buildroot}%{_sysusersdir}/xrpld.conf +install -Dm0644 %{_sourcedir}/xrpld.tmpfiles %{buildroot}%{_tmpfilesdir}/xrpld.conf +install -Dm0644 %{_sourcedir}/50-xrpld.preset %{buildroot}%{_presetdir}/50-xrpld.preset + +# Logrotate config +install -Dm0644 %{_sourcedir}/xrpld.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/%{name} + +# Update helper +install -Dm0755 %{_sourcedir}/update-xrpld %{buildroot}%{_libexecdir}/%{name}/update-xrpld + +# Docs +install -Dm0644 %{_sourcedir}/LICENSE.md %{buildroot}%{_docdir}/%{name}/LICENSE.md +install -Dm0644 %{_sourcedir}/README.md %{buildroot}%{_docdir}/%{name}/README.md + +# Legacy compatibility for pre-FHS package layouts. +# TODO: remove after rippled fully deprecated. +install -d %{buildroot}/usr/local/bin +ln -s %{_bindir}/%{name} %{buildroot}/usr/local/bin/rippled + +%pre +%sysusers_create_package %{name} %{_sourcedir}/xrpld.sysusers + +%post +systemd-tmpfiles --create %{_tmpfilesdir}/xrpld.conf || : +%systemd_post xrpld.service update-xrpld.timer + +%preun +%systemd_preun xrpld.service update-xrpld.timer + +%postun +%systemd_postun_with_restart xrpld.service + +%files +%license %{_docdir}/%{name}/LICENSE.md +%doc %{_docdir}/%{name}/README.md + +%dir %{_sysconfdir}/%{name} +%dir %{_libexecdir}/%{name} + +%{_bindir}/%{name} + +%config(noreplace) %{_sysconfdir}/%{name}/xrpld.cfg +%config(noreplace) %{_sysconfdir}/%{name}/validators.txt +%config(noreplace) %{_sysconfdir}/logrotate.d/%{name} + +%{_libexecdir}/%{name}/update-xrpld + +%{_unitdir}/xrpld.service +%{_unitdir}/update-xrpld.service +%{_unitdir}/update-xrpld.timer +%{_presetdir}/50-xrpld.preset +%{_sysusersdir}/xrpld.conf +%{_tmpfilesdir}/xrpld.conf + +%ghost %dir /var/lib/%{name} +%ghost %dir /var/log/%{name} + + +# Legacy compatibility for pre-FHS package layouts. +# TODO: remove after rippled fully deprecated. +/usr/local/bin/rippled diff --git a/package/shared/50-xrpld.preset b/package/shared/50-xrpld.preset new file mode 100644 index 0000000000..6264e00131 --- /dev/null +++ b/package/shared/50-xrpld.preset @@ -0,0 +1,4 @@ +# /usr/lib/systemd/system-preset/50-xrpld.preset +enable xrpld.service +# Don't enable automatic updates +disable update-xrpld.timer diff --git a/package/shared/update-xrpld b/package/shared/update-xrpld new file mode 100755 index 0000000000..86be33118b --- /dev/null +++ b/package/shared/update-xrpld @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Optional: also write logs to a legacy file in addition to journald. +# By default, this script logs to systemd/journald, viewable via: +# journalctl -t update-xrpld +# +# Uncomment the line below if you need a flat file for compatibility with +# external tooling, manual inspection, or environments where journald logs +# are not persisted or easily accessible. +# +# Note: This duplicates all output (stdout/stderr) to both journald and the file. +# It is generally not needed on modern systems and may cause log file growth +# if left enabled long-term. +# +# Requires /var/log/xrpld/ to exist and be writable by the service (root). +# +# exec > >(tee -a /var/log/xrpld/update.log) 2>&1 + +PATH=/usr/sbin:/usr/bin:/sbin:/bin + +PKG_NAME=${PKG_NAME:-xrpld} + +log() { +# If running under systemd/journald, let it handle timestamps. + if [[ -n "${JOURNAL_STREAM:-}" ]]; then + printf '%s\n' "$*" + else + printf '%s %s\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" + fi +} + +require_root() { + if [[ ${EUID:-$(id -u)} -ne 0 ]]; then + log "RESULT: failed reason=not-root" + exit 1 + fi +} + +get_installed_version() { + if command -v dpkg-query >/dev/null 2>&1; then + dpkg-query -W -f='${Version}' "$PKG_NAME" 2>/dev/null || printf 'unknown' + elif command -v rpm >/dev/null 2>&1; then + rpm -q --qf '%{VERSION}-%{RELEASE}' "$PKG_NAME" 2>/dev/null || printf 'unknown' + else + printf 'unknown' + fi +} + +trap 'log "RESULT: failed reason=script-error exit_code=$?"' ERR + +apt_can_update() { + apt-get update -qq + apt-get -s --only-upgrade install "$PKG_NAME" 2>/dev/null | grep -q "^Inst ${PKG_NAME}\b" +} + +apt_apply_update() { + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ + -o Dpkg::Options::="--force-confdef" \ + -o Dpkg::Options::="--force-confold" \ + "$PKG_NAME" +} + +get_rpm_pm() { + if command -v dnf >/dev/null 2>&1; then + printf 'dnf\n' + elif command -v yum >/dev/null 2>&1; then + printf 'yum\n' + else + return 1 + fi +} + +rpm_refresh_metadata() { + local pm=$1 + if [[ "$pm" == "dnf" ]]; then + dnf makecache --refresh -q >/dev/null + else + yum clean expire-cache -q >/dev/null + fi +} + +rpm_can_update() { + local pm=$1 + + rpm_refresh_metadata "$pm" + local rc=0 + set +e + "$pm" check-update -q "$PKG_NAME" >/dev/null 2>&1 + rc=$? + set -e + + if [[ $rc -eq 100 ]]; then + return 0 + elif [[ $rc -eq 0 ]]; then + return 1 + else + log "$pm check-update failed with exit code ${rc}." + exit 1 + fi +} + +rpm_apply_update() { + local pm=$1 + "$pm" update -y "$PKG_NAME" +} + +restart_service() { + # Preserve the operator's prior service state: if xrpld was intentionally + # stopped before the update, don't bring it back up just because the + # auto-update timer fired. + if systemctl is-active --quiet "${PKG_NAME}.service"; then + systemctl restart "${PKG_NAME}.service" + log "${PKG_NAME} service restarted successfully." + else + log "${PKG_NAME} service was not running; skipping restart to preserve prior state." + fi +} + +main() { + require_root + if command -v apt-get >/dev/null 2>&1; then + log "Checking for ${PKG_NAME} updates via apt" + if apt_can_update; then + log "Update available; installing." + apt_apply_update + restart_service + log "RESULT: updated ${PKG_NAME}=$(get_installed_version)" + else + log "RESULT: no-update ${PKG_NAME}=$(get_installed_version)" + fi + return + fi + + local rpm_pm="" + if rpm_pm="$(get_rpm_pm)"; then + log "Checking for ${PKG_NAME} updates via ${rpm_pm}" + if rpm_can_update "$rpm_pm"; then + log "Update available; installing" + rpm_apply_update "$rpm_pm" + restart_service + log "RESULT: updated ${PKG_NAME}=$(get_installed_version)" + else + log "RESULT: no-update ${PKG_NAME}=$(get_installed_version)" + fi + return + fi + log "RESULT: failed reason=no-package-manager" + exit 1 +} + +main "$@" diff --git a/package/shared/update-xrpld.service b/package/shared/update-xrpld.service new file mode 100644 index 0000000000..a964ca5482 --- /dev/null +++ b/package/shared/update-xrpld.service @@ -0,0 +1,16 @@ +[Unit] +Description=Check for and install xrpld package updates +Documentation=man:systemd.service(5) +Wants=network-online.target +After=network-online.target +ConditionPathExists=/usr/libexec/xrpld/update-xrpld +ConditionPathExists=/usr/bin/xrpld + +[Service] +Type=oneshot +ExecStart=/usr/bin/flock -n /run/lock/xrpld-update.lock /usr/libexec/xrpld/update-xrpld +StandardOutput=journal +StandardError=journal +SyslogIdentifier=update-xrpld +TimeoutStartSec=30min +PrivateTmp=true diff --git a/package/shared/update-xrpld.timer b/package/shared/update-xrpld.timer new file mode 100644 index 0000000000..21dabf1400 --- /dev/null +++ b/package/shared/update-xrpld.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Daily xrpld update check + +[Timer] +OnCalendar=*-*-* 00:00:00 +RandomizedDelaySec=24h +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/package/shared/xrpld.logrotate b/package/shared/xrpld.logrotate new file mode 100644 index 0000000000..0ae2b7783b --- /dev/null +++ b/package/shared/xrpld.logrotate @@ -0,0 +1,19 @@ +/var/log/xrpld/*.log { + daily + minsize 200M + rotate 7 + nocreate + missingok + notifempty + compress + compresscmd /usr/bin/gzip + compressext .gz + postrotate + # Only signal the daemon if it's actually running; otherwise the RPC + # call returns a transport error and logrotate marks the rotation as + # failed, generating recurring errors on stopped nodes. + if systemctl is-active --quiet xrpld; then + /usr/bin/xrpld --conf /etc/xrpld/xrpld.cfg logrotate + fi + endscript +} diff --git a/package/shared/xrpld.service b/package/shared/xrpld.service new file mode 100644 index 0000000000..72b6cc9938 --- /dev/null +++ b/package/shared/xrpld.service @@ -0,0 +1,22 @@ +[Unit] +Description=XRP Ledger Daemon +After=network-online.target +Wants=network-online.target +StartLimitIntervalSec=300 +StartLimitBurst=5 + +[Service] +Type=simple +ExecStart=/usr/bin/xrpld --net --silent --conf /etc/xrpld/xrpld.cfg +Restart=always +RestartSec=5s +NoNewPrivileges=true +ProtectSystem=full +ProtectHome=true +PrivateTmp=true +User=xrpld +Group=xrpld +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target diff --git a/package/shared/xrpld.sysusers b/package/shared/xrpld.sysusers new file mode 100644 index 0000000000..4547ac6f3d --- /dev/null +++ b/package/shared/xrpld.sysusers @@ -0,0 +1 @@ +u xrpld - "XRP Ledger daemon" /var/lib/xrpld /sbin/nologin diff --git a/package/shared/xrpld.tmpfiles b/package/shared/xrpld.tmpfiles new file mode 100644 index 0000000000..ff9b4d95c2 --- /dev/null +++ b/package/shared/xrpld.tmpfiles @@ -0,0 +1,2 @@ +d /var/lib/xrpld 0750 xrpld xrpld - +d /var/log/xrpld 0750 xrpld xrpld - diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index b10667c467..f7f805faa2 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -78,7 +78,7 @@ private: "http://207.261.33.37:8080/validators", "https://ripple.com/validators", "https://ripple.com:443/validators", - "file:///etc/opt/xrpld/validators.txt", + "file:///etc/xrpld/validators.txt", "file:///C:/Lib/validators.txt" #if !_MSC_VER , diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index 7830ad9c56..d8789795c0 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -372,8 +372,8 @@ Config::setup(std::string const& strConf, bool bQuiet, bool bSilent, bool bStand } // As a last resort, check the system config directory. - dataDir = "/var/opt/" + systemName(); - CONFIG_DIR = "/etc/opt/" + systemName(); + dataDir = "/var/lib/" + systemName(); + CONFIG_DIR = "/etc/" + systemName(); CONFIG_FILE_ = CONFIG_DIR / kConfigFileName; if (boost::filesystem::exists(CONFIG_FILE_)) break;