From af359b71b000651812e1ee70638b480502eba0ec Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Thu, 5 Apr 2018 22:05:05 +0200 Subject: media-server on odin --- custom/uucp-mediaserver.nix | 59 ++++++++++ custom/uucp-mediaserver/scripts.nix | 32 ++++++ custom/uucp-mediaserver/scripts/mediaspace | 9 ++ custom/uucp-mediaserver/scripts/queue | 134 +++++++++++++++++++++++ custom/uucp-mediaserver/scripts/queuesize | 24 ++++ custom/uucp-mediaserver/scripts/queuestatus | 41 +++++++ custom/uucp-mediaserver/scripts/update-queuesize | 10 ++ 7 files changed, 309 insertions(+) create mode 100644 custom/uucp-mediaserver.nix create mode 100644 custom/uucp-mediaserver/scripts.nix create mode 100755 custom/uucp-mediaserver/scripts/mediaspace create mode 100755 custom/uucp-mediaserver/scripts/queue create mode 100755 custom/uucp-mediaserver/scripts/queuesize create mode 100755 custom/uucp-mediaserver/scripts/queuestatus create mode 100755 custom/uucp-mediaserver/scripts/update-queuesize (limited to 'custom') diff --git a/custom/uucp-mediaserver.nix b/custom/uucp-mediaserver.nix new file mode 100644 index 00000000..a8af8bc6 --- /dev/null +++ b/custom/uucp-mediaserver.nix @@ -0,0 +1,59 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.uucp.media-server; + + touchStateFiles = name: '' + touch ${cfg.queueDir}/${name}.queue + touch ${cfg.queueDir}/${name}.space + touch ${cfg.queueDir}/${name}.queuesize + + chown ${cfg.owner}:${cfg.group} ${cfg.queueDir}/${name}.queue ${cfg.queueDir}/${name}.space ${cfg.queueDir}/${name}.queuesize + ''; +in { + options = { + services.uucp.media-server = { + enable = mkEnableOption "UUCP media server"; + + remoteNodes = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Clients to track + ''; + }; + + queueDir = mkOption { + type = types.path; + default = "/var/spool/media"; + description = "Queue directory"; + }; + + owner = mkOption { + type = types.str; + default = "root"; + description = "Owner of the various queue files"; + }; + + group = mkOption { + type = types.str; + default = "media"; + description = "Group of the various queue files"; + }; + }; + }; + + config = mkIf cfg.enable { + system.activationScripts."uucp-media-server" = '' + mkdir -p ${cfg.queueDir} + chmod 750 ${cfg.queueDir} + chown ${cfg.owner}:${cfg.group} ${cfg.queueDir} + + ${concatStringsSep "\n" (map touchStateFiles cfg.remoteNodes)} + ''; + + environment.systemPackages = [ (pkgs.callPackage ./uucp-mediaserver/scripts.nix { config = cfg; }) ]; + }; +} diff --git a/custom/uucp-mediaserver/scripts.nix b/custom/uucp-mediaserver/scripts.nix new file mode 100644 index 00000000..21eab6de --- /dev/null +++ b/custom/uucp-mediaserver/scripts.nix @@ -0,0 +1,32 @@ +{ stdenv, zsh, config }: + +let + mkSymlinks = name: '' + ln -s $out/libexec/mediaspace $out/bin/mediaspace.${name} + ln -s $out/libexec/queue $out/bin/queue.${name} + ln -s $out/libexec/queuesize $out/bin/queuesize.${name} + ln -s $out/libexec/queuestatus $out/bin/queuestatus.${name} + ln -s $out/libexec/update-queuesize $out/bin/update-queuesize.${name} + ''; +in stdenv.mkDerivation { + name = "uucp-mediaserver"; + src = ./scripts; + + phases = [ "installPhase" ]; + + inherit (config) queueDir; + + installPhase = '' + mkdir -p $out/libexec + + substituteFile $src/mediaspace $out/libexec/mediaspace + substituteFile $src/queue $out/libexec/queue + substituteFile $src/queuesize $out/libexec/queuesize + substituteFile $src/queuestatus $out/libexec/queuestatus + substituteFile $src/update-queuesize $out/libexec/update-queuesize + + mkdir -p $out/bin + + ${concatStringsSep "\n" (map mkSymlinks config.remoteNodes)} + ''; +} diff --git a/custom/uucp-mediaserver/scripts/mediaspace b/custom/uucp-mediaserver/scripts/mediaspace new file mode 100755 index 00000000..5d636a53 --- /dev/null +++ b/custom/uucp-mediaserver/scripts/mediaspace @@ -0,0 +1,9 @@ +#!@zsh@/bin/zsh + +base=$(basename $0) +suffix=${base##*.} + +printf "%d\n" "$1" > @queueDir@/mediaspace.$suffix +echo > @queueDir@/queuesize.$suffix +update-queuesize.$suffix + diff --git a/custom/uucp-mediaserver/scripts/queue b/custom/uucp-mediaserver/scripts/queue new file mode 100755 index 00000000..0039b3b8 --- /dev/null +++ b/custom/uucp-mediaserver/scripts/queue @@ -0,0 +1,134 @@ +#!@zsh@/bin/zsh + +logTag=${0:t} +exec 1> >(logger -t "$logTag" -p news.notice) +exec 2> >(logger -t "$logTag" -p news.error) + +doDebug=false +debug() { + if $doDebug; then + logger -t "$logTag" -p news.debug + else + cat >/dev/null + fi +} +verbose() { $@ | debug } + +function mungefilename() { + print ${@} | tr -s $';&*|<> \t!_' '_' +} + +typeset -a cleanupCmds +cleanupCmds=() + +function doCleanup { + for cmd (${cleanupCmds}); do + eval ${cmd} | debug + done +} + +trap doCleanup EXIT + +function cleanup() { + local cmd + cmd="" + for arg ($@); do + [[ -n "${cmd}" ]] && cmd="${cmd} " + cmd="${cmd}${(qq)arg}" + done + + cleanupCmds+=(${cmd}) +} + +base=$(basename $0) +suffix=${base##*.} + +force=0 +if [[ "$1" == "-f" ]]; then + shift + force=1 + if [[ -n "$1" && "$1" -eq "$1" ]] 2>/dev/null; then + force="$1" + shift + fi +fi + +noCall=false +if [[ "$1" == "-r" ]]; then + shift + noCall=true +fi + +for f (${@}); do + f=$(readlink -f ${f}) + if grep -q ${f} @queueDir@/${suffix}.queue; then + printf "‘%s’ is already in queue file\n" ${f:t} | warn + continue + fi + if uustat | grep -q ${f:t}; then + printf "‘%s’ is already in uucp queue\n" ${f:t} | warn + fi + print -r ${f} >> @queueDir@/${suffix}.queue +done + +offset=1 + +advance() { + cat =(head -n $((offset - 1)) @queuedir@/${suffix}.queue) =(tail -n +$((offset + 1)) @queueDir@/${suffix}.queue) >@queueDir@/${suffix}.queue +} + +while true; do + [[ $(wc -l @queueDir@/${suffix}.queue | cut -d ' ' -f 1) -lt $offset ]] && break + file=$(tail -n +${offset} @queueDir@/${suffix}.queue | head -n 1) + printf "Considering ‘%s’" ${file} | debug + if [[ -z "${file}" || ! -e "${file}" ]]; then + if [[ -n "${file}" ]]; then + printf "‘%s’ does not exist, skipping\n" "${file}" >&2 + printf "Subject: Missing file in %s\n\n%s" $logTag ${file} \ + | sendmail gkleen \ + && echo "Sent mail." + fi + advance + continue + fi + + space=$(($(cat @queueDir@/${suffix}.space) - $(queuesize.$suffix))) + printf "%s left on %s\n" $(numfmt --suffix=B --to=iec-i -- $space) $suffix | debug + + size=$(stat -c "%s" "${file}") + printf "‘%s’ is %s\n" ${file:t} $(numfmt --suffix=B --to=iec-i -- $size) | debug + if [[ "${size}" -le "${space}" || "${force}" -gt 0 ]]; then + printf "queuing ‘%s’ for %s\n" ${file:t} ${suffix} | debug + function send() { + typeset -a cmd + cmd=(uux $(if ${noCall}; then echo "-r"; fi) -g z) + + compatibleName=${file} + function munge() { [[ $(mungefilename ${file}) != ${file} ]] } + + if munge; then + compatibleName=${file:h}/$(mungefilename ${file:t}) + [[ -e ${compatibleName} ]] || verbose ln -vs ${file} ${compatibleName} + cmd+=(-C) + cleanup rm -v ${compatibleName} + fi + + cmd+=("${suffix}!recv-media" "!${compatibleName}" "$(date --date=@$(stat -c '%Y' "${file}") "+%Y%m%d%H%M.%S")") + + if munge; then + cmd+=("$(print -- ${file:t} | base64 -w0)") + fi + $cmd && printf "Queued ‘%s’ for %s\n" ${file:t} $suffix + } + + function skip() { + offset=$((offset + 1)) + printf "Failed to queue ‘%s’\n" ${file} >&2 + } + + { { [[ ! -e "${file}" ]] || send } && advance && update-queuesize.$suffix } || skip + force=$(($force - 1)) + else + break + fi +done diff --git a/custom/uucp-mediaserver/scripts/queuesize b/custom/uucp-mediaserver/scripts/queuesize new file mode 100755 index 00000000..3b98ccdb --- /dev/null +++ b/custom/uucp-mediaserver/scripts/queuesize @@ -0,0 +1,24 @@ +#!@zsh@/bin/zsh + +base=$(basename $0) +suffix=${base##*.} + +#sent=$(cat /var/queuesize.$suffix) +#uustat -s $suffix | grep 'Executing recv-media' | sed -r 's/^.*\(sending ([0-9]+) bytes\)/\1/' | awk "BEGIN{s=${sent}}{s+=\$1}END{print s}" + +awk 'BEGIN{s=0}{s+=$1}END{print s;}' @queueDir@/${suffix}.queuesize + +# typeset -a queued +# queued=() + +# ids=$({ uustat -s $suffix | cut -d ' ' -f 1; cut -d ' ' -f 2 /var/queuesize.$suffix } | sort | uniq -d ) +# queued=(${(f)ids}) + +# sum=0 + +# while read size id; do +# [[ ${queued[(r)$id]} == ${(q)id} ]] || continue +# sum=$((sum + size)) +# done < /var/queuesize.$suffix + +# print $sum diff --git a/custom/uucp-mediaserver/scripts/queuestatus b/custom/uucp-mediaserver/scripts/queuestatus new file mode 100755 index 00000000..babacfea --- /dev/null +++ b/custom/uucp-mediaserver/scripts/queuestatus @@ -0,0 +1,41 @@ +#!@zsh@/bin/zsh + +typeset -a queue +queue=() + +suffix=${${0:t}##*.} +uucpsize() { + command queuesize.${suffix} ${@} +} +mediaspace() { + cat @queueDir@/${suffix}.space +} +queuesize() { + local sum=0 + for file (${queue}); do + local size=$(stat -c "%s" "${file}") || continue + sum=$((sum + size)) + done + printf "%d" ${sum} +} + +queueTxt=$(grep -vE '^\s*$' @queueDir@/${suffix}.queue) +queue=(${(f)queueTxt}) + +printf "Space: %s\n Reported: %s\n UUCP queue size: %s\n" \ + $(numfmt --to=iec-i --suffix=B -- $(($(mediaspace) - $(uucpsize)))) \ + $(mediaspace | numfmt --to=iec-i --suffix=B) \ + $(uucpsize | numfmt --to=iec-i --suffix=B) + +printf "Queue: %d\n Size: %s\n" \ + ${#queue} \ + $(queuesize | numfmt --to=iec-i --suffix=B) + +printf "\n" + +for file (${queue}); do + size() { + stat -c "%s" "${file}" | numfmt --to=iec-i --suffix=B + } + printf "%6s %s\n" $(size || printf "N/A") ${file:t} +done diff --git a/custom/uucp-mediaserver/scripts/update-queuesize b/custom/uucp-mediaserver/scripts/update-queuesize new file mode 100755 index 00000000..db1b3e2a --- /dev/null +++ b/custom/uucp-mediaserver/scripts/update-queuesize @@ -0,0 +1,10 @@ +#!@zsh@/bin/zsh + +base=$(basename $0) +suffix=${base##*.} + +uustat -s $suffix | grep 'Executing recv-media' | sed -r 's/^([^ ]+) .*\(sending ([0-9]+) bytes\)/\2 \1/' >> @queueDir@/${suffix}.queuesize +tmpFile=$(mktemp --tmpdir=$HOME) +sort -k 2 @queueDir@/${suffix}.queuesize | uniq -f 1 > "${tmpFile}" +cat "${tmpFile}" >! @queueDir@/${suffix}.queuesize +rm "${tmpFile}" -- cgit v1.2.3