From 830407e88f9d40d954356c3754f2647f91d5c06a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 17:26:00 +0200 Subject: Adding upstream version 5.6.0. Signed-off-by: Daniel Baumann --- scripts/bench.sh | 12 +++ scripts/bugreport-journals.py | 194 ++++++++++++++++++++++++++++++++++++ scripts/build-in-obs.sh | 32 ++++++ scripts/coverage_c_combine.sh | 26 +++++ scripts/coverage_env.sh | 42 ++++++++ scripts/doh_b64encode_query.py | 26 +++++ scripts/gen-cdefs.sh | 82 +++++++++++++++ scripts/gen-pgp-keyblock.sh | 38 +++++++ scripts/get-date.sh | 14 +++ scripts/kresd-host.lua | 115 +++++++++++++++++++++ scripts/kresd-query.lua | 63 ++++++++++++ scripts/kresd.apparmor | 29 ++++++ scripts/luacov_gen_empty.sh | 18 ++++ scripts/luacov_to_info.lua | 57 +++++++++++ scripts/make-archive.sh | 38 +++++++ scripts/make-doc.sh | 42 ++++++++ scripts/make-obs.sh | 59 +++++++++++ scripts/map_install_src.lua | 168 +++++++++++++++++++++++++++++++ scripts/run-pylint.sh | 12 +++ scripts/run-scanbuild-with-args.sh | 51 ++++++++++ scripts/test-config.sh | 32 ++++++ scripts/test-integration-prepare.sh | 8 ++ scripts/update-authors.sh | 41 ++++++++ scripts/update-root-hints.sh | 28 ++++++ 24 files changed, 1227 insertions(+) create mode 100755 scripts/bench.sh create mode 100755 scripts/bugreport-journals.py create mode 100755 scripts/build-in-obs.sh create mode 100755 scripts/coverage_c_combine.sh create mode 100755 scripts/coverage_env.sh create mode 100755 scripts/doh_b64encode_query.py create mode 100755 scripts/gen-cdefs.sh create mode 100755 scripts/gen-pgp-keyblock.sh create mode 100755 scripts/get-date.sh create mode 100755 scripts/kresd-host.lua create mode 100755 scripts/kresd-query.lua create mode 100644 scripts/kresd.apparmor create mode 100755 scripts/luacov_gen_empty.sh create mode 100755 scripts/luacov_to_info.lua create mode 100755 scripts/make-archive.sh create mode 100755 scripts/make-doc.sh create mode 100755 scripts/make-obs.sh create mode 100755 scripts/map_install_src.lua create mode 100755 scripts/run-pylint.sh create mode 100755 scripts/run-scanbuild-with-args.sh create mode 100755 scripts/test-config.sh create mode 100755 scripts/test-integration-prepare.sh create mode 100755 scripts/update-authors.sh create mode 100755 scripts/update-root-hints.sh (limited to 'scripts') diff --git a/scripts/bench.sh b/scripts/bench.sh new file mode 100755 index 0000000..232c523 --- /dev/null +++ b/scripts/bench.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later +set -o errexit -o nounset + +# Run benchmark +cd "${MESON_SOURCE_ROOT}" + +echo "Test LRU with increasing overfill, misses should increase ~ linearly" + +for num in 65536 32768 16384 8192 4096; do + "${MESON_BUILD_ROOT}/${MESON_SUBDIR}/bench_lru" 23 "${MESON_SOURCE_ROOT}/${MESON_SUBDIR}/bench_lru_set1.tsv" - "${num}" +done diff --git a/scripts/bugreport-journals.py b/scripts/bugreport-journals.py new file mode 100755 index 0000000..d66ddfb --- /dev/null +++ b/scripts/bugreport-journals.py @@ -0,0 +1,194 @@ +#!/usr/bin/python3 +""" +Collect systemd-journal log entries around time of daemon exit and coredumps. +""" + +import datetime +import json +import logging +import pathlib +import shutil +import subprocess +import sys + + +TIMESPAN_BEFORE = 600 # s +TIMESPAN_AFTER = TIMESPAN_BEFORE +CURSOR_DIR = pathlib.Path('/var/lib/knot-resolver') +CURSOR_PATH = CURSOR_DIR / 'coredump_watcher.cursor' + + +class Timestamp: + def __init__(self, usec): + self.usec = int(usec) + + @property + def unix(self): + return self.usec // 10**6 + + def __str__(self): + return datetime.datetime.utcfromtimestamp(self.unix).strftime('%Y-%m-%d_%H:%M:%S') + + def __lt__(self, other): + return self.usec < other.usec + + def __eq__(self, other): + return self.usec == other.usec + + +class Entry(dict): + @property + def timestamp(self): + usec = self.get('__REALTIME_TIMESTAMP') + if usec is None: + return None + return Timestamp(usec) + + @property + def core_path(self): + filename = self.get('COREDUMP_FILENAME') + if filename is None: + return None + return pathlib.Path(filename) + + def get_first(self, *keys): + for key in keys: + try: + return self[key] + except KeyError: + continue + return None + + @property + def program(self): + return self.get_first('COREDUMP_UNIT', 'UNIT', '_SYSTEMD_UNIT', 'SYSLOG_IDENTIFIER') + + @property + def pid(self): + return self.get_first('COREDUMP_PID', '_PID') + + +def save_cursor(cursor): + if cursor is None: + return + CURSOR_DIR.mkdir(parents=True, exist_ok=True) + with CURSOR_PATH.open('w') as curfile: + curfile.write(cursor) + logging.info('log cursor saved into %s, next run will skip old logs', + CURSOR_PATH) + + +def load_cursor(): + try: + with CURSOR_PATH.open('r') as curfile: + logging.info('log cursor read from %s, skipping old logs', + CURSOR_PATH) + return curfile.read().strip() + except FileNotFoundError: + logging.info('log cursor file %s does not exist, parsing all logs', + CURSOR_PATH) + return None + + +def get_cursor(): + journal_args = ['journalctl', '-o', 'json', '-n', '1'] + with subprocess.Popen( + journal_args, + bufsize=1, # line buffering + universal_newlines=True, + stdout=subprocess.PIPE) as jproc: + stdout, _ = jproc.communicate() + data = json.loads(stdout) + entry = Entry(**data) + return entry.get('__CURSOR') + + +def read_journal(*args): + journal_args = [ + 'journalctl', + '-o', 'json', + '-u', 'kres*', + '-u', 'systemd-coredump*'] + journal_args += args + with subprocess.Popen( + journal_args, + bufsize=1, # line buffering + universal_newlines=True, + stdout=subprocess.PIPE) as jproc: + for line in jproc.stdout: + data = json.loads(line) + yield Entry(**data) + + +def extract_logs(around_time, log_name): + start_time = Timestamp(around_time.usec - TIMESPAN_BEFORE * 10**6) + end_time = Timestamp(around_time.usec + TIMESPAN_AFTER * 10**6) + log_window = list(read_journal( + '--since', '@{}'.format(start_time.unix), + '--until', '@{}'.format(end_time.unix))) + with log_name.with_suffix('.json').open('w') as jsonf: + json.dump(log_window, jsonf, indent=4) + with log_name.with_suffix('.log').open('w') as logf: + logf.write('##### logs since {}\n'.format(start_time)) + for entry in log_window: + if entry.timestamp == around_time: + logf.write('##### HERE #####\n') + logf.write('{t} {h} {prg}[{pid}]: {m}\n'.format( + t=entry.timestamp, + h=entry.get('_HOSTNAME'), + prg=entry.program, + pid=entry.pid, + m=entry.get('MESSAGE'))) + logf.write('##### logs until {}\n'.format(end_time)) + + +def main(): + logging.basicConfig(level=logging.INFO) + + if len(sys.argv) != 2: + sys.exit('Usage: {} '.format(sys.argv[0])) + outdir = pathlib.Path(sys.argv[1]) + outdir.mkdir(parents=True, exist_ok=True) + + cursor_previous = load_cursor() + cursor_at_start = get_cursor() + + exit_times = [] + coredumps = {} + filter_args = [] + if cursor_previous is not None: + filter_args = ['--after-cursor', cursor_previous] + for entry in read_journal(*filter_args): + if 'EXIT_CODE' in entry: + logging.debug('exit@%s: %s', entry.timestamp, entry) + exit_times.append(entry.timestamp) + if 'COREDUMP_FILENAME' in entry: + logging.debug('coredump @ %s: %s', entry.timestamp, entry.core_path) + coredumps[entry.core_path] = entry.timestamp + + exit_times.sort() + logging.debug('detected exits: %s', exit_times) + for exit_time in exit_times: + extract_logs(exit_time, outdir / str(exit_time)) + + coredumps_missing = 0 + logging.debug('detected coredumps: %s', coredumps) + for core_path, core_time in coredumps.items(): + core_name = core_path.name + out_path_prefix = (outdir / str(core_time)) + extract_logs(core_time, out_path_prefix.with_suffix('.logs')) + try: + shutil.copy( + str(core_path), + str(out_path_prefix.with_suffix('.{}'.format(core_name)))) + except FileNotFoundError as ex: + logging.error('coredump file %s cannot be copied: %s', core_path, ex) + coredumps_missing += 1 + logging.info('wrote %d coredumps and %d logs snippets (%s coredumps missing)', + len(coredumps) - coredumps_missing, len(exit_times), coredumps_missing) + + save_cursor(cursor_at_start) + + +if __name__ == '__main__': + main() diff --git a/scripts/build-in-obs.sh b/scripts/build-in-obs.sh new file mode 100755 index 0000000..3256dde --- /dev/null +++ b/scripts/build-in-obs.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Push packaging files to OBS +# +# Example usage: +# 1. ./scripts/make-obs.sh +# 2. ./scripts/build-in-obs.sh knot-resolver-latest +set -o errexit -o nounset -o xtrace + +pkgdir='pkg/obs' + +project=home:CZ-NIC:$1 +package=knot-resolver + +if ! [[ "$1" == *-devel || "$1" == *-testing ]]; then + read -p "Pushing to '$project', are you sure? [y/N]: " yn + case $yn in + [Yy]* ) + ;; + * ) + exit 1 + esac +fi + +osc co "${project}" "${package}" +pushd "${project}/${package}" +osc del * ||: +cp -r ../../${pkgdir}/* ./ +osc addremove +osc ci -n +popd diff --git a/scripts/coverage_c_combine.sh b/scripts/coverage_c_combine.sh new file mode 100755 index 0000000..a891ded --- /dev/null +++ b/scripts/coverage_c_combine.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later + +# $1 = top source directory +# $2 = coverage data directory path +# $3 = output directory for *.info files + +set -o errexit -o nounset +shopt -s nullglob +IFS=$'\n' + +TOPSRCDIR="$1" +DATAROOT="$2" +OUTDIR="$3" + +cd "${TOPSRCDIR}" +for COVNAME in $(find "${DATAROOT}" -name .topdir_kresd_coverage) +do + find "${DATAROOT}" -name '*.gcda' -not -path "${DATAROOT}/*" -delete + COVDIR="$(dirname "${COVNAME}")" + COVDATA_FILENAMES=("${COVDIR}"/*) # filenames in BASH array + (( ${#COVDATA_FILENAMES[*]} )) || continue # skip empty dirs + + cp -r -t ${TOPSRCDIR} "${COVDIR}"/* + ${LCOV} -q --no-external --capture -d lib -d daemon -d modules -o "$(mktemp -p "${OUTDIR}" -t XXXXXXXX.c.info)" > /dev/null +done diff --git a/scripts/coverage_env.sh b/scripts/coverage_env.sh new file mode 100755 index 0000000..0f6810f --- /dev/null +++ b/scripts/coverage_env.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later + +# generate variables for coverage testing +# $1 = top source directory +# $2 = coverage data directory path +# $3 = name of test/new subdirectory name +# $4 = [optional] --export to generate export commands + +set -o errexit -o nounset +shopt -s nullglob + +test -z "${COVERAGE:-}" && exit 0 # not enabled, do nothing +test ! -z "${V:-}" && set -o xtrace # verbose mode + +EXPORT="" +test "${4:-}" == "--export" && EXPORT="export " +TOPSRCDIR="$1" +DATAROOT="$2" +OUTPATH="$2/$3" + +# check that output directory is empty +# beware: Makefile will always call coverage_env.sh for all targets +# so directories get created but not populated +# i.e. test -d is not sufficient check +OUTPATH_FILENAMES=("${OUTPATH}"/*) # filenames in BASH array +(( ${#OUTPATH_FILENAMES[*]} )) && echo "false" && >&2 echo "fatal: output directory ${OUTPATH} must be empty (or non-existent)" && exit 1 + +mkdir -p "${OUTPATH}" +# convert paths to absolute +pushd "${OUTPATH}" &> /dev/null +touch .topdir_kresd_coverage +OUTPATH="$(pwd -P)" +popd &> /dev/null + +# determine GCOV_PREFIX_STRIP value for current source directory +TOPSRCDIR_SLASHES="${TOPSRCDIR//[^\/]/}" # remove everything except / +GCOV_PREFIX_STRIP="${#TOPSRCDIR_SLASHES}" # number of / == number of components + +KRESD_COVERAGE_STATS="${OUTPATH}/luacov.stats.out" +GCOV_PREFIX="${OUTPATH}" +echo "${EXPORT}KRESD_COVERAGE_STATS=\"${KRESD_COVERAGE_STATS}\" ${EXPORT}GCOV_PREFIX=\"${GCOV_PREFIX}\" ${EXPORT}GCOV_PREFIX_STRIP=\"${GCOV_PREFIX_STRIP}\"" diff --git a/scripts/doh_b64encode_query.py b/scripts/doh_b64encode_query.py new file mode 100755 index 0000000..59569b8 --- /dev/null +++ b/scripts/doh_b64encode_query.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +import argparse +import base64 + +import dns +import dns.message + + +def main(): + parser = argparse.ArgumentParser( + description='Convert query name and type to base64 URL-encoded form') + parser.add_argument('qname', type=str, help='query name') + parser.add_argument('qtype', type=str, help='query type') + args = parser.parse_args() + + msg = dns.message.make_query(args.qname, args.qtype, dns.rdataclass.IN) + msg.id = 0 + wire = msg.to_wire() + encoded = base64.urlsafe_b64encode(wire) + printable = encoded.decode('utf-8') + + print(printable) + + +if __name__ == '__main__': + main() diff --git a/scripts/gen-cdefs.sh b/scripts/gen-cdefs.sh new file mode 100755 index 0000000..ddb0aa7 --- /dev/null +++ b/scripts/gen-cdefs.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later +set -o pipefail -o errexit + +if [ "$2" != types ] && [ "$2" != functions ]; then + echo "Usage: $0 libkres (types|functions)" >&2 + echo " and input identifiers, one per line." >&2 + echo " You need debug symbols in the library." >&2 + echo + echo " If you call this on a type that's a typedef, it gets expanded." >&2 + echo " To avoid that, prefix the identifier with 'typedef '." >&2 + exit 1 +fi + +if ! command -v gdb >/dev/null; then + echo "Failed to find gdb" >&2 + exit 1 +fi + +if ! command -v sed >/dev/null; then + echo "Failed to find GNU sed" >&2 + exit 1 +fi + +if ! sed --version | head -1 | grep -q "GNU sed"; then + echo "GNU sed required to run this script" >&2 +fi + +# be very precise with the directories for libraries to not pick wrong library +case "$1" in + libknot) library="$(PATH="$(pkg-config libknot --variable=libdir)" command -v "$1.so")" ;; + libzscanner) library="$(PATH="$(pkg-config libzscanner --variable=libdir)" command -v "$1.so")" ;; + *) library="$(command -v "$1")" # use absolute path to library +esac + +if [ -z "$library" ]; then + echo "$1 not found. Note: only .so platforms work currently." >&2 + exit 1 +fi + +# Let's use an array to hold command-line arguments, to simplify quoting. +GDB=(gdb) +GDB+=(-n -quiet -batch "-symbols=$library") +GDB+=(-iex "set width unlimited" -iex "set max-value-size unlimited") + +grep -v '^#\|^$' | while read -r ident; do + if [ "$2" = functions ]; then + output="$("${GDB[@]}" --ex "info functions ^$ident\$" \ + | sed '0,/^All functions/ d; /^File .*:$/ d')" + else # types + case "$ident" in + struct\ *|union\ *|enum\ *) + output="$("${GDB[@]}" --ex "ptype $ident" \ + | sed '0,/^type = /s/^type = /\n/; $ s/$/;/')" + ;; + typedef\ *) # typedef that shouldn't be expanded + output="$("${GDB[@]}" --ex "info types ^"$(echo "$ident" | sed 's/^typedef //')"\$" \ + | sed -e '0,/^File .*:$/ d' -e '/^File .*:$/,$ d')" + # we need to stop early to remove ^^ multiple matches + ;; + *) # we assume it's a typedef that should be expanded + output="$("${GDB[@]}" --ex "ptype $ident" \ + | sed "0,/^type = /s/^type = /typedef /; $ s/$/ $ident;/")" + ;; + esac + fi + # LuaJIT FFI blows up on "uint" type + output="$(echo "$output" | sed 's/\buint\b/unsigned int/g')" + # GDB 8.2+ added source line prefix to output + output="$(echo "$output" | sed 's/^[0-9]\+:[[:space:]]*//g')" + # use tabs instead of spaces + output="$(echo "$output" | sed 's/ /\t/g')" + + # abort on empty output + if [ -z "$(echo "$output" | tr -d "\n;")" ]; then + echo "Failed to find cdef of $ident" >&2 + exit 1 + fi + echo "$output" | grep -v '^$' +done + +exit 0 diff --git a/scripts/gen-pgp-keyblock.sh b/scripts/gen-pgp-keyblock.sh new file mode 100755 index 0000000..2985531 --- /dev/null +++ b/scripts/gen-pgp-keyblock.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Script to create/update Knot Resolver PGP keyring +set -o errexit -o nounset + +keys=( + 'B6006460B60A80E782062449E747DF1F9575A3AA' # vladimir.cunat@nic.cz + '3057EE9A448F362D74205A779AB120DA0A76F6DE' # ales.mrazek@nic.cz + # '4A8BA48C2AED933BD495C509A1FBA5F7EF8C4869' # tomas.krizek@nic.cz expired 2022-03-31 +) +outfile="kresd-keyblock.asc" +url="https://secure.nic.cz/files/knot-resolver/kresd-keyblock.asc" + +keyring="$(mktemp -d)" +keyring_import="$(mktemp -d)" +published="$(mktemp)" + +cleanup() { + rm -rf "${keyring}" + rm -rf "${keyring_import}" + rm -rf "${published}" +} +trap cleanup EXIT + +# obtain keys from keys.openpgp.org +gpg --homedir "${keyring}" -q --keyserver keys.openpgp.org --recv-keys "${keys[@]}" + +# export minimal size keys with just the necessary signatures +rm -f "${outfile}" +gpg --homedir "${keyring}" -q --export --export-options export-minimal --armor --output "${outfile}" "${keys[@]}" + +# display keys after import +gpg --homedir "${keyring_import}" -q --import "${outfile}" +gpg --homedir "${keyring_import}" -k +echo "Created: ${outfile}" + +# check if update of secure.nic.cz keyblock might be needed +curl -sfo "${published}" "${url}" +diff -q "${outfile}" "${published}" &>/dev/null || echo "Generated keyblock differs from ${url}" diff --git a/scripts/get-date.sh b/scripts/get-date.sh new file mode 100755 index 0000000..3653155 --- /dev/null +++ b/scripts/get-date.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-3.0-or-later +set -o nounset +cd "$(dirname $0)/.." + +# Get date from NEWS if possible (regular release) +DATE=$(head -n1 < NEWS | sed 's/.*(\(.*\)).*/\1/' | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$$') + +if [[ $? -ne 0 ]]; then + # or use last modification time of NEWS (dev versions) + DATE=$(date -u -r NEWS +%F) +fi + +echo -n $DATE diff --git a/scripts/kresd-host.lua b/scripts/kresd-host.lua new file mode 100755 index 0000000..be6efd4 --- /dev/null +++ b/scripts/kresd-host.lua @@ -0,0 +1,115 @@ +#!/usr/bin/env luajit +-- SPDX-License-Identifier: GPL-3.0-or-later +-- Work around OS X stripping dyld variables +cli_bin = 'luajit scripts/kresd-query.lua' +libdir = os.getenv('DYLD_LIBRARY_PATH') +if libdir then + cli_bin = string.format('DYLD_LIBRARY_PATH="%s" %s', libdir, cli_bin) +end +-- Parse CLI arguments +local function help(rc) + print(string.format([[ +Usage: %s [-vdh46D] [-c class] [-t type] + [-f keyfile] hostname + Queries the DNS for information. + The hostname is looked up for IP4, IP6 and mail. + Use the -v option to see DNSSEC security information. + -t type what type to look for. + -c class what class to look for, if not class IN. + -C confstr additional kresd-style configuration. + -D DNSSEC enable with default root anchor + -f keyfile read trust anchors from file, with lines as -y. + -v be more verbose, shows nodata and security. + -d debug, traces the action, -d -d shows more. + -4 use ipv4 network, avoid ipv6. + -6 use ipv6 network, avoid ipv4. + -h show this usage help.]], + arg[0])) + return rc +end + +-- Parse CLI arguments +if #arg < 1 then + return help(1) +end +local qtypes, qclass, qname = {}, 'IN', nil +local verbose, config = false, {} +k = 1 while k <= #arg do + local v = arg[k] + if v == '-h' or v == '--help' then + return help(0) + elseif v == '-C' then + k = k + 1 + table.insert(config, arg[k]) + elseif v == '-D' then + table.insert(config, 'trust_anchors.add_file("root.keys")') + elseif v == '-f' then + k = k + 1 + table.insert(config, string.format('trust_anchors.add_file("%s")', arg[k])) + elseif v == '-v' then + verbose = true + elseif v == '-d' then + verbose = true + table.insert(config, 'log_level("debug")') + elseif v == '-4' then + table.insert(config, 'net.ipv6 = false') + elseif v == '-6' then + table.insert(config, 'net.ipv4 = false') + elseif v == '-c' then + k = k + 1 + qclass = arg[k]:upper() + elseif v == '-t' then + k = k + 1 + table.insert(qtypes, arg[k]:upper()) + elseif v:byte() == string.byte('-') then + return help(1) + else + qname = v + -- Check if name is an IP addresses + -- @TODO: convert to domain name and make a PTR lookup + end + k = k + 1 +end +if not qname then + return help(1) +end +if #qtypes == 0 then + qtypes = {'A', 'AAAA', 'MX'} +end +-- Assemble config/query +for _, qtype in ipairs(qtypes) do + query = string.format('-t %s -c %s %s', qtype, qclass, qname) + capture = string.format([[ + local qname = "%s" + local qtype = "%s" + local qverbose = %s]], qname, qtype, tostring(verbose))..[[ + local qry = req:resolved() + local section = pkt:rrsets(kres.section.ANSWER) + for i = 1, #section do + local rr = section[i] + for k = 1, rr.rrs.count do + local rdata = rr:tostring(k - 1) + local owner = kres.dname2str(rr:owner()) + if qverbose then + if not qry.flags.DNSSEC_WANT or qry.flags.DNSSEC_INSECURE then + rdata = rdata .. " (insecure)" + else + rdata = rdata .. " (secure)" + end + end + if rr.type == kres.type.A then + print(string.format("%s has address %s", owner, rdata)) + elseif rr.type == kres.type.AAAA then + print(string.format("%s has IPv6 address %s", owner, rdata)) + elseif rr.type == kres.type.MX then + print(string.format("%s mail is handled by %s", owner, rdata)) + elseif rr.type == kres.type.CNAME then + print(string.format("%s is an alias for %s", owner, rdata)) + else + print(string.format("%s has %s record %s", owner, qtype, rdata)) + end + end + end + ]] + os.execute(string.format('%s -C \'%s\' %s \'%s\'', cli_bin, table.concat(config, ' '), query, capture)) +end diff --git a/scripts/kresd-query.lua b/scripts/kresd-query.lua new file mode 100755 index 0000000..713b9c7 --- /dev/null +++ b/scripts/kresd-query.lua @@ -0,0 +1,63 @@ +#!/usr/bin/env luajit +-- SPDX-License-Identifier: GPL-3.0-or-later +cli_bin = 'kresd -q -c -' +-- Work around OS X stripping dyld variables +libdir = os.getenv('DYLD_LIBRARY_PATH') +if libdir then + cli_bin = string.format('DYLD_LIBRARY_PATH="%s" %s', libdir, cli_bin) +end +cli_cmd = [[echo ' +option("ALWAYS_CUT", true) +%s +return resolve("%s", kres.type.%s, kres.class.%s, 0, +function (pkt, req) + local ok, err = pcall(function () %s end) + if not ok then + print(err) + end + quit() +end)']] +-- Parse CLI arguments +local function help() + name = 'kresd-query.lua' + print(string.format('Usage: %s [-t type] [-c class] [-C config]