#!/usr/bin/env bash if [[ -n ${IPF_STORAGE_SH_LOADED:-} ]]; then return 0 fi IPF_STORAGE_SH_LOADED=1 : "${IPF_STORAGE_DIR:=/var/lib/iptables-forward}" : "${IPF_STORAGE_DB:=${IPF_STORAGE_DIR}/rules.db}" : "${IPF_LOCK_FILE:=${IPF_STORAGE_DIR}/.lock}" storage_dir() { printf '%s\n' "${IPF_STORAGE_DIR}"; } storage_db_path() { printf '%s\n' "${IPF_STORAGE_DB}"; } storage_lock_path() { printf '%s\n' "${IPF_LOCK_FILE}"; } storage_init() { mkdir -p "${IPF_STORAGE_DIR}" touch "${IPF_STORAGE_DB}" "${IPF_LOCK_FILE}" chmod 750 "${IPF_STORAGE_DIR}" chmod 640 "${IPF_STORAGE_DB}" chmod 600 "${IPF_LOCK_FILE}" } storage_with_lock() { storage_init ( flock -x 9 "$@" ) 9>>"${IPF_LOCK_FILE}" } storage_add_unlocked() { local line=${1-} [[ -n ${line} ]] || return 1 storage_init printf '%s\n' "${line}" >>"${IPF_STORAGE_DB}" } storage_add() { storage_with_lock storage_add_unlocked "$@"; } storage_list() { [[ -f ${IPF_STORAGE_DB} ]] || return 0 cat "${IPF_STORAGE_DB}" } storage_parse() { local line=${1-} local key=${2-} local part IFS='|' read -r -a parts <<<"${line}" for part in "${parts[@]}"; do if [[ ${part} == "${key}="* ]]; then printf '%s\n' "${part#*=}" return 0 fi done return 1 } storage_get() { local uuid=${1-} local line current [[ -n ${uuid} ]] || return 1 while IFS= read -r line || [[ -n ${line} ]]; do current=$(storage_parse "${line}" uuid || true) if [[ ${current} == "${uuid}" ]]; then printf '%s\n' "${line}" return 0 fi done < <(storage_list) return 1 } storage_delete_unlocked() { local uuid=${1-} local tmp found=0 line current [[ -n ${uuid} ]] || return 1 storage_init tmp="${IPF_STORAGE_DB}.tmp.$$" : >"${tmp}" while IFS= read -r line || [[ -n ${line} ]]; do current=$(storage_parse "${line}" uuid || true) if [[ ${current} == "${uuid}" ]]; then found=1 continue fi printf '%s\n' "${line}" >>"${tmp}" done <"${IPF_STORAGE_DB}" (( found == 1 )) || { rm -f "${tmp}"; return 1; } mv "${tmp}" "${IPF_STORAGE_DB}" } storage_delete() { storage_with_lock storage_delete_unlocked "$@"; } storage_count() { local count=0 line while IFS= read -r line || [[ -n ${line} ]]; do [[ -n ${line} ]] || continue ((count += 1)) done < <(storage_list) printf '%s\n' "${count}" }