#!/bin/sh
# Copyright 1999-2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# IPX start helper for systemd and OpenRC.
#
# This script reads its configuration from environment variables, typically
# provided through /etc/conf.d/ipx.
#
# Manual interface format:
#   <device>:<frame>:<netnum>
#
# Static route format:
#   <target_network>:<router_network>:<router_node>
#
# Behaviour:
#   - The first successfully configured interface becomes the primary IPX
#     interface.
#   - Missing interfaces are skipped.
#   - Optionally, interfaces with no active link can also be skipped.
#   - Static routes are added after interface configuration.

set -u

configured=0
retval=0
primary_set=0

log_warn() {
    printf '%s\n' "ipx: $*" >&2
}

log_err() {
    printf '%s\n' "ipx: $*" >&2
}

link_is_usable() {
    local dev carrier_file operstate_file state

    dev=$1
    carrier_file="/sys/class/net/${dev}/carrier"
    operstate_file="/sys/class/net/${dev}/operstate"

    if [ "${IPX_SKIP_LINK_DOWN:-no}" != "yes" ]; then
	return 0
    fi

    if [ -r "${carrier_file}" ]; then
	state=$(cat "${carrier_file}")
	if [ "${state}" = "0" ]; then
	    log_warn "interface ${dev} has no carrier, skipping"
	    return 1
	fi
	return 0
    fi

    if [ -r "${operstate_file}" ]; then
	state=$(cat "${operstate_file}")
	case "${state}" in
	    down)
		log_warn "interface ${dev} is link-down, skipping"
		return 1
		;;
	esac
    fi

    return 0
}

if [ "${IPX_INTERNAL_NET:-no}" = "yes" ]; then
    if ! /sbin/ipx_internal_net add "${IPX_NETNUM}" "${IPX_NODENUM}"; then
	log_err "failed to create internal IPX network"
	retval=1
    fi
else
    oldifs=${IFS}
    IFS='
'
    for entry in ${IPX_INTERFACES:-}; do
	[ -n "${entry}" ] || continue

	case "${entry}" in
	    \#*)
		continue
		;;
	esac

	dev=${entry%%:*}
	rest=${entry#*:}
	frame=${rest%%:*}
	netnum=${rest#*:}

	if [ -z "${dev}" ] || [ -z "${frame}" ] || [ -z "${netnum}" ] || [ "${rest}" = "${entry}" ]; then
	    log_err "invalid IPX_INTERFACES entry: ${entry}"
	    retval=1
	    break
	fi

	if [ ! -d "/sys/class/net/${dev}" ]; then
	    log_warn "interface ${dev} is not present, skipping"
	    continue
	fi

	if ! link_is_usable "${dev}"; then
	    continue
	fi

	if [ "${primary_set}" -eq 0 ]; then
	    if /sbin/ipx_interface add -p "${dev}" "${frame}" "${netnum}"; then
		configured=1
		primary_set=1
	    else
		log_err "failed to add primary IPX interface on ${dev}"
		retval=1
	    fi
	else
	    if /sbin/ipx_interface add "${dev}" "${frame}" "${netnum}"; then
		configured=1
	    else
		log_err "failed to add IPX interface on ${dev}"
		retval=1
	    fi
	fi
    done
    IFS=${oldifs}

    if [ "${configured}" -eq 0 ] && [ "${retval}" -eq 0 ]; then
	log_warn "no configured IPX interfaces were present"
    fi
fi

if [ "${retval}" -eq 0 ]; then
    oldifs=${IFS}
    IFS='
'
    for entry in ${IPX_ROUTES:-}; do
	[ -n "${entry}" ] || continue

	case "${entry}" in
	    \#*)
		continue
		;;
	esac

	target=${entry%%:*}
	rest=${entry#*:}
	router_net=${rest%%:*}
	router_node=${rest#*:}

	if [ -z "${target}" ] || [ -z "${router_net}" ] || [ -z "${router_node}" ] || [ "${rest}" = "${entry}" ]; then
	    log_err "invalid IPX_ROUTES entry: ${entry}"
	    retval=1
	    break
	fi

	if ! /sbin/ipx_route add "${target}" "${router_net}" "${router_node}"; then
	    log_err "failed to add IPX route to ${target}"
	    retval=1
	fi
    done
    IFS=${oldifs}
fi

if ! /sbin/ipx_configure \
    --auto_primary="${IPX_AUTO_PRIMARY}" \
    --auto_interface="${IPX_AUTO_INTERFACE}"; then
    log_err "failed to apply automatic IPX configuration"
    retval=1
fi

if [ "${retval}" -ne 0 ]; then
    log_warn "startup failed, cleaning up partial IPX configuration"
    /usr/libexec/ipx/network-stop.sh || true
fi

exit "${retval}"
