magisk-zapret2/zapret2/scripts/command-builder.sh
loop-uh 852d42c02e Answer in builtins what the replace path kept re-buying in forks
Android prices every fork at ~25ms and every exec at ~90ms, and the
preset apply was paying that price for questions it had already
answered: 95 separate stat calls re-proving file metadata one field at
a time, command substitutions around proc readers whose parsing was
already builtin-only, expected firewall rules rebuilt through captures
on every verify, and printf — an external binary on Android's mksh —
invoked once per line of every publication.

One stat capture now serves every metadata question a proof asks
(path_meta_capture, consumed by the uid/mode/nlink/size predicates and
retired on proof exit); the state-dir proof and a fully-pinned process
identity become lock-scoped facts on the same single-writer argument as
the owner read cache; proc_starttime/proc_argv0 gain fork-free
global-return forms with the printf wrappers kept as seams; the qnum
argument check reuses the cmdline snapshot argv0 already paid for;
expected firewall rules are built as data instead of captured; and
multi-line writers emit once through z2_emit_line, which resolves to
mksh's raw print builtin on the device and printf elsewhere. Load-time
probes replace the per-call command -v PATH walks, and log stamps reuse
one date exec per second via EPOCHREALTIME.

Measured on the Pixel 9 Pro XL: preset apply 56s before this series,
40s after the owner read cache, 14.6s now. tests/shell/run.sh passes;
the three test seams that named replaced internals (proc_starttime,
z2_fw_restore_command, the owner printf format) follow the new forms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 16:55:22 +03:00

952 lines
44 KiB
Shell

#!/system/bin/sh
# Strict preset compiler for Android nfqws2.
#
# The public machine protocol is intentionally line based. A compiled artifact
# stores one complete argument per line; neither this file nor zapret-start.sh
# evaluates or word-splits preset text.
COMMAND_BUILDER_CLI_MODE=0
COMMAND_BUILDER_ERROR_PREFIX=Z2_PRESET_ERROR
PRESET_MAX_BYTES=1048576
STRATEGY_CATALOG_MAX_BYTES=1048576
COMPILED_ARGV_MAX_BYTES=2097152
command_builder_safe_file_name_byte_length() {
local value="$1" LC_ALL=C
[ "${#value}" -le 255 ] 2>/dev/null
}
is_safe_preset_file_name() {
local name="$1"
[ -n "$name" ] && command_builder_safe_file_name_byte_length "$name" || return 1
[ "${name# }" = "$name" ] && [ "${name% }" = "$name" ] || return 1
case "$name" in
_*|.|..|*/*|*\\*|*"'"*|*'"'*|*.TXT|*.Txt|*.tXt|*.txT|*.TXt|*.TxT|*.tXT) return 1 ;;
*.txt) ;;
*) return 1 ;;
esac
case "$name" in *[[:cntrl:]]*) return 1 ;; esac
return 0
}
# Runtime catalog discovery projects only direct, trusted directory entries.
# Keep it ahead of common.sh and the compiler body: loading several thousand
# lines of lifecycle helpers to list already-qualified package files made this
# bounded read take seconds on Android.
if [ "${1:-}" = --list-presets-machine ]; then
[ "$#" -eq 2 ] || { printf 'Z2_PRESET_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
ZAPRET_DIR="${2:-}"
case "$ZAPRET_DIR" in
/*) ;;
*) printf 'Z2_PRESET_ERROR\tUNSAFE_ROOT\n' >&2; exit 2 ;;
esac
case "$ZAPRET_DIR" in
*'/../'*|*'/./'*|*/..|*/.)
printf 'Z2_PRESET_ERROR\tUNSAFE_ROOT\n' >&2
exit 2
;;
esac
PRESETS_DIR="$ZAPRET_DIR/presets"
[ -d "$PRESETS_DIR" ] && [ ! -L "$PRESETS_DIR" ] || {
printf 'Z2_PRESET_ERROR\tPRESET_CATALOG_MISSING\n'
exit 2
}
ready=0
quarantined=0
total=0
for preset_file in "$PRESETS_DIR"/*.txt; do
[ -e "$preset_file" ] || [ -L "$preset_file" ] || continue
preset_name="${preset_file##*/}"
case "$preset_name" in _*) continue ;; esac
is_safe_preset_file_name "$preset_name" || continue
total=$((total + 1))
reason=
if [ -L "$preset_file" ]; then
reason=PRESET_SYMLINK
elif [ ! -f "$preset_file" ]; then
reason=PRESET_MISSING
elif [ ! -s "$preset_file" ]; then
reason=PRESET_EMPTY
elif [ ! -r "$preset_file" ]; then
reason=PRESET_UNREADABLE
fi
if [ -z "$reason" ]; then
ready=$((ready + 1))
printf 'Z2_PRESET\tREADY\tOK\t%s\n' "$preset_name"
else
quarantined=$((quarantined + 1))
printf 'Z2_PRESET\tQUARANTINED\t%s\t%s\n' "$reason" "$preset_name"
fi
done
printf 'Z2_PRESET_SUMMARY\t2\tready=%s\tquarantined=%s\ttotal=%s\n' \
"$ready" "$quarantined" "$total"
exit 0
fi
case "${1:-}" in
--list-presets-machine|--scan-presets-machine|--validate-preset-machine|--preflight-preset-machine|--preview-preset-machine|--validate-strategies-machine)
COMMAND_BUILDER_CLI_MODE=1
[ "$1" != --validate-strategies-machine ] || COMMAND_BUILDER_ERROR_PREFIX=Z2_STRATEGIES_ERROR
ZAPRET_DIR="${2:-}"
case "$ZAPRET_DIR" in
/*) ;;
*) printf '%s\tUNSAFE_ROOT\n' "$COMMAND_BUILDER_ERROR_PREFIX" >&2; exit 2 ;;
esac
case "$ZAPRET_DIR" in
*'/../'*|*'/./'*|*/..|*/.)
printf '%s\tUNSAFE_ROOT\n' "$COMMAND_BUILDER_ERROR_PREFIX" >&2
exit 2
;;
esac
PRESETS_DIR="$ZAPRET_DIR/presets"
LISTS_DIR="$ZAPRET_DIR/lists"
SCRIPT_DIR="$ZAPRET_DIR/scripts"
MODDIR="$(dirname "$ZAPRET_DIR")"
if [ -f "$SCRIPT_DIR/common.sh" ] && [ ! -L "$SCRIPT_DIR/common.sh" ]; then
. "$SCRIPT_DIR/common.sh" || exit 2
fi
log_msg() { :; }
log_error() { :; }
log_debug() { :; }
;;
*)
[ -n "${ZAPRET_DIR:-}" ] || { echo "ERROR: source common.sh first" >&2; exit 1; }
;;
esac
PRESET_VALIDATION_CODE=OK
PRESET_VALIDATION_DETAIL=
PRESET_DEPENDENCY_PATH=
PRESET_DEPENDENCY_RELATIVE=
preset_validation_fail() {
PRESET_VALIDATION_CODE="$1"
PRESET_VALIDATION_DETAIL="${2:-}"
return 1
}
is_safe_dependency_name() {
local name="$1"
[ -n "$name" ] && command_builder_safe_file_name_byte_length "$name" || return 1
[ "${name# }" = "$name" ] && [ "${name% }" = "$name" ] || return 1
case "$name" in .|..|*/*|*\\*|*"'"*|*'"'*) return 1 ;; esac
case "$name" in *[[:cntrl:]]*) return 1 ;; esac
return 0
}
validate_preset_dependency() {
local dependency_class="$1" raw="$2" relative= base=
case "$dependency_class:$raw" in
lua:@lua/*) relative="${raw#@lua/}"; base="$ZAPRET_DIR/lua" ;;
blob:@bin/*) relative="${raw#@bin/}"; base="$ZAPRET_DIR/bin" ;;
list:lists/*) relative="${raw#lists/}"; base="$LISTS_DIR" ;;
*) preset_validation_fail UNSAFE_DEPENDENCY_PATH "$raw"; return 1 ;;
esac
is_safe_dependency_name "$relative" || {
preset_validation_fail UNSAFE_DEPENDENCY_PATH "$raw"; return 1;
}
PRESET_DEPENDENCY_PATH="$base/$relative"
PRESET_DEPENDENCY_RELATIVE="zapret2/${base##*/}/$relative"
if [ -n "${PRESET_ALLOWED_DEPENDENCIES_FILE:-}" ]; then
[ -f "$PRESET_ALLOWED_DEPENDENCIES_FILE" ] &&
grep -Fqx "$PRESET_DEPENDENCY_RELATIVE" "$PRESET_ALLOWED_DEPENDENCIES_FILE" || {
preset_validation_fail DEPENDENCY_NOT_DECLARED "$raw"; return 1;
}
fi
[ ! -L "$PRESET_DEPENDENCY_PATH" ] || {
preset_validation_fail DEPENDENCY_SYMLINK "$raw"; return 1;
}
[ -f "$PRESET_DEPENDENCY_PATH" ] || {
preset_validation_fail DEPENDENCY_MISSING "$raw"; return 1;
}
[ -s "$PRESET_DEPENDENCY_PATH" ] || {
preset_validation_fail DEPENDENCY_EMPTY "$raw"; return 1;
}
[ -r "$PRESET_DEPENDENCY_PATH" ] || {
preset_validation_fail DEPENDENCY_UNREADABLE "$raw"; return 1;
}
}
validate_filter_ports() {
local list="$1" old_ifs item first last
[ -n "$list" ] || return 1
[ "$list" != '*' ] || return 0
case "$list" in *[!0-9,:-]*|,*|*,|*,,*) return 1 ;; esac
old_ifs="$IFS"; IFS=,; set -- $list; IFS="$old_ifs"
[ "$#" -gt 0 ] || return 1
for item in "$@"; do
case "$item" in
*-*) first="${item%%-*}"; last="${item#*-}"; case "$last" in *-*) return 1 ;; esac ;;
*:*) first="${item%%:*}"; last="${item#*:}"; case "$last" in *:*) return 1 ;; esac ;;
*) first="$item"; last="$item" ;;
esac
case "$first:$last" in *[!0-9:]*) return 1 ;; esac
[ "$first" -ge 1 ] 2>/dev/null && [ "$last" -le 65535 ] 2>/dev/null &&
[ "$first" -le "$last" ] 2>/dev/null || return 1
done
}
validate_l7_filter() {
local value="$1"
case "$value" in
stun|discord|stun,discord|discord,stun) return 0 ;;
*) return 1 ;;
esac
}
validate_strategy_blob_references() {
local remaining="$1" token reference
while [ -n "$remaining" ]; do
token="${remaining%%:*}"
case "$remaining" in *:*) remaining="${remaining#*:}" ;; *) remaining= ;; esac
case "$token" in
blob=*|fake_blob=*|pattern=*|seqovl_pattern=*) reference="${token#*=}" ;;
*) continue ;;
esac
case "$reference" in
0x*) continue ;;
''|*[!A-Za-z0-9_.-]*) preset_validation_fail INVALID_BLOB_REFERENCE "$reference"; return 1 ;;
esac
case "$declared_blobs" in
*"|$reference|"*) ;;
*) preset_validation_fail BLOB_REFERENCE_MISSING "$reference"; return 1 ;;
esac
done
}
validate_capture_packet_count() {
case "$1" in ''|0|0*|*[!0-9]*) return 1 ;; esac
[ "${#1}" -le 9 ] 2>/dev/null
}
validate_preset_file() {
local preset_file="$1" logical_name="$2" candidate_name line cr size
local in_profiles=0 profile_open=0 profile_name=0 profile_filter=0 profile_strategy=0 profile_skip=0
local profiles=0 lua_count=0 blob_count=0 raw option blob_name
local capture_tcp_out= capture_tcp_in= capture_udp_out= capture_udp_in=
local seen_capture_tcp_out=0 seen_capture_tcp_in=0 seen_capture_udp_out=0 seen_capture_udp_in=0
local declared_blobs='|fake_default_http|fake_default_quic|fake_default_tls|'
PRESET_VALIDATION_CODE=OK
PRESET_VALIDATION_DETAIL=
is_safe_preset_file_name "$logical_name" || {
preset_validation_fail UNSAFE_PRESET_NAME "$logical_name"; return 1;
}
case "$preset_file" in
"$PRESETS_DIR"/*) candidate_name="${preset_file#"$PRESETS_DIR"/}" ;;
*) preset_validation_fail PRESET_NOT_DIRECT_CHILD "$preset_file"; return 1 ;;
esac
case "$candidate_name" in ''|*/*|*\\*) preset_validation_fail PRESET_NOT_DIRECT_CHILD "$preset_file"; return 1 ;; esac
[ ! -L "$preset_file" ] || { preset_validation_fail PRESET_SYMLINK "$logical_name"; return 1; }
[ -f "$preset_file" ] || { preset_validation_fail PRESET_MISSING "$logical_name"; return 1; }
[ -s "$preset_file" ] || { preset_validation_fail PRESET_EMPTY "$logical_name"; return 1; }
[ -r "$preset_file" ] || { preset_validation_fail PRESET_UNREADABLE "$logical_name"; return 1; }
size="$(wc -c < "$preset_file" 2>/dev/null)" || {
preset_validation_fail PRESET_UNREADABLE "$logical_name"; return 1;
}
case "$size" in ''|*[!0-9]*) preset_validation_fail PRESET_UNREADABLE "$logical_name"; return 1 ;; esac
[ "$size" -le "$PRESET_MAX_BYTES" ] 2>/dev/null || {
preset_validation_fail PRESET_TOO_LARGE "$logical_name"; return 1;
}
cr="$(printf '\r')"
while IFS= read -r line || [ -n "$line" ]; do
line="${line%"$cr"}"
case "$line" in
'# NFQWS2_TCP_PKT_OUT='*)
[ "$in_profiles" -eq 0 ] && [ "$seen_capture_tcp_out" -eq 0 ] || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
capture_tcp_out="${line#*=}"
validate_capture_packet_count "$capture_tcp_out" || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
seen_capture_tcp_out=1
continue
;;
'# NFQWS2_TCP_PKT_IN='*)
[ "$in_profiles" -eq 0 ] && [ "$seen_capture_tcp_in" -eq 0 ] || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
capture_tcp_in="${line#*=}"
validate_capture_packet_count "$capture_tcp_in" || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
seen_capture_tcp_in=1
continue
;;
'# NFQWS2_UDP_PKT_OUT='*)
[ "$in_profiles" -eq 0 ] && [ "$seen_capture_udp_out" -eq 0 ] || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
capture_udp_out="${line#*=}"
validate_capture_packet_count "$capture_udp_out" || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
seen_capture_udp_out=1
continue
;;
'# NFQWS2_UDP_PKT_IN='*)
[ "$in_profiles" -eq 0 ] && [ "$seen_capture_udp_in" -eq 0 ] || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
capture_udp_in="${line#*=}"
validate_capture_packet_count "$capture_udp_in" || {
preset_validation_fail INVALID_CAPTURE_POLICY "$logical_name"; return 1;
}
seen_capture_udp_in=1
continue
;;
''|'#'*|';'*) continue ;;
esac
case "$line" in *[[:cntrl:]]*) preset_validation_fail UNSAFE_OPTION_VALUE "$logical_name"; return 1 ;; esac
case "$line" in --ipcache*) preset_validation_fail FORBIDDEN_IPCACHE_OPTION "$logical_name"; return 1 ;; esac
case "$line" in
--lua-init=*)
[ "$in_profiles" -eq 0 ] || { preset_validation_fail GLOBAL_OPTION_AFTER_PROFILE "$logical_name"; return 1; }
raw="${line#--lua-init=}"
validate_preset_dependency lua "$raw" || return 1
lua_count=$((lua_count + 1))
;;
--blob=*)
[ "$in_profiles" -eq 0 ] || { preset_validation_fail GLOBAL_OPTION_AFTER_PROFILE "$logical_name"; return 1; }
raw="${line#--blob=}"
blob_name="${raw%%:*}"
case "$blob_name" in ''|*[!A-Za-z0-9_.-]*) preset_validation_fail INVALID_BLOB "$logical_name"; return 1 ;; esac
case "$declared_blobs" in
*"|$blob_name|"*) preset_validation_fail INVALID_BLOB "$logical_name"; return 1 ;;
esac
case "$raw" in
*:@bin/*) validate_preset_dependency blob "${raw##*:}" || return 1 ;;
*:0x*) ;;
*) preset_validation_fail INVALID_BLOB "$logical_name"; return 1 ;;
esac
declared_blobs="$declared_blobs$blob_name|"
blob_count=$((blob_count + 1))
;;
--ctrack-disable=*)
[ "$in_profiles" -eq 0 ] || { preset_validation_fail GLOBAL_OPTION_AFTER_PROFILE "$logical_name"; return 1; }
case "${line#*=}" in 0|1) ;; *) preset_validation_fail INVALID_OPTION_VALUE "$logical_name"; return 1 ;; esac
;;
--name=*)
[ "$profile_open" -eq 0 ] || { preset_validation_fail PROFILE_DUPLICATE_NAME "$logical_name"; return 1; }
[ -n "${line#--name=}" ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
in_profiles=1; profile_open=1; profile_name=1
;;
--skip)
[ "$profile_open" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
[ "$profile_skip" -eq 0 ] || { preset_validation_fail PROFILE_DUPLICATE_SKIP "$logical_name"; return 1; }
profile_skip=1
;;
--filter-tcp=*|--filter-udp=*)
[ "$profile_open" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
validate_filter_ports "${line#*=}" || { preset_validation_fail INVALID_FILTER "$logical_name"; return 1; }
profile_filter=$((profile_filter + 1))
;;
--filter-l7=*)
[ "$profile_open" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
validate_l7_filter "${line#*=}" || { preset_validation_fail INVALID_FILTER "$logical_name"; return 1; }
profile_filter=$((profile_filter + 1))
;;
--filter-l3=*)
[ "$profile_open" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
case "${line#*=}" in ipv4|ipv6|ipv4,ipv6|ipv6,ipv4) ;; *) preset_validation_fail INVALID_FILTER "$logical_name"; return 1 ;; esac
;;
--hostlist=*|--hostlist-exclude=*|--ipset=*|--ipset-exclude=*)
[ "$profile_open" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
option="${line%%=*}"; raw="${line#*=}"
validate_preset_dependency list "$raw" || return 1
;;
--hostlist-domains=*|--out-range=*|--payload=*)
[ "$profile_open" -eq 1 ] && [ -n "${line#*=}" ] || {
preset_validation_fail INVALID_OPTION_VALUE "$logical_name"; return 1;
}
;;
--lua-desync=*)
[ "$profile_open" -eq 1 ] && [ -n "${line#*=}" ] || {
preset_validation_fail PROFILE_STRATEGY_MISSING "$logical_name"; return 1;
}
validate_strategy_blob_references "$line" || return 1
profile_strategy=$((profile_strategy + 1))
;;
--new)
[ "$profile_open" -eq 1 ] || { preset_validation_fail EMPTY_PROFILE "$logical_name"; return 1; }
[ "$profile_name" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
[ "$profile_filter" -gt 0 ] || { preset_validation_fail PROFILE_FILTER_MISSING "$logical_name"; return 1; }
[ "$profile_strategy" -gt 0 ] || { preset_validation_fail PROFILE_STRATEGY_MISSING "$logical_name"; return 1; }
profiles=$((profiles + 1)); profile_open=0; profile_name=0; profile_filter=0; profile_strategy=0; profile_skip=0
;;
--wf-*|*windivert*) preset_validation_fail WINDOWS_OPTION_FORBIDDEN "$logical_name"; return 1 ;;
*) preset_validation_fail UNKNOWN_OPTION "$logical_name"; return 1 ;;
esac
done < "$preset_file"
[ "$profile_open" -eq 1 ] || { preset_validation_fail TRAILING_NEW "$logical_name"; return 1; }
[ "$profile_name" -eq 1 ] || { preset_validation_fail PROFILE_NAME_MISSING "$logical_name"; return 1; }
[ "$profile_filter" -gt 0 ] || { preset_validation_fail PROFILE_FILTER_MISSING "$logical_name"; return 1; }
[ "$profile_strategy" -gt 0 ] || { preset_validation_fail PROFILE_STRATEGY_MISSING "$logical_name"; return 1; }
profiles=$((profiles + 1))
[ "$profiles" -gt 0 ] && [ "$lua_count" -gt 0 ] && [ "$blob_count" -gt 0 ] || {
preset_validation_fail NO_VALID_OPTIONS "$logical_name"; return 1;
}
[ "$seen_capture_tcp_out$seen_capture_tcp_in$seen_capture_udp_out$seen_capture_udp_in" = 1111 ] || {
preset_validation_fail CAPTURE_POLICY_MISSING "$logical_name"; return 1;
}
COMPILED_TCP_PKT_OUT="$capture_tcp_out"
COMPILED_TCP_PKT_IN="$capture_tcp_in"
COMPILED_UDP_PKT_OUT="$capture_udp_out"
COMPILED_UDP_PKT_IN="$capture_udp_in"
}
collect_capture_ports() {
# The port union is two short lines, so it is carried in shell variables
# instead of a scratch file: a file here would need its own symlink and
# existence guards, and the awk output never justified that surface.
local preset_file="$1" captured rest newline
newline='
'
captured="$(awk '
function add_interval(family, first, last) {
if (family == "tcp") {
tcp_count++; tcp_first[tcp_count]=first+0; tcp_last[tcp_count]=last+0
} else {
udp_count++; udp_first[udp_count]=first+0; udp_last[udp_count]=last+0
}
}
function add_list(family, list, count, values, i, token, parts, pair) {
count=split(list, values, ",")
for (i=1; i<=count; i++) {
token=values[i]
if (token == "*") { add_interval(family, 1, 65535); continue }
gsub(/-/, ":", token)
parts=split(token, pair, ":")
if (parts == 1) add_interval(family, pair[1], pair[1])
else add_interval(family, pair[1], pair[2])
}
}
function flush_profile() {
if (!profile_skip) {
if (profile_tcp != "") add_list("tcp", profile_tcp)
if (profile_udp != "") add_list("udp", profile_udp)
if (profile_voice) add_list("udp", "3478,5349,19302")
}
profile_skip=0; profile_tcp=""; profile_udp=""; profile_voice=0
}
function normalize(first, last, count, i, j, swap, out, have, lo, hi, token) {
for (i=1; i<=count; i++) for (j=i+1; j<=count; j++)
if (first[j] < first[i] || (first[j] == first[i] && last[j] < last[i])) {
swap=first[i]; first[i]=first[j]; first[j]=swap
swap=last[i]; last[i]=last[j]; last[j]=swap
}
out=""; have=0
for (i=1; i<=count; i++) {
if (!have) { lo=first[i]; hi=last[i]; have=1; continue }
if (first[i] <= hi+1) {
if (last[i] > hi) hi=last[i]
continue
}
token=(lo == hi ? lo : lo ":" hi)
out=out (out == "" ? "" : ",") token
lo=first[i]; hi=last[i]
}
if (have) {
token=(lo == hi ? lo : lo ":" hi)
out=out (out == "" ? "" : ",") token
}
return out
}
{
sub(/\r$/, "")
if ($0 == "--new") { flush_profile(); next }
if ($0 == "--skip") { profile_skip=1; next }
if ($0 ~ /^--filter-tcp=/) {
value=substr($0, length("--filter-tcp=") + 1)
profile_tcp=profile_tcp (profile_tcp == "" ? "" : ",") value
next
}
if ($0 ~ /^--filter-udp=/) {
value=substr($0, length("--filter-udp=") + 1)
profile_udp=profile_udp (profile_udp == "" ? "" : ",") value
next
}
if ($0 == "--filter-l7=stun" || $0 == "--filter-l7=discord" ||
$0 == "--filter-l7=stun,discord" || $0 == "--filter-l7=discord,stun") {
profile_voice=1
}
}
END {
flush_profile()
# Key each line so an empty union stays distinguishable after
# command substitution strips trailing newlines.
print "tcp=" normalize(tcp_first, tcp_last, tcp_count)
print "udp=" normalize(udp_first, udp_last, udp_count)
}
' "$preset_file")" || return 1
case "$captured" in
"tcp="*"$newline""udp="*) ;;
*) return 1 ;;
esac
rest="${captured#*"$newline"}"
case "$rest" in *"$newline"*) return 1 ;; esac
COMPILED_TCP_PORTS="${captured%%"$newline"*}"
COMPILED_TCP_PORTS="${COMPILED_TCP_PORTS#tcp=}"
COMPILED_UDP_PORTS="${rest#udp=}"
[ -n "$COMPILED_TCP_PORTS$COMPILED_UDP_PORTS" ] || {
preset_validation_fail NO_ENABLED_PROFILE
return 1
}
}
compile_preset_artifact() {
local preset_file="$1" logical_name="$2" artifact="$3" tmp source_sha runtime_sha size
# Retire any previous artifact's metadata proof first: an early failure
# here must not leave a stale proof that lets a later run_compiled_artifact
# skip its own authentication.
COMPILED_METADATA_FOR=""
validate_preset_file "$preset_file" "$logical_name" || return 1
collect_capture_ports "$preset_file" || return 1
source_sha="$(sha256sum "$preset_file" 2>/dev/null)" || return 1
source_sha="${source_sha%% *}"
case "$source_sha" in [0-9a-f][0-9a-f]*) [ "${#source_sha}" -eq 64 ] || return 1 ;; *) return 1 ;; esac
runtime_sha="$(sha256sum "$RUNTIME_CONFIG" 2>/dev/null)" || return 1
runtime_sha="${runtime_sha%% *}"
case "$runtime_sha" in [0-9a-f][0-9a-f]*) [ "${#runtime_sha}" -eq 64 ] || return 1 ;; *) return 1 ;; esac
tmp="$artifact.tmp.$$"
[ ! -e "$tmp" ] && [ ! -L "$tmp" ] || return 1
umask 077
{
printf 'Z2_ARGV\t2\n'
printf 'PRESET\t%s\nSHA256\t%s\nRUNTIME_SHA256\t%s\nTCP\t%s\nUDP\t%s\n' \
"$logical_name" "$source_sha" "$runtime_sha" "$COMPILED_TCP_PORTS" "$COMPILED_UDP_PORTS"
printf 'TCP_PKT_OUT\t%s\nTCP_PKT_IN\t%s\nUDP_PKT_OUT\t%s\nUDP_PKT_IN\t%s\nARGS\n' \
"$COMPILED_TCP_PKT_OUT" "$COMPILED_TCP_PKT_IN" \
"$COMPILED_UDP_PKT_OUT" "$COMPILED_UDP_PKT_IN"
printf '%s\n' "--qnum=${QNUM:-200}" "--fwmark=${DESYNC_MARK:-0x40000000}" "--uid=${NFQWS_UID:-0:0}"
case "${LOG_MODE:-none}" in
android) printf '%s\n' '--debug=android' ;;
file) printf '%s\n' "--debug=@${DEBUG_LOG}" ;;
syslog) printf '%s\n' '--debug=syslog' ;;
none) ;;
*) return 1 ;;
esac
awk \
-v lua_prefix="$ZAPRET_DIR/lua/" \
-v bin_prefix="$ZAPRET_DIR/bin/" \
-v lists_prefix="$LISTS_DIR/" '
{
sub(/\r$/, "")
if ($0 == "" || $0 ~ /^[#;]/) next
if ($0 ~ /^--lua-init=@lua\//) {
sub(/^--lua-init=@lua\//, "--lua-init=@" lua_prefix)
} else if ($0 ~ /^--blob=.*:@bin\//) {
sub(/:@bin\//, ":@" bin_prefix)
} else if ($0 ~ /^--(hostlist|hostlist-exclude|ipset|ipset-exclude)=lists\//) {
sub(/=lists\//, "=" lists_prefix)
}
print
}
' "$preset_file"
} > "$tmp" || { rm -f "$tmp"; return 1; }
size="$(wc -c < "$tmp" 2>/dev/null)" || { rm -f "$tmp"; return 1; }
case "$size" in ''|*[!0-9]*) rm -f "$tmp"; return 1 ;; esac
[ "$size" -gt 0 ] && [ "$size" -le "$COMPILED_ARGV_MAX_BYTES" ] || { rm -f "$tmp"; return 1; }
chmod 0600 "$tmp" 2>/dev/null || { rm -f "$tmp"; return 1; }
mv -f "$tmp" "$artifact" || { rm -f "$tmp"; return 1; }
COMPILED_ARGV_FILE="$artifact"
# The compiler is now the authority for every metadata field the artifact
# carries; publishing them here lets callers skip a full re-parse.
COMPILED_PRESET="$logical_name"
COMPILED_SOURCE_SHA256="$source_sha"
COMPILED_RUNTIME_SHA256="$runtime_sha"
COMPILED_METADATA_FOR="$artifact"
}
compiled_artifact_binding_current() {
local artifact="$1" preset_file="$2" logical_name="$3"
local current_source_sha current_runtime_sha
read_compiled_artifact_metadata "$artifact" || return 1
[ "$COMPILED_PRESET" = "$logical_name" ] || return 1
current_source_sha="$(sha256sum "$preset_file" 2>/dev/null)" || return 1
current_source_sha="${current_source_sha%% *}"
[ "$current_source_sha" = "$COMPILED_SOURCE_SHA256" ] || return 1
current_runtime_sha="$(sha256sum "$RUNTIME_CONFIG" 2>/dev/null)" || return 1
current_runtime_sha="${current_runtime_sha%% *}"
[ "$current_runtime_sha" = "$COMPILED_RUNTIME_SHA256" ]
}
COMPILED_VALIDATION_RECEIPT_VERSION=1
read_compiled_validation_receipt() {
local path="${1:-$COMPILED_VALIDATION_RECEIPT}" size extra
local version_line generation_line archive_line argv_line
VALIDATED_INSTALL_GENERATION=
VALIDATED_INSTALL_ARCHIVE_SHA256=
VALIDATED_ARGV_SHA256=
path_meta_capture "$path"
if state_file_is_secure "$path" && path_mode_is_0600 "$path" &&
path_nlink_is_one "$path" && path_meta_size_read "$path"; then
size="$Z2_PATH_SIZE"
path_meta_retire
else
path_meta_retire
return 1
fi
is_decimal "$size" && [ "$size" -gt 0 ] 2>/dev/null &&
[ "$size" -le 1024 ] 2>/dev/null || return 1
{
IFS= read -r version_line &&
IFS= read -r generation_line &&
IFS= read -r archive_line &&
IFS= read -r argv_line
if IFS= read -r extra; then return 1; fi
} < "$path" || return 1
[ "$version_line" = "version=$COMPILED_VALIDATION_RECEIPT_VERSION" ] || return 1
case "$generation_line" in install_generation=*) ;; *) return 1 ;; esac
case "$archive_line" in install_archive_sha256=*) ;; *) return 1 ;; esac
case "$argv_line" in argv_sha256=*) ;; *) return 1 ;; esac
VALIDATED_INSTALL_GENERATION="${generation_line#*=}"
VALIDATED_INSTALL_ARCHIVE_SHA256="${archive_line#*=}"
VALIDATED_ARGV_SHA256="${argv_line#*=}"
is_safe_token "$VALIDATED_INSTALL_GENERATION" &&
is_lower_sha256 "$VALIDATED_INSTALL_ARCHIVE_SHA256" &&
is_lower_sha256 "$VALIDATED_ARGV_SHA256"
}
compiled_validation_receipt_current() {
local artifact="$1" argv_sha256
read_install_generation_meta || return 1
read_compiled_validation_receipt || return 1
[ "$VALIDATED_INSTALL_GENERATION" = "$INSTALL_META_GENERATION" ] &&
[ "$VALIDATED_INSTALL_ARCHIVE_SHA256" = "$INSTALL_META_ARCHIVE_SHA256" ] ||
return 1
argv_sha256="$(sha256sum "$artifact" 2>/dev/null)" || return 1
argv_sha256="${argv_sha256%% *}"
[ "$argv_sha256" = "$VALIDATED_ARGV_SHA256" ]
}
write_compiled_validation_receipt() {
local artifact="$1" argv_sha256 tmp="$COMPILED_VALIDATION_RECEIPT.tmp.$$"
read_install_generation_meta || return 1
argv_sha256="$(sha256sum "$artifact" 2>/dev/null)" || return 1
argv_sha256="${argv_sha256%% *}"
is_lower_sha256 "$argv_sha256" || return 1
state_file_target_is_safe "$COMPILED_VALIDATION_RECEIPT" || return 1
state_path_is_managed_file "$tmp" || return 1
[ ! -e "$tmp" ] && [ ! -L "$tmp" ] || return 1
umask 077
{
printf 'version=%s\n' "$COMPILED_VALIDATION_RECEIPT_VERSION"
printf 'install_generation=%s\n' "$INSTALL_META_GENERATION"
printf 'install_archive_sha256=%s\n' "$INSTALL_META_ARCHIVE_SHA256"
printf 'argv_sha256=%s\n' "$argv_sha256"
} > "$tmp" || { rm -f "$tmp"; return 1; }
chmod 0600 "$tmp" 2>/dev/null &&
mv -f "$tmp" "$COMPILED_VALIDATION_RECEIPT" || {
rm -f "$tmp"
return 1
}
}
ensure_compiled_artifact() {
local preset_file="$1" logical_name="$2" artifact="$3"
if compiled_artifact_binding_current "$artifact" "$preset_file" "$logical_name"; then
COMPILED_ARGV_FILE="$artifact"
return 0
fi
compile_preset_artifact "$preset_file" "$logical_name" "$artifact"
}
read_compiled_artifact_metadata() {
local artifact="$1" line stage=0 seen_preset=0 seen_sha=0 seen_runtime_sha=0 seen_tcp=0 seen_udp=0
local seen_tcp_out=0 seen_tcp_in=0 seen_udp_out=0 seen_udp_in=0 size tab key value
COMPILED_METADATA_FOR=""
COMPILED_PRESET=; COMPILED_SOURCE_SHA256=; COMPILED_RUNTIME_SHA256=; COMPILED_TCP_PORTS=; COMPILED_UDP_PORTS=
COMPILED_TCP_PKT_OUT=; COMPILED_TCP_PKT_IN=; COMPILED_UDP_PKT_OUT=; COMPILED_UDP_PKT_IN=
[ -f "$artifact" ] && [ ! -L "$artifact" ] && [ -r "$artifact" ] || return 1
size="$(wc -c < "$artifact" 2>/dev/null)" || return 1
case "$size" in ''|*[!0-9]*) return 1 ;; esac
[ "$size" -gt 0 ] && [ "$size" -le "$COMPILED_ARGV_MAX_BYTES" ] || return 1
tab=' '
while IFS= read -r line || [ -n "$line" ]; do
if [ "$stage" -eq 0 ]; then
[ "$line" = "Z2_ARGV${tab}2" ] || return 1
stage=1
continue
fi
if [ "$stage" -eq 1 ]; then
[ "$line" != ARGS ] || { stage=2; continue; }
case "$line" in *"$tab"*) ;; *) return 1 ;; esac
key="${line%%"$tab"*}"; value="${line#*"$tab"}"
case "$key" in
PRESET) [ "$seen_preset" -eq 0 ] || return 1; COMPILED_PRESET="$value"; seen_preset=1 ;;
SHA256) [ "$seen_sha" -eq 0 ] || return 1; COMPILED_SOURCE_SHA256="$value"; seen_sha=1 ;;
RUNTIME_SHA256) [ "$seen_runtime_sha" -eq 0 ] || return 1; COMPILED_RUNTIME_SHA256="$value"; seen_runtime_sha=1 ;;
TCP) [ "$seen_tcp" -eq 0 ] || return 1; COMPILED_TCP_PORTS="$value"; seen_tcp=1 ;;
UDP) [ "$seen_udp" -eq 0 ] || return 1; COMPILED_UDP_PORTS="$value"; seen_udp=1 ;;
TCP_PKT_OUT) [ "$seen_tcp_out" -eq 0 ] || return 1; COMPILED_TCP_PKT_OUT="$value"; seen_tcp_out=1 ;;
TCP_PKT_IN) [ "$seen_tcp_in" -eq 0 ] || return 1; COMPILED_TCP_PKT_IN="$value"; seen_tcp_in=1 ;;
UDP_PKT_OUT) [ "$seen_udp_out" -eq 0 ] || return 1; COMPILED_UDP_PKT_OUT="$value"; seen_udp_out=1 ;;
UDP_PKT_IN) [ "$seen_udp_in" -eq 0 ] || return 1; COMPILED_UDP_PKT_IN="$value"; seen_udp_in=1 ;;
*) return 1 ;;
esac
continue
fi
case "$line" in --*) ;; *) return 1 ;; esac
done < "$artifact"
[ "$stage" -eq 2 ] &&
[ "$seen_preset$seen_sha$seen_runtime_sha$seen_tcp$seen_udp$seen_tcp_out$seen_tcp_in$seen_udp_out$seen_udp_in" = 111111111 ] ||
return 1
is_safe_preset_file_name "$COMPILED_PRESET" || return 1
case "$COMPILED_SOURCE_SHA256" in *[!0-9a-f]*|'') return 1 ;; esac
[ "${#COMPILED_SOURCE_SHA256}" -eq 64 ] || return 1
case "$COMPILED_RUNTIME_SHA256" in *[!0-9a-f]*|'') return 1 ;; esac
[ "${#COMPILED_RUNTIME_SHA256}" -eq 64 ] || return 1
[ -z "$COMPILED_TCP_PORTS" ] ||
validate_filter_ports "$COMPILED_TCP_PORTS" || return 1
[ -z "$COMPILED_UDP_PORTS" ] ||
validate_filter_ports "$COMPILED_UDP_PORTS" || return 1
[ -n "$COMPILED_TCP_PORTS$COMPILED_UDP_PORTS" ] || return 1
validate_capture_packet_count "$COMPILED_TCP_PKT_OUT" || return 1
validate_capture_packet_count "$COMPILED_TCP_PKT_IN" || return 1
validate_capture_packet_count "$COMPILED_UDP_PKT_OUT" || return 1
validate_capture_packet_count "$COMPILED_UDP_PKT_IN" || return 1
COMPILED_METADATA_FOR="$artifact"
}
run_compiled_artifact() {
local artifact="$1" mode="$2" line in_args=0
# Every launch path has already authenticated this exact artifact via a
# binding or metadata read in the same process; re-parse only when that
# proof is missing. The argv loop below still validates each line.
[ "${COMPILED_METADATA_FOR:-}" = "$artifact" ] ||
read_compiled_artifact_metadata "$artifact" || return 1
set --
while IFS= read -r line || [ -n "$line" ]; do
if [ "$in_args" -eq 0 ]; then [ "$line" != ARGS ] || in_args=1; continue; fi
case "$line" in
--ipcache*) return 1 ;;
--*) set -- "$@" "$line" ;;
*) return 1 ;;
esac
done < "$artifact"
[ "$#" -gt 3 ] || return 1
case "$mode" in
dry-run) "$NFQWS2" --dry-run "$@" ;;
foreground) "$NFQWS2" "$@" ;;
daemon)
[ -n "${PIDFILE:-}" ] || return 1
"$NFQWS2" --daemon "--pidfile=$PIDFILE" "$@" >/dev/null 2>&1 &
LAUNCHED_PID=$!
;;
background)
"$NFQWS2" "$@" >/dev/null 2>&1 &
LAUNCHED_PID=$!
;;
*) return 1 ;;
esac
}
preview_compiled_artifact_machine() {
local artifact="$1" logical_name="$2" line in_args=0 count=0
read_compiled_artifact_metadata "$artifact" || return 1
[ "$COMPILED_PRESET" = "$logical_name" ] || return 1
printf 'Z2_COMMAND_PREVIEW\t2\t%s\tTCP=%s\tUDP=%s\tTCP_OUT=%s\tTCP_IN=%s\tUDP_OUT=%s\tUDP_IN=%s\n' \
"$logical_name" "$COMPILED_TCP_PORTS" "$COMPILED_UDP_PORTS" \
"$COMPILED_TCP_PKT_OUT" "$COMPILED_TCP_PKT_IN" \
"$COMPILED_UDP_PKT_OUT" "$COMPILED_UDP_PKT_IN"
printf 'Z2_COMMAND_EXECUTABLE\t%s\n' "$NFQWS2"
# Preview is a pure projection of the packaged launcher contract. Runtime
# capability checks and binary execution belong to preflight/start.
printf 'Z2_COMMAND_ARGUMENT\t--daemon\n'
printf 'Z2_COMMAND_ARGUMENT\t--pidfile=%s\n' "$PIDFILE"
count=2
while IFS= read -r line || [ -n "$line" ]; do
if [ "$in_args" -eq 0 ]; then
[ "$line" != ARGS ] || in_args=1
continue
fi
case "$line" in --*) ;; *) return 1 ;; esac
printf 'Z2_COMMAND_ARGUMENT\t%s\n' "$line"
count=$((count + 1))
done < "$artifact"
[ "$count" -gt 3 ] || return 1
printf 'Z2_COMMAND_SUMMARY\t1\tcount=%s\n' "$count"
}
scan_presets_machine() {
local preset_file preset_name valid=0 quarantined=0 total=0
[ -d "$PRESETS_DIR" ] && [ ! -L "$PRESETS_DIR" ] || {
printf 'Z2_PRESET_ERROR\tPRESET_CATALOG_MISSING\n'; return 2;
}
for preset_file in "$PRESETS_DIR"/*.txt; do
[ -e "$preset_file" ] || [ -L "$preset_file" ] || continue
preset_name="${preset_file##*/}"
case "$preset_name" in _*) continue ;; esac
total=$((total + 1))
if validate_preset_file "$preset_file" "$preset_name"; then
valid=$((valid + 1)); printf 'Z2_PRESET\tVALID\tOK\t%s\n' "$preset_name"
else
quarantined=$((quarantined + 1)); printf 'Z2_PRESET\tQUARANTINED\t%s\t%s\n' "$PRESET_VALIDATION_CODE" "$preset_name"
fi
done
printf 'Z2_PRESET_SUMMARY\t1\tvalid=%s\tquarantined=%s\ttotal=%s\n' "$valid" "$quarantined" "$total"
}
# Runtime discovery is deliberately not package qualification. Published
# presets were exhaustively qualified before release, and app-authored changes
# are qualified before their atomic replacement. Listing therefore performs
# only bounded directory-entry checks; the deep scanner remains a release/CI
# boundary and must never occupy the APK's shared root transport.
list_presets_machine() {
local preset_file preset_name ready=0 quarantined=0 total=0 reason
[ -d "$PRESETS_DIR" ] && [ ! -L "$PRESETS_DIR" ] || {
printf 'Z2_PRESET_ERROR\tPRESET_CATALOG_MISSING\n'; return 2;
}
for preset_file in "$PRESETS_DIR"/*.txt; do
[ -e "$preset_file" ] || [ -L "$preset_file" ] || continue
preset_name="${preset_file##*/}"
case "$preset_name" in _*) continue ;; esac
# Unsafe names are not representable in the app protocol and remain
# invisible rather than invalidating the complete trusted catalog.
is_safe_preset_file_name "$preset_name" || continue
total=$((total + 1))
reason=
if [ -L "$preset_file" ]; then
reason=PRESET_SYMLINK
elif [ ! -f "$preset_file" ]; then
reason=PRESET_MISSING
elif [ ! -s "$preset_file" ]; then
reason=PRESET_EMPTY
elif [ ! -r "$preset_file" ]; then
reason=PRESET_UNREADABLE
fi
if [ -z "$reason" ]; then
ready=$((ready + 1))
printf 'Z2_PRESET\tREADY\tOK\t%s\n' "$preset_name"
else
quarantined=$((quarantined + 1))
printf 'Z2_PRESET\tQUARANTINED\t%s\t%s\n' "$reason" "$preset_name"
fi
done
printf 'Z2_PRESET_SUMMARY\t2\tready=%s\tquarantined=%s\ttotal=%s\n' \
"$ready" "$quarantined" "$total"
}
validate_preset_machine() {
if validate_preset_file "$1" "$2"; then
printf 'Z2_PRESET_VALIDATION\t1\tOK\t%s\n' "$2"; return 0
fi
printf 'Z2_PRESET_VALIDATION\t0\t%s\t%s\n' "$PRESET_VALIDATION_CODE" "$2"; return 1
}
validate_strategy_catalog_file() {
local file="$1" line cr size section= seen='|' names=0 authors=0 labels=0 descriptions=0 blobs=0 strategies=0
[ -f "$file" ] && [ ! -L "$file" ] && [ -s "$file" ] && [ -r "$file" ] || return 1
size="$(wc -c < "$file" 2>/dev/null)" || return 1
case "$size" in ''|*[!0-9]*) return 1 ;; esac
[ "$size" -le "$STRATEGY_CATALOG_MAX_BYTES" ] || return 1
cr="$(printf '\r')"
while IFS= read -r line || [ -n "$line" ]; do
line="${line%"$cr"}"
case "$line" in ''|'#'*|';'*) continue ;; esac
case "$line" in
'['*']')
[ -z "$section" ] || {
[ "$names" -eq 1 ] && [ "$authors" -le 1 ] && [ "$labels" -le 1 ] &&
[ "$descriptions" -le 1 ] && [ "$blobs" -le 1 ] && [ "$strategies" -gt 0 ] || return 1
}
section="${line#[}"; section="${section%]}"
case "$section" in ''|*[!A-Za-z0-9_.-]*) return 1 ;; esac
case "$seen" in *"|$section|"*) return 1 ;; esac
seen="$seen$section|"; names=0; authors=0; labels=0; descriptions=0; blobs=0; strategies=0
;;
'name = '*) [ -n "$section" ] && [ -n "${line#name = }" ] || return 1; names=$((names + 1)) ;;
'author = '*) [ -n "$section" ] && [ -n "${line#author = }" ] || return 1; authors=$((authors + 1)) ;;
'label = '*) [ -n "$section" ] && [ -n "${line#label = }" ] || return 1; labels=$((labels + 1)) ;;
'description = '*) [ -n "$section" ] && [ -n "${line#description = }" ] || return 1; descriptions=$((descriptions + 1)) ;;
'blobs = '*)
[ -n "$section" ] && [ -n "${line#blobs = }" ] || return 1
validate_strategy_blob_list "${line#blobs = }" || return 1
blobs=$((blobs + 1))
;;
--lua-desync=*) [ -n "$section" ] && [ -n "${line#*=}" ] || return 1; case "$line" in *--ipcache*) return 1 ;; esac; strategies=$((strategies + 1)) ;;
*) return 1 ;;
esac
done < "$file"
[ -n "$section" ] && [ "$names" -eq 1 ] && [ "$authors" -le 1 ] && [ "$labels" -le 1 ] &&
[ "$descriptions" -le 1 ] && [ "$blobs" -le 1 ] && [ "$strategies" -gt 0 ]
}
# Strategy catalogs contain hundreds of sections. Keep this validation in the
# current shell: a grep process for every `blobs =` row takes tens of seconds
# on process-heavy Android devices and blocks every other root-backed screen.
validate_strategy_blob_list() {
local remaining="$1" item
case "$remaining" in ''|,*|*,|*,,*) return 1 ;; esac
trim_config_value_in_place "$remaining"
[ "$CONFIG_VALUE_TRIMMED" = "$remaining" ] || return 1
while [ -n "$remaining" ]; do
item="${remaining%%,*}"
case "$remaining" in *','*) remaining="${remaining#*,}" ;; *) remaining="" ;; esac
trim_config_value_in_place "$item"
item="$CONFIG_VALUE_TRIMMED"
case "$item" in ''|*[!A-Za-z0-9_.-]*) return 1 ;; esac
done
return 0
}
validate_strategy_catalogs_machine() {
local catalog
for catalog in tcp udp voice http80; do
validate_strategy_catalog_file "$ZAPRET_DIR/strategy-catalogs/$catalog.txt" || return 1
done
}
if [ "$COMMAND_BUILDER_CLI_MODE" -eq 1 ]; then
case "$1" in
--list-presets-machine)
[ "$#" -eq 2 ] || { printf 'Z2_PRESET_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
list_presets_machine; exit $?
;;
--scan-presets-machine)
[ "$#" -eq 2 ] || { printf 'Z2_PRESET_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
scan_presets_machine; exit $?
;;
--validate-preset-machine)
[ "$#" -eq 4 ] || { printf 'Z2_PRESET_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
validate_preset_machine "$3" "$4"; exit $?
;;
--preflight-preset-machine)
[ "$#" -eq 4 ] || { printf 'Z2_PRESET_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
load_effective_core_config_readonly || { printf 'Z2_PRESET_ERROR\tRUNTIME_UNAVAILABLE\n'; exit 2; }
ensure_state_tmp_dir || { printf 'Z2_PRESET_ERROR\tRUNTIME_UNAVAILABLE\n'; exit 2; }
artifact="${Z2_STATE_TMP}/preset-preflight.$$"
if compile_preset_artifact "$3" "$4" "$artifact" && run_compiled_artifact "$artifact" dry-run >/dev/null 2>&1; then
rm -f "$artifact"; printf 'Z2_PRESET_VALIDATION\t1\tOK\t%s\n' "$4"; exit 0
fi
[ "$PRESET_VALIDATION_CODE" != OK ] || PRESET_VALIDATION_CODE=NFQWS_DRY_RUN_FAILED
rm -f "$artifact"; printf 'Z2_PRESET_VALIDATION\t0\t%s\t%s\n' "$PRESET_VALIDATION_CODE" "$4"; exit 1
;;
--preview-preset-machine)
[ "$#" -eq 4 ] || { printf 'Z2_PRESET_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
load_effective_core_config_readonly || { printf 'Z2_PRESET_ERROR\tRUNTIME_UNAVAILABLE\n'; exit 2; }
ensure_state_tmp_dir || { printf 'Z2_PRESET_ERROR\tUNSAFE_PREVIEW_TARGET\n'; exit 2; }
artifact="${Z2_STATE_TMP}/preset-preview.$$"
state_file_target_is_safe "$artifact" || { printf 'Z2_PRESET_ERROR\tUNSAFE_PREVIEW_TARGET\n'; exit 2; }
if compile_preset_artifact "$3" "$4" "$artifact" &&
preview_compiled_artifact_machine "$artifact" "$4"; then
rm -f "$artifact"; exit 0
fi
[ "$PRESET_VALIDATION_CODE" != OK ] || PRESET_VALIDATION_CODE=PREVIEW_FAILED
rm -f "$artifact"
printf 'Z2_COMMAND_PREVIEW\t0\t%s\t%s\n' "$PRESET_VALIDATION_CODE" "$4"
exit 1
;;
--validate-strategies-machine)
[ "$#" -eq 2 ] || { printf 'Z2_STRATEGIES_ERROR\tINVALID_ARGUMENTS\n'; exit 2; }
if validate_strategy_catalogs_machine; then printf 'Z2_STRATEGIES\tOK\n'; exit 0; fi
printf 'Z2_STRATEGIES_ERROR\tINVALID_CONFIGURATION\n'; exit 1
;;
esac
fi