xref: /freebsd/libexec/rc/safe_eval.sh (revision 701d7be6e4a9a145700fdee5c038470b355a0e05)
1:
2# RCSid:
3#	$Id: safe_eval.sh,v 1.28 2026/04/22 16:36:32 sjg Exp $
4#
5#	@(#) Copyright (c) 2023-2026 Simon J. Gerraty
6#
7#	SPDX-License-Identifier: BSD-2-Clause
8#
9#	Please send copies of changes and bug-fixes to:
10#	sjg@crufty.net
11
12_SAFE_EVAL_SH=:
13
14# does local *actually* work?
15local_works() {
16    local _fu
17}
18
19if local_works > /dev/null 2>&1; then
20    _local=local
21else
22    _local=:
23fi
24
25##
26# safe_set [xtras]
27#
28# return a safe variable setting
29# any non-alphanumeric chars other than those in "xtras"
30# will be replaced with '_'
31# Lines containing `` or $() are too likely to result in syntax errors
32# so just delete them.
33#
34# "xtras" should be used with caution and cannot include ';'
35#
36safe_set() {
37    ${SED:-sed} -e 's/^[ 	]*//;s/[ 	]*#.*//;s/^:.*//' \
38    -e '/`/d' -e '/\$(/d' \
39    -e '/^[A-Za-z_][A-Za-z0-9_]*=/!d;s;[^A-Za-z0-9_. 	"'"$1"'$,/=:+-];_;g;' \
40    -e '/=.*_.*[ 	]/s,=\(.*\),="\1",;s,"",",g'
41}
42
43##
44# safe_eval [file]
45#
46# eval variable assignments only from file
47# taking care to eliminate any shell meta chars
48#
49safe_eval() {
50    eval `cat "$@" | safe_set`
51}
52
53##
54# safe_eval_export [file]
55#
56# eval variable assignments only from file
57# taking care to eliminate any shell meta chars
58# export any variables thus set
59#
60safe_eval_export() {
61    eval `cat "$@" | safe_set | ${SED:-sed} 's/^\([^=]*\)=.*/&; export \1/'`
62}
63
64##
65# safe_dot file [...]
66#
67# feed all "file" that exist to safe_eval
68#
69safe_dot() {
70    eval $_local ef ex f rc
71    ef=
72    ex=
73    rc=1
74    while :
75    do
76        case "$1" in
77        --export) ex=_export; shift;;
78        *) break;;
79        esac
80    done
81    for f in "$@"
82    do
83        test -s "$f" -a -f "$f" || continue
84        : check for space or tab in "$f"
85        case "$f" in
86        *[[:space:]]*|*" "*|*"	"*) # we cannot do this efficiently
87            dotted="$dotted $f"
88            safe_eval$ex "$f"
89            rc=$?
90            continue
91            ;;
92        esac
93        ef="${ef:+$ef }$f"
94        dotted="$dotted $f"
95    done
96    test -z "$ef" && return $rc
97    safe_eval$ex $ef
98    return 0
99}
100
101case /$0 in
102*/safe_eval*)
103    case "$1" in
104    dot|eval|set) op=safe_$1; shift; $op "$@";;
105    *) safe_dot "$@";;
106    esac
107    ;;
108esac
109