manifest 4.42 KB
Newer Older
ssrq's avatar
ssrq committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#!/bin/sh -e
#
# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#

grep_line() { echo "$2" | grep -qxF "$1"; }
unquote_lines() {
	sed -e '/^".*"$/{s/^"//;s/"$//}' \
	    -e '/'"^'.*'"'$/{s/'"^'"'//;s/'"'$"'//}'
}

append_values() {
	while read -r _value
	do
		set -- "$@" --value "${_value}"
	done
	unset _value
	"$@" </dev/null
}

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
uci_validate_name() {
	# like util.c uci_validate_name()
	test -n "$*" && test -z "$(echo "$*" | tr -d '[:alnum:]_')"
}

## Check section name and error if invalid!
case ${__object_id:?}
in
	(*.*)
		uci_validate_name "${__object_id%%.*}" || {
			printf 'Invalid package name: %s\n' "${__object_id%%.*}" >&2
			exit 1
		}
		uci_validate_name "${__object_id#*.}" || {
			printf 'Invalid section name: %s\n' "${__object_id#*.}" >&2
			exit 1
		}
		;;
	(*)
		uci_validate_name "${__object_id:?}" || {
			printf 'Invalid section name: %s\n' "${__object_id:?}" >&2
			exit 1
		}
		;;
esac

ssrq's avatar
ssrq committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
section=$(cat "${__object:?}/explorer/match")

state_should=$(cat "${__object:?}/parameter/state")
transaction_name=$(cat "${__object:?}/parameter/transaction")

case $state_should
in
	(present)
		test -f "${__object:?}/parameter/type" || {
			echo 'Parameter --type is required.' >&2
			exit 1
		}
		type_is=$(cat "${__object:?}/explorer/type")
		type_should=$(cat "${__object:?}/parameter/type")

77 78 79 80
		optnames_is=$(
			sed -n -e 's/=.*$//' \
			       -e 's/^[^.]*\.[^.]*\.//p' "${__object:?}/explorer/options")

ssrq's avatar
ssrq committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
		if test -f "${__object:?}/parameter/option"
		then
			optnames_should=$(
				sed -e 's/=.*$//' "${__object:?}/parameter/option" | sort -u)
		fi

		if test -n "${type_is}"
		then
			if test "${type_is}" != "${type_should##*.}"
			then
				# Check if section type matches (section exists and --type provided)
				printf 'Section type "%s" does not match --type "%s".\n' \
					"${type_is}" "${type_should}" >&2
				exit 1
			fi
			sect_type=${type_is}
		else
			sect_type=${type_should##*.}
		fi

		if test -z "${section}"
		then
			# No section exists and --match was used.
			# So we generate a new section identifier from $__object_id.
			case ${__object_id:?}
			in
				(*.*) section=${__object_id:?} ;;
				(*) section="${type_should%%.*}.${__object_id:?}" ;;
			esac
		fi

		# Make sure the section itself is present
113 114 115 116 117 118
		if ! grep -qxF "${section}=${sect_type}" "${__object}/explorer/options"
		then
			__uci "${section}" --state present --transaction "${transaction_name}" \
				--value "${sect_type}"
			export require=__uci/"${section}"
		fi
ssrq's avatar
ssrq committed
119 120

		# Delete options not in "should"
121 122
		echo "${optnames_is}" \
		| while read -r _optname
ssrq's avatar
ssrq committed
123
		  do
124
			  if ! grep_line "${_optname}" "${optnames_should}"
ssrq's avatar
ssrq committed
125
			  then
126
				  __uci "${section}.${_optname}" --state absent \
ssrq's avatar
ssrq committed
127 128 129 130 131 132
					  --transaction "${transaction_name}" </dev/null
			  fi
		  done

		# Set "should" options
		echo "${optnames_should}" \
133 134
		| grep -e . \
		| while read -r _optname
ssrq's avatar
ssrq committed
135
		  do
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
			  values_is=$(
				  sed -n -e 's/^[^.]*\.[^.]*\.//;T' \
				         -e "/^${_optname}=/p" \
				         -e 's/^.*=//' "${__object}/explorer/options" \
				  | tr '\036' '\n' \
				  | unquote_lines)

			  values_should=$(
				  grep -e "^${_optname}=" "${__object:?}/parameter/option" \
				  | sed -e 's/^.*=//' \
				  | unquote_lines)

			  # Compare "is" and "should" and only generate __uci object
			  # if they differ
			  if test "${values_is}" != "${values_should}"
			  then
				  # NOTE: Do not use dash's echo, as it evaluates escape
				  # sequences.
				  printf '%s\n' "${values_should}" | append_values \
					  __uci "${section}.${_optname}" --state present \
						  --transaction "${transaction_name}"
			  fi
ssrq's avatar
ssrq committed
158 159 160 161 162 163 164 165 166 167 168 169 170
		  done
		;;
	(absent)
		# if explorer found no section there is nothing to delete
		test -n "${section}" || exit 0

		__uci "${section}" --state absent --transaction "${transaction_name}"
		;;
	(*)
		printf 'Invalid --state: %s\n' "${state_should}" >&2
		exit 1
		;;
esac