# vim: ft=make ts=4 sw=4 noet
.DEFAULT_GOAL := all

NAME    = bind
VERSION = 9.20.24
GARTYPE = v2

DESCRIPTION = ISC BIND 9 DNS server
define BLURB
  BIND 9.20 authoritative and recursive DNS server suite.
  Includes named, rndc, dig, nslookup, host, nsupdate, delv.
endef

MASTER_SITES = https://ftp.isc.org/isc/bind9/$(VERSION)/
DISTFILES   += $(NAME)-$(VERSION).tar.xz

LICENSE = LICENSE

# BIND 9.16+ requires libuv >= 1.40; 9.18+ requires liburcu >= 0.10
BUILD_DEP_PKGS += OZSWopenssl OZSWzlib OZSWreadline OZSWlibuv OZSWliburcu

# -----------------------------------------------------------------------
# OZSWbind9rt — runtime libraries (libdns, libisc, libns, etc.)
# -----------------------------------------------------------------------
PACKAGES                  += OZSWbind9rt
SPKG_DESC_OZSWbind9rt      = ISC BIND 9.20 runtime libraries
CATALOGNAME_OZSWbind9rt    = bind9rt
RUNTIME_DEP_PKGS_OZSWbind9rt += OZSWopenssl OZSWzlib OZSWlibuv OZSWliburcu
PKGFILES_OZSWbind9rt  = .*/lib/libdns\.so.*
PKGFILES_OZSWbind9rt += .*/lib/libbind9\.so.*
PKGFILES_OZSWbind9rt += .*/lib/libirs\.so.*
PKGFILES_OZSWbind9rt += .*/lib/libisc\.so.*
PKGFILES_OZSWbind9rt += .*/lib/libisccc\.so.*
PKGFILES_OZSWbind9rt += .*/lib/libisccfg\.so.*
PKGFILES_OZSWbind9rt += .*/lib/libns\.so.*

# -----------------------------------------------------------------------
# OZSWbind9 — server, tools, headers (catch-all)
# -----------------------------------------------------------------------
PACKAGES             += OZSWbind9
SPKG_DESC_OZSWbind9   = ISC BIND 9.20 DNS server and utilities
CATALOGNAME_OZSWbind9 = bind9
RUNTIME_DEP_PKGS_OZSWbind9 += OZSWbind9rt OZSWopenssl OZSWzlib OZSWreadline OZSWlibuv OZSWliburcu

# -----------------------------------------------------------------------
# Build configuration
# -----------------------------------------------------------------------

EXTENSIONS = 1

CONFIGURE_ARGS  = --prefix=$(prefix)
CONFIGURE_ARGS += --sysconfdir=/etc/named
CONFIGURE_ARGS += --localstatedir=/var
# OpenSSL via BUILD_PREFIX; libuv and liburcu via pkg-config
CONFIGURE_ARGS += --with-openssl=$(BUILD_PREFIX)
# Disable optional features we don't have
CONFIGURE_ARGS += --without-libxml2
CONFIGURE_ARGS += --without-gssapi
CONFIGURE_ARGS += --without-lmdb
CONFIGURE_ARGS += --without-json-c
CONFIGURE_ARGS += --without-libnghttp2
CONFIGURE_ARGS += --disable-dnstap
CONFIGURE_ARGS += --disable-doh
CONFIGURE_ARGS += --disable-dependency-tracking
CONFIGURE_ARGS += DTRACE=
# Solaris: socket/nsl/rt/pthread needed explicitly
CONFIGURE_ARGS += CFLAGS="-D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -include /usr/include/sys/types.h"
CONFIGURE_ARGS += CXXFLAGS="-D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -include /usr/include/sys/types.h"
CONFIGURE_ARGS += LDFLAGS="-L$(BUILD_PREFIX)/lib -Wl,-R,$(BUILD_PREFIX)/lib -lsocket -lnsl -lrt -lpthread"

post-extract:
	@echo "==> Creating lib/isc/ifaddrs.h shim (getifaddrs via SIOCGIFCONF for Solaris)"
	@# Only interfaceiter.c includes <ifaddrs.h>; placing it in lib/isc/ makes it
	@# findable via -I$(srcdir) without any Makefile.in changes.
	@# getifaddrs/freeifaddrs are static so they only exist in interfaceiter.c's TU.
	@/opt/ozsw/bin/python3 -c "\
import textwrap; \
h = textwrap.dedent('''\
    /* ifaddrs.h -- getifaddrs/freeifaddrs shim for OpenSolaris snv_111b via SIOCGIFCONF.\n\
     * Only used by BIND'\''s interfaceiter.c; functions are static to avoid ODR issues.\n\
     */\n\
    #ifndef _IFADDRS_H\n\
    #define _IFADDRS_H\n\
    \n\
    #include <sys/types.h>\n\
    #include <sys/socket.h>\n\
    #include <sys/ioctl.h>\n\
    #include <net/if.h>\n\
    #include <netinet/in.h>\n\
    #include <stdlib.h>\n\
    #include <string.h>\n\
    #include <unistd.h>\n\
    \n\
    struct ifaddrs {\n\
        struct ifaddrs  *ifa_next;\n\
        char            *ifa_name;\n\
        unsigned int     ifa_flags;\n\
        struct sockaddr *ifa_addr;\n\
        struct sockaddr *ifa_netmask;\n\
        union {\n\
            struct sockaddr *ifu_broadaddr;\n\
            struct sockaddr *ifu_dstaddr;\n\
        } ifa_ifu;\n\
        void            *ifa_data;\n\
    };\n\
    #define ifa_broadaddr ifa_ifu.ifu_broadaddr\n\
    #define ifa_dstaddr   ifa_ifu.ifu_dstaddr\n\
    \n\
    static void\n\
    freeifaddrs(struct ifaddrs *ifa)\n\
    {\n\
        while (ifa) {\n\
            struct ifaddrs *next = ifa->ifa_next;\n\
            free(ifa->ifa_name);\n\
            free(ifa->ifa_addr);\n\
            free(ifa->ifa_netmask);\n\
            free(ifa);\n\
            ifa = next;\n\
        }\n\
    }\n\
    \n\
    static int\n\
    getifaddrs(struct ifaddrs **ifap)\n\
    {\n\
        struct ifconf     ifc;\n\
        struct ifreq      buf[64];\n\
        struct ifaddrs   *head = NULL, **tail = &head;\n\
        int               fd, n, i;\n\
    \n\
        fd = socket(AF_INET, SOCK_DGRAM, 0);\n\
        if (fd < 0) return -1;\n\
        ifc.ifc_len = sizeof(buf);\n\
        ifc.ifc_req = buf;\n\
        if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { close(fd); return -1; }\n\
        close(fd);\n\
    \n\
        n = ifc.ifc_len / (int)sizeof(struct ifreq);\n\
        for (i = 0; i < n; i++) {\n\
            struct ifreq     req;\n\
            struct ifaddrs  *ifa;\n\
            int              sfd;\n\
    \n\
            if (buf[i].ifr_addr.sa_family != AF_INET)\n\
                continue;\n\
    \n\
            ifa = calloc(1, sizeof(*ifa));\n\
            if (!ifa) goto fail;\n\
    \n\
            ifa->ifa_name = strdup(buf[i].ifr_name);\n\
            if (!ifa->ifa_name) { free(ifa); goto fail; }\n\
    \n\
            ifa->ifa_addr = malloc(sizeof(struct sockaddr_in));\n\
            if (ifa->ifa_addr)\n\
                memcpy(ifa->ifa_addr, &buf[i].ifr_addr, sizeof(struct sockaddr_in));\n\
    \n\
            sfd = socket(AF_INET, SOCK_DGRAM, 0);\n\
            if (sfd >= 0) {\n\
                memset(&req, 0, sizeof(req));\n\
                strncpy(req.ifr_name, buf[i].ifr_name, IFNAMSIZ - 1);\n\
                if (ioctl(sfd, SIOCGIFFLAGS, &req) == 0)\n\
                    ifa->ifa_flags = (unsigned int)req.ifr_flags;\n\
                memset(&req, 0, sizeof(req));\n\
                strncpy(req.ifr_name, buf[i].ifr_name, IFNAMSIZ - 1);\n\
                if (ioctl(sfd, SIOCGIFNETMASK, &req) == 0) {\n\
                    ifa->ifa_netmask = malloc(sizeof(struct sockaddr_in));\n\
                    if (ifa->ifa_netmask)\n\
                        memcpy(ifa->ifa_netmask, &req.ifr_addr, sizeof(struct sockaddr_in));\n\
                }\n\
                close(sfd);\n\
            }\n\
    \n\
            *tail = ifa;\n\
            tail  = &ifa->ifa_next;\n\
        }\n\
        *ifap = head;\n\
        return 0;\n\
    fail:\n\
        freeifaddrs(head);\n\
        return -1;\n\
    }\n\
    \n\
    #endif /* _IFADDRS_H */\n\
    '''); \
open('$(WORKSRC)/lib/isc/ifaddrs.h','w').write(h)"
	@echo "==> Patching util/dtrace.sh: Solaris tr treats a-z as literal, use [:lower:]/[:upper:]"
	@gsed -i 's/| tr "a-z" "A-Z"/| tr '\''[:lower:]'\'' '\''[:upper:]'\''/g' $(WORKSRC)/util/dtrace.sh
	@echo "==> Generating probes.h files with correct uppercase macros (Solaris sed/dtrace.sh produces wrong case)"
	@/opt/ozsw/bin/python3 -c "import re, os; w='$(WORKSRC)'; dirs=['lib/isc','lib/dns','lib/ns']; [(open(os.path.join(w,d,'probes.h'),'w').write(''.join(['#define {p}_{probe}_ENABLED() 0\n#define {p}_{probe}(...)\n'.format(p=re.search(r\"provider (\\S+)\", open(os.path.join(w,d,'probes.d')).read()).group(1).upper(), probe=m.group(1).upper()) for m in re.finditer(r\"probe ([a-z_]+)\\(\", open(os.path.join(w,d,'probes.d')).read())]))) for d in dirs if os.path.exists(os.path.join(w,d,'probes.d'))]"
	@$(MAKECOOKIE)

# Fix libtool ECHO="print -r --" (ksh93 builtin, fails under bash)
# Regenerate probes.h using dtrace.sh shim so macro names are correct (uppercase).
# The native Solaris dtrace binary generates mixed-case names that don't match job.c.
post-configure:
	@find $(WORKSRC) -name "libtool" -type f -exec gsed -i 's/ECHO="print -r --"/ECHO="printf %s\\n"/g' {} \;
	@$(MAKECOOKIE)

include gar/category.mk
