1#! /helper/script/for/moderni/sh
2IFS=''; set -fCu  # safe mode
3
4# This is a helper script called by the '-exec' primary of 'find' in the
5# var/loop/find module. It turns its arguments into assignments for the main
6# shell to eval.
7#
8# --- begin license ---
9# Copyright (c) 2019 Martijn Dekker <martijn@inlv.org>, Groningen, Netherlands
10#
11# Permission to use, copy, modify, and/or distribute this software for any
12# purpose with or without fee is hereby granted, provided that the above
13# copyright notice and this permission notice appear in all copies.
14#
15# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22# --- end license ---
23
24# If the pipe is broken, the -exec'ed shell will get SIGPIPE but the 'find' utility itself won't.
25# To avoid 'find' going haywire, our -exec'ed shell must trap SIGPIPE and kill its parent PID, which
26# is the 'find' utility. Also add a fallback check for I/O error in 'put', in case SIGPIPE is ignored.
27
28trap 'trap - PIPE; kill -s PIPE $PPID $$' PIPE
29
30interrupt_find() {
31	kill -s PIPE $$		# this will also kill our $PPID (the 'find' utility) through the trap
32	kill -s TERM $PPID $$	# SIGPIPE is ignored: loop/find.mm will OK this if WRN_NOSIGPIPE was detected, or die()
33	DIE "signals ignored"	# both SIGPIPE and SIGTERM are ignored: fatal; loop/find.mm will die()
34}
35
36DIE() {
37	echo "LOOP find: $@" >&2
38	kill -s KILL $PPID $$
39}
40
41# Check that either the variable or the xargs option was exported to here, but not both.
42
43case ${_loop_PATH+A}${_loop_AUX+O}${_loop_V+K}${_loop_xargs+K} in
44( AOK )	;;
45( * )	echo "die 'LOOP find: internal error'" >&8 || DIE "internal error"
46	interrupt_find ;;
47esac
48
49PATH=${_loop_PATH}
50
51# Use modernish shell-quoting (via awk) to guarantee one loop iteration
52# command per line, so the main shell can safely 'read -r' and 'eval' any
53# possible file names from the FIFO.
54
55awk -f ${_loop_AUX}/find.awk -- "$@" >&8
56e=$?
57case $e in
58( 0 )	;;
59( 126 )	DIE "system error: awk could not be executed" ;;
60( 127 )	DIE "system error: awk could not be found" ;;
61( 129 | 1[3-9]? | [!1]?? | ????* )
62	sig=$(kill -l $e 2>/dev/null)
63	sig=${sig#[sS][iI][gG]}
64	case $sig in
65	( [pP][iI][pP][eE] )
66		interrupt_find ;;  # propagate SIGPIPE upwards
67	( '' | [0-9]* )
68		DIE "system error: awk exited with status $e" ;;
69	( * )	DIE "system error: awk was killed by SIG$sig" ;;
70	esac ;;
71( * )	# other nonzero exit status: presume write error from awk
72	interrupt_find ;;
73esac
74