--- /dev/null
+#!/bin/sh
+
+usage() {
+ cat <<EOF
+Usage: $0 update|remove --spec <prio>:<path>:<alt-path>
+
+EOF
+ exit 1
+}
+
+errmsg() {
+ echo "$0: $@" >&2
+}
+
+uci_() {
+ $UCI ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} "$@"
+}
+
+check_path() {
+ local path="${IPKG_INSTROOT}$1"
+
+ [ -L "$path" -o ! -e "$path" ] || {
+ errmsg "$0: $path exists and is not an symbolic file"
+ exit 1
+ }
+}
+
+update_path() {
+ local path="$1"
+ local found_section found_altpath
+ local found_prio=-1 found_prio_altpath
+ local IFS cur altpath
+
+ config_load opkg
+ config_foreach find_path alternatives "$prio" "$path"
+ if [ -n "$found_prio_altpath" ]; then
+ IFS=:; set -- $found_prio_altpath; altpath=$2; IFS="$oIFS"
+ cur="$(readlink -f "$path")"
+ if [ "$cur" != "$altpath" ]; then
+ errmsg "link $path -> $altpath"
+ ln -sf "$altpath" "${IPKG_INSTROOT}$path"
+ fi
+ elif [ -n "$found_section" ]; then
+ errmsg "remove empty alternatives section for $path"
+ uci_ delete "opkg.$found_section"
+ uci_ commit opkg
+ rm -f "${IPKG_INSTROOT}$path"
+ fi
+}
+
+find_altpath() {
+ local cfgaltpath="$1"
+ local cfg="$2"
+ local prio="$3"
+ local altpath="$4"
+ local cfgprio cfgaltpath_
+ local oIFS="$IFS"; IFS=:; set -- $cfgaltpath; cfgprio="$1"; cfgaltpath_="$2"; IFS="$oIFS"
+
+ if [ "$cfgaltpath_" = "$altpath" ]; then
+ found_altpath="$cfgaltpath"
+ fi
+ if [ "$cfgprio" -gt "$found_prio" ]; then
+ found_prio="$cfgprio"
+ found_prio_altpath="$cfgaltpath"
+ fi
+}
+
+find_path() {
+ local cfg="$1"
+ local prio="$2"
+ local path="$3"
+ local altpath="$4"
+ local cfgpath
+
+ config_get cfgpath "$cfg" path
+ [ "$cfgpath" = "$path" ] || return
+ found_section="$cfg"
+ config_list_foreach "$cfg" altpath find_altpath "$cfg" "$prio" "$altpath"
+}
+
+cmd_update() {
+ local spec="$1"
+ local prio path altpath
+ local oIFS="$IFS"
+ local found_section found_altpath
+ local found_prio=-1 found_prio_altpath
+
+ IFS=:; set -- $spec; IFS="$oIFS"
+ prio="$1"
+ path="$2"
+ altpath="$3"
+ check_path "$path"
+ if [ ! -e "${IPKG_INSTROOT}$altpath" ]; then
+ errmsg "$altpath does not exist"
+ return 1
+ fi
+
+ config_load opkg
+ config_foreach find_path alternatives "$prio" "$path" "$altpath"
+ if [ -z "$found_section" ]; then
+ found_section="$(uci_ add opkg alternatives)"
+ uci_ set opkg.$found_section.path=$path
+ fi
+ if [ -n "$found_altpath" ]; then
+ if [ "$found_altpath" != "$prio:$altpath" ]; then
+ # update priority
+ uci_ del_list opkg.$found_section.altpath=$found_altpath
+ uci_ add_list opkg.$found_section.altpath=$prio:$altpath
+ fi
+ else
+ uci_ add_list opkg.$found_section.altpath=$prio:$altpath
+ fi
+ uci_ commit opkg
+ update_path "$path"
+}
+
+cmd_remove() {
+ local spec="$1"
+ local prio path altpath
+ local oIFS="$IFS"
+ local found_section found_altpath
+ local found_prio=-1 found_prio_altpath
+
+ IFS=:; set -- $spec; IFS="$oIFS"
+ prio="$1"
+ path="$2"
+ altpath="$3"
+ check_path "$path"
+
+ config_load opkg
+ config_foreach find_path alternatives "$prio" "$path" "$altpath"
+ if [ -n "$found_section" -a -n "$found_altpath" ]; then
+ uci_ del_list opkg.$found_section.altpath=$found_altpath
+ uci_ commit opkg
+ update_path "$path"
+ else
+ errmsg "spec $spec not found"
+ fi
+}
+
+. ${IPKG_INSTROOT}/lib/functions.sh
+
+UCI="${UCI:-/sbin/uci}"
+UCI_STATE_DIR="${IPKG_INSTROOT}/var/state"
+ARG_CMD=
+ARG_SPEC=
+while [ "$#" -gt 0 ]; do
+ case "$1" in
+ update|remove)
+ ARG_CMD="$1"
+ shift
+ ;;
+ --spec)
+ ARG_SPEC="$2";
+ shift 2
+ ;;
+ *) usage ;;
+ esac
+done
+
+[ -n "$ARG_CMD" -a -n "$ARG_SPEC" ] || usage
+
+cmd_$ARG_CMD "$ARG_SPEC"