diff options
| -rw-r--r-- | frontends/etc/dserver/dtail-freebsd.json.tpl | 127 | ||||
| -rw-r--r-- | frontends/etc/rc.d/dserver-freebsd.tpl | 30 | ||||
| -rw-r--r-- | frontends/scripts/dserver-update-key-cache-freebsd.sh.tpl | 33 | ||||
| -rwxr-xr-x | packages/files/dtail-rocky/dserver-update-key-cache.sh | 54 | ||||
| -rw-r--r-- | packages/files/dtail-rocky/dserver-update-keycache.service | 6 | ||||
| -rw-r--r-- | packages/files/dtail-rocky/dserver-update-keycache.timer | 11 | ||||
| -rw-r--r-- | packages/files/dtail-rocky/dserver.service | 22 | ||||
| -rw-r--r-- | packages/files/dtail-rocky/dtail.json | 131 | ||||
| -rw-r--r-- | packages/scripts/pkg-dtail-freebsd.sh | 79 | ||||
| -rwxr-xr-x | packages/scripts/pkg-dtail-rpm.sh | 140 |
10 files changed, 633 insertions, 0 deletions
diff --git a/frontends/etc/dserver/dtail-freebsd.json.tpl b/frontends/etc/dserver/dtail-freebsd.json.tpl new file mode 100644 index 0000000..cd99560 --- /dev/null +++ b/frontends/etc/dserver/dtail-freebsd.json.tpl @@ -0,0 +1,127 @@ +{ + "Client": { + "TermColorsEnable": true, + "TermColors": { + "Remote": { + "DelimiterAttr": "Dim", + "DelimiterBg": "Blue", + "DelimiterFg": "Cyan", + "RemoteAttr": "Dim", + "RemoteBg": "Blue", + "RemoteFg": "White", + "CountAttr": "Dim", + "CountBg": "Blue", + "CountFg": "White", + "HostnameAttr": "Bold", + "HostnameBg": "Blue", + "HostnameFg": "White", + "IDAttr": "Dim", + "IDBg": "Blue", + "IDFg": "White", + "StatsOkAttr": "None", + "StatsOkBg": "Green", + "StatsOkFg": "Black", + "StatsWarnAttr": "None", + "StatsWarnBg": "Red", + "StatsWarnFg": "White", + "TextAttr": "None", + "TextBg": "Black", + "TextFg": "White" + }, + "Client": { + "DelimiterAttr": "Dim", + "DelimiterBg": "Yellow", + "DelimiterFg": "Black", + "ClientAttr": "Dim", + "ClientBg": "Yellow", + "ClientFg": "Black", + "HostnameAttr": "Dim", + "HostnameBg": "Yellow", + "HostnameFg": "Black", + "TextAttr": "None", + "TextBg": "Black", + "TextFg": "White" + }, + "Server": { + "DelimiterAttr": "AttrDim", + "DelimiterBg": "BgCyan", + "DelimiterFg": "FgBlack", + "ServerAttr": "AttrDim", + "ServerBg": "BgCyan", + "ServerFg": "FgBlack", + "HostnameAttr": "AttrBold", + "HostnameBg": "BgCyan", + "HostnameFg": "FgBlack", + "TextAttr": "AttrNone", + "TextBg": "BgBlack", + "TextFg": "FgWhite" + }, + "Common": { + "SeverityErrorAttr": "AttrBold", + "SeverityErrorBg": "BgRed", + "SeverityErrorFg": "FgWhite", + "SeverityFatalAttr": "AttrBold", + "SeverityFatalBg": "BgMagenta", + "SeverityFatalFg": "FgWhite", + "SeverityWarnAttr": "AttrBold", + "SeverityWarnBg": "BgBlack", + "SeverityWarnFg": "FgWhite" + }, + "MaprTable": { + "DataAttr": "AttrNone", + "DataBg": "BgBlue", + "DataFg": "FgWhite", + "DelimiterAttr": "AttrDim", + "DelimiterBg": "BgBlue", + "DelimiterFg": "FgWhite", + "HeaderAttr": "AttrBold", + "HeaderBg": "BgBlue", + "HeaderFg": "FgWhite", + "HeaderDelimiterAttr": "AttrDim", + "HeaderDelimiterBg": "BgBlue", + "HeaderDelimiterFg": "FgWhite", + "HeaderSortKeyAttr": "AttrUnderline", + "HeaderGroupKeyAttr": "AttrReverse", + "RawQueryAttr": "AttrDim", + "RawQueryBg": "BgBlack", + "RawQueryFg": "FgCyan" + } + } + }, + "Server": { + "SSHBindAddress": "0.0.0.0", + "HostKeyFile": "/var/run/dserver/cache/ssh_host_key", + "HostKeyBits": 2048, + "MapreduceLogFormat": "default", + "MaxConcurrentCats": 2, + "MaxConcurrentTails": 50, + "MaxConnections": 50, + "MaxLineLength": 1048576, + "Permissions": { + "Default": [ + "readfiles:^/.*$" + ], + "Users": { + "paul": [ + "readfiles:^/.*$" + ], + "pbuetow": [ + "readfiles:^/.*$" + ], + "jamesblake": [ + "readfiles:^/tmp/foo.log$", + "readfiles:^/.*$", + "readfiles:!^/tmp/bar.log$" + ] + } + } + }, + "Common": { + "LogDir": "/var/log/dserver", + "Logger": "Fout", + "LogRotation": "Daily", + "CacheDir": "/var/run/dserver/cache", + "SSHPort": 2222, + "LogLevel": "Info" + } +} diff --git a/frontends/etc/rc.d/dserver-freebsd.tpl b/frontends/etc/rc.d/dserver-freebsd.tpl new file mode 100644 index 0000000..6110c0c --- /dev/null +++ b/frontends/etc/rc.d/dserver-freebsd.tpl @@ -0,0 +1,30 @@ +#!/bin/sh +# +# PROVIDE: dserver +# REQUIRE: LOGIN +# KEYWORD: shutdown + +. /etc/rc.subr + +name="dserver" +rcvar="dserver_enable" +desc="DTail distributed log server" + +# Use daemon(8) explicitly: rc.subr's dserver_user wraps with su -m but does +# not fork, so the service command blocks. daemon(8) -u runs as the target +# user and properly detaches from the terminal. +procname="/usr/local/bin/dserver" +command="/usr/sbin/daemon" +command_args="-u dserver -o /var/log/dserver/dserver.log -- /usr/local/bin/dserver -cfg /usr/local/etc/dserver/dtail.json" + +start_precmd="dserver_precmd" + +dserver_precmd() +{ + install -d -o dserver -m 0755 /var/log/dserver + install -d -o dserver -m 0755 /var/run/dserver + install -d -o dserver -m 0755 /var/run/dserver/cache +} + +load_rc_config $name +run_rc_command "$1" diff --git a/frontends/scripts/dserver-update-key-cache-freebsd.sh.tpl b/frontends/scripts/dserver-update-key-cache-freebsd.sh.tpl new file mode 100644 index 0000000..22173d7 --- /dev/null +++ b/frontends/scripts/dserver-update-key-cache-freebsd.sh.tpl @@ -0,0 +1,33 @@ +#!/bin/sh +# Refresh the dserver SSH key cache from user authorized_keys files. +# Called by /usr/local/etc/periodic/daily/200.dserver-update-key-cache. + +CACHEDIR=/var/run/dserver/cache +DSERVER_USER=dserver +DSERVER_GROUP=dserver + +echo 'Updating SSH key cache' + +ls /home/ | while read remoteuser; do + keysfile="/home/$remoteuser/.ssh/authorized_keys" + + if [ -f "$keysfile" ]; then + cachefile="$CACHEDIR/$remoteuser.authorized_keys" + echo "Caching $keysfile -> $cachefile" + + cp "$keysfile" "$cachefile" + chown "$DSERVER_USER:$DSERVER_GROUP" "$cachefile" + chmod 600 "$cachefile" + fi +done + +# Remove stale cache entries for users whose authorized_keys no longer exist +find "$CACHEDIR" -name '*.authorized_keys' -type f | while read cachefile; do + remoteuser=$(basename "$cachefile" .authorized_keys) + if [ ! -f "/home/$remoteuser/.ssh/authorized_keys" ]; then + echo "Deleting obsolete cache file $cachefile" + rm "$cachefile" + fi +done + +echo 'All set...' diff --git a/packages/files/dtail-rocky/dserver-update-key-cache.sh b/packages/files/dtail-rocky/dserver-update-key-cache.sh new file mode 100755 index 0000000..831f5be --- /dev/null +++ b/packages/files/dtail-rocky/dserver-update-key-cache.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +set -euo pipefail + +declare -r CACHEDIR=/var/run/dserver/cache +declare -r DSERVER_USER=dserver +declare -r DSERVER_GROUP=dserver + +cache_keys() { + local remoteuser=$1 + local home_dir=$2 + local keysfile=$home_dir/.ssh/authorized_keys + local cachefile=$CACHEDIR/$remoteuser.authorized_keys + + if [[ -f "$keysfile" ]]; then + echo "Caching $keysfile -> $cachefile" + cp "$keysfile" "$cachefile" + chown "$DSERVER_USER:$DSERVER_GROUP" "$cachefile" + chmod 600 "$cachefile" + fi +} + +expected_key_path() { + local remoteuser=$1 + + if [[ "$remoteuser" == "root" ]]; then + printf '%s\n' /root/.ssh/authorized_keys + return + fi + + printf '/home/%s/.ssh/authorized_keys\n' "$remoteuser" +} + +echo "Updating SSH key cache" + +mkdir -p "$CACHEDIR" + +cache_keys root /root + +while IFS= read -r remoteuser; do + cache_keys "$remoteuser" "/home/$remoteuser" +done < <(find /home -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | sort) + +find "$CACHEDIR" -name '*.authorized_keys' -type f | while read -r cachefile; do + remoteuser=$(basename "$cachefile" | cut -d. -f1) + keysfile=$(expected_key_path "$remoteuser") + + if [[ ! -f "$keysfile" ]]; then + echo "Deleting obsolete cache file $cachefile" + rm -f "$cachefile" + fi +done + +echo "All set..." diff --git a/packages/files/dtail-rocky/dserver-update-keycache.service b/packages/files/dtail-rocky/dserver-update-keycache.service new file mode 100644 index 0000000..dddab12 --- /dev/null +++ b/packages/files/dtail-rocky/dserver-update-keycache.service @@ -0,0 +1,6 @@ +[Unit] +Description=Refresh DServer SSH key cache + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/dserver-update-key-cache.sh diff --git a/packages/files/dtail-rocky/dserver-update-keycache.timer b/packages/files/dtail-rocky/dserver-update-keycache.timer new file mode 100644 index 0000000..339011d --- /dev/null +++ b/packages/files/dtail-rocky/dserver-update-keycache.timer @@ -0,0 +1,11 @@ +[Unit] +Description=Refresh DServer SSH key cache every 30 minutes + +[Timer] +OnBootSec=2m +OnCalendar=*:0/30 +Persistent=true +Unit=dserver-update-keycache.service + +[Install] +WantedBy=timers.target diff --git a/packages/files/dtail-rocky/dserver.service b/packages/files/dtail-rocky/dserver.service new file mode 100644 index 0000000..f43a5ce --- /dev/null +++ b/packages/files/dtail-rocky/dserver.service @@ -0,0 +1,22 @@ +[Unit] +Description=DTail server +After=network.target + +[Service] +Slice=dserver.slice +User=dserver +Group=dserver +ExecStart=/usr/local/bin/dserver -cfg /etc/dserver/dtail.json +WorkingDirectory=/var/run/dserver +RuntimeDirectory=dserver +RuntimeDirectoryMode=0755 +ExecStartPre=/usr/bin/mkdir -p /var/run/dserver/cache /var/run/dserver/log +NoNewPrivileges=true +PrivateDevices=true +PrivateTmp=true +CPUAccounting=true +MemoryAccounting=true +BlockIOAccounting=true + +[Install] +WantedBy=multi-user.target diff --git a/packages/files/dtail-rocky/dtail.json b/packages/files/dtail-rocky/dtail.json new file mode 100644 index 0000000..eaa0a39 --- /dev/null +++ b/packages/files/dtail-rocky/dtail.json @@ -0,0 +1,131 @@ +{ + "Client": { + "TermColorsEnable": true, + "TermColors": { + "Remote": { + "DelimiterAttr": "Dim", + "DelimiterBg": "Blue", + "DelimiterFg": "Cyan", + "RemoteAttr": "Dim", + "RemoteBg": "Blue", + "RemoteFg": "White", + "CountAttr": "Dim", + "CountBg": "Blue", + "CountFg": "White", + "HostnameAttr": "Bold", + "HostnameBg": "Blue", + "HostnameFg": "White", + "IDAttr": "Dim", + "IDBg": "Blue", + "IDFg": "White", + "StatsOkAttr": "None", + "StatsOkBg": "Green", + "StatsOkFg": "Black", + "StatsWarnAttr": "None", + "StatsWarnBg": "Red", + "StatsWarnFg": "White", + "TextAttr": "None", + "TextBg": "Black", + "TextFg": "White" + }, + "Client": { + "DelimiterAttr": "Dim", + "DelimiterBg": "Yellow", + "DelimiterFg": "Black", + "ClientAttr": "Dim", + "ClientBg": "Yellow", + "ClientFg": "Black", + "HostnameAttr": "Dim", + "HostnameBg": "Yellow", + "HostnameFg": "Black", + "TextAttr": "None", + "TextBg": "Black", + "TextFg": "White" + }, + "Server": { + "DelimiterAttr": "AttrDim", + "DelimiterBg": "BgCyan", + "DelimiterFg": "FgBlack", + "ServerAttr": "AttrDim", + "ServerBg": "BgCyan", + "ServerFg": "FgBlack", + "HostnameAttr": "AttrBold", + "HostnameBg": "BgCyan", + "HostnameFg": "FgBlack", + "TextAttr": "AttrNone", + "TextBg": "BgBlack", + "TextFg": "FgWhite" + }, + "Common": { + "SeverityErrorAttr": "AttrBold", + "SeverityErrorBg": "BgRed", + "SeverityErrorFg": "FgWhite", + "SeverityFatalAttr": "AttrBold", + "SeverityFatalBg": "BgMagenta", + "SeverityFatalFg": "FgWhite", + "SeverityWarnAttr": "AttrBold", + "SeverityWarnBg": "BgBlack", + "SeverityWarnFg": "FgWhite" + }, + "MaprTable": { + "DataAttr": "AttrNone", + "DataBg": "BgBlue", + "DataFg": "FgWhite", + "DelimiterAttr": "AttrDim", + "DelimiterBg": "BgBlue", + "DelimiterFg": "FgWhite", + "HeaderAttr": "AttrBold", + "HeaderBg": "BgBlue", + "HeaderFg": "FgWhite", + "HeaderDelimiterAttr": "AttrDim", + "HeaderDelimiterBg": "BgBlue", + "HeaderDelimiterFg": "FgWhite", + "HeaderSortKeyAttr": "AttrUnderline", + "HeaderGroupKeyAttr": "AttrReverse", + "RawQueryAttr": "AttrDim", + "RawQueryBg": "BgBlack", + "RawQueryFg": "FgCyan" + } + } + }, + "Server": { + "SSHBindAddress": "0.0.0.0", + "HostKeyFile": "cache/ssh_host_key", + "HostKeyBits": 2048, + "MapreduceLogFormat": "default", + "MaxConcurrentCats": 2, + "MaxConcurrentTails": 50, + "MaxConnections": 50, + "MaxLineLength": 1048576, + "TurboBoostDisable": false, + "Permissions": { + "Default": [ + "readfiles:^/.*$" + ], + "Users": { + "paul": [ + "readfiles:^/.*$" + ], + "pbuetow": [ + "readfiles:^/.*$" + ], + "jamesblake": [ + "readfiles:^/tmp/foo.log$", + "readfiles:^/.*$", + "readfiles:!^/tmp/bar.log$" + ], + "root": [ + "readfiles:^/.*$" + ] + } + } + }, + "Common": { + "LogDir": "log", + "Logger": "Fout", + "LogRotation": "Daily", + "CacheDir": "cache", + "SSHPort": 2222, + "LogLevel": "Info" + } +} diff --git a/packages/scripts/pkg-dtail-freebsd.sh b/packages/scripts/pkg-dtail-freebsd.sh new file mode 100644 index 0000000..1d42aaf --- /dev/null +++ b/packages/scripts/pkg-dtail-freebsd.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# Build a FreeBSD dtail package from pre-compiled binaries and upload to the repo PV. +# Run on f0 via SSH. Called by the Makefile. +# +# Arguments: +# $1 — version (e.g. 4.3.2-ng) +# $2 — PV destination (e.g. /data/nfs/k3svolumes/pkgrepo/freebsd/FreeBSD:15:amd64/latest) + +set -e + +VERSION="$1" +PV_DEST="$2" +NAME="dtail" +COMMENT="Distributed log tail and grep tool" +DESC="DTail is a distributed DevOps tool for tailing, grepping, catting, and mapping across many remote machines at once via SSH." +MAINTAINER="paul@buetow.org" +WWW="https://codeberg.org/snonux/dtail" + +WORKDIR="/tmp/${NAME}-freebsd-pkg" +rm -rf "$WORKDIR" +mkdir -p \ + "$WORKDIR/stage/usr/local/bin" \ + "$WORKDIR/stage/usr/local/etc/rc.d" \ + "$WORKDIR/stage/usr/local/etc/dserver" \ + "$WORKDIR/out/All" + +# Binaries (cross-compiled linux→freebsd with nozstd; .zst logs not supported) +for bin in dserver dcat dgrep dmap dtail dtailhealth; do + cp "/tmp/dtail-freebsd-binaries/${bin}" "$WORKDIR/stage/usr/local/bin/${bin}" + chmod 755 "$WORKDIR/stage/usr/local/bin/${bin}" +done + +# Key cache helper (sh-compatible; walks /home/ on FreeBSD) +cp "/tmp/dtail-freebsd-binaries/dserver-update-key-cache.sh" \ + "$WORKDIR/stage/usr/local/bin/dserver-update-key-cache.sh" +chmod 555 "$WORKDIR/stage/usr/local/bin/dserver-update-key-cache.sh" + +# rc.d script (FreeBSD rc.subr style; config at /usr/local/etc/dserver/dtail.json) +cp "/tmp/dtail-freebsd-binaries/dserver.rc" \ + "$WORKDIR/stage/usr/local/etc/rc.d/dserver" +chmod 555 "$WORKDIR/stage/usr/local/etc/rc.d/dserver" + +# Config +cp "/tmp/dtail-freebsd-binaries/dtail.json" \ + "$WORKDIR/stage/usr/local/etc/dserver/dtail.json" +chmod 644 "$WORKDIR/stage/usr/local/etc/dserver/dtail.json" + +# Packing list — paths relative to /usr/local prefix +cat > "$WORKDIR/plist" <<'PLIST' +bin/dserver +bin/dcat +bin/dgrep +bin/dmap +bin/dtail +bin/dtailhealth +bin/dserver-update-key-cache.sh +etc/rc.d/dserver +etc/dserver/dtail.json +PLIST + +# Package manifest (UCL) +cat > "$WORKDIR/+MANIFEST" <<MANIFEST +name: "${NAME}" +version: "${VERSION}" +origin: "local/${NAME}" +comment: "${COMMENT}" +desc: "${DESC}" +maintainer: "${MAINTAINER}" +www: "${WWW}" +prefix: /usr/local +MANIFEST + +# Build package, regenerate repo metadata, copy to PV +doas pkg create -M "$WORKDIR/+MANIFEST" -p "$WORKDIR/plist" -r "$WORKDIR/stage" -o "$WORKDIR/out/All" +doas pkg repo "$WORKDIR/out" +doas cp -Rf "$WORKDIR/out/"* "$PV_DEST/" + +rm -rf "$WORKDIR" /tmp/dtail-freebsd-binaries /tmp/pkg-dtail-freebsd.sh +echo "FreeBSD package ${NAME}-${VERSION} uploaded to repo" diff --git a/packages/scripts/pkg-dtail-rpm.sh b/packages/scripts/pkg-dtail-rpm.sh new file mode 100755 index 0000000..b654933 --- /dev/null +++ b/packages/scripts/pkg-dtail-rpm.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ $# -ne 5 ]]; then + echo "usage: $0 <x86_64|aarch64> <version> <dtail-src> <asset-dir> <out-dir>" >&2 + exit 1 +fi + +rpm_arch=$1 +raw_version=$2 +dtail_src=$3 +asset_dir=$4 +out_dir=$5 + +case "$rpm_arch" in + x86_64) + goarch=amd64 + ;; + aarch64) + goarch=arm64 + ;; + *) + echo "unsupported rpm arch: $rpm_arch" >&2 + exit 1 + ;; +esac + +rpm_version=${raw_version%%-*} +rpm_release=1 +if [[ "$raw_version" == *-* ]]; then + suffix=${raw_version#"$rpm_version"-} + suffix=${suffix//[^A-Za-z0-9.+~]/.} + rpm_release="1.${suffix}" +fi + +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT + +pkgroot="$workdir/root" +topdir="$workdir/rpmbuild" +mkdir -p \ + "$pkgroot/usr/local/bin" \ + "$pkgroot/etc/dserver" \ + "$pkgroot/usr/lib/systemd/system" \ + "$pkgroot/usr/share/licenses/dtail" \ + "$topdir/BUILD" \ + "$topdir/BUILDROOT" \ + "$topdir/RPMS" \ + "$topdir/SOURCES" \ + "$topdir/SPECS" \ + "$topdir/SRPMS" + +if [[ -n "${DTAIL_PREBUILT_ROOT:-}" ]]; then + cp -a "$DTAIL_PREBUILT_ROOT/." "$pkgroot/" +else + for bin in dserver dcat dgrep dmap dtail dtailhealth; do + ( + cd "$dtail_src" + CGO_ENABLED=0 GOOS=linux GOARCH="$goarch" go build -tags nozstd -o "$pkgroot/usr/local/bin/$bin" "./cmd/$bin/main.go" + ) + done + + install -m 0644 "$asset_dir/dtail.json" "$pkgroot/etc/dserver/dtail.json" + install -m 0755 "$asset_dir/dserver-update-key-cache.sh" "$pkgroot/usr/local/bin/dserver-update-key-cache.sh" + install -m 0644 "$asset_dir/dserver.service" "$pkgroot/usr/lib/systemd/system/dserver.service" + install -m 0644 "$asset_dir/dserver-update-keycache.service" "$pkgroot/usr/lib/systemd/system/dserver-update-keycache.service" + install -m 0644 "$asset_dir/dserver-update-keycache.timer" "$pkgroot/usr/lib/systemd/system/dserver-update-keycache.timer" + install -m 0644 "$dtail_src/LICENSE" "$pkgroot/usr/share/licenses/dtail/LICENSE" +fi + +cp -a "$pkgroot" "$topdir/SOURCES/root" + +cat >"$topdir/SPECS/dtail.spec" <<EOF +Name: dtail +Version: $rpm_version +Release: $rpm_release +Summary: Distributed log tail and grep tool +License: Apache-2.0 +URL: https://codeberg.org/snonux/dtail +BuildArch: $rpm_arch +Requires(pre): shadow-utils +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description +DTail is a distributed DevOps tool for tailing, grepping, catting, and +mapping across many remote machines at once via SSH. + +%prep + +%build + +%install +mkdir -p %{buildroot} +cp -a %{_sourcedir}/root/. %{buildroot}/ + +%pre +getent group dserver >/dev/null || groupadd -r dserver +getent passwd dserver >/dev/null || useradd -r -g dserver -d /var/lib/dserver -s /sbin/nologin -c "DTail server" dserver +exit 0 + +%post +systemctl daemon-reload >/dev/null 2>&1 || true + +%preun +if [ \$1 -eq 0 ]; then + systemctl --no-reload disable --now dserver-update-keycache.timer >/dev/null 2>&1 || true +fi + +%postun +systemctl daemon-reload >/dev/null 2>&1 || true + +%files +%license /usr/share/licenses/dtail/LICENSE +%dir /etc/dserver +%config(noreplace) /etc/dserver/dtail.json +/usr/local/bin/dserver +/usr/local/bin/dcat +/usr/local/bin/dgrep +/usr/local/bin/dmap +/usr/local/bin/dtail +/usr/local/bin/dtailhealth +/usr/local/bin/dserver-update-key-cache.sh +/usr/lib/systemd/system/dserver.service +/usr/lib/systemd/system/dserver-update-keycache.service +/usr/lib/systemd/system/dserver-update-keycache.timer + +%changelog +* Sat Apr 11 2026 Paul Buetow <paul@buetow.org> - $rpm_version-$rpm_release +- Package DTail for Rocky Linux 9 +EOF + +mkdir -p "$out_dir" +rpmbuild --quiet \ + --define "_topdir $topdir" \ + --target "$rpm_arch" \ + -bb "$topdir/SPECS/dtail.spec" +cp "$topdir/RPMS/$rpm_arch"/*.rpm "$out_dir/" |
